Add edit subcommand. Fix #171
This commit is contained in:
parent
a89438f3ba
commit
3e98748c54
|
@ -38,7 +38,7 @@ pub(crate) mod runtime;
|
||||||
const DEFAULT_CONFIG_FILE_CONTENT : &str = include_str!("../res/config.yml");
|
const DEFAULT_CONFIG_FILE_CONTENT : &str = include_str!("../res/config.yml");
|
||||||
|
|
||||||
pub const DEFAULT_CONFIG_FILE_NAME : &str = "default.yml";
|
pub const DEFAULT_CONFIG_FILE_NAME : &str = "default.yml";
|
||||||
const USER_CONFIGS_FOLDER_NAME: &str = "user";
|
pub const USER_CONFIGS_FOLDER_NAME: &str = "user";
|
||||||
|
|
||||||
// Default values for primitives
|
// Default values for primitives
|
||||||
fn default_name() -> String{ "default".to_owned() }
|
fn default_name() -> String{ "default".to_owned() }
|
||||||
|
@ -68,9 +68,16 @@ fn default_exclude_default_entries() -> bool {false}
|
||||||
fn default_matches() -> Vec<Match> { Vec::new() }
|
fn default_matches() -> Vec<Match> { Vec::new() }
|
||||||
fn default_global_vars() -> Vec<MatchVariable> { Vec::new() }
|
fn default_global_vars() -> Vec<MatchVariable> { Vec::new() }
|
||||||
|
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
fn default_editor() -> String{ "/bin/nano".to_owned() }
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
fn default_editor() -> String{ "/usr/bin/nano".to_owned() } // TODO: change
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
fn default_editor() -> String{ "C:\\Windows\\System32\\notepad.exe".to_owned() }
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
pub struct Configs {
|
pub struct Configs {
|
||||||
#[serde(default = "default_name")]
|
#[serde(default = "default_name")]
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
|
||||||
#[serde(default = "default_parent")]
|
#[serde(default = "default_parent")]
|
||||||
|
@ -148,6 +155,9 @@ pub struct Configs {
|
||||||
#[serde(default = "default_exclude_default_entries")]
|
#[serde(default = "default_exclude_default_entries")]
|
||||||
pub exclude_default_entries: bool,
|
pub exclude_default_entries: bool,
|
||||||
|
|
||||||
|
#[serde(default = "default_editor")]
|
||||||
|
pub editor: String,
|
||||||
|
|
||||||
#[serde(default = "default_matches")]
|
#[serde(default = "default_matches")]
|
||||||
pub matches: Vec<Match>,
|
pub matches: Vec<Match>,
|
||||||
|
|
||||||
|
|
48
src/edit.rs
48
src/edit.rs
|
@ -18,44 +18,40 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use crate::config::ConfigSet;
|
use crate::config::ConfigSet;
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
pub fn open_editor(config: &ConfigSet, file_path: &Path) -> bool {
|
||||||
pub fn open_editor(config: &ConfigSet) -> bool {
|
|
||||||
// TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
pub fn open_editor(config: &ConfigSet) -> bool {
|
|
||||||
// TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
pub fn open_editor(config: &ConfigSet) -> bool {
|
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
||||||
// Get the configuration file path
|
// Check if another editor is defined in the environment variables
|
||||||
let file_path = crate::context::get_config_dir().join(crate::config::DEFAULT_CONFIG_FILE_NAME);
|
let editor_var = std::env::var_os("EDITOR");
|
||||||
|
let visual_var = std::env::var_os("VISUAL");
|
||||||
|
|
||||||
|
// Prioritize the editors specified by the environment variable, otherwise use the config
|
||||||
|
let editor : String = if let Some(editor_var) = editor_var {
|
||||||
|
editor_var.to_string_lossy().to_string()
|
||||||
|
}else if let Some(visual_var) = visual_var {
|
||||||
|
visual_var.to_string_lossy().to_string()
|
||||||
|
}else{
|
||||||
|
config.default.editor.clone()
|
||||||
|
};
|
||||||
|
|
||||||
// Start the editor and wait for its termination
|
// Start the editor and wait for its termination
|
||||||
let status = Command::new("cmd")
|
let status = Command::new(editor)
|
||||||
.arg("/C")
|
|
||||||
.arg("start")
|
|
||||||
.arg("/wait")
|
|
||||||
.arg("C:\\Windows\\System32\\notepad.exe")
|
|
||||||
.arg(file_path)
|
.arg(file_path)
|
||||||
.spawn();
|
.spawn();
|
||||||
|
|
||||||
if let Ok(mut child) = status {
|
if let Ok(mut child) = status {
|
||||||
// Wait for the user to edit the configuration
|
// Wait for the user to edit the configuration
|
||||||
child.wait();
|
let result = child.wait();
|
||||||
|
|
||||||
// TODO: instead of waiting, a file watcher should be started to detect file changes and
|
if let Ok(exit_status) = result {
|
||||||
// after each of them a reload should be issued
|
exit_status.success()
|
||||||
|
}else{
|
||||||
println!("Ok");
|
false
|
||||||
true
|
}
|
||||||
}else{
|
}else{
|
||||||
println!("Error: could not start editor.");
|
println!("Error: could not start editor at: {}", config.default.editor);
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
70
src/main.rs
70
src/main.rs
|
@ -98,7 +98,9 @@ fn main() {
|
||||||
.about("Toggle the status of the espanso replacement engine."))
|
.about("Toggle the status of the espanso replacement engine."))
|
||||||
)
|
)
|
||||||
.subcommand(SubCommand::with_name("edit")
|
.subcommand(SubCommand::with_name("edit")
|
||||||
.about("Open the default text editor to edit config files and reload them automatically when exiting"))
|
.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).")))
|
||||||
.subcommand(SubCommand::with_name("dump")
|
.subcommand(SubCommand::with_name("dump")
|
||||||
.about("Prints all current configuration options."))
|
.about("Prints all current configuration options."))
|
||||||
.subcommand(SubCommand::with_name("detect")
|
.subcommand(SubCommand::with_name("detect")
|
||||||
|
@ -166,8 +168,8 @@ fn main() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if matches.subcommand_matches("edit").is_some() {
|
if let Some(matches) = matches.subcommand_matches("edit") {
|
||||||
edit_main(config_set);
|
edit_main(config_set, matches);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -881,8 +883,66 @@ fn path_main(_config_set: ConfigSet, matches: &ArgMatches) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn edit_main(config_set: ConfigSet) {
|
fn edit_main(config_set: ConfigSet, matches: &ArgMatches) {
|
||||||
crate::edit::open_editor(&config_set);
|
// Determine which is the file to edit
|
||||||
|
let config = matches.value_of("config").unwrap_or("default");
|
||||||
|
|
||||||
|
let config_dir = crate::context::get_config_dir();
|
||||||
|
|
||||||
|
let config_path = match config {
|
||||||
|
"default" => {
|
||||||
|
config_dir.join(crate::config::DEFAULT_CONFIG_FILE_NAME)
|
||||||
|
},
|
||||||
|
name => { // Otherwise, search in the user/ config folder
|
||||||
|
config_dir.join(crate::config::USER_CONFIGS_FOLDER_NAME)
|
||||||
|
.join(name.to_owned() + ".yml")
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
println!("Editing file: {:?}", &config_path);
|
||||||
|
|
||||||
|
// Based on the fact that the file already exists or not, we should detect in different
|
||||||
|
// ways if a reload is needed
|
||||||
|
let should_reload =if config_path.exists() {
|
||||||
|
// Get the last modified date, so that we can detect if the user actually edits the file
|
||||||
|
// before reloading
|
||||||
|
let metadata = std::fs::metadata(&config_path).expect("cannot gather file metadata");
|
||||||
|
let last_modified = metadata.modified().expect("cannot read file last modified date");
|
||||||
|
|
||||||
|
let result = crate::edit::open_editor(&config_set, &config_path);
|
||||||
|
if result {
|
||||||
|
let new_metadata = std::fs::metadata(&config_path).expect("cannot gather file metadata");
|
||||||
|
let new_last_modified = new_metadata.modified().expect("cannot read file last modified date");
|
||||||
|
|
||||||
|
if last_modified != new_last_modified {
|
||||||
|
println!("File has been modified, reloading configuration");
|
||||||
|
true
|
||||||
|
}else{
|
||||||
|
println!("File has not been modified, avoiding reload");
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
let result = crate::edit::open_editor(&config_set, &config_path);
|
||||||
|
if result {
|
||||||
|
// If the file has been created, we should reload the espanso config
|
||||||
|
if config_path.exists() {
|
||||||
|
println!("A new file has been created, reloading configuration");
|
||||||
|
true
|
||||||
|
}else{
|
||||||
|
println!("No file has been created, avoiding reload");
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if should_reload {
|
||||||
|
restart_main(config_set)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn acquire_lock() -> Option<File> {
|
fn acquire_lock() -> Option<File> {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user