diff --git a/cable/unix-channels.toml b/cable/unix-channels.toml index 585b54a8..b6bf7ec 100644 --- a/cable/unix-channels.toml +++ b/cable/unix-channels.toml @@ -90,3 +90,7 @@ source_command = "sed '1!G;h;$!d' ${HISTFILE:-${HOME}/.bash_history}" [[cable_channel]] name = "fish-history" source_command = "fish -c 'history'" + +[[cable_channel]] +name = "nu-history" +source_command = "nu -c 'history'" diff --git a/television/cli/args.rs b/television/cli/args.rs index 100bbe2..43202c9 100644 --- a/television/cli/args.rs +++ b/television/cli/args.rs @@ -177,6 +177,7 @@ pub enum Shell { Fish, PowerShell, Cmd, + Nu, } #[allow(clippy::unnecessary_wraps)] diff --git a/television/utils/shell.rs b/television/utils/shell.rs index c9fc46c..e0d996f 100644 --- a/television/utils/shell.rs +++ b/television/utils/shell.rs @@ -12,6 +12,7 @@ pub enum Shell { Fish, PowerShell, Cmd, + Nu, } impl Default for Shell { @@ -78,6 +79,7 @@ impl Shell { Shell::Fish => "fish", Shell::PowerShell => "powershell", Shell::Cmd => "cmd", + Shell::Nu => "nu", } } } @@ -90,6 +92,7 @@ impl From for Shell { CliShell::Fish => Shell::Fish, CliShell::PowerShell => Shell::PowerShell, CliShell::Cmd => Shell::Cmd, + CliShell::Nu => Shell::Nu, } } } @@ -102,6 +105,7 @@ impl From<&CliShell> for Shell { CliShell::Fish => Shell::Fish, CliShell::PowerShell => Shell::PowerShell, CliShell::Cmd => Shell::Cmd, + CliShell::Nu => Shell::Nu, } } } @@ -109,6 +113,7 @@ impl From<&CliShell> for Shell { const COMPLETION_ZSH: &str = include_str!("shell/completion.zsh"); const COMPLETION_BASH: &str = include_str!("shell/completion.bash"); const COMPLETION_FISH: &str = include_str!("shell/completion.fish"); +const COMPLETION_NU: &str = include_str!("shell/completion.nu"); // create the appropriate key binding for each supported shell pub fn ctrl_keybinding(shell: Shell, character: char) -> Result { @@ -116,6 +121,7 @@ pub fn ctrl_keybinding(shell: Shell, character: char) -> Result { Shell::Bash => Ok(format!(r"\C-{character}")), Shell::Zsh => Ok(format!(r"^{character}")), Shell::Fish => Ok(format!(r"\c{character}")), + Shell::Nu => Ok(format!(r"Ctrl-{character}")), _ => anyhow::bail!("This shell is not yet supported: {:?}", shell), } } @@ -125,6 +131,7 @@ pub fn completion_script(shell: Shell) -> Result<&'static str> { Shell::Bash => Ok(COMPLETION_BASH), Shell::Zsh => Ok(COMPLETION_ZSH), Shell::Fish => Ok(COMPLETION_FISH), + Shell::Nu => Ok(COMPLETION_NU), _ => anyhow::bail!("This shell is not yet supported: {:?}", shell), } } @@ -190,4 +197,13 @@ mod tests { let result = ctrl_keybinding(shell, character); assert!(result.is_err()); } + + #[test] + fn test_nushell_ctrl_keybinding() { + let character = 's'; + let shell = Shell::Nu; + let result = ctrl_keybinding(shell, character); + assert!(result.is_ok()); + assert_eq!(result.unwrap(), "Ctrl-s"); + } } diff --git a/television/utils/shell/completion.nu b/television/utils/shell/completion.nu new file mode 100644 index 0000000..477c32d --- /dev/null +++ b/television/utils/shell/completion.nu @@ -0,0 +1,59 @@ +def tv_smart_autocomplete [] { + let current_prompt = (commandline) + let cursor = (commandline get-cursor) + let current_prompt = ($current_prompt | str substring 0..$cursor) + + let output = (tv --autocomplete-prompt $current_prompt | str trim) + + if ($output | str length) > 0 { + let needs_space = not ($current_prompt | str ends-with " ") + let new_prompt = if $needs_space { $"($current_prompt) " + $output } else { $current_prompt + $output } + } + # Update the line editor with the new prompt + + if ($output | is-not-empty) { + commandline edit --replace $output + commandline set-cursor --end + } +} + +def tv_shell_history [] { + let current_prompt = (commandline) + let cursor = (commandline get-cursor) + let current_prompt = ($current_prompt | str substring 0..$cursor) + + let output = (tv nu-history --input $current_prompt | str trim) + + if ($output | is-not-empty) { + commandline edit --replace $output + commandline set-cursor --end + } +} + +# Bind custom keybindings + +$env.config = ( + $env.config + | upsert keybindings [ + { + name: tv_completion, + modifier: Control, + keycode: char_t, + mode: [vi_normal, vi_insert, emacs], + event: { + send: executehostcommand, + cmd: "tv_smart_autocomplete" + } + } + { + name: tv_history, + modifier: Control, + keycode: char_r, + mode: [vi_normal, vi_insert, emacs], + event: { + send: executehostcommand, + cmd: "tv_shell_history" + } + } + ] +)