-
-
Notifications
You must be signed in to change notification settings - Fork 77
Implemented search history for application plugin #116
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
32de25a
57fdace
dab1260
4a00576
01813a5
d5cae82
48cd51e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,67 @@ | ||
| use std::collections::VecDeque; | ||
| use std::fs; | ||
| use std::env; | ||
|
|
||
| use crate::scrubber::DesktopEntry; | ||
|
|
||
|
|
||
| pub struct History(VecDeque<DesktopEntry>); | ||
|
|
||
| impl History { | ||
| pub fn new() -> Self { | ||
| Self(VecDeque::new()) | ||
| } | ||
|
|
||
| pub fn load() -> Self { | ||
|
|
||
| let path = format!( | ||
| "{}/.cache/anyrun-applications-history", | ||
| env::var("HOME").expect("Unable to determine HOME directory") | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Prefer |
||
| ); | ||
|
|
||
| if let Ok(content) = fs::read_to_string(&path) { | ||
| let history: VecDeque<DesktopEntry> = ron::from_str(&content) | ||
| .unwrap_or_else(|why| { | ||
| eprintln!("Error parsing history: {}", why); | ||
| VecDeque::new() | ||
| }); | ||
| return Self(history); | ||
| } | ||
|
|
||
| Self::new() | ||
| } | ||
|
|
||
| pub fn write(&self) { | ||
|
|
||
| let path = format!( | ||
| "{}/.cache/anyrun-applications-history", | ||
| env::var("HOME").expect("Unable to determine HOME directory") | ||
| ); | ||
|
|
||
| let content = ron::to_string(&self.0).unwrap_or_else(|why| { | ||
| eprintln!("Error serializing history: {}", why); | ||
| String::new() | ||
| }); | ||
| if let Err(why) = fs::write(&path, content) { | ||
| eprintln!("Error writing history: {}", why); | ||
| } | ||
| } | ||
|
|
||
| pub fn add_entry(&mut self, entry: DesktopEntry) { | ||
| self.0.push_front(entry); | ||
| } | ||
|
|
||
| pub fn truncate(&mut self, max_entries: usize) { | ||
| self.0.truncate(max_entries); | ||
| } | ||
|
|
||
| pub fn get_entry_info(&self, entry: &DesktopEntry) -> Option<(usize, usize)> { | ||
| let index = self.0.iter().position(|x| x == entry)?; | ||
| let count = self.0.iter().filter(|x| *x == entry).count(); | ||
| Some((index, count)) | ||
| } | ||
| pub fn count(&self) -> usize { | ||
| self.0.len() | ||
| } | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,6 +10,7 @@ pub struct Config { | |
| desktop_actions: bool, | ||
| max_entries: usize, | ||
| terminal: Option<String>, | ||
| history_size: usize, | ||
| } | ||
|
|
||
| impl Default for Config { | ||
|
|
@@ -18,21 +19,24 @@ impl Default for Config { | |
| desktop_actions: false, | ||
| max_entries: 5, | ||
| terminal: None, | ||
| history_size: 50, | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should be an optional, in a way that |
||
| } | ||
| } | ||
| } | ||
|
|
||
| pub struct State { | ||
| config: Config, | ||
| config: Config, | ||
| entries: Vec<(DesktopEntry, u64)>, | ||
| history: history::History, | ||
| } | ||
|
|
||
| mod scrubber; | ||
| mod history; | ||
|
|
||
| const SENSIBLE_TERMINALS: &[&str] = &["alacritty", "foot", "kitty", "wezterm", "wterm"]; | ||
|
|
||
| #[handler] | ||
| pub fn handler(selection: Match, state: &State) -> HandleResult { | ||
| pub fn handler(selection: Match, state: &mut State) -> HandleResult { | ||
| let entry = state | ||
| .entries | ||
| .iter() | ||
|
|
@@ -74,6 +78,11 @@ pub fn handler(selection: Match, state: &State) -> HandleResult { | |
| eprintln!("Error running desktop entry: {}", why); | ||
| } | ||
|
|
||
| state.history.add_entry(entry.clone()); | ||
| state.history.truncate(state.config.history_size); | ||
| state.history.write(); | ||
|
|
||
|
|
||
| HandleResult::Close | ||
| } | ||
|
|
||
|
|
@@ -95,11 +104,15 @@ pub fn init(config_dir: RString) -> State { | |
| Vec::new() | ||
| }); | ||
|
|
||
| State { config, entries } | ||
| let history = history::History::load(); | ||
| println!("Loaded {} history entries", history.count()); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should be |
||
|
|
||
| State { config, entries, history } | ||
| } | ||
|
|
||
| #[get_matches] | ||
| pub fn get_matches(input: RString, state: &State) -> RVec<Match> { | ||
|
|
||
| let matcher = fuzzy_matcher::skim::SkimMatcherV2::default().smart_case(); | ||
| let mut entries = state | ||
| .entries | ||
|
|
@@ -116,9 +129,18 @@ pub fn get_matches(input: RString, state: &State) -> RVec<Match> { | |
| .keywords | ||
| .iter() | ||
| .map(|keyword| matcher.fuzzy_match(keyword, &input).unwrap_or(0)) | ||
| .sum::<i64>(); | ||
| .sum::<i64>(); | ||
|
|
||
| let mut score = (app_score * 25 + keyword_score) - entry.offset; | ||
| let history_score = state.history.get_entry_info(entry).map(|(index, count)| { | ||
| let recency_bias = i64::max(5-index as i64, 0); | ||
| (count as i64 + recency_bias) * 20 | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since the weighting has changed recently, this likely needs different weighting to make it work properly. |
||
| }).unwrap_or(0); | ||
|
|
||
| if app_score + keyword_score == 0 { | ||
| return None; | ||
| } | ||
|
|
||
| let mut score = (app_score * 25 + keyword_score + history_score) - entry.offset; | ||
|
|
||
| // prioritize actions | ||
| if entry.desc.is_some() { | ||
|
|
@@ -135,17 +157,17 @@ pub fn get_matches(input: RString, state: &State) -> RVec<Match> { | |
|
|
||
| entries.sort_by(|a, b| b.2.cmp(&a.2)); | ||
|
|
||
| entries.truncate(state.config.max_entries); | ||
| entries.truncate(state.config.max_entries); | ||
| entries | ||
| .into_iter() | ||
| .map(|(entry, id, _)| Match { | ||
| title: entry.name.clone().into(), | ||
| description: entry.desc.clone().map(|desc| desc.into()).into(), | ||
| use_pango: false, | ||
| icon: ROption::RSome(entry.icon.clone().into()), | ||
| id: ROption::RSome(id), | ||
| }) | ||
| .collect() | ||
| .into_iter() | ||
| .map(|(entry, id, _)| Match { | ||
| title: entry.name.clone().into(), | ||
| description: entry.desc.clone().map(|desc| desc.into()).into(), | ||
| use_pango: false, | ||
| icon: ROption::RSome(entry.icon.clone().into()), | ||
| id: ROption::RSome(id), | ||
| }) | ||
| .collect() | ||
| } | ||
|
|
||
| #[info] | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be
~/.cache/anyrun/applications-historyin line with what thenix-runplugin uses.