diff --git a/espanso/src/cli/cmd.rs b/espanso/src/cli/cmd.rs
new file mode 100644
index 0000000..1dcd462
--- /dev/null
+++ b/espanso/src/cli/cmd.rs
@@ -0,0 +1,72 @@
+/*
+ * This file is part of espanso.
+ *
+ * Copyright (C) 2019-2021 Federico Terzi
+ *
+ * espanso is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * espanso is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with espanso. If not, see .
+ */
+
+use std::path::Path;
+
+use crate::{
+ ipc::{create_ipc_client_to_worker, IPCEvent},
+ lock::acquire_worker_lock,
+};
+
+use super::{CliModule, CliModuleArgs};
+use anyhow::{bail, Result};
+use espanso_ipc::IPCClient;
+
+pub fn new() -> CliModule {
+ CliModule {
+ requires_paths: true,
+ subcommand: "cmd".to_string(),
+ entry: cmd_main,
+ ..Default::default()
+ }
+}
+
+fn cmd_main(args: CliModuleArgs) -> i32 {
+ let cli_args = args.cli_args.expect("missing cli_args");
+ let paths = args.paths.expect("missing paths");
+
+ let event = if cli_args.subcommand_matches("enable").is_some() {
+ IPCEvent::EnableRequest
+ } else if cli_args.subcommand_matches("disable").is_some() {
+ IPCEvent::DisableRequest
+ } else if cli_args.subcommand_matches("toggle").is_some() {
+ IPCEvent::ToggleRequest
+ } else if cli_args.subcommand_matches("search").is_some() {
+ IPCEvent::OpenSearchBar
+ } else {
+ eprintln!("unknown command, please run `espanso cmd --help` to see a list of valid ones.");
+ return 1;
+ };
+
+ if let Err(error) = send_event_to_worker(&paths.runtime, event) {
+ eprintln!("unable to send command, error: {:?}", error);
+ return 2;
+ }
+
+ 0
+}
+
+fn send_event_to_worker(runtime_path: &Path, event: IPCEvent) -> Result<()> {
+ if acquire_worker_lock(runtime_path).is_some() {
+ bail!("Worker process is not running, please start Espanso first.")
+ }
+
+ let mut client = create_ipc_client_to_worker(runtime_path)?;
+ client.send_async(event)
+}
diff --git a/espanso/src/cli/mod.rs b/espanso/src/cli/mod.rs
index 6c3fb99..f7a3768 100644
--- a/espanso/src/cli/mod.rs
+++ b/espanso/src/cli/mod.rs
@@ -23,6 +23,7 @@ use clap::ArgMatches;
use espanso_config::{config::ConfigStore, error::NonFatalErrorSet, matches::store::MatchStore};
use espanso_path::Paths;
+pub mod cmd;
pub mod daemon;
pub mod edit;
pub mod env_path;
diff --git a/espanso/src/cli/worker/engine/funnel/ipc.rs b/espanso/src/cli/worker/engine/funnel/ipc.rs
index 3efc97f..0708358 100644
--- a/espanso/src/cli/worker/engine/funnel/ipc.rs
+++ b/espanso/src/cli/worker/engine/funnel/ipc.rs
@@ -68,5 +68,12 @@ impl<'a> funnel::Source<'a> for IpcEventSource<'a> {
}
fn is_event_type_allowed(event: &EventType) -> bool {
- matches!(event, EventType::MatchExecRequest(_))
+ matches!(
+ event,
+ EventType::MatchExecRequest(_)
+ | EventType::ShowSearchBar
+ | EventType::DisableRequest
+ | EventType::EnableRequest
+ | EventType::ToggleRequest
+ )
}
diff --git a/espanso/src/cli/worker/ipc.rs b/espanso/src/cli/worker/ipc.rs
index 9c06c03..1ae545e 100644
--- a/espanso/src/cli/worker/ipc.rs
+++ b/espanso/src/cli/worker/ipc.rs
@@ -59,21 +59,17 @@ pub fn initialize_and_spawn(
EventHandlerResponse::NoResponse
}
- IPCEvent::RequestMatchExpansion(payload) => {
- if let Err(err) =
- event_notify.send(EventType::MatchExecRequest(MatchExecRequestEvent {
- trigger: payload.trigger,
- args: payload.args,
- }))
- {
- error!(
- "experienced error while sending event signal from worker ipc handler: {}",
- err
- );
- }
-
- EventHandlerResponse::NoResponse
- }
+ IPCEvent::DisableRequest => send_event(&event_notify, EventType::DisableRequest),
+ IPCEvent::EnableRequest => send_event(&event_notify, EventType::EnableRequest),
+ IPCEvent::ToggleRequest => send_event(&event_notify, EventType::ToggleRequest),
+ IPCEvent::OpenSearchBar => send_event(&event_notify, EventType::ShowSearchBar),
+ IPCEvent::RequestMatchExpansion(payload) => send_event(
+ &event_notify,
+ EventType::MatchExecRequest(MatchExecRequestEvent {
+ trigger: payload.trigger,
+ args: payload.args,
+ }),
+ ),
#[allow(unreachable_patterns)]
unexpected_event => {
warn!(
@@ -89,3 +85,17 @@ pub fn initialize_and_spawn(
Ok(())
}
+
+fn send_event(
+ event_notify: &Sender,
+ event: EventType,
+) -> EventHandlerResponse {
+ if let Err(err) = event_notify.send(event) {
+ error!(
+ "experienced error while sending event signal from worker ipc handler: {}",
+ err
+ );
+ }
+
+ EventHandlerResponse::NoResponse
+}
diff --git a/espanso/src/ipc.rs b/espanso/src/ipc.rs
index 1e1f6b1..5e8d3b4 100644
--- a/espanso/src/ipc.rs
+++ b/espanso/src/ipc.rs
@@ -27,6 +27,11 @@ pub enum IPCEvent {
Exit,
ExitAllProcesses,
+ EnableRequest,
+ DisableRequest,
+ ToggleRequest,
+ OpenSearchBar,
+
RequestMatchExpansion(RequestMatchExpansionPayload),
}
diff --git a/espanso/src/main.rs b/espanso/src/main.rs
index d066ab6..58cf84f 100644
--- a/espanso/src/main.rs
+++ b/espanso/src/main.rs
@@ -72,6 +72,7 @@ lazy_static! {
cli::workaround::new(),
cli::package::new(),
cli::match_cli::new(),
+ cli::cmd::new(),
];
static ref ALIASES: Vec = vec![
CliAlias {
@@ -220,17 +221,17 @@ fn main() {
.subcommand(SubCommand::with_name("unregister").about("Remove 'espanso' command from PATH"))
.about("Add or remove the 'espanso' command from the PATH"),
)
- // .subcommand(SubCommand::with_name("cmd")
- // .about("Send a command to the espanso daemon.")
- // .subcommand(SubCommand::with_name("exit")
- // .about("Terminate the daemon."))
- // .subcommand(SubCommand::with_name("enable")
- // .about("Enable the espanso replacement engine."))
- // .subcommand(SubCommand::with_name("disable")
- // .about("Disable the espanso replacement engine."))
- // .subcommand(SubCommand::with_name("toggle")
- // .about("Toggle the status of the espanso replacement engine."))
- // )
+ .subcommand(SubCommand::with_name("cmd")
+ .about("Send a command to the espanso daemon.")
+ .subcommand(SubCommand::with_name("enable")
+ .about("Enable expansions."))
+ .subcommand(SubCommand::with_name("disable")
+ .about("Disable expansions."))
+ .subcommand(SubCommand::with_name("toggle")
+ .about("Enable/Disable expansions."))
+ .subcommand(SubCommand::with_name("search")
+ .about("Open the Espanso's search bar."))
+ )
.subcommand(SubCommand::with_name("edit")
.about("Shortcut to open the default text editor to edit config files")
.arg(Arg::with_name("target_file")
@@ -252,10 +253,6 @@ For example, specifying 'email' is equivalent to 'match/email.yml'."#))
.setting(AppSettings::Hidden)
.about("Start the daemon without spawning a new process."),
)
- // .subcommand(SubCommand::with_name("register")
- // .about("MacOS and Linux only. Register espanso in the system daemon manager."))
- // .subcommand(SubCommand::with_name("unregister")
- // .about("MacOS and Linux only. Unregister espanso from the system daemon manager."))
.subcommand(SubCommand::with_name("launcher").setting(AppSettings::Hidden))
.subcommand(SubCommand::with_name("log").about("Print the daemon logs."))
.subcommand(
@@ -306,8 +303,6 @@ For example, specifying 'email' is equivalent to 'match/email.yml'."#))
),
),
)
- // .subcommand(SubCommand::with_name("status")
- // .about("Check if the espanso daemon is running or not."))
.subcommand(
SubCommand::with_name("path")
.about("Prints all the espanso directory paths to easily locate configuration and matches.")