diff --git a/espanso/src/cli/match_cli/list.rs b/espanso/src/cli/match_cli/list.rs
new file mode 100644
index 0000000..53614de
--- /dev/null
+++ b/espanso/src/cli/match_cli/list.rs
@@ -0,0 +1,102 @@
+/*
+ * 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 anyhow::Result;
+use clap::ArgMatches;
+use espanso_config::{
+ config::{AppProperties, ConfigStore},
+ matches::{store::MatchStore, Match, MatchCause},
+};
+use serde::Serialize;
+
+pub fn list_main(
+ cli_args: &ArgMatches,
+ config_store: Box,
+ match_store: Box,
+) -> Result<()> {
+ let only_triggers = cli_args.is_present("onlytriggers");
+ let preserve_newlines = cli_args.is_present("preservenewlines");
+
+ let class = cli_args.value_of("class");
+ let title = cli_args.value_of("title");
+ let exec = cli_args.value_of("exec");
+
+ let config = config_store.active(&AppProperties { title, class, exec });
+ let match_set = match_store.query(config.match_paths());
+
+ if cli_args.is_present("json") {
+ print_matches_as_json(&match_set.matches)?;
+ } else {
+ print_matches_as_plain(&match_set.matches, only_triggers, preserve_newlines)
+ }
+
+ Ok(())
+}
+
+pub fn print_matches_as_plain(match_list: &[&Match], only_triggers: bool, preserve_newlines: bool) {
+ for m in match_list {
+ let triggers = match &m.cause {
+ MatchCause::None => vec!["(none)".to_string()],
+ MatchCause::Trigger(trigger_cause) => trigger_cause.triggers.clone(),
+ MatchCause::Regex(regex_cause) => vec![regex_cause.regex.clone()],
+ };
+
+ for trigger in triggers {
+ if only_triggers {
+ println!("{}", trigger);
+ } else {
+ let description = m.description();
+
+ if preserve_newlines {
+ println!("{} - {}", trigger, description)
+ } else {
+ println!("{} - {}", trigger, description.replace('\n', " "))
+ }
+ }
+ }
+ }
+}
+
+#[derive(Debug, Serialize)]
+struct JsonMatchEntry {
+ triggers: Vec,
+ replace: String,
+}
+
+pub fn print_matches_as_json(match_list: &[&Match]) -> Result<()> {
+ let mut entries = Vec::new();
+ for m in match_list {
+ let triggers = match &m.cause {
+ MatchCause::None => vec!["(none)".to_string()],
+ MatchCause::Trigger(trigger_cause) => trigger_cause.triggers.clone(),
+ MatchCause::Regex(regex_cause) => vec![regex_cause.regex.clone()],
+ };
+
+ entries.push(JsonMatchEntry {
+ triggers,
+ replace: m.description().to_string(),
+ })
+ }
+
+ let json = serde_json::to_string_pretty(&entries)?;
+
+ println!("{}", json);
+
+ Ok(())
+}
diff --git a/espanso/src/cli/match_cli/mod.rs b/espanso/src/cli/match_cli/mod.rs
new file mode 100644
index 0000000..aa458b8
--- /dev/null
+++ b/espanso/src/cli/match_cli/mod.rs
@@ -0,0 +1,51 @@
+/*
+ * 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 super::{CliModule, CliModuleArgs};
+
+mod list;
+
+pub fn new() -> CliModule {
+ CliModule {
+ requires_config: true,
+ subcommand: "match".to_string(),
+ entry: match_main,
+ ..Default::default()
+ }
+}
+
+fn match_main(args: CliModuleArgs) -> i32 {
+ let cli_args = args.cli_args.expect("missing cli_args");
+ let config_store = args.config_store.expect("missing config_store");
+ let match_store = args.match_store.expect("missing match_store");
+
+ if let Some(sub_args) = cli_args.subcommand_matches("list") {
+ if let Err(err) = list::list_main(sub_args, config_store, match_store) {
+ eprintln!("unable to list matches: {:?}", err);
+ return 1;
+ }
+ } else if let Some(_sub_args) = cli_args.subcommand_matches("exec") {
+ todo!();
+ } else {
+ eprintln!("Invalid use, please run 'espanso match --help' to get more information.");
+ return 1;
+ }
+
+ 0
+}
diff --git a/espanso/src/cli/mod.rs b/espanso/src/cli/mod.rs
index 2cdba94..6c3fb99 100644
--- a/espanso/src/cli/mod.rs
+++ b/espanso/src/cli/mod.rs
@@ -28,6 +28,7 @@ pub mod edit;
pub mod env_path;
pub mod launcher;
pub mod log;
+pub mod match_cli;
pub mod migrate;
pub mod modulo;
pub mod package;
diff --git a/espanso/src/main.rs b/espanso/src/main.rs
index d0897ed..f5c9f0b 100644
--- a/espanso/src/main.rs
+++ b/espanso/src/main.rs
@@ -71,6 +71,7 @@ lazy_static! {
cli::service::new(),
cli::workaround::new(),
cli::package::new(),
+ cli::match_cli::new(),
];
static ref ALIASES: Vec = vec![
CliAlias {
@@ -353,39 +354,57 @@ For example, specifying 'email' is equivalent to 'match/email.yml'."#))
.subcommand(restart_subcommand)
.subcommand(stop_subcommand)
.subcommand(status_subcommand)
- // .subcommand(SubCommand::with_name("match")
- // .about("List and execute matches from the CLI")
- // .subcommand(SubCommand::with_name("list")
- // .about("Print all matches to standard output")
- // .arg(Arg::with_name("json")
- // .short("j")
- // .long("json")
- // .help("Return the matches as json")
- // .required(false)
- // .takes_value(false)
- // )
- // .arg(Arg::with_name("onlytriggers")
- // .short("t")
- // .long("onlytriggers")
- // .help("Print only triggers without replacement")
- // .required(false)
- // .takes_value(false)
- // )
- // .arg(Arg::with_name("preservenewlines")
- // .short("n")
- // .long("preservenewlines")
- // .help("Preserve newlines when printing replacements")
- // .required(false)
- // .takes_value(false)
- // )
- // )
- // .subcommand(SubCommand::with_name("exec")
- // .about("Triggers the expansion of the given match")
- // .arg(Arg::with_name("trigger")
- // .help("The trigger of the match to be expanded")
- // )
- // )
- // )
+ .subcommand(SubCommand::with_name("match")
+ .about("List and execute matches from the CLI")
+ .subcommand(SubCommand::with_name("list")
+ .about("Print matches to standard output")
+ .arg(Arg::with_name("json")
+ .short("j")
+ .long("json")
+ .help("Output matches to the JSON format")
+ .required(false)
+ .takes_value(false)
+ )
+ .arg(Arg::with_name("onlytriggers")
+ .short("t")
+ .long("only-triggers")
+ .help("Print only triggers without replacement")
+ .required(false)
+ .takes_value(false)
+ )
+ .arg(Arg::with_name("preservenewlines")
+ .short("n")
+ .long("preserve-newlines")
+ .help("Preserve newlines when printing replacements. Does nothing when using JSON format.")
+ .required(false)
+ .takes_value(false)
+ )
+ .arg(Arg::with_name("class")
+ .long("class")
+ .help("Only return matches that would be active with the given class. This is relevant if you want to list matches only active inside an app-specific config.")
+ .required(false)
+ .takes_value(true)
+ )
+ .arg(Arg::with_name("title")
+ .long("title")
+ .help("Only return matches that would be active with the given title. This is relevant if you want to list matches only active inside an app-specific config.")
+ .required(false)
+ .takes_value(true)
+ )
+ .arg(Arg::with_name("exec")
+ .long("exec")
+ .help("Only return matches that would be active with the given exec. This is relevant if you want to list matches only active inside an app-specific config.")
+ .required(false)
+ .takes_value(true)
+ )
+ )
+ // .subcommand(SubCommand::with_name("exec")
+ // .about("Triggers the expansion of the given match")
+ // .arg(Arg::with_name("trigger")
+ // .help("The trigger of the match to be expanded")
+ // )
+ // )
+ )
.subcommand(
SubCommand::with_name("package")
.about("package-management commands")