mirror of
https://github.com/alexpasmantier/television.git
synced 2025-06-07 03:55:23 +00:00
refactor(shell): improve shell integration configuration syntax
This commit is contained in:
parent
c74b47d07c
commit
d3725f2cc3
@ -149,52 +149,30 @@ toggle_preview = "ctrl-o"
|
|||||||
# E.g. typing `git checkout <CTRL-T>` will open television with a list of
|
# E.g. typing `git checkout <CTRL-T>` will open television with a list of
|
||||||
# branches to choose from.
|
# branches to choose from.
|
||||||
|
|
||||||
[shell_integration.commands]
|
[shell_integration.channel_triggers]
|
||||||
# Add your commands here. Each key is a command that will trigger tv with the
|
# Add your channel triggers here. Each key is a channel that will be triggered
|
||||||
# corresponding channel as value.
|
# by the corresponding commands.
|
||||||
# Example: say you want the following prompts to trigger the following channels
|
# Example: say you want the following commands to trigger the following channels
|
||||||
# when pressing <CTRL-T>:
|
# when pressing <CTRL-T>:
|
||||||
# `git checkout` should trigger the `git-branches` channel
|
# `git checkout` should trigger the `git-branches` channel
|
||||||
# `ls` should trigger the `dirs` channel
|
# `ls` should trigger the `dirs` channel
|
||||||
# `cat` should trigger the `files` channel
|
# `cat` and `cp` should trigger the `files` channel
|
||||||
#
|
#
|
||||||
# You would add the following to your configuration file:
|
# You would add the following to your configuration file:
|
||||||
# ```
|
# ```
|
||||||
# [shell_integration.commands]
|
# [shell_integration.channel_triggers]
|
||||||
# "git checkout" = "git-branch"
|
# "git-branches" = ["git checkout"]
|
||||||
# "ls" = "dirs"
|
# "dirs" = ["ls"]
|
||||||
# "cat" = "files"
|
# "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]
|
[shell_integration.keybindings]
|
||||||
# controls which key binding should trigger tv
|
# controls which key binding should trigger tv
|
||||||
@ -203,4 +181,3 @@ toggle_preview = "ctrl-o"
|
|||||||
# controls which keybinding should trigger tv
|
# controls which keybinding should trigger tv
|
||||||
# for command history
|
# for command history
|
||||||
"command_history" = "ctrl-r"
|
"command_history" = "ctrl-r"
|
||||||
|
|
||||||
|
@ -89,7 +89,7 @@ impl Config {
|
|||||||
#[allow(clippy::missing_panics_doc, clippy::missing_errors_doc)]
|
#[allow(clippy::missing_panics_doc, clippy::missing_errors_doc)]
|
||||||
pub fn new() -> Result<Self> {
|
pub fn new() -> Result<Self> {
|
||||||
// Load the default_config values as base defaults
|
// 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");
|
.expect("Error parsing default config");
|
||||||
|
|
||||||
// initialize the config builder
|
// initialize the config builder
|
||||||
@ -107,22 +107,35 @@ impl Config {
|
|||||||
let path = config_dir.join(CONFIG_FILE_NAME);
|
let path = config_dir.join(CONFIG_FILE_NAME);
|
||||||
let contents = std::fs::read_to_string(&path)?;
|
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!(
|
warn!(
|
||||||
"Error parsing config file, using default configuration: {}" , e
|
"Error parsing config file, using default configuration: {}" , e
|
||||||
);
|
);
|
||||||
default_config.clone()
|
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
|
// merge keybindings with default keybindings
|
||||||
let keybindings = merge_keybindings(
|
let keybindings = merge_keybindings(
|
||||||
default_config.keybindings,
|
default_config.keybindings,
|
||||||
&cfg.keybindings,
|
&user_cfg.keybindings,
|
||||||
);
|
);
|
||||||
let cfg = Config { keybindings, ..cfg };
|
let final_cfg = Config {
|
||||||
|
keybindings,
|
||||||
|
..user_cfg
|
||||||
|
};
|
||||||
|
|
||||||
debug!("Config: {:?}", cfg);
|
debug!("Config: {:?}", final_cfg);
|
||||||
Ok(cfg)
|
Ok(final_cfg)
|
||||||
} else {
|
} else {
|
||||||
warn!("No config file found at {:?}, creating default configuration file at that location.", config_dir);
|
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
|
// create the default configuration file in the user's config directory
|
||||||
|
@ -2,13 +2,19 @@ use std::hash::Hash;
|
|||||||
|
|
||||||
use crate::config::parse_key;
|
use crate::config::parse_key;
|
||||||
use crate::event::Key;
|
use crate::event::Key;
|
||||||
|
use crate::utils::hashmaps;
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize, Default, PartialEq)]
|
#[derive(Clone, Debug, Deserialize, Default, PartialEq)]
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub struct ShellIntegrationConfig {
|
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<String, String>,
|
pub commands: FxHashMap<String, String>,
|
||||||
|
/// {channel: [commands]}
|
||||||
|
pub channel_triggers: FxHashMap<String, Vec<String>>,
|
||||||
pub keybindings: FxHashMap<String, String>,
|
pub keybindings: FxHashMap<String, String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -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 SMART_AUTOCOMPLETE_CONFIGURATION_KEY: &str = "smart_autocomplete";
|
||||||
const COMMAND_HISTORY_CONFIGURATION_KEY: &str = "command_history";
|
const COMMAND_HISTORY_CONFIGURATION_KEY: &str = "command_history";
|
||||||
const DEFAULT_SHELL_AUTOCOMPLETE_KEY: char = 'T';
|
const DEFAULT_SHELL_AUTOCOMPLETE_KEY: char = 'T';
|
||||||
|
19
television/utils/hashmaps.rs
Normal file
19
television/utils/hashmaps.rs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
use std::hash::Hash;
|
||||||
|
|
||||||
|
pub fn invert_hashmap<K, V, I, S: ::std::hash::BuildHasher>(
|
||||||
|
hashmap: &HashMap<K, V, S>,
|
||||||
|
) -> HashMap<I, K>
|
||||||
|
where
|
||||||
|
K: Eq + Hash + Clone,
|
||||||
|
V: Eq + Hash + Clone + IntoIterator<Item = I>,
|
||||||
|
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
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
pub mod cache;
|
pub mod cache;
|
||||||
pub mod command;
|
pub mod command;
|
||||||
pub mod files;
|
pub mod files;
|
||||||
|
pub mod hashmaps;
|
||||||
pub mod indices;
|
pub mod indices;
|
||||||
pub mod input;
|
pub mod input;
|
||||||
pub mod metadata;
|
pub mod metadata;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user