mirror of
https://github.com/DorianRudolph/sirula.git
synced 2024-11-29 11:14:17 +03:00
Add option to sort by most frequently used
This commit is contained in:
parent
bf216d7e45
commit
3714e5e0be
@ -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")
|
||||||
|
|
||||||
|
@ -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,19 +81,22 @@ 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 => match self.history.last_used.cmp(&other.history.last_used) {
|
||||||
Ordering::Equal => string_collate(&self.display_string, &other.display_string),
|
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);
|
||||||
|
@ -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",
|
||||||
|
@ -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 {
|
||||||
|
self.last_used.eq(&other.last_used) && self.usage_count.eq(&other.usage_count)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_history() -> HashMap<String, HistoryData> {
|
||||||
match get_history_file(false) {
|
match get_history_file(false) {
|
||||||
Some(file) => {
|
Some(file) => {
|
||||||
let config_str = std::fs::read_to_string(file).expect("Cannot read history file");
|
let config_str = std::fs::read_to_string(file).expect("Cannot read history file");
|
||||||
toml::from_str(&config_str).expect("Cannot parse config: {}")
|
toml::from_str(&config_str).expect("Cannot parse config: {}")
|
||||||
},
|
},
|
||||||
_ => History { last_used: HashMap::new() }
|
_ => HashMap::new()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn save(&self) {
|
pub fn save_history(history: &HashMap<String, HistoryData>) {
|
||||||
let file = get_history_file(true).expect("Cannot create history file or cache directory");
|
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 mut file = File::create(file).expect("Cannot open history file for writing");
|
||||||
let s = toml::to_string(self).unwrap();
|
let s = toml::to_string(history).unwrap();
|
||||||
file.write_all(s.as_bytes()).expect("Cannot write to history file");
|
file.write_all(s.as_bytes()).expect("Cannot write to history file");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update(&mut self, id: &str) {
|
pub fn update_history(history: &mut HashMap<String, HistoryData>, id: &str) {
|
||||||
let epoch = SystemTime::now().duration_since(UNIX_EPOCH).expect("Time went backwards");
|
let epoch = SystemTime::now().duration_since(UNIX_EPOCH).expect("Time went backwards");
|
||||||
self.last_used.insert(id.to_string(), epoch.as_secs());
|
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 } );
|
||||||
}
|
}
|
@ -85,7 +85,7 @@ fn app_startup(application: >k::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: >k::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();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user