diff --git a/.config/config.toml b/.config/config.toml index 1b4e76a..96ef5ea 100644 --- a/.config/config.toml +++ b/.config/config.toml @@ -149,52 +149,30 @@ toggle_preview = "ctrl-o" # E.g. typing `git checkout ` will open television with a list of # branches to choose from. -[shell_integration.commands] -# Add your commands here. Each key is a command that will trigger tv with the -# corresponding channel as value. -# Example: say you want the following prompts to trigger the following channels +[shell_integration.channel_triggers] +# Add your channel triggers here. Each key is a channel that will be triggered +# by the corresponding commands. +# Example: say you want the following commands to trigger the following channels # when pressing : -# `git checkout` should trigger the `git-branches` channel -# `ls` should trigger the `dirs` channel -# `cat` should trigger the `files` channel +# `git checkout` should trigger the `git-branches` channel +# `ls` should trigger the `dirs` channel +# `cat` and `cp` should trigger the `files` channel # # You would add the following to your configuration file: # ``` -# [shell_integration.commands] -# "git checkout" = "git-branch" -# "ls" = "dirs" -# "cat" = "files" +# [shell_integration.channel_triggers] +# "git-branches" = ["git checkout"] +# "dirs" = ["ls"] +# "files" = ["cat", "cp"] # ``` +"env" = ["export", "unset"] +"dirs" = ["cd", "ls", "rmdir"] +"files" = ["cat", "less", "head", "tail", "vim", "bat"] +"git-diff" = ["git add"] +"git-branch" = ["git checkout", "git branch -d"] +"docker-images" = ["docker run"] +"git-repos" = ["nvim"] -# environment variables -"export" = "env" -"unset" = "env" - -# dirs channel -"cd" = "dirs" -"ls" = "dirs" -"rmdir" = "dirs" - -# files channel -"cat" = "files" -"less" = "files" -"head" = "files" -"tail" = "files" -"vim" = "files" -"bat" = "files" - -# git-diff channel -"git add" = "git-diff" - -# git-branch channel -"git checkout" = "git-branch" -"git branch -d" = "git-branch" - -# docker-images channel -"docker run" = "docker-images" - -# gitrepos channel -"nvim" = "git-repos" [shell_integration.keybindings] # controls which key binding should trigger tv @@ -203,4 +181,3 @@ toggle_preview = "ctrl-o" # controls which keybinding should trigger tv # for command history "command_history" = "ctrl-r" - diff --git a/television/config/mod.rs b/television/config/mod.rs index 2b71823..08d8b1a 100644 --- a/television/config/mod.rs +++ b/television/config/mod.rs @@ -89,7 +89,7 @@ impl Config { #[allow(clippy::missing_panics_doc, clippy::missing_errors_doc)] pub fn new() -> Result { // Load the default_config values as base defaults - let default_config: Config = toml::from_str(DEFAULT_CONFIG) + let mut default_config: Config = toml::from_str(DEFAULT_CONFIG) .expect("Error parsing default config"); // initialize the config builder @@ -107,22 +107,35 @@ impl Config { let path = config_dir.join(CONFIG_FILE_NAME); let contents = std::fs::read_to_string(&path)?; - let cfg: Config = toml::from_str(&contents).unwrap_or_else(|e| { + let mut user_cfg: Config = toml::from_str(&contents).unwrap_or_else(|e| { warn!( "Error parsing config file, using default configuration: {}" , e ); default_config.clone() }); + // merge shell integration triggers with commands + default_config.shell_integration.merge_triggers(); + user_cfg.shell_integration.merge_triggers(); + // merge shell integration commands with default commands + let mut merged_commands = + default_config.shell_integration.commands.clone(); + merged_commands + .extend(user_cfg.shell_integration.commands.clone()); + user_cfg.shell_integration.commands = merged_commands; + // merge keybindings with default keybindings let keybindings = merge_keybindings( default_config.keybindings, - &cfg.keybindings, + &user_cfg.keybindings, ); - let cfg = Config { keybindings, ..cfg }; + let final_cfg = Config { + keybindings, + ..user_cfg + }; - debug!("Config: {:?}", cfg); - Ok(cfg) + debug!("Config: {:?}", final_cfg); + Ok(final_cfg) } else { warn!("No config file found at {:?}, creating default configuration file at that location.", config_dir); // create the default configuration file in the user's config directory diff --git a/television/config/shell_integration.rs b/television/config/shell_integration.rs index 0820fca..c12f4db 100644 --- a/television/config/shell_integration.rs +++ b/television/config/shell_integration.rs @@ -2,13 +2,19 @@ use std::hash::Hash; use crate::config::parse_key; use crate::event::Key; +use crate::utils::hashmaps; use rustc_hash::FxHashMap; use serde::Deserialize; #[derive(Clone, Debug, Deserialize, Default, PartialEq)] #[serde(default)] pub struct ShellIntegrationConfig { + /// DEPRECATED: This is a legacy configuration option that is no longer used. + /// It is kept here for backwards compatibility. + /// {command: channel} pub commands: FxHashMap, + /// {channel: [commands]} + pub channel_triggers: FxHashMap>, pub keybindings: FxHashMap, } @@ -19,6 +25,21 @@ impl Hash for ShellIntegrationConfig { } } +impl ShellIntegrationConfig { + /// Merge the channel triggers into the commands hashmap + /// This is done to maintain backwards compatibility with the old configuration + /// format. + /// + /// {command: channel} + {channel: [commands]} => {command: channel} + pub fn merge_triggers(&mut self) { + // invert the hashmap to get {command: channel} + let inverted_triggers = + hashmaps::invert_hashmap(&self.channel_triggers); + // merge the inverted hashmap with the existing commands hashmap + self.commands.extend(inverted_triggers); + } +} + const SMART_AUTOCOMPLETE_CONFIGURATION_KEY: &str = "smart_autocomplete"; const COMMAND_HISTORY_CONFIGURATION_KEY: &str = "command_history"; const DEFAULT_SHELL_AUTOCOMPLETE_KEY: char = 'T'; diff --git a/television/utils/hashmaps.rs b/television/utils/hashmaps.rs new file mode 100644 index 0000000..dce7932 --- /dev/null +++ b/television/utils/hashmaps.rs @@ -0,0 +1,19 @@ +use std::collections::HashMap; +use std::hash::Hash; + +pub fn invert_hashmap( + hashmap: &HashMap, +) -> HashMap +where + K: Eq + Hash + Clone, + V: Eq + Hash + Clone + IntoIterator, + I: Eq + Hash + Clone, +{ + let mut inverted = HashMap::new(); + for (key, values) in hashmap { + for value in values.clone() { + inverted.insert(value, key.clone()); + } + } + inverted +} diff --git a/television/utils/mod.rs b/television/utils/mod.rs index 8328621..80fa27a 100644 --- a/television/utils/mod.rs +++ b/television/utils/mod.rs @@ -1,6 +1,7 @@ pub mod cache; pub mod command; pub mod files; +pub mod hashmaps; pub mod indices; pub mod input; pub mod metadata;