From f70b92aeee9c027e25b9704659d9a5984a8e49d0 Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Thu, 4 Feb 2021 00:11:02 +0000 Subject: [PATCH 01/97] Add search bar at bottom of revlog --- src/app.rs | 3 + src/components/commitlist.rs | 16 ++++ src/components/find_commit.rs | 144 ++++++++++++++++++++++++++++++++++ src/components/mod.rs | 2 + src/components/textinput.rs | 31 +++++--- src/keys.rs | 42 +++++----- src/queue.rs | 2 + src/tabs/revlog.rs | 90 +++++++++++++++++---- 8 files changed, 282 insertions(+), 48 deletions(-) create mode 100644 src/components/find_commit.rs diff --git a/src/app.rs b/src/app.rs index 2ce3b6be50..09cf56b4a2 100644 --- a/src/app.rs +++ b/src/app.rs @@ -537,6 +537,9 @@ impl App { self.push_popup.push(branch)?; flags.insert(NeedsUpdate::ALL) } + InternalEvent::FilterLog(string_to_fliter_by) => { + self.revlog.filter(string_to_fliter_by) + } }; Ok(flags) diff --git a/src/components/commitlist.rs b/src/components/commitlist.rs index 16b071d977..5efae50e04 100644 --- a/src/components/commitlist.rs +++ b/src/components/commitlist.rs @@ -39,6 +39,7 @@ pub struct CommitList { scroll_top: Cell, theme: SharedTheme, key_config: SharedKeyConfig, + filter_string: Option, } impl CommitList { @@ -60,6 +61,7 @@ impl CommitList { theme, key_config, title: String::from(title), + filter_string: None, } } @@ -114,6 +116,11 @@ impl CommitList { self.tags = Some(tags); } + /// + pub fn set_filter(&mut self, filter_string: Option) { + self.filter_string = filter_string; + } + /// pub fn selected_entry(&self) -> Option<&LogEntry> { self.items.iter().nth( @@ -261,6 +268,15 @@ impl CommitList { for (idx, e) in self .items .iter() + .filter(|log_entry| { + if let Some(filter_string) = &self.filter_string { + return log_entry + .hash_short + .contains(filter_string) + || log_entry.msg.contains(filter_string); + } + true + }) .skip(self.scroll_top.get()) .take(height) .enumerate() diff --git a/src/components/find_commit.rs b/src/components/find_commit.rs new file mode 100644 index 0000000000..a3bca72267 --- /dev/null +++ b/src/components/find_commit.rs @@ -0,0 +1,144 @@ +use super::{ + textinput::TextInputComponent, visibility_blocking, + CommandBlocking, CommandInfo, Component, DrawableComponent, +}; +use crate::{ + keys::SharedKeyConfig, + queue::{InternalEvent, Queue}, + strings, + ui::style::SharedTheme, +}; +use anyhow::Result; +use crossterm::event::Event; +use tui::{backend::Backend, layout::Rect, Frame}; + +pub struct FindCommitComponent { + input: TextInputComponent, + branch_ref: Option, + queue: Queue, + is_focused: bool, + visible: bool, + key_config: SharedKeyConfig, +} + +impl DrawableComponent for FindCommitComponent { + fn draw( + &self, + f: &mut Frame, + rect: Rect, + ) -> Result<()> { + self.input.draw(f, rect)?; + Ok(()) + } +} + +impl Component for FindCommitComponent { + fn commands( + &self, + out: &mut Vec, + force_all: bool, + ) -> CommandBlocking { + if self.is_visible() || force_all { + self.input.commands(out, force_all); + + out.push(CommandInfo::new( + strings::commands::rename_branch_confirm_msg( + &self.key_config, + ), + true, + true, + )); + } + + visibility_blocking(self) + } + + fn event(&mut self, ev: Event) -> Result { + if self.is_visible() { + if let Event::Key(e) = ev { + if e == self.key_config.enter { + // Send internal event to filter revlog + self.queue.borrow_mut().push_back( + InternalEvent::FilterLog( + self.input.get_text().to_string(), + ), + ); + return Ok(true); + } else if e == self.key_config.exit_popup { + // Prevent text input closing + return Ok(true); + } + } + if self.input.event(ev)? { + return Ok(true); + } + } + Ok(false) + } + + fn is_visible(&self) -> bool { + return self.visible; + } + + fn hide(&mut self) { + self.visible = false; + } + fn show(&mut self) -> Result<()> { + self.visible = true; + Ok(()) + } + + fn focus(&mut self, focus: bool) { + self.is_focused = focus; + } + + fn focused(&self) -> bool { + return self.is_focused; + } + + fn toggle_visible(&mut self) -> Result<()> { + self.visible = !self.visible; + Ok(()) + } +} + +impl FindCommitComponent { + /// + pub fn new( + queue: Queue, + theme: SharedTheme, + key_config: SharedKeyConfig, + ) -> Self { + let mut input_component = TextInputComponent::new( + theme, + key_config.clone(), + &strings::rename_branch_popup_title(&key_config), + &strings::rename_branch_popup_msg(&key_config), + true, + ); + input_component.show().expect("Will not err"); + input_component.set_should_use_rect(true); + Self { + queue, + input: input_component, + branch_ref: None, + key_config, + visible: false, + is_focused: false, + } + } + + /// + pub fn open( + &mut self, + branch_ref: String, + cur_name: String, + ) -> Result<()> { + self.branch_ref = None; + self.branch_ref = Some(branch_ref); + self.input.set_text(cur_name); + self.show()?; + + Ok(()) + } +} diff --git a/src/components/mod.rs b/src/components/mod.rs index 38efec75e5..21511d38f3 100644 --- a/src/components/mod.rs +++ b/src/components/mod.rs @@ -8,6 +8,7 @@ mod cred; mod diff; mod externaleditor; mod filetree; +mod find_commit; mod help; mod inspect_commit; mod msg; @@ -29,6 +30,7 @@ pub use create_branch::CreateBranchComponent; pub use diff::DiffComponent; pub use externaleditor::ExternalEditorComponent; pub use filetree::FileTreeComponent; +pub use find_commit::FindCommitComponent; pub use help::HelpComponent; pub use inspect_commit::InspectCommitComponent; pub use msg::MsgComponent; diff --git a/src/components/textinput.rs b/src/components/textinput.rs index 58044f8b0f..b4d01a3349 100644 --- a/src/components/textinput.rs +++ b/src/components/textinput.rs @@ -39,6 +39,7 @@ pub struct TextInputComponent { key_config: SharedKeyConfig, cursor_position: usize, input_type: InputType, + should_use_rect: bool, } impl TextInputComponent { @@ -60,6 +61,7 @@ impl TextInputComponent { default_msg: default_msg.to_string(), cursor_position: 0, input_type: InputType::Multiline, + should_use_rect: false, } } @@ -234,6 +236,10 @@ impl TextInputComponent { f.render_widget(w, rect); } } + + pub fn set_should_use_rect(&mut self, b: bool) { + self.should_use_rect = b; + } } // merges last line of `txt` with first of `append` so we do not generate unneeded newlines @@ -260,7 +266,7 @@ impl DrawableComponent for TextInputComponent { fn draw( &self, f: &mut Frame, - _rect: Rect, + rect: Rect, ) -> Result<()> { if self.visible { let txt = if self.msg.is_empty() { @@ -272,16 +278,21 @@ impl DrawableComponent for TextInputComponent { self.get_draw_text() }; - let area = match self.input_type { - InputType::Multiline => { - let area = ui::centered_rect(60, 20, f.size()); - ui::rect_inside( - Size::new(10, 3), - f.size().into(), - area, - ) + let area = if self.should_use_rect { + rect + } else { + match self.input_type { + InputType::Multiline => { + let area = + ui::centered_rect(60, 20, f.size()); + ui::rect_inside( + Size::new(10, 3), + f.size().into(), + area, + ) + } + _ => ui::centered_rect_absolute(32, 3, f.size()), } - _ => ui::centered_rect_absolute(32, 3, f.size()), }; f.render_widget(Clear, area); diff --git a/src/keys.rs b/src/keys.rs index 2f3bcce118..55e5d074e6 100644 --- a/src/keys.rs +++ b/src/keys.rs @@ -33,6 +33,8 @@ pub struct KeyConfig { pub exit_popup: KeyEvent, pub open_commit: KeyEvent, pub open_commit_editor: KeyEvent, + pub show_find_commit_text_input: KeyEvent, + pub focus_find_commit: KeyEvent, pub open_help: KeyEvent, pub move_left: KeyEvent, pub move_right: KeyEvent, @@ -85,7 +87,9 @@ impl Default for KeyConfig { exit: KeyEvent { code: KeyCode::Char('c'), modifiers: KeyModifiers::CONTROL}, exit_popup: KeyEvent { code: KeyCode::Esc, modifiers: KeyModifiers::empty()}, open_commit: KeyEvent { code: KeyCode::Char('c'), modifiers: KeyModifiers::empty()}, - open_commit_editor: KeyEvent { code: KeyCode::Char('e'), modifiers:KeyModifiers::CONTROL}, + open_commit_editor: KeyEvent { code: KeyCode::Char('e'), modifiers:KeyModifiers::CONTROL}, + show_find_commit_text_input: KeyEvent {code: KeyCode::Char('s'), modifiers: KeyModifiers::empty()}, + focus_find_commit: KeyEvent {code: KeyCode::Down, modifiers: KeyModifiers::ALT}, open_help: KeyEvent { code: KeyCode::Char('h'), modifiers: KeyModifiers::empty()}, move_left: KeyEvent { code: KeyCode::Left, modifiers: KeyModifiers::empty()}, move_right: KeyEvent { code: KeyCode::Right, modifiers: KeyModifiers::empty()}, @@ -206,27 +210,21 @@ impl KeyConfig { | KeyCode::BackTab | KeyCode::Delete | KeyCode::Insert - | KeyCode::Esc => { - format!( - "{}{}", - Self::get_modifier_hint(ev.modifiers), - self.get_key_symbol(ev.code) - ) - } - KeyCode::Char(c) => { - format!( - "{}{}", - Self::get_modifier_hint(ev.modifiers), - c - ) - } - KeyCode::F(u) => { - format!( - "{}F{}", - Self::get_modifier_hint(ev.modifiers), - u - ) - } + | KeyCode::Esc => format!( + "{}{}", + Self::get_modifier_hint(ev.modifiers), + self.get_key_symbol(ev.code) + ), + KeyCode::Char(c) => format!( + "{}{}", + Self::get_modifier_hint(ev.modifiers), + c + ), + KeyCode::F(u) => format!( + "{}F{}", + Self::get_modifier_hint(ev.modifiers), + u + ), KeyCode::Null => Self::get_modifier_hint(ev.modifiers), } } diff --git a/src/queue.rs b/src/queue.rs index 678baf6bb8..7e5cb12090 100644 --- a/src/queue.rs +++ b/src/queue.rs @@ -61,6 +61,8 @@ pub enum InternalEvent { OpenExternalEditor(Option), /// Push(String), + /// + FilterLog(String), } /// diff --git a/src/tabs/revlog.rs b/src/tabs/revlog.rs index 9a2a673520..baf3a0176d 100644 --- a/src/tabs/revlog.rs +++ b/src/tabs/revlog.rs @@ -2,7 +2,7 @@ use crate::{ components::{ visibility_blocking, CommandBlocking, CommandInfo, CommitDetailsComponent, CommitList, Component, - DrawableComponent, + DrawableComponent, FindCommitComponent, }, keys::SharedKeyConfig, queue::{InternalEvent, Queue}, @@ -31,12 +31,15 @@ const SLICE_SIZE: usize = 1200; pub struct Revlog { commit_details: CommitDetailsComponent, list: CommitList, + find_commit: FindCommitComponent, git_log: AsyncLog, git_tags: AsyncTags, queue: Queue, visible: bool, branch_name: cached::BranchName, key_config: SharedKeyConfig, + show_find_commit_box: bool, + filter_string: Option, } impl Revlog { @@ -57,6 +60,11 @@ impl Revlog { ), list: CommitList::new( &strings::log_title(&key_config), + theme.clone(), + key_config.clone(), + ), + find_commit: FindCommitComponent::new( + queue.clone(), theme, key_config.clone(), ), @@ -65,6 +73,8 @@ impl Revlog { visible: false, branch_name: cached::BranchName::new(CWD), key_config, + show_find_commit_box: true, + filter_string: None, } } @@ -166,6 +176,14 @@ impl Revlog { tags.and_then(|tags| tags.get(&commit).cloned()) }) } + + pub fn filter(&mut self, filter_by: String) { + if filter_by == "" { + self.list.set_filter(None); + } else { + self.list.set_filter(Some(filter_by)); + } + } } impl DrawableComponent for Revlog { @@ -174,22 +192,50 @@ impl DrawableComponent for Revlog { f: &mut Frame, area: Rect, ) -> Result<()> { - let chunks = Layout::default() - .direction(Direction::Horizontal) - .constraints( - [ - Constraint::Percentage(60), - Constraint::Percentage(40), - ] - .as_ref(), - ) - .split(area); - if self.commit_details.is_visible() { - self.list.draw(f, chunks[0])?; - self.commit_details.draw(f, chunks[1])?; + let chunks = Layout::default() + .direction(Direction::Horizontal) + .constraints( + [ + Constraint::Percentage(60), + Constraint::Percentage(40), + ] + .as_ref(), + ) + .split(area); + + if self.find_commit.is_visible() { + let log_find_chunks = Layout::default() + .direction(Direction::Vertical) + .constraints( + [ + Constraint::Percentage(90), + Constraint::Percentage(20), + ] + .as_ref(), + ) + .split(chunks[0]); + self.list.draw(f, log_find_chunks[0])?; + self.find_commit.draw(f, log_find_chunks[1])?; + self.commit_details.draw(f, chunks[1])?; + } } else { - self.list.draw(f, area)?; + if self.find_commit.is_visible() { + let log_find_chunks = Layout::default() + .direction(Direction::Vertical) + .constraints( + [ + Constraint::Percentage(90), + Constraint::Percentage(20), + ] + .as_ref(), + ) + .split(area); + self.list.draw(f, log_find_chunks[0])?; + self.find_commit.draw(f, log_find_chunks[1])?; + } else { + self.list.draw(f, area)?; + } } Ok(()) @@ -199,7 +245,11 @@ impl DrawableComponent for Revlog { impl Component for Revlog { fn event(&mut self, ev: Event) -> Result { if self.visible { - let event_used = self.list.event(ev)?; + let event_used = if self.find_commit.focused() { + self.find_commit.event(ev)? + } else { + self.list.event(ev)? + }; if event_used { self.update()?; @@ -244,6 +294,14 @@ impl Component for Revlog { .borrow_mut() .push_back(InternalEvent::SelectBranch); return Ok(true); + } else if k + == self.key_config.show_find_commit_text_input + { + self.find_commit.toggle_visible()?; + return Ok(true); + } else if k == self.key_config.focus_find_commit { + self.find_commit.focus(true); + return Ok(true); } } } From 2a5d9a83dd294cad59c570b2bd931f04adf4f155 Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Thu, 4 Feb 2021 00:23:58 +0000 Subject: [PATCH 02/97] Add esc to escape and fix invisible commit details --- src/components/find_commit.rs | 1 + src/tabs/revlog.rs | 3 +++ 2 files changed, 4 insertions(+) diff --git a/src/components/find_commit.rs b/src/components/find_commit.rs index a3bca72267..a3b34044ec 100644 --- a/src/components/find_commit.rs +++ b/src/components/find_commit.rs @@ -66,6 +66,7 @@ impl Component for FindCommitComponent { return Ok(true); } else if e == self.key_config.exit_popup { // Prevent text input closing + self.focus(false); return Ok(true); } } diff --git a/src/tabs/revlog.rs b/src/tabs/revlog.rs index baf3a0176d..9ce5a44273 100644 --- a/src/tabs/revlog.rs +++ b/src/tabs/revlog.rs @@ -218,6 +218,9 @@ impl DrawableComponent for Revlog { self.list.draw(f, log_find_chunks[0])?; self.find_commit.draw(f, log_find_chunks[1])?; self.commit_details.draw(f, chunks[1])?; + } else { + self.list.draw(f, chunks[0])?; + self.commit_details.draw(f, chunks[1])?; } } else { if self.find_commit.is_visible() { From 5cc8e7d934545eb01cdf637934ff700a45ac0643 Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Thu, 4 Feb 2021 00:25:34 +0000 Subject: [PATCH 03/97] Remove unused lines --- src/components/find_commit.rs | 18 +----------------- src/tabs/revlog.rs | 2 -- 2 files changed, 1 insertion(+), 19 deletions(-) diff --git a/src/components/find_commit.rs b/src/components/find_commit.rs index a3b34044ec..c34a46f407 100644 --- a/src/components/find_commit.rs +++ b/src/components/find_commit.rs @@ -14,7 +14,6 @@ use tui::{backend::Backend, layout::Rect, Frame}; pub struct FindCommitComponent { input: TextInputComponent, - branch_ref: Option, queue: Queue, is_focused: bool, visible: bool, @@ -117,29 +116,14 @@ impl FindCommitComponent { &strings::rename_branch_popup_msg(&key_config), true, ); - input_component.show().expect("Will not err"); + input_component.show().expect("Will not error"); input_component.set_should_use_rect(true); Self { queue, input: input_component, - branch_ref: None, key_config, visible: false, is_focused: false, } } - - /// - pub fn open( - &mut self, - branch_ref: String, - cur_name: String, - ) -> Result<()> { - self.branch_ref = None; - self.branch_ref = Some(branch_ref); - self.input.set_text(cur_name); - self.show()?; - - Ok(()) - } } diff --git a/src/tabs/revlog.rs b/src/tabs/revlog.rs index 9ce5a44273..c9e418bdfa 100644 --- a/src/tabs/revlog.rs +++ b/src/tabs/revlog.rs @@ -38,8 +38,6 @@ pub struct Revlog { visible: bool, branch_name: cached::BranchName, key_config: SharedKeyConfig, - show_find_commit_box: bool, - filter_string: Option, } impl Revlog { From be0c76f90ac6273d5c2c1fb738b27e20b02eb7e5 Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Thu, 4 Feb 2021 00:26:35 +0000 Subject: [PATCH 04/97] Fix revlog --- src/tabs/revlog.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/tabs/revlog.rs b/src/tabs/revlog.rs index c9e418bdfa..b6d9a8351f 100644 --- a/src/tabs/revlog.rs +++ b/src/tabs/revlog.rs @@ -71,8 +71,6 @@ impl Revlog { visible: false, branch_name: cached::BranchName::new(CWD), key_config, - show_find_commit_box: true, - filter_string: None, } } From bd5123a9f604d82cdc0b8d08d7b28070f192bc49 Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Thu, 4 Feb 2021 00:34:12 +0000 Subject: [PATCH 05/97] Fix vim keys test --- assets/vim_style_key_config.ron | 3 +++ 1 file changed, 3 insertions(+) diff --git a/assets/vim_style_key_config.ron b/assets/vim_style_key_config.ron index bd193b3e00..72c64cb865 100644 --- a/assets/vim_style_key_config.ron +++ b/assets/vim_style_key_config.ron @@ -70,6 +70,9 @@ push: ( code: Char('p'), modifiers: ( bits: 0,),), fetch: ( code: Char('f'), modifiers: ( bits: 0,),), + show_find_commit_text_input: ( code: Char('s'), modifiers: ( bits: 0,),), + focus_find_commit: ( code: Char('j'), modifiers: ( bits: 3,),), + //removed in 0.11 //tab_toggle_reverse_windows: ( code: BackTab, modifiers: ( bits: 1,),), ) From 3414a05f4fb37358b5d53d99968b170e08d26e13 Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Thu, 4 Feb 2021 00:41:08 +0000 Subject: [PATCH 06/97] Allow searching to happen live rather than press enter --- src/components/find_commit.rs | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/components/find_commit.rs b/src/components/find_commit.rs index c34a46f407..608d50606f 100644 --- a/src/components/find_commit.rs +++ b/src/components/find_commit.rs @@ -55,21 +55,18 @@ impl Component for FindCommitComponent { fn event(&mut self, ev: Event) -> Result { if self.is_visible() { if let Event::Key(e) = ev { - if e == self.key_config.enter { - // Send internal event to filter revlog - self.queue.borrow_mut().push_back( - InternalEvent::FilterLog( - self.input.get_text().to_string(), - ), - ); - return Ok(true); - } else if e == self.key_config.exit_popup { + if e == self.key_config.exit_popup { // Prevent text input closing self.focus(false); return Ok(true); } } if self.input.event(ev)? { + self.queue.borrow_mut().push_back( + InternalEvent::FilterLog( + self.input.get_text().to_string(), + ), + ); return Ok(true); } } From 07f4ec1346a0d94761c76fd7024c3f13f85669a3 Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Thu, 4 Feb 2021 00:50:59 +0000 Subject: [PATCH 07/97] Filter commits in selected_entry --- src/components/commitlist.rs | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/components/commitlist.rs b/src/components/commitlist.rs index 5efae50e04..c7ae84c49c 100644 --- a/src/components/commitlist.rs +++ b/src/components/commitlist.rs @@ -123,9 +123,21 @@ impl CommitList { /// pub fn selected_entry(&self) -> Option<&LogEntry> { - self.items.iter().nth( - self.selection.saturating_sub(self.items.index_offset()), - ) + self.items + .iter() + .filter(|log_entry| { + if let Some(filter_string) = &self.filter_string { + return log_entry + .hash_short + .contains(filter_string) + || log_entry.msg.contains(filter_string); + } + true + }) + .nth( + self.selection + .saturating_sub(self.items.index_offset()), + ) } pub fn copy_entry_hash(&self) -> Result<()> { From e8a6db5c42cdb464415655022bfce576398f53f9 Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Thu, 4 Feb 2021 12:15:59 +0000 Subject: [PATCH 08/97] Fix naming --- src/components/find_commit.rs | 26 +++++++------------------- src/strings.rs | 17 +++++++++++++++++ 2 files changed, 24 insertions(+), 19 deletions(-) diff --git a/src/components/find_commit.rs b/src/components/find_commit.rs index 608d50606f..80c242cc99 100644 --- a/src/components/find_commit.rs +++ b/src/components/find_commit.rs @@ -1,6 +1,6 @@ use super::{ - textinput::TextInputComponent, visibility_blocking, - CommandBlocking, CommandInfo, Component, DrawableComponent, + textinput::TextInputComponent, CommandBlocking, CommandInfo, + Component, DrawableComponent, }; use crate::{ keys::SharedKeyConfig, @@ -34,22 +34,10 @@ impl DrawableComponent for FindCommitComponent { impl Component for FindCommitComponent { fn commands( &self, - out: &mut Vec, - force_all: bool, + _out: &mut Vec, + _force_all: bool, ) -> CommandBlocking { - if self.is_visible() || force_all { - self.input.commands(out, force_all); - - out.push(CommandInfo::new( - strings::commands::rename_branch_confirm_msg( - &self.key_config, - ), - true, - true, - )); - } - - visibility_blocking(self) + CommandBlocking::PassingOn } fn event(&mut self, ev: Event) -> Result { @@ -109,8 +97,8 @@ impl FindCommitComponent { let mut input_component = TextInputComponent::new( theme, key_config.clone(), - &strings::rename_branch_popup_title(&key_config), - &strings::rename_branch_popup_msg(&key_config), + &strings::find_commit_title(&key_config), + &strings::find_commit_msg(&key_config), true, ); input_component.show().expect("Will not error"); diff --git a/src/strings.rs b/src/strings.rs index 617a738c82..8f96d2cfe6 100644 --- a/src/strings.rs +++ b/src/strings.rs @@ -113,6 +113,12 @@ pub fn confirm_msg_delete_branch( pub fn log_title(_key_config: &SharedKeyConfig) -> String { "Commit".to_string() } +pub fn find_commit_title(_key_config: &SharedKeyConfig) -> String { + "Find Commit".to_string() +} +pub fn find_commit_msg(_key_config: &SharedKeyConfig) -> String { + "Search Sha, Author and Message".to_string() +} pub fn tag_commit_popup_title( _key_config: &SharedKeyConfig, ) -> String { @@ -714,6 +720,17 @@ pub mod commands { CMD_GROUP_LOG, ) } + pub fn find_commit(key_config: &SharedKeyConfig) -> CommandText { + CommandText::new( + format!( + "Find Commit [{}]", + key_config + .get_hint(key_config.show_find_commit_text_input), + ), + "find commit", + CMD_GROUP_LOG, + ) + } pub fn tag_commit_confirm_msg( key_config: &SharedKeyConfig, ) -> CommandText { From 95e3a709e00c00a941250fc3a850d831dc56b397 Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Thu, 4 Feb 2021 12:16:32 +0000 Subject: [PATCH 09/97] Remove unused command --- src/strings.rs | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/strings.rs b/src/strings.rs index 8f96d2cfe6..fe42cce9d0 100644 --- a/src/strings.rs +++ b/src/strings.rs @@ -720,17 +720,6 @@ pub mod commands { CMD_GROUP_LOG, ) } - pub fn find_commit(key_config: &SharedKeyConfig) -> CommandText { - CommandText::new( - format!( - "Find Commit [{}]", - key_config - .get_hint(key_config.show_find_commit_text_input), - ), - "find commit", - CMD_GROUP_LOG, - ) - } pub fn tag_commit_confirm_msg( key_config: &SharedKeyConfig, ) -> CommandText { From 709b50133a0c52f2c8e8246c0f8274f48c674b1b Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Thu, 4 Feb 2021 12:30:15 +0000 Subject: [PATCH 10/97] Allow escaping with esc again --- src/components/find_commit.rs | 2 +- src/tabs/revlog.rs | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/components/find_commit.rs b/src/components/find_commit.rs index 80c242cc99..728c81a76e 100644 --- a/src/components/find_commit.rs +++ b/src/components/find_commit.rs @@ -41,7 +41,7 @@ impl Component for FindCommitComponent { } fn event(&mut self, ev: Event) -> Result { - if self.is_visible() { + if self.is_visible() && self.focused() { if let Event::Key(e) = ev { if e == self.key_config.exit_popup { // Prevent text input closing diff --git a/src/tabs/revlog.rs b/src/tabs/revlog.rs index b6d9a8351f..93faa18928 100644 --- a/src/tabs/revlog.rs +++ b/src/tabs/revlog.rs @@ -244,11 +244,10 @@ impl DrawableComponent for Revlog { impl Component for Revlog { fn event(&mut self, ev: Event) -> Result { if self.visible { - let event_used = if self.find_commit.focused() { - self.find_commit.event(ev)? - } else { - self.list.event(ev)? - }; + let mut event_used = self.find_commit.event(ev)?; + if !event_used { + event_used = self.list.event(ev)?; + } if event_used { self.update()?; From b06a716598bbf16324f5cfb32b166da24b0a05fb Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Thu, 4 Feb 2021 12:33:31 +0000 Subject: [PATCH 11/97] Auto set focus on filter commit to true --- src/tabs/revlog.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tabs/revlog.rs b/src/tabs/revlog.rs index 93faa18928..b2d4cee566 100644 --- a/src/tabs/revlog.rs +++ b/src/tabs/revlog.rs @@ -296,6 +296,7 @@ impl Component for Revlog { == self.key_config.show_find_commit_text_input { self.find_commit.toggle_visible()?; + self.find_commit.focus(true); return Ok(true); } else if k == self.key_config.focus_find_commit { self.find_commit.focus(true); From bfbcc9a84b5a49f54a87688b9d0c4c1f36ff53a2 Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Thu, 4 Feb 2021 13:31:53 +0000 Subject: [PATCH 12/97] If filtering log get all commits --- asyncgit/src/revlog.rs | 13 ++++++++---- src/tabs/revlog.rs | 48 +++++++++++++++++++++++++++++++++++------- 2 files changed, 49 insertions(+), 12 deletions(-) diff --git a/asyncgit/src/revlog.rs b/asyncgit/src/revlog.rs index ffb11218b9..c29ed6ad10 100644 --- a/asyncgit/src/revlog.rs +++ b/asyncgit/src/revlog.rs @@ -97,8 +97,11 @@ impl AsyncLog { Ok(false) } - /// - pub fn fetch(&mut self) -> Result { + /// None for amount means fetch the default + pub fn fetch( + &mut self, + amount: Option, + ) -> Result { self.background.store(false, Ordering::Relaxed); if self.is_pending() { @@ -125,6 +128,7 @@ impl AsyncLog { arc_current, arc_background, &sender, + amount.unwrap_or(LIMIT_COUNT), ) .expect("failed to fetch"); @@ -140,14 +144,15 @@ impl AsyncLog { arc_current: Arc>>, arc_background: Arc, sender: &Sender, + amount: usize, ) -> Result<()> { - let mut entries = Vec::with_capacity(LIMIT_COUNT); + let mut entries = Vec::with_capacity(amount); let r = repo(CWD)?; let mut walker = LogWalker::new(&r); loop { entries.clear(); let res_is_err = - walker.read(&mut entries, LIMIT_COUNT).is_err(); + walker.read(&mut entries, amount).is_err(); if !res_is_err { let mut current = arc_current.lock()?; diff --git a/src/tabs/revlog.rs b/src/tabs/revlog.rs index b2d4cee566..df99a1810b 100644 --- a/src/tabs/revlog.rs +++ b/src/tabs/revlog.rs @@ -38,6 +38,8 @@ pub struct Revlog { visible: bool, branch_name: cached::BranchName, key_config: SharedKeyConfig, + is_filtering: bool, + has_all_commits: bool, } impl Revlog { @@ -71,6 +73,8 @@ impl Revlog { visible: false, branch_name: cached::BranchName::new(CWD), key_config, + is_filtering: false, + has_all_commits: false, } } @@ -84,8 +88,13 @@ impl Revlog { /// pub fn update(&mut self) -> Result<()> { if self.visible { - let log_changed = - self.git_log.fetch()? == FetchStatus::Started; + let log_changed = if self.is_filtering { + // If filtering should get all commits + self.git_log.fetch(Some(usize::MAX))? + == FetchStatus::Started + } else { + self.git_log.fetch(None)? == FetchStatus::Started + }; self.list.set_count_total(self.git_log.count()?); @@ -140,15 +149,24 @@ impl Revlog { let want_min = self.list.selection().saturating_sub(SLICE_SIZE / 2); - let commits = sync::get_commits_info( - CWD, - &self.git_log.get_slice(want_min, SLICE_SIZE)?, - self.list.current_size().0.into(), - ); + // If filtering get all commits + let commits = if self.is_filtering { + sync::get_commits_info( + CWD, + &self.git_log.get_slice(0, usize::MAX)?, + self.list.current_size().0.into(), + ) + } else { + sync::get_commits_info( + CWD, + &self.git_log.get_slice(want_min, SLICE_SIZE)?, + self.list.current_size().0.into(), + ) + }; if let Ok(commits) = commits { self.list.items().set_items(want_min, commits); - } + }; Ok(()) } @@ -175,8 +193,22 @@ impl Revlog { pub fn filter(&mut self, filter_by: String) { if filter_by == "" { + self.is_filtering = false; + self.has_all_commits = false; self.list.set_filter(None); } else { + self.is_filtering = true; + // Don't get all the commits again if already have them, + // depening on repo could be expensive to constantly update + if !self.has_all_commits { + if let Err(e) = self.update() { + self.queue.borrow_mut().push_back( + InternalEvent::ShowErrorMsg(e.to_string()), + ); + } + self.has_all_commits = true; + } + self.list.set_filter(Some(filter_by)); } } From 0e671b91e420f01043ee0f05b4bec229317830c5 Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Thu, 4 Feb 2021 13:47:05 +0000 Subject: [PATCH 13/97] Change set total count to update total count in commitlist --- src/components/commitlist.rs | 16 ++++++++++++++-- src/tabs/revlog.rs | 2 +- src/tabs/stashlist.rs | 2 +- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/components/commitlist.rs b/src/components/commitlist.rs index c7ae84c49c..4bc5b10003 100644 --- a/src/components/commitlist.rs +++ b/src/components/commitlist.rs @@ -86,8 +86,20 @@ impl CommitList { } /// - pub fn set_count_total(&mut self, total: usize) { - self.count_total = total; + pub fn update_total_count(&mut self) { + self.count_total = self + .items + .iter() + .filter(|log_entry| { + if let Some(filter_string) = &self.filter_string { + return log_entry + .hash_short + .contains(filter_string) + || log_entry.msg.contains(filter_string); + } + true + }) + .count(); self.selection = cmp::min(self.selection, self.selection_max()); } diff --git a/src/tabs/revlog.rs b/src/tabs/revlog.rs index df99a1810b..71b1001be3 100644 --- a/src/tabs/revlog.rs +++ b/src/tabs/revlog.rs @@ -96,7 +96,7 @@ impl Revlog { self.git_log.fetch(None)? == FetchStatus::Started }; - self.list.set_count_total(self.git_log.count()?); + self.list.update_total_count(); let selection = self.list.selection(); let selection_max = self.list.selection_max(); diff --git a/src/tabs/stashlist.rs b/src/tabs/stashlist.rs index 98f6c0139a..63d285e65a 100644 --- a/src/tabs/stashlist.rs +++ b/src/tabs/stashlist.rs @@ -48,7 +48,7 @@ impl StashList { let commits = sync::get_commits_info(CWD, stashes.as_slice(), 100)?; - self.list.set_count_total(commits.len()); + self.list.update_total_count(); self.list.items().set_items(0, commits); } From 1b1c6ee82e035465f58f5c2555e445de85b37435 Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Thu, 4 Feb 2021 13:48:25 +0000 Subject: [PATCH 14/97] Change key to bring up find commit box to : --- src/keys.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/keys.rs b/src/keys.rs index 55e5d074e6..7e39dbabef 100644 --- a/src/keys.rs +++ b/src/keys.rs @@ -88,7 +88,7 @@ impl Default for KeyConfig { exit_popup: KeyEvent { code: KeyCode::Esc, modifiers: KeyModifiers::empty()}, open_commit: KeyEvent { code: KeyCode::Char('c'), modifiers: KeyModifiers::empty()}, open_commit_editor: KeyEvent { code: KeyCode::Char('e'), modifiers:KeyModifiers::CONTROL}, - show_find_commit_text_input: KeyEvent {code: KeyCode::Char('s'), modifiers: KeyModifiers::empty()}, + show_find_commit_text_input: KeyEvent {code: KeyCode::Char(':'), modifiers: KeyModifiers::empty()}, focus_find_commit: KeyEvent {code: KeyCode::Down, modifiers: KeyModifiers::ALT}, open_help: KeyEvent { code: KeyCode::Char('h'), modifiers: KeyModifiers::empty()}, move_left: KeyEvent { code: KeyCode::Left, modifiers: KeyModifiers::empty()}, From 21904ea6029402d68e1c670ee47f9220f0c3da74 Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Thu, 4 Feb 2021 13:49:44 +0000 Subject: [PATCH 15/97] Don't show char count in find commit component --- src/components/find_commit.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/find_commit.rs b/src/components/find_commit.rs index 728c81a76e..2b54bc677b 100644 --- a/src/components/find_commit.rs +++ b/src/components/find_commit.rs @@ -99,7 +99,7 @@ impl FindCommitComponent { key_config.clone(), &strings::find_commit_title(&key_config), &strings::find_commit_msg(&key_config), - true, + false, ); input_component.show().expect("Will not error"); input_component.set_should_use_rect(true); From 84ca7d268cf26874eb25521118efc22a3c705151 Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Thu, 4 Feb 2021 13:52:20 +0000 Subject: [PATCH 16/97] Also filter by author --- src/components/commitlist.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/components/commitlist.rs b/src/components/commitlist.rs index 4bc5b10003..352992b340 100644 --- a/src/components/commitlist.rs +++ b/src/components/commitlist.rs @@ -95,7 +95,8 @@ impl CommitList { return log_entry .hash_short .contains(filter_string) - || log_entry.msg.contains(filter_string); + || log_entry.msg.contains(filter_string) + || log_entry.author.contains(filter_string); } true }) @@ -142,7 +143,8 @@ impl CommitList { return log_entry .hash_short .contains(filter_string) - || log_entry.msg.contains(filter_string); + || log_entry.msg.contains(filter_string) + || log_entry.author.contains(filter_string); } true }) @@ -297,7 +299,8 @@ impl CommitList { return log_entry .hash_short .contains(filter_string) - || log_entry.msg.contains(filter_string); + || log_entry.msg.contains(filter_string) + || log_entry.author.contains(filter_string); } true }) From ab8770c64ecd34fba672fc77c0cc8b124c0994dd Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Thu, 4 Feb 2021 13:57:52 +0000 Subject: [PATCH 17/97] Add find commit to log commands --- src/strings.rs | 11 +++++++++++ src/tabs/revlog.rs | 6 ++++++ 2 files changed, 17 insertions(+) diff --git a/src/strings.rs b/src/strings.rs index fe42cce9d0..33c0ff3e2c 100644 --- a/src/strings.rs +++ b/src/strings.rs @@ -320,6 +320,17 @@ pub mod commands { CMD_GROUP_LOG, ) } + pub fn find_commit(key_config: &SharedKeyConfig) -> CommandText { + CommandText::new( + format!( + "Find Commit [{}]", + key_config + .get_hint(key_config.show_find_commit_text_input), + ), + "show find commit box to search by sha, author or message", + CMD_GROUP_LOG, + ) + } pub fn diff_home_end( key_config: &SharedKeyConfig, ) -> CommandText { diff --git a/src/tabs/revlog.rs b/src/tabs/revlog.rs index 71b1001be3..79bcfb5b82 100644 --- a/src/tabs/revlog.rs +++ b/src/tabs/revlog.rs @@ -382,6 +382,12 @@ impl Component for Revlog { self.visible || force_all, )); + out.push(CommandInfo::new( + strings::commands::find_commit(&self.key_config), + true, + self.visible || force_all, + )); + visibility_blocking(self) } From 41c121efd4ee74243a74e4420251d542cddd197b Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Thu, 4 Feb 2021 14:06:07 +0000 Subject: [PATCH 18/97] esc on log tab to cancel search --- src/components/find_commit.rs | 5 +++++ src/tabs/revlog.rs | 10 ++++++++++ 2 files changed, 15 insertions(+) diff --git a/src/components/find_commit.rs b/src/components/find_commit.rs index 2b54bc677b..cf766092e7 100644 --- a/src/components/find_commit.rs +++ b/src/components/find_commit.rs @@ -46,6 +46,7 @@ impl Component for FindCommitComponent { if e == self.key_config.exit_popup { // Prevent text input closing self.focus(false); + self.visible = false; return Ok(true); } } @@ -111,4 +112,8 @@ impl FindCommitComponent { is_focused: false, } } + + pub fn clear_input(&mut self) { + self.input.clear(); + } } diff --git a/src/tabs/revlog.rs b/src/tabs/revlog.rs index 79bcfb5b82..ab23c0167d 100644 --- a/src/tabs/revlog.rs +++ b/src/tabs/revlog.rs @@ -333,6 +333,16 @@ impl Component for Revlog { } else if k == self.key_config.focus_find_commit { self.find_commit.focus(true); return Ok(true); + } else if k == self.key_config.exit_popup { + self.filter("".to_string()); + self.find_commit.clear_input(); + if let Err(e) = self.update() { + self.queue.borrow_mut().push_back( + InternalEvent::ShowErrorMsg( + e.to_string(), + ), + ); + } } } } From 56ef6be7fbd21f0ec7ee454da5edd107f18150ca Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Thu, 4 Feb 2021 14:06:59 +0000 Subject: [PATCH 19/97] Change search back to s --- src/keys.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/keys.rs b/src/keys.rs index 7e39dbabef..55e5d074e6 100644 --- a/src/keys.rs +++ b/src/keys.rs @@ -88,7 +88,7 @@ impl Default for KeyConfig { exit_popup: KeyEvent { code: KeyCode::Esc, modifiers: KeyModifiers::empty()}, open_commit: KeyEvent { code: KeyCode::Char('c'), modifiers: KeyModifiers::empty()}, open_commit_editor: KeyEvent { code: KeyCode::Char('e'), modifiers:KeyModifiers::CONTROL}, - show_find_commit_text_input: KeyEvent {code: KeyCode::Char(':'), modifiers: KeyModifiers::empty()}, + show_find_commit_text_input: KeyEvent {code: KeyCode::Char('s'), modifiers: KeyModifiers::empty()}, focus_find_commit: KeyEvent {code: KeyCode::Down, modifiers: KeyModifiers::ALT}, open_help: KeyEvent { code: KeyCode::Char('h'), modifiers: KeyModifiers::empty()}, move_left: KeyEvent { code: KeyCode::Left, modifiers: KeyModifiers::empty()}, From e6dd94a3cdfee02f341d75fac6df555a155513c5 Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Thu, 4 Feb 2021 14:21:23 +0000 Subject: [PATCH 20/97] Also update count when not filtering --- src/tabs/revlog.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tabs/revlog.rs b/src/tabs/revlog.rs index ab23c0167d..85081449ac 100644 --- a/src/tabs/revlog.rs +++ b/src/tabs/revlog.rs @@ -196,8 +196,10 @@ impl Revlog { self.is_filtering = false; self.has_all_commits = false; self.list.set_filter(None); + self.list.update_total_count(); } else { self.is_filtering = true; + self.list.set_filter(Some(filter_by)); // Don't get all the commits again if already have them, // depening on repo could be expensive to constantly update if !self.has_all_commits { @@ -208,8 +210,6 @@ impl Revlog { } self.has_all_commits = true; } - - self.list.set_filter(Some(filter_by)); } } } From b5fdcebe63cd3b3418101cfa5809bd038a0b6f42 Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Thu, 4 Feb 2021 15:42:01 +0000 Subject: [PATCH 21/97] Fix h not working in text input --- src/app.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app.rs b/src/app.rs index 09cf56b4a2..6af3b36e34 100644 --- a/src/app.rs +++ b/src/app.rs @@ -349,11 +349,11 @@ impl App { create_branch_popup, rename_branch_popup, select_branch_popup, - help, revlog, status_tab, stashing_tab, - stashlist_tab + stashlist_tab, + help ] ); From 1ba3b2337df308d28f1604e94238fe77b05d21fb Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Thu, 4 Feb 2021 15:49:26 +0000 Subject: [PATCH 22/97] Change tabs to spaces in keys.rs --- src/keys.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/keys.rs b/src/keys.rs index 55e5d074e6..34e84984b1 100644 --- a/src/keys.rs +++ b/src/keys.rs @@ -87,9 +87,9 @@ impl Default for KeyConfig { exit: KeyEvent { code: KeyCode::Char('c'), modifiers: KeyModifiers::CONTROL}, exit_popup: KeyEvent { code: KeyCode::Esc, modifiers: KeyModifiers::empty()}, open_commit: KeyEvent { code: KeyCode::Char('c'), modifiers: KeyModifiers::empty()}, - open_commit_editor: KeyEvent { code: KeyCode::Char('e'), modifiers:KeyModifiers::CONTROL}, - show_find_commit_text_input: KeyEvent {code: KeyCode::Char('s'), modifiers: KeyModifiers::empty()}, - focus_find_commit: KeyEvent {code: KeyCode::Down, modifiers: KeyModifiers::ALT}, + open_commit_editor: KeyEvent { code: KeyCode::Char('e'), modifiers:KeyModifiers::CONTROL}, + show_find_commit_text_input: KeyEvent {code: KeyCode::Char('s'), modifiers: KeyModifiers::empty()}, + focus_find_commit: KeyEvent {code: KeyCode::Down, modifiers: KeyModifiers::ALT}, open_help: KeyEvent { code: KeyCode::Char('h'), modifiers: KeyModifiers::empty()}, move_left: KeyEvent { code: KeyCode::Left, modifiers: KeyModifiers::empty()}, move_right: KeyEvent { code: KeyCode::Right, modifiers: KeyModifiers::empty()}, From 504e0a960d1a048c950e3cd8070e7b4e187fea54 Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Thu, 4 Feb 2021 19:47:42 +0000 Subject: [PATCH 23/97] Filter commits in commit log rather than commitlist --- asyncgit/src/revlog.rs | 13 ++--- src/components/commitlist.rs | 53 ++------------------ src/tabs/revlog.rs | 95 +++++++++++++++++++----------------- src/tabs/stashlist.rs | 2 +- 4 files changed, 60 insertions(+), 103 deletions(-) diff --git a/asyncgit/src/revlog.rs b/asyncgit/src/revlog.rs index c29ed6ad10..ffb11218b9 100644 --- a/asyncgit/src/revlog.rs +++ b/asyncgit/src/revlog.rs @@ -97,11 +97,8 @@ impl AsyncLog { Ok(false) } - /// None for amount means fetch the default - pub fn fetch( - &mut self, - amount: Option, - ) -> Result { + /// + pub fn fetch(&mut self) -> Result { self.background.store(false, Ordering::Relaxed); if self.is_pending() { @@ -128,7 +125,6 @@ impl AsyncLog { arc_current, arc_background, &sender, - amount.unwrap_or(LIMIT_COUNT), ) .expect("failed to fetch"); @@ -144,15 +140,14 @@ impl AsyncLog { arc_current: Arc>>, arc_background: Arc, sender: &Sender, - amount: usize, ) -> Result<()> { - let mut entries = Vec::with_capacity(amount); + let mut entries = Vec::with_capacity(LIMIT_COUNT); let r = repo(CWD)?; let mut walker = LogWalker::new(&r); loop { entries.clear(); let res_is_err = - walker.read(&mut entries, amount).is_err(); + walker.read(&mut entries, LIMIT_COUNT).is_err(); if !res_is_err { let mut current = arc_current.lock()?; diff --git a/src/components/commitlist.rs b/src/components/commitlist.rs index 352992b340..387ad5c743 100644 --- a/src/components/commitlist.rs +++ b/src/components/commitlist.rs @@ -39,7 +39,6 @@ pub struct CommitList { scroll_top: Cell, theme: SharedTheme, key_config: SharedKeyConfig, - filter_string: Option, } impl CommitList { @@ -61,7 +60,6 @@ impl CommitList { theme, key_config, title: String::from(title), - filter_string: None, } } @@ -86,21 +84,8 @@ impl CommitList { } /// - pub fn update_total_count(&mut self) { - self.count_total = self - .items - .iter() - .filter(|log_entry| { - if let Some(filter_string) = &self.filter_string { - return log_entry - .hash_short - .contains(filter_string) - || log_entry.msg.contains(filter_string) - || log_entry.author.contains(filter_string); - } - true - }) - .count(); + pub fn set_total_count(&mut self, total: usize) { + self.count_total = total; self.selection = cmp::min(self.selection, self.selection_max()); } @@ -129,29 +114,11 @@ impl CommitList { self.tags = Some(tags); } - /// - pub fn set_filter(&mut self, filter_string: Option) { - self.filter_string = filter_string; - } - /// pub fn selected_entry(&self) -> Option<&LogEntry> { - self.items - .iter() - .filter(|log_entry| { - if let Some(filter_string) = &self.filter_string { - return log_entry - .hash_short - .contains(filter_string) - || log_entry.msg.contains(filter_string) - || log_entry.author.contains(filter_string); - } - true - }) - .nth( - self.selection - .saturating_sub(self.items.index_offset()), - ) + self.items.iter().nth( + self.selection.saturating_sub(self.items.index_offset()), + ) } pub fn copy_entry_hash(&self) -> Result<()> { @@ -294,16 +261,6 @@ impl CommitList { for (idx, e) in self .items .iter() - .filter(|log_entry| { - if let Some(filter_string) = &self.filter_string { - return log_entry - .hash_short - .contains(filter_string) - || log_entry.msg.contains(filter_string) - || log_entry.author.contains(filter_string); - } - true - }) .skip(self.scroll_top.get()) .take(height) .enumerate() diff --git a/src/tabs/revlog.rs b/src/tabs/revlog.rs index 85081449ac..345a0f0a5e 100644 --- a/src/tabs/revlog.rs +++ b/src/tabs/revlog.rs @@ -38,8 +38,8 @@ pub struct Revlog { visible: bool, branch_name: cached::BranchName, key_config: SharedKeyConfig, - is_filtering: bool, - has_all_commits: bool, + filter_string: Option, + filter_count: usize, } impl Revlog { @@ -73,8 +73,8 @@ impl Revlog { visible: false, branch_name: cached::BranchName::new(CWD), key_config, - is_filtering: false, - has_all_commits: false, + filter_string: None, + filter_count: 0, } } @@ -88,15 +88,14 @@ impl Revlog { /// pub fn update(&mut self) -> Result<()> { if self.visible { - let log_changed = if self.is_filtering { - // If filtering should get all commits - self.git_log.fetch(Some(usize::MAX))? - == FetchStatus::Started - } else { - self.git_log.fetch(None)? == FetchStatus::Started - }; + let log_changed = + self.git_log.fetch()? == FetchStatus::Started; - self.list.update_total_count(); + if let Some(_) = &self.filter_string { + self.list.set_total_count(self.filter_count); + } else { + self.list.set_total_count(self.git_log.count()?); + } let selection = self.list.selection(); let selection_max = self.list.selection_max(); @@ -149,23 +148,36 @@ impl Revlog { let want_min = self.list.selection().saturating_sub(SLICE_SIZE / 2); - // If filtering get all commits - let commits = if self.is_filtering { - sync::get_commits_info( - CWD, - &self.git_log.get_slice(0, usize::MAX)?, - self.list.current_size().0.into(), - ) - } else { - sync::get_commits_info( - CWD, - &self.git_log.get_slice(want_min, SLICE_SIZE)?, - self.list.current_size().0.into(), - ) - }; - - if let Ok(commits) = commits { - self.list.items().set_items(want_min, commits); + let commits = sync::get_commits_info( + CWD, + &self.git_log.get_slice(want_min, SLICE_SIZE)?, + self.list.current_size().0.into(), + ); + + if let Ok(mut commits) = commits { + if let Some(filter_string) = &self.filter_string { + let filtered_commits = commits + .drain(..) + .filter(|commit_info| { + return commit_info + .id + .get_short_string() + .contains(filter_string) + || commit_info + .message + .contains(filter_string) + || commit_info + .author + .contains(filter_string); + }) + .collect::>(); + self.filter_count = filtered_commits.len(); + self.list + .items() + .set_items(want_min, filtered_commits); + } else { + self.list.items().set_items(want_min, commits); + } }; Ok(()) @@ -193,23 +205,16 @@ impl Revlog { pub fn filter(&mut self, filter_by: String) { if filter_by == "" { - self.is_filtering = false; - self.has_all_commits = false; - self.list.set_filter(None); - self.list.update_total_count(); + self.filter_string = None; + self.list.clear(); } else { - self.is_filtering = true; - self.list.set_filter(Some(filter_by)); - // Don't get all the commits again if already have them, - // depening on repo could be expensive to constantly update - if !self.has_all_commits { - if let Err(e) = self.update() { - self.queue.borrow_mut().push_back( - InternalEvent::ShowErrorMsg(e.to_string()), - ); - } - self.has_all_commits = true; - } + self.filter_string = Some(filter_by); + self.list.clear(); + } + if let Err(e) = self.update() { + self.queue.borrow_mut().push_back( + InternalEvent::ShowErrorMsg(e.to_string()), + ); } } } diff --git a/src/tabs/stashlist.rs b/src/tabs/stashlist.rs index 63d285e65a..d6782c61bb 100644 --- a/src/tabs/stashlist.rs +++ b/src/tabs/stashlist.rs @@ -48,7 +48,7 @@ impl StashList { let commits = sync::get_commits_info(CWD, stashes.as_slice(), 100)?; - self.list.update_total_count(); + self.list.set_total_count(commits.len()); self.list.items().set_items(0, commits); } From 6930d73b31d6a3a94ee9b0a542173161356959e7 Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Thu, 4 Feb 2021 21:31:32 +0000 Subject: [PATCH 24/97] Add extend item list to fetch commit --- asyncgit/src/revlog.rs | 6 +-- src/components/utils/logitems.rs | 10 ++++ src/tabs/revlog.rs | 88 +++++++++++++++++++------------- 3 files changed, 65 insertions(+), 39 deletions(-) diff --git a/asyncgit/src/revlog.rs b/asyncgit/src/revlog.rs index ffb11218b9..a137b6c51f 100644 --- a/asyncgit/src/revlog.rs +++ b/asyncgit/src/revlog.rs @@ -34,8 +34,8 @@ pub struct AsyncLog { background: Arc, } -static LIMIT_COUNT: usize = 3000; -static SLEEP_FOREGROUND: Duration = Duration::from_millis(2); +static LIMIT_COUNT: usize = 5; +static SLEEP_FOREGROUND: Duration = Duration::from_millis(500); static SLEEP_BACKGROUND: Duration = Duration::from_millis(1000); impl AsyncLog { @@ -63,7 +63,7 @@ impl AsyncLog { let list = self.current.lock()?; let list_len = list.len(); let min = start_index.min(list_len); - let max = min + amount; + let max = min.saturating_add(amount); let max = max.min(list_len); Ok(list[min..max].to_vec()) } diff --git a/src/components/utils/logitems.rs b/src/components/utils/logitems.rs index 9fa26be0f9..5af9b2f3c2 100644 --- a/src/components/utils/logitems.rs +++ b/src/components/utils/logitems.rs @@ -62,6 +62,16 @@ impl ItemBatch { self.index_offset = start_index; } + /// + pub fn extend(&mut self, commits: Vec) { + self.items.extend(commits.into_iter().map(LogEntry::from)); + } + + /// + pub fn len(&self) -> usize { + self.items.len() + } + /// returns `true` if we should fetch updated list of items pub fn needs_data(&self, idx: usize, idx_max: usize) -> bool { let want_min = diff --git a/src/tabs/revlog.rs b/src/tabs/revlog.rs index 345a0f0a5e..d313bd7bdf 100644 --- a/src/tabs/revlog.rs +++ b/src/tabs/revlog.rs @@ -40,6 +40,7 @@ pub struct Revlog { key_config: SharedKeyConfig, filter_string: Option, filter_count: usize, + prev_log_count: usize, } impl Revlog { @@ -75,6 +76,7 @@ impl Revlog { key_config, filter_string: None, filter_count: 0, + prev_log_count: 0, } } @@ -91,12 +93,6 @@ impl Revlog { let log_changed = self.git_log.fetch()? == FetchStatus::Started; - if let Some(_) = &self.filter_string { - self.list.set_total_count(self.filter_count); - } else { - self.list.set_total_count(self.git_log.count()?); - } - let selection = self.list.selection(); let selection_max = self.list.selection_max(); if self.list.items().needs_data(selection, selection_max) @@ -105,6 +101,12 @@ impl Revlog { self.fetch_commits()?; } + if let Some(_) = &self.filter_string { + //self.list.set_total_count(self.git_log.count()?); + } else { + self.list.set_total_count(self.git_log.count()?); + } + self.git_tags.request(Duration::from_secs(3), false)?; self.list.set_branch( @@ -148,37 +150,50 @@ impl Revlog { let want_min = self.list.selection().saturating_sub(SLICE_SIZE / 2); - let commits = sync::get_commits_info( - CWD, - &self.git_log.get_slice(want_min, SLICE_SIZE)?, - self.list.current_size().0.into(), - ); - - if let Ok(mut commits) = commits { - if let Some(filter_string) = &self.filter_string { - let filtered_commits = commits - .drain(..) - .filter(|commit_info| { - return commit_info - .id - .get_short_string() - .contains(filter_string) - || commit_info - .message - .contains(filter_string) - || commit_info - .author - .contains(filter_string); - }) - .collect::>(); - self.filter_count = filtered_commits.len(); - self.list - .items() - .set_items(want_min, filtered_commits); - } else { + if self.filter_string.is_none() { + let commits = sync::get_commits_info( + CWD, + &self.git_log.get_slice(want_min, SLICE_SIZE)?, + self.list.current_size().0.into(), + ); + + if let Ok(commits) = commits { self.list.items().set_items(want_min, commits); - } - }; + }; + } else { + let commits = sync::get_commits_info( + CWD, + &self + .git_log + .get_slice(self.prev_log_count, usize::MAX)?, + self.list.current_size().0.into(), + ); + + if let Ok(mut commits) = commits { + if let Some(filter_string) = &self.filter_string { + let filtered_commits = commits + .drain(..) + .filter(|commit_info| { + return commit_info + .id + .get_short_string() + .contains(filter_string) + || commit_info + .message + .contains(filter_string) + || commit_info + .author + .contains(filter_string); + }) + .collect::>(); + self.filter_count += filtered_commits.len(); + self.list.items().extend(filtered_commits); + let total_count = self.filter_count; + self.list.set_total_count(total_count); + } + }; + self.prev_log_count = self.git_log.count()?; + } Ok(()) } @@ -204,6 +219,7 @@ impl Revlog { } pub fn filter(&mut self, filter_by: String) { + self.filter_count = 0; if filter_by == "" { self.filter_string = None; self.list.clear(); From a505c05932998f69c84f5f3be98324d55cec3f24 Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Thu, 4 Feb 2021 22:02:50 +0000 Subject: [PATCH 25/97] Revert to 1ba3b23: Change tabs to spaces in keys.rs --- asyncgit/src/revlog.rs | 19 +++--- src/components/commitlist.rs | 53 ++++++++++++++-- src/components/utils/logitems.rs | 10 --- src/tabs/revlog.rs | 103 ++++++++++++------------------- src/tabs/stashlist.rs | 2 +- 5 files changed, 102 insertions(+), 85 deletions(-) diff --git a/asyncgit/src/revlog.rs b/asyncgit/src/revlog.rs index a137b6c51f..c29ed6ad10 100644 --- a/asyncgit/src/revlog.rs +++ b/asyncgit/src/revlog.rs @@ -34,8 +34,8 @@ pub struct AsyncLog { background: Arc, } -static LIMIT_COUNT: usize = 5; -static SLEEP_FOREGROUND: Duration = Duration::from_millis(500); +static LIMIT_COUNT: usize = 3000; +static SLEEP_FOREGROUND: Duration = Duration::from_millis(2); static SLEEP_BACKGROUND: Duration = Duration::from_millis(1000); impl AsyncLog { @@ -63,7 +63,7 @@ impl AsyncLog { let list = self.current.lock()?; let list_len = list.len(); let min = start_index.min(list_len); - let max = min.saturating_add(amount); + let max = min + amount; let max = max.min(list_len); Ok(list[min..max].to_vec()) } @@ -97,8 +97,11 @@ impl AsyncLog { Ok(false) } - /// - pub fn fetch(&mut self) -> Result { + /// None for amount means fetch the default + pub fn fetch( + &mut self, + amount: Option, + ) -> Result { self.background.store(false, Ordering::Relaxed); if self.is_pending() { @@ -125,6 +128,7 @@ impl AsyncLog { arc_current, arc_background, &sender, + amount.unwrap_or(LIMIT_COUNT), ) .expect("failed to fetch"); @@ -140,14 +144,15 @@ impl AsyncLog { arc_current: Arc>>, arc_background: Arc, sender: &Sender, + amount: usize, ) -> Result<()> { - let mut entries = Vec::with_capacity(LIMIT_COUNT); + let mut entries = Vec::with_capacity(amount); let r = repo(CWD)?; let mut walker = LogWalker::new(&r); loop { entries.clear(); let res_is_err = - walker.read(&mut entries, LIMIT_COUNT).is_err(); + walker.read(&mut entries, amount).is_err(); if !res_is_err { let mut current = arc_current.lock()?; diff --git a/src/components/commitlist.rs b/src/components/commitlist.rs index 387ad5c743..352992b340 100644 --- a/src/components/commitlist.rs +++ b/src/components/commitlist.rs @@ -39,6 +39,7 @@ pub struct CommitList { scroll_top: Cell, theme: SharedTheme, key_config: SharedKeyConfig, + filter_string: Option, } impl CommitList { @@ -60,6 +61,7 @@ impl CommitList { theme, key_config, title: String::from(title), + filter_string: None, } } @@ -84,8 +86,21 @@ impl CommitList { } /// - pub fn set_total_count(&mut self, total: usize) { - self.count_total = total; + pub fn update_total_count(&mut self) { + self.count_total = self + .items + .iter() + .filter(|log_entry| { + if let Some(filter_string) = &self.filter_string { + return log_entry + .hash_short + .contains(filter_string) + || log_entry.msg.contains(filter_string) + || log_entry.author.contains(filter_string); + } + true + }) + .count(); self.selection = cmp::min(self.selection, self.selection_max()); } @@ -114,11 +129,29 @@ impl CommitList { self.tags = Some(tags); } + /// + pub fn set_filter(&mut self, filter_string: Option) { + self.filter_string = filter_string; + } + /// pub fn selected_entry(&self) -> Option<&LogEntry> { - self.items.iter().nth( - self.selection.saturating_sub(self.items.index_offset()), - ) + self.items + .iter() + .filter(|log_entry| { + if let Some(filter_string) = &self.filter_string { + return log_entry + .hash_short + .contains(filter_string) + || log_entry.msg.contains(filter_string) + || log_entry.author.contains(filter_string); + } + true + }) + .nth( + self.selection + .saturating_sub(self.items.index_offset()), + ) } pub fn copy_entry_hash(&self) -> Result<()> { @@ -261,6 +294,16 @@ impl CommitList { for (idx, e) in self .items .iter() + .filter(|log_entry| { + if let Some(filter_string) = &self.filter_string { + return log_entry + .hash_short + .contains(filter_string) + || log_entry.msg.contains(filter_string) + || log_entry.author.contains(filter_string); + } + true + }) .skip(self.scroll_top.get()) .take(height) .enumerate() diff --git a/src/components/utils/logitems.rs b/src/components/utils/logitems.rs index 5af9b2f3c2..9fa26be0f9 100644 --- a/src/components/utils/logitems.rs +++ b/src/components/utils/logitems.rs @@ -62,16 +62,6 @@ impl ItemBatch { self.index_offset = start_index; } - /// - pub fn extend(&mut self, commits: Vec) { - self.items.extend(commits.into_iter().map(LogEntry::from)); - } - - /// - pub fn len(&self) -> usize { - self.items.len() - } - /// returns `true` if we should fetch updated list of items pub fn needs_data(&self, idx: usize, idx_max: usize) -> bool { let want_min = diff --git a/src/tabs/revlog.rs b/src/tabs/revlog.rs index d313bd7bdf..85081449ac 100644 --- a/src/tabs/revlog.rs +++ b/src/tabs/revlog.rs @@ -38,9 +38,8 @@ pub struct Revlog { visible: bool, branch_name: cached::BranchName, key_config: SharedKeyConfig, - filter_string: Option, - filter_count: usize, - prev_log_count: usize, + is_filtering: bool, + has_all_commits: bool, } impl Revlog { @@ -74,9 +73,8 @@ impl Revlog { visible: false, branch_name: cached::BranchName::new(CWD), key_config, - filter_string: None, - filter_count: 0, - prev_log_count: 0, + is_filtering: false, + has_all_commits: false, } } @@ -90,8 +88,15 @@ impl Revlog { /// pub fn update(&mut self) -> Result<()> { if self.visible { - let log_changed = - self.git_log.fetch()? == FetchStatus::Started; + let log_changed = if self.is_filtering { + // If filtering should get all commits + self.git_log.fetch(Some(usize::MAX))? + == FetchStatus::Started + } else { + self.git_log.fetch(None)? == FetchStatus::Started + }; + + self.list.update_total_count(); let selection = self.list.selection(); let selection_max = self.list.selection_max(); @@ -101,12 +106,6 @@ impl Revlog { self.fetch_commits()?; } - if let Some(_) = &self.filter_string { - //self.list.set_total_count(self.git_log.count()?); - } else { - self.list.set_total_count(self.git_log.count()?); - } - self.git_tags.request(Duration::from_secs(3), false)?; self.list.set_branch( @@ -150,50 +149,24 @@ impl Revlog { let want_min = self.list.selection().saturating_sub(SLICE_SIZE / 2); - if self.filter_string.is_none() { - let commits = sync::get_commits_info( + // If filtering get all commits + let commits = if self.is_filtering { + sync::get_commits_info( CWD, - &self.git_log.get_slice(want_min, SLICE_SIZE)?, + &self.git_log.get_slice(0, usize::MAX)?, self.list.current_size().0.into(), - ); - - if let Ok(commits) = commits { - self.list.items().set_items(want_min, commits); - }; + ) } else { - let commits = sync::get_commits_info( + sync::get_commits_info( CWD, - &self - .git_log - .get_slice(self.prev_log_count, usize::MAX)?, + &self.git_log.get_slice(want_min, SLICE_SIZE)?, self.list.current_size().0.into(), - ); + ) + }; - if let Ok(mut commits) = commits { - if let Some(filter_string) = &self.filter_string { - let filtered_commits = commits - .drain(..) - .filter(|commit_info| { - return commit_info - .id - .get_short_string() - .contains(filter_string) - || commit_info - .message - .contains(filter_string) - || commit_info - .author - .contains(filter_string); - }) - .collect::>(); - self.filter_count += filtered_commits.len(); - self.list.items().extend(filtered_commits); - let total_count = self.filter_count; - self.list.set_total_count(total_count); - } - }; - self.prev_log_count = self.git_log.count()?; - } + if let Ok(commits) = commits { + self.list.items().set_items(want_min, commits); + }; Ok(()) } @@ -219,18 +192,24 @@ impl Revlog { } pub fn filter(&mut self, filter_by: String) { - self.filter_count = 0; if filter_by == "" { - self.filter_string = None; - self.list.clear(); + self.is_filtering = false; + self.has_all_commits = false; + self.list.set_filter(None); + self.list.update_total_count(); } else { - self.filter_string = Some(filter_by); - self.list.clear(); - } - if let Err(e) = self.update() { - self.queue.borrow_mut().push_back( - InternalEvent::ShowErrorMsg(e.to_string()), - ); + self.is_filtering = true; + self.list.set_filter(Some(filter_by)); + // Don't get all the commits again if already have them, + // depening on repo could be expensive to constantly update + if !self.has_all_commits { + if let Err(e) = self.update() { + self.queue.borrow_mut().push_back( + InternalEvent::ShowErrorMsg(e.to_string()), + ); + } + self.has_all_commits = true; + } } } } diff --git a/src/tabs/stashlist.rs b/src/tabs/stashlist.rs index d6782c61bb..63d285e65a 100644 --- a/src/tabs/stashlist.rs +++ b/src/tabs/stashlist.rs @@ -48,7 +48,7 @@ impl StashList { let commits = sync::get_commits_info(CWD, stashes.as_slice(), 100)?; - self.list.set_total_count(commits.len()); + self.list.update_total_count(); self.list.items().set_items(0, commits); } From db48ec5d5c1561070514da5e45829e9c1b2ea72b Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Tue, 9 Feb 2021 13:42:14 +0000 Subject: [PATCH 26/97] Implement async filterer for commits --- asyncgit/src/revlog.rs | 12 +- asyncgit/src/sync/commits_info.rs | 2 +- src/components/commitlist.rs | 17 +- src/components/mod.rs | 1 + src/components/utils/async_commit_filter.rs | 228 ++++++++++++++++++++ src/components/utils/mod.rs | 1 + src/tabs/revlog.rs | 53 +++-- src/tabs/stashlist.rs | 2 +- 8 files changed, 273 insertions(+), 43 deletions(-) create mode 100644 src/components/utils/async_commit_filter.rs diff --git a/asyncgit/src/revlog.rs b/asyncgit/src/revlog.rs index c29ed6ad10..921000b372 100644 --- a/asyncgit/src/revlog.rs +++ b/asyncgit/src/revlog.rs @@ -27,6 +27,7 @@ pub enum FetchStatus { } /// +#[derive(Clone)] pub struct AsyncLog { current: Arc>>, sender: Sender, @@ -34,7 +35,7 @@ pub struct AsyncLog { background: Arc, } -static LIMIT_COUNT: usize = 3000; +static LIMIT_COUNT: usize = 5; static SLEEP_FOREGROUND: Duration = Duration::from_millis(2); static SLEEP_BACKGROUND: Duration = Duration::from_millis(1000); @@ -97,11 +98,8 @@ impl AsyncLog { Ok(false) } - /// None for amount means fetch the default - pub fn fetch( - &mut self, - amount: Option, - ) -> Result { + /// + pub fn fetch(&mut self) -> Result { self.background.store(false, Ordering::Relaxed); if self.is_pending() { @@ -128,7 +126,7 @@ impl AsyncLog { arc_current, arc_background, &sender, - amount.unwrap_or(LIMIT_COUNT), + LIMIT_COUNT, ) .expect("failed to fetch"); diff --git a/asyncgit/src/sync/commits_info.rs b/asyncgit/src/sync/commits_info.rs index 5d3ad8209c..c2d2661935 100644 --- a/asyncgit/src/sync/commits_info.rs +++ b/asyncgit/src/sync/commits_info.rs @@ -43,7 +43,7 @@ impl From for CommitId { } /// -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct CommitInfo { /// pub message: String, diff --git a/src/components/commitlist.rs b/src/components/commitlist.rs index 352992b340..c3b3d5d850 100644 --- a/src/components/commitlist.rs +++ b/src/components/commitlist.rs @@ -86,21 +86,8 @@ impl CommitList { } /// - pub fn update_total_count(&mut self) { - self.count_total = self - .items - .iter() - .filter(|log_entry| { - if let Some(filter_string) = &self.filter_string { - return log_entry - .hash_short - .contains(filter_string) - || log_entry.msg.contains(filter_string) - || log_entry.author.contains(filter_string); - } - true - }) - .count(); + pub fn update_total_count(&mut self, count: usize) { + self.count_total = count; self.selection = cmp::min(self.selection, self.selection_max()); } diff --git a/src/components/mod.rs b/src/components/mod.rs index 21511d38f3..fb8520e84f 100644 --- a/src/components/mod.rs +++ b/src/components/mod.rs @@ -41,6 +41,7 @@ pub use select_branch::SelectBranchComponent; pub use stashmsg::StashMsgComponent; pub use tag_commit::TagCommitComponent; pub use textinput::{InputType, TextInputComponent}; +pub use utils::async_commit_filter; pub use utils::filetree::FileTreeItemKind; use crate::ui::style::Theme; diff --git a/src/components/utils/async_commit_filter.rs b/src/components/utils/async_commit_filter.rs new file mode 100644 index 0000000000..98009a1c69 --- /dev/null +++ b/src/components/utils/async_commit_filter.rs @@ -0,0 +1,228 @@ +use anyhow::Result; +use asyncgit::{ + sync::{self, CommitInfo}, + AsyncLog, CWD, +}; +use bitflags::bitflags; +use crossbeam_channel::{Sender, TryRecvError}; +use std::{ + sync::{ + atomic::{AtomicBool, AtomicUsize, Ordering}, + Arc, Mutex, + }, + thread, + time::Duration, +}; + +const FILTER_SLEEP_DURATION: Duration = Duration::from_millis(2); +const FILTER_SLEEP_DURATION_FAILED_LOCK: Duration = + Duration::from_millis(5); +const SLICE_SIZE: usize = 1200; + +bitflags! { + pub struct FilterBy: u32 { + const SHA = 0b0000_0001; + const AUTHOR = 0b0000_0010; + const MESSAGE = 0b0000_0100; + } +} + +pub struct AsyncCommitFilterer { + git_log: AsyncLog, + filter_string: String, + filter_by: FilterBy, + filtered_commits: Arc>>, + filter_count: Arc, + filter_finished: Arc, + filter_thread_sender: Option>, + message_length_limit: usize, +} + +impl AsyncCommitFilterer { + pub fn new( + git_log: AsyncLog, + message_length_limit: usize, + ) -> Self { + Self { + filter_string: "".to_string(), + filter_by: FilterBy::empty(), + git_log: git_log, + filtered_commits: Arc::new(Mutex::new(Vec::new())), + filter_count: Arc::new(AtomicUsize::new(0)), + filter_finished: Arc::new(AtomicBool::new(false)), + filter_thread_sender: None, + message_length_limit, + } + } + + pub fn clear( + &mut self, + ) -> Result< + (), + std::sync::PoisonError< + std::sync::MutexGuard>, + >, + > { + self.filtered_commits.lock()?.clear(); + Ok(()) + } + + pub fn filter( + vec_commit_info: &mut Vec, + filter_string: &String, + filter_by: FilterBy, + ) -> Vec { + vec_commit_info + .drain(..) + .filter(|ci| { + if filter_by.contains(FilterBy::SHA) { + if filter_string.contains(&ci.id.to_string()) { + return true; + } + } + if filter_by.contains(FilterBy::AUTHOR) { + if filter_string.contains(&ci.author) { + return true; + } + } + if filter_by.contains(FilterBy::MESSAGE) { + if filter_string.contains(&ci.message) { + return true; + } + } + false + }) + .collect::>() + } + + pub fn start_filter( + &mut self, + filter_string: String, + filter_by: FilterBy, + ) -> Result<()> { + self.clear().expect("Can't fail unless app crashes"); + self.filter_string = filter_string.clone(); + self.filter_by = filter_by.clone(); + + let filtered_commits = Arc::clone(&self.filtered_commits); + let filter_count = Arc::clone(&self.filter_count); + let async_log = self.git_log.clone(); + let filter_finished = Arc::clone(&self.filter_finished); + let message_length_limit = self.message_length_limit; + + let (tx, rx) = crossbeam_channel::unbounded(); + + self.filter_thread_sender = Some(tx); + + thread::spawn(move || { + let mut cur_index: usize = 0; + loop { + match rx.try_recv() { + Ok(_) | Err(TryRecvError::Disconnected) => { + break; + } + Err(TryRecvError::Empty) => { + // Get the git_log and start filtering through it + match async_log + .get_slice(cur_index, SLICE_SIZE) + { + Ok(ids) => match sync::get_commits_info( + CWD, + &ids, + message_length_limit, + ) { + Ok(mut v) => { + if v.len() == 1 + && async_log.is_pending() + { + // Assume finished if log not pending and only 1 commit + filter_finished.store( + true, + Ordering::Relaxed, + ); + break; + } + + let mut filtered = Self::filter( + &mut v, + &filter_string, + filter_by, + ); + filter_count.fetch_add( + filtered.len(), + Ordering::Relaxed, + ); + match filtered_commits.lock() { + Ok(mut fc) => { + fc.append(&mut filtered); + drop(fc); + cur_index += SLICE_SIZE; + thread::sleep( + FILTER_SLEEP_DURATION, + ); + } + Err(_) => { + // Failed to lock `filtered_commits` + thread::sleep( + FILTER_SLEEP_DURATION_FAILED_LOCK, + ); + } + } + } + Err(_) => { + // Failed to get commit info + thread::sleep( + FILTER_SLEEP_DURATION_FAILED_LOCK, + ); + } + }, + Err(_) => { + // Failed to get slice + thread::sleep( + FILTER_SLEEP_DURATION_FAILED_LOCK, + ); + } + } + } + } + } + }); + Ok(()) + } + + /// Stop the filter, is is possible to restart from this stage by calling restart + pub fn stop_filter(&self) -> Result<(), ()> { + if let Some(sender) = &self.filter_thread_sender { + return sender.send(true).map_err(|_| ()); + } + Err(()) + } + + /// Use if the next item to be filtered is a substring of the previous item. + /// This then only searches through the previous list + //pub fn continue_filter(&mut self, _s: String) -> Result<()> { + // Ok(()) + //} + + pub fn get_filter_items( + &mut self, + start: usize, + amount: usize, + ) -> Result< + Vec, + std::sync::PoisonError< + std::sync::MutexGuard>, + >, + > { + let fc = self.filtered_commits.lock()?; + let len = fc.len(); + let min = start.min(len); + let max = min + amount; + let max = max.min(len); + Ok(fc[min..max].to_vec()) + } + + pub fn count(&self) -> usize { + self.filter_count.load(Ordering::Relaxed) + } +} diff --git a/src/components/utils/mod.rs b/src/components/utils/mod.rs index a3fe5652c9..81fc380716 100644 --- a/src/components/utils/mod.rs +++ b/src/components/utils/mod.rs @@ -1,5 +1,6 @@ use chrono::{DateTime, Local, NaiveDateTime, Utc}; +pub mod async_commit_filter; pub mod filetree; pub mod logitems; pub mod statustree; diff --git a/src/tabs/revlog.rs b/src/tabs/revlog.rs index 85081449ac..bbfcffac73 100644 --- a/src/tabs/revlog.rs +++ b/src/tabs/revlog.rs @@ -1,5 +1,6 @@ use crate::{ components::{ + async_commit_filter::{AsyncCommitFilterer, FilterBy}, visibility_blocking, CommandBlocking, CommandInfo, CommitDetailsComponent, CommitList, Component, DrawableComponent, FindCommitComponent, @@ -32,6 +33,7 @@ pub struct Revlog { commit_details: CommitDetailsComponent, list: CommitList, find_commit: FindCommitComponent, + async_filter: AsyncCommitFilterer, git_log: AsyncLog, git_tags: AsyncTags, queue: Queue, @@ -39,7 +41,6 @@ pub struct Revlog { branch_name: cached::BranchName, key_config: SharedKeyConfig, is_filtering: bool, - has_all_commits: bool, } impl Revlog { @@ -50,6 +51,7 @@ impl Revlog { theme: SharedTheme, key_config: SharedKeyConfig, ) -> Self { + let log = AsyncLog::new(sender); Self { queue: queue.clone(), commit_details: CommitDetailsComponent::new( @@ -68,13 +70,13 @@ impl Revlog { theme, key_config.clone(), ), - git_log: AsyncLog::new(sender), + async_filter: AsyncCommitFilterer::new(log.clone(), 10), + git_log: log, git_tags: AsyncTags::new(sender), visible: false, branch_name: cached::BranchName::new(CWD), key_config, is_filtering: false, - has_all_commits: false, } } @@ -88,15 +90,15 @@ impl Revlog { /// pub fn update(&mut self) -> Result<()> { if self.visible { - let log_changed = if self.is_filtering { - // If filtering should get all commits - self.git_log.fetch(Some(usize::MAX))? - == FetchStatus::Started + let mut log_changed = false; + if self.is_filtering { + self.list + .update_total_count(self.async_filter.count()); } else { - self.git_log.fetch(None)? == FetchStatus::Started - }; - - self.list.update_total_count(); + log_changed = + self.git_log.fetch()? == FetchStatus::Started; + self.list.update_total_count(self.git_log.count()?); + } let selection = self.list.selection(); let selection_max = self.list.selection_max(); @@ -149,19 +151,19 @@ impl Revlog { let want_min = self.list.selection().saturating_sub(SLICE_SIZE / 2); - // If filtering get all commits let commits = if self.is_filtering { - sync::get_commits_info( - CWD, - &self.git_log.get_slice(0, usize::MAX)?, - self.list.current_size().0.into(), - ) + self.async_filter + .get_filter_items(want_min, SLICE_SIZE) + .map_err(|_| { + anyhow::anyhow!("Failed to get filtered items") + }) } else { sync::get_commits_info( CWD, &self.git_log.get_slice(want_min, SLICE_SIZE)?, self.list.current_size().0.into(), ) + .map_err(|e| anyhow::anyhow!(e.to_string())) }; if let Ok(commits) = commits { @@ -192,11 +194,24 @@ impl Revlog { } pub fn filter(&mut self, filter_by: String) { + if filter_by == "" { + self.async_filter + .start_filter(filter_by, FilterBy::all()) + .expect("TODO: REMOVE EXPECT"); + self.is_filtering = false; + } else { + self.async_filter.stop_filter(); + self.is_filtering = true; + } + + /* if filter_by == "" { self.is_filtering = false; self.has_all_commits = false; self.list.set_filter(None); - self.list.update_total_count(); + self.list.update_total_count( + self.git_log.count().expect("Some"), + ); } else { self.is_filtering = true; self.list.set_filter(Some(filter_by)); @@ -210,7 +225,7 @@ impl Revlog { } self.has_all_commits = true; } - } + }*/ } } diff --git a/src/tabs/stashlist.rs b/src/tabs/stashlist.rs index 63d285e65a..d1016c0cf5 100644 --- a/src/tabs/stashlist.rs +++ b/src/tabs/stashlist.rs @@ -48,7 +48,7 @@ impl StashList { let commits = sync::get_commits_info(CWD, stashes.as_slice(), 100)?; - self.list.update_total_count(); + self.list.update_total_count(commits.len()); self.list.items().set_items(0, commits); } From 7c9fc66696a61f3e9e111de2403d3696b1d985f3 Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Tue, 9 Feb 2021 13:43:06 +0000 Subject: [PATCH 27/97] Remove filter code from commitlist --- src/components/commitlist.rs | 36 +++--------------------------------- 1 file changed, 3 insertions(+), 33 deletions(-) diff --git a/src/components/commitlist.rs b/src/components/commitlist.rs index c3b3d5d850..d8b44cb17a 100644 --- a/src/components/commitlist.rs +++ b/src/components/commitlist.rs @@ -39,7 +39,6 @@ pub struct CommitList { scroll_top: Cell, theme: SharedTheme, key_config: SharedKeyConfig, - filter_string: Option, } impl CommitList { @@ -61,7 +60,6 @@ impl CommitList { theme, key_config, title: String::from(title), - filter_string: None, } } @@ -116,29 +114,11 @@ impl CommitList { self.tags = Some(tags); } - /// - pub fn set_filter(&mut self, filter_string: Option) { - self.filter_string = filter_string; - } - /// pub fn selected_entry(&self) -> Option<&LogEntry> { - self.items - .iter() - .filter(|log_entry| { - if let Some(filter_string) = &self.filter_string { - return log_entry - .hash_short - .contains(filter_string) - || log_entry.msg.contains(filter_string) - || log_entry.author.contains(filter_string); - } - true - }) - .nth( - self.selection - .saturating_sub(self.items.index_offset()), - ) + self.items.iter().nth( + self.selection.saturating_sub(self.items.index_offset()), + ) } pub fn copy_entry_hash(&self) -> Result<()> { @@ -281,16 +261,6 @@ impl CommitList { for (idx, e) in self .items .iter() - .filter(|log_entry| { - if let Some(filter_string) = &self.filter_string { - return log_entry - .hash_short - .contains(filter_string) - || log_entry.msg.contains(filter_string) - || log_entry.author.contains(filter_string); - } - true - }) .skip(self.scroll_top.get()) .take(height) .enumerate() From 9d3985dce469a0b06a6f404cd3eff83b578eebc3 Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Tue, 9 Feb 2021 13:51:42 +0000 Subject: [PATCH 28/97] Shutdown filter thread before starting another filter --- src/components/utils/async_commit_filter.rs | 7 +++++++ src/tabs/revlog.rs | 4 +++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/components/utils/async_commit_filter.rs b/src/components/utils/async_commit_filter.rs index 98009a1c69..5f438fc3ad 100644 --- a/src/components/utils/async_commit_filter.rs +++ b/src/components/utils/async_commit_filter.rs @@ -103,6 +103,13 @@ impl AsyncCommitFilterer { self.clear().expect("Can't fail unless app crashes"); self.filter_string = filter_string.clone(); self.filter_by = filter_by.clone(); + if let Some(sender) = &self.filter_thread_sender { + return sender.send(true).map_err(|_| { + anyhow::anyhow!( + "Could not send shutdown to filter thread" + ) + }); + } let filtered_commits = Arc::clone(&self.filtered_commits); let filter_count = Arc::clone(&self.filter_count); diff --git a/src/tabs/revlog.rs b/src/tabs/revlog.rs index bbfcffac73..4137cd3755 100644 --- a/src/tabs/revlog.rs +++ b/src/tabs/revlog.rs @@ -200,7 +200,9 @@ impl Revlog { .expect("TODO: REMOVE EXPECT"); self.is_filtering = false; } else { - self.async_filter.stop_filter(); + self.async_filter.stop_filter().expect( + "TODO: Could not stop filter, it's out of control!!!", + ); self.is_filtering = true; } From 47df534dc2253964e843dcba200dde995e033509 Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Tue, 9 Feb 2021 15:03:26 +0000 Subject: [PATCH 29/97] Working async commit filter --- src/components/utils/async_commit_filter.rs | 41 ++++++++++++++++----- src/tabs/revlog.rs | 30 +++++++++------ 2 files changed, 50 insertions(+), 21 deletions(-) diff --git a/src/components/utils/async_commit_filter.rs b/src/components/utils/async_commit_filter.rs index 5f438fc3ad..d5578a33e1 100644 --- a/src/components/utils/async_commit_filter.rs +++ b/src/components/utils/async_commit_filter.rs @@ -1,7 +1,7 @@ use anyhow::Result; use asyncgit::{ sync::{self, CommitInfo}, - AsyncLog, CWD, + AsyncLog, AsyncNotification, CWD, }; use bitflags::bitflags; use crossbeam_channel::{Sender, TryRecvError}; @@ -27,6 +27,12 @@ bitflags! { } } +#[derive(PartialEq)] +pub enum FilterStatus { + Filtering, + Finished, +} + pub struct AsyncCommitFilterer { git_log: AsyncLog, filter_string: String, @@ -35,12 +41,14 @@ pub struct AsyncCommitFilterer { filter_count: Arc, filter_finished: Arc, filter_thread_sender: Option>, + sender: Sender, message_length_limit: usize, } impl AsyncCommitFilterer { pub fn new( git_log: AsyncLog, + sender: &Sender, message_length_limit: usize, ) -> Self { Self { @@ -51,6 +59,7 @@ impl AsyncCommitFilterer { filter_count: Arc::new(AtomicUsize::new(0)), filter_finished: Arc::new(AtomicBool::new(false)), filter_thread_sender: None, + sender: sender.clone(), message_length_limit, } } @@ -76,17 +85,17 @@ impl AsyncCommitFilterer { .drain(..) .filter(|ci| { if filter_by.contains(FilterBy::SHA) { - if filter_string.contains(&ci.id.to_string()) { + if ci.id.to_string().contains(filter_string) { return true; } } if filter_by.contains(FilterBy::AUTHOR) { - if filter_string.contains(&ci.author) { + if ci.author.contains(filter_string) { return true; } } if filter_by.contains(FilterBy::MESSAGE) { - if filter_string.contains(&ci.message) { + if ci.message.contains(filter_string) { return true; } } @@ -103,13 +112,15 @@ impl AsyncCommitFilterer { self.clear().expect("Can't fail unless app crashes"); self.filter_string = filter_string.clone(); self.filter_by = filter_by.clone(); - if let Some(sender) = &self.filter_thread_sender { + self.filter_count.store(0, Ordering::Relaxed); + self.stop_filter().expect("Can't fail"); + /*if let Some(sender) = &self.filter_thread_sender { return sender.send(true).map_err(|_| { anyhow::anyhow!( "Could not send shutdown to filter thread" ) }); - } + }*/ let filtered_commits = Arc::clone(&self.filtered_commits); let filter_count = Arc::clone(&self.filter_count); @@ -120,6 +131,7 @@ impl AsyncCommitFilterer { let (tx, rx) = crossbeam_channel::unbounded(); self.filter_thread_sender = Some(tx); + let async_app_sender = self.sender.clone(); thread::spawn(move || { let mut cur_index: usize = 0; @@ -140,7 +152,7 @@ impl AsyncCommitFilterer { ) { Ok(mut v) => { if v.len() == 1 - && async_log.is_pending() + && !async_log.is_pending() { // Assume finished if log not pending and only 1 commit filter_finished.store( @@ -164,6 +176,7 @@ impl AsyncCommitFilterer { fc.append(&mut filtered); drop(fc); cur_index += SLICE_SIZE; + async_app_sender.send(AsyncNotification::Log).expect("error sending"); thread::sleep( FILTER_SLEEP_DURATION, ); @@ -200,9 +213,11 @@ impl AsyncCommitFilterer { /// Stop the filter, is is possible to restart from this stage by calling restart pub fn stop_filter(&self) -> Result<(), ()> { if let Some(sender) = &self.filter_thread_sender { - return sender.send(true).map_err(|_| ()); + match sender.try_send(true) { + Ok(_) | Err(_) => {} + }; } - Err(()) + Ok(()) } /// Use if the next item to be filtered is a substring of the previous item. @@ -232,4 +247,12 @@ impl AsyncCommitFilterer { pub fn count(&self) -> usize { self.filter_count.load(Ordering::Relaxed) } + + pub fn fetch(&self) -> FilterStatus { + if self.filter_finished.load(Ordering::Relaxed) { + FilterStatus::Finished + } else { + FilterStatus::Filtering + } + } } diff --git a/src/tabs/revlog.rs b/src/tabs/revlog.rs index 4137cd3755..76ac8c3815 100644 --- a/src/tabs/revlog.rs +++ b/src/tabs/revlog.rs @@ -1,6 +1,8 @@ use crate::{ components::{ - async_commit_filter::{AsyncCommitFilterer, FilterBy}, + async_commit_filter::{ + AsyncCommitFilterer, FilterBy, FilterStatus, + }, visibility_blocking, CommandBlocking, CommandInfo, CommitDetailsComponent, CommitList, Component, DrawableComponent, FindCommitComponent, @@ -70,7 +72,11 @@ impl Revlog { theme, key_config.clone(), ), - async_filter: AsyncCommitFilterer::new(log.clone(), 10), + async_filter: AsyncCommitFilterer::new( + log.clone(), + sender, + 10, + ), git_log: log, git_tags: AsyncTags::new(sender), visible: false, @@ -90,15 +96,14 @@ impl Revlog { /// pub fn update(&mut self) -> Result<()> { if self.visible { - let mut log_changed = false; - if self.is_filtering { + let log_changed = if self.is_filtering { self.list .update_total_count(self.async_filter.count()); + self.async_filter.fetch() == FilterStatus::Filtering } else { - log_changed = - self.git_log.fetch()? == FetchStatus::Started; self.list.update_total_count(self.git_log.count()?); - } + self.git_log.fetch()? == FetchStatus::Started + }; let selection = self.list.selection(); let selection_max = self.list.selection_max(); @@ -195,16 +200,17 @@ impl Revlog { pub fn filter(&mut self, filter_by: String) { if filter_by == "" { - self.async_filter - .start_filter(filter_by, FilterBy::all()) - .expect("TODO: REMOVE EXPECT"); - self.is_filtering = false; - } else { self.async_filter.stop_filter().expect( "TODO: Could not stop filter, it's out of control!!!", ); + self.is_filtering = false; + } else { + self.async_filter + .start_filter(filter_by, FilterBy::all()) + .expect("TODO: REMOVE EXPECT"); self.is_filtering = true; } + self.update(); /* if filter_by == "" { From b2d2f8253a2b69020d78a64a09c804c71a28934d Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Tue, 9 Feb 2021 16:37:23 +0000 Subject: [PATCH 30/97] Fix async filter thread terminating upon finishing search --- src/components/utils/async_commit_filter.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/utils/async_commit_filter.rs b/src/components/utils/async_commit_filter.rs index d5578a33e1..7239c0c8fb 100644 --- a/src/components/utils/async_commit_filter.rs +++ b/src/components/utils/async_commit_filter.rs @@ -14,9 +14,9 @@ use std::{ time::Duration, }; -const FILTER_SLEEP_DURATION: Duration = Duration::from_millis(2); +const FILTER_SLEEP_DURATION: Duration = Duration::from_millis(5); const FILTER_SLEEP_DURATION_FAILED_LOCK: Duration = - Duration::from_millis(5); + Duration::from_millis(10); const SLICE_SIZE: usize = 1200; bitflags! { @@ -151,10 +151,10 @@ impl AsyncCommitFilterer { message_length_limit, ) { Ok(mut v) => { - if v.len() == 1 + if v.len() <= 1 && !async_log.is_pending() { - // Assume finished if log not pending and only 1 commit + // Assume finished if log not pending and either 0 or 1 commit filter_finished.store( true, Ordering::Relaxed, From 70ca71a49402e597a0718ab0b9ced02e24312ef3 Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Tue, 9 Feb 2021 17:39:04 +0000 Subject: [PATCH 31/97] Set commit length when retrieving filtered commits --- asyncgit/src/sync/commits_info.rs | 3 +- asyncgit/src/sync/mod.rs | 4 ++- src/components/utils/async_commit_filter.rs | 37 ++++++++++----------- src/tabs/revlog.rs | 15 ++++----- 4 files changed, 30 insertions(+), 29 deletions(-) diff --git a/asyncgit/src/sync/commits_info.rs b/asyncgit/src/sync/commits_info.rs index c2d2661935..d94378e9d5 100644 --- a/asyncgit/src/sync/commits_info.rs +++ b/asyncgit/src/sync/commits_info.rs @@ -107,7 +107,8 @@ pub fn get_message( } #[inline] -fn limit_str(s: &str, limit: usize) -> &str { +/// +pub fn limit_str(s: &str, limit: usize) -> &str { if let Some(first) = s.lines().next() { let mut limit = limit.min(first.len()); while !first.is_char_boundary(limit) { diff --git a/asyncgit/src/sync/mod.rs b/asyncgit/src/sync/mod.rs index 618039b86a..f6553cb09a 100644 --- a/asyncgit/src/sync/mod.rs +++ b/asyncgit/src/sync/mod.rs @@ -32,7 +32,9 @@ pub use commit_details::{ get_commit_details, CommitDetails, CommitMessage, }; pub use commit_files::get_commit_files; -pub use commits_info::{get_commits_info, CommitId, CommitInfo}; +pub use commits_info::{ + get_commits_info, limit_str, CommitId, CommitInfo, +}; pub use diff::get_diff_commit; pub use hooks::{ hooks_commit_msg, hooks_post_commit, hooks_pre_commit, HookResult, diff --git a/src/components/utils/async_commit_filter.rs b/src/components/utils/async_commit_filter.rs index 7239c0c8fb..ba6e8febe7 100644 --- a/src/components/utils/async_commit_filter.rs +++ b/src/components/utils/async_commit_filter.rs @@ -1,6 +1,6 @@ use anyhow::Result; use asyncgit::{ - sync::{self, CommitInfo}, + sync::{self, limit_str, CommitInfo}, AsyncLog, AsyncNotification, CWD, }; use bitflags::bitflags; @@ -14,7 +14,7 @@ use std::{ time::Duration, }; -const FILTER_SLEEP_DURATION: Duration = Duration::from_millis(5); +const FILTER_SLEEP_DURATION: Duration = Duration::from_millis(500); const FILTER_SLEEP_DURATION_FAILED_LOCK: Duration = Duration::from_millis(10); const SLICE_SIZE: usize = 1200; @@ -42,14 +42,12 @@ pub struct AsyncCommitFilterer { filter_finished: Arc, filter_thread_sender: Option>, sender: Sender, - message_length_limit: usize, } impl AsyncCommitFilterer { pub fn new( git_log: AsyncLog, sender: &Sender, - message_length_limit: usize, ) -> Self { Self { filter_string: "".to_string(), @@ -60,7 +58,6 @@ impl AsyncCommitFilterer { filter_finished: Arc::new(AtomicBool::new(false)), filter_thread_sender: None, sender: sender.clone(), - message_length_limit, } } @@ -109,24 +106,18 @@ impl AsyncCommitFilterer { filter_string: String, filter_by: FilterBy, ) -> Result<()> { + self.stop_filter(); + self.clear().expect("Can't fail unless app crashes"); self.filter_string = filter_string.clone(); self.filter_by = filter_by.clone(); self.filter_count.store(0, Ordering::Relaxed); - self.stop_filter().expect("Can't fail"); - /*if let Some(sender) = &self.filter_thread_sender { - return sender.send(true).map_err(|_| { - anyhow::anyhow!( - "Could not send shutdown to filter thread" - ) - }); - }*/ let filtered_commits = Arc::clone(&self.filtered_commits); let filter_count = Arc::clone(&self.filter_count); let async_log = self.git_log.clone(); let filter_finished = Arc::clone(&self.filter_finished); - let message_length_limit = self.message_length_limit; + filter_finished.store(false, Ordering::Relaxed); let (tx, rx) = crossbeam_channel::unbounded(); @@ -148,7 +139,7 @@ impl AsyncCommitFilterer { Ok(ids) => match sync::get_commits_info( CWD, &ids, - message_length_limit, + usize::MAX, ) { Ok(mut v) => { if v.len() <= 1 @@ -210,14 +201,16 @@ impl AsyncCommitFilterer { Ok(()) } - /// Stop the filter, is is possible to restart from this stage by calling restart - pub fn stop_filter(&self) -> Result<(), ()> { + /// Stop the filter if one was running, otherwise does nothing. + /// Is it possible to restart from this stage by calling restart + pub fn stop_filter(&self) { + // Any error this gives can be safely ignored, + // it will send if reciever exists, otherwise does nothing if let Some(sender) = &self.filter_thread_sender { match sender.try_send(true) { Ok(_) | Err(_) => {} }; } - Ok(()) } /// Use if the next item to be filtered is a substring of the previous item. @@ -230,6 +223,7 @@ impl AsyncCommitFilterer { &mut self, start: usize, amount: usize, + message_length_limit: usize, ) -> Result< Vec, std::sync::PoisonError< @@ -241,7 +235,12 @@ impl AsyncCommitFilterer { let min = start.min(len); let max = min + amount; let max = max.min(len); - Ok(fc[min..max].to_vec()) + let mut commits_requested = fc[min..max].to_vec(); + for c in &mut commits_requested { + c.message = limit_str(&c.message, message_length_limit) + .to_string(); + } + Ok(commits_requested) } pub fn count(&self) -> usize { diff --git a/src/tabs/revlog.rs b/src/tabs/revlog.rs index 76ac8c3815..a8f89fd25f 100644 --- a/src/tabs/revlog.rs +++ b/src/tabs/revlog.rs @@ -75,7 +75,6 @@ impl Revlog { async_filter: AsyncCommitFilterer::new( log.clone(), sender, - 10, ), git_log: log, git_tags: AsyncTags::new(sender), @@ -158,10 +157,12 @@ impl Revlog { let commits = if self.is_filtering { self.async_filter - .get_filter_items(want_min, SLICE_SIZE) - .map_err(|_| { - anyhow::anyhow!("Failed to get filtered items") - }) + .get_filter_items( + want_min, + SLICE_SIZE, + self.list.current_size().0.into(), + ) + .map_err(|e| anyhow::anyhow!(e.to_string())) } else { sync::get_commits_info( CWD, @@ -200,9 +201,7 @@ impl Revlog { pub fn filter(&mut self, filter_by: String) { if filter_by == "" { - self.async_filter.stop_filter().expect( - "TODO: Could not stop filter, it's out of control!!!", - ); + self.async_filter.stop_filter(); self.is_filtering = false; } else { self.async_filter From cd938f6060052bc985602e1dffce1c1e81eee8b8 Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Tue, 9 Feb 2021 17:47:06 +0000 Subject: [PATCH 32/97] Finish filter if 0 recieved rather than <=1 --- src/components/utils/async_commit_filter.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/utils/async_commit_filter.rs b/src/components/utils/async_commit_filter.rs index ba6e8febe7..0e69cfac19 100644 --- a/src/components/utils/async_commit_filter.rs +++ b/src/components/utils/async_commit_filter.rs @@ -142,10 +142,10 @@ impl AsyncCommitFilterer { usize::MAX, ) { Ok(mut v) => { - if v.len() <= 1 + if v.len() == 0 && !async_log.is_pending() { - // Assume finished if log not pending and either 0 or 1 commit + // Assume finished if log not pending and 0 recieved filter_finished.store( true, Ordering::Relaxed, From fdf2fad14def295c194a38a40e1f8c15e5eedcbd Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Tue, 9 Feb 2021 18:03:59 +0000 Subject: [PATCH 33/97] Make search case insensitive --- src/components/utils/async_commit_filter.rs | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/components/utils/async_commit_filter.rs b/src/components/utils/async_commit_filter.rs index 0e69cfac19..5e89dbcf10 100644 --- a/src/components/utils/async_commit_filter.rs +++ b/src/components/utils/async_commit_filter.rs @@ -82,17 +82,30 @@ impl AsyncCommitFilterer { .drain(..) .filter(|ci| { if filter_by.contains(FilterBy::SHA) { - if ci.id.to_string().contains(filter_string) { + if ci + .id + .to_string() + .to_lowercase() + .contains(&filter_string.to_lowercase()) + { return true; } } if filter_by.contains(FilterBy::AUTHOR) { - if ci.author.contains(filter_string) { + if ci + .author + .to_lowercase() + .contains(&filter_string.to_lowercase()) + { return true; } } if filter_by.contains(FilterBy::MESSAGE) { - if ci.message.contains(filter_string) { + if ci + .message + .to_lowercase() + .contains(&filter_string.to_lowercase()) + { return true; } } From d3abde62f7986538d7c48a28e0df574f92225953 Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Tue, 9 Feb 2021 18:07:46 +0000 Subject: [PATCH 34/97] Fix clippy warning --- src/app.rs | 2 +- src/tabs/revlog.rs | 37 ++++--------------------------------- 2 files changed, 5 insertions(+), 34 deletions(-) diff --git a/src/app.rs b/src/app.rs index 6af3b36e34..2b20802fbb 100644 --- a/src/app.rs +++ b/src/app.rs @@ -538,7 +538,7 @@ impl App { flags.insert(NeedsUpdate::ALL) } InternalEvent::FilterLog(string_to_fliter_by) => { - self.revlog.filter(string_to_fliter_by) + self.revlog.filter(string_to_fliter_by)? } }; diff --git a/src/tabs/revlog.rs b/src/tabs/revlog.rs index a8f89fd25f..d292e93c62 100644 --- a/src/tabs/revlog.rs +++ b/src/tabs/revlog.rs @@ -199,7 +199,7 @@ impl Revlog { }) } - pub fn filter(&mut self, filter_by: String) { + pub fn filter(&mut self, filter_by: String) -> Result<()> { if filter_by == "" { self.async_filter.stop_filter(); self.is_filtering = false; @@ -209,30 +209,7 @@ impl Revlog { .expect("TODO: REMOVE EXPECT"); self.is_filtering = true; } - self.update(); - - /* - if filter_by == "" { - self.is_filtering = false; - self.has_all_commits = false; - self.list.set_filter(None); - self.list.update_total_count( - self.git_log.count().expect("Some"), - ); - } else { - self.is_filtering = true; - self.list.set_filter(Some(filter_by)); - // Don't get all the commits again if already have them, - // depening on repo could be expensive to constantly update - if !self.has_all_commits { - if let Err(e) = self.update() { - self.queue.borrow_mut().push_back( - InternalEvent::ShowErrorMsg(e.to_string()), - ); - } - self.has_all_commits = true; - } - }*/ + self.update() } } @@ -356,15 +333,9 @@ impl Component for Revlog { self.find_commit.focus(true); return Ok(true); } else if k == self.key_config.exit_popup { - self.filter("".to_string()); + self.filter("".to_string())?; self.find_commit.clear_input(); - if let Err(e) = self.update() { - self.queue.borrow_mut().push_back( - InternalEvent::ShowErrorMsg( - e.to_string(), - ), - ); - } + self.update()?; } } } From ebbe26e8d6c308b22d38b27a56e1e0523cd75f80 Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Tue, 9 Feb 2021 23:11:20 +0000 Subject: [PATCH 35/97] Add a filter function using : in search to filter by sha, author or message --- src/tabs/revlog.rs | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/src/tabs/revlog.rs b/src/tabs/revlog.rs index d292e93c62..68f11a36f1 100644 --- a/src/tabs/revlog.rs +++ b/src/tabs/revlog.rs @@ -199,13 +199,44 @@ impl Revlog { }) } + fn get_what_to_filter_by( + filter_by_str: String, + ) -> (String, FilterBy) { + if let Some(':') = filter_by_str.chars().nth(0) { + let mut to_filter_by = FilterBy::empty(); + let mut split_str = + filter_by_str.split(' ').collect::>(); + if split_str.len() == 1 { + split_str.push(""); + } + let first = split_str[0]; + if first.contains('s') { + to_filter_by = to_filter_by | FilterBy::SHA; + } + if first.contains('a') { + to_filter_by = to_filter_by | FilterBy::AUTHOR; + } + if first.contains('m') { + to_filter_by = to_filter_by | FilterBy::MESSAGE; + } + if to_filter_by.is_empty() { + to_filter_by = FilterBy::all(); + } + + return (split_str[1..].join(" "), to_filter_by); + } + (filter_by_str, FilterBy::all()) + } + pub fn filter(&mut self, filter_by: String) -> Result<()> { if filter_by == "" { self.async_filter.stop_filter(); self.is_filtering = false; } else { + let (search_string_processed, to_filter_by) = + Self::get_what_to_filter_by(filter_by); self.async_filter - .start_filter(filter_by, FilterBy::all()) + .start_filter(search_string_processed, to_filter_by) .expect("TODO: REMOVE EXPECT"); self.is_filtering = true; } From 16da8a0f78ffc4405529bd5c9fa1f623704e4130 Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Tue, 9 Feb 2021 23:20:22 +0000 Subject: [PATCH 36/97] Remove expect --- src/tabs/revlog.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tabs/revlog.rs b/src/tabs/revlog.rs index 68f11a36f1..eb56b323ed 100644 --- a/src/tabs/revlog.rs +++ b/src/tabs/revlog.rs @@ -237,7 +237,7 @@ impl Revlog { Self::get_what_to_filter_by(filter_by); self.async_filter .start_filter(search_string_processed, to_filter_by) - .expect("TODO: REMOVE EXPECT"); + .map_err(|e| anyhow::anyhow!(e.to_string()))?; self.is_filtering = true; } self.update() From 0114cbf215c1b05d5cb287ff4883f3717771cf1b Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Tue, 9 Feb 2021 23:21:58 +0000 Subject: [PATCH 37/97] Change async filter sleep durations --- src/components/utils/async_commit_filter.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/utils/async_commit_filter.rs b/src/components/utils/async_commit_filter.rs index 5e89dbcf10..0c1aaf04f0 100644 --- a/src/components/utils/async_commit_filter.rs +++ b/src/components/utils/async_commit_filter.rs @@ -14,9 +14,9 @@ use std::{ time::Duration, }; -const FILTER_SLEEP_DURATION: Duration = Duration::from_millis(500); +const FILTER_SLEEP_DURATION: Duration = Duration::from_millis(20); const FILTER_SLEEP_DURATION_FAILED_LOCK: Duration = - Duration::from_millis(10); + Duration::from_millis(500); const SLICE_SIZE: usize = 1200; bitflags! { From b4cf79889e7ee87c5d34e8b32224b43395452a65 Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Tue, 9 Feb 2021 23:52:21 +0000 Subject: [PATCH 38/97] Trim whitespace --- src/app.rs | 2 +- src/tabs/revlog.rs | 12 ++++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/app.rs b/src/app.rs index 2b20802fbb..54abba9d4d 100644 --- a/src/app.rs +++ b/src/app.rs @@ -538,7 +538,7 @@ impl App { flags.insert(NeedsUpdate::ALL) } InternalEvent::FilterLog(string_to_fliter_by) => { - self.revlog.filter(string_to_fliter_by)? + self.revlog.filter(&string_to_fliter_by)? } }; diff --git a/src/tabs/revlog.rs b/src/tabs/revlog.rs index eb56b323ed..6d8ee76412 100644 --- a/src/tabs/revlog.rs +++ b/src/tabs/revlog.rs @@ -223,18 +223,22 @@ impl Revlog { to_filter_by = FilterBy::all(); } - return (split_str[1..].join(" "), to_filter_by); + return ( + split_str[1..].join(" ").trim().to_string(), + to_filter_by, + ); } (filter_by_str, FilterBy::all()) } - pub fn filter(&mut self, filter_by: String) -> Result<()> { + pub fn filter(&mut self, filter_by: &str) -> Result<()> { + let trimmed_string = filter_by.trim().to_string(); if filter_by == "" { self.async_filter.stop_filter(); self.is_filtering = false; } else { let (search_string_processed, to_filter_by) = - Self::get_what_to_filter_by(filter_by); + Self::get_what_to_filter_by(trimmed_string); self.async_filter .start_filter(search_string_processed, to_filter_by) .map_err(|e| anyhow::anyhow!(e.to_string()))?; @@ -364,7 +368,7 @@ impl Component for Revlog { self.find_commit.focus(true); return Ok(true); } else if k == self.key_config.exit_popup { - self.filter("".to_string())?; + self.filter("")?; self.find_commit.clear_input(); self.update()?; } From 0be484058e95c5acea046b4d342105b4ddca340f Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Wed, 10 Feb 2021 00:33:06 +0000 Subject: [PATCH 39/97] Allow union filtering with || --- src/components/utils/async_commit_filter.rs | 91 ++++++++++----------- src/tabs/revlog.rs | 66 ++++++++------- 2 files changed, 81 insertions(+), 76 deletions(-) diff --git a/src/components/utils/async_commit_filter.rs b/src/components/utils/async_commit_filter.rs index 0c1aaf04f0..3207d9d306 100644 --- a/src/components/utils/async_commit_filter.rs +++ b/src/components/utils/async_commit_filter.rs @@ -35,8 +35,7 @@ pub enum FilterStatus { pub struct AsyncCommitFilterer { git_log: AsyncLog, - filter_string: String, - filter_by: FilterBy, + filter_strings: Vec<(String, FilterBy)>, filtered_commits: Arc>>, filter_count: Arc, filter_finished: Arc, @@ -50,8 +49,7 @@ impl AsyncCommitFilterer { sender: &Sender, ) -> Self { Self { - filter_string: "".to_string(), - filter_by: FilterBy::empty(), + filter_strings: Vec::new(), git_log: git_log, filtered_commits: Arc::new(Mutex::new(Vec::new())), filter_count: Arc::new(AtomicUsize::new(0)), @@ -74,56 +72,58 @@ impl AsyncCommitFilterer { } pub fn filter( - vec_commit_info: &mut Vec, - filter_string: &String, - filter_by: FilterBy, + vec_commit_info: Vec, + filter_strings: &Vec<(String, FilterBy)>, ) -> Vec { - vec_commit_info - .drain(..) - .filter(|ci| { - if filter_by.contains(FilterBy::SHA) { - if ci - .id - .to_string() - .to_lowercase() - .contains(&filter_string.to_lowercase()) - { - return true; + let mut commit_infos = vec_commit_info; + for (s, filter) in filter_strings { + commit_infos = commit_infos + .drain(..) + .filter(|ci| { + if filter.contains(FilterBy::SHA) { + if ci + .id + .to_string() + .to_lowercase() + .contains(&s.to_lowercase()) + { + return true; + } } - } - if filter_by.contains(FilterBy::AUTHOR) { - if ci - .author - .to_lowercase() - .contains(&filter_string.to_lowercase()) - { - return true; + + if filter.contains(FilterBy::AUTHOR) { + if ci + .author + .to_lowercase() + .contains(&s.to_lowercase()) + { + return true; + } } - } - if filter_by.contains(FilterBy::MESSAGE) { - if ci - .message - .to_lowercase() - .contains(&filter_string.to_lowercase()) - { - return true; + if filter.contains(FilterBy::MESSAGE) { + if ci + .message + .to_lowercase() + .contains(&s.to_lowercase()) + { + return true; + } } - } - false - }) - .collect::>() + false + }) + .collect::>() + } + return commit_infos; } pub fn start_filter( &mut self, - filter_string: String, - filter_by: FilterBy, + filter_strings: Vec<(String, FilterBy)>, ) -> Result<()> { self.stop_filter(); self.clear().expect("Can't fail unless app crashes"); - self.filter_string = filter_string.clone(); - self.filter_by = filter_by.clone(); + self.filter_strings = filter_strings.clone(); self.filter_count.store(0, Ordering::Relaxed); let filtered_commits = Arc::clone(&self.filtered_commits); @@ -154,7 +154,7 @@ impl AsyncCommitFilterer { &ids, usize::MAX, ) { - Ok(mut v) => { + Ok(v) => { if v.len() == 0 && !async_log.is_pending() { @@ -167,9 +167,8 @@ impl AsyncCommitFilterer { } let mut filtered = Self::filter( - &mut v, - &filter_string, - filter_by, + v, + &filter_strings, ); filter_count.fetch_add( filtered.len(), diff --git a/src/tabs/revlog.rs b/src/tabs/revlog.rs index 6d8ee76412..cd111b4a82 100644 --- a/src/tabs/revlog.rs +++ b/src/tabs/revlog.rs @@ -200,35 +200,41 @@ impl Revlog { } fn get_what_to_filter_by( - filter_by_str: String, - ) -> (String, FilterBy) { - if let Some(':') = filter_by_str.chars().nth(0) { - let mut to_filter_by = FilterBy::empty(); - let mut split_str = - filter_by_str.split(' ').collect::>(); - if split_str.len() == 1 { - split_str.push(""); - } - let first = split_str[0]; - if first.contains('s') { - to_filter_by = to_filter_by | FilterBy::SHA; - } - if first.contains('a') { - to_filter_by = to_filter_by | FilterBy::AUTHOR; - } - if first.contains('m') { - to_filter_by = to_filter_by | FilterBy::MESSAGE; - } - if to_filter_by.is_empty() { - to_filter_by = FilterBy::all(); - } + filter_by_str: &str, + ) -> Vec<(String, FilterBy)> { + let mut search_vec = vec![]; + for split_sub in filter_by_str.split("||") { + if let Some(':') = split_sub.chars().nth(0) { + let mut to_filter_by = FilterBy::empty(); + let mut split_str = + split_sub.split(' ').collect::>(); + if split_str.len() == 1 { + split_str.push(""); + } + let first = split_str[0]; + if first.contains('s') { + to_filter_by = to_filter_by | FilterBy::SHA; + } + if first.contains('a') { + to_filter_by = to_filter_by | FilterBy::AUTHOR; + } + if first.contains('m') { + to_filter_by = to_filter_by | FilterBy::MESSAGE; + } + if to_filter_by.is_empty() { + to_filter_by = FilterBy::all(); + } - return ( - split_str[1..].join(" ").trim().to_string(), - to_filter_by, - ); + search_vec.push(( + split_str[1..].join(" ").trim().to_string(), + to_filter_by, + )); + } else { + search_vec + .push((split_sub.to_string(), FilterBy::all())) + } } - (filter_by_str, FilterBy::all()) + return search_vec; } pub fn filter(&mut self, filter_by: &str) -> Result<()> { @@ -237,10 +243,10 @@ impl Revlog { self.async_filter.stop_filter(); self.is_filtering = false; } else { - let (search_string_processed, to_filter_by) = - Self::get_what_to_filter_by(trimmed_string); + let filter_strings = + Self::get_what_to_filter_by(&trimmed_string); self.async_filter - .start_filter(search_string_processed, to_filter_by) + .start_filter(filter_strings) .map_err(|e| anyhow::anyhow!(e.to_string()))?; self.is_filtering = true; } From 05c734c45ceee088f8183d18e4c8ad8d21965a68 Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Wed, 10 Feb 2021 18:33:09 +0000 Subject: [PATCH 40/97] Use rayon core for thread and add work pending --- src/components/utils/async_commit_filter.rs | 13 +++++++++---- src/tabs/revlog.rs | 1 + 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/components/utils/async_commit_filter.rs b/src/components/utils/async_commit_filter.rs index 3207d9d306..fc46f24ee8 100644 --- a/src/components/utils/async_commit_filter.rs +++ b/src/components/utils/async_commit_filter.rs @@ -14,10 +14,10 @@ use std::{ time::Duration, }; -const FILTER_SLEEP_DURATION: Duration = Duration::from_millis(20); +const FILTER_SLEEP_DURATION: Duration = Duration::from_millis(2000); const FILTER_SLEEP_DURATION_FAILED_LOCK: Duration = Duration::from_millis(500); -const SLICE_SIZE: usize = 1200; +const SLICE_SIZE: usize = 100; bitflags! { pub struct FilterBy: u32 { @@ -53,12 +53,16 @@ impl AsyncCommitFilterer { git_log: git_log, filtered_commits: Arc::new(Mutex::new(Vec::new())), filter_count: Arc::new(AtomicUsize::new(0)), - filter_finished: Arc::new(AtomicBool::new(false)), + filter_finished: Arc::new(AtomicBool::new(true)), filter_thread_sender: None, sender: sender.clone(), } } + pub fn is_pending(&self) -> bool { + self.fetch() == FilterStatus::Filtering + } + pub fn clear( &mut self, ) -> Result< @@ -137,7 +141,7 @@ impl AsyncCommitFilterer { self.filter_thread_sender = Some(tx); let async_app_sender = self.sender.clone(); - thread::spawn(move || { + rayon_core::spawn(move || { let mut cur_index: usize = 0; loop { match rx.try_recv() { @@ -223,6 +227,7 @@ impl AsyncCommitFilterer { Ok(_) | Err(_) => {} }; } + self.filter_finished.store(true, Ordering::Relaxed); } /// Use if the next item to be filtered is a substring of the previous item. diff --git a/src/tabs/revlog.rs b/src/tabs/revlog.rs index cd111b4a82..f5d19dcc84 100644 --- a/src/tabs/revlog.rs +++ b/src/tabs/revlog.rs @@ -89,6 +89,7 @@ impl Revlog { pub fn any_work_pending(&self) -> bool { self.git_log.is_pending() || self.git_tags.is_pending() + || self.async_filter.is_pending() || self.commit_details.any_work_pending() } From bf0d6ea86e2658571b7c04ed07e864d0812c4b46 Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Wed, 10 Feb 2021 19:18:40 +0000 Subject: [PATCH 41/97] Fix sleep timings so filter runs quicker --- src/components/utils/async_commit_filter.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/utils/async_commit_filter.rs b/src/components/utils/async_commit_filter.rs index fc46f24ee8..41520171e4 100644 --- a/src/components/utils/async_commit_filter.rs +++ b/src/components/utils/async_commit_filter.rs @@ -14,10 +14,10 @@ use std::{ time::Duration, }; -const FILTER_SLEEP_DURATION: Duration = Duration::from_millis(2000); +const FILTER_SLEEP_DURATION: Duration = Duration::from_millis(10); const FILTER_SLEEP_DURATION_FAILED_LOCK: Duration = Duration::from_millis(500); -const SLICE_SIZE: usize = 100; +const SLICE_SIZE: usize = 1200; bitflags! { pub struct FilterBy: u32 { From 933d4c53e0a6fb7df704d92633246428c8d3e055 Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Wed, 10 Feb 2021 19:35:01 +0000 Subject: [PATCH 42/97] Store state locally for quicker return if no work pending --- src/components/utils/async_commit_filter.rs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/components/utils/async_commit_filter.rs b/src/components/utils/async_commit_filter.rs index 41520171e4..9f515c10b1 100644 --- a/src/components/utils/async_commit_filter.rs +++ b/src/components/utils/async_commit_filter.rs @@ -39,6 +39,7 @@ pub struct AsyncCommitFilterer { filtered_commits: Arc>>, filter_count: Arc, filter_finished: Arc, + filter_finished_local: bool, filter_thread_sender: Option>, sender: Sender, } @@ -54,13 +55,20 @@ impl AsyncCommitFilterer { filtered_commits: Arc::new(Mutex::new(Vec::new())), filter_count: Arc::new(AtomicUsize::new(0)), filter_finished: Arc::new(AtomicBool::new(true)), + filter_finished_local: true, filter_thread_sender: None, sender: sender.clone(), } } - pub fn is_pending(&self) -> bool { - self.fetch() == FilterStatus::Filtering + pub fn is_pending(&mut self) -> bool { + self.filter_finished_local + || if self.fetch() == FilterStatus::Finished { + self.filter_finished_local = true; + true + } else { + false + } } pub fn clear( @@ -219,7 +227,7 @@ impl AsyncCommitFilterer { /// Stop the filter if one was running, otherwise does nothing. /// Is it possible to restart from this stage by calling restart - pub fn stop_filter(&self) { + pub fn stop_filter(&mut self) { // Any error this gives can be safely ignored, // it will send if reciever exists, otherwise does nothing if let Some(sender) = &self.filter_thread_sender { @@ -227,6 +235,7 @@ impl AsyncCommitFilterer { Ok(_) | Err(_) => {} }; } + self.filter_finished_local = false; self.filter_finished.store(true, Ordering::Relaxed); } From 9578e8d23843a1e4eb8845878fb67eaa28fefb07 Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Wed, 10 Feb 2021 20:04:20 +0000 Subject: [PATCH 43/97] Use refcell to fix is_pending --- src/components/utils/async_commit_filter.rs | 25 +++++++++++---------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/components/utils/async_commit_filter.rs b/src/components/utils/async_commit_filter.rs index 9f515c10b1..45081d155d 100644 --- a/src/components/utils/async_commit_filter.rs +++ b/src/components/utils/async_commit_filter.rs @@ -6,6 +6,7 @@ use asyncgit::{ use bitflags::bitflags; use crossbeam_channel::{Sender, TryRecvError}; use std::{ + cell::RefCell, sync::{ atomic::{AtomicBool, AtomicUsize, Ordering}, Arc, Mutex, @@ -39,7 +40,7 @@ pub struct AsyncCommitFilterer { filtered_commits: Arc>>, filter_count: Arc, filter_finished: Arc, - filter_finished_local: bool, + is_pending_local: RefCell, filter_thread_sender: Option>, sender: Sender, } @@ -55,20 +56,20 @@ impl AsyncCommitFilterer { filtered_commits: Arc::new(Mutex::new(Vec::new())), filter_count: Arc::new(AtomicUsize::new(0)), filter_finished: Arc::new(AtomicBool::new(true)), - filter_finished_local: true, + is_pending_local: RefCell::new(true), filter_thread_sender: None, sender: sender.clone(), } } - pub fn is_pending(&mut self) -> bool { - self.filter_finished_local - || if self.fetch() == FilterStatus::Finished { - self.filter_finished_local = true; - true - } else { - false - } + pub fn is_pending(&self) -> bool { + let mut b = self.is_pending_local.borrow_mut(); + if *b { + *b = self.fetch() == FilterStatus::Filtering; + *b + } else { + false + } } pub fn clear( @@ -227,7 +228,7 @@ impl AsyncCommitFilterer { /// Stop the filter if one was running, otherwise does nothing. /// Is it possible to restart from this stage by calling restart - pub fn stop_filter(&mut self) { + pub fn stop_filter(&self) { // Any error this gives can be safely ignored, // it will send if reciever exists, otherwise does nothing if let Some(sender) = &self.filter_thread_sender { @@ -235,7 +236,7 @@ impl AsyncCommitFilterer { Ok(_) | Err(_) => {} }; } - self.filter_finished_local = false; + self.is_pending_local.replace(true); self.filter_finished.store(true, Ordering::Relaxed); } From e9eeb53be2723b715457a3842fd18df3f8a06520 Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Thu, 11 Feb 2021 10:55:15 +0000 Subject: [PATCH 44/97] Allow &&(intersection) and ||(union) filtering --- src/components/utils/async_commit_filter.rs | 102 ++++++++++++-------- src/tabs/revlog.rs | 67 +++++++------ 2 files changed, 99 insertions(+), 70 deletions(-) diff --git a/src/components/utils/async_commit_filter.rs b/src/components/utils/async_commit_filter.rs index 45081d155d..96feb516a3 100644 --- a/src/components/utils/async_commit_filter.rs +++ b/src/components/utils/async_commit_filter.rs @@ -36,7 +36,7 @@ pub enum FilterStatus { pub struct AsyncCommitFilterer { git_log: AsyncLog, - filter_strings: Vec<(String, FilterBy)>, + filter_strings: Vec>, filtered_commits: Arc>>, filter_count: Arc, filter_finished: Arc, @@ -85,53 +85,73 @@ impl AsyncCommitFilterer { } pub fn filter( - vec_commit_info: Vec, - filter_strings: &Vec<(String, FilterBy)>, + mut vec_commit_info: Vec, + filter_strings: &Vec>, ) -> Vec { - let mut commit_infos = vec_commit_info; - for (s, filter) in filter_strings { - commit_infos = commit_infos - .drain(..) - .filter(|ci| { - if filter.contains(FilterBy::SHA) { - if ci - .id - .to_string() - .to_lowercase() - .contains(&s.to_lowercase()) - { - return true; - } - } - - if filter.contains(FilterBy::AUTHOR) { - if ci - .author - .to_lowercase() - .contains(&s.to_lowercase()) - { - return true; - } + vec_commit_info + .drain(..) + .filter(|commit| { + for to_and in filter_strings { + let mut is_and = true; + for (s, filter) in to_and { + let b = false + || if filter.contains(FilterBy::SHA) { + if commit + .id + .to_string() + .to_lowercase() + .contains(&s.to_lowercase()) + { + true + } else { + false + } + } else { + false + } + || if filter.contains(FilterBy::AUTHOR) { + if commit + .author + .to_lowercase() + .contains(&s.to_lowercase()) + { + true + } else { + false + } + } else { + false + } + || if filter.contains(FilterBy::MESSAGE) { + if commit + .message + .to_lowercase() + .contains(&s.to_lowercase()) + { + true + //filtered_commits.push(commit.clone()); + //break; + } else { + false + } + } else { + false + }; + is_and = is_and && b; } - if filter.contains(FilterBy::MESSAGE) { - if ci - .message - .to_lowercase() - .contains(&s.to_lowercase()) - { - return true; - } + if is_and { + return true; } - false - }) - .collect::>() - } - return commit_infos; + } + false + }) + .collect() + //return filtered_commits; } pub fn start_filter( &mut self, - filter_strings: Vec<(String, FilterBy)>, + filter_strings: Vec>, ) -> Result<()> { self.stop_filter(); diff --git a/src/tabs/revlog.rs b/src/tabs/revlog.rs index f5d19dcc84..f87884f433 100644 --- a/src/tabs/revlog.rs +++ b/src/tabs/revlog.rs @@ -202,38 +202,47 @@ impl Revlog { fn get_what_to_filter_by( filter_by_str: &str, - ) -> Vec<(String, FilterBy)> { + ) -> Vec> { let mut search_vec = vec![]; - for split_sub in filter_by_str.split("||") { - if let Some(':') = split_sub.chars().nth(0) { - let mut to_filter_by = FilterBy::empty(); - let mut split_str = - split_sub.split(' ').collect::>(); - if split_str.len() == 1 { - split_str.push(""); - } - let first = split_str[0]; - if first.contains('s') { - to_filter_by = to_filter_by | FilterBy::SHA; - } - if first.contains('a') { - to_filter_by = to_filter_by | FilterBy::AUTHOR; - } - if first.contains('m') { - to_filter_by = to_filter_by | FilterBy::MESSAGE; - } - if to_filter_by.is_empty() { - to_filter_by = FilterBy::all(); - } + let mut and_vec = Vec::new(); + for or in filter_by_str.split("||") { + for split_sub in or.split("&&") { + if let Some(':') = split_sub.chars().nth(0) { + let mut to_filter_by = FilterBy::empty(); + let mut split_str = + split_sub.split(' ').collect::>(); + if split_str.len() == 1 { + split_str.push(""); + } + let first = split_str[0]; + if first.contains('s') { + to_filter_by = to_filter_by | FilterBy::SHA; + } + if first.contains('a') { + to_filter_by = + to_filter_by | FilterBy::AUTHOR; + } + if first.contains('m') { + to_filter_by = + to_filter_by | FilterBy::MESSAGE; + } + if to_filter_by.is_empty() { + to_filter_by = FilterBy::all(); + } - search_vec.push(( - split_str[1..].join(" ").trim().to_string(), - to_filter_by, - )); - } else { - search_vec - .push((split_sub.to_string(), FilterBy::all())) + and_vec.push(( + split_str[1..].join(" ").trim().to_string(), + to_filter_by, + )); + } else { + and_vec.push(( + split_sub.to_string(), + FilterBy::all(), + )) + } } + search_vec.push(and_vec.clone()); + and_vec.clear(); } return search_vec; } From f442c33e4c8ad0ed426bbec2f733f27ac530887d Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Thu, 11 Feb 2021 17:59:59 +0000 Subject: [PATCH 45/97] Use mutexes to prevent several threads filtering at once --- src/components/utils/async_commit_filter.rs | 118 +++++++++++++------- 1 file changed, 77 insertions(+), 41 deletions(-) diff --git a/src/components/utils/async_commit_filter.rs b/src/components/utils/async_commit_filter.rs index 96feb516a3..bf3eb0ab5b 100644 --- a/src/components/utils/async_commit_filter.rs +++ b/src/components/utils/async_commit_filter.rs @@ -42,6 +42,9 @@ pub struct AsyncCommitFilterer { filter_finished: Arc, is_pending_local: RefCell, filter_thread_sender: Option>, + //filter_thread_receiver: Receiver, + filter_thread_running: Arc, + filter_thread_mutex: Arc>, sender: Sender, } @@ -50,14 +53,18 @@ impl AsyncCommitFilterer { git_log: AsyncLog, sender: &Sender, ) -> Self { + //let (tx, rx) = crossbeam_channel::unbounded(); Self { filter_strings: Vec::new(), git_log: git_log, filtered_commits: Arc::new(Mutex::new(Vec::new())), filter_count: Arc::new(AtomicUsize::new(0)), - filter_finished: Arc::new(AtomicBool::new(true)), + filter_finished: Arc::new(AtomicBool::new(false)), + filter_thread_mutex: Arc::new(Mutex::new(())), is_pending_local: RefCell::new(true), filter_thread_sender: None, + //filter_thread_receiver: rx.clone(), + filter_thread_running: Arc::new(AtomicBool::new(true)), sender: sender.clone(), } } @@ -149,6 +156,7 @@ impl AsyncCommitFilterer { //return filtered_commits; } + #[allow(clippy::too_many_lines)] pub fn start_filter( &mut self, filter_strings: Vec>, @@ -163,18 +171,34 @@ impl AsyncCommitFilterer { let filter_count = Arc::clone(&self.filter_count); let async_log = self.git_log.clone(); let filter_finished = Arc::clone(&self.filter_finished); - filter_finished.store(false, Ordering::Relaxed); + + let filter_thread_running = + Arc::clone(&self.filter_thread_running); let (tx, rx) = crossbeam_channel::unbounded(); + //let rx = self.filter_thread_receiver.clone(); self.filter_thread_sender = Some(tx); let async_app_sender = self.sender.clone(); + let prev_thread_mutex = Arc::clone(&self.filter_thread_mutex); + // let filter_thread_mutex = Arc::new(Mutex::new(true)); + self.filter_thread_mutex = Arc::new(Mutex::new(())); + + let cur_thread_mutex = Arc::clone(&self.filter_thread_mutex); + // Arc::clone(&self.filter_thread_mutex); + rayon_core::spawn(move || { + // Only 1 thread can filter at a time + let _c = cur_thread_mutex.lock().expect("cant fail"); + let _p = prev_thread_mutex.lock().expect("cant fail"); + filter_finished.store(false, Ordering::Relaxed); let mut cur_index: usize = 0; loop { match rx.try_recv() { Ok(_) | Err(TryRecvError::Disconnected) => { + filter_thread_running + .store(false, Ordering::Relaxed); break; } Err(TryRecvError::Empty) => { @@ -182,56 +206,68 @@ impl AsyncCommitFilterer { match async_log .get_slice(cur_index, SLICE_SIZE) { - Ok(ids) => match sync::get_commits_info( - CWD, - &ids, - usize::MAX, - ) { - Ok(v) => { - if v.len() == 0 - && !async_log.is_pending() - { - // Assume finished if log not pending and 0 recieved - filter_finished.store( - true, + Ok(ids) => { + match sync::get_commits_info( + CWD, + &ids, + usize::MAX, + ) { + Ok(v) => { + if v.len() == 0 + && !async_log.is_pending() + { + // Assume finished if log not pending and 0 recieved + filter_finished.store( + true, + Ordering::Relaxed, + ); + filter_thread_running + .store( + false, + Ordering::Relaxed, + ); + break; + } + + let mut filtered = + Self::filter( + v, + &filter_strings, + ); + filter_count.fetch_add( + filtered.len(), Ordering::Relaxed, ); - break; - } - - let mut filtered = Self::filter( - v, - &filter_strings, - ); - filter_count.fetch_add( - filtered.len(), - Ordering::Relaxed, - ); - match filtered_commits.lock() { - Ok(mut fc) => { - fc.append(&mut filtered); - drop(fc); - cur_index += SLICE_SIZE; - async_app_sender.send(AsyncNotification::Log).expect("error sending"); - thread::sleep( + match filtered_commits.lock() + { + Ok(mut fc) => { + fc.append( + &mut filtered, + ); + drop(fc); + cur_index += + SLICE_SIZE; + async_app_sender.send(AsyncNotification::Log).expect("error sending"); + thread::sleep( FILTER_SLEEP_DURATION, ); - } - Err(_) => { - // Failed to lock `filtered_commits` - thread::sleep( + } + Err(_) => { + // Failed to lock `filtered_commits` + thread::sleep( FILTER_SLEEP_DURATION_FAILED_LOCK, ); + } } } - } - Err(_) => { - // Failed to get commit info - thread::sleep( + Err(_) => { + // Failed to get commit info + thread::sleep( FILTER_SLEEP_DURATION_FAILED_LOCK, ); + } } - }, + } Err(_) => { // Failed to get slice thread::sleep( From ae01732680616326a60886d85fd6ee8dfaf6f01e Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Thu, 11 Feb 2021 18:09:44 +0000 Subject: [PATCH 46/97] Clear filtered commits when starting a new search in thread --- src/components/utils/async_commit_filter.rs | 126 ++++++++++---------- 1 file changed, 61 insertions(+), 65 deletions(-) diff --git a/src/components/utils/async_commit_filter.rs b/src/components/utils/async_commit_filter.rs index bf3eb0ab5b..8c56892d29 100644 --- a/src/components/utils/async_commit_filter.rs +++ b/src/components/utils/async_commit_filter.rs @@ -193,89 +193,85 @@ impl AsyncCommitFilterer { let _c = cur_thread_mutex.lock().expect("cant fail"); let _p = prev_thread_mutex.lock().expect("cant fail"); filter_finished.store(false, Ordering::Relaxed); + filter_count.store(0, Ordering::Relaxed); + filtered_commits.lock().expect("Cant fail").clear(); let mut cur_index: usize = 0; loop { - match rx.try_recv() { - Ok(_) | Err(TryRecvError::Disconnected) => { - filter_thread_running - .store(false, Ordering::Relaxed); - break; - } - Err(TryRecvError::Empty) => { - // Get the git_log and start filtering through it - match async_log - .get_slice(cur_index, SLICE_SIZE) - { - Ok(ids) => { - match sync::get_commits_info( - CWD, - &ids, - usize::MAX, - ) { - Ok(v) => { - if v.len() == 0 - && !async_log.is_pending() - { - // Assume finished if log not pending and 0 recieved - filter_finished.store( - true, - Ordering::Relaxed, - ); - filter_thread_running - .store( - false, - Ordering::Relaxed, - ); - break; - } - - let mut filtered = - Self::filter( - v, - &filter_strings, - ); - filter_count.fetch_add( - filtered.len(), + // Get the git_log and start filtering through it + match async_log.get_slice(cur_index, SLICE_SIZE) { + Ok(ids) => { + match sync::get_commits_info( + CWD, + &ids, + usize::MAX, + ) { + Ok(v) => { + match rx.try_recv() { + Ok(_) + | Err( + TryRecvError::Disconnected, + ) => { + filter_thread_running.store( + false, Ordering::Relaxed, ); - match filtered_commits.lock() - { - Ok(mut fc) => { - fc.append( - &mut filtered, - ); - drop(fc); - cur_index += - SLICE_SIZE; - async_app_sender.send(AsyncNotification::Log).expect("error sending"); - thread::sleep( - FILTER_SLEEP_DURATION, - ); - } - Err(_) => { - // Failed to lock `filtered_commits` - thread::sleep( - FILTER_SLEEP_DURATION_FAILED_LOCK, + break; + } + _ => {} + } + if v.len() == 0 + && !async_log.is_pending() + { + // Assume finished if log not pending and 0 recieved + filter_finished.store( + true, + Ordering::Relaxed, + ); + filter_thread_running.store( + false, + Ordering::Relaxed, + ); + break; + } + + let mut filtered = + Self::filter(v, &filter_strings); + filter_count.fetch_add( + filtered.len(), + Ordering::Relaxed, ); - } - } + match filtered_commits.lock() { + Ok(mut fc) => { + fc.append(&mut filtered); + drop(fc); + cur_index += SLICE_SIZE; + async_app_sender.send(AsyncNotification::Log).expect("error sending"); + thread::sleep( + FILTER_SLEEP_DURATION, + ); } Err(_) => { - // Failed to get commit info + // Failed to lock `filtered_commits` thread::sleep( - FILTER_SLEEP_DURATION_FAILED_LOCK, - ); + FILTER_SLEEP_DURATION_FAILED_LOCK, + ); } } } Err(_) => { - // Failed to get slice + // Failed to get commit info thread::sleep( FILTER_SLEEP_DURATION_FAILED_LOCK, ); } } } + Err(_) => { + // Failed to get slice + thread::sleep( + FILTER_SLEEP_DURATION_FAILED_LOCK, + ); + } } } }); From c5b469b89fb16dd56265ab49506e64bc5366c237 Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Thu, 11 Feb 2021 18:51:04 +0000 Subject: [PATCH 47/97] Use parking log mutex --- Cargo.lock | 1 + Cargo.toml | 1 + src/components/utils/async_commit_filter.rs | 55 +++++++-------------- 3 files changed, 20 insertions(+), 37 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 85afe425f2..572ae4e7d3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -370,6 +370,7 @@ dependencies = [ "dirs-next", "itertools", "log", + "parking_lot", "pprof", "rayon-core", "ron", diff --git a/Cargo.toml b/Cargo.toml index a0cf5b1a0b..ba73d09900 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,6 +40,7 @@ serde = "1.0" anyhow = "1.0.38" unicode-width = "0.1" textwrap = "0.13" +parking_lot = "0.11" [target.'cfg(all(target_family="unix",not(target_os="macos")))'.dependencies] which = "4.0" diff --git a/src/components/utils/async_commit_filter.rs b/src/components/utils/async_commit_filter.rs index 8c56892d29..f0137e4070 100644 --- a/src/components/utils/async_commit_filter.rs +++ b/src/components/utils/async_commit_filter.rs @@ -9,12 +9,14 @@ use std::{ cell::RefCell, sync::{ atomic::{AtomicBool, AtomicUsize, Ordering}, - Arc, Mutex, + Arc, }, thread, time::Duration, }; +use parking_lot::Mutex; + const FILTER_SLEEP_DURATION: Duration = Duration::from_millis(10); const FILTER_SLEEP_DURATION_FAILED_LOCK: Duration = Duration::from_millis(500); @@ -79,15 +81,8 @@ impl AsyncCommitFilterer { } } - pub fn clear( - &mut self, - ) -> Result< - (), - std::sync::PoisonError< - std::sync::MutexGuard>, - >, - > { - self.filtered_commits.lock()?.clear(); + pub fn clear(&mut self) -> Result<()> { + self.filtered_commits.lock().clear(); Ok(()) } @@ -190,11 +185,11 @@ impl AsyncCommitFilterer { rayon_core::spawn(move || { // Only 1 thread can filter at a time - let _c = cur_thread_mutex.lock().expect("cant fail"); - let _p = prev_thread_mutex.lock().expect("cant fail"); + let _c = cur_thread_mutex.lock(); + let _p = prev_thread_mutex.lock(); filter_finished.store(false, Ordering::Relaxed); filter_count.store(0, Ordering::Relaxed); - filtered_commits.lock().expect("Cant fail").clear(); + filtered_commits.lock().clear(); let mut cur_index: usize = 0; loop { // Get the git_log and start filtering through it @@ -240,23 +235,14 @@ impl AsyncCommitFilterer { filtered.len(), Ordering::Relaxed, ); - match filtered_commits.lock() { - Ok(mut fc) => { - fc.append(&mut filtered); - drop(fc); - cur_index += SLICE_SIZE; - async_app_sender.send(AsyncNotification::Log).expect("error sending"); - thread::sleep( - FILTER_SLEEP_DURATION, - ); - } - Err(_) => { - // Failed to lock `filtered_commits` - thread::sleep( - FILTER_SLEEP_DURATION_FAILED_LOCK, - ); - } - } + let mut fc = filtered_commits.lock(); + fc.append(&mut filtered); + drop(fc); + cur_index += SLICE_SIZE; + async_app_sender + .send(AsyncNotification::Log) + .expect("error sending"); + thread::sleep(FILTER_SLEEP_DURATION); } Err(_) => { // Failed to get commit info @@ -303,13 +289,8 @@ impl AsyncCommitFilterer { start: usize, amount: usize, message_length_limit: usize, - ) -> Result< - Vec, - std::sync::PoisonError< - std::sync::MutexGuard>, - >, - > { - let fc = self.filtered_commits.lock()?; + ) -> Result> { + let fc = self.filtered_commits.lock(); let len = fc.len(); let min = start.min(len); let max = min + amount; From 8fc599d4544a5eddba4a08803a428860429afc53 Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Thu, 11 Feb 2021 18:51:34 +0000 Subject: [PATCH 48/97] Fix import order --- src/components/utils/async_commit_filter.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/components/utils/async_commit_filter.rs b/src/components/utils/async_commit_filter.rs index f0137e4070..546946ea56 100644 --- a/src/components/utils/async_commit_filter.rs +++ b/src/components/utils/async_commit_filter.rs @@ -5,6 +5,7 @@ use asyncgit::{ }; use bitflags::bitflags; use crossbeam_channel::{Sender, TryRecvError}; +use parking_lot::Mutex; use std::{ cell::RefCell, sync::{ @@ -15,8 +16,6 @@ use std::{ time::Duration, }; -use parking_lot::Mutex; - const FILTER_SLEEP_DURATION: Duration = Duration::from_millis(10); const FILTER_SLEEP_DURATION_FAILED_LOCK: Duration = Duration::from_millis(500); From 524ddcc616b37a131ee79871182a4d3076a730da Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Thu, 11 Feb 2021 18:57:13 +0000 Subject: [PATCH 49/97] Fix spinner up before filter --- src/components/utils/async_commit_filter.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/components/utils/async_commit_filter.rs b/src/components/utils/async_commit_filter.rs index 546946ea56..8b4c05175f 100644 --- a/src/components/utils/async_commit_filter.rs +++ b/src/components/utils/async_commit_filter.rs @@ -62,7 +62,7 @@ impl AsyncCommitFilterer { filter_count: Arc::new(AtomicUsize::new(0)), filter_finished: Arc::new(AtomicBool::new(false)), filter_thread_mutex: Arc::new(Mutex::new(())), - is_pending_local: RefCell::new(true), + is_pending_local: RefCell::new(false), filter_thread_sender: None, //filter_thread_receiver: rx.clone(), filter_thread_running: Arc::new(AtomicBool::new(true)), @@ -181,6 +181,7 @@ impl AsyncCommitFilterer { let cur_thread_mutex = Arc::clone(&self.filter_thread_mutex); // Arc::clone(&self.filter_thread_mutex); + self.is_pending_local.replace(true); rayon_core::spawn(move || { // Only 1 thread can filter at a time @@ -273,7 +274,7 @@ impl AsyncCommitFilterer { Ok(_) | Err(_) => {} }; } - self.is_pending_local.replace(true); + self.is_pending_local.replace(false); self.filter_finished.store(true, Ordering::Relaxed); } From 06d6ade63b0e44040c84b953b1bf25ee0fdebdd6 Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Thu, 11 Feb 2021 18:58:57 +0000 Subject: [PATCH 50/97] Remove filter_thread_running --- src/components/utils/async_commit_filter.rs | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/components/utils/async_commit_filter.rs b/src/components/utils/async_commit_filter.rs index 8b4c05175f..a71f9c1c77 100644 --- a/src/components/utils/async_commit_filter.rs +++ b/src/components/utils/async_commit_filter.rs @@ -44,7 +44,6 @@ pub struct AsyncCommitFilterer { is_pending_local: RefCell, filter_thread_sender: Option>, //filter_thread_receiver: Receiver, - filter_thread_running: Arc, filter_thread_mutex: Arc>, sender: Sender, } @@ -65,7 +64,6 @@ impl AsyncCommitFilterer { is_pending_local: RefCell::new(false), filter_thread_sender: None, //filter_thread_receiver: rx.clone(), - filter_thread_running: Arc::new(AtomicBool::new(true)), sender: sender.clone(), } } @@ -166,9 +164,6 @@ impl AsyncCommitFilterer { let async_log = self.git_log.clone(); let filter_finished = Arc::clone(&self.filter_finished); - let filter_thread_running = - Arc::clone(&self.filter_thread_running); - let (tx, rx) = crossbeam_channel::unbounded(); //let rx = self.filter_thread_receiver.clone(); @@ -206,10 +201,6 @@ impl AsyncCommitFilterer { | Err( TryRecvError::Disconnected, ) => { - filter_thread_running.store( - false, - Ordering::Relaxed, - ); break; } _ => {} @@ -222,10 +213,6 @@ impl AsyncCommitFilterer { true, Ordering::Relaxed, ); - filter_thread_running.store( - false, - Ordering::Relaxed, - ); break; } From 7ed2cda405a4777b081af47875ff2992031f36a2 Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Thu, 11 Feb 2021 18:59:56 +0000 Subject: [PATCH 51/97] Remove unneeded comments --- src/components/utils/async_commit_filter.rs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/components/utils/async_commit_filter.rs b/src/components/utils/async_commit_filter.rs index a71f9c1c77..116e041faa 100644 --- a/src/components/utils/async_commit_filter.rs +++ b/src/components/utils/async_commit_filter.rs @@ -43,7 +43,6 @@ pub struct AsyncCommitFilterer { filter_finished: Arc, is_pending_local: RefCell, filter_thread_sender: Option>, - //filter_thread_receiver: Receiver, filter_thread_mutex: Arc>, sender: Sender, } @@ -53,7 +52,6 @@ impl AsyncCommitFilterer { git_log: AsyncLog, sender: &Sender, ) -> Self { - //let (tx, rx) = crossbeam_channel::unbounded(); Self { filter_strings: Vec::new(), git_log: git_log, @@ -63,7 +61,6 @@ impl AsyncCommitFilterer { filter_thread_mutex: Arc::new(Mutex::new(())), is_pending_local: RefCell::new(false), filter_thread_sender: None, - //filter_thread_receiver: rx.clone(), sender: sender.clone(), } } @@ -128,8 +125,6 @@ impl AsyncCommitFilterer { .contains(&s.to_lowercase()) { true - //filtered_commits.push(commit.clone()); - //break; } else { false } @@ -145,7 +140,6 @@ impl AsyncCommitFilterer { false }) .collect() - //return filtered_commits; } #[allow(clippy::too_many_lines)] @@ -165,17 +159,14 @@ impl AsyncCommitFilterer { let filter_finished = Arc::clone(&self.filter_finished); let (tx, rx) = crossbeam_channel::unbounded(); - //let rx = self.filter_thread_receiver.clone(); self.filter_thread_sender = Some(tx); let async_app_sender = self.sender.clone(); let prev_thread_mutex = Arc::clone(&self.filter_thread_mutex); - // let filter_thread_mutex = Arc::new(Mutex::new(true)); self.filter_thread_mutex = Arc::new(Mutex::new(())); let cur_thread_mutex = Arc::clone(&self.filter_thread_mutex); - // Arc::clone(&self.filter_thread_mutex); self.is_pending_local.replace(true); rayon_core::spawn(move || { From c444aaae77e0f9059c2f096bf13aedb7927a4ab7 Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Thu, 11 Feb 2021 19:08:12 +0000 Subject: [PATCH 52/97] Make filter function more succinct --- src/components/utils/async_commit_filter.rs | 57 +++++++-------------- 1 file changed, 18 insertions(+), 39 deletions(-) diff --git a/src/components/utils/async_commit_filter.rs b/src/components/utils/async_commit_filter.rs index 116e041faa..39683824f4 100644 --- a/src/components/utils/async_commit_filter.rs +++ b/src/components/utils/async_commit_filter.rs @@ -90,48 +90,27 @@ impl AsyncCommitFilterer { for to_and in filter_strings { let mut is_and = true; for (s, filter) in to_and { - let b = false - || if filter.contains(FilterBy::SHA) { - if commit + is_and = is_and + && ((filter.contains(FilterBy::SHA) + && commit .id .to_string() .to_lowercase() - .contains(&s.to_lowercase()) - { - true - } else { - false - } - } else { - false - } - || if filter.contains(FilterBy::AUTHOR) { - if commit - .author - .to_lowercase() - .contains(&s.to_lowercase()) - { - true - } else { - false - } - } else { - false - } - || if filter.contains(FilterBy::MESSAGE) { - if commit - .message - .to_lowercase() - .contains(&s.to_lowercase()) - { - true - } else { - false - } - } else { - false - }; - is_and = is_and && b; + .contains(&s.to_lowercase())) + || (filter + .contains(FilterBy::AUTHOR) + && commit + .author + .to_lowercase() + .contains( + &s.to_lowercase(), + )) + || filter + .contains(FilterBy::MESSAGE) + && commit + .message + .to_lowercase() + .contains(&s.to_lowercase())); } if is_and { return true; From 5bd747b08ebfdd9e1d467ea9c29f0921def530c9 Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Thu, 11 Feb 2021 19:10:22 +0000 Subject: [PATCH 53/97] Remove clippy allow too many lines --- src/components/utils/async_commit_filter.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/utils/async_commit_filter.rs b/src/components/utils/async_commit_filter.rs index 39683824f4..d8b80f9a00 100644 --- a/src/components/utils/async_commit_filter.rs +++ b/src/components/utils/async_commit_filter.rs @@ -121,7 +121,6 @@ impl AsyncCommitFilterer { .collect() } - #[allow(clippy::too_many_lines)] pub fn start_filter( &mut self, filter_strings: Vec>, From 8db4523219766bf09a586f5f0b197fe5338d6a8f Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Thu, 11 Feb 2021 19:11:38 +0000 Subject: [PATCH 54/97] Fix brackets in filter function --- src/components/utils/async_commit_filter.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/components/utils/async_commit_filter.rs b/src/components/utils/async_commit_filter.rs index d8b80f9a00..36e119281c 100644 --- a/src/components/utils/async_commit_filter.rs +++ b/src/components/utils/async_commit_filter.rs @@ -105,12 +105,14 @@ impl AsyncCommitFilterer { .contains( &s.to_lowercase(), )) - || filter + || (filter .contains(FilterBy::MESSAGE) && commit .message .to_lowercase() - .contains(&s.to_lowercase())); + .contains( + &s.to_lowercase(), + ))); } if is_and { return true; From a1cd02051c1af4deb02f20bc10c3d185d3d376c1 Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Thu, 11 Feb 2021 19:16:51 +0000 Subject: [PATCH 55/97] Remove reset values from start_filter in main thread --- src/components/utils/async_commit_filter.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/components/utils/async_commit_filter.rs b/src/components/utils/async_commit_filter.rs index 36e119281c..19533790c7 100644 --- a/src/components/utils/async_commit_filter.rs +++ b/src/components/utils/async_commit_filter.rs @@ -129,9 +129,7 @@ impl AsyncCommitFilterer { ) -> Result<()> { self.stop_filter(); - self.clear().expect("Can't fail unless app crashes"); self.filter_strings = filter_strings.clone(); - self.filter_count.store(0, Ordering::Relaxed); let filtered_commits = Arc::clone(&self.filtered_commits); let filter_count = Arc::clone(&self.filter_count); From 126431a516c365b09116fddcf196fa091e052edc Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Thu, 11 Feb 2021 19:18:26 +0000 Subject: [PATCH 56/97] Remove clear function from async filter --- src/components/utils/async_commit_filter.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/components/utils/async_commit_filter.rs b/src/components/utils/async_commit_filter.rs index 19533790c7..16a1386125 100644 --- a/src/components/utils/async_commit_filter.rs +++ b/src/components/utils/async_commit_filter.rs @@ -75,11 +75,6 @@ impl AsyncCommitFilterer { } } - pub fn clear(&mut self) -> Result<()> { - self.filtered_commits.lock().clear(); - Ok(()) - } - pub fn filter( mut vec_commit_info: Vec, filter_strings: &Vec>, From 7a416de9ea04c6be8f1ea4457e18078f6749ab15 Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Thu, 11 Feb 2021 19:59:38 +0000 Subject: [PATCH 57/97] Move try_recv to before getting slice of commits --- src/components/utils/async_commit_filter.rs | 100 +++++++++++--------- 1 file changed, 53 insertions(+), 47 deletions(-) diff --git a/src/components/utils/async_commit_filter.rs b/src/components/utils/async_commit_filter.rs index 16a1386125..c235edd4f2 100644 --- a/src/components/utils/async_commit_filter.rs +++ b/src/components/utils/async_commit_filter.rs @@ -151,64 +151,70 @@ impl AsyncCommitFilterer { filtered_commits.lock().clear(); let mut cur_index: usize = 0; loop { - // Get the git_log and start filtering through it - match async_log.get_slice(cur_index, SLICE_SIZE) { - Ok(ids) => { - match sync::get_commits_info( - CWD, - &ids, - usize::MAX, - ) { - Ok(v) => { - match rx.try_recv() { - Ok(_) - | Err( - TryRecvError::Disconnected, - ) => { - break; - } - _ => {} - } - if v.len() == 0 - && !async_log.is_pending() - { - // Assume finished if log not pending and 0 recieved - filter_finished.store( - true, - Ordering::Relaxed, - ); - break; - } + match rx.try_recv() { + Ok(_) | Err(TryRecvError::Disconnected) => { + break; + } + _ => { + // Get the git_log and start filtering through it + match async_log + .get_slice(cur_index, SLICE_SIZE) + { + Ok(ids) => { + match sync::get_commits_info( + CWD, + &ids, + usize::MAX, + ) { + Ok(v) => { + if v.len() == 0 + && !async_log.is_pending() + { + // Assume finished if log not pending and 0 recieved + filter_finished.store( + true, + Ordering::Relaxed, + ); + break; + } - let mut filtered = - Self::filter(v, &filter_strings); - filter_count.fetch_add( - filtered.len(), - Ordering::Relaxed, - ); - let mut fc = filtered_commits.lock(); - fc.append(&mut filtered); - drop(fc); - cur_index += SLICE_SIZE; - async_app_sender + let mut filtered = + Self::filter( + v, + &filter_strings, + ); + filter_count.fetch_add( + filtered.len(), + Ordering::Relaxed, + ); + let mut fc = + filtered_commits.lock(); + fc.append(&mut filtered); + drop(fc); + cur_index += SLICE_SIZE; + async_app_sender .send(AsyncNotification::Log) .expect("error sending"); - thread::sleep(FILTER_SLEEP_DURATION); + thread::sleep( + FILTER_SLEEP_DURATION, + ); + } + Err(_) => { + // Failed to get commit info + thread::sleep( + FILTER_SLEEP_DURATION_FAILED_LOCK, + ); + } + } } Err(_) => { - // Failed to get commit info + // Failed to get slice thread::sleep( FILTER_SLEEP_DURATION_FAILED_LOCK, ); } } } - Err(_) => { - // Failed to get slice - thread::sleep( - FILTER_SLEEP_DURATION_FAILED_LOCK, - ); - } } } }); From d70e14991b0ff312e5ddee559104de34e02c74b4 Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Thu, 11 Feb 2021 20:19:49 +0000 Subject: [PATCH 58/97] Add complement search --- src/components/utils/async_commit_filter.rs | 67 +++++++++++++++------ src/tabs/revlog.rs | 9 ++- 2 files changed, 55 insertions(+), 21 deletions(-) diff --git a/src/components/utils/async_commit_filter.rs b/src/components/utils/async_commit_filter.rs index c235edd4f2..db81f44d9d 100644 --- a/src/components/utils/async_commit_filter.rs +++ b/src/components/utils/async_commit_filter.rs @@ -26,6 +26,7 @@ bitflags! { const SHA = 0b0000_0001; const AUTHOR = 0b0000_0010; const MESSAGE = 0b0000_0100; + const NOT = 0b0000_1000; } } @@ -85,29 +86,55 @@ impl AsyncCommitFilterer { for to_and in filter_strings { let mut is_and = true; for (s, filter) in to_and { - is_and = is_and - && ((filter.contains(FilterBy::SHA) - && commit - .id - .to_string() - .to_lowercase() - .contains(&s.to_lowercase())) - || (filter - .contains(FilterBy::AUTHOR) - && commit - .author + is_and = if filter.contains(FilterBy::NOT) { + is_and + && ((filter.contains(FilterBy::SHA) + && !commit + .id + .to_string() .to_lowercase() - .contains( - &s.to_lowercase(), - )) - || (filter - .contains(FilterBy::MESSAGE) + .contains(&s.to_lowercase())) + || (filter + .contains(FilterBy::AUTHOR) + && !commit + .author + .to_lowercase() + .contains( + &s.to_lowercase(), + )) + || (filter + .contains(FilterBy::MESSAGE) + && !commit + .message + .to_lowercase() + .contains( + &s.to_lowercase(), + ))) + } else { + is_and + && ((filter.contains(FilterBy::SHA) && commit - .message + .id + .to_string() .to_lowercase() - .contains( - &s.to_lowercase(), - ))); + .contains(&s.to_lowercase())) + || (filter + .contains(FilterBy::AUTHOR) + && commit + .author + .to_lowercase() + .contains( + &s.to_lowercase(), + )) + || (filter + .contains(FilterBy::MESSAGE) + && commit + .message + .to_lowercase() + .contains( + &s.to_lowercase(), + ))) + } } if is_and { return true; diff --git a/src/tabs/revlog.rs b/src/tabs/revlog.rs index f87884f433..1b89193a07 100644 --- a/src/tabs/revlog.rs +++ b/src/tabs/revlog.rs @@ -226,9 +226,16 @@ impl Revlog { to_filter_by = to_filter_by | FilterBy::MESSAGE; } + if first.contains('!') { + to_filter_by = to_filter_by | FilterBy::NOT; + } + if to_filter_by.is_empty() { + to_filter_by = + FilterBy::all() & !FilterBy::NOT; + } else if to_filter_by == FilterBy::NOT { to_filter_by = FilterBy::all(); - } + }; and_vec.push(( split_str[1..].join(" ").trim().to_string(), From a2faf2984ba43e948bb2deb4b5fa998898ad8de1 Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Fri, 12 Feb 2021 22:38:24 +0000 Subject: [PATCH 59/97] Support case sensitive filtering --- src/components/utils/async_commit_filter.rs | 102 +++++++++++++++----- src/tabs/revlog.rs | 15 ++- 2 files changed, 90 insertions(+), 27 deletions(-) diff --git a/src/components/utils/async_commit_filter.rs b/src/components/utils/async_commit_filter.rs index db81f44d9d..5e89d864c8 100644 --- a/src/components/utils/async_commit_filter.rs +++ b/src/components/utils/async_commit_filter.rs @@ -27,6 +27,7 @@ bitflags! { const AUTHOR = 0b0000_0010; const MESSAGE = 0b0000_0100; const NOT = 0b0000_1000; + const CASE_SENSITIVE = 0b0001_0000; } } @@ -76,6 +77,7 @@ impl AsyncCommitFilterer { } } + #[allow(clippy::too_many_lines)] pub fn filter( mut vec_commit_info: Vec, filter_strings: &Vec>, @@ -86,54 +88,102 @@ impl AsyncCommitFilterer { for to_and in filter_strings { let mut is_and = true; for (s, filter) in to_and { - is_and = if filter.contains(FilterBy::NOT) { - is_and - && ((filter.contains(FilterBy::SHA) - && !commit - .id - .to_string() - .to_lowercase() - .contains(&s.to_lowercase())) - || (filter - .contains(FilterBy::AUTHOR) + if filter.contains(FilterBy::CASE_SENSITIVE) { + is_and = if filter.contains(FilterBy::NOT) + { + is_and + && ((filter + .contains(FilterBy::SHA) && !commit + .id + .to_string() + .contains(s)) + || (filter.contains( + FilterBy::AUTHOR, + ) && !commit .author + .contains(s)) + || (filter.contains( + FilterBy::MESSAGE, + ) && !commit + .message + .contains(s))) + } else { + is_and + && ((filter + .contains(FilterBy::SHA) + && commit + .id + .to_string() + .contains(s)) + || (filter.contains( + FilterBy::AUTHOR, + ) && commit + .author + .contains(s)) + || (filter.contains( + FilterBy::MESSAGE, + ) && commit + .message + .contains(s))) + } + } else { + is_and = if filter.contains(FilterBy::NOT) + { + is_and + && ((filter + .contains(FilterBy::SHA) + && !commit + .id + .to_string() .to_lowercase() .contains( &s.to_lowercase(), )) - || (filter - .contains(FilterBy::MESSAGE) - && !commit + || (filter.contains( + FilterBy::AUTHOR, + ) && !commit + .author + .to_lowercase() + .contains( + &s.to_lowercase(), + )) + || (filter.contains( + FilterBy::MESSAGE, + ) && !commit .message .to_lowercase() .contains( &s.to_lowercase(), ))) - } else { - is_and - && ((filter.contains(FilterBy::SHA) - && commit - .id - .to_string() - .to_lowercase() - .contains(&s.to_lowercase())) - || (filter - .contains(FilterBy::AUTHOR) + } else { + is_and + && ((filter + .contains(FilterBy::SHA) && commit + .id + .to_string() + .to_lowercase() + .contains( + &s.to_lowercase(), + )) + || (filter.contains( + FilterBy::AUTHOR, + ) && commit .author .to_lowercase() .contains( &s.to_lowercase(), )) - || (filter - .contains(FilterBy::MESSAGE) - && commit + || (filter.contains( + FilterBy::MESSAGE, + ) && commit .message .to_lowercase() .contains( &s.to_lowercase(), ))) + } } } if is_and { diff --git a/src/tabs/revlog.rs b/src/tabs/revlog.rs index 1b89193a07..40d1094c2b 100644 --- a/src/tabs/revlog.rs +++ b/src/tabs/revlog.rs @@ -226,6 +226,10 @@ impl Revlog { to_filter_by = to_filter_by | FilterBy::MESSAGE; } + if first.contains('c') { + to_filter_by = + to_filter_by | FilterBy::CASE_SENSITIVE; + } if first.contains('!') { to_filter_by = to_filter_by | FilterBy::NOT; } @@ -233,8 +237,17 @@ impl Revlog { if to_filter_by.is_empty() { to_filter_by = FilterBy::all() & !FilterBy::NOT; + } else if to_filter_by + == FilterBy::CASE_SENSITIVE & FilterBy::NOT + { + FilterBy::all(); } else if to_filter_by == FilterBy::NOT { - to_filter_by = FilterBy::all(); + to_filter_by = + FilterBy::all() & !FilterBy::NOT; + } else if to_filter_by == FilterBy::CASE_SENSITIVE + { + to_filter_by = + FilterBy::all() & !FilterBy::NOT; }; and_vec.push(( From 571c40171ea97effec36561d03946b9c16052256 Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Fri, 12 Feb 2021 22:51:15 +0000 Subject: [PATCH 60/97] Add comment to filter function explaining what input is expected --- src/components/utils/async_commit_filter.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/components/utils/async_commit_filter.rs b/src/components/utils/async_commit_filter.rs index 5e89d864c8..8658511f33 100644 --- a/src/components/utils/async_commit_filter.rs +++ b/src/components/utils/async_commit_filter.rs @@ -77,6 +77,13 @@ impl AsyncCommitFilterer { } } + /// `filter_strings` should be split by or them and, for example, + /// + /// A || B && C && D || E + /// + /// would be + /// + /// vec [vec![A], vec![B, C, D], vec![E]] #[allow(clippy::too_many_lines)] pub fn filter( mut vec_commit_info: Vec, From d5d24fb4a16e8b7a46b1d035864ae7a03d7e212c Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Fri, 12 Feb 2021 23:09:12 +0000 Subject: [PATCH 61/97] Fix clippy warnings and not revlog filter by --- src/components/find_commit.rs | 4 +- src/components/utils/async_commit_filter.rs | 6 +-- src/tabs/revlog.rs | 51 ++++++++++----------- 3 files changed, 28 insertions(+), 33 deletions(-) diff --git a/src/components/find_commit.rs b/src/components/find_commit.rs index cf766092e7..171ff004d4 100644 --- a/src/components/find_commit.rs +++ b/src/components/find_commit.rs @@ -63,7 +63,7 @@ impl Component for FindCommitComponent { } fn is_visible(&self) -> bool { - return self.visible; + self.visible } fn hide(&mut self) { @@ -79,7 +79,7 @@ impl Component for FindCommitComponent { } fn focused(&self) -> bool { - return self.is_focused; + self.is_focused } fn toggle_visible(&mut self) -> Result<()> { diff --git a/src/components/utils/async_commit_filter.rs b/src/components/utils/async_commit_filter.rs index 8658511f33..d84bfec676 100644 --- a/src/components/utils/async_commit_filter.rs +++ b/src/components/utils/async_commit_filter.rs @@ -56,7 +56,7 @@ impl AsyncCommitFilterer { ) -> Self { Self { filter_strings: Vec::new(), - git_log: git_log, + git_log, filtered_commits: Arc::new(Mutex::new(Vec::new())), filter_count: Arc::new(AtomicUsize::new(0)), filter_finished: Arc::new(AtomicBool::new(false)), @@ -87,7 +87,7 @@ impl AsyncCommitFilterer { #[allow(clippy::too_many_lines)] pub fn filter( mut vec_commit_info: Vec, - filter_strings: &Vec>, + filter_strings: &[Vec<(String, FilterBy)>], ) -> Vec { vec_commit_info .drain(..) @@ -251,7 +251,7 @@ impl AsyncCommitFilterer { usize::MAX, ) { Ok(v) => { - if v.len() == 0 + if v.is_empty() && !async_log.is_pending() { // Assume finished if log not pending and 0 recieved diff --git a/src/tabs/revlog.rs b/src/tabs/revlog.rs index 40d1094c2b..33d75d1d80 100644 --- a/src/tabs/revlog.rs +++ b/src/tabs/revlog.rs @@ -207,7 +207,7 @@ impl Revlog { let mut and_vec = Vec::new(); for or in filter_by_str.split("||") { for split_sub in or.split("&&") { - if let Some(':') = split_sub.chars().nth(0) { + if let Some(':') = split_sub.chars().next() { let mut to_filter_by = FilterBy::empty(); let mut split_str = split_sub.split(' ').collect::>(); @@ -216,22 +216,19 @@ impl Revlog { } let first = split_str[0]; if first.contains('s') { - to_filter_by = to_filter_by | FilterBy::SHA; + to_filter_by |= FilterBy::SHA; } if first.contains('a') { - to_filter_by = - to_filter_by | FilterBy::AUTHOR; + to_filter_by |= FilterBy::AUTHOR; } if first.contains('m') { - to_filter_by = - to_filter_by | FilterBy::MESSAGE; + to_filter_by |= FilterBy::MESSAGE; } if first.contains('c') { - to_filter_by = - to_filter_by | FilterBy::CASE_SENSITIVE; + to_filter_by |= FilterBy::CASE_SENSITIVE; } if first.contains('!') { - to_filter_by = to_filter_by | FilterBy::NOT; + to_filter_by |= FilterBy::NOT; } if to_filter_by.is_empty() { @@ -242,8 +239,8 @@ impl Revlog { { FilterBy::all(); } else if to_filter_by == FilterBy::NOT { - to_filter_by = - FilterBy::all() & !FilterBy::NOT; + to_filter_by = FilterBy::all() + & !FilterBy::CASE_SENSITIVE; } else if to_filter_by == FilterBy::CASE_SENSITIVE { to_filter_by = @@ -264,7 +261,7 @@ impl Revlog { search_vec.push(and_vec.clone()); and_vec.clear(); } - return search_vec; + search_vec } pub fn filter(&mut self, filter_by: &str) -> Result<()> { @@ -320,23 +317,21 @@ impl DrawableComponent for Revlog { self.list.draw(f, chunks[0])?; self.commit_details.draw(f, chunks[1])?; } + } else if self.find_commit.is_visible() { + let log_find_chunks = Layout::default() + .direction(Direction::Vertical) + .constraints( + [ + Constraint::Percentage(90), + Constraint::Percentage(20), + ] + .as_ref(), + ) + .split(area); + self.list.draw(f, log_find_chunks[0])?; + self.find_commit.draw(f, log_find_chunks[1])?; } else { - if self.find_commit.is_visible() { - let log_find_chunks = Layout::default() - .direction(Direction::Vertical) - .constraints( - [ - Constraint::Percentage(90), - Constraint::Percentage(20), - ] - .as_ref(), - ) - .split(area); - self.list.draw(f, log_find_chunks[0])?; - self.find_commit.draw(f, log_find_chunks[1])?; - } else { - self.list.draw(f, area)?; - } + self.list.draw(f, area)?; } Ok(()) From 712fb82c7574f0786a17ecb7f84e1ef6b0617aee Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Fri, 12 Feb 2021 23:15:03 +0000 Subject: [PATCH 62/97] Fix filter if no leading : --- src/tabs/revlog.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/tabs/revlog.rs b/src/tabs/revlog.rs index 33d75d1d80..c310e60ba1 100644 --- a/src/tabs/revlog.rs +++ b/src/tabs/revlog.rs @@ -232,8 +232,9 @@ impl Revlog { } if to_filter_by.is_empty() { - to_filter_by = - FilterBy::all() & !FilterBy::NOT; + to_filter_by = FilterBy::all() + & !FilterBy::NOT + & !FilterBy::CASE_SENSITIVE; } else if to_filter_by == FilterBy::CASE_SENSITIVE & FilterBy::NOT { @@ -254,7 +255,9 @@ impl Revlog { } else { and_vec.push(( split_sub.to_string(), - FilterBy::all(), + FilterBy::all() + & !FilterBy::NOT + & !FilterBy::CASE_SENSITIVE, )) } } From 529cc741793baa85982489b61b69d7f76a8b5504 Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Sat, 13 Feb 2021 00:27:43 +0000 Subject: [PATCH 63/97] Support filtering by tags --- asyncgit/src/tags.rs | 1 + src/components/utils/async_commit_filter.rs | 75 ++++++++++++++++++--- src/tabs/revlog.rs | 7 +- 3 files changed, 71 insertions(+), 12 deletions(-) diff --git a/asyncgit/src/tags.rs b/asyncgit/src/tags.rs index f23b54afcd..b38060f594 100644 --- a/asyncgit/src/tags.rs +++ b/asyncgit/src/tags.rs @@ -22,6 +22,7 @@ struct TagsResult { } /// +#[derive(Clone)] pub struct AsyncTags { last: Arc>>, sender: Sender, diff --git a/src/components/utils/async_commit_filter.rs b/src/components/utils/async_commit_filter.rs index d84bfec676..aba1cc5b7d 100644 --- a/src/components/utils/async_commit_filter.rs +++ b/src/components/utils/async_commit_filter.rs @@ -1,7 +1,7 @@ use anyhow::Result; use asyncgit::{ - sync::{self, limit_str, CommitInfo}, - AsyncLog, AsyncNotification, CWD, + sync::{self, limit_str, CommitId, CommitInfo}, + AsyncLog, AsyncNotification, AsyncTags, CWD, }; use bitflags::bitflags; use crossbeam_channel::{Sender, TryRecvError}; @@ -28,6 +28,7 @@ bitflags! { const MESSAGE = 0b0000_0100; const NOT = 0b0000_1000; const CASE_SENSITIVE = 0b0001_0000; + const TAGS = 0b0010_0000; } } @@ -39,6 +40,7 @@ pub enum FilterStatus { pub struct AsyncCommitFilterer { git_log: AsyncLog, + git_tags: AsyncTags, filter_strings: Vec>, filtered_commits: Arc>>, filter_count: Arc, @@ -52,11 +54,13 @@ pub struct AsyncCommitFilterer { impl AsyncCommitFilterer { pub fn new( git_log: AsyncLog, + git_tags: AsyncTags, sender: &Sender, ) -> Self { Self { filter_strings: Vec::new(), git_log, + git_tags, filtered_commits: Arc::new(Mutex::new(Vec::new())), filter_count: Arc::new(AtomicUsize::new(0)), filter_finished: Arc::new(AtomicBool::new(false)), @@ -87,6 +91,9 @@ impl AsyncCommitFilterer { #[allow(clippy::too_many_lines)] pub fn filter( mut vec_commit_info: Vec, + tags: &Option< + std::collections::BTreeMap>, + >, filter_strings: &[Vec<(String, FilterBy)>], ) -> Vec { vec_commit_info @@ -99,12 +106,17 @@ impl AsyncCommitFilterer { is_and = if filter.contains(FilterBy::NOT) { is_and - && ((filter - .contains(FilterBy::SHA) - && !commit - .id - .to_string() - .contains(s)) + && (filter + .contains(FilterBy::TAGS) + && tags.as_ref().map_or(false, |t| t.get(&commit.id).map_or(false, |commit_tags| commit_tags.iter().filter(|tag_string|{ + !tag_string.contains(s) + }).count() > 0)) + || (filter + .contains(FilterBy::SHA) + && !commit + .id + .to_string() + .contains(s)) || (filter.contains( FilterBy::AUTHOR, ) && !commit @@ -117,7 +129,12 @@ impl AsyncCommitFilterer { .contains(s))) } else { is_and - && ((filter + && (filter + .contains(FilterBy::TAGS) + && tags.as_ref().map_or(false, |t| t.get(&commit.id).map_or(false, |commit_tags| commit_tags.iter().filter(|tag_string|{ + !tag_string.contains(s) + }).count() > 0)) + || (filter .contains(FilterBy::SHA) && commit .id @@ -138,7 +155,12 @@ impl AsyncCommitFilterer { is_and = if filter.contains(FilterBy::NOT) { is_and - && ((filter + && (filter + .contains(FilterBy::TAGS) + && tags.as_ref().map_or(false, |t| t.get(&commit.id).map_or(false, |commit_tags| commit_tags.iter().filter(|tag_string|{ + !tag_string.to_lowercase().contains(&s.to_lowercase()) + }).count() > 0)) + || (filter .contains(FilterBy::SHA) && !commit .id @@ -165,7 +187,12 @@ impl AsyncCommitFilterer { ))) } else { is_and - && ((filter + && (filter + .contains(FilterBy::TAGS) + && tags.as_ref().map_or(false, |t| t.get(&commit.id).map_or(false, |commit_tags| commit_tags.iter().filter(|tag_string|{ + tag_string.to_lowercase().contains(&s.to_lowercase()) + }).count() > 0)) + || (filter .contains(FilterBy::SHA) && commit .id @@ -202,6 +229,7 @@ impl AsyncCommitFilterer { .collect() } + #[allow(clippy::too_many_lines)] pub fn start_filter( &mut self, filter_strings: Vec>, @@ -226,6 +254,30 @@ impl AsyncCommitFilterer { let cur_thread_mutex = Arc::clone(&self.filter_thread_mutex); self.is_pending_local.replace(true); + // If the search does not contain tags, do not include them + let mut contains_tags = false; + for or in &filter_strings { + for (_, filter_by) in or { + if filter_by.contains(FilterBy::TAGS) { + contains_tags = true; + break; + } + } + if contains_tags { + break; + } + } + + let tags = if contains_tags { + if let Ok(o) = self.git_tags.last() { + o + } else { + None + } + } else { + None + }; + rayon_core::spawn(move || { // Only 1 thread can filter at a time let _c = cur_thread_mutex.lock(); @@ -265,6 +317,7 @@ impl AsyncCommitFilterer { let mut filtered = Self::filter( v, + &tags, &filter_strings, ); filter_count.fetch_add( diff --git a/src/tabs/revlog.rs b/src/tabs/revlog.rs index c310e60ba1..a20586903b 100644 --- a/src/tabs/revlog.rs +++ b/src/tabs/revlog.rs @@ -54,6 +54,7 @@ impl Revlog { key_config: SharedKeyConfig, ) -> Self { let log = AsyncLog::new(sender); + let tags = AsyncTags::new(sender); Self { queue: queue.clone(), commit_details: CommitDetailsComponent::new( @@ -74,10 +75,11 @@ impl Revlog { ), async_filter: AsyncCommitFilterer::new( log.clone(), + tags.clone(), sender, ), git_log: log, - git_tags: AsyncTags::new(sender), + git_tags: tags, visible: false, branch_name: cached::BranchName::new(CWD), key_config, @@ -227,6 +229,9 @@ impl Revlog { if first.contains('c') { to_filter_by |= FilterBy::CASE_SENSITIVE; } + if first.contains('t') { + to_filter_by |= FilterBy::TAGS; + } if first.contains('!') { to_filter_by |= FilterBy::NOT; } From f4f5b6e8cbb4535ea31ccb0cf71ada13d15cec5d Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Sat, 13 Feb 2021 10:36:55 +0000 Subject: [PATCH 64/97] Support brackets in search --- src/tabs/revlog.rs | 44 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/src/tabs/revlog.rs b/src/tabs/revlog.rs index a20586903b..7b39955a67 100644 --- a/src/tabs/revlog.rs +++ b/src/tabs/revlog.rs @@ -273,7 +273,9 @@ impl Revlog { } pub fn filter(&mut self, filter_by: &str) -> Result<()> { - let trimmed_string = filter_by.trim().to_string(); + let pre_processed_string = + Self::pre_process_string(filter_by.to_string()); + let trimmed_string = pre_processed_string.trim().to_string(); if filter_by == "" { self.async_filter.stop_filter(); self.is_filtering = false; @@ -287,6 +289,46 @@ impl Revlog { } self.update() } + + /// pre process string to remove any brackets + pub fn pre_process_string(mut s: String) -> String { + while s.contains("&&(") { + let before = s.clone(); + s = Self::remove_out_brackets(&s); + if s == before { + break; + } + } + s + } + + pub fn remove_out_brackets(s: &str) -> String { + if let Some(first_bracket) = s.find("&&(") { + let (first, rest_of_string) = + s.split_at(first_bracket + 3); + if let Some(last_bracket) = rest_of_string.find(')') { + let mut v = vec![]; + let (second, third) = + rest_of_string.split_at(last_bracket); + if let Some((first, third)) = first + .strip_suffix('(') + .zip(third.strip_prefix(')')) + { + for element in second.split("||") { + // Append first, prepend third onto branket element + v.push(format!( + "{}{}{}", + first.clone(), + element.clone(), + third.clone() + )); + } + return v.join("||"); + } + } + } + return s.to_string(); + } } impl DrawableComponent for Revlog { From 9c51df3c4a07f90a7989e395634a0a4acd4fc36b Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Sat, 13 Feb 2021 11:11:37 +0000 Subject: [PATCH 65/97] Allow nested brackets --- src/tabs/revlog.rs | 42 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/src/tabs/revlog.rs b/src/tabs/revlog.rs index 7b39955a67..8f08efa003 100644 --- a/src/tabs/revlog.rs +++ b/src/tabs/revlog.rs @@ -306,7 +306,9 @@ impl Revlog { if let Some(first_bracket) = s.find("&&(") { let (first, rest_of_string) = s.split_at(first_bracket + 3); - if let Some(last_bracket) = rest_of_string.find(')') { + if let Some(last_bracket) = + Self::get_ending_bracket(rest_of_string) + { let mut v = vec![]; let (second, third) = rest_of_string.split_at(last_bracket); @@ -329,6 +331,44 @@ impl Revlog { } return s.to_string(); } + + pub fn get_ending_bracket(s: &str) -> Option { + let mut brack_count = 0; + let mut char_iter = s.chars(); + let mut ending_brakcet_pos = None; + let mut iter_count = 0; + loop { + if let Some(c) = char_iter.next() { + if c == '&' { + if let Some(c2) = char_iter.next() { + { + iter_count += 1; + if c2 == '&' { + if let Some(c3) = char_iter.next() { + iter_count += 1; + if c3 == '(' { + brack_count += 1; + } + } + } + } + } + } else if c == ')' { + if brack_count == 0 { + // Found + ending_brakcet_pos = Some(iter_count); + break; + } else { + brack_count -= 1; + } + } + } else { + break; + } + iter_count += 1; + } + ending_brakcet_pos + } } impl DrawableComponent for Revlog { From f6863d00534d1b9bfdf5fbdd346d2704c876778a Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Sat, 13 Feb 2021 11:14:37 +0000 Subject: [PATCH 66/97] Fix clippy --- src/tabs/revlog.rs | 46 ++++++++++++++++++++-------------------------- 1 file changed, 20 insertions(+), 26 deletions(-) diff --git a/src/tabs/revlog.rs b/src/tabs/revlog.rs index 8f08efa003..9cf315ad87 100644 --- a/src/tabs/revlog.rs +++ b/src/tabs/revlog.rs @@ -320,16 +320,14 @@ impl Revlog { // Append first, prepend third onto branket element v.push(format!( "{}{}{}", - first.clone(), - element.clone(), - third.clone() + first, element, third )); } return v.join("||"); } } } - return s.to_string(); + s.to_string() } pub fn get_ending_bracket(s: &str) -> Option { @@ -337,33 +335,29 @@ impl Revlog { let mut char_iter = s.chars(); let mut ending_brakcet_pos = None; let mut iter_count = 0; - loop { - if let Some(c) = char_iter.next() { - if c == '&' { - if let Some(c2) = char_iter.next() { - { - iter_count += 1; - if c2 == '&' { - if let Some(c3) = char_iter.next() { - iter_count += 1; - if c3 == '(' { - brack_count += 1; - } + while let Some(c) = char_iter.next() { + if c == '&' { + if let Some(c2) = char_iter.next() { + { + iter_count += 1; + if c2 == '&' { + if let Some(c3) = char_iter.next() { + iter_count += 1; + if c3 == '(' { + brack_count += 1; } } } } - } else if c == ')' { - if brack_count == 0 { - // Found - ending_brakcet_pos = Some(iter_count); - break; - } else { - brack_count -= 1; - } } - } else { - break; + } else if c == ')' { + if brack_count == 0 { + // Found + ending_brakcet_pos = Some(iter_count); + break; + } else { + brack_count -= 1; + } } iter_count += 1; } From a361c708c81d182236c6eb7f6f260afe1e9cfa41 Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Sat, 13 Feb 2021 11:18:26 +0000 Subject: [PATCH 67/97] Fix clippy --- src/tabs/revlog.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/tabs/revlog.rs b/src/tabs/revlog.rs index 9cf315ad87..b6fe74e43b 100644 --- a/src/tabs/revlog.rs +++ b/src/tabs/revlog.rs @@ -355,9 +355,8 @@ impl Revlog { // Found ending_brakcet_pos = Some(iter_count); break; - } else { - brack_count -= 1; } + brack_count -= 1; } iter_count += 1; } From a0b9af590186aa84513068f5479203b7c2fc8395 Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Sat, 13 Feb 2021 12:30:31 +0000 Subject: [PATCH 68/97] Support nested brackets and fix not tag search to show commits with no tags --- src/components/utils/async_commit_filter.rs | 6 ++--- src/tabs/revlog.rs | 27 +++++++++------------ 2 files changed, 14 insertions(+), 19 deletions(-) diff --git a/src/components/utils/async_commit_filter.rs b/src/components/utils/async_commit_filter.rs index aba1cc5b7d..3912b68272 100644 --- a/src/components/utils/async_commit_filter.rs +++ b/src/components/utils/async_commit_filter.rs @@ -108,7 +108,7 @@ impl AsyncCommitFilterer { is_and && (filter .contains(FilterBy::TAGS) - && tags.as_ref().map_or(false, |t| t.get(&commit.id).map_or(false, |commit_tags| commit_tags.iter().filter(|tag_string|{ + && tags.as_ref().map_or(false, |t| t.get(&commit.id).map_or(true, |commit_tags| commit_tags.iter().filter(|tag_string|{ !tag_string.contains(s) }).count() > 0)) || (filter @@ -132,7 +132,7 @@ impl AsyncCommitFilterer { && (filter .contains(FilterBy::TAGS) && tags.as_ref().map_or(false, |t| t.get(&commit.id).map_or(false, |commit_tags| commit_tags.iter().filter(|tag_string|{ - !tag_string.contains(s) + tag_string.contains(s) }).count() > 0)) || (filter .contains(FilterBy::SHA) @@ -157,7 +157,7 @@ impl AsyncCommitFilterer { is_and && (filter .contains(FilterBy::TAGS) - && tags.as_ref().map_or(false, |t| t.get(&commit.id).map_or(false, |commit_tags| commit_tags.iter().filter(|tag_string|{ + && tags.as_ref().map_or(false, |t| t.get(&commit.id).map_or(true, |commit_tags| commit_tags.iter().filter(|tag_string|{ !tag_string.to_lowercase().contains(&s.to_lowercase()) }).count() > 0)) || (filter diff --git a/src/tabs/revlog.rs b/src/tabs/revlog.rs index b6fe74e43b..8da35e72e1 100644 --- a/src/tabs/revlog.rs +++ b/src/tabs/revlog.rs @@ -246,7 +246,8 @@ impl Revlog { FilterBy::all(); } else if to_filter_by == FilterBy::NOT { to_filter_by = FilterBy::all() - & !FilterBy::CASE_SENSITIVE; + & !FilterBy::CASE_SENSITIVE + & !FilterBy::TAGS; } else if to_filter_by == FilterBy::CASE_SENSITIVE { to_filter_by = @@ -275,6 +276,7 @@ impl Revlog { pub fn filter(&mut self, filter_by: &str) -> Result<()> { let pre_processed_string = Self::pre_process_string(filter_by.to_string()); + println!("{}", pre_processed_string); let trimmed_string = pre_processed_string.trim().to_string(); if filter_by == "" { self.async_filter.stop_filter(); @@ -312,6 +314,7 @@ impl Revlog { let mut v = vec![]; let (second, third) = rest_of_string.split_at(last_bracket); + println!("{}___{}___{}", first, second, third); if let Some((first, third)) = first .strip_suffix('(') .zip(third.strip_prefix(')')) @@ -322,6 +325,10 @@ impl Revlog { "{}{}{}", first, element, third )); + + // std::thread::sleep( + // std::time::Duration::from_secs(2), + //); } return v.join("||"); } @@ -334,22 +341,10 @@ impl Revlog { let mut brack_count = 0; let mut char_iter = s.chars(); let mut ending_brakcet_pos = None; - let mut iter_count = 0; + let mut iter_count: usize = 0; while let Some(c) = char_iter.next() { - if c == '&' { - if let Some(c2) = char_iter.next() { - { - iter_count += 1; - if c2 == '&' { - if let Some(c3) = char_iter.next() { - iter_count += 1; - if c3 == '(' { - brack_count += 1; - } - } - } - } - } + if c == '(' { + brack_count += 1; } else if c == ')' { if brack_count == 0 { // Found From 16473573d808bf9a273f0c846544ba5d428b1cf0 Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Sat, 13 Feb 2021 12:31:59 +0000 Subject: [PATCH 69/97] Remove unneeded comments --- src/tabs/revlog.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/tabs/revlog.rs b/src/tabs/revlog.rs index 8da35e72e1..229c42b0d6 100644 --- a/src/tabs/revlog.rs +++ b/src/tabs/revlog.rs @@ -314,7 +314,6 @@ impl Revlog { let mut v = vec![]; let (second, third) = rest_of_string.split_at(last_bracket); - println!("{}___{}___{}", first, second, third); if let Some((first, third)) = first .strip_suffix('(') .zip(third.strip_prefix(')')) @@ -325,10 +324,6 @@ impl Revlog { "{}{}{}", first, element, third )); - - // std::thread::sleep( - // std::time::Duration::from_secs(2), - //); } return v.join("||"); } From 507d6f8560986519bfb833961e0e1782df94c86e Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Sat, 13 Feb 2021 12:38:12 +0000 Subject: [PATCH 70/97] Small varible name change --- src/tabs/revlog.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tabs/revlog.rs b/src/tabs/revlog.rs index 229c42b0d6..ad7b5babeb 100644 --- a/src/tabs/revlog.rs +++ b/src/tabs/revlog.rs @@ -318,11 +318,11 @@ impl Revlog { .strip_suffix('(') .zip(third.strip_prefix(')')) { - for element in second.split("||") { - // Append first, prepend third onto branket element + for inside_bracket_item in second.split("||") { + // Append first, prepend third onto bracket element v.push(format!( "{}{}{}", - first, element, third + first, inside_bracket_item, third )); } return v.join("||"); From 32eb3e27ff6ce4b85ff6d2cf8a786c467177417e Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Sat, 13 Feb 2021 12:45:21 +0000 Subject: [PATCH 71/97] Reset LIMIT_COUNT in revlog to 3000 --- asyncgit/src/revlog.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/asyncgit/src/revlog.rs b/asyncgit/src/revlog.rs index 921000b372..fd1f77d242 100644 --- a/asyncgit/src/revlog.rs +++ b/asyncgit/src/revlog.rs @@ -35,7 +35,7 @@ pub struct AsyncLog { background: Arc, } -static LIMIT_COUNT: usize = 5; +static LIMIT_COUNT: usize = 3000; static SLEEP_FOREGROUND: Duration = Duration::from_millis(2); static SLEEP_BACKGROUND: Duration = Duration::from_millis(1000); From 501a194bdae7922e9c4ab855d3eed4f99da77e7b Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Sat, 13 Feb 2021 12:46:22 +0000 Subject: [PATCH 72/97] Remove unneeded logging --- src/tabs/revlog.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tabs/revlog.rs b/src/tabs/revlog.rs index ad7b5babeb..251efb9043 100644 --- a/src/tabs/revlog.rs +++ b/src/tabs/revlog.rs @@ -276,7 +276,6 @@ impl Revlog { pub fn filter(&mut self, filter_by: &str) -> Result<()> { let pre_processed_string = Self::pre_process_string(filter_by.to_string()); - println!("{}", pre_processed_string); let trimmed_string = pre_processed_string.trim().to_string(); if filter_by == "" { self.async_filter.stop_filter(); From fe6d81738bbfa8e0e869f4d59c31dbe4910e10d5 Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Thu, 18 Feb 2021 17:36:54 +0000 Subject: [PATCH 73/97] Remove amount argument from fetch_helper --- asyncgit/src/revlog.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/asyncgit/src/revlog.rs b/asyncgit/src/revlog.rs index fd1f77d242..60f7bd6482 100644 --- a/asyncgit/src/revlog.rs +++ b/asyncgit/src/revlog.rs @@ -126,7 +126,6 @@ impl AsyncLog { arc_current, arc_background, &sender, - LIMIT_COUNT, ) .expect("failed to fetch"); @@ -142,15 +141,14 @@ impl AsyncLog { arc_current: Arc>>, arc_background: Arc, sender: &Sender, - amount: usize, ) -> Result<()> { - let mut entries = Vec::with_capacity(amount); + let mut entries = Vec::with_capacity(LIMIT_COUNT); let r = repo(CWD)?; let mut walker = LogWalker::new(&r); loop { entries.clear(); let res_is_err = - walker.read(&mut entries, amount).is_err(); + walker.read(&mut entries, LIMIT_COUNT).is_err(); if !res_is_err { let mut current = arc_current.lock()?; From 447d0952cf5b8f5f4e900cef83e43b1cfa0f7c9b Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Thu, 18 Feb 2021 17:38:56 +0000 Subject: [PATCH 74/97] Move comment above derive --- asyncgit/src/sync/commits_info.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/asyncgit/src/sync/commits_info.rs b/asyncgit/src/sync/commits_info.rs index d94378e9d5..8a69ed1401 100644 --- a/asyncgit/src/sync/commits_info.rs +++ b/asyncgit/src/sync/commits_info.rs @@ -106,8 +106,8 @@ pub fn get_message( } } -#[inline] /// +#[inline] pub fn limit_str(s: &str, limit: usize) -> &str { if let Some(first) = s.lines().next() { let mut limit = limit.min(first.len()); From e68938d38d4066188990d2ac4d78aa6a8c3600d6 Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Thu, 18 Feb 2021 17:52:44 +0000 Subject: [PATCH 75/97] Create function get_tags --- src/components/utils/async_commit_filter.rs | 52 +++++++++++---------- 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/src/components/utils/async_commit_filter.rs b/src/components/utils/async_commit_filter.rs index 3912b68272..c7b1af946e 100644 --- a/src/components/utils/async_commit_filter.rs +++ b/src/components/utils/async_commit_filter.rs @@ -1,6 +1,6 @@ use anyhow::Result; use asyncgit::{ - sync::{self, limit_str, CommitId, CommitInfo}, + sync::{self, limit_str, CommitId, CommitInfo, Tags}, AsyncLog, AsyncNotification, AsyncTags, CWD, }; use bitflags::bitflags; @@ -229,7 +229,31 @@ impl AsyncCommitFilterer { .collect() } - #[allow(clippy::too_many_lines)] + /// If the filtering string contain filtering by tags + /// return them, else don't get the tags + fn get_tags( + filter_strings: &Vec>, + git_tags: &mut AsyncTags, + ) -> Result> { + let mut contains_tags = false; + for or in filter_strings { + for (_, filter_by) in or { + if filter_by.contains(FilterBy::TAGS) { + contains_tags = true; + break; + } + } + if contains_tags { + break; + } + } + + if contains_tags { + return git_tags.last().map_err(|e| anyhow::anyhow!(e)); + } + Ok(None) + } + pub fn start_filter( &mut self, filter_strings: Vec>, @@ -255,28 +279,8 @@ impl AsyncCommitFilterer { self.is_pending_local.replace(true); // If the search does not contain tags, do not include them - let mut contains_tags = false; - for or in &filter_strings { - for (_, filter_by) in or { - if filter_by.contains(FilterBy::TAGS) { - contains_tags = true; - break; - } - } - if contains_tags { - break; - } - } - - let tags = if contains_tags { - if let Ok(o) = self.git_tags.last() { - o - } else { - None - } - } else { - None - }; + let tags = + Self::get_tags(&filter_strings, &mut self.git_tags)?; rayon_core::spawn(move || { // Only 1 thread can filter at a time From 71582a7005b83d38753b3811ee1387b8de5e256d Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Thu, 18 Feb 2021 17:56:21 +0000 Subject: [PATCH 76/97] Remove added ; --- src/tabs/revlog.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tabs/revlog.rs b/src/tabs/revlog.rs index 251efb9043..da02b5e5c1 100644 --- a/src/tabs/revlog.rs +++ b/src/tabs/revlog.rs @@ -177,7 +177,7 @@ impl Revlog { if let Ok(commits) = commits { self.list.items().set_items(want_min, commits); - }; + } Ok(()) } From f933bf26d380dca7c3730249c1e8a67bb4725fd9 Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Thu, 18 Feb 2021 17:58:08 +0000 Subject: [PATCH 77/97] Add comment to get_ending_bracket --- src/tabs/revlog.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tabs/revlog.rs b/src/tabs/revlog.rs index da02b5e5c1..02bf967e8b 100644 --- a/src/tabs/revlog.rs +++ b/src/tabs/revlog.rs @@ -331,6 +331,7 @@ impl Revlog { s.to_string() } + // Get outer matching brakets in a string pub fn get_ending_bracket(s: &str) -> Option { let mut brack_count = 0; let mut char_iter = s.chars(); From d1c3b546f0bc582e489f04359459186bb235bd45 Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Thu, 18 Feb 2021 17:59:12 +0000 Subject: [PATCH 78/97] Add comment to remove_out_brackets --- src/tabs/revlog.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/tabs/revlog.rs b/src/tabs/revlog.rs index 02bf967e8b..1f40e5dfde 100644 --- a/src/tabs/revlog.rs +++ b/src/tabs/revlog.rs @@ -303,6 +303,7 @@ impl Revlog { s } + /// Remove the brakcets, replacing them with the unbracketed 'full' expression pub fn remove_out_brackets(s: &str) -> String { if let Some(first_bracket) = s.find("&&(") { let (first, rest_of_string) = @@ -331,7 +332,7 @@ impl Revlog { s.to_string() } - // Get outer matching brakets in a string + /// Get outer matching brakets in a string pub fn get_ending_bracket(s: &str) -> Option { let mut brack_count = 0; let mut char_iter = s.chars(); From 1f133c76d20511f15d78206ad7824bfd50e16fbc Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Thu, 18 Feb 2021 18:05:38 +0000 Subject: [PATCH 79/97] Only re-filter if string is different --- src/tabs/revlog.rs | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/src/tabs/revlog.rs b/src/tabs/revlog.rs index 1f40e5dfde..eb713a5496 100644 --- a/src/tabs/revlog.rs +++ b/src/tabs/revlog.rs @@ -43,6 +43,7 @@ pub struct Revlog { branch_name: cached::BranchName, key_config: SharedKeyConfig, is_filtering: bool, + filter_string: String, } impl Revlog { @@ -274,21 +275,26 @@ impl Revlog { } pub fn filter(&mut self, filter_by: &str) -> Result<()> { - let pre_processed_string = - Self::pre_process_string(filter_by.to_string()); - let trimmed_string = pre_processed_string.trim().to_string(); - if filter_by == "" { - self.async_filter.stop_filter(); - self.is_filtering = false; - } else { - let filter_strings = - Self::get_what_to_filter_by(&trimmed_string); - self.async_filter - .start_filter(filter_strings) - .map_err(|e| anyhow::anyhow!(e.to_string()))?; - self.is_filtering = true; + if filter_by != &self.filter_string { + self.filter_string = filter_by.to_string(); + let pre_processed_string = + Self::pre_process_string(filter_by.to_string()); + let trimmed_string = + pre_processed_string.trim().to_string(); + if filter_by == "" { + self.async_filter.stop_filter(); + self.is_filtering = false; + } else { + let filter_strings = + Self::get_what_to_filter_by(&trimmed_string); + self.async_filter + .start_filter(filter_strings) + .map_err(|e| anyhow::anyhow!(e.to_string()))?; + self.is_filtering = true; + } + return self.update(); } - self.update() + Ok(()) } /// pre process string to remove any brackets From 6124b9be8a20614303ddac2f8beb8451469eafa1 Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Thu, 18 Feb 2021 18:06:16 +0000 Subject: [PATCH 80/97] Add filter_string to new revlog --- src/tabs/revlog.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tabs/revlog.rs b/src/tabs/revlog.rs index eb713a5496..c3946dab69 100644 --- a/src/tabs/revlog.rs +++ b/src/tabs/revlog.rs @@ -85,6 +85,7 @@ impl Revlog { branch_name: cached::BranchName::new(CWD), key_config, is_filtering: false, + filter_string: "".to_string(), } } From 4b07b3ab8ab4c8b264fd133b9cf439537389ce4d Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Thu, 18 Feb 2021 18:09:37 +0000 Subject: [PATCH 81/97] Change back to set_total_count in commitlist --- src/components/commitlist.rs | 2 +- src/tabs/revlog.rs | 5 ++--- src/tabs/stashlist.rs | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/components/commitlist.rs b/src/components/commitlist.rs index d8b44cb17a..a39777e15f 100644 --- a/src/components/commitlist.rs +++ b/src/components/commitlist.rs @@ -84,7 +84,7 @@ impl CommitList { } /// - pub fn update_total_count(&mut self, count: usize) { + pub fn set_total_count(&mut self, count: usize) { self.count_total = count; self.selection = cmp::min(self.selection, self.selection_max()); diff --git a/src/tabs/revlog.rs b/src/tabs/revlog.rs index c3946dab69..22d6e1b40a 100644 --- a/src/tabs/revlog.rs +++ b/src/tabs/revlog.rs @@ -101,11 +101,10 @@ impl Revlog { pub fn update(&mut self) -> Result<()> { if self.visible { let log_changed = if self.is_filtering { - self.list - .update_total_count(self.async_filter.count()); + self.list.set_total_count(self.async_filter.count()); self.async_filter.fetch() == FilterStatus::Filtering } else { - self.list.update_total_count(self.git_log.count()?); + self.list.set_total_count(self.git_log.count()?); self.git_log.fetch()? == FetchStatus::Started }; diff --git a/src/tabs/stashlist.rs b/src/tabs/stashlist.rs index d1016c0cf5..d6782c61bb 100644 --- a/src/tabs/stashlist.rs +++ b/src/tabs/stashlist.rs @@ -48,7 +48,7 @@ impl StashList { let commits = sync::get_commits_info(CWD, stashes.as_slice(), 100)?; - self.list.update_total_count(commits.len()); + self.list.set_total_count(commits.len()); self.list.items().set_items(0, commits); } From d70cc4fca3a052133be9257f0a803664fb131fa0 Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Thu, 18 Feb 2021 18:25:37 +0000 Subject: [PATCH 82/97] Fix clippy warnings and change while to for in get_ending_bracket --- src/components/utils/async_commit_filter.rs | 2 +- src/tabs/revlog.rs | 9 +++------ 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/components/utils/async_commit_filter.rs b/src/components/utils/async_commit_filter.rs index c7b1af946e..d7711f58f7 100644 --- a/src/components/utils/async_commit_filter.rs +++ b/src/components/utils/async_commit_filter.rs @@ -232,7 +232,7 @@ impl AsyncCommitFilterer { /// If the filtering string contain filtering by tags /// return them, else don't get the tags fn get_tags( - filter_strings: &Vec>, + filter_strings: &[Vec<(String, FilterBy)>], git_tags: &mut AsyncTags, ) -> Result> { let mut contains_tags = false; diff --git a/src/tabs/revlog.rs b/src/tabs/revlog.rs index 22d6e1b40a..3293bceb6e 100644 --- a/src/tabs/revlog.rs +++ b/src/tabs/revlog.rs @@ -275,7 +275,7 @@ impl Revlog { } pub fn filter(&mut self, filter_by: &str) -> Result<()> { - if filter_by != &self.filter_string { + if filter_by != self.filter_string { self.filter_string = filter_by.to_string(); let pre_processed_string = Self::pre_process_string(filter_by.to_string()); @@ -341,21 +341,18 @@ impl Revlog { /// Get outer matching brakets in a string pub fn get_ending_bracket(s: &str) -> Option { let mut brack_count = 0; - let mut char_iter = s.chars(); let mut ending_brakcet_pos = None; - let mut iter_count: usize = 0; - while let Some(c) = char_iter.next() { + for (i, c) in s.chars().enumerate() { if c == '(' { brack_count += 1; } else if c == ')' { if brack_count == 0 { // Found - ending_brakcet_pos = Some(iter_count); + ending_brakcet_pos = Some(i); break; } brack_count -= 1; } - iter_count += 1; } ending_brakcet_pos } From 2d3cf33e8415ec050084c501798a89c223341801 Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Thu, 18 Feb 2021 18:48:54 +0000 Subject: [PATCH 83/97] Fix search by trimming string --- src/tabs/revlog.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tabs/revlog.rs b/src/tabs/revlog.rs index 3293bceb6e..945095f63b 100644 --- a/src/tabs/revlog.rs +++ b/src/tabs/revlog.rs @@ -261,11 +261,11 @@ impl Revlog { )); } else { and_vec.push(( - split_sub.to_string(), + split_sub.trim().to_string(), FilterBy::all() & !FilterBy::NOT & !FilterBy::CASE_SENSITIVE, - )) + )); } } search_vec.push(and_vec.clone()); From 7b610b3d95f4794efd7543ac47b4780ec104ea10 Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Thu, 18 Feb 2021 18:49:52 +0000 Subject: [PATCH 84/97] Add brackets round tag filter in async_filter --- src/components/utils/async_commit_filter.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/components/utils/async_commit_filter.rs b/src/components/utils/async_commit_filter.rs index d7711f58f7..4740383088 100644 --- a/src/components/utils/async_commit_filter.rs +++ b/src/components/utils/async_commit_filter.rs @@ -106,11 +106,11 @@ impl AsyncCommitFilterer { is_and = if filter.contains(FilterBy::NOT) { is_and - && (filter + && ((filter .contains(FilterBy::TAGS) && tags.as_ref().map_or(false, |t| t.get(&commit.id).map_or(true, |commit_tags| commit_tags.iter().filter(|tag_string|{ !tag_string.contains(s) - }).count() > 0)) + }).count() > 0))) || (filter .contains(FilterBy::SHA) && !commit @@ -129,11 +129,11 @@ impl AsyncCommitFilterer { .contains(s))) } else { is_and - && (filter + && ((filter .contains(FilterBy::TAGS) && tags.as_ref().map_or(false, |t| t.get(&commit.id).map_or(false, |commit_tags| commit_tags.iter().filter(|tag_string|{ tag_string.contains(s) - }).count() > 0)) + }).count() > 0))) || (filter .contains(FilterBy::SHA) && commit @@ -155,11 +155,11 @@ impl AsyncCommitFilterer { is_and = if filter.contains(FilterBy::NOT) { is_and - && (filter + && ((filter .contains(FilterBy::TAGS) && tags.as_ref().map_or(false, |t| t.get(&commit.id).map_or(true, |commit_tags| commit_tags.iter().filter(|tag_string|{ !tag_string.to_lowercase().contains(&s.to_lowercase()) - }).count() > 0)) + }).count() > 0))) || (filter .contains(FilterBy::SHA) && !commit @@ -187,11 +187,11 @@ impl AsyncCommitFilterer { ))) } else { is_and - && (filter + && ((filter .contains(FilterBy::TAGS) && tags.as_ref().map_or(false, |t| t.get(&commit.id).map_or(false, |commit_tags| commit_tags.iter().filter(|tag_string|{ tag_string.to_lowercase().contains(&s.to_lowercase()) - }).count() > 0)) + }).count() > 0))) || (filter .contains(FilterBy::SHA) && commit From 6ab22fac092eca52b9a4c1029796a91dd0d8f8a7 Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Fri, 19 Feb 2021 15:15:45 +0000 Subject: [PATCH 85/97] Add search filter commits to readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 49c5c7e2c9..cfb6294d2b 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ - Stashing (save, apply, drop, and inspect) - Push to remote - Branch List (create, rename, delete) -- Browse commit log, diff committed changes +- Browse commit log, diff committed changes, search/filter commits - Scalable terminal UI layout - Async [input polling](assets/perf_compare.jpg) - Async git API for fluid control From 2a99ed524c59a464cdc2ea19a705eee9a66200a8 Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Fri, 19 Feb 2021 15:27:02 +0000 Subject: [PATCH 86/97] Remove is_and && from filter --- src/components/utils/async_commit_filter.rs | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/components/utils/async_commit_filter.rs b/src/components/utils/async_commit_filter.rs index 4740383088..51df3a8665 100644 --- a/src/components/utils/async_commit_filter.rs +++ b/src/components/utils/async_commit_filter.rs @@ -105,8 +105,7 @@ impl AsyncCommitFilterer { if filter.contains(FilterBy::CASE_SENSITIVE) { is_and = if filter.contains(FilterBy::NOT) { - is_and - && ((filter + (filter .contains(FilterBy::TAGS) && tags.as_ref().map_or(false, |t| t.get(&commit.id).map_or(true, |commit_tags| commit_tags.iter().filter(|tag_string|{ !tag_string.contains(s) @@ -126,10 +125,9 @@ impl AsyncCommitFilterer { FilterBy::MESSAGE, ) && !commit .message - .contains(s))) + .contains(s)) } else { - is_and - && ((filter + (filter .contains(FilterBy::TAGS) && tags.as_ref().map_or(false, |t| t.get(&commit.id).map_or(false, |commit_tags| commit_tags.iter().filter(|tag_string|{ tag_string.contains(s) @@ -149,13 +147,12 @@ impl AsyncCommitFilterer { FilterBy::MESSAGE, ) && commit .message - .contains(s))) + .contains(s)) } } else { is_and = if filter.contains(FilterBy::NOT) { - is_and - && ((filter + (filter .contains(FilterBy::TAGS) && tags.as_ref().map_or(false, |t| t.get(&commit.id).map_or(true, |commit_tags| commit_tags.iter().filter(|tag_string|{ !tag_string.to_lowercase().contains(&s.to_lowercase()) @@ -184,10 +181,9 @@ impl AsyncCommitFilterer { .to_lowercase() .contains( &s.to_lowercase(), - ))) + )) } else { - is_and - && ((filter + (filter .contains(FilterBy::TAGS) && tags.as_ref().map_or(false, |t| t.get(&commit.id).map_or(false, |commit_tags| commit_tags.iter().filter(|tag_string|{ tag_string.to_lowercase().contains(&s.to_lowercase()) @@ -216,7 +212,7 @@ impl AsyncCommitFilterer { .to_lowercase() .contains( &s.to_lowercase(), - ))) + )) } } } From c777ef3f9dc7cb06f8d221b2819f421a60202e4d Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Fri, 19 Feb 2021 16:20:03 +0000 Subject: [PATCH 87/97] Remove ALT down to focus on search --- src/keys.rs | 2 -- src/tabs/revlog.rs | 3 --- 2 files changed, 5 deletions(-) diff --git a/src/keys.rs b/src/keys.rs index 34e84984b1..1d82d6c851 100644 --- a/src/keys.rs +++ b/src/keys.rs @@ -34,7 +34,6 @@ pub struct KeyConfig { pub open_commit: KeyEvent, pub open_commit_editor: KeyEvent, pub show_find_commit_text_input: KeyEvent, - pub focus_find_commit: KeyEvent, pub open_help: KeyEvent, pub move_left: KeyEvent, pub move_right: KeyEvent, @@ -89,7 +88,6 @@ impl Default for KeyConfig { open_commit: KeyEvent { code: KeyCode::Char('c'), modifiers: KeyModifiers::empty()}, open_commit_editor: KeyEvent { code: KeyCode::Char('e'), modifiers:KeyModifiers::CONTROL}, show_find_commit_text_input: KeyEvent {code: KeyCode::Char('s'), modifiers: KeyModifiers::empty()}, - focus_find_commit: KeyEvent {code: KeyCode::Down, modifiers: KeyModifiers::ALT}, open_help: KeyEvent { code: KeyCode::Char('h'), modifiers: KeyModifiers::empty()}, move_left: KeyEvent { code: KeyCode::Left, modifiers: KeyModifiers::empty()}, move_right: KeyEvent { code: KeyCode::Right, modifiers: KeyModifiers::empty()}, diff --git a/src/tabs/revlog.rs b/src/tabs/revlog.rs index 945095f63b..b08dda5e97 100644 --- a/src/tabs/revlog.rs +++ b/src/tabs/revlog.rs @@ -472,9 +472,6 @@ impl Component for Revlog { self.find_commit.toggle_visible()?; self.find_commit.focus(true); return Ok(true); - } else if k == self.key_config.focus_find_commit { - self.find_commit.focus(true); - return Ok(true); } else if k == self.key_config.exit_popup { self.filter("")?; self.find_commit.clear_input(); From 3fe9a33b78c36da2816e2028059ac7037078039d Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Fri, 19 Feb 2021 16:24:30 +0000 Subject: [PATCH 88/97] Remove comment about getting tags from start_filter --- src/components/utils/async_commit_filter.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/utils/async_commit_filter.rs b/src/components/utils/async_commit_filter.rs index 51df3a8665..9a89bcac05 100644 --- a/src/components/utils/async_commit_filter.rs +++ b/src/components/utils/async_commit_filter.rs @@ -274,7 +274,6 @@ impl AsyncCommitFilterer { let cur_thread_mutex = Arc::clone(&self.filter_thread_mutex); self.is_pending_local.replace(true); - // If the search does not contain tags, do not include them let tags = Self::get_tags(&filter_strings, &mut self.git_tags)?; From dd158e0c9868074b5ee190d852c514284e6fa502 Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Fri, 19 Feb 2021 16:39:23 +0000 Subject: [PATCH 89/97] Remove continue filter comment --- src/components/utils/async_commit_filter.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/components/utils/async_commit_filter.rs b/src/components/utils/async_commit_filter.rs index 9a89bcac05..0a2efe0baf 100644 --- a/src/components/utils/async_commit_filter.rs +++ b/src/components/utils/async_commit_filter.rs @@ -371,12 +371,6 @@ impl AsyncCommitFilterer { self.filter_finished.store(true, Ordering::Relaxed); } - /// Use if the next item to be filtered is a substring of the previous item. - /// This then only searches through the previous list - //pub fn continue_filter(&mut self, _s: String) -> Result<()> { - // Ok(()) - //} - pub fn get_filter_items( &mut self, start: usize, From b0ee95143b58a49146286519af5613cabe3dc0fb Mon Sep 17 00:00:00 2001 From: Richard Menzies Date: Thu, 25 Feb 2021 00:44:08 +0000 Subject: [PATCH 90/97] Fix merge problems --- src/components/textinput.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/components/textinput.rs b/src/components/textinput.rs index 8938046bd9..e8849fe4bc 100644 --- a/src/components/textinput.rs +++ b/src/components/textinput.rs @@ -39,11 +39,8 @@ pub struct TextInputComponent { key_config: SharedKeyConfig, cursor_position: usize, input_type: InputType, -<<<<<<< HEAD should_use_rect: bool, -======= current_area: Cell, ->>>>>>> master } impl TextInputComponent { @@ -65,11 +62,8 @@ impl TextInputComponent { default_msg: default_msg.to_string(), cursor_position: 0, input_type: InputType::Multiline, -<<<<<<< HEAD should_use_rect: false, -======= current_area: Cell::new(Rect::default()), ->>>>>>> master } } From 82ce6fc9f4646a5d2f711655b0a46f2621f3e5ed Mon Sep 17 00:00:00 2001 From: Anton Rapetov Date: Sun, 25 Apr 2021 10:59:49 -0400 Subject: [PATCH 91/97] Add tests for `Revlog::get_what_to_filter_by` --- src/tabs/revlog.rs | 150 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 150 insertions(+) diff --git a/src/tabs/revlog.rs b/src/tabs/revlog.rs index b08dda5e97..b6538ea493 100644 --- a/src/tabs/revlog.rs +++ b/src/tabs/revlog.rs @@ -551,3 +551,153 @@ impl Component for Revlog { Ok(()) } } + +#[cfg(test)] +mod test { + use super::Revlog; + use crate::components::async_commit_filter::FilterBy; + + #[test] + fn test_get_what_to_filter_by_flags() { + assert_eq!( + Revlog::get_what_to_filter_by("foo"), + vec![vec![("foo".to_owned(), FilterBy::everywhere())]] + ); + + assert_eq!( + Revlog::get_what_to_filter_by(":s foo"), + vec![vec![("foo".to_owned(), FilterBy::SHA)]] + ); + + assert_eq!( + Revlog::get_what_to_filter_by(":sm foo"), + vec![vec![( + "foo".to_owned(), + FilterBy::SHA | FilterBy::MESSAGE + )]] + ); + + assert_eq!( + Revlog::get_what_to_filter_by(":samt foo"), + vec![vec![("foo".to_owned(), FilterBy::everywhere())]] + ); + + assert_eq!( + Revlog::get_what_to_filter_by(":!csamt foo"), + vec![vec![("foo".to_owned(), FilterBy::all())]] + ); + + assert_eq!( + Revlog::get_what_to_filter_by(":!c foo"), + vec![vec![("foo".to_owned(), FilterBy::all())]] + ); + + assert_eq!( + Revlog::get_what_to_filter_by(":! foo"), + vec![vec![( + "foo".to_owned(), + FilterBy::everywhere() | FilterBy::NOT + )]] + ); + + assert_eq!( + Revlog::get_what_to_filter_by(":c foo"), + vec![vec![( + "foo".to_owned(), + FilterBy::everywhere() | FilterBy::CASE_SENSITIVE + )]] + ); + + assert_eq!( + Revlog::get_what_to_filter_by(":!m foo"), + vec![vec![( + "foo".to_owned(), + FilterBy::MESSAGE | FilterBy::NOT + )]] + ); + } + + #[test] + fn test_get_what_to_filter_by_log_op() { + assert_eq!( + Revlog::get_what_to_filter_by("foo && bar"), + vec![vec![ + ("foo".to_owned(), FilterBy::everywhere()), + ("bar".to_owned(), FilterBy::everywhere()) + ]] + ); + + assert_eq!( + Revlog::get_what_to_filter_by("foo || bar"), + vec![ + vec![("foo".to_owned(), FilterBy::everywhere())], + vec![("bar".to_owned(), FilterBy::everywhere())] + ] + ); + + assert_eq!( + Revlog::get_what_to_filter_by("foo && bar || :m baz"), + vec![ + vec![ + ("foo".to_owned(), FilterBy::everywhere()), + ("bar".to_owned(), FilterBy::everywhere()) + ], + vec![("baz".to_owned(), FilterBy::MESSAGE)] + ] + ); + } + + #[test] + fn test_get_what_to_filter_by_spaces() { + assert_eq!( + Revlog::get_what_to_filter_by("foo&&bar"), + vec![vec![ + ("foo".to_owned(), FilterBy::everywhere()), + ("bar".to_owned(), FilterBy::everywhere()) + ]] + ); + assert_eq!( + Revlog::get_what_to_filter_by(" foo && bar "), + vec![vec![ + ("foo".to_owned(), FilterBy::everywhere()), + ("bar".to_owned(), FilterBy::everywhere()) + ]] + ); + + assert_eq!( + Revlog::get_what_to_filter_by(" foo bar baz "), + vec![vec![( + "foo bar baz".to_owned(), + FilterBy::everywhere() + )]] + ); + assert_eq!( + Revlog::get_what_to_filter_by(" :m foo bar baz "), + vec![vec![( + "foo bar baz".to_owned(), + FilterBy::MESSAGE + )]] + ); + assert_eq!( + Revlog::get_what_to_filter_by( + " :m foo bar baz && qwe t " + ), + vec![vec![ + ("foo bar baz".to_owned(), FilterBy::MESSAGE), + ("qwe t".to_owned(), FilterBy::everywhere()) + ]] + ); + } + + #[test] + fn test_get_what_to_filter_by_invalid_flags_ignored() { + assert_eq!( + Revlog::get_what_to_filter_by(":q foo"), + vec![vec![("foo".to_owned(), FilterBy::everywhere())]] + ); + assert_eq!( + Revlog::get_what_to_filter_by(":mq foo"), + vec![vec![("foo".to_owned(), FilterBy::MESSAGE)]] + ); + } +} From f12fde4392bca3df38b1001b8d0754b58032c7a9 Mon Sep 17 00:00:00 2001 From: Anton Rapetov Date: Sun, 25 Apr 2021 11:00:57 -0400 Subject: [PATCH 92/97] Refactor, fix a few bugs(with space handling), and add documentation to --- src/components/utils/async_commit_filter.rs | 33 +++++++ src/tabs/revlog.rs | 96 +++++++++------------ 2 files changed, 73 insertions(+), 56 deletions(-) diff --git a/src/components/utils/async_commit_filter.rs b/src/components/utils/async_commit_filter.rs index 0a2efe0baf..181adc75ca 100644 --- a/src/components/utils/async_commit_filter.rs +++ b/src/components/utils/async_commit_filter.rs @@ -6,6 +6,7 @@ use asyncgit::{ use bitflags::bitflags; use crossbeam_channel::{Sender, TryRecvError}; use parking_lot::Mutex; +use std::convert::TryFrom; use std::{ cell::RefCell, sync::{ @@ -32,6 +33,38 @@ bitflags! { } } +impl FilterBy { + pub fn everywhere() -> Self { + Self::all() & !Self::NOT & !Self::CASE_SENSITIVE + } + + pub fn exclude_modifiers(self) -> Self { + self & !Self::NOT & !Self::CASE_SENSITIVE + } +} + +impl Default for FilterBy { + fn default() -> Self { + Self::all() & !Self::NOT & !Self::CASE_SENSITIVE + } +} + +impl TryFrom for FilterBy { + type Error = anyhow::Error; + + fn try_from(v: char) -> Result { + match v { + 's' => Ok(Self::SHA), + 'a' => Ok(Self::AUTHOR), + 'm' => Ok(Self::MESSAGE), + '!' => Ok(Self::NOT), + 'c' => Ok(Self::CASE_SENSITIVE), + 't' => Ok(Self::TAGS), + _ => Err(anyhow::anyhow!(format!("Unknown flag: {}", v))), + } + } +} + #[derive(PartialEq)] pub enum FilterStatus { Filtering, diff --git a/src/tabs/revlog.rs b/src/tabs/revlog.rs index b6538ea493..e8f768db0d 100644 --- a/src/tabs/revlog.rs +++ b/src/tabs/revlog.rs @@ -20,6 +20,7 @@ use asyncgit::{ }; use crossbeam_channel::Sender; use crossterm::event::Event; +use std::convert::TryFrom; use std::time::Duration; use sync::CommitTags; use tui::{ @@ -203,70 +204,53 @@ impl Revlog { }) } + /// Parses search string into individual sub-searches. + /// Each sub-search is a tuple of (string-to-search, flags-where-to-search) + /// + /// Returns vec of vec of sub-searches. + /// Where search results: + /// 1. from outer vec should be combined via 'disjunction' (or); + /// 2. from inter vec should be combined via 'conjunction' (and). + /// + /// Currently parentheses in the `filter_by_str` are not supported. + /// They should be removed by `Self::pre_process_string`. fn get_what_to_filter_by( filter_by_str: &str, ) -> Vec> { - let mut search_vec = vec![]; + let mut search_vec = Vec::new(); let mut and_vec = Vec::new(); for or in filter_by_str.split("||") { - for split_sub in or.split("&&") { - if let Some(':') = split_sub.chars().next() { - let mut to_filter_by = FilterBy::empty(); - let mut split_str = - split_sub.split(' ').collect::>(); - if split_str.len() == 1 { - split_str.push(""); - } - let first = split_str[0]; - if first.contains('s') { - to_filter_by |= FilterBy::SHA; - } - if first.contains('a') { - to_filter_by |= FilterBy::AUTHOR; - } - if first.contains('m') { - to_filter_by |= FilterBy::MESSAGE; - } - if first.contains('c') { - to_filter_by |= FilterBy::CASE_SENSITIVE; - } - if first.contains('t') { - to_filter_by |= FilterBy::TAGS; - } - if first.contains('!') { - to_filter_by |= FilterBy::NOT; - } - - if to_filter_by.is_empty() { - to_filter_by = FilterBy::all() - & !FilterBy::NOT - & !FilterBy::CASE_SENSITIVE; - } else if to_filter_by - == FilterBy::CASE_SENSITIVE & FilterBy::NOT - { - FilterBy::all(); - } else if to_filter_by == FilterBy::NOT { - to_filter_by = FilterBy::all() - & !FilterBy::CASE_SENSITIVE - & !FilterBy::TAGS; - } else if to_filter_by == FilterBy::CASE_SENSITIVE - { - to_filter_by = - FilterBy::all() & !FilterBy::NOT; - }; - - and_vec.push(( - split_str[1..].join(" ").trim().to_string(), - to_filter_by, - )); - } else { + for split_sub in or.split("&&").map(str::trim) { + if !split_sub.starts_with(":") { and_vec.push(( - split_sub.trim().to_string(), - FilterBy::all() - & !FilterBy::NOT - & !FilterBy::CASE_SENSITIVE, + split_sub.to_string(), + FilterBy::everywhere(), )); + continue; + } + + let mut split_str = split_sub.splitn(2, ' '); + let first = split_str.next().unwrap(); + let mut to_filter_by = first.chars().skip(1).fold( + FilterBy::empty(), + |acc, ch| { + acc | FilterBy::try_from(ch) + .unwrap_or(FilterBy::empty()) + }, + ); + + if to_filter_by.exclude_modifiers().is_empty() { + to_filter_by |= FilterBy::everywhere(); } + + and_vec.push(( + split_str + .next() + .unwrap_or(&"") + .trim_start() + .to_string(), + to_filter_by, + )); } search_vec.push(and_vec.clone()); and_vec.clear(); From 6e31762ed9683ea7b3c1a6933e34c508562e00da Mon Sep 17 00:00:00 2001 From: Anton Rapetov Date: Sun, 25 Apr 2021 14:49:36 -0400 Subject: [PATCH 93/97] Use std::sync::Mutex instead of the one from parking_lot --- Cargo.lock | 1 - Cargo.toml | 1 - src/components/utils/async_commit_filter.rs | 16 ++++++++-------- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b3585423c1..598bbc5514 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -365,7 +365,6 @@ dependencies = [ "dirs-next", "itertools", "log", - "parking_lot", "pprof", "rayon-core", "ron", diff --git a/Cargo.toml b/Cargo.toml index 12c685f8ca..8644cf39d2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,7 +40,6 @@ serde = "1.0" anyhow = "1.0" unicode-width = "0.1" textwrap = "0.13" -parking_lot = "0.11" unicode-truncate = "0.2.0" [target.'cfg(all(target_family="unix",not(target_os="macos")))'.dependencies] diff --git a/src/components/utils/async_commit_filter.rs b/src/components/utils/async_commit_filter.rs index de20d44771..12a313a453 100644 --- a/src/components/utils/async_commit_filter.rs +++ b/src/components/utils/async_commit_filter.rs @@ -5,13 +5,12 @@ use asyncgit::{ }; use bitflags::bitflags; use crossbeam_channel::{Sender, TryRecvError}; -use parking_lot::Mutex; use std::convert::TryFrom; use std::{ cell::RefCell, sync::{ atomic::{AtomicBool, AtomicUsize, Ordering}, - Arc, + Arc, Mutex, }, thread, time::Duration, @@ -313,11 +312,11 @@ impl AsyncCommitFilterer { rayon_core::spawn(move || { // Only 1 thread can filter at a time - let _c = cur_thread_mutex.lock(); - let _p = prev_thread_mutex.lock(); + let _c = cur_thread_mutex.lock().unwrap(); + let _p = prev_thread_mutex.lock().unwrap(); filter_finished.store(false, Ordering::Relaxed); filter_count.store(0, Ordering::Relaxed); - filtered_commits.lock().clear(); + filtered_commits.lock().unwrap().clear(); let mut cur_index: usize = 0; loop { match rx.try_recv() { @@ -357,8 +356,9 @@ impl AsyncCommitFilterer { filtered.len(), Ordering::Relaxed, ); - let mut fc = - filtered_commits.lock(); + let mut fc = filtered_commits + .lock() + .unwrap(); fc.append(&mut filtered); drop(fc); cur_index += SLICE_SIZE; @@ -411,7 +411,7 @@ impl AsyncCommitFilterer { amount: usize, message_length_limit: usize, ) -> Result> { - let fc = self.filtered_commits.lock(); + let fc = self.filtered_commits.lock().unwrap(); let len = fc.len(); let min = start.min(len); let max = min + amount; From efa44c2584a3f959ac03c7fba95483675b4cfc0d Mon Sep 17 00:00:00 2001 From: Anton Rapetov Date: Sun, 25 Apr 2021 14:58:03 -0400 Subject: [PATCH 94/97] Return original formating in KeyConfig::get_hint in src/keys.rs --- src/keys.rs | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/src/keys.rs b/src/keys.rs index ce88736657..d8757205bf 100644 --- a/src/keys.rs +++ b/src/keys.rs @@ -218,21 +218,27 @@ impl KeyConfig { | KeyCode::BackTab | KeyCode::Delete | KeyCode::Insert - | KeyCode::Esc => format!( - "{}{}", - Self::get_modifier_hint(ev.modifiers), - self.get_key_symbol(ev.code) - ), - KeyCode::Char(c) => format!( - "{}{}", - Self::get_modifier_hint(ev.modifiers), - c - ), - KeyCode::F(u) => format!( - "{}F{}", - Self::get_modifier_hint(ev.modifiers), - u - ), + | KeyCode::Esc => { + format!( + "{}{}", + Self::get_modifier_hint(ev.modifiers), + self.get_key_symbol(ev.code) + ) + } + KeyCode::Char(c) => { + format!( + "{}{}", + Self::get_modifier_hint(ev.modifiers), + c + ) + } + KeyCode::F(u) => { + format!( + "{}F{}", + Self::get_modifier_hint(ev.modifiers), + u + ) + } KeyCode::Null => Self::get_modifier_hint(ev.modifiers), } } From 47cdc0934e22b7eb09d0bc2cd618b2e9d8d75776 Mon Sep 17 00:00:00 2001 From: Anton Rapetov Date: Sat, 1 May 2021 20:02:34 -0400 Subject: [PATCH 95/97] Remove used AsyncCommitFilterer::filter_strings field --- src/components/utils/async_commit_filter.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/components/utils/async_commit_filter.rs b/src/components/utils/async_commit_filter.rs index 12a313a453..f8e2ac2ac9 100644 --- a/src/components/utils/async_commit_filter.rs +++ b/src/components/utils/async_commit_filter.rs @@ -74,7 +74,6 @@ pub enum FilterStatus { pub struct AsyncCommitFilterer { git_log: AsyncLog, git_tags: AsyncTags, - filter_strings: Vec>, filtered_commits: Arc>>, filter_count: Arc, filter_finished: Arc, @@ -91,7 +90,6 @@ impl AsyncCommitFilterer { sender: &Sender, ) -> Self { Self { - filter_strings: Vec::new(), git_log, git_tags, filtered_commits: Arc::new(Mutex::new(Vec::new())), @@ -289,8 +287,6 @@ impl AsyncCommitFilterer { ) -> Result<()> { self.stop_filter(); - self.filter_strings = filter_strings.clone(); - let filtered_commits = Arc::clone(&self.filtered_commits); let filter_count = Arc::clone(&self.filter_count); let async_log = self.git_log.clone(); From 0afcc9e0b6e7ca2482bc75ac838bbf1d294c3cf9 Mon Sep 17 00:00:00 2001 From: Anton Rapetov Date: Sat, 1 May 2021 22:24:59 -0400 Subject: [PATCH 96/97] Reformat with rustfmt --- asyncgit/src/sync/commits_info.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/asyncgit/src/sync/commits_info.rs b/asyncgit/src/sync/commits_info.rs index 94b921de1d..0858eb3573 100644 --- a/asyncgit/src/sync/commits_info.rs +++ b/asyncgit/src/sync/commits_info.rs @@ -5,7 +5,9 @@ use scopetime::scope_time; use unicode_truncate::UnicodeTruncateStr; /// identifies a single commit -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)] +#[derive( + Debug, Copy, Clone, PartialEq, Eq, Hash, Ord, PartialOrd, +)] pub struct CommitId(Oid); impl CommitId { From 38eeeeb5174917c6c3e5910ac25756c42fa5ca2b Mon Sep 17 00:00:00 2001 From: Anton Rapetov Date: Sat, 8 May 2021 11:06:15 -0400 Subject: [PATCH 97/97] Fix clippy errors --- src/components/utils/async_commit_filter.rs | 16 ++++++++++------ src/tabs/revlog.rs | 12 +++++++----- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/components/utils/async_commit_filter.rs b/src/components/utils/async_commit_filter.rs index f8e2ac2ac9..aaea4468f4 100644 --- a/src/components/utils/async_commit_filter.rs +++ b/src/components/utils/async_commit_filter.rs @@ -1,4 +1,4 @@ -use anyhow::Result; +use anyhow::{Error, Result}; use asyncgit::{ sync::{self, CommitId, CommitInfo, Tags}, AsyncLog, AsyncNotification, AsyncTags, CWD, @@ -308,11 +308,12 @@ impl AsyncCommitFilterer { rayon_core::spawn(move || { // Only 1 thread can filter at a time - let _c = cur_thread_mutex.lock().unwrap(); - let _p = prev_thread_mutex.lock().unwrap(); + let _c = cur_thread_mutex.lock().expect("mutex poisoned"); + let _p = + prev_thread_mutex.lock().expect("mutex poisoned"); filter_finished.store(false, Ordering::Relaxed); filter_count.store(0, Ordering::Relaxed); - filtered_commits.lock().unwrap().clear(); + filtered_commits.lock().expect("mutex poisoned").clear(); let mut cur_index: usize = 0; loop { match rx.try_recv() { @@ -354,7 +355,7 @@ impl AsyncCommitFilterer { ); let mut fc = filtered_commits .lock() - .unwrap(); + .expect("mutex poisoned"); fc.append(&mut filtered); drop(fc); cur_index += SLICE_SIZE; @@ -407,7 +408,10 @@ impl AsyncCommitFilterer { amount: usize, message_length_limit: usize, ) -> Result> { - let fc = self.filtered_commits.lock().unwrap(); + let fc = self + .filtered_commits + .lock() + .map_err(|_| Error::msg("mutex poisoned"))?; let len = fc.len(); let min = start.min(len); let max = min + amount; diff --git a/src/tabs/revlog.rs b/src/tabs/revlog.rs index a5a99205f4..307c85e4f8 100644 --- a/src/tabs/revlog.rs +++ b/src/tabs/revlog.rs @@ -221,7 +221,7 @@ impl Revlog { let mut and_vec = Vec::new(); for or in filter_by_str.split("||") { for split_sub in or.split("&&").map(str::trim) { - if !split_sub.starts_with(":") { + if !split_sub.starts_with(':') { and_vec.push(( split_sub.to_string(), FilterBy::everywhere(), @@ -230,12 +230,14 @@ impl Revlog { } let mut split_str = split_sub.splitn(2, ' '); - let first = split_str.next().unwrap(); + let first = split_str + .next() + .expect("Split must return at least one element"); let mut to_filter_by = first.chars().skip(1).fold( FilterBy::empty(), |acc, ch| { acc | FilterBy::try_from(ch) - .unwrap_or(FilterBy::empty()) + .unwrap_or_else(|_| FilterBy::empty()) }, ); @@ -246,7 +248,7 @@ impl Revlog { and_vec.push(( split_str .next() - .unwrap_or(&"") + .unwrap_or("") .trim_start() .to_string(), to_filter_by, @@ -265,7 +267,7 @@ impl Revlog { Self::pre_process_string(filter_by.to_string()); let trimmed_string = pre_processed_string.trim().to_string(); - if filter_by == "" { + if filter_by.is_empty() { self.async_filter.stop_filter(); self.is_filtering = false; } else {