diff --git a/Cargo.lock b/Cargo.lock index 20105a1..7343ba1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2863,8 +2863,7 @@ dependencies = [ [[package]] name = "onagre-launcher-plugins" version = "1.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59fc31c9107be72521d13a00cd1bfebc2617c6cee0464ec132344714745e863e" +source = "git+https://github.com/onagre-launcher/launcher#56c8cb6e6b4feecae96990dd94c93d5eb790ad3c" dependencies = [ "anyhow", "async-pidfd", @@ -2899,8 +2898,7 @@ dependencies = [ [[package]] name = "onagre-launcher-service" version = "1.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0266efdbe976efefdc5fc003b2f7470be1d40aae43326194220265d60c2314cc" +source = "git+https://github.com/onagre-launcher/launcher#56c8cb6e6b4feecae96990dd94c93d5eb790ad3c" dependencies = [ "anyhow", "async-oneshot", @@ -2929,8 +2927,7 @@ dependencies = [ [[package]] name = "onagre-launcher-toolkit" version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86303060d76d035cf871f5f7938ad7889312f7c5f48f5f11c46aad9ead341836" +source = "git+https://github.com/onagre-launcher/launcher#56c8cb6e6b4feecae96990dd94c93d5eb790ad3c" dependencies = [ "async-trait", "dirs 4.0.0", diff --git a/Cargo.toml b/Cargo.toml index 2fd3d60..bd4c752 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,7 +30,7 @@ iced_style = "0.9.0" tokio = { version = "1.29.1", features = ["process", "macros", "io-util"] } sled = "0.34.7" -onagre-launcher-toolkit = "0.1.1" +onagre-launcher-toolkit = { git = "https://github.com/onagre-launcher/launcher" } clap = { version = "^4", features = ["derive"] } freedesktop-icons = "0.2.5" @@ -53,4 +53,4 @@ shell-words = "^1" [dev-dependencies] speculoos = "0.11.0" -pretty_assertions = "1.2.1" \ No newline at end of file +pretty_assertions = "1.2.1" diff --git a/src/app/mod.rs b/src/app/mod.rs index 98854d3..587f60c 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -19,9 +19,7 @@ use once_cell::sync::Lazy; use crate::app::entries::pop_entry::PopSearchResult; use crate::app::entries::AsEntry; use crate::app::mode::ActiveMode; -use crate::app::plugin_matchers::Plugin; use crate::app::state::{Selection, State}; -use crate::app::subscriptions::plugin_configs::PluginMatcherSubscription; use crate::app::subscriptions::pop_launcher::{PopLauncherSubscription, SubscriptionMessage}; use crate::db::desktop_entry::DesktopEntryEntity; use crate::db::plugin::PluginCommandEntity; @@ -38,7 +36,7 @@ pub mod state; pub mod style; pub mod subscriptions; -pub fn run() -> iced::Result { +pub fn run(pre_value: Option) -> iced::Result { debug!("Starting Onagre in debug mode"); let default_font = THEME @@ -68,7 +66,7 @@ pub fn run() -> iced::Result { antialiasing: true, exit_on_close_request: false, default_font, - flags: (), + flags: OnagreFlags { pre_value }, }) } @@ -84,25 +82,36 @@ pub enum Message { InputChanged(String), KeyboardEvent(KeyCode), SubscriptionResponse(SubscriptionMessage), - PluginConfig(Plugin), Unfocused, } static INPUT_ID: Lazy = Lazy::new(text_input::Id::unique); static SCROLL_ID: Lazy = Lazy::new(scrollable::Id::unique); +pub struct OnagreFlags { + pre_value: Option, +} + impl Application for Onagre<'_> { type Executor = iced::executor::Default; type Message = Message; type Theme = Theme; - type Flags = (); + type Flags = OnagreFlags; - fn new(_: Self::Flags) -> (Self, Command) { - let onagre = Onagre { - state: Default::default(), - request_tx: Default::default(), - }; + fn new(flags: OnagreFlags) -> (Self, Command) { + let onagre; + if let Some(pre_value) = flags.pre_value { + onagre = Onagre { + state: State::with_mode(&pre_value), + request_tx: Default::default(), + }; + } else { + onagre = Onagre { + state: Default::default(), + request_tx: Default::default(), + }; + } ( onagre, @@ -127,12 +136,6 @@ impl Application for Onagre<'_> { Command::none() } } - Message::PluginConfig(plugin) => { - self.state - .plugin_matchers - .insert(plugin.name.clone(), plugin); - Command::none() - } } } @@ -285,12 +288,11 @@ impl Application for Onagre<'_> { app_wrapper.into() } - fn subscription(&self) -> iced::Subscription { + fn subscription(&self) -> Subscription { let keyboard_event = Onagre::keyboard_event(); let pop_launcher = PopLauncherSubscription::create().map(Message::SubscriptionResponse); - let matchers = PluginMatcherSubscription::create().map(Message::PluginConfig); - let subs = vec![keyboard_event, pop_launcher, matchers]; - iced::Subscription::batch(subs) + let subs = vec![keyboard_event, pop_launcher]; + Subscription::batch(subs) } } @@ -357,8 +359,7 @@ impl Onagre<'_> { _ => Selection::PopLauncher(0), }; - let _: iced::Command = - scrollable::snap_to(SCROLL_ID.clone(), RelativeOffset::START); + let _: Command = scrollable::snap_to(SCROLL_ID.clone(), RelativeOffset::START); match &self.state.get_active_mode() { ActiveMode::History => {} diff --git a/src/app/state.rs b/src/app/state.rs index cab4acd..5587905 100644 --- a/src/app/state.rs +++ b/src/app/state.rs @@ -21,12 +21,44 @@ pub struct State<'a> { pub plugin_matchers: PluginConfigCache, } -#[derive(Debug, Default)] +#[derive(Debug)] pub struct PluginConfigCache { pub(crate) inner: HashMap, } impl PluginConfigCache { + pub fn load() -> Self { + let mut cache = HashMap::new(); + for (path, config, regex) in onagre_launcher_toolkit::service::load::from_paths() { + let icon: Option = THEME.icon_theme.as_ref().and_then(|theme| { + config + .icon + .as_ref() + .map(|source| (source, theme)) + .and_then(|(source, theme)| IconPath::from_source(source, theme)) + }); + + let name = path + .parent() + .expect("Plugin config should have a parent directory") + .file_name() + .expect("Plugin directory should have an utf8 filename") + .to_string_lossy() + .to_string(); + + let plugin = Plugin { + name: name.clone(), + icon, + history: config.history, + help: config.query.help.map(|h| h.to_string()), + regex, + }; + + cache.insert(name, plugin); + } + + PluginConfigCache { inner: cache } + } pub fn get_plugin_icon(&self, plugin_name: &str) -> Option { self.inner.get(plugin_name).and_then(|de| de.icon.clone()) } @@ -62,52 +94,51 @@ impl State<'_> { } } - // TODO: refactor me please + pub fn with_mode(mode_query: &str) -> Self { + let plugin_matchers = PluginConfigCache::load(); + let plugin_split = match_web_plugins(mode_query).or_else(|| { + plugin_matchers + .inner + .values() + .map(|matcher| matcher.try_match(mode_query)) + .find_map(|match_| match_) + }); + + let mode = plugin_split + .as_ref() + .map(|split| ActiveMode::from(split.clone())) + .unwrap_or_default(); + let modifier_display = plugin_split + .as_ref() + .map(|query_data| query_data.modifier.clone()) + .unwrap_or_default(); + let input_display = plugin_split + .map(|query_data| query_data.query) + .unwrap_or_default(); + + State { + selected: Selection::History(0), + cache: Default::default(), + pop_search: Default::default(), + scroll: Default::default(), + input_value: SearchInput { + mode, + modifier_display, // dgg + input_display, // + pop_query: mode_query.to_string(), // dgg + }, + exec_on_next_search: false, + plugin_matchers, + } + } + pub fn set_input(&mut self, input: &str) { let previous_modi = self.input_value.modifier_display.clone(); if !previous_modi.is_empty() { - if input.is_empty() { - self.input_value.modifier_display = "".to_string(); - self.input_value.input_display = if THEME.plugin_hint().is_none() { - input.to_string() - } else { - previous_modi - }; - self.input_value.mode = ActiveMode::DesktopEntry; - let _: iced::Command = text_input::move_cursor_to_end(INPUT_ID.clone()); - } else { - self.input_value.input_display = input.to_string(); - } + self.set_input_with_modifier(input, previous_modi); } else { - let terms = &format!("{}{}", previous_modi, input); - let plugin_split = match_web_plugins(terms).or_else(|| { - self.plugin_matchers - .inner - .values() - .map(|matcher| matcher.try_match(terms)) - .find_map(|match_| match_) - }); - - if let Some(query_data) = plugin_split { - self.input_value.modifier_display = query_data.modifier.clone(); - self.input_value.mode = ActiveMode::from(query_data.clone()); - // If plugin-hint is disabled use the full input, - // otherwise use the split value - self.input_value.input_display = if THEME.plugin_hint().is_none() { - input.to_string() - } else { - query_data.query - }; - } else { - self.input_value.input_display = input.to_string(); - - if input.is_empty() { - self.input_value.mode = ActiveMode::History - } else { - self.input_value.mode = ActiveMode::DesktopEntry - } - } + self.set_input_without_modifier(input); }; let pop_query = match &self.input_value.mode { @@ -128,6 +159,51 @@ impl State<'_> { self.input_value.mode, self.input_value.input_display ); } + + fn set_input_without_modifier(&mut self, input: &str) { + let plugin_split = match_web_plugins(input).or_else(|| { + self.plugin_matchers + .inner + .values() + .map(|matcher| matcher.try_match(input)) + .find_map(|match_| match_) + }); + + if let Some(query_data) = plugin_split { + self.input_value.modifier_display = query_data.modifier.clone(); + self.input_value.mode = ActiveMode::from(query_data.clone()); + // If plugin-hint is disabled use the full input, + // otherwise use the split value + self.input_value.input_display = if THEME.plugin_hint().is_none() { + input.to_string() + } else { + query_data.query + }; + } else { + self.input_value.input_display = input.to_string(); + + if input.is_empty() { + self.input_value.mode = ActiveMode::History + } else { + self.input_value.mode = ActiveMode::DesktopEntry + } + } + } + + fn set_input_with_modifier(&mut self, input: &str, previous_modi: String) { + if input.is_empty() { + self.input_value.modifier_display = "".to_string(); + self.input_value.input_display = if THEME.plugin_hint().is_none() { + input.to_string() + } else { + previous_modi + }; + self.input_value.mode = ActiveMode::DesktopEntry; + let _: iced::Command = text_input::move_cursor_to_end(INPUT_ID.clone()); + } else { + self.input_value.input_display = input.to_string(); + } + } } #[derive(Debug, Default)] @@ -147,7 +223,7 @@ impl Default for State<'_> { scroll: Default::default(), input_value: SearchInput::default(), exec_on_next_search: false, - plugin_matchers: PluginConfigCache::default(), + plugin_matchers: PluginConfigCache::load(), } } } diff --git a/src/app/subscriptions/mod.rs b/src/app/subscriptions/mod.rs index 7a0fc9b..117dddd 100644 --- a/src/app/subscriptions/mod.rs +++ b/src/app/subscriptions/mod.rs @@ -1,2 +1 @@ -pub mod plugin_configs; pub mod pop_launcher; diff --git a/src/app/subscriptions/plugin_configs.rs b/src/app/subscriptions/plugin_configs.rs deleted file mode 100644 index 4d887dd..0000000 --- a/src/app/subscriptions/plugin_configs.rs +++ /dev/null @@ -1,57 +0,0 @@ -use std::hash::Hasher; - -use iced::futures::stream::BoxStream; -use iced::futures::StreamExt; -use iced::Subscription; -use iced_core::event::Status; -use iced_runtime::futures::subscription::Recipe; - -use crate::app::plugin_matchers::Plugin; -use crate::icons::IconPath; -use crate::THEME; - -pub struct PluginMatcherSubscription; - -impl PluginMatcherSubscription { - pub fn create() -> Subscription { - Subscription::from_recipe(PluginMatcherSubscription) - } -} - -impl Recipe for PluginMatcherSubscription { - type Output = Plugin; - - fn hash(&self, state: &mut iced_core::Hasher) { - state.write("PluginMatcherSubscription".as_bytes()) - } - - fn stream(self: Box, _: BoxStream<(iced::Event, Status)>) -> BoxStream { - Box::pin(onagre_launcher_toolkit::service::load::from_paths().map( - |(path, config, regex)| { - let icon: Option = THEME.icon_theme.as_ref().and_then(|theme| { - config - .icon - .as_ref() - .map(|source| (source, theme)) - .and_then(|(source, theme)| IconPath::from_source(source, theme)) - }); - - let name = path - .parent() - .expect("Plugin config should have a parent directory") - .file_name() - .expect("Plugin directory should have an utf8 filename") - .to_string_lossy() - .to_string(); - - Plugin { - name, - icon, - history: config.history, - help: config.query.help.map(|h| h.to_string()), - regex, - } - }, - )) - } -} diff --git a/src/main.rs b/src/main.rs index e968760..7b9f032 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,7 +3,7 @@ use std::path::PathBuf; use anyhow::anyhow; use app::style::Theme; use clap::Parser; -use log::{info, LevelFilter}; +use log::{debug, info, LevelFilter}; use once_cell::sync::Lazy; use std::sync::Mutex; use systemd_journal_logger::JournalLog; @@ -34,6 +34,9 @@ struct Cli { help = "Path to an alternate onagre theme file" )] theme: Option, + + #[arg(long = "mode", short = 'm', help = "The mode parameter as a string")] + mode: Option, } pub fn main() -> iced::Result { @@ -51,5 +54,11 @@ pub fn main() -> iced::Result { info!("Using alternate theme : {:?}", THEME_PATH.lock().unwrap()); } - app::run() + if let Some(mode) = cli.mode { + debug!("Mode parameter: {:?}", mode); + + app::run(Some(mode)) + } else { + app::run(None) + } }