[PATCH wldash v3] feat: add ranking based on usage to launcher widget
Export this patch
A v3, and the last ;)
Less unwrap.
Signed-off-by: Cyril Levis <git@levis.name>
---
src/data.rs | 57 +++++++++++++++++++++++++++++++++++++++++
src/main.rs | 1 +
src/widgets/launcher.rs | 21 ++++++++++++---
3 files changed, 75 insertions(+), 4 deletions(-)
create mode 100644 src/data.rs
diff --git a/src/data.rs b/src/data.rs
new file mode 100644
index 0000000..8992b2f
--- /dev/null
+++ b/src/data.rs
@@ -0,0 +1,57 @@
+use serde::{Deserialize, Serialize};
+use std::collections::HashMap;
+use std::env;
+use std::error::Error;
+use std::fs::{create_dir_all, File, OpenOptions};
+use std::path::PathBuf;
+
+#[derive(Debug, PartialEq, Serialize, Deserialize, Clone, Default)]
+pub struct Data {
+ pub entries: HashMap<String, i64>,
+}
+
+impl Data {
+ pub fn load() -> Result<Data, Box<dyn Error>> {
+ Ok(serde_yaml::from_reader(Self::read_file()?)?)
+ }
+
+ pub fn save(&self) -> Result<(), Box<dyn Error>> {
+ Ok(serde_yaml::to_writer(Self::write_file()?, self)?)
+ }
+
+ fn read_file() -> Result<File, Box<dyn Error>> {
+ Ok(OpenOptions::new()
+ .create(true)
+ .write(true)
+ .read(true)
+ .open(Self::path()?)?)
+ }
+
+ fn write_file() -> Result<File, Box<dyn Error>> {
+ Ok(OpenOptions::new()
+ .create(true)
+ .write(true)
+ .truncate(true)
+ .open(Self::path()?)?)
+ }
+
+ fn path() -> Result<PathBuf, Box<dyn Error>> {
+ let xdg_cache = match env::var_os("XDG_CACHE_HOME") {
+ Some(s) => s
+ .into_string()
+ .map_err(|_| "Unable to resolve $XDG_CACHE_HOME")?,
+ None => format!(
+ "{}/.cache",
+ env::var_os("HOME")
+ .ok_or("Unable to resolve $HOME")?
+ .into_string()
+ .map_err(|_| "Unable to resolve $HOME")?
+ ),
+ };
+
+ let cache_dir = PathBuf::from(xdg_cache).join("wldash");
+ create_dir_all(&cache_dir)?;
+
+ Ok(cache_dir.join("data.yaml"))
+ }
+}
diff --git a/src/main.rs b/src/main.rs
index 68dd057..3d36fc6 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -16,6 +16,7 @@ mod cmd;
mod color;
mod config;
mod configfmt;
+mod data;
mod desktop;
mod doublemempool;
mod draw;
diff --git a/src/widgets/launcher.rs b/src/widgets/launcher.rs
index 081f266..a8593ba 100644
--- a/src/widgets/launcher.rs
+++ b/src/widgets/launcher.rs
@@ -14,6 +14,7 @@ use std::collections::HashMap;
use std::process::Command;
use std::sync::mpsc::Sender;
+use crate::data::Data;
use crate::keyboard::keysyms;
use fuzzy_matcher::skim::SkimMatcherV2;
use fuzzy_matcher::FuzzyMatcher;
@@ -34,6 +35,7 @@ pub struct Launcher<'a> {
length: u32,
dirty: bool,
tx: Sender<Cmd>,
+ counter: Data,
}
impl<'a> Launcher<'a> {
@@ -61,6 +63,7 @@ impl<'a> Launcher<'a> {
length,
dirty: true,
tx: listener,
+ counter: Data::load().unwrap_or_default(),
})
}
@@ -101,6 +104,7 @@ impl<'a> Launcher<'a> {
let (_, indices) = fuzzy_matcher
.fuzzy_indices(&m.name.to_lowercase(), &self.input.to_lowercase())
.unwrap_or((0, vec![]));
+
let mut colors = Vec::with_capacity(m.name.len());
for pos in 0..m.name.len() {
if indices.contains(&pos) {
@@ -215,12 +219,14 @@ fn wlcopy(s: &str) -> Result<(), String> {
struct Matcher {
matches: HashMap<Desktop, i64>,
+ counter: Data,
}
impl Matcher {
- fn new() -> Self {
+ fn new(counter: Data) -> Self {
Self {
matches: HashMap::new(),
+ counter,
}
}
@@ -248,9 +254,12 @@ impl Matcher {
.collect::<Vec<(i64, Desktop)>>();
m.sort_by(|(ma1, d1), (ma2, d2)| {
- if ma1 > ma2 {
+ let count1 = self.counter.entries.get(&d1.name).unwrap_or(&0);
+ let count2 = self.counter.entries.get(&d2.name).unwrap_or(&0);
+
+ if ma1 + count1 > ma2 + count2 {
Ordering::Less
- } else if ma1 < ma2 {
+ } else if ma1 + count1 < ma2 + count2 {
Ordering::Greater
} else if d1.name.len() < d2.name.len() {
Ordering::Less
@@ -306,7 +315,7 @@ impl<'a> Widget for Launcher<'a> {
}
Some('!') => (),
_ => {
- let mut matcher = Matcher::new();
+ let mut matcher = Matcher::new(self.counter.clone());
for desktop in self.options.iter() {
matcher.try_match(
@@ -428,6 +437,10 @@ impl<'a> Widget for Launcher<'a> {
} else {
lexed
};
+
+ *self.counter.entries.entry(d.name.clone()).or_insert(0) += 1;
+ self.counter.save().expect("Unable to save data");
+
if !lexed.is_empty() {
let _ =
Command::new(lexed[0].clone()).args(&lexed[1..]).spawn();
--
2.34.1
wldash/patches/.build.yml: SUCCESS in 2m28s
[feat: add ranking based on usage to launcher widget][0] v3 from [Cyril Levis][1]
[0]: https://lists.sr.ht/~kennylevinsen/public-inbox/patches/27838
[1]: mailto:git@levis.name
✓ #660332 SUCCESS wldash/patches/.build.yml https://builds.sr.ht/~kennylevinsen/job/660332
Applied, thanks!