From 3cfc8e9c5e969fc8434922a797006aa4a843102c Mon Sep 17 00:00:00 2001 From: diniamo Date: Sat, 13 Jan 2024 19:02:11 +0100 Subject: [PATCH 1/8] feat: custom image support --- .gitignore | 2 ++ anyrun-interface/src/lib.rs | 2 ++ anyrun/src/main.rs | 31 +++++++++++++++++++++++++++++-- examples/config.ron | 8 +++++++- plugins/applications/src/lib.rs | 1 + plugins/dictionary/src/lib.rs | 1 + plugins/kidex/src/lib.rs | 4 ++++ plugins/randr/src/lib.rs | 4 ++++ plugins/rink/src/lib.rs | 1 + plugins/shell/src/lib.rs | 1 + plugins/stdin/src/lib.rs | 16 ++++++++++------ plugins/symbols/src/lib.rs | 1 + plugins/translate/src/lib.rs | 1 + plugins/websearch/src/lib.rs | 1 + 14 files changed, 65 insertions(+), 9 deletions(-) diff --git a/.gitignore b/.gitignore index ea8c4bf..185ca35 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ /target + +.idea diff --git a/anyrun-interface/src/lib.rs b/anyrun-interface/src/lib.rs index efd6dca..7c08755 100644 --- a/anyrun-interface/src/lib.rs +++ b/anyrun-interface/src/lib.rs @@ -41,6 +41,8 @@ pub struct Match { pub use_pango: bool, /// The icon name from the icon theme in use pub icon: ROption, + /// The path to a custom image to use instead of an icon + pub image: ROption, /// For runners to differentiate between the matches. Not required. pub id: ROption, } diff --git a/anyrun/src/main.rs b/anyrun/src/main.rs index fb9f62e..2b8897f 100644 --- a/anyrun/src/main.rs +++ b/anyrun/src/main.rs @@ -37,6 +37,10 @@ struct Config { #[serde(default)] hide_icons: bool, + #[serde(default = "Config::default_max_image_width")] + max_image_width: i32, + #[serde(default = "Config::default_max_image_height")] + max_image_height: i32, #[serde(default)] hide_plugin_info: bool, #[serde(default)] @@ -77,6 +81,14 @@ impl Config { ] } + fn default_max_image_width() -> i32 { + 150 + } + + fn default_max_image_height() -> i32 { + 100 + } + fn default_layer() -> Layer { Layer::Overlay } @@ -91,6 +103,8 @@ impl Default for Config { height: Self::default_height(), plugins: Self::default_plugins(), hide_icons: false, + max_image_width: 150, + max_image_height: 100, hide_plugin_info: false, ignore_exclusive_zones: false, close_on_click: false, @@ -196,6 +210,8 @@ mod style_names { pub const MATCH_TITLE: &str = "match-title"; pub const MATCH_DESC: &str = "match-desc"; + pub const MATCH_ICON: &str = "match-icon"; + pub const MATCH_IMAGE: &str = "match-image"; } /// Default config directory @@ -714,9 +730,20 @@ fn handle_matches(plugin_view: PluginView, runtime_data: &RuntimeData, matches: .hexpand(true) .build(); if !runtime_data.config.hide_icons { - if let ROption::RSome(icon) = &_match.icon { + if let ROption::RSome(image) = &_match.image { let mut builder = gtk::Image::builder() - .name(style_names::MATCH) + .name(style_names::MATCH_IMAGE); + + match gdk_pixbuf::Pixbuf::from_file_at_size(image.as_str(), runtime_data.config.max_image_width, runtime_data.config.max_image_height) { + Ok(pixbuf) => { + builder = builder.pixbuf(&pixbuf); + hbox.add(&builder.build()); + }, + Err(why) => println!("Failed to load image file: {}", why) + } + } else if let ROption::RSome(icon) = &_match.icon { + let mut builder = gtk::Image::builder() + .name(style_names::MATCH_ICON) .pixel_size(32); let path = PathBuf::from(icon.as_str()); diff --git a/examples/config.ron b/examples/config.ron index 145be44..3b311df 100644 --- a/examples/config.ron +++ b/examples/config.ron @@ -16,7 +16,13 @@ Config( height: Absolute(0), // Hide match and plugin info icons - hide_icons: false, + hide_icons: false, + + // The maximum width of custom images + max_image_width: 100, + + // The maximum height of custom images + max_image_height: 50, // ignore exclusive zones, f.e. Waybar ignore_exclusive_zones: false, diff --git a/plugins/applications/src/lib.rs b/plugins/applications/src/lib.rs index 30cebb8..a95df63 100644 --- a/plugins/applications/src/lib.rs +++ b/plugins/applications/src/lib.rs @@ -143,6 +143,7 @@ pub fn get_matches(input: RString, state: &State) -> RVec { description: entry.desc.clone().map(|desc| desc.into()).into(), use_pango: false, icon: ROption::RSome(entry.icon.clone().into()), + image: ROption::RNone, id: ROption::RSome(id), }) .collect() diff --git a/plugins/dictionary/src/lib.rs b/plugins/dictionary/src/lib.rs index 2e2b153..d5fe6fe 100644 --- a/plugins/dictionary/src/lib.rs +++ b/plugins/dictionary/src/lib.rs @@ -89,6 +89,7 @@ pub fn get_matches(input: RString, config: &Config) -> RVec { description: ROption::RSome(meaning.part_of_speech.clone().into()), use_pango: false, icon: ROption::RSome("accessories-dictionary".into()), + image: ROption::RNone, id: ROption::RNone, }) .collect::>() diff --git a/plugins/kidex/src/lib.rs b/plugins/kidex/src/lib.rs index d7f3189..1621d8b 100644 --- a/plugins/kidex/src/lib.rs +++ b/plugins/kidex/src/lib.rs @@ -102,6 +102,7 @@ pub fn get_matches(input: RString, state: &State) -> RVec { use_pango: false, id: ROption::RSome(IndexAction::Open as u64), icon: ROption::RSome("document-open".into()), + image: ROption::RNone, }, Match { title: "Copy Path".into(), @@ -109,6 +110,7 @@ pub fn get_matches(input: RString, state: &State) -> RVec { use_pango: false, id: ROption::RSome(IndexAction::CopyPath as u64), icon: ROption::RSome("edit-copy".into()), + image: ROption::RNone, }, Match { title: "Back".into(), @@ -116,6 +118,7 @@ pub fn get_matches(input: RString, state: &State) -> RVec { use_pango: false, id: ROption::RSome(IndexAction::Back as u64), icon: ROption::RSome("edit-undo".into()), + image: ROption::RNone, }, ] .into() @@ -155,6 +158,7 @@ pub fn get_matches(input: RString, state: &State) -> RVec { } else { "text-x-generic".into() }), + image: ROption::RNone, id: ROption::RSome(id as u64), }) .collect() diff --git a/plugins/randr/src/lib.rs b/plugins/randr/src/lib.rs index 73f330c..70c1a93 100644 --- a/plugins/randr/src/lib.rs +++ b/plugins/randr/src/lib.rs @@ -124,6 +124,7 @@ pub fn get_matches(input: RString, state: &State) -> RVec { ), use_pango: false, icon: ROption::RSome("object-flip-horizontal".into()), + image: ROption::RNone, id: ROption::RSome(mon.id), }) .collect::>(), @@ -150,6 +151,7 @@ pub fn get_matches(input: RString, state: &State) -> RVec { description: ROption::RNone, use_pango: false, icon: ROption::RSome(configure.icon().into()), + image: ROption::RNone, // Store 2 32 bit IDs in the single 64 bit integer, a bit of a hack id: ROption::RSome(_mon.id << 32 | Into::::into(configure)), }) @@ -165,6 +167,7 @@ pub fn get_matches(input: RString, state: &State) -> RVec { description: ROption::RNone, use_pango: false, icon: ROption::RSome(Configure::Zero.icon().into()), + image: ROption::RNone, id: ROption::RSome((&Configure::Zero).into()), }); @@ -173,6 +176,7 @@ pub fn get_matches(input: RString, state: &State) -> RVec { description: ROption::RSome("Return to the previous menu".into()), use_pango: false, icon: ROption::RSome("edit-undo".into()), + image: ROption::RNone, id: ROption::RSome(u64::MAX), }); diff --git a/plugins/rink/src/lib.rs b/plugins/rink/src/lib.rs index 7df0d0c..198d6b1 100644 --- a/plugins/rink/src/lib.rs +++ b/plugins/rink/src/lib.rs @@ -50,6 +50,7 @@ fn get_matches(input: RString, ctx: &mut rink_core::Context) -> RVec { description: desc.map(RString::from).into(), use_pango: false, icon: ROption::RNone, + image: ROption::RNone, id: ROption::RNone, }] .into() diff --git a/plugins/shell/src/lib.rs b/plugins/shell/src/lib.rs index 1d2f473..01caa36 100644 --- a/plugins/shell/src/lib.rs +++ b/plugins/shell/src/lib.rs @@ -55,6 +55,7 @@ fn get_matches(input: RString, config: &Config) -> RVec { ), use_pango: false, icon: ROption::RNone, + image: ROption::RNone, id: ROption::RNone, }] .into() diff --git a/plugins/stdin/src/lib.rs b/plugins/stdin/src/lib.rs index 2d6a029..b865f7e 100644 --- a/plugins/stdin/src/lib.rs +++ b/plugins/stdin/src/lib.rs @@ -68,12 +68,16 @@ fn get_matches(input: RString, state: &State) -> RVec { lines .into_iter() - .map(|(line, _)| Match { - title: line.into(), - description: ROption::RNone, - use_pango: false, - icon: ROption::RNone, - id: ROption::RNone, + .map(|(line, _)| { + let mut line = line.split("\t"); + Match { + title: line.next().unwrap_or("".into()).into(), + description: ROption::RNone, + use_pango: false, + icon: ROption::RNone, + image: line.next().map_or(ROption::RNone, |p| ROption::RSome(p.into())), + id: ROption::RNone, + } }) .collect::>() .into() diff --git a/plugins/symbols/src/lib.rs b/plugins/symbols/src/lib.rs index 8a5e9be..b2f4f84 100644 --- a/plugins/symbols/src/lib.rs +++ b/plugins/symbols/src/lib.rs @@ -92,6 +92,7 @@ fn get_matches(input: RString, state: &State) -> RVec { description: ROption::RSome(symbol.name.clone().into()), use_pango: false, icon: ROption::RNone, + image: ROption::RNone, id: ROption::RNone, }) .collect() diff --git a/plugins/translate/src/lib.rs b/plugins/translate/src/lib.rs index d4af44f..83507b6 100644 --- a/plugins/translate/src/lib.rs +++ b/plugins/translate/src/lib.rs @@ -276,6 +276,7 @@ fn get_matches(input: RString, state: &State) -> RVec { .into()), use_pango: false, icon: ROption::RNone, + image: ROption::RNone, id: ROption::RNone } ) diff --git a/plugins/websearch/src/lib.rs b/plugins/websearch/src/lib.rs index 68dcd53..3d72057 100644 --- a/plugins/websearch/src/lib.rs +++ b/plugins/websearch/src/lib.rs @@ -82,6 +82,7 @@ fn get_matches(input: RString, config: &Config) -> RVec { description: ROption::RSome(format!("Search with {}", engine).into()), use_pango: false, icon: ROption::RNone, + image: ROption::RNone, id: ROption::RSome(i as u64), }) .collect() From 6a4ac6d5857a13e02ade965dc0c0cb98e9f2090f Mon Sep 17 00:00:00 2001 From: diniamo Date: Sat, 13 Jan 2024 19:06:40 +0100 Subject: [PATCH 2/8] revert change that isn't needed anymore --- anyrun/src/main.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/anyrun/src/main.rs b/anyrun/src/main.rs index 2b8897f..b89f17f 100644 --- a/anyrun/src/main.rs +++ b/anyrun/src/main.rs @@ -210,8 +210,6 @@ mod style_names { pub const MATCH_TITLE: &str = "match-title"; pub const MATCH_DESC: &str = "match-desc"; - pub const MATCH_ICON: &str = "match-icon"; - pub const MATCH_IMAGE: &str = "match-image"; } /// Default config directory @@ -732,7 +730,7 @@ fn handle_matches(plugin_view: PluginView, runtime_data: &RuntimeData, matches: if !runtime_data.config.hide_icons { if let ROption::RSome(image) = &_match.image { let mut builder = gtk::Image::builder() - .name(style_names::MATCH_IMAGE); + .name(style_names::MATCH); match gdk_pixbuf::Pixbuf::from_file_at_size(image.as_str(), runtime_data.config.max_image_width, runtime_data.config.max_image_height) { Ok(pixbuf) => { @@ -743,7 +741,7 @@ fn handle_matches(plugin_view: PluginView, runtime_data: &RuntimeData, matches: } } else if let ROption::RSome(icon) = &_match.icon { let mut builder = gtk::Image::builder() - .name(style_names::MATCH_ICON) + .name(style_names::MATCH) .pixel_size(32); let path = PathBuf::from(icon.as_str()); From bbff2e53b53125d6423a4390f69145306662fec8 Mon Sep 17 00:00:00 2001 From: diniamo Date: Sat, 13 Jan 2024 19:14:05 +0100 Subject: [PATCH 3/8] implement clippy suggestions --- plugins/applications/src/lib.rs | 2 +- plugins/stdin/src/lib.rs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/applications/src/lib.rs b/plugins/applications/src/lib.rs index a95df63..78b0de1 100644 --- a/plugins/applications/src/lib.rs +++ b/plugins/applications/src/lib.rs @@ -122,7 +122,7 @@ pub fn get_matches(input: RString, state: &State) -> RVec { // prioritize actions if entry.desc.is_some() { - score = score * 2; + score *= 2; } if score > 0 { diff --git a/plugins/stdin/src/lib.rs b/plugins/stdin/src/lib.rs index b865f7e..63a2486 100644 --- a/plugins/stdin/src/lib.rs +++ b/plugins/stdin/src/lib.rs @@ -35,7 +35,7 @@ fn init(config_dir: RString) -> State { State { config, - lines: stdin().lines().filter_map(|line| line.ok()).collect(), + lines: stdin().lines().map_while(Result::ok).collect(), } } @@ -69,9 +69,9 @@ fn get_matches(input: RString, state: &State) -> RVec { lines .into_iter() .map(|(line, _)| { - let mut line = line.split("\t"); + let mut line = line.split('\t'); Match { - title: line.next().unwrap_or("".into()).into(), + title: line.next().unwrap_or("").into(), description: ROption::RNone, use_pango: false, icon: ROption::RNone, From 06f88923ed943f65027bb3a08a0f981963f51a7c Mon Sep 17 00:00:00 2001 From: diniamo Date: Sat, 13 Jan 2024 19:15:26 +0100 Subject: [PATCH 4/8] run cargo fmt --- anyrun/src/main.rs | 13 ++++++++----- plugins/stdin/src/lib.rs | 4 +++- plugins/translate/src/lib.rs | 11 ++++++++--- 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/anyrun/src/main.rs b/anyrun/src/main.rs index b89f17f..efb867c 100644 --- a/anyrun/src/main.rs +++ b/anyrun/src/main.rs @@ -729,15 +729,18 @@ fn handle_matches(plugin_view: PluginView, runtime_data: &RuntimeData, matches: .build(); if !runtime_data.config.hide_icons { if let ROption::RSome(image) = &_match.image { - let mut builder = gtk::Image::builder() - .name(style_names::MATCH); + let mut builder = gtk::Image::builder().name(style_names::MATCH); - match gdk_pixbuf::Pixbuf::from_file_at_size(image.as_str(), runtime_data.config.max_image_width, runtime_data.config.max_image_height) { + match gdk_pixbuf::Pixbuf::from_file_at_size( + image.as_str(), + runtime_data.config.max_image_width, + runtime_data.config.max_image_height, + ) { Ok(pixbuf) => { builder = builder.pixbuf(&pixbuf); hbox.add(&builder.build()); - }, - Err(why) => println!("Failed to load image file: {}", why) + } + Err(why) => println!("Failed to load image file: {}", why), } } else if let ROption::RSome(icon) = &_match.icon { let mut builder = gtk::Image::builder() diff --git a/plugins/stdin/src/lib.rs b/plugins/stdin/src/lib.rs index 63a2486..5c2298c 100644 --- a/plugins/stdin/src/lib.rs +++ b/plugins/stdin/src/lib.rs @@ -75,7 +75,9 @@ fn get_matches(input: RString, state: &State) -> RVec { description: ROption::RNone, use_pango: false, icon: ROption::RNone, - image: line.next().map_or(ROption::RNone, |p| ROption::RSome(p.into())), + image: line + .next() + .map_or(ROption::RNone, |p| ROption::RSome(p.into())), id: ROption::RNone, } }) diff --git a/plugins/translate/src/lib.rs b/plugins/translate/src/lib.rs index 83507b6..fdb095f 100644 --- a/plugins/translate/src/lib.rs +++ b/plugins/translate/src/lib.rs @@ -211,7 +211,12 @@ fn get_matches(input: RString, state: &State) -> RVec { let mut matches = src_matches .into_iter() - .flat_map(|src| dest_matches.clone().into_iter().map(move |dest| (Some(src), dest))) + .flat_map(|src| { + dest_matches + .clone() + .into_iter() + .map(move |dest| (Some(src), dest)) + }) .collect::>(); matches.sort_by(|a, b| (b.1 .2 + b.0.unwrap().2).cmp(&(a.1 .2 + a.0.unwrap().2))); @@ -237,12 +242,12 @@ fn get_matches(input: RString, state: &State) -> RVec { .into_iter() .map(|(src, dest)| async move { match src { - Some(src) => + Some(src) => (dest.1, state.client.get(format!("https://translate.googleapis.com/translate_a/single?client=gtx&sl={}&tl={}&dt=t&q={}", src.0, dest.0, text)).send().await), None => (dest.1, state.client.get(format!("https://translate.googleapis.com/translate_a/single?client=gtx&sl=auto&tl={}&dt=t&q={}", dest.0, text)).send().await) } }); - + let res = futures::future::join_all(futures) // Wait for all futures to complete .await; From 81747e221dbf6c6e2d0112c7262221d7e2ae12f9 Mon Sep 17 00:00:00 2001 From: diniamo Date: Sat, 13 Jan 2024 19:23:22 +0100 Subject: [PATCH 5/8] forgot to change these --- examples/config.ron | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/config.ron b/examples/config.ron index 3b311df..03995b5 100644 --- a/examples/config.ron +++ b/examples/config.ron @@ -19,10 +19,10 @@ Config( hide_icons: false, // The maximum width of custom images - max_image_width: 100, + max_image_width: 150, // The maximum height of custom images - max_image_height: 50, + max_image_height: 100, // ignore exclusive zones, f.e. Waybar ignore_exclusive_zones: false, From 815273e0957f8dab2c4b0bddfa85455716701091 Mon Sep 17 00:00:00 2001 From: diniamo Date: Sat, 13 Jan 2024 21:00:01 +0100 Subject: [PATCH 6/8] add icon support to stdin, update readme --- plugins/stdin/README.md | 15 +++++++++++++++ plugins/stdin/src/lib.rs | 17 ++++++++++++----- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/plugins/stdin/README.md b/plugins/stdin/README.md index 6ebe6eb..08b658a 100644 --- a/plugins/stdin/README.md +++ b/plugins/stdin/README.md @@ -7,3 +7,18 @@ Allows for easy integration into scripts that have been made with something like This plugin should generally be used alone, if a dmenu replacement is needed. This can be done with `anyrun --plugins libstdin.so`. The content to fuzzy match on needs to be piped into Anyrun. + +## Icons and images + +The plugin uses tabs to separate the text from the custom icon or image file. This means that you need to make sure that you don't pipe any tabs, unless you want to set a custom icon or image. + +This feature works by adding a tab after the title text, and then either: +- specifying an icon name or path +- or specifying an image path after with the `image:` prefix + +For example: +``` +Option 1 help-about +Option 2 /path/to/icon.png +Option 3 image:/path/to/image.png +``` diff --git a/plugins/stdin/src/lib.rs b/plugins/stdin/src/lib.rs index 5c2298c..c6722ce 100644 --- a/plugins/stdin/src/lib.rs +++ b/plugins/stdin/src/lib.rs @@ -70,14 +70,21 @@ fn get_matches(input: RString, state: &State) -> RVec { .into_iter() .map(|(line, _)| { let mut line = line.split('\t'); + let title = line.next().unwrap_or("").into(); + let (icon, image) = line.next().map_or((ROption::RNone, ROption::RNone), |second| { + if second.starts_with("image:") { + (ROption::RNone, ROption::RSome(second.chars().skip("image:".len()).collect().into())) + } else { + (ROption::RSome(second.into()), ROption::RNone) + } + }); + Match { - title: line.next().unwrap_or("").into(), + title, description: ROption::RNone, use_pango: false, - icon: ROption::RNone, - image: line - .next() - .map_or(ROption::RNone, |p| ROption::RSome(p.into())), + icon, + image, id: ROption::RNone, } }) From 04502034d7ecccbd9fa81d87b631aa58e1e51e4b Mon Sep 17 00:00:00 2001 From: diniamo Date: Sat, 13 Jan 2024 21:05:39 +0100 Subject: [PATCH 7/8] fix error + cargo fmt --- plugins/stdin/src/lib.rs | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/plugins/stdin/src/lib.rs b/plugins/stdin/src/lib.rs index c6722ce..5356275 100644 --- a/plugins/stdin/src/lib.rs +++ b/plugins/stdin/src/lib.rs @@ -71,13 +71,24 @@ fn get_matches(input: RString, state: &State) -> RVec { .map(|(line, _)| { let mut line = line.split('\t'); let title = line.next().unwrap_or("").into(); - let (icon, image) = line.next().map_or((ROption::RNone, ROption::RNone), |second| { - if second.starts_with("image:") { - (ROption::RNone, ROption::RSome(second.chars().skip("image:".len()).collect().into())) - } else { - (ROption::RSome(second.into()), ROption::RNone) - } - }); + let (icon, image) = line + .next() + .map_or((ROption::RNone, ROption::RNone), |second| { + if second.starts_with("image:") { + ( + ROption::RNone, + ROption::RSome( + second + .chars() + .skip("image:".len()) + .collect::() + .into(), + ), + ) + } else { + (ROption::RSome(second.into()), ROption::RNone) + } + }); Match { title, From 5facc3cc0eca923e330bb178f61c93c81a48740c Mon Sep 17 00:00:00 2001 From: diniamo Date: Sat, 13 Jan 2024 23:26:56 +0100 Subject: [PATCH 8/8] fix minor grammar inconsistency --- plugins/stdin/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/stdin/README.md b/plugins/stdin/README.md index 08b658a..1255aeb 100644 --- a/plugins/stdin/README.md +++ b/plugins/stdin/README.md @@ -10,7 +10,7 @@ The content to fuzzy match on needs to be piped into Anyrun. ## Icons and images -The plugin uses tabs to separate the text from the custom icon or image file. This means that you need to make sure that you don't pipe any tabs, unless you want to set a custom icon or image. +This plugin uses tabs to separate the text from the custom icon or image file. This means that you need to make sure that you don't pipe any tabs, unless you want to set a custom icon or image. This feature works by adding a tab after the title text, and then either: - specifying an icon name or path