persist current tab as options (#1339)

This commit is contained in:
extrawurst 2022-09-18 18:05:29 +02:00 committed by GitHub
parent cb01fda516
commit 9534e4c2f9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 126 additions and 31 deletions

View file

@ -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

View file

@ -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(())
} }

View file

@ -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,

View file

@ -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)) =

View file

@ -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;

View file

@ -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),
); );
} }

View file

@ -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
View 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)
}
}

View file

@ -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) {