~kennylevinsen/public-inbox

wldash: feat: add ranking based on usage to launcher widget v3 APPLIED

Cyril Levis: 1
 feat: add ranking based on usage to launcher widget

 3 files changed, 75 insertions(+), 4 deletions(-)
#660332 .build.yml success
Export patchset (mbox)
How do I use this?

Copy & paste the following snippet into your terminal to import this patchset into git:

curl -s https://lists.sr.ht/~kennylevinsen/public-inbox/patches/27838/mbox | git am -3
Learn more about email & git

[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!