diff --git a/Cargo.lock b/Cargo.lock
index a6ff414..8963d5b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -427,6 +427,7 @@ dependencies = [
"espanso-info",
"espanso-inject",
"espanso-ipc",
+ "espanso-kvs",
"espanso-mac-utils",
"espanso-match",
"espanso-migrate",
@@ -549,6 +550,18 @@ dependencies = [
"thiserror",
]
+[[package]]
+name = "espanso-kvs"
+version = "0.1.0"
+dependencies = [
+ "anyhow",
+ "log",
+ "serde",
+ "serde_json",
+ "tempdir",
+ "thiserror",
+]
+
[[package]]
name = "espanso-mac-utils"
version = "0.1.0"
diff --git a/Cargo.toml b/Cargo.toml
index f3a1639..426c234 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -15,4 +15,5 @@ members = [
"espanso-modulo",
"espanso-migrate",
"espanso-mac-utils",
+ "espanso-kvs",
]
\ No newline at end of file
diff --git a/Makefile.toml b/Makefile.toml
index 32e55db..bb19e44 100644
--- a/Makefile.toml
+++ b/Makefile.toml
@@ -34,8 +34,8 @@ dependencies=["create-bundle"]
[tasks.test]
command = "cargo"
-args = ["test", "--workspace", "--exclude", "espanso-modulo", "--no-default-features"]
+args = ["test", "--workspace", "--exclude", "espanso-modulo", "--exclude", "espanso-ipc", "--no-default-features"]
[tasks.test-output]
command = "cargo"
-args = ["test", "--workspace", "--exclude", "espanso-modulo", "--no-default-features", "--", "--nocapture"]
\ No newline at end of file
+args = ["test", "--workspace", "--exclude", "espanso-modulo", "--exclude", "espanso-ipc", "--no-default-features", "--", "--nocapture"]
\ No newline at end of file
diff --git a/espanso/Cargo.toml b/espanso/Cargo.toml
index a12194c..daf7be1 100644
--- a/espanso/Cargo.toml
+++ b/espanso/Cargo.toml
@@ -32,6 +32,7 @@ espanso-path = { path = "../espanso-path" }
espanso-ipc = { path = "../espanso-ipc" }
espanso-modulo = { path = "../espanso-modulo", optional = true }
espanso-migrate = { path = "../espanso-migrate" }
+espanso-kvs = { path = "../espanso-kvs" }
maplit = "1.0.2"
simplelog = "0.9.0"
log = "0.4.14"
diff --git a/espanso/src/cli/launcher/mod.rs b/espanso/src/cli/launcher/mod.rs
index 540efc3..882c342 100644
--- a/espanso/src/cli/launcher/mod.rs
+++ b/espanso/src/cli/launcher/mod.rs
@@ -17,9 +17,8 @@
* along with espanso. If not, see .
*/
-use espanso_modulo::wizard::{MigrationResult, WizardHandlers, WizardOptions};
-
use self::util::MigrationError;
+use crate::preferences::Preferences;
use super::{CliModule, CliModuleArgs};
@@ -41,10 +40,19 @@ pub fn new() -> CliModule {
#[cfg(feature = "modulo")]
fn launcher_main(args: CliModuleArgs) -> i32 {
+ use espanso_modulo::wizard::{MigrationResult, WizardHandlers, WizardOptions};
+
+ // TODO: should we create a non-gui wizard? We can also use it for the non-modulo versions of espanso
+
let paths = args.paths.expect("missing paths in launcher main");
let icon_paths = crate::icon::load_icon_paths(&paths.runtime).expect("unable to load icon paths");
- // TODO: should move wizard to "init" subcommand?
+ let preferences =
+ crate::preferences::get_default(&paths.runtime).expect("unable to initialize preferences");
+
+ let is_welcome_page_enabled = !preferences.has_completed_wizard();
+
+ let is_move_bundle_page_enabled = false; // TODO
let is_legacy_version_page_enabled = util::is_legacy_version_running(&paths.runtime);
let runtime_dir_clone = paths.runtime.clone();
@@ -55,26 +63,20 @@ fn launcher_main(args: CliModuleArgs) -> i32 {
let paths_clone = paths.clone();
let backup_and_migrate_handler =
Box::new(move || match util::migrate_configuration(&paths_clone) {
- Ok(_) => {
- MigrationResult::Success
- }
- Err(error) => {
- match error.downcast_ref::() {
- Some(MigrationError::DirtyError) => {
- MigrationResult::DirtyFailure
- }
- Some(MigrationError::CleanError) => {
- MigrationResult::CleanFailure
- }
- _ => {
- MigrationResult::UnknownFailure
- }
- }
- }
+ Ok(_) => MigrationResult::Success,
+ Err(error) => match error.downcast_ref::() {
+ Some(MigrationError::DirtyError) => MigrationResult::DirtyFailure,
+ Some(MigrationError::CleanError) => MigrationResult::CleanFailure,
+ _ => MigrationResult::UnknownFailure,
+ },
});
+ // TODO: enable "Add to PATH" page only when NOT in portable mode
+ // TODO: if the user clicks on "Continue" after unchecking the "ADD to PATH"
+ // checkbox, we should remember (with the kvs) the choice and avoid asking again.
let is_add_path_page_enabled = if cfg!(target_os = "macos") {
// TODO: add actual check
+ // TODO: consider also Windows case
true
} else {
false
@@ -87,39 +89,46 @@ fn launcher_main(args: CliModuleArgs) -> i32 {
false
};
- // TODO: show welcome page only the first time (we need a persistent key-value store)
// TODO: show a "espanso is now running page at the end" (it should be triggered everytime
// espanso is started, unless the user unchecks "show this message at startup")
// This page could also be used when the user starts espanso, but an instance is already running.
- espanso_modulo::wizard::show(WizardOptions {
- version: crate::VERSION.to_string(),
- is_welcome_page_enabled: true, // TODO
- is_move_bundle_page_enabled: false, // TODO
- is_legacy_version_page_enabled,
- is_migrate_page_enabled,
- is_add_path_page_enabled,
- is_accessibility_page_enabled,
- window_icon_path: icon_paths
- .wizard_icon
- .map(|path| path.to_string_lossy().to_string()),
- welcome_image_path: icon_paths
- .logo_no_background
- .map(|path| path.to_string_lossy().to_string()),
- accessibility_image_1_path: None, // TODO
- accessibility_image_2_path: None, // TODO
- handlers: WizardHandlers {
- is_legacy_version_running: Some(is_legacy_version_running_handler),
- backup_and_migrate: Some(backup_and_migrate_handler),
- add_to_path: None, // TODO
- enable_accessibility: None, // TODO
- is_accessibility_enabled: None, // TODO
- },
- });
+ // Only show the wizard if a panel should be displayed
+ if is_welcome_page_enabled
+ || is_move_bundle_page_enabled
+ || is_legacy_version_page_enabled
+ || is_migrate_page_enabled
+ || is_add_path_page_enabled
+ || is_accessibility_page_enabled
+ {
+ espanso_modulo::wizard::show(WizardOptions {
+ version: crate::VERSION.to_string(),
+ is_welcome_page_enabled,
+ is_move_bundle_page_enabled,
+ is_legacy_version_page_enabled,
+ is_migrate_page_enabled,
+ is_add_path_page_enabled,
+ is_accessibility_page_enabled,
+ window_icon_path: icon_paths
+ .wizard_icon
+ .map(|path| path.to_string_lossy().to_string()),
+ welcome_image_path: icon_paths
+ .logo_no_background
+ .map(|path| path.to_string_lossy().to_string()),
+ accessibility_image_1_path: None, // TODO
+ accessibility_image_2_path: None, // TODO
+ handlers: WizardHandlers {
+ is_legacy_version_running: Some(is_legacy_version_running_handler),
+ backup_and_migrate: Some(backup_and_migrate_handler),
+ add_to_path: None, // TODO
+ enable_accessibility: None, // TODO
+ is_accessibility_enabled: None, // TODO
+ },
+ });
- // TODO: enable "Add to PATH" page only when NOT in portable mode
- // TODO: if the user clicks on "Continue" after unchecking the "ADD to PATH"
- // checkbox, we should remember (with the kvs) the choice and avoid asking again.
+ // TODO: check the wizard return status?
+ preferences.set_completed_wizard(true);
+ }
0
}
@@ -127,4 +136,6 @@ fn launcher_main(args: CliModuleArgs) -> i32 {
#[cfg(not(feature = "modulo"))]
fn launcher_main(_: CliModuleArgs) -> i32 {
// TODO: handle what happens here
+
+ 0
}
diff --git a/espanso/src/main.rs b/espanso/src/main.rs
index a36204c..efd9ac0 100644
--- a/espanso/src/main.rs
+++ b/espanso/src/main.rs
@@ -43,6 +43,7 @@ mod icon;
mod ipc;
mod lock;
mod logging;
+mod preferences;
mod util;
const VERSION: &str = env!("CARGO_PKG_VERSION");
@@ -289,6 +290,10 @@ fn main() {
// TODO: explain that the register and unregister commands are only meaningful
// when using the system daemon manager on macOS and Linux
+ // TODO: set the LSEnvironment variable as described here: https://stackoverflow.com/questions/12203377/combined-gui-and-command-line-os-x-app?rq=1
+ // to detect if the executable was launched inside an AppBundle, and if so, launch the "launcher" handler
+ // This should only apply when on macOS.
+
let matches = clap_instance.clone().get_matches();
let log_level = match matches.occurrences_of("v") {
0 | 1 => LevelFilter::Info,
diff --git a/espanso/src/preferences/default.rs b/espanso/src/preferences/default.rs
new file mode 100644
index 0000000..f58da01
--- /dev/null
+++ b/espanso/src/preferences/default.rs
@@ -0,0 +1,64 @@
+/*
+ * 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 espanso_kvs::KVS;
+use serde::{de::DeserializeOwned, Serialize};
+use std::path::Path;
+
+use anyhow::Result;
+
+use super::Preferences;
+
+const HAS_COMPLETED_WIZARD_KEY: &str = "has_completed_wizard";
+
+#[derive(Clone)]
+pub struct DefaultPreferences {
+ kvs: KVSType,
+}
+
+impl DefaultPreferences {
+ pub fn new(runtime_dir: &Path, kvs: KVSType) -> Result {
+ Ok(Self { kvs })
+ }
+
+ fn get(&self, key: &str) -> Option {
+ let value = self
+ .kvs
+ .get(key)
+ .expect(&format!("unable to read preference for key {}", key));
+ value
+ }
+
+ fn set(&self, key: &str, value: T) {
+ self
+ .kvs
+ .set(key, value)
+ .expect(&format!("unable to write preference for key {}", key))
+ }
+}
+
+impl Preferences for DefaultPreferences {
+ fn has_completed_wizard(&self) -> bool {
+ self.get(HAS_COMPLETED_WIZARD_KEY).unwrap_or(false)
+ }
+
+ fn set_completed_wizard(&self, value: bool) {
+ self.set(HAS_COMPLETED_WIZARD_KEY, value);
+ }
+}
diff --git a/espanso/src/preferences/mod.rs b/espanso/src/preferences/mod.rs
new file mode 100644
index 0000000..a83c57f
--- /dev/null
+++ b/espanso/src/preferences/mod.rs
@@ -0,0 +1,33 @@
+/*
+ * 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 anyhow::Result;
+
+mod default;
+
+pub trait Preferences: Send + Sync {
+ fn has_completed_wizard(&self) -> bool;
+ fn set_completed_wizard(&self, value: bool);
+}
+
+pub fn get_default(runtime_dir: &Path) -> Result {
+ let kvs = espanso_kvs::get_persistent(runtime_dir)?;
+ default::DefaultPreferences::new(runtime_dir, kvs)
+}
\ No newline at end of file