mirror of
https://github.com/gitui-org/gitui
synced 2026-05-24 09:28:21 +00:00
persist current tab as options (#1339)
This commit is contained in:
parent
cb01fda516
commit
9534e4c2f9
9 changed files with 126 additions and 31 deletions
|
|
@ -13,8 +13,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
* submodules support ([#1087](https://github.com/extrawurst/gitui/issues/1087))
|
* submodules support ([#1087](https://github.com/extrawurst/gitui/issues/1087))
|
||||||
|
* remember tab between app starts ([#1338](https://github.com/extrawurst/gitui/issues/1338))
|
||||||
* customizable `cmdbar_bg` theme color & screen spanning selected line bg [[@gigitsu](https://github.com/gigitsu)] ([#1299](https://github.com/extrawurst/gitui/pull/1299))
|
* customizable `cmdbar_bg` theme color & screen spanning selected line bg [[@gigitsu](https://github.com/gigitsu)] ([#1299](https://github.com/extrawurst/gitui/pull/1299))
|
||||||
* use filewatcher instead of polling updates ([#1](https://github.com/extrawurst/gitui/issues/1))
|
|
||||||
* word motions to text input [[@Rodrigodd](https://github.com/Rodrigodd)] ([#1256](https://github.com/extrawurst/gitui/issues/1256))
|
* word motions to text input [[@Rodrigodd](https://github.com/Rodrigodd)] ([#1256](https://github.com/extrawurst/gitui/issues/1256))
|
||||||
* file blame at right revision from commit-details [[@heiskane](https://github.com/heiskane)] ([#1122](https://github.com/extrawurst/gitui/issues/1122))
|
* file blame at right revision from commit-details [[@heiskane](https://github.com/heiskane)] ([#1122](https://github.com/extrawurst/gitui/issues/1122))
|
||||||
* add `regex-fancy` and `regex-onig` features to allow building Syntect with Onigumara regex engine instead of the default engine based on fancy-regex [[@jirutka](https://github.com/jirutka)]
|
* add `regex-fancy` and `regex-onig` features to allow building Syntect with Onigumara regex engine instead of the default engine based on fancy-regex [[@jirutka](https://github.com/jirutka)]
|
||||||
|
|
@ -22,6 +22,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
|
|
||||||
### Fixes
|
### Fixes
|
||||||
* remove insecure dependency `ansi_term` ([#1290](https://github.com/extrawurst/gitui/issues/1290))
|
* remove insecure dependency `ansi_term` ([#1290](https://github.com/extrawurst/gitui/issues/1290))
|
||||||
|
* use filewatcher instead of polling updates ([#1](https://github.com/extrawurst/gitui/issues/1))
|
||||||
|
|
||||||
## [0.21.0] - 2021-08-17
|
## [0.21.0] - 2021-08-17
|
||||||
|
|
||||||
|
|
|
||||||
24
src/app.rs
24
src/app.rs
|
|
@ -10,12 +10,13 @@ use crate::{
|
||||||
FileRevlogComponent, HelpComponent, InspectCommitComponent,
|
FileRevlogComponent, HelpComponent, InspectCommitComponent,
|
||||||
MsgComponent, OptionsPopupComponent, PullComponent,
|
MsgComponent, OptionsPopupComponent, PullComponent,
|
||||||
PushComponent, PushTagsComponent, RenameBranchComponent,
|
PushComponent, PushTagsComponent, RenameBranchComponent,
|
||||||
RevisionFilesPopup, SharedOptions, StashMsgComponent,
|
RevisionFilesPopup, StashMsgComponent,
|
||||||
SubmodulesListComponent, TagCommitComponent,
|
SubmodulesListComponent, TagCommitComponent,
|
||||||
TagListComponent,
|
TagListComponent,
|
||||||
},
|
},
|
||||||
input::{Input, InputEvent, InputState},
|
input::{Input, InputEvent, InputState},
|
||||||
keys::{key_match, KeyConfig, SharedKeyConfig},
|
keys::{key_match, KeyConfig, SharedKeyConfig},
|
||||||
|
options::{Options, SharedOptions},
|
||||||
popup_stack::PopupStack,
|
popup_stack::PopupStack,
|
||||||
queue::{
|
queue::{
|
||||||
Action, InternalEvent, NeedsUpdate, Queue, StackablePopupOpen,
|
Action, InternalEvent, NeedsUpdate, Queue, StackablePopupOpen,
|
||||||
|
|
@ -92,6 +93,7 @@ pub struct App {
|
||||||
key_config: SharedKeyConfig,
|
key_config: SharedKeyConfig,
|
||||||
input: Input,
|
input: Input,
|
||||||
popup_stack: PopupStack,
|
popup_stack: PopupStack,
|
||||||
|
options: SharedOptions,
|
||||||
|
|
||||||
// "Flags"
|
// "Flags"
|
||||||
requires_redraw: Cell<bool>,
|
requires_redraw: Cell<bool>,
|
||||||
|
|
@ -109,15 +111,17 @@ impl App {
|
||||||
input: Input,
|
input: Input,
|
||||||
theme: Theme,
|
theme: Theme,
|
||||||
key_config: KeyConfig,
|
key_config: KeyConfig,
|
||||||
) -> Self {
|
) -> Result<Self> {
|
||||||
log::trace!("open repo at: {:?}", &repo);
|
log::trace!("open repo at: {:?}", &repo);
|
||||||
|
|
||||||
let queue = Queue::new();
|
let queue = Queue::new();
|
||||||
let theme = Rc::new(theme);
|
let theme = Rc::new(theme);
|
||||||
let key_config = Rc::new(key_config);
|
let key_config = Rc::new(key_config);
|
||||||
let options = SharedOptions::default();
|
let options = Options::new(repo.clone());
|
||||||
|
|
||||||
Self {
|
let tab = options.borrow().current_tab();
|
||||||
|
|
||||||
|
let mut app = Self {
|
||||||
input,
|
input,
|
||||||
reset: ConfirmComponent::new(
|
reset: ConfirmComponent::new(
|
||||||
queue.clone(),
|
queue.clone(),
|
||||||
|
|
@ -263,7 +267,6 @@ impl App {
|
||||||
key_config.clone(),
|
key_config.clone(),
|
||||||
),
|
),
|
||||||
msg: MsgComponent::new(theme.clone(), key_config.clone()),
|
msg: MsgComponent::new(theme.clone(), key_config.clone()),
|
||||||
tab: 0,
|
|
||||||
revlog: Revlog::new(
|
revlog: Revlog::new(
|
||||||
&repo,
|
&repo,
|
||||||
&queue,
|
&queue,
|
||||||
|
|
@ -277,7 +280,7 @@ impl App {
|
||||||
sender,
|
sender,
|
||||||
theme.clone(),
|
theme.clone(),
|
||||||
key_config.clone(),
|
key_config.clone(),
|
||||||
options,
|
options.clone(),
|
||||||
),
|
),
|
||||||
stashing_tab: Stashing::new(
|
stashing_tab: Stashing::new(
|
||||||
&repo,
|
&repo,
|
||||||
|
|
@ -299,14 +302,20 @@ impl App {
|
||||||
theme.clone(),
|
theme.clone(),
|
||||||
key_config.clone(),
|
key_config.clone(),
|
||||||
),
|
),
|
||||||
|
tab: 0,
|
||||||
queue,
|
queue,
|
||||||
theme,
|
theme,
|
||||||
|
options,
|
||||||
key_config,
|
key_config,
|
||||||
requires_redraw: Cell::new(false),
|
requires_redraw: Cell::new(false),
|
||||||
file_to_open: None,
|
file_to_open: None,
|
||||||
repo,
|
repo,
|
||||||
popup_stack: PopupStack::default(),
|
popup_stack: PopupStack::default(),
|
||||||
}
|
};
|
||||||
|
|
||||||
|
app.set_tab(tab)?;
|
||||||
|
|
||||||
|
Ok(app)
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
|
|
@ -678,6 +687,7 @@ impl App {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.tab = tab;
|
self.tab = tab;
|
||||||
|
self.options.borrow_mut().set_current_tab(tab);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,12 @@
|
||||||
use super::{
|
use super::{
|
||||||
status_tree::StatusTreeComponent,
|
status_tree::StatusTreeComponent,
|
||||||
utils::filetree::{FileTreeItem, FileTreeItemKind},
|
utils::filetree::{FileTreeItem, FileTreeItemKind},
|
||||||
CommandBlocking, DrawableComponent, SharedOptions,
|
CommandBlocking, DrawableComponent,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
components::{CommandInfo, Component, EventState},
|
components::{CommandInfo, Component, EventState},
|
||||||
keys::{key_match, SharedKeyConfig},
|
keys::{key_match, SharedKeyConfig},
|
||||||
|
options::SharedOptions,
|
||||||
queue::{Action, InternalEvent, NeedsUpdate, Queue, ResetItem},
|
queue::{Action, InternalEvent, NeedsUpdate, Queue, ResetItem},
|
||||||
strings, try_or_popup,
|
strings, try_or_popup,
|
||||||
ui::style::SharedTheme,
|
ui::style::SharedTheme,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
use super::{utils::logitems::ItemBatch, SharedOptions};
|
use super::utils::logitems::ItemBatch;
|
||||||
use super::{visibility_blocking, BlameFileOpen, InspectCommitOpen};
|
use super::{visibility_blocking, BlameFileOpen, InspectCommitOpen};
|
||||||
use crate::keys::key_match;
|
use crate::keys::key_match;
|
||||||
|
use crate::options::SharedOptions;
|
||||||
use crate::queue::StackablePopupOpen;
|
use crate::queue::StackablePopupOpen;
|
||||||
use crate::{
|
use crate::{
|
||||||
components::{
|
components::{
|
||||||
|
|
@ -191,7 +192,7 @@ impl FileRevlogComponent {
|
||||||
let diff_params = DiffParams {
|
let diff_params = DiffParams {
|
||||||
path: open_request.file_path.clone(),
|
path: open_request.file_path.clone(),
|
||||||
diff_type: DiffType::Commit(commit_id),
|
diff_type: DiffType::Commit(commit_id),
|
||||||
options: self.options.borrow().diff,
|
options: self.options.borrow().diff_options(),
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some((params, last)) =
|
if let Some((params, last)) =
|
||||||
|
|
|
||||||
|
|
@ -51,9 +51,7 @@ pub use file_revlog::{FileRevOpen, FileRevlogComponent};
|
||||||
pub use help::HelpComponent;
|
pub use help::HelpComponent;
|
||||||
pub use inspect_commit::{InspectCommitComponent, InspectCommitOpen};
|
pub use inspect_commit::{InspectCommitComponent, InspectCommitOpen};
|
||||||
pub use msg::MsgComponent;
|
pub use msg::MsgComponent;
|
||||||
pub use options_popup::{
|
pub use options_popup::{AppOption, OptionsPopupComponent};
|
||||||
AppOption, OptionsPopupComponent, SharedOptions,
|
|
||||||
};
|
|
||||||
pub use pull::PullComponent;
|
pub use pull::PullComponent;
|
||||||
pub use push::PushComponent;
|
pub use push::PushComponent;
|
||||||
pub use push_tags::PushTagsComponent;
|
pub use push_tags::PushTagsComponent;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
use std::{cell::RefCell, rc::Rc};
|
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
visibility_blocking, CommandBlocking, CommandInfo, Component,
|
visibility_blocking, CommandBlocking, CommandInfo, Component,
|
||||||
DrawableComponent, EventState,
|
DrawableComponent, EventState,
|
||||||
|
|
@ -7,12 +5,13 @@ use super::{
|
||||||
use crate::{
|
use crate::{
|
||||||
components::utils::string_width_align,
|
components::utils::string_width_align,
|
||||||
keys::{key_match, SharedKeyConfig},
|
keys::{key_match, SharedKeyConfig},
|
||||||
|
options::SharedOptions,
|
||||||
queue::{InternalEvent, Queue},
|
queue::{InternalEvent, Queue},
|
||||||
strings::{self},
|
strings::{self},
|
||||||
ui::{self, style::SharedTheme},
|
ui::{self, style::SharedTheme},
|
||||||
};
|
};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use asyncgit::sync::{diff::DiffOptions, ShowUntrackedFilesConfig};
|
use asyncgit::sync::ShowUntrackedFilesConfig;
|
||||||
use crossterm::event::Event;
|
use crossterm::event::Event;
|
||||||
use tui::{
|
use tui::{
|
||||||
backend::Backend,
|
backend::Backend,
|
||||||
|
|
@ -31,14 +30,6 @@ pub enum AppOption {
|
||||||
DiffInterhunkLines,
|
DiffInterhunkLines,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Copy, Clone)]
|
|
||||||
pub struct Options {
|
|
||||||
pub status_show_untracked: Option<ShowUntrackedFilesConfig>,
|
|
||||||
pub diff: DiffOptions,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type SharedOptions = Rc<RefCell<Options>>;
|
|
||||||
|
|
||||||
pub struct OptionsPopupComponent {
|
pub struct OptionsPopupComponent {
|
||||||
selection: AppOption,
|
selection: AppOption,
|
||||||
queue: Queue,
|
queue: Queue,
|
||||||
|
|
@ -91,26 +82,27 @@ impl OptionsPopupComponent {
|
||||||
);
|
);
|
||||||
Self::add_header(txt, "");
|
Self::add_header(txt, "");
|
||||||
|
|
||||||
|
let diff = self.options.borrow().diff_options();
|
||||||
Self::add_header(txt, "Diff");
|
Self::add_header(txt, "Diff");
|
||||||
self.add_entry(
|
self.add_entry(
|
||||||
txt,
|
txt,
|
||||||
width,
|
width,
|
||||||
"Ignore whitespaces",
|
"Ignore whitespaces",
|
||||||
&self.options.borrow().diff.ignore_whitespace.to_string(),
|
&diff.ignore_whitespace.to_string(),
|
||||||
self.is_select(AppOption::DiffIgnoreWhitespaces),
|
self.is_select(AppOption::DiffIgnoreWhitespaces),
|
||||||
);
|
);
|
||||||
self.add_entry(
|
self.add_entry(
|
||||||
txt,
|
txt,
|
||||||
width,
|
width,
|
||||||
"Context lines",
|
"Context lines",
|
||||||
&self.options.borrow().diff.context.to_string(),
|
&diff.context.to_string(),
|
||||||
self.is_select(AppOption::DiffContextLines),
|
self.is_select(AppOption::DiffContextLines),
|
||||||
);
|
);
|
||||||
self.add_entry(
|
self.add_entry(
|
||||||
txt,
|
txt,
|
||||||
width,
|
width,
|
||||||
"Inter hunk lines",
|
"Inter hunk lines",
|
||||||
&self.options.borrow().diff.interhunk_lines.to_string(),
|
&diff.interhunk_lines.to_string(),
|
||||||
self.is_select(AppOption::DiffInterhunkLines),
|
self.is_select(AppOption::DiffInterhunkLines),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ mod components;
|
||||||
mod input;
|
mod input;
|
||||||
mod keys;
|
mod keys;
|
||||||
mod notify_mutex;
|
mod notify_mutex;
|
||||||
|
mod options;
|
||||||
mod popup_stack;
|
mod popup_stack;
|
||||||
mod profiler;
|
mod profiler;
|
||||||
mod queue;
|
mod queue;
|
||||||
|
|
@ -175,7 +176,7 @@ fn run_app(
|
||||||
input.clone(),
|
input.clone(),
|
||||||
theme,
|
theme,
|
||||||
key_config,
|
key_config,
|
||||||
);
|
)?;
|
||||||
|
|
||||||
let mut spinner = Spinner::default();
|
let mut spinner = Spinner::default();
|
||||||
let mut first_update = true;
|
let mut first_update = true;
|
||||||
|
|
|
||||||
90
src/options.rs
Normal file
90
src/options.rs
Normal file
|
|
@ -0,0 +1,90 @@
|
||||||
|
use anyhow::Result;
|
||||||
|
use asyncgit::sync::{
|
||||||
|
diff::DiffOptions, repo_dir, RepoPathRef,
|
||||||
|
ShowUntrackedFilesConfig,
|
||||||
|
};
|
||||||
|
use ron::{
|
||||||
|
de::from_bytes,
|
||||||
|
ser::{to_string_pretty, PrettyConfig},
|
||||||
|
};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::{
|
||||||
|
cell::RefCell,
|
||||||
|
fs::File,
|
||||||
|
io::{Read, Write},
|
||||||
|
path::PathBuf,
|
||||||
|
rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Default, Copy, Clone, Serialize, Deserialize)]
|
||||||
|
struct OptionsData {
|
||||||
|
pub tab: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Options {
|
||||||
|
//TODO: un-pub and use getters/setters and move into persisted data
|
||||||
|
pub status_show_untracked: Option<ShowUntrackedFilesConfig>,
|
||||||
|
pub diff: DiffOptions,
|
||||||
|
|
||||||
|
repo: RepoPathRef,
|
||||||
|
data: OptionsData,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type SharedOptions = Rc<RefCell<Options>>;
|
||||||
|
|
||||||
|
impl Options {
|
||||||
|
pub fn new(repo: RepoPathRef) -> SharedOptions {
|
||||||
|
Rc::new(RefCell::new(Self {
|
||||||
|
data: Self::read(&repo).unwrap_or_default(),
|
||||||
|
diff: DiffOptions::default(),
|
||||||
|
status_show_untracked: None,
|
||||||
|
repo,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_current_tab(&mut self, tab: usize) {
|
||||||
|
self.data.tab = tab;
|
||||||
|
self.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn current_tab(&self) -> usize {
|
||||||
|
self.data.tab
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn diff_options(&self) -> DiffOptions {
|
||||||
|
self.diff
|
||||||
|
}
|
||||||
|
|
||||||
|
fn save(&self) {
|
||||||
|
if let Err(e) = self.save_failable() {
|
||||||
|
log::error!("options save error: {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read(repo: &RepoPathRef) -> Result<OptionsData> {
|
||||||
|
let dir = Self::options_file(repo)?;
|
||||||
|
|
||||||
|
let mut f = File::open(dir)?;
|
||||||
|
let mut buffer = Vec::new();
|
||||||
|
f.read_to_end(&mut buffer)?;
|
||||||
|
Ok(from_bytes(&buffer)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn save_failable(&self) -> Result<()> {
|
||||||
|
let dir = Self::options_file(&self.repo)?;
|
||||||
|
|
||||||
|
let mut file = File::create(&dir)?;
|
||||||
|
let data =
|
||||||
|
to_string_pretty(&self.data, PrettyConfig::default())?;
|
||||||
|
file.write_all(data.as_bytes())?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn options_file(repo: &RepoPathRef) -> Result<PathBuf> {
|
||||||
|
let dir = repo_dir(&repo.borrow())?;
|
||||||
|
let dir = dir.join("gitui");
|
||||||
|
Ok(dir)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,9 +4,10 @@ use crate::{
|
||||||
command_pump, event_pump, visibility_blocking,
|
command_pump, event_pump, visibility_blocking,
|
||||||
ChangesComponent, CommandBlocking, CommandInfo, Component,
|
ChangesComponent, CommandBlocking, CommandInfo, Component,
|
||||||
DiffComponent, DrawableComponent, EventState,
|
DiffComponent, DrawableComponent, EventState,
|
||||||
FileTreeItemKind, SharedOptions,
|
FileTreeItemKind,
|
||||||
},
|
},
|
||||||
keys::{key_match, SharedKeyConfig},
|
keys::{key_match, SharedKeyConfig},
|
||||||
|
options::SharedOptions,
|
||||||
queue::{Action, InternalEvent, NeedsUpdate, Queue, ResetItem},
|
queue::{Action, InternalEvent, NeedsUpdate, Queue, ResetItem},
|
||||||
strings, try_or_popup,
|
strings, try_or_popup,
|
||||||
ui::style::SharedTheme,
|
ui::style::SharedTheme,
|
||||||
|
|
@ -490,7 +491,7 @@ impl Status {
|
||||||
let diff_params = DiffParams {
|
let diff_params = DiffParams {
|
||||||
path: path.clone(),
|
path: path.clone(),
|
||||||
diff_type,
|
diff_type,
|
||||||
options: self.options.borrow().diff,
|
options: self.options.borrow().diff_options(),
|
||||||
};
|
};
|
||||||
|
|
||||||
if self.diff.current() == (path.clone(), is_stage) {
|
if self.diff.current() == (path.clone(), is_stage) {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue