Add option to sort by most frequently used

This commit is contained in:
loserMcloser 2022-04-10 22:14:00 -06:00
parent bf216d7e45
commit 3714e5e0be
5 changed files with 60 additions and 41 deletions

View File

@ -41,7 +41,10 @@ exclude = [] # list of regexes for excluded app ids (name of the .desktop file)
# use "" to disable launching commands # use "" to disable launching commands
command_prefix = ":" command_prefix = ":"
frequent_first = true # sort matches of equal quality by most frequently used
recent_first = true # sort matches of equal quality by most recently used recent_first = true # sort matches of equal quality by most recently used
# when both frequent_first and recent_first are set,
# sorting is by frequency first, and recency is used to break ties in frequency
# term_command = "alacritty -e {}" # command for applications run in terminal (default uses "$TERMINAL -e") # term_command = "alacritty -e {}" # command for applications run in terminal (default uses "$TERMINAL -e")

View File

@ -27,7 +27,7 @@ use gio::AppInfo;
use glib::shell_unquote; use glib::shell_unquote;
use crate::locale::string_collate; use crate::locale::string_collate;
use super::{consts::*, Config, Field, History}; use super::{consts::*, Config, Field, HistoryData};
use regex::RegexSet; use regex::RegexSet;
#[derive(Eq)] #[derive(Eq)]
@ -38,7 +38,7 @@ pub struct AppEntry {
pub info: AppInfo, pub info: AppInfo,
pub label: Label, pub label: Label,
pub score: i64, pub score: i64,
pub last_used: u64, pub history: HistoryData
} }
impl AppEntry { impl AppEntry {
@ -81,15 +81,18 @@ impl AppEntry {
impl PartialEq for AppEntry { impl PartialEq for AppEntry {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
self.score.eq(&other.score) && self.last_used.eq(&other.last_used) self.score.eq(&other.score) && self.history.eq(&other.history)
} }
} }
impl Ord for AppEntry { impl Ord for AppEntry {
fn cmp(&self, other: &Self) -> Ordering { fn cmp(&self, other: &Self) -> Ordering {
match self.score.cmp(&other.score) { match self.score.cmp(&other.score) {
Ordering::Equal => match self.last_used.cmp(&other.last_used) { Ordering::Equal => match self.history.usage_count.cmp(&other.history.usage_count) {
Ordering::Equal => string_collate(&self.display_string, &other.display_string), Ordering::Equal => match self.history.last_used.cmp(&other.history.last_used) {
Ordering::Equal => string_collate(&self.display_string, &other.display_string),
ord => ord.reverse()
}
ord => ord.reverse() ord => ord.reverse()
} }
ord => ord.reverse() ord => ord.reverse()
@ -129,7 +132,8 @@ fn add_attrs(list: &AttrList, attrs: &Vec<Attribute>, start: u32, end: u32) {
} }
} }
pub fn load_entries(config: &Config, history: &History) -> HashMap<ListBoxRow, AppEntry> { pub fn load_entries(config: &Config, history: &HashMap<String, HistoryData>)
-> HashMap<ListBoxRow, AppEntry> {
let mut entries = HashMap::new(); let mut entries = HashMap::new();
let icon_theme = IconTheme::default().unwrap(); let icon_theme = IconTheme::default().unwrap();
let apps = gio::AppInfo::all(); let apps = gio::AppInfo::all();
@ -202,9 +206,9 @@ pub fn load_entries(config: &Config, history: &History) -> HashMap<ListBoxRow, A
row.add(&hbox); row.add(&hbox);
row.style_context().add_class(APP_ROW_CLASS); row.style_context().add_class(APP_ROW_CLASS);
let last_used = if config.recent_first { let history_data = history.get(&id).copied().unwrap_or_default();
history.last_used.get(&id).copied().unwrap_or_default() let last_used = if config.recent_first { history_data.last_used } else { 0 };
} else { 0 }; let usage_count = if config.frequent_first { history_data.usage_count } else { 0 };
let app_entry = AppEntry { let app_entry = AppEntry {
display_string, display_string,
@ -213,7 +217,7 @@ pub fn load_entries(config: &Config, history: &History) -> HashMap<ListBoxRow, A
info: app, info: app,
label, label,
score: 100, score: 100,
last_used, history: HistoryData { last_used, usage_count }
}; };
app_entry.set_markup(config); app_entry.set_markup(config);
entries.insert(row, app_entry); entries.insert(row, app_entry);

View File

@ -50,6 +50,7 @@ make_config!(Config {
markup_highlight: Vec<Attribute> = (parse_attributes("foreground=\"red\" underline=\"double\"").unwrap()) "markup_highlight" [deserialize_with = "deserialize_markup"], markup_highlight: Vec<Attribute> = (parse_attributes("foreground=\"red\" underline=\"double\"").unwrap()) "markup_highlight" [deserialize_with = "deserialize_markup"],
markup_extra: Vec<Attribute> = (parse_attributes("font_style=\"italic\" font_size=\"smaller\"").unwrap()) "markup_extra" [deserialize_with = "deserialize_markup"], markup_extra: Vec<Attribute> = (parse_attributes("font_style=\"italic\" font_size=\"smaller\"").unwrap()) "markup_extra" [deserialize_with = "deserialize_markup"],
exclusive: bool = (true) "exclusive", exclusive: bool = (true) "exclusive",
frequent_first: bool = (true) "frequent_first",
recent_first: bool = (true) "recent_first", recent_first: bool = (true) "recent_first",
icon_size: i32 = (64) "icon_size", icon_size: i32 = (64) "icon_size",
lines: i32 = (2) "lines", lines: i32 = (2) "lines",

View File

@ -5,31 +5,42 @@ use std::time::{SystemTime, UNIX_EPOCH};
use super::util::get_history_file; use super::util::get_history_file;
use std::fs::File; use std::fs::File;
#[derive(Deserialize, Serialize)] #[derive(Copy, Clone, Default, Eq, Deserialize, Serialize)]
pub struct History { pub struct HistoryData {
pub last_used: HashMap<String, u64> pub last_used : u64,
pub usage_count : u32
} }
impl History { impl PartialEq for HistoryData {
pub fn load() -> History { fn eq(&self, other: &Self) -> bool {
match get_history_file(false) { self.last_used.eq(&other.last_used) && self.usage_count.eq(&other.usage_count)
Some(file) => {
let config_str = std::fs::read_to_string(file).expect("Cannot read history file");
toml::from_str(&config_str).expect("Cannot parse config: {}")
},
_ => History { last_used: HashMap::new() }
}
}
pub fn save(&self) {
let file = get_history_file(true).expect("Cannot create history file or cache directory");
let mut file = File::create(file).expect("Cannot open history file for writing");
let s = toml::to_string(self).unwrap();
file.write_all(s.as_bytes()).expect("Cannot write to history file");
}
pub fn update(&mut self, id: &str) {
let epoch = SystemTime::now().duration_since(UNIX_EPOCH).expect("Time went backwards");
self.last_used.insert(id.to_string(), epoch.as_secs());
} }
} }
pub fn load_history() -> HashMap<String, HistoryData> {
match get_history_file(false) {
Some(file) => {
let config_str = std::fs::read_to_string(file).expect("Cannot read history file");
toml::from_str(&config_str).expect("Cannot parse config: {}")
},
_ => HashMap::new()
}
}
pub fn save_history(history: &HashMap<String, HistoryData>) {
let file = get_history_file(true).expect("Cannot create history file or cache directory");
let mut file = File::create(file).expect("Cannot open history file for writing");
let s = toml::to_string(history).unwrap();
file.write_all(s.as_bytes()).expect("Cannot write to history file");
}
pub fn update_history(history: &mut HashMap<String, HistoryData>, id: &str) {
let epoch = SystemTime::now().duration_since(UNIX_EPOCH).expect("Time went backwards");
let usage_count;
match history.get(&id.to_string()) {
Some(history_match) => { usage_count = history_match.usage_count + 1 },
None => { usage_count = 1 }
}
history.insert( id.to_string(), HistoryData{ last_used: epoch.as_secs(), usage_count } );
}

View File

@ -85,7 +85,7 @@ fn app_startup(application: &gtk::Application) {
let listbox = gtk::ListBoxBuilder::new().name(LISTBOX_NAME).build(); let listbox = gtk::ListBoxBuilder::new().name(LISTBOX_NAME).build();
scroll.add(&listbox); scroll.add(&listbox);
let history = Rc::new(RefCell::new(History::load())); let history = Rc::new(RefCell::new(load_history()));
let entries = Rc::new(RefCell::new(load_entries(&config, &history.borrow()))); let entries = Rc::new(RefCell::new(load_entries(&config, &history.borrow())));
for (row, _) in &entries.borrow() as &HashMap<ListBoxRow, AppEntry> { for (row, _) in &entries.borrow() as &HashMap<ListBoxRow, AppEntry> {
@ -155,8 +155,8 @@ fn app_startup(application: &gtk::Application) {
launch_app(&e.info, term_command.as_deref()); launch_app(&e.info, term_command.as_deref());
let mut history = history.borrow_mut(); let mut history = history.borrow_mut();
history.update(e.info.id().unwrap().as_str()); update_history(&mut history, e.info.id().unwrap().as_str());
history.save(); save_history(&history);
window.close(); window.close();
} }