diff --git a/Cargo.lock b/Cargo.lock index 704c51b866c..bfbb66bd32a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -75,6 +75,7 @@ dependencies = [ "pretty_assertions", "rayon-core", "scopetime", + "serde", "serial_test", "shellexpand", "tempfile", diff --git a/asyncgit/Cargo.toml b/asyncgit/Cargo.toml index 85a4aec1a96..862af7efe7b 100644 --- a/asyncgit/Cargo.toml +++ b/asyncgit/Cargo.toml @@ -22,6 +22,7 @@ log = "0.4" openssl-sys = { version = '0.9', features = ["vendored"], optional = true } rayon-core = "1.9" scopetime = { path = "../scopetime", version = "0.1" } +serde = "1.0" shellexpand = "2.1" thiserror = "1.0" unicode-truncate = "0.2.0" diff --git a/asyncgit/src/sync/config.rs b/asyncgit/src/sync/config.rs index 3d095c77cd9..da68feebed5 100644 --- a/asyncgit/src/sync/config.rs +++ b/asyncgit/src/sync/config.rs @@ -1,12 +1,18 @@ +//TODO: hopefully released in next rust (see https://github.com/rust-lang/rust-clippy/issues/9440) +#![allow(clippy::use_self)] + use crate::error::Result; use git2::Repository; use scopetime::scope_time; +use serde::{Deserialize, Serialize}; use super::{repository::repo, RepoPath}; // see https://git-scm.com/docs/git-config#Documentation/git-config.txt-statusshowUntrackedFiles /// represents the `status.showUntrackedFiles` git config state -#[derive(Hash, Copy, Clone, PartialEq, Eq)] +#[derive( + Hash, Copy, Clone, PartialEq, Eq, Serialize, Deserialize, +)] pub enum ShowUntrackedFilesConfig { /// No, diff --git a/asyncgit/src/sync/diff.rs b/asyncgit/src/sync/diff.rs index c93f937f644..c5bc17ca7be 100644 --- a/asyncgit/src/sync/diff.rs +++ b/asyncgit/src/sync/diff.rs @@ -13,6 +13,7 @@ use git2::{ Delta, Diff, DiffDelta, DiffFormat, DiffHunk, Patch, Repository, }; use scopetime::scope_time; +use serde::{Deserialize, Serialize}; use std::{cell::RefCell, fs, path::Path, rc::Rc}; /// type of diff of a single line @@ -127,7 +128,9 @@ pub struct FileDiff { } /// see -#[derive(Debug, Hash, Clone, Copy, PartialEq, Eq)] +#[derive( + Debug, Hash, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, +)] pub struct DiffOptions { /// see pub ignore_whitespace: bool, diff --git a/src/components/changes.rs b/src/components/changes.rs index 92fa0262b9e..523ae5687a4 100644 --- a/src/components/changes.rs +++ b/src/components/changes.rs @@ -107,7 +107,7 @@ impl ChangesComponent { }; } else { let config = - self.options.borrow().status_show_untracked; + self.options.borrow().status_show_untracked(); //TODO: check if we can handle the one file case with it aswell sync::stage_add_all( @@ -123,7 +123,7 @@ impl ChangesComponent { // would mean that after staging the workdir becomes empty if sync::is_workdir_clean( &self.repo.borrow(), - self.options.borrow().status_show_untracked, + self.options.borrow().status_show_untracked(), )? { self.queue .push(InternalEvent::StatusLastFileMoved); @@ -141,7 +141,7 @@ impl ChangesComponent { } fn index_add_all(&mut self) -> Result<()> { - let config = self.options.borrow().status_show_untracked; + let config = self.options.borrow().status_show_untracked(); sync::stage_add_all(&self.repo.borrow(), "*", config)?; diff --git a/src/components/options_popup.rs b/src/components/options_popup.rs index 3e9fd46e69c..cfc9e51e998 100644 --- a/src/components/options_popup.rs +++ b/src/components/options_popup.rs @@ -72,7 +72,7 @@ impl OptionsPopupComponent { txt, width, "Show untracked", - match self.options.borrow().status_show_untracked { + match self.options.borrow().status_show_untracked() { None => "Gitconfig", Some(ShowUntrackedFilesConfig::No) => "No", Some(ShowUntrackedFilesConfig::Normal) => "Normal", @@ -179,7 +179,7 @@ impl OptionsPopupComponent { match self.selection { AppOption::StatusShowUntracked => { let untracked = - self.options.borrow().status_show_untracked; + self.options.borrow().status_show_untracked(); let untracked = match untracked { None => { @@ -194,34 +194,31 @@ impl OptionsPopupComponent { Some(ShowUntrackedFilesConfig::No) => None, }; - self.options.borrow_mut().status_show_untracked = - untracked; + self.options + .borrow_mut() + .set_status_show_untracked(untracked); } AppOption::DiffIgnoreWhitespaces => { - let old = - self.options.borrow().diff.ignore_whitespace; self.options .borrow_mut() - .diff - .ignore_whitespace = !old; + .diff_toggle_whitespace(); } AppOption::DiffContextLines => { - let old = self.options.borrow().diff.context; - self.options.borrow_mut().diff.context = - old.saturating_add(1); + self.options + .borrow_mut() + .diff_context_change(true); } AppOption::DiffInterhunkLines => { - let old = - self.options.borrow().diff.interhunk_lines; - self.options.borrow_mut().diff.interhunk_lines = - old.saturating_add(1); + self.options + .borrow_mut() + .diff_hunk_lines_change(true); } }; } else { match self.selection { AppOption::StatusShowUntracked => { let untracked = - self.options.borrow().status_show_untracked; + self.options.borrow().status_show_untracked(); let untracked = match untracked { None => Some(ShowUntrackedFilesConfig::No), @@ -236,27 +233,24 @@ impl OptionsPopupComponent { } }; - self.options.borrow_mut().status_show_untracked = - untracked; + self.options + .borrow_mut() + .set_status_show_untracked(untracked); } AppOption::DiffIgnoreWhitespaces => { - let old = - self.options.borrow().diff.ignore_whitespace; self.options .borrow_mut() - .diff - .ignore_whitespace = !old; + .diff_toggle_whitespace(); } AppOption::DiffContextLines => { - let old = self.options.borrow().diff.context; - self.options.borrow_mut().diff.context = - old.saturating_sub(1); + self.options + .borrow_mut() + .diff_context_change(false); } AppOption::DiffInterhunkLines => { - let old = - self.options.borrow().diff.interhunk_lines; - self.options.borrow_mut().diff.interhunk_lines = - old.saturating_sub(1); + self.options + .borrow_mut() + .diff_hunk_lines_change(false); } }; } diff --git a/src/options.rs b/src/options.rs index 48005e32f9f..2aba12d5a1c 100644 --- a/src/options.rs +++ b/src/options.rs @@ -19,14 +19,12 @@ use std::{ #[derive(Default, Copy, Clone, Serialize, Deserialize)] struct OptionsData { pub tab: usize, + pub diff: DiffOptions, + pub status_show_untracked: Option, } #[derive(Clone)] pub struct Options { - //TODO: un-pub and use getters/setters and move into persisted data - pub status_show_untracked: Option, - pub diff: DiffOptions, - repo: RepoPathRef, data: OptionsData, } @@ -37,8 +35,6 @@ 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, })) } @@ -53,7 +49,48 @@ impl Options { } pub const fn diff_options(&self) -> DiffOptions { - self.diff + self.data.diff + } + + pub const fn status_show_untracked( + &self, + ) -> Option { + self.data.status_show_untracked + } + + pub fn set_status_show_untracked( + &mut self, + value: Option, + ) { + self.data.status_show_untracked = value; + self.save(); + } + + pub fn diff_context_change(&mut self, increase: bool) { + self.data.diff.context = if increase { + self.data.diff.context.saturating_add(1) + } else { + self.data.diff.context.saturating_sub(1) + }; + + self.save(); + } + + pub fn diff_hunk_lines_change(&mut self, increase: bool) { + self.data.diff.interhunk_lines = if increase { + self.data.diff.interhunk_lines.saturating_add(1) + } else { + self.data.diff.interhunk_lines.saturating_sub(1) + }; + + self.save(); + } + + pub fn diff_toggle_whitespace(&mut self) { + self.data.diff.ignore_whitespace = + !self.data.diff.ignore_whitespace; + + self.save(); } fn save(&self) { diff --git a/src/tabs/status.rs b/src/tabs/status.rs index 117883db6d1..609c6c61860 100644 --- a/src/tabs/status.rs +++ b/src/tabs/status.rs @@ -397,7 +397,8 @@ impl Status { self.git_branch_name.lookup().map(Some).unwrap_or(None); if self.is_visible() { - let config = self.options.borrow().status_show_untracked; + let config = + self.options.borrow().status_show_untracked(); self.git_diff.refresh()?; self.git_status_workdir.fetch(&StatusParams::new(