From ee1366a0a8699a3d06446ec8e3c3629b452dccde Mon Sep 17 00:00:00 2001 From: Atanas Pepechkov Date: Sat, 13 Jan 2024 18:56:21 +0200 Subject: [PATCH] add sudo wrapper as optional shell integration feature --- src/config/Config.zig | 4 ++- src/shell-integration/bash/ghostty.bash | 32 ++++++++++++++++--- .../ghostty-shell-integration.fish | 29 +++++++++++++++++ src/shell-integration/zsh/ghostty-integration | 24 ++++++++++++++ src/termio/shell_integration.zig | 1 + 5 files changed, 85 insertions(+), 5 deletions(-) diff --git a/src/config/Config.zig b/src/config/Config.zig index d5826f76a..606a271e0 100644 --- a/src/config/Config.zig +++ b/src/config/Config.zig @@ -774,8 +774,9 @@ keybind: Keybinds = .{}, /// Available features: /// /// - "cursor" - Set the cursor to a blinking bar at the prompt. +/// - "sudo" - Set sudo wrapper to preserve terminfo. /// -/// Example: "cursor", "no-cursor" +/// Example: "cursor", "no-cursor", "sudo", "no-sudo" @"shell-integration-features": ShellIntegrationFeatures = .{}, /// Sets the reporting format for OSC sequences that request color information. @@ -2853,6 +2854,7 @@ pub const ShellIntegration = enum { /// Shell integration features pub const ShellIntegrationFeatures = packed struct { cursor: bool = true, + sudo: bool = false, }; /// OSC 4, 10, 11, and 12 default color reporting format. diff --git a/src/shell-integration/bash/ghostty.bash b/src/shell-integration/bash/ghostty.bash index b312a987d..163ce120b 100644 --- a/src/shell-integration/bash/ghostty.bash +++ b/src/shell-integration/bash/ghostty.bash @@ -41,10 +41,34 @@ function __ghostty_precmd() { PS2=$PS2'\[\e]133;B\a\]' # Cursor - if test "$GHOSTTY_SHELL_INTEGRATION_NO_CURSOR" != "1"; then - PS1=$PS1'\[\e[5 q\]' - PS0=$PS0'\[\e[0 q\]' - fi + if test "$GHOSTTY_SHELL_INTEGRATION_NO_CURSOR" != "1"; then + PS1=$PS1'\[\e[5 q\]' + PS0=$PS0'\[\e[0 q\]' + fi + + # Sudo + if [[ "$GHOSTTY_SHELL_INTEGRATION_NO_SUDO" != "1" ]] && [[ -n "$TERMINFO" ]]; then + # Wrap `sudo` command to ensure Ghostty terminfo is preserved + sudo() { + builtin local sudo_has_sudoedit_flags="no" + for arg in "$@"; do + # Check if argument is '-e' or '--edit' (sudoedit flags) + if [[ "$arg" == "-e" || $arg == "--edit" ]]; then + sudo_has_sudoedit_flags="yes" + builtin break + fi + # Check if argument is neither an option nor a key-value pair + if [[ "$arg" != -* && "$arg" != *=* ]]; then + builtin break + fi + done + if [[ "$sudo_has_sudoedit_flags" == "yes" ]]; then + builtin command sudo "$@"; + else + builtin command sudo TERMINFO="$TERMINFO" "$@"; + fi + } + fi # Command PS0=$PS0'$(__ghostty_get_current_command)' diff --git a/src/shell-integration/fish/vendor_conf.d/ghostty-shell-integration.fish b/src/shell-integration/fish/vendor_conf.d/ghostty-shell-integration.fish index f176d80c4..fb3088865 100755 --- a/src/shell-integration/fish/vendor_conf.d/ghostty-shell-integration.fish +++ b/src/shell-integration/fish/vendor_conf.d/ghostty-shell-integration.fish @@ -64,6 +64,35 @@ function __ghostty_setup --on-event fish_prompt -d "Setup ghostty integration" end end + # Check if we are setting sudo + set --local no_sudo "$GHOSTTY_SHELL_INTEGRATION_NO_SUDO" + + # When using sudo shell integration feature, ensure $TERMINFO is set + # and `sudo` is not already a function or alias + if test -z $no_sudo + and test -n "$TERMINFO"; and test "file" = (type -t sudo 2> /dev/null; or echo "x") + # Wrap `sudo` command to ensure Ghostty terminfo is preserved + function sudo -d "Wrap sudo to preserve terminfo" + set --local sudo_has_sudoedit_flags "no" + for arg in $argv + # Check if argument is '-e' or '--edit' (sudoedit flags) + if string match -q -- "-e" "$arg"; or string match -q -- "--edit" "$arg" + set --local sudo_has_sudoedit_flags "yes" + break + end + # Check if argument is neither an option nor a key-value pair + if not string match -r -q -- "^-" "$arg"; and not string match -r -q -- "=" "$arg" + break + end + end + if test "$sudo_has_sudoedit_flags" = "yes" + command sudo $argv + else + command sudo TERMINFO="$TERMINFO" $argv + end + end + end + # Setup prompt marking function __ghostty_mark_prompt_start --on-event fish_prompt --on-event fish_cancel --on-event fish_posterror # If we never got the output end event, then we need to send it now. diff --git a/src/shell-integration/zsh/ghostty-integration b/src/shell-integration/zsh/ghostty-integration index c9611b9ab..438285a5c 100755 --- a/src/shell-integration/zsh/ghostty-integration +++ b/src/shell-integration/zsh/ghostty-integration @@ -218,6 +218,30 @@ _ghostty_deferred_init() { builtin print -rnu $_ghostty_fd \$'\\e[0 q'" fi + # Sudo + if [[ "$GHOSTTY_SHELL_INTEGRATION_NO_SUDO" != "1" ]] && [[ -n "$TERMINFO" ]]; then + # Wrap `sudo` command to ensure Ghostty terminfo is preserved + sudo() { + builtin local sudo_has_sudoedit_flags="no" + for arg in "$@"; do + # Check if argument is '-e' or '--edit' (sudoedit flags) + if [[ "$arg" == "-e" || $arg == "--edit" ]]; then + sudo_has_sudoedit_flags="yes" + builtin break + fi + # Check if argument is neither an option nor a key-value pair + if [[ "$arg" != -* && "$arg" != *=* ]]; then + builtin break + fi + done + if [[ "$sudo_has_sudoedit_flags" == "yes" ]]; then + builtin command sudo "$@"; + else + builtin command sudo TERMINFO="$TERMINFO" "$@"; + fi + } + fi + # Some zsh users manually run `source ~/.zshrc` in order to apply rc file # changes to the current shell. This is a terrible practice that breaks many # things, including our shell integration. For example, Oh My Zsh and Prezto diff --git a/src/termio/shell_integration.zig b/src/termio/shell_integration.zig index 296c95db6..f8266f969 100644 --- a/src/termio/shell_integration.zig +++ b/src/termio/shell_integration.zig @@ -49,6 +49,7 @@ pub fn setup( // Setup our feature env vars if (!features.cursor) try env.put("GHOSTTY_SHELL_INTEGRATION_NO_CURSOR", "1"); + if (!features.sudo) try env.put("GHOSTTY_SHELL_INTEGRATION_NO_SUDO", "1"); return shell; }