feat(core): implement 'espanso cmd' subcommand. Fix #832

This commit is contained in:
Federico Terzi 2021-10-31 16:33:19 +01:00
parent 70d97bf90d
commit 4ca35ea14d
6 changed files with 123 additions and 33 deletions

72
espanso/src/cli/cmd.rs Normal file
View File

@ -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 <https://www.gnu.org/licenses/>.
*/
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)
}

View File

@ -23,6 +23,7 @@ use clap::ArgMatches;
use espanso_config::{config::ConfigStore, error::NonFatalErrorSet, matches::store::MatchStore}; use espanso_config::{config::ConfigStore, error::NonFatalErrorSet, matches::store::MatchStore};
use espanso_path::Paths; use espanso_path::Paths;
pub mod cmd;
pub mod daemon; pub mod daemon;
pub mod edit; pub mod edit;
pub mod env_path; pub mod env_path;

View File

@ -68,5 +68,12 @@ impl<'a> funnel::Source<'a> for IpcEventSource<'a> {
} }
fn is_event_type_allowed(event: &EventType) -> bool { fn is_event_type_allowed(event: &EventType) -> bool {
matches!(event, EventType::MatchExecRequest(_)) matches!(
event,
EventType::MatchExecRequest(_)
| EventType::ShowSearchBar
| EventType::DisableRequest
| EventType::EnableRequest
| EventType::ToggleRequest
)
} }

View File

@ -59,21 +59,17 @@ pub fn initialize_and_spawn(
EventHandlerResponse::NoResponse EventHandlerResponse::NoResponse
} }
IPCEvent::RequestMatchExpansion(payload) => { IPCEvent::DisableRequest => send_event(&event_notify, EventType::DisableRequest),
if let Err(err) = IPCEvent::EnableRequest => send_event(&event_notify, EventType::EnableRequest),
event_notify.send(EventType::MatchExecRequest(MatchExecRequestEvent { IPCEvent::ToggleRequest => send_event(&event_notify, EventType::ToggleRequest),
trigger: payload.trigger, IPCEvent::OpenSearchBar => send_event(&event_notify, EventType::ShowSearchBar),
args: payload.args, IPCEvent::RequestMatchExpansion(payload) => send_event(
})) &event_notify,
{ EventType::MatchExecRequest(MatchExecRequestEvent {
error!( trigger: payload.trigger,
"experienced error while sending event signal from worker ipc handler: {}", args: payload.args,
err }),
); ),
}
EventHandlerResponse::NoResponse
}
#[allow(unreachable_patterns)] #[allow(unreachable_patterns)]
unexpected_event => { unexpected_event => {
warn!( warn!(
@ -89,3 +85,17 @@ pub fn initialize_and_spawn(
Ok(()) Ok(())
} }
fn send_event(
event_notify: &Sender<EventType>,
event: EventType,
) -> EventHandlerResponse<IPCEvent> {
if let Err(err) = event_notify.send(event) {
error!(
"experienced error while sending event signal from worker ipc handler: {}",
err
);
}
EventHandlerResponse::NoResponse
}

View File

@ -27,6 +27,11 @@ pub enum IPCEvent {
Exit, Exit,
ExitAllProcesses, ExitAllProcesses,
EnableRequest,
DisableRequest,
ToggleRequest,
OpenSearchBar,
RequestMatchExpansion(RequestMatchExpansionPayload), RequestMatchExpansion(RequestMatchExpansionPayload),
} }

View File

@ -72,6 +72,7 @@ lazy_static! {
cli::workaround::new(), cli::workaround::new(),
cli::package::new(), cli::package::new(),
cli::match_cli::new(), cli::match_cli::new(),
cli::cmd::new(),
]; ];
static ref ALIASES: Vec<CliAlias> = vec![ static ref ALIASES: Vec<CliAlias> = vec![
CliAlias { CliAlias {
@ -220,17 +221,17 @@ fn main() {
.subcommand(SubCommand::with_name("unregister").about("Remove 'espanso' command from PATH")) .subcommand(SubCommand::with_name("unregister").about("Remove 'espanso' command from PATH"))
.about("Add or remove the 'espanso' command from the PATH"), .about("Add or remove the 'espanso' command from the PATH"),
) )
// .subcommand(SubCommand::with_name("cmd") .subcommand(SubCommand::with_name("cmd")
// .about("Send a command to the espanso daemon.") .about("Send a command to the espanso daemon.")
// .subcommand(SubCommand::with_name("exit") .subcommand(SubCommand::with_name("enable")
// .about("Terminate the daemon.")) .about("Enable expansions."))
// .subcommand(SubCommand::with_name("enable") .subcommand(SubCommand::with_name("disable")
// .about("Enable the espanso replacement engine.")) .about("Disable expansions."))
// .subcommand(SubCommand::with_name("disable") .subcommand(SubCommand::with_name("toggle")
// .about("Disable the espanso replacement engine.")) .about("Enable/Disable expansions."))
// .subcommand(SubCommand::with_name("toggle") .subcommand(SubCommand::with_name("search")
// .about("Toggle the status of the espanso replacement engine.")) .about("Open the Espanso's search bar."))
// ) )
.subcommand(SubCommand::with_name("edit") .subcommand(SubCommand::with_name("edit")
.about("Shortcut to open the default text editor to edit config files") .about("Shortcut to open the default text editor to edit config files")
.arg(Arg::with_name("target_file") .arg(Arg::with_name("target_file")
@ -252,10 +253,6 @@ For example, specifying 'email' is equivalent to 'match/email.yml'."#))
.setting(AppSettings::Hidden) .setting(AppSettings::Hidden)
.about("Start the daemon without spawning a new process."), .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("launcher").setting(AppSettings::Hidden))
.subcommand(SubCommand::with_name("log").about("Print the daemon logs.")) .subcommand(SubCommand::with_name("log").about("Print the daemon logs."))
.subcommand( .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(
SubCommand::with_name("path") SubCommand::with_name("path")
.about("Prints all the espanso directory paths to easily locate configuration and matches.") .about("Prints all the espanso directory paths to easily locate configuration and matches.")