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 ea8c4bf7..185ca35e 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 efd6dcac..7c08755a 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 fb9f62ec..2b8897f9 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 145be442..3b311df0 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 30cebb85..a95df636 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 2e2b153c..d5fe6fef 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 d7f3189a..1621d8b9 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 73f330c0..70c1a93e 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 7df0d0ce..198d6b10 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 1d2f4733..01caa367 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 2d6a0299..b865f7e8 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 8a5e9bec..b2f4f844 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 d4af44f4..83507b66 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 68dcd53a..3d72057a 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 2b8897f9..b89f17f2 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 a95df636..78b0de1d 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 b865f7e8..63a2486b 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 b89f17f2..efb867cb 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 63a2486b..5c2298c8 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 83507b66..fdb095fb 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 3b311df0..03995b5b 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 6ebe6eb2..08b658a2 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 5c2298c8..c6722ce8 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 c6722ce8..53562756 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 08b658a2..1255aeb7 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