From 1f0fe74ac10c2cb6c0203afa9efad3dd24eec257 Mon Sep 17 00:00:00 2001 From: Federico Terzi <federicoterzi96@gmail.com> Date: Sun, 28 Mar 2021 18:22:50 +0200 Subject: [PATCH] feat(core): implement basic cli handler structure and path handler --- Cargo.lock | 76 ++++++++ espanso/Cargo.toml | 7 +- espanso/src/cli/mod.rs | 65 +++++++ espanso/src/cli/path.rs | 59 ++++++ espanso/src/logging/mod.rs | 89 +++++++++ espanso/src/main.rs | 388 ++++++++++++++++++++++++------------- espanso/src/main_old2.rs | 75 ------- 7 files changed, 549 insertions(+), 210 deletions(-) create mode 100644 espanso/src/cli/mod.rs create mode 100644 espanso/src/cli/path.rs create mode 100644 espanso/src/logging/mod.rs delete mode 100644 espanso/src/main_old2.rs diff --git a/Cargo.lock b/Cargo.lock index 1c17b12..5fed2e9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9,6 +9,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "ansi_term" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" +dependencies = [ + "winapi", +] + [[package]] name = "anyhow" version = "1.0.38" @@ -27,6 +36,17 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + [[package]] name = "autocfg" version = "1.0.1" @@ -93,6 +113,21 @@ dependencies = [ "winapi", ] +[[package]] +name = "clap" +version = "2.33.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" +dependencies = [ + "ansi_term", + "atty", + "bitflags 1.2.1", + "strsim", + "textwrap", + "unicode-width", + "vec_map", +] + [[package]] name = "const_fn" version = "0.4.5" @@ -250,6 +285,8 @@ dependencies = [ name = "espanso" version = "1.0.0" dependencies = [ + "anyhow", + "clap", "espanso-clipboard", "espanso-config", "espanso-detect", @@ -258,8 +295,11 @@ dependencies = [ "espanso-match", "espanso-path", "espanso-ui", + "lazy_static", + "log", "maplit", "simplelog", + "thiserror", ] [[package]] @@ -448,6 +488,15 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "hermit-abi" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" +dependencies = [ + "libc", +] + [[package]] name = "itertools" version = "0.10.0" @@ -867,6 +916,12 @@ dependencies = [ "termcolor", ] +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" + [[package]] name = "strum" version = "0.8.0" @@ -947,6 +1002,15 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width", +] + [[package]] name = "thiserror" version = "1.0.23" @@ -993,6 +1057,12 @@ version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796" +[[package]] +name = "unicode-width" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" + [[package]] name = "unicode-xid" version = "0.0.4" @@ -1005,6 +1075,12 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" +[[package]] +name = "vec_map" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" + [[package]] name = "version_check" version = "0.9.2" diff --git a/espanso/Cargo.toml b/espanso/Cargo.toml index 4843267..f6a2412 100644 --- a/espanso/Cargo.toml +++ b/espanso/Cargo.toml @@ -23,4 +23,9 @@ espanso-clipboard = { path = "../espanso-clipboard" } espanso-info = { path = "../espanso-info" } espanso-path = { path = "../espanso-path" } maplit = "1.0.2" -simplelog = "0.9.0" \ No newline at end of file +simplelog = "0.9.0" +log = "0.4.14" +anyhow = "1.0.38" +thiserror = "1.0.23" +clap = "2.33.3" +lazy_static = "1.4.0" \ No newline at end of file diff --git a/espanso/src/cli/mod.rs b/espanso/src/cli/mod.rs new file mode 100644 index 0000000..df2cb10 --- /dev/null +++ b/espanso/src/cli/mod.rs @@ -0,0 +1,65 @@ +/* + * 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 clap::ArgMatches; +use espanso_config::{config::ConfigStore, matches::store::MatchStore}; +use espanso_path::Paths; + +pub mod log; +pub mod path; + +pub struct CliModule { + pub enable_logs: bool, + pub requires_paths: bool, + pub requires_config: bool, + pub subcommand: String, + pub entry: fn(CliModuleArgs), +} + +impl Default for CliModule { + fn default() -> Self { + Self { + enable_logs: false, + requires_paths: false, + requires_config: false, + subcommand: "".to_string(), + entry: |_| {}, + } + } +} + +pub struct CliModuleArgs { + pub config_store: Option<Box<dyn ConfigStore>>, + pub match_store: Option<Box<dyn MatchStore>>, + pub is_legacy_config: bool, + pub paths: Option<Paths>, + pub cli_args: Option<ArgMatches<'static>>, +} + +impl Default for CliModuleArgs { + fn default() -> Self { + Self { + config_store: None, + match_store: None, + is_legacy_config: false, + paths: None, + cli_args: None, + } + } +} diff --git a/espanso/src/cli/path.rs b/espanso/src/cli/path.rs new file mode 100644 index 0000000..e5a276b --- /dev/null +++ b/espanso/src/cli/path.rs @@ -0,0 +1,59 @@ +/* + * 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 super::{CliModule, CliModuleArgs}; + +pub fn new() -> CliModule { + CliModule { + requires_paths: true, + requires_config: true, + subcommand: "path".to_string(), + entry: path_main, + ..Default::default() + } +} + +fn path_main(args: CliModuleArgs) { + let paths = args.paths.expect("missing paths argument"); + let cli_args = args.cli_args.expect("missing cli_args argument"); + + if cli_args.subcommand_matches("config").is_some() { + println!("{}", paths.config.to_string_lossy()); + } else if cli_args.subcommand_matches("packages").is_some() { + println!("{}", paths.packages.to_string_lossy()); + } else if cli_args.subcommand_matches("data").is_some() || cli_args.subcommand_matches("runtime").is_some() { + println!("{}", paths.runtime.to_string_lossy()); + } else if cli_args.subcommand_matches("default").is_some() { + if args.is_legacy_config { + println!("{}", paths.config.join("default.yml").to_string_lossy()); + } else { + println!("{}", paths.config.join("config").join("default.yml").to_string_lossy()); + } + } else if cli_args.subcommand_matches("base").is_some() { + if args.is_legacy_config { + eprintln!("base config not available when using legacy configuration format"); + } else { + println!("{}", paths.config.join("match").join("base.yml").to_string_lossy()); + } + } else { + println!("Config: {}", paths.config.to_string_lossy()); + println!("Packages: {}", paths.packages.to_string_lossy()); + println!("Runtime: {}", paths.runtime.to_string_lossy()); + } +} diff --git a/espanso/src/logging/mod.rs b/espanso/src/logging/mod.rs new file mode 100644 index 0000000..ff3c52d --- /dev/null +++ b/espanso/src/logging/mod.rs @@ -0,0 +1,89 @@ +/* + * 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 anyhow::Result; +use std::{ + fs::{File, OpenOptions}, + path::Path, +}; +use std::{ + io::Write, + sync::{Arc, Mutex}, +}; + +/// This struct can be passed as an output to the logger to "defer" the +/// decision of the output file +#[derive(Clone)] +pub(crate) struct FileProxy { + output: Arc<Mutex<Option<File>>>, +} + +impl FileProxy { + pub fn new() -> Self { + Self { + output: Arc::new(Mutex::new(None)), + } + } + + pub fn set_output_file(&self, path: &Path) -> Result<()> { + let log_file = OpenOptions::new() + .read(true) + .write(true) + .create(true) + .append(true) + .open(path)?; + let mut lock = self.output.lock().expect("unable to obtain FileProxy lock"); + *lock = Some(log_file); + Ok(()) + } +} + +impl Write for FileProxy { + fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> { + match self.output.lock() { + Ok(lock) => { + if let Some(mut output) = lock.as_ref() { + output.write(buf) + } else { + Ok(0) + } + } + Err(_) => Err(std::io::Error::new( + std::io::ErrorKind::Other, + "lock poison error", + )), + } + } + + fn flush(&mut self) -> std::io::Result<()> { + match self.output.lock() { + Ok(lock) => { + if let Some(mut output) = lock.as_ref() { + output.flush() + } else { + Ok(()) + } + } + Err(_) => Err(std::io::Error::new( + std::io::ErrorKind::Other, + "lock poison error", + )), + } + } +} diff --git a/espanso/src/main.rs b/espanso/src/main.rs index 7e8ccb9..cc5048c 100644 --- a/espanso/src/main.rs +++ b/espanso/src/main.rs @@ -1,144 +1,264 @@ -use std::{path::PathBuf, time::Duration}; +/* + * 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 espanso_detect::{ - event::{InputEvent, Status}, - get_source, - hotkey::HotKey, - SourceCreationOptions, -}; -use espanso_inject::{get_injector, keys, Injector}; -use espanso_ui::{event::UIEvent::*, icons::TrayIcon, menu::*}; -use simplelog::{CombinedLogger, Config, LevelFilter, TermLogger, TerminalMode}; +#[macro_use] +extern crate lazy_static; + +use clap::{App, AppSettings, Arg, SubCommand}; +use cli::{CliModule, CliModuleArgs}; +use logging::FileProxy; +use simplelog::{CombinedLogger, Config, LevelFilter, TermLogger, TerminalMode, WriteLogger}; + +mod cli; +mod engine; +mod logging; +mod util; + +const VERSION: &str = env!("CARGO_PKG_VERSION"); +const LOG_FILE_NAME: &str = "espanso.log"; + +lazy_static! { + static ref CLI_HANDLERS: Vec<CliModule> = vec![ + cli::path::new(), + ]; +} fn main() { - println!("Hello, world!z"); + // TODO: attach console - CombinedLogger::init(vec![ - TermLogger::new(LevelFilter::Debug, Config::default(), TerminalMode::Mixed), - // WriteLogger::new( - // LevelFilter::Info, - // Config::default(), - // File::create("my_rust_binary.log").unwrap(), - // ), - ]) - .unwrap(); - - let paths = espanso_path::resolve_paths(); - println!("paths: {:?}", paths); - let config = espanso_config::load_legacy(&paths.config, &paths.packages).unwrap(); + let install_subcommand = SubCommand::with_name("install") + .about("Install a package. Equivalent to 'espanso package install'") + .arg( + Arg::with_name("external") + .short("e") + .long("external") + .required(false) + .takes_value(false) + .help("Allow installing packages from non-verified repositories."), + ) + .arg(Arg::with_name("package_name").help("Package name")) + .arg( + Arg::with_name("repository_url") + .help("(Optional) Link to GitHub repository") + .required(false) + .default_value("hub"), + ) + .arg( + Arg::with_name("proxy") + .help("Use a proxy, should be used as --proxy=https://proxy:1234") + .required(false) + .long("proxy") + .takes_value(true), + ); - // let icon_paths = vec![ - // ( - // espanso_ui::icons::TrayIcon::Normal, - // r"C:\Users\Freddy\AppData\Local\espanso\espanso.ico".to_string(), - // ), - // ( - // espanso_ui::icons::TrayIcon::Disabled, - // r"C:\Users\Freddy\AppData\Local\espanso\espansored.ico".to_string(), - // ), - // ]; - let icon_paths = vec![ - ( - espanso_ui::icons::TrayIcon::Normal, - r"/Users/freddy/Library/Application Support/espanso/icon.png".to_string(), - ), - ( - espanso_ui::icons::TrayIcon::Disabled, - r"/Users/freddy/Library/Application Support/espanso/icondisabled.png".to_string(), - ), - ]; + let uninstall_subcommand = SubCommand::with_name("uninstall") + .about("Remove an installed package. Equivalent to 'espanso package uninstall'") + .arg(Arg::with_name("package_name").help("Package name")); - // let (remote, mut eventloop) = espanso_ui::win32::create(espanso_ui::win32::Win32UIOptions { - // show_icon: true, - // icon_paths: &icon_paths, - // notification_icon_path: r"C:\Users\Freddy\Insync\Development\Espanso\Images\icongreensmall.png" - // .to_string(), - // }); - // let (remote, mut eventloop) = espanso_ui::mac::create(espanso_ui::mac::MacUIOptions { - // show_icon: true, - // icon_paths: &icon_paths, - // }); - let (remote, mut eventloop) = espanso_ui::create_ui(espanso_ui::UIOptions { - notification_icon_path: Some( - r"C:\Users\Freddy\Insync\Development\Espanso\Images\icongreensmall.png".to_string(), - ), - ..Default::default() - }) - .unwrap(); + let mut clap_instance = App::new("espanso") + .version(VERSION) + .author("Federico Terzi") + .about("A Privacy-first, Cross-platform Text Expander") + .arg(Arg::with_name("v") + .short("v") + .multiple(true) + .help("Sets the level of verbosity")) + .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("edit") + .about("Open the default text editor to edit config files and reload them automatically when exiting") + .arg(Arg::with_name("config") + .help("Defaults to \"default\". The configuration file name to edit (without the .yml extension).")) + .arg(Arg::with_name("norestart") + .short("n") + .long("norestart") + .required(false) + .takes_value(false) + .help("Avoid restarting espanso after editing the file")) + ) + .subcommand(SubCommand::with_name("detect") + .about("Tool to detect current window properties, to simplify filters creation.")) + .subcommand(SubCommand::with_name("daemon") + .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("log") + .about("Print the latest daemon logs.")) + .subcommand(SubCommand::with_name("start") + .about("Start the daemon spawning a new process in the background.")) + .subcommand(SubCommand::with_name("stop") + .about("Stop the espanso daemon.")) + .subcommand(SubCommand::with_name("restart") + .about("Restart the espanso daemon.")) + .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.") + .subcommand(SubCommand::with_name("config") + .about("Print the current config folder path.")) + .subcommand(SubCommand::with_name("packages") + .about("Print the current packages folder path.")) + .subcommand(SubCommand::with_name("data") + .about("Print the current data folder path.") + .setting(AppSettings::Hidden)) // Legacy path + .subcommand(SubCommand::with_name("runtime") + .about("Print the current runtime folder path.")) + .subcommand(SubCommand::with_name("default") + .about("Print the default configuration file path.")) + .subcommand(SubCommand::with_name("base") + .about("Print the default match file path.")) + ) + .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") + ) + ) + ) + // Package manager + .subcommand(SubCommand::with_name("package") + .about("Espanso package manager commands") + .subcommand(install_subcommand.clone()) + .subcommand(uninstall_subcommand.clone()) + .subcommand(SubCommand::with_name("list") + .about("List all installed packages") + .arg(Arg::with_name("full") + .help("Print all package info") + .long("full"))) - eventloop.initialize().unwrap(); + .subcommand(SubCommand::with_name("refresh") + .about("Update espanso package index")) + ) + .subcommand(SubCommand::with_name("worker") + .setting(AppSettings::Hidden) + .arg(Arg::with_name("reload") + .short("r") + .long("reload") + .required(false) + .takes_value(false)) + ) + .subcommand(install_subcommand) + .subcommand(uninstall_subcommand); - let handle = std::thread::spawn(move || { - let injector = get_injector(Default::default()).unwrap(); - let mut source = get_source(SourceCreationOptions { - //use_evdev: true, - hotkeys: vec![ - HotKey::new(1, "CTRL+SPACE").unwrap(), - //HotKey::new(1, "OPTION+SPACE").unwrap(), - HotKey::new(2, "CTRL+OPTION+3").unwrap(), - ], - ..Default::default() - }) - .unwrap(); - let clipboard = espanso_clipboard::get_clipboard(Default::default()).unwrap(); - let provider = espanso_info::get_provider().unwrap(); - source.initialize().unwrap(); - source - .eventloop(Box::new(move |event: InputEvent| { - println!("ev {:?}", event); - match event { - InputEvent::Mouse(_) => {} - InputEvent::Keyboard(evt) => { - if evt.key == espanso_detect::event::Key::Escape && evt.status == Status::Released { - //remote.update_tray_icon(espanso_ui::icons::TrayIcon::Disabled); - //remote.show_notification("Espanso is running!"); - injector - .send_string("Hey guys! @", Default::default()) - .expect("error"); - //std::thread::sleep(std::time::Duration::from_secs(2)); - //injector.send_key_combination(&[keys::Key::Control, keys::Key::V], Default::default()).unwrap(); - } - if evt.key == espanso_detect::event::Key::Shift && evt.status == Status::Released { - println!("info {:?}", provider.get_info()); - } - } - InputEvent::HotKey(hotkey) => { - if hotkey.hotkey_id == 2 { - println!("clip {:?}", clipboard.get_text()); - } else if hotkey.hotkey_id == 1 { - //clipboard.set_text("test text").unwrap(); - clipboard.set_html("<i>test text</i>", Some("test text fallback")).unwrap(); - //clipboard.set_image(&PathBuf::from(r"C:\Users\Freddy\Insync\Development\Espanso\Images\icongreen.png")).unwrap(); - } - } - } - })) - .unwrap(); - }); + // TODO: explain that the start and restart commands are only meaningful + // when using the system daemon manager on macOS and Linux - eventloop.run(Box::new(move |event| { - println!("ui {:?}", event); - let menu = Menu::from(vec![ - MenuItem::Simple(SimpleMenuItem::new("open", "Open")), - MenuItem::Separator, - MenuItem::Sub(SubMenuItem::new( - "Sub", - vec![ - MenuItem::Simple(SimpleMenuItem::new("sub1", "Sub 1")), - MenuItem::Simple(SimpleMenuItem::new("sub2", "Sub 2")), - ], - )), - ]) - .unwrap(); - match event { - TrayIconClick => { - remote.show_context_menu(&menu); - } - ContextMenuClick(raw_id) => { - //remote.update_tray_icon(TrayIcon::Disabled); - remote.show_notification("Hello there!"); - println!("item {:?}", menu.get_item_id(raw_id)); - } + let matches = clap_instance.clone().get_matches(); + let log_level = match matches.occurrences_of("v") { + 0 => LevelFilter::Warn, + 1 => LevelFilter::Info, + _ => LevelFilter::Debug, + }; + + let handler = CLI_HANDLERS + .iter() + .find(|cli| matches.subcommand_matches(&cli.subcommand).is_some()); + + if let Some(handler) = handler { + let log_proxy = FileProxy::new(); + if handler.enable_logs { + CombinedLogger::init(vec![ + TermLogger::new(log_level, Config::default(), TerminalMode::Mixed), + WriteLogger::new(log_level, Config::default(), log_proxy.clone()), + ]) + .expect("unable to initialize logs"); } - })); -} + + let mut cli_args: CliModuleArgs = CliModuleArgs::default(); + + if handler.requires_paths || handler.requires_config { + // TODO: here take into account env variable and/or command line flag + let paths = espanso_path::resolve_paths(); + + if handler.requires_config { + let (config_store, match_store, is_legacy_config) = + if espanso_config::is_legacy_config(&paths.config) { + let (config_store, match_store) = + espanso_config::load_legacy(&paths.config, &paths.packages) + .expect("unable to load legacy config"); + (config_store, match_store, true) + } else { + let (config_store, match_store) = + espanso_config::load(&paths.config).expect("unable to load config"); + (config_store, match_store, false) + }; + + cli_args.is_legacy_config = is_legacy_config; + cli_args.config_store = Some(config_store); + cli_args.match_store = Some(match_store); + } + + if handler.enable_logs { + log_proxy + .set_output_file(&paths.runtime.join(LOG_FILE_NAME)) + .expect("unable to set up log output file"); + } + + cli_args.paths = Some(paths); + } + + if let Some(args) = matches.subcommand_matches(&handler.subcommand) { + cli_args.cli_args = Some(args.clone()); + } + + (handler.entry)(cli_args) + } else { + clap_instance + .print_long_help() + .expect("unable to print help"); + println!(); + } +} \ No newline at end of file diff --git a/espanso/src/main_old2.rs b/espanso/src/main_old2.rs deleted file mode 100644 index e51724e..0000000 --- a/espanso/src/main_old2.rs +++ /dev/null @@ -1,75 +0,0 @@ -use espanso_detect::event::{InputEvent, Status}; -use espanso_ui::{linux::LinuxUIOptions, menu::*}; -use simplelog::{CombinedLogger, Config, LevelFilter, TermLogger, TerminalMode}; - -fn main() { - println!("Hello, world!z"); - CombinedLogger::init(vec![ - TermLogger::new(LevelFilter::Debug, Config::default(), TerminalMode::Mixed), - // WriteLogger::new( - // LevelFilter::Info, - // Config::default(), - // File::create("my_rust_binary.log").unwrap(), - // ), - ]) - .unwrap(); - - let icon_paths = vec![ - ( - espanso_ui::icons::TrayIcon::Normal, - r"C:\Users\Freddy\AppData\Local\espanso\espanso.ico".to_string(), - ), - ( - espanso_ui::icons::TrayIcon::Disabled, - r"C:\Users\Freddy\AppData\Local\espanso\espansored.ico".to_string(), - ), - ]; - - - // let (remote, mut eventloop) = espanso_ui::win32::create(espanso_ui::win32::Win32UIOptions { - // show_icon: true, - // icon_paths: &icon_paths, - // notification_icon_path: r"C:\Users\Freddy\Insync\Development\Espanso\Images\icongreensmall.png" - // .to_string(), - // }); - let (remote, mut eventloop) = espanso_ui::linux::create(LinuxUIOptions { - notification_icon_path: r"/home/freddy/insync/Development/Espanso/Images/icongreensmall.png".to_owned(), - }); - - let handle = std::thread::spawn(move || { - //let mut source = espanso_detect::win32::Win32Source::new(); - let mut source = espanso_detect::evdev::EVDEVSource::new(); - source.initialize(); - source.eventloop(Box::new(move |event: InputEvent| { - println!("ev {:?}", event); - match event { - InputEvent::Mouse(_) => {} - InputEvent::Keyboard(evt) => { - if evt.key == espanso_detect::event::Key::Shift && evt.status == Status::Pressed { - //remote.update_tray_icon(espanso_ui::icons::TrayIcon::Disabled); - remote.show_notification("Espanso is running!"); - } - } - } - })); - }); - - // eventloop.initialize(); - // eventloop.run(Box::new(move |event| { - // println!("ui {:?}", event); - // let menu = Menu::from(vec![ - // MenuItem::Simple(SimpleMenuItem::new("open", "Open")), - // MenuItem::Separator, - // MenuItem::Sub(SubMenuItem::new( - // "Sub", - // vec![ - // MenuItem::Simple(SimpleMenuItem::new("sub1", "Sub 1")), - // MenuItem::Simple(SimpleMenuItem::new("sub2", "Sub 2")), - // ], - // )), - // ]) - // .unwrap(); - // remote.show_context_menu(&menu); - // })) - eventloop.run(); -}