From 93e9cfdd8d07f17972d1fce74f2440ab9d957c36 Mon Sep 17 00:00:00 2001 From: Shizcow Date: Thu, 2 Jul 2020 15:35:20 -0600 Subject: [PATCH 1/9] Added fuzzy matching plugin. Unsure if the alg is good enouguh to be used yet; I'll test it out for a few days --- src/config/src/config.rs | 9 +++++---- src/config/src/util.rs | 6 +++--- src/dmenu/item.rs | 2 ++ src/dmenu/plugin_entry.rs | 1 + src/plugins/fuzzy/deps.toml | 2 ++ src/plugins/fuzzy/main.rs | 30 ++++++++++++++++++++++++++++++ src/plugins/fuzzy/plugin.yml | 3 +++ 7 files changed, 46 insertions(+), 7 deletions(-) create mode 100644 src/plugins/fuzzy/deps.toml create mode 100644 src/plugins/fuzzy/main.rs create mode 100644 src/plugins/fuzzy/plugin.yml diff --git a/src/config/src/config.rs b/src/config/src/config.rs index 20785dc..524504d 100644 --- a/src/config/src/config.rs +++ b/src/config/src/config.rs @@ -26,15 +26,16 @@ fn main() { // prepare to edit cli_base args let mut yaml = get_yaml("../dmenu/cli_base.yml"); - let yaml_args: &mut Vec = get_yaml_args(&mut yaml); + let yaml_args: &mut Vec = get_yaml_args(&mut yaml).unwrap(); // For every plugin, check if it has arguements. If so, add them to clap and overrider // While we're here, set proc_use to watch the plugin entry points for plugin in plugins { let mut plugin_yaml = get_yaml(&format!("../plugins/{}/plugin.yml", plugin)); - let plugin_yaml_args: &mut Vec = get_yaml_args(&mut plugin_yaml); - - yaml_args.append(plugin_yaml_args); + + if let Some(plugin_yaml_args) = get_yaml_args(&mut plugin_yaml) { + yaml_args.append(plugin_yaml_args); + } watch_globs.push(( format!("../plugins/{}/{}", plugin, get_yaml_top_level(&mut plugin_yaml, "entry") diff --git a/src/config/src/util.rs b/src/config/src/util.rs index 7c578d2..7e5d0f3 100644 --- a/src/config/src/util.rs +++ b/src/config/src/util.rs @@ -55,7 +55,7 @@ pub fn get_yaml_top_level<'a>(yaml: &'a mut Yaml, fieldsearch: &str) -> Option<& } #[allow(unused)] -pub fn get_yaml_args(yaml: &mut Yaml) -> &mut Vec { +pub fn get_yaml_args(yaml: &mut Yaml) -> Option<&mut Vec> { match yaml { Yaml::Hash(hash) => { for field in hash { @@ -64,7 +64,7 @@ pub fn get_yaml_args(yaml: &mut Yaml) -> &mut Vec { match field.1 { Yaml::Array(arr) => { sanitize_args(arr); - return arr; + return Some(arr); }, _ => panic!("Incorrect arg format on cli_base"), } @@ -74,7 +74,7 @@ pub fn get_yaml_args(yaml: &mut Yaml) -> &mut Vec { }, _ => panic!("Incorrect yaml format on cli_base"), } - panic!("No args found in yaml object"); + None } fn sanitize_args(args: &mut Vec) { diff --git a/src/dmenu/item.rs b/src/dmenu/item.rs index 512acf2..e136d97 100644 --- a/src/dmenu/item.rs +++ b/src/dmenu/item.rs @@ -4,6 +4,7 @@ use crate::drw::{Drw, TextOption::*}; use crate::config::{Schemes::*, DefaultWidth}; use regex::Regex; +#[allow(unused_imports)] pub enum MatchCode {Exact, Prefix, Substring, None} pub use MatchCode::*; #[derive(Debug)] @@ -24,6 +25,7 @@ impl Item { pub fn draw(&self, x: c_int, y: c_int, w: c_int, drw: &mut Drw) -> Result { drw.text(x, y, w as u32, drw.pseudo_globals.bh as u32, drw.pseudo_globals.lrpad as u32/2, Other(&self.text), false) } + #[allow(unused)] // won't be used if overriden pub fn matches(&self, re: &Regex) -> MatchCode { match re.find_iter(&self.text) .nth(0).map(|m| (m.start(), m.end())) diff --git a/src/dmenu/plugin_entry.rs b/src/dmenu/plugin_entry.rs index e1400ae..13f6abe 100644 --- a/src/dmenu/plugin_entry.rs +++ b/src/dmenu/plugin_entry.rs @@ -1,6 +1,7 @@ #[allow(unused_imports)] use crate::clapflags::CLAP_FLAGS; use crate::drw::Drw; +#[allow(unused_imports)] use crate::item::{Item, MatchCode}; use overrider::*; diff --git a/src/plugins/fuzzy/deps.toml b/src/plugins/fuzzy/deps.toml new file mode 100644 index 0000000..99dfa47 --- /dev/null +++ b/src/plugins/fuzzy/deps.toml @@ -0,0 +1,2 @@ +fuzzy-matcher = "0.3.4" +termion = "1.5.1" \ No newline at end of file diff --git a/src/plugins/fuzzy/main.rs b/src/plugins/fuzzy/main.rs new file mode 100644 index 0000000..3993607 --- /dev/null +++ b/src/plugins/fuzzy/main.rs @@ -0,0 +1,30 @@ +use overrider::*; + +use fuzzy_matcher::FuzzyMatcher; +use fuzzy_matcher::skim::SkimMatcherV2; + +use crate::drw::Drw; +use crate::item::Item; + +#[override_default] +impl Drw { + pub fn gen_matches(&mut self) -> Result, String> { + let searchterm = self.input.clone(); + let mut items: Vec<(Item, i64)> = + self.items.as_mut().unwrap().data.iter().map(|item| { + let matcher: Box = Box::new(SkimMatcherV2::default()); + (item.clone(), + if let Some(score) = matcher.fuzzy_match(&item.text, &searchterm) { + println!("{}", score); + -score + } else { + 1 + }) + }).collect(); + items.retain(|(_, score)| *score <= 0); + items.sort_by_key(|(item, _)| item.text.len()); // this prioritizes exact matches + items.sort_by_key(|(_, score)| *score); + + Ok(items.into_iter().map(|(item, _)| item).collect()) + } +} diff --git a/src/plugins/fuzzy/plugin.yml b/src/plugins/fuzzy/plugin.yml new file mode 100644 index 0000000..9362e8e --- /dev/null +++ b/src/plugins/fuzzy/plugin.yml @@ -0,0 +1,3 @@ +about: Fuzzy string matching for searches +entry: main.rs +cargo_dependencies: deps.toml From 8c2e9dcfe041c32161e0520abaa336904c771339 Mon Sep 17 00:00:00 2001 From: Shizcow Date: Thu, 2 Jul 2020 15:46:56 -0600 Subject: [PATCH 2/9] Fixed failed-to-build with multiple plugins --- src/plugins/fuzzy/main.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/fuzzy/main.rs b/src/plugins/fuzzy/main.rs index 3993607..4cceeb7 100644 --- a/src/plugins/fuzzy/main.rs +++ b/src/plugins/fuzzy/main.rs @@ -1,5 +1,7 @@ use overrider::*; +use crate::clapflags::CLAP_FLAGS; + use fuzzy_matcher::FuzzyMatcher; use fuzzy_matcher::skim::SkimMatcherV2; From d57600b135eb0a8bb45f69ab8988f5664765d8e2 Mon Sep 17 00:00:00 2001 From: Shizcow Date: Thu, 2 Jul 2020 16:12:32 -0600 Subject: [PATCH 3/9] fuzzy: Removed unused dependency, fixed build warning, fixed dispose --- src/plugins/fuzzy/deps.toml | 3 +-- src/plugins/fuzzy/main.rs | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/plugins/fuzzy/deps.toml b/src/plugins/fuzzy/deps.toml index 99dfa47..79026d9 100644 --- a/src/plugins/fuzzy/deps.toml +++ b/src/plugins/fuzzy/deps.toml @@ -1,2 +1 @@ -fuzzy-matcher = "0.3.4" -termion = "1.5.1" \ No newline at end of file +fuzzy-matcher = "0.3.4" \ No newline at end of file diff --git a/src/plugins/fuzzy/main.rs b/src/plugins/fuzzy/main.rs index 4cceeb7..c628d07 100644 --- a/src/plugins/fuzzy/main.rs +++ b/src/plugins/fuzzy/main.rs @@ -1,5 +1,6 @@ use overrider::*; +#[allow(unused_imports)] use crate::clapflags::CLAP_FLAGS; use fuzzy_matcher::FuzzyMatcher; @@ -17,7 +18,6 @@ impl Drw { let matcher: Box = Box::new(SkimMatcherV2::default()); (item.clone(), if let Some(score) = matcher.fuzzy_match(&item.text, &searchterm) { - println!("{}", score); -score } else { 1 From 2f3b19df9b1a50922c111f74974edb96455de276 Mon Sep 17 00:00:00 2001 From: Shizcow Date: Thu, 2 Jul 2020 19:49:41 -0600 Subject: [PATCH 4/9] Added basic functionality --- config.mk | 2 +- src/plugins/spellcheck/deps.toml | 1 + src/plugins/spellcheck/main.rs | 51 +++++++++++++++++++++++++++++++ src/plugins/spellcheck/plugin.yml | 12 ++++++++ 4 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 src/plugins/spellcheck/deps.toml create mode 100644 src/plugins/spellcheck/main.rs create mode 100644 src/plugins/spellcheck/plugin.yml diff --git a/config.mk b/config.mk index 9c443c0..628e88d 100644 --- a/config.mk +++ b/config.mk @@ -18,4 +18,4 @@ RUSTFLAGS = # space seperated list of plugins to be compiled in # run `make plugins` to see a list of available plugins -PLUGINS = +PLUGINS = spellcheck diff --git a/src/plugins/spellcheck/deps.toml b/src/plugins/spellcheck/deps.toml new file mode 100644 index 0000000..84e59a7 --- /dev/null +++ b/src/plugins/spellcheck/deps.toml @@ -0,0 +1 @@ +ispell = "0.3.0" \ No newline at end of file diff --git a/src/plugins/spellcheck/main.rs b/src/plugins/spellcheck/main.rs new file mode 100644 index 0000000..ae79db4 --- /dev/null +++ b/src/plugins/spellcheck/main.rs @@ -0,0 +1,51 @@ +use overrider::*; + +use crate::clapflags::CLAP_FLAGS; + +use ispell::{SpellLauncher}; + +use crate::drw::Drw; +use crate::item::Item; + +#[override_flag(flag = spellcheck)] +impl Drw { + pub fn gen_matches(&mut self) -> Result, String> { + let checker = SpellLauncher::new() + .aspell() + .launch(); + + match checker { + Ok(mut checker) => { + match checker.check(&self.input) { + Ok(mut res) => { + if res.is_empty() { + Ok(vec![Item::new(self.input.clone(), false, self)?]) + } else { + let mut ret = Vec::new(); + for word in res.swap_remove(0).suggestions.into_iter() { + ret.push(Item::new(word, false, self)?); + } + Ok(ret) + } + }, + Err(err) => Err(format!("Error: could not run aspell: {}", err)) + } + }, + Err(err) => Err(format!("Error: could not start aspell: {}", err)) + } + } +} + +use crate::config::{ConfigDefault, DefaultWidth}; +#[override_flag(flag = spellcheck)] +impl ConfigDefault { + pub fn nostdin() -> bool { + true + } + pub fn render_flex() -> bool { + true + } + pub fn render_default_width() -> DefaultWidth { + DefaultWidth::Custom(15) + } +} diff --git a/src/plugins/spellcheck/plugin.yml b/src/plugins/spellcheck/plugin.yml new file mode 100644 index 0000000..bd5be50 --- /dev/null +++ b/src/plugins/spellcheck/plugin.yml @@ -0,0 +1,12 @@ +about: Single word spellcheck +entry: main.rs +cargo_dependencies: deps.toml + +args: + - spellcheck: + help: Enter spellcheck mode + long_help: > + Enter spellcheck mode. Begin typing a word for spelling suggestions. Only accepts + single word queries. Pressing Enter will copy to clipboard before exiting. + long: spellcheck + visible_aliases: sc From beb1345b1a3305679ae631b3407fa5db74bf3e81 Mon Sep 17 00:00:00 2001 From: Shizcow Date: Thu, 2 Jul 2020 19:57:12 -0600 Subject: [PATCH 5/9] Disposes to clipboard, input validated for spaces (kind of) --- src/plugins/spellcheck/main.rs | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/plugins/spellcheck/main.rs b/src/plugins/spellcheck/main.rs index ae79db4..955b804 100644 --- a/src/plugins/spellcheck/main.rs +++ b/src/plugins/spellcheck/main.rs @@ -1,8 +1,8 @@ use overrider::*; -use crate::clapflags::CLAP_FLAGS; - use ispell::{SpellLauncher}; +use std::process::{Command, Stdio}; +use std::io::Write; use crate::drw::Drw; use crate::item::Item; @@ -13,6 +13,9 @@ impl Drw { let checker = SpellLauncher::new() .aspell() .launch(); + + self.input = self.input.split(" ").nth(0).unwrap_or("").to_owned(); + self.pseudo_globals.cursor = self.input.chars().count(); match checker { Ok(mut checker) => { @@ -34,6 +37,20 @@ impl Drw { Err(err) => Err(format!("Error: could not start aspell: {}", err)) } } + pub fn dispose(&mut self, output: String, recommendation: bool) -> Result { + if output.len() > 0 { + let mut child = Command::new("xclip") + .arg("-sel") + .arg("clip") + .stdin(Stdio::piped()) + .spawn() + .map_err(|_| "Failed to spawn child process".to_owned())?; + + child.stdin.as_mut().ok_or("Failed to open stdin".to_owned())? + .write_all(output.as_bytes()).map_err(|_| "Failed to write to stdin".to_owned())?; + } + Ok(recommendation) + } } use crate::config::{ConfigDefault, DefaultWidth}; @@ -46,6 +63,6 @@ impl ConfigDefault { true } pub fn render_default_width() -> DefaultWidth { - DefaultWidth::Custom(15) + DefaultWidth::Custom(10) } } From 4081a1f213a2630971630206a982bede979ff414 Mon Sep 17 00:00:00 2001 From: Shizcow Date: Thu, 2 Jul 2020 19:58:22 -0600 Subject: [PATCH 6/9] Properly disabled spaces, still need to fix cursor --- src/plugins/spellcheck/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/spellcheck/main.rs b/src/plugins/spellcheck/main.rs index 955b804..9b1fff8 100644 --- a/src/plugins/spellcheck/main.rs +++ b/src/plugins/spellcheck/main.rs @@ -14,7 +14,7 @@ impl Drw { .aspell() .launch(); - self.input = self.input.split(" ").nth(0).unwrap_or("").to_owned(); + self.input = self.input.replace(" ", ""); self.pseudo_globals.cursor = self.input.chars().count(); match checker { From 4410de0b9ec5607a5a17a38f7ba827f486e970db Mon Sep 17 00:00:00 2001 From: Shizcow Date: Thu, 2 Jul 2020 20:09:27 -0600 Subject: [PATCH 7/9] Proper sanitization for input --- src/plugins/spellcheck/main.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/plugins/spellcheck/main.rs b/src/plugins/spellcheck/main.rs index 9b1fff8..2d3a96d 100644 --- a/src/plugins/spellcheck/main.rs +++ b/src/plugins/spellcheck/main.rs @@ -14,8 +14,11 @@ impl Drw { .aspell() .launch(); - self.input = self.input.replace(" ", ""); - self.pseudo_globals.cursor = self.input.chars().count(); + let (mut first, mut second) = self.input.split_at(self.pseudo_globals.cursor); + let first_replaced = first.replace(" ", ""); + let second_replaced = second.replace(" ", ""); + self.pseudo_globals.cursor = first_replaced.chars().count(); + self.input = first_replaced+&second_replaced; match checker { Ok(mut checker) => { From 44cff23d6e7294bb33a3c99a6be9aafe843bd9b0 Mon Sep 17 00:00:00 2001 From: Shizcow Date: Thu, 2 Jul 2020 21:00:32 -0600 Subject: [PATCH 8/9] Fixed timeout bug by updating to latest ispell repo, finished up spellcheck plugin --- config.mk | 2 +- makefile | 5 +++++ src/dmenu/run.rs | 4 +--- src/plugins/spellcheck/deps.toml | 3 ++- src/plugins/spellcheck/main.rs | 2 +- src/plugins/spellcheck/plugin.yml | 5 ++--- 6 files changed, 12 insertions(+), 9 deletions(-) diff --git a/config.mk b/config.mk index 628e88d..9c443c0 100644 --- a/config.mk +++ b/config.mk @@ -18,4 +18,4 @@ RUSTFLAGS = # space seperated list of plugins to be compiled in # run `make plugins` to see a list of available plugins -PLUGINS = spellcheck +PLUGINS = diff --git a/makefile b/makefile index 03064d2..4c78131 100644 --- a/makefile +++ b/makefile @@ -37,6 +37,11 @@ man: config test: all seq 1 100 | target/dmenu $(ARGS) +debug: m4 + cd src/build && cargo build $(XINERAMA_FLAGS) + cp src/build/target/debug/dmenu target + seq 1 100 | RUST_BACKTRACE=1 target/dmenu $(ARGS) + plugins: cd src/config && cargo run --bin list-plugins diff --git a/src/dmenu/run.rs b/src/dmenu/run.rs index 2046de7..7281195 100644 --- a/src/dmenu/run.rs +++ b/src/dmenu/run.rs @@ -359,9 +359,7 @@ impl Drw { } }, } - if self.draw().is_err() { - return Ok(true); - } + self.draw()?; } Ok(false) } diff --git a/src/plugins/spellcheck/deps.toml b/src/plugins/spellcheck/deps.toml index 84e59a7..357773e 100644 --- a/src/plugins/spellcheck/deps.toml +++ b/src/plugins/spellcheck/deps.toml @@ -1 +1,2 @@ -ispell = "0.3.0" \ No newline at end of file +# Why do people push changes to a crate and not put it on crates.io after 4 years? +ispell = {git = "https://github.com/lise-henry/rust-ispell"} \ No newline at end of file diff --git a/src/plugins/spellcheck/main.rs b/src/plugins/spellcheck/main.rs index 2d3a96d..bf4b017 100644 --- a/src/plugins/spellcheck/main.rs +++ b/src/plugins/spellcheck/main.rs @@ -14,7 +14,7 @@ impl Drw { .aspell() .launch(); - let (mut first, mut second) = self.input.split_at(self.pseudo_globals.cursor); + let (first, second) = self.input.split_at(self.pseudo_globals.cursor); let first_replaced = first.replace(" ", ""); let second_replaced = second.replace(" ", ""); self.pseudo_globals.cursor = first_replaced.chars().count(); diff --git a/src/plugins/spellcheck/plugin.yml b/src/plugins/spellcheck/plugin.yml index bd5be50..86d6e8b 100644 --- a/src/plugins/spellcheck/plugin.yml +++ b/src/plugins/spellcheck/plugin.yml @@ -5,8 +5,7 @@ cargo_dependencies: deps.toml args: - spellcheck: help: Enter spellcheck mode - long_help: > - Enter spellcheck mode. Begin typing a word for spelling suggestions. Only accepts - single word queries. Pressing Enter will copy to clipboard before exiting. + long_help: "Enter spellcheck mode. Begin typing a word for spelling suggestions.\nOnly accepts + single word queries.\nPressing Enter will copy to clipboard before exiting." long: spellcheck visible_aliases: sc From fc5583b9282683e6498d35be7922da1c4d51766f Mon Sep 17 00:00:00 2001 From: Shizcow Date: Fri, 3 Jul 2020 19:28:24 -0600 Subject: [PATCH 9/9] ispell finally updated --- src/plugins/spellcheck/deps.toml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/plugins/spellcheck/deps.toml b/src/plugins/spellcheck/deps.toml index 357773e..a911117 100644 --- a/src/plugins/spellcheck/deps.toml +++ b/src/plugins/spellcheck/deps.toml @@ -1,2 +1 @@ -# Why do people push changes to a crate and not put it on crates.io after 4 years? -ispell = {git = "https://github.com/lise-henry/rust-ispell"} \ No newline at end of file +ispell = "0.3.1" \ No newline at end of file