diff options
author | thing1 <thing1@seacrossedlovers.xyz> | 2025-01-28 09:14:32 +0000 |
---|---|---|
committer | thing1 <thing1@seacrossedlovers.xyz> | 2025-01-28 09:14:32 +0000 |
commit | 904cec3c4a329cf89fc3219d359239910d61f3f6 (patch) | |
tree | 8d113899921dfbaca0e77c49ab5fc827362d1091 /autoload/windowing |
Diffstat (limited to 'autoload/windowing')
-rw-r--r-- | autoload/windowing/appleterminal.kak | 44 | ||||
-rw-r--r-- | autoload/windowing/detection.kak | 71 | ||||
-rw-r--r-- | autoload/windowing/iterm.kak | 124 | ||||
-rw-r--r-- | autoload/windowing/kitty.kak | 84 | ||||
-rw-r--r-- | autoload/windowing/new-client.kak | 9 | ||||
-rw-r--r-- | autoload/windowing/repl/dtach.kak | 38 | ||||
-rw-r--r-- | autoload/windowing/repl/kitty.kak | 56 | ||||
-rw-r--r-- | autoload/windowing/repl/tmux.kak | 91 | ||||
-rw-r--r-- | autoload/windowing/repl/x11.kak | 41 | ||||
-rw-r--r-- | autoload/windowing/screen.kak | 75 | ||||
-rw-r--r-- | autoload/windowing/sway.kak | 81 | ||||
-rw-r--r-- | autoload/windowing/tmux.kak | 82 | ||||
-rw-r--r-- | autoload/windowing/wayland.kak | 66 | ||||
-rw-r--r-- | autoload/windowing/wezterm.kak | 70 | ||||
-rw-r--r-- | autoload/windowing/x11.kak | 78 | ||||
-rw-r--r-- | autoload/windowing/zellij.kak | 67 |
16 files changed, 1077 insertions, 0 deletions
diff --git a/autoload/windowing/appleterminal.kak b/autoload/windowing/appleterminal.kak new file mode 100644 index 0000000..f47c83c --- /dev/null +++ b/autoload/windowing/appleterminal.kak @@ -0,0 +1,44 @@ +# macOS Terminal.app +# ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾ + +provide-module appleterminal %{ + +# ensure that we're running in Terminal.app +evaluate-commands %sh{ + [ -z "${kak_opt_windowing_modules}" ] || [ "$TERM_PROGRAM" = "Apple_Terminal" ] || echo 'fail Terminal.app not detected' +} + +define-command appleterminal-terminal-window -params 1.. -docstring ' +appleterminal-terminal-window <program> [<arguments>]: create a new terminal as a Terminal.app window +The program passed as argument will be executed in the new terminal'\ +%{ + nop %sh{ + # join the arguments as one string for the shell execution (see x11.kak) + quoted=$( + for i in exec env "PATH=$PATH" "TMPDIR=$TMPDIR" "$@"; do + printf "'%s' " "$(printf %s "$i" | sed "s|'|'\\\\''|g")" + done + ) + + # since Terminal.app runs the command in the interactive shell, add initial space to prevent adding it to shell history + cmd=" $quoted" + echo "$cmd" | osascript \ + -e 'set s to (do shell script "cat 0<&3")' \ + -e 'tell application "Terminal" to do script s' >/dev/null 3<&0 + } +} +complete-command appleterminal-terminal-window shell + +alias global terminal appleterminal-terminal-window + +define-command appleterminal-focus -params ..1 -docstring ' +appleterminal-focus [<client>]: focus the given client +If no client is passed then the current one is used' \ +%{ + fail 'Focusing Terminal.app client is unimplemented' +} +complete-command -menu appleterminal-focus client + +alias global focus appleterminal-focus + +} diff --git a/autoload/windowing/detection.kak b/autoload/windowing/detection.kak new file mode 100644 index 0000000..2fde81c --- /dev/null +++ b/autoload/windowing/detection.kak @@ -0,0 +1,71 @@ +# Attempt to detect the windowing environment we're operating in +# +# We try to load modules from the windowing_modules str-list option in order, +# stopping when one of the modules loads successfully. This ensures that only +# a single module is loaded by default. +# +# On load each module must attempt to detect the environment it's appropriate +# for, and if the environment isn't appropriate it must fail with an error. +# In addition, each module must check for the length of the windowing_modules +# str-list option defined below, and must /not/ check for an appropriate +# environment if the list is empty. An example of this test: +# +# evaluate-commands %sh{ +# [ -z "${kak_opt_windowing_modules}" ] || [ -n "$TMUX" ] || echo 'fail tmux not detected' +# } +# +# Each module is expected to define at least two aliases: +# * terminal - create a new terminal with sensible defaults +# * focus - focus the specified client, defaulting to the current client +# + +declare-option -docstring \ +"Ordered list of windowing modules to try and load. An empty list disables +both automatic module loading and environment detection, enabling complete +manual control of the module loading." \ +str-list windowing_modules 'tmux' 'screen' 'zellij' 'kitty' 'iterm' 'appleterminal' 'sway' 'wayland' 'x11' 'wezterm' + +declare-option -docstring %{ + windowing module to use in the 'terminal' command +} str windowing_module + +declare-option -docstring %{ + where to create new windows in the 'terminal' command. + + Possible values: + - "window" (default) - new window + - "horizontal" - horizontal split (left/right) + - "vertical" - vertical split (top/bottom) + - "tab" - new tab besides current window +} str windowing_placement window + +define-command terminal -params 1.. -docstring %{ + terminal <program> [<arguments>]: create a new terminal using the preferred windowing environment and placement + + This executes "%opt{windowing_module}-terminal-%opt{windowing_placement}" with the given arguments. + If the windowing module is 'wayland', 'sway' or 'x11', then the 'termcmd' option is used as terminal program. + + Example usage: + + terminal sh + evaluate-commands %{ set local windowing_placement horizontal; terminal sh } + + See also the 'new' command. +} %{ + "%opt{windowing_module}-terminal-%opt{windowing_placement}" %arg{@} +} +complete-command terminal shell + +hook -group windowing global KakBegin .* %{ + evaluate-commands %sh{ + set -- ${kak_opt_windowing_modules} + if [ $# -gt 0 ]; then + echo 'try %{ ' + while [ $# -ge 1 ]; do + echo "require-module ${1}; set-option global windowing_module ${1} } catch %{ " + shift + done + echo "echo -debug 'no windowing module detected' }" + fi + } +} diff --git a/autoload/windowing/iterm.kak b/autoload/windowing/iterm.kak new file mode 100644 index 0000000..2ca46df --- /dev/null +++ b/autoload/windowing/iterm.kak @@ -0,0 +1,124 @@ +# https://www.iterm2.com +# ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾ + +provide-module iterm %{ + +# ensure that we're running on iTerm +evaluate-commands %sh{ + [ -z "${kak_opt_windowing_modules}" ] || [ "$TERM_PROGRAM" = "iTerm.app" ] || echo 'fail iTerm not detected' +} + +define-command -hidden -params 2.. iterm-terminal-impl %{ + nop %sh{ + direction="$1" + shift + # join the arguments as one string for the shell execution (see x11.kak) + args=$( + for i in "$@"; do + printf "'%s' " "$(printf %s "$i" | sed "s|'|'\\\\''|g")" + done + ) + + # go through another round of escaping for osascript + # \ -> \\ + # " -> \" + do_esc() { + printf %s "$*" | sed -e 's|\\|\\\\|g; s|"|\\"|g' + } + + escaped=$(do_esc "$args") + esc_path=$(do_esc "$PATH") + esc_tmp=$(do_esc "$TMPDIR") + cmd="env PATH='${esc_path}' TMPDIR='${esc_tmp}' $escaped" + if [ "$direction" = 'tab' ]; then + osascript \ + -e "tell application \"iTerm\"" \ + -e " tell current window" \ + -e " create tab with default profile command \"${cmd}\"" \ + -e " end tell" \ + -e "end tell" >/dev/null + elif [ "$direction" = 'window' ]; then + osascript \ + -e "tell application \"iTerm\"" \ + -e " create window with default profile command \"${cmd}\"" \ + -e "end tell" >/dev/null + else + osascript \ + -e "tell application \"iTerm\"" \ + -e " tell current session of current window" \ + -e " tell (split ${direction} with same profile command \"${cmd}\") to select" \ + -e " end tell" \ + -e "end tell" >/dev/null + fi + } +} + +define-command iterm-terminal-vertical -params 1.. -docstring ' +iterm-terminal-vertical <program> [<arguments>]: create a new terminal as an iterm pane +The current pane is split into two, left and right +The program passed as argument will be executed in the new terminal'\ +%{ + iterm-terminal-impl 'vertically' %arg{@} +} +complete-command iterm-terminal-vertical shell + +define-command iterm-terminal-horizontal -params 1.. -docstring ' +iterm-terminal-horizontal <program> [<arguments>]: create a new terminal as an iterm pane +The current pane is split into two, top and bottom +The program passed as argument will be executed in the new terminal'\ +%{ + iterm-terminal-impl 'horizontally' %arg{@} +} +complete-command iterm-terminal-horizontal shell + +define-command iterm-terminal-tab -params 1.. -docstring ' +iterm-terminal-tab <program> [<arguments>]: create a new terminal as an iterm tab +The program passed as argument will be executed in the new terminal'\ +%{ + iterm-terminal-impl 'tab' %arg{@} +} +complete-command iterm-terminal-tab shell + +define-command iterm-terminal-window -params 1.. -docstring ' +iterm-terminal-window <program> [<arguments>]: create a new terminal as an iterm window +The program passed as argument will be executed in the new terminal'\ +%{ + iterm-terminal-impl 'window' %arg{@} +} +complete-command iterm-terminal-window shell + +define-command iterm-focus -params ..1 -docstring ' +iterm-focus [<client>]: focus the given client +If no client is passed then the current one is used' \ +%{ + evaluate-commands %sh{ + if [ $# -eq 1 ]; then + printf %s\\n "evaluate-commands -client '$1' focus" + else + session="${kak_client_env_ITERM_SESSION_ID#*:}" + osascript \ + -e "tell application \"iTerm\" to repeat with aWin in windows" \ + -e " tell aWin to repeat with aTab in tabs" \ + -e " tell aTab to repeat with aSession in sessions" \ + -e " tell aSession" \ + -e " if (unique id = \"${session}\") then" \ + -e " tell aWin" \ + -e " select" \ + -e " end tell" \ + -e " tell aTab" \ + -e " select" \ + -e " end tell" \ + -e " select" \ + -e " end if" \ + -e " end tell" \ + -e " end repeat" \ + -e " end repeat" \ + -e "end repeat" + fi + } +} +complete-command -menu iterm-focus client + +alias global focus iterm-focus + +} diff --git a/autoload/windowing/kitty.kak b/autoload/windowing/kitty.kak new file mode 100644 index 0000000..a81f969 --- /dev/null +++ b/autoload/windowing/kitty.kak @@ -0,0 +1,84 @@ +# https://sw.kovidgoyal.net/kitty/index.html +# ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾ + +provide-module kitty %{ + +# ensure that we're running on kitty +evaluate-commands %sh{ + [ -z "${kak_opt_windowing_modules}" ] || [ "$TERM" = "xterm-kitty" ] || echo 'fail Kitty not detected' +} + +declare-option -docstring %{window type that kitty creates on new and repl calls (window|os-window)} str kitty_window_type window + +define-command kitty-terminal-window -params 1.. -docstring ' +kitty-terminal-window <program> [<arguments>]: create a new terminal as a kitty window +The program passed as argument will be executed in the new terminal' \ +%{ + nop %sh{ + match="" + if [ -n "$kak_client_env_KITTY_WINDOW_ID" ]; then + match="--match=window_id:$kak_client_env_KITTY_WINDOW_ID" + fi + + listen="" + if [ -n "$kak_client_env_KITTY_LISTEN_ON" ]; then + listen="--to=$kak_client_env_KITTY_LISTEN_ON" + fi + + kitty @ $listen launch --no-response --type="$kak_opt_kitty_window_type" --cwd="$PWD" $match "$@" + } +} +complete-command kitty-terminal-window shell + +define-command kitty-terminal-tab -params 1.. -docstring ' +kitty-terminal-tab <program> [<arguments>]: create a new terminal as kitty tab +The program passed as argument will be executed in the new terminal' \ +%{ + nop %sh{ + match="" + if [ -n "$kak_client_env_KITTY_WINDOW_ID" ]; then + match="--match=window_id:$kak_client_env_KITTY_WINDOW_ID" + fi + + listen="" + if [ -n "$kak_client_env_KITTY_LISTEN_ON" ]; then + listen="--to=$kak_client_env_KITTY_LISTEN_ON" + fi + + kitty @ $listen launch --no-response --type=tab --cwd="$PWD" $match "$@" + } +} +complete-command kitty-terminal-tab shell + +define-command kitty-focus -params ..1 -docstring ' +kitty-focus [<client>]: focus the given client +If no client is passed then the current one is used' \ +%{ + evaluate-commands %sh{ + if [ $# -eq 1 ]; then + printf "evaluate-commands -client '%s' focus" "$1" + else + match="" + if [ -n "$kak_client_env_KITTY_WINDOW_ID" ]; then + match="--match=id:$kak_client_env_KITTY_WINDOW_ID" + fi + + listen="" + if [ -n "$kak_client_env_KITTY_LISTEN_ON" ]; then + listen="--to=$kak_client_env_KITTY_LISTEN_ON" + fi + + kitty @ $listen focus-window --no-response $match + fi + } +} +complete-command -menu kitty-focus client + +alias global focus kitty-focus + +# deprecated +define-command -hidden kitty-terminal -params 1.. %{ + kitty-terminal-window %arg{@} +} + +} diff --git a/autoload/windowing/new-client.kak b/autoload/windowing/new-client.kak new file mode 100644 index 0000000..f852b39 --- /dev/null +++ b/autoload/windowing/new-client.kak @@ -0,0 +1,9 @@ +define-command new -params .. -docstring ' +new [<commands>]: create a new Kakoune client +The ''terminal'' command is used to determine the user''s preferred terminal emulator +The optional arguments are passed as commands to the new client' \ +%{ + terminal kak -c %val{session} -e "%arg{@}" +} + +complete-command -menu new command diff --git a/autoload/windowing/repl/dtach.kak b/autoload/windowing/repl/dtach.kak new file mode 100644 index 0000000..02d11ec --- /dev/null +++ b/autoload/windowing/repl/dtach.kak @@ -0,0 +1,38 @@ +provide-module dtach-repl %{ + +# test if dtach is installed +evaluate-commands %sh{ + [ -n "$(command -v dtach)" ] || echo 'fail dtach not found' +} + +declare-option -docstring "id of the REPL" str dtach_repl_id + +define-command -docstring %{ + dtach-repl [<arguments>]: create a new terminal window for repl interaction + All optional parameters are forwarded to the new terminal window +} \ + -params .. \ + dtach-repl %{ terminal sh -c %{ + file="$(mktemp -u -t kak_dtach_repl.XXXXX)" + trap 'rm -f "${file}"' EXIT + printf "evaluate-commands -try-client $1 \ + 'set-option current dtach_repl_id ${file}'" | kak -p "$2" + shift 2 + dtach -c "${file}" -E sh -c "${@:-$SHELL}" || "${@:-$SHELL}" + } -- %val{client} %val{session} %arg{@} +} +complete-command dtach-repl shell + +define-command dtach-send-text -params 0..1 -docstring %{ + dtach-send-text [text]: Send text to the REPL. + If no text is passed, then the selection is used + } %{ + nop %sh{ + printf "%s" "${@:-$kak_selection}" | dtach -p "$kak_opt_dtach_repl_id" + } +} + +alias global repl-new dtach-repl +alias global repl-send-text dtach-send-text + +} diff --git a/autoload/windowing/repl/kitty.kak b/autoload/windowing/repl/kitty.kak new file mode 100644 index 0000000..1f60366 --- /dev/null +++ b/autoload/windowing/repl/kitty.kak @@ -0,0 +1,56 @@ +hook global ModuleLoaded kitty %{ + require-module kitty-repl +} + +provide-module kitty-repl %{ + +define-command -params .. \ + -docstring %{ + kitty-repl [<arguments>]: Create a new window for repl interaction. + + All optional parameters are forwarded to the new window. + } \ + kitty-repl %{ + nop %sh{ + if [ $# -eq 0 ]; then + cmd="${SHELL:-/bin/sh}" + else + cmd="$*" + fi + + match="" + if [ -n "$kak_client_env_KITTY_WINDOW_ID" ]; then + match="--match=window_id:$kak_client_env_KITTY_WINDOW_ID" + fi + + listen="" + if [ -n "$kak_client_env_KITTY_LISTEN_ON" ]; then + listen="--to=$kak_client_env_KITTY_LISTEN_ON" + fi + + kitty @ $listen launch --no-response --keep-focus --type="$kak_opt_kitty_window_type" --title=kak_repl_window --cwd="$PWD" $match $cmd + } +} +complete-command kitty-repl shell + +define-command -hidden -params 0..1 \ + -docstring %{ + kitty-send-text [text]: Send text to the REPL window. + + If no text is passed, the selection is used. + } \ + kitty-send-text %{ + nop %sh{ + if [ $# -eq 0 ]; then + text="$kak_selection" + else + text="$1" + fi + kitty @ send-text --match=title:kak_repl_window "$text" + } +} + +alias global repl-new kitty-repl +alias global repl-send-text kitty-send-text + +} diff --git a/autoload/windowing/repl/tmux.kak b/autoload/windowing/repl/tmux.kak new file mode 100644 index 0000000..5b77633 --- /dev/null +++ b/autoload/windowing/repl/tmux.kak @@ -0,0 +1,91 @@ +# http://tmux.github.io/ +# ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾ +# Tmux version >= 2 is required to use this module + +hook global ModuleLoaded tmux %{ + require-module tmux-repl +} + +provide-module tmux-repl %{ + +declare-option -docstring "tmux pane id in which the REPL is running" str tmux_repl_id + +define-command -hidden -params 1.. tmux-repl-impl %{ + evaluate-commands %sh{ + if [ -z "$TMUX" ]; then + echo 'fail This command is only available in a tmux session' + exit + fi + tmux_args="$1" + if [ "${1%%-*}" = split ]; then + tmux_args="$tmux_args -t ${kak_client_env_TMUX_PANE}" + elif [ "${1%% *}" = new-window ]; then + session_id=$(tmux display-message -p -t ${kak_client_env_TMUX_PANE} '#{session_id}') + tmux_args="$tmux_args -t $session_id" + fi + shift + repl_pane_id=$(tmux $tmux_args -P -F '#{pane_id}' "$@") + printf "set-option current tmux_repl_id '%s'" "$repl_pane_id" + } +} + +define-command tmux-repl-vertical -params 0.. -docstring "Create a new vertical pane for repl interaction" %{ + tmux-repl-impl 'split-window -v' %arg{@} +} +complete-command tmux-repl-vertical shell + +define-command tmux-repl-horizontal -params 0.. -docstring "Create a new horizontal pane for repl interaction" %{ + tmux-repl-impl 'split-window -h' %arg{@} +} +complete-command tmux-repl-horizontal shell + +define-command tmux-repl-window -params 0.. -docstring "Create a new window for repl interaction" %{ + tmux-repl-impl 'new-window' %arg{@} +} +complete-command tmux-repl-window shell + +define-command -params 0..1 tmux-repl-set-pane -docstring %{ + tmux-repl-set-pane [pane number]: Set an existing tmux pane for repl interaction + If the address of new pane is not given, next pane is used + (To get the pane number in tmux, + use 'tmux display-message -p '#{pane_id}'" in that pane) + } %{ + evaluate-commands %sh{ + if [ -z "$TMUX" ]; then + echo 'fail This command is only available in a tmux session' + exit + fi + if [ $# -eq 0 ]; then + curr_pane_no="${kak_client_env_TMUX_PANE#%}" + tgt_pane=$((curr_pane_no+1)) + else + tgt_pane="$1" + fi + curr_win="$(tmux display-message -t ${kak_client_env_TMUX_PANE} -p '#{window_id}')" + if tmux list-panes -t "$curr_win" -F \#D | grep -Fxq "%"$tgt_pane; then + printf "set-option current tmux_repl_id '%s'" %$tgt_pane + else + echo 'fail The correct pane is not there. Activate using tmux-terminal-* or some other way' + fi + } +} + +define-command -hidden tmux-send-text -params 0..1 -docstring %{ + tmux-send-text [text]: Send text to the REPL pane. + If no text is passed, then the selection is used + } %{ + evaluate-commands %sh{ + if [ $# -eq 0 ]; then + tmux set-buffer -b kak_selection -- "${kak_selection}" + else + tmux set-buffer -b kak_selection -- "$1" + fi + tmux paste-buffer -b kak_selection -t "$kak_opt_tmux_repl_id" || + echo 'fail tmux-send-text: failed to send text, see *debug* buffer for details' + } +} + +alias global repl-new tmux-repl-horizontal +alias global repl-send-text tmux-send-text + +} diff --git a/autoload/windowing/repl/x11.kak b/autoload/windowing/repl/x11.kak new file mode 100644 index 0000000..8f048a7 --- /dev/null +++ b/autoload/windowing/repl/x11.kak @@ -0,0 +1,41 @@ +hook global ModuleLoaded x11 %{ + require-module x11-repl +} + +provide-module x11-repl %{ + +declare-option -docstring "window id of the REPL window" str x11_repl_id + +define-command -docstring %{ + x11-repl [<arguments>]: create a new window for repl interaction + All optional parameters are forwarded to the new window +} \ + -params .. \ + x11-repl %{ x11-terminal-window sh -c %{ + winid="${WINDOWID:-$(xdotool search --pid ${PPID} | tail -1)}" + printf "evaluate-commands -try-client $1 \ + 'set-option current x11_repl_id ${winid}'" | kak -p "$2" + shift 2; + [ "$1" ] && "$@" || "$SHELL" + } -- %val{client} %val{session} %arg{@} +} +complete-command x11-repl shell + +define-command x11-send-text -params 0..1 -docstring %{ + x11-send-text [text]: Send text to the REPL window. + If no text is passed, then the selection is used + } %{ + evaluate-commands %sh{ + ([ "$#" -gt 0 ] && printf "%s" "$1" || printf "%s" "${kak_selection}" ) | xsel -i || + echo 'fail x11-send-text: failed to run xsel, see *debug* buffer for details' && + kak_winid=$(xdotool getactivewindow) && + xdotool windowactivate "${kak_opt_x11_repl_id}" key --clearmodifiers Shift+Insert && + xdotool windowactivate "${kak_winid}" || + echo 'fail x11-send-text: failed to run xdotool, see *debug* buffer for details' + } +} + +alias global repl-new x11-repl +alias global repl-send-text x11-send-text + +} diff --git a/autoload/windowing/screen.kak b/autoload/windowing/screen.kak new file mode 100644 index 0000000..d5515c9 --- /dev/null +++ b/autoload/windowing/screen.kak @@ -0,0 +1,75 @@ +# http://gnu.org/software/screen/ +# ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾ + + +provide-module screen %{ + +# ensure that we're running under screen +evaluate-commands %sh{ + [ -z "${kak_opt_windowing_modules}" ] || [ -n "$STY" ] || echo 'fail screen not detected' +} + +define-command screen-terminal-impl -hidden -params 3.. %{ + nop %sh{ + tty="$(ps -o tty ${kak_client_pid} | tail -n 1)" + screen -X eval "$1" "$2" + shift 2 + # see x11.kak for what this achieves + args=$( + for i in "$@"; do + printf "'%s' " "$(printf %s "$i" | sed "s|'|'\\\\''|g")" + done + ) + screen -X screen sh -c "${args} ; screen -X remove" < "/dev/$tty" + } +} + +define-command screen-terminal-vertical -params 1.. -docstring ' +screen-terminal-vertical <program> [<arguments>]: create a new terminal as a screen pane +The current pane is split into two, left and right +The program passed as argument will be executed in the new terminal' \ +%{ + screen-terminal-impl 'split -v' 'focus right' %arg{@} +} +complete-command screen-terminal-vertical shell + +define-command screen-terminal-horizontal -params 1.. -docstring ' +screen-terminal-horizontal <program> [<arguments>]: create a new terminal as a screen pane +The current pane is split into two, top and bottom +The program passed as argument will be executed in the new terminal' \ +%{ + screen-terminal-impl 'split -h' 'focus down' %arg{@} +} +complete-command screen-terminal-horizontal shell + +define-command screen-terminal-window -params 1.. -docstring ' +screen-terminal-window <program> [<arguments>]: create a new terminal as a screen window +The program passed as argument will be executed in the new terminal' \ +%{ + nop %sh{ + tty="$(ps -o tty ${kak_client_pid} | tail -n 1)" + screen -X screen "$@" < "/dev/$tty" + } +} +complete-command screen-terminal-window shell + +define-command screen-focus -params ..1 -docstring ' +screen-focus [<client>]: focus the given client +If no client is passed then the current one is used' \ +%{ + evaluate-commands %sh{ + if [ $# -eq 1 ]; then + printf %s\\n " + evaluate-commands -client '$1' focus + " + elif [ -n "${kak_client_env_STY}" ]; then + tty="$(ps -o tty ${kak_client_pid} | tail -n 1)" + screen -X select "${kak_client_env_WINDOW}" < "/dev/$tty" + fi + } +} +complete-command -menu screen-focus client + +alias global focus screen-focus + +} diff --git a/autoload/windowing/sway.kak b/autoload/windowing/sway.kak new file mode 100644 index 0000000..c4501c2 --- /dev/null +++ b/autoload/windowing/sway.kak @@ -0,0 +1,81 @@ +provide-module sway %{ + +# Ensure we're actually in Sway +evaluate-commands %sh{ + [ -z "${kak_opt_windowing_modules}" ] || + [ -n "$SWAYSOCK" ] || + echo 'fail SWAYSOCK is not set' +} + +require-module 'wayland' + +alias global sway-terminal-window wayland-terminal-window + +define-command sway-terminal-vertical -params 1.. -docstring ' + sway-terminal-vertical <program> [<arguments>]: create a new terminal as a Sway window + The current pane is split into two, top and bottom + The program passed as argument will be executed in the new terminal' \ +%{ + nop %sh{swaymsg split vertical} + wayland-terminal-window %arg{@} +} +complete-command sway-terminal-vertical shell + +define-command sway-terminal-horizontal -params 1.. -docstring ' + sway-terminal-horizontal <program> [<arguments>]: create a new terminal as a Sway window + The current pane is split into two, left and right + The program passed as argument will be executed in the new terminal' \ +%{ + nop %sh{swaymsg split horizontal} + wayland-terminal-window %arg{@} +} +complete-command sway-terminal-horizontal shell + +define-command sway-terminal-tab -params 1.. -docstring ' + sway-terminal-tab <program> [<arguments>]: create a new terminal as a Sway window + The program passed as argument will be executed in the new terminal' \ +%{ + nop %sh{swaymsg 'split horizontal; layout tabbed'} + wayland-terminal-window %arg{@} +} +complete-command sway-terminal-tab shell + +define-command sway-focus-pid -hidden %{ + evaluate-commands %sh{ + pid=$kak_client_pid + + # Try to focus a window with the current PID, walking up the tree of + # parent processes until the focus eventually succeeds + while ! swaymsg [pid=$pid] focus > /dev/null 2> /dev/null ; do + # Replace the current PID with its parent PID + pid=$(ps -p $pid -o ppid=) + + # If we couldn't get a PPID for some reason, or it's 1 or less, we + # should just fail. + if [ -z $pid ] || [ $pid -le 1 ]; then + echo "fail Can't find PID for Sway window to focus" + break + fi + done + } +} + +define-command sway-focus -params ..1 -docstring ' +sway-focus [<kakoune_client>]: focus a given client''s window. +If no client is passed, then the current client is used' \ +%{ + # Quick branch to make sure we're calling sway-focus-pid from the client + # the user wants to focus on. + evaluate-commands %sh{ + if [ $# -eq 1 ]; then + printf "evaluate-commands -client '%s' sway-focus-pid" "$1" + else + echo sway-focus-pid + fi + } +} +complete-command -menu sway-focus client + +alias global focus sway-focus + +} diff --git a/autoload/windowing/tmux.kak b/autoload/windowing/tmux.kak new file mode 100644 index 0000000..2d43db0 --- /dev/null +++ b/autoload/windowing/tmux.kak @@ -0,0 +1,82 @@ +# http://tmux.github.io/ +# ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾ + +provide-module tmux %{ + +# ensure we're running under tmux +evaluate-commands %sh{ + [ -z "${kak_opt_windowing_modules}" ] || [ -n "$TMUX" ] || echo 'fail tmux not detected' +} + +define-command -hidden -params 2.. tmux-terminal-impl %{ + evaluate-commands %sh{ + tmux=${kak_client_env_TMUX:-$TMUX} + if [ -z "$tmux" ]; then + echo "fail 'This command is only available in a tmux session'" + exit + fi + tmux_args="$1" + if [ "${1%%-*}" = split ]; then + tmux_args="$tmux_args -t ${kak_client_env_TMUX_PANE}" + elif [ "${1%% *}" = new-window ]; then + session_id=$(tmux display-message -p -t ${kak_client_env_TMUX_PANE} '#{session_id}') + tmux_args="$tmux_args -t $session_id" + fi + shift + # ideally we should escape single ';' to stop tmux from interpreting it as a new command + # but that's probably too rare to care + if [ -n "$TMPDIR" ]; then + TMUX=$tmux tmux $tmux_args env TMPDIR="$TMPDIR" "$@" + else + TMUX=$tmux tmux $tmux_args "$@" + fi + } +} + +define-command tmux-terminal-vertical -params 1.. -docstring ' +tmux-terminal-vertical <program> [<arguments>]: create a new terminal as a tmux pane +The current pane is split into two, top and bottom +The program passed as argument will be executed in the new terminal' \ +%{ + tmux-terminal-impl 'split-window -v' %arg{@} +} +complete-command tmux-terminal-vertical shell + +define-command tmux-terminal-horizontal -params 1.. -docstring ' +tmux-terminal-horizontal <program> [<arguments>]: create a new terminal as a tmux pane +The current pane is split into two, left and right +The program passed as argument will be executed in the new terminal' \ +%{ + tmux-terminal-impl 'split-window -h' %arg{@} +} +complete-command tmux-terminal-horizontal shell + +define-command tmux-terminal-window -params 1.. -docstring ' +tmux-terminal-window <program> [<arguments>]: create a new terminal as a tmux window +The program passed as argument will be executed in the new terminal' \ +%{ + tmux-terminal-impl 'new-window' %arg{@} +} +complete-command tmux-terminal-window shell + +define-command tmux-focus -params ..1 -docstring ' +tmux-focus [<client>]: focus the given client +If no client is passed then the current one is used' \ +%{ + evaluate-commands %sh{ + if [ $# -eq 1 ]; then + printf "evaluate-commands -client '%s' focus" "$1" + elif [ -n "${kak_client_env_TMUX}" ]; then + # select-pane makes the pane active in the window, but does not select the window. Both select-pane + # and select-window should be invoked in order to select a pane on a currently not focused window. + TMUX="${kak_client_env_TMUX}" tmux select-window -t "${kak_client_env_TMUX_PANE}" \; \ + select-pane -t "${kak_client_env_TMUX_PANE}" > /dev/null + fi + } +} +complete-command -menu tmux-focus client + +## The default behaviour for the `new` command is to open an horizontal pane in a tmux session +alias global focus tmux-focus + +} diff --git a/autoload/windowing/wayland.kak b/autoload/windowing/wayland.kak new file mode 100644 index 0000000..33737f7 --- /dev/null +++ b/autoload/windowing/wayland.kak @@ -0,0 +1,66 @@ +# wayland + +provide-module wayland %{ + +# ensure that we're running in the right environment +evaluate-commands %sh{ + [ -z "${kak_opt_windowing_modules}" ] || [ -n "$WAYLAND_DISPLAY" ] || echo 'fail WAYLAND_DISPLAY is not set' +} + +# termcmd should be set such as the next argument is the whole +# command line to execute +declare-option -docstring %{shell command run to spawn a new terminal +A shell command is appended to the one set in this option at runtime} \ + str termcmd %sh{ + for termcmd in 'alacritty -e sh -c' \ + 'kitty sh -c' \ + 'foot sh -c' \ + 'termite -e ' \ + 'wterm -e sh -c' \ + 'gnome-terminal -e ' \ + 'xfce4-terminal -e ' \ + 'konsole -e '; do + terminal=${termcmd%% *} + if command -v $terminal >/dev/null 2>&1; then + printf %s\\n "$termcmd" + exit + fi + done +} + +define-command wayland-terminal-window -params 1.. -docstring ' +wayland-terminal-window <program> [<arguments>]: create a new terminal as a Wayland window +The program passed as argument will be executed in the new terminal' \ +%{ + evaluate-commands -save-regs 'a' %{ + set-register a %arg{@} + evaluate-commands %sh{ + if [ -z "${kak_opt_termcmd}" ]; then + echo "fail 'termcmd option is not set'" + exit + fi + termcmd=$kak_opt_termcmd + args=$kak_quoted_reg_a + unset kak_opt_termcmd kak_quoted_reg_a + setsid ${termcmd} "$args" < /dev/null > /dev/null 2>&1 & + } + } +} +complete-command wayland-terminal-window shell + +define-command wayland-focus -params ..1 -docstring ' +wayland-focus [<kakoune_client>]: focus a given client''s window +If no client is passed, then the current client is used' \ +%{ + fail 'Focusing specific windows in most Wayland window managers is unsupported' +} +complete-command -menu wayland-focus client + +alias global focus wayland-focus + +# deprecated +define-command -hidden wayland-terminal -params 1.. %{ + wayland-terminal-window %arg{@} +} + +} diff --git a/autoload/windowing/wezterm.kak b/autoload/windowing/wezterm.kak new file mode 100644 index 0000000..1e3fafd --- /dev/null +++ b/autoload/windowing/wezterm.kak @@ -0,0 +1,70 @@ +# https://wezfurlong.org/wezterm/index.html +# ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾ + + +provide-module wezterm %{ + +# ensure that we're running under screen +evaluate-commands %sh{ + [ -z "${kak_opt_windowing_modules}" ] || [ -n "$WEZTERM_UNIX_SOCKET" ] || echo 'fail wezterm not detected' +} + +define-command wezterm-terminal-impl -hidden -params 2.. %{ + nop %sh{ + wezterm cli "$@" + } +} + +define-command wezterm-terminal-vertical -params 1.. -docstring ' +wezterm-terminal-vertical <program> [<arguments>]: create a new terminal as a wezterm pane +The current pane is split into two, top and bottom +The program passed as argument will be executed in the new terminal' \ +%{ + wezterm-terminal-impl split-pane --cwd "%val{client_env_PWD}" --bottom --pane-id "%val{client_env_WEZTERM_PANE}" -- %arg{@} +} +complete-command wezterm-terminal-vertical shell + +define-command wezterm-terminal-horizontal -params 1.. -docstring ' +wezterm-terminal-horizontal <program> [<arguments>]: create a new terminal as a wezterm pane +The current pane is split into two, left and right +The program passed as argument will be executed in the new terminal' \ +%{ + wezterm-terminal-impl split-pane --cwd "%val{client_env_PWD}" --right --pane-id "%val{client_env_WEZTERM_PANE}" -- %arg{@} +} +complete-command wezterm-terminal-horizontal shell + +define-command wezterm-terminal-tab -params 1.. -docstring ' +wezterm-terminal-tab <program> [<arguments>]: create a new terminal as a wezterm tab +The program passed as argument will be executed in the new terminal' \ +%{ + wezterm-terminal-impl spawn --cwd "%val{client_env_PWD}" --pane-id "%val{client_env_WEZTERM_PANE}" -- %arg{@} +} +complete-command wezterm-terminal-tab shell + +define-command wezterm-terminal-window -params 1.. -docstring ' +wezterm-terminal-window <program> [<arguments>]: create a new terminal as a wezterm window +The program passed as argument will be executed in the new terminal' \ +%{ + wezterm-terminal-impl spawn --cwd "%val{client_env_PWD}" --new-window --pane-id "%val{client_env_WEZTERM_PANE}" -- %arg{@} +} +complete-command wezterm-terminal-window shell + +define-command wezterm-focus -params ..1 -docstring ' +wezterm-focus [<client>]: focus the given client +If no client is passed then the current one is used' \ +%{ + evaluate-commands %sh{ + if [ $# -eq 1 ]; then + printf %s\\n " + evaluate-commands -client '$1' focus + " + elif [ -n "${kak_client_env_WEZTERM_PANE}" ]; then + wezterm cli activate-pane --pane-id "${kak_client_env_WEZTERM_PANE}" > /dev/null 2>&1 + fi + } +} +complete-command -menu wezterm-focus client + +alias global focus wezterm-focus + +} diff --git a/autoload/windowing/x11.kak b/autoload/windowing/x11.kak new file mode 100644 index 0000000..f65718b --- /dev/null +++ b/autoload/windowing/x11.kak @@ -0,0 +1,78 @@ +# x11 + +provide-module x11 %{ + +# ensure that we're running in the right environment +evaluate-commands %sh{ + [ -z "${kak_opt_windowing_modules}" ] || [ -n "$DISPLAY" ] || echo 'fail DISPLAY is not set' +} + +# termcmd should be set such as the next argument is the whole +# command line to execute +declare-option -docstring %{shell command run to spawn a new terminal +A shell command is appended to the one set in this option at runtime} \ + str termcmd %sh{ + for termcmd in 'alacritty -e sh -c' \ + 'kitty sh -c' \ + 'termite -e ' \ + 'urxvt -e sh -c' \ + 'rxvt -e sh -c' \ + 'st -e sh -c' \ + 'xterm -e sh -c' \ + 'roxterm -e sh -c' \ + 'mintty -e sh -c' \ + 'sakura -x ' \ + 'gnome-terminal -e ' \ + 'xfce4-terminal -x sh -c' \ + 'konsole -e '; do + terminal=${termcmd%% *} + if command -v $terminal >/dev/null 2>&1; then + printf %s\\n "$termcmd" + exit + fi + done +} + +define-command x11-terminal-window -params 1.. -docstring ' +x11-terminal-window <program> [<arguments>]: create a new terminal as an X11 window +The program passed as argument will be executed in the new terminal' \ +%{ + evaluate-commands -save-regs 'a' %{ + set-register a %arg{@} + evaluate-commands %sh{ + if [ -z "${kak_opt_termcmd}" ]; then + echo "fail 'termcmd option is not set'" + exit + fi + termcmd=$kak_opt_termcmd + args=$kak_quoted_reg_a + unset kak_opt_termcmd kak_quoted_reg_a + setsid ${termcmd} "$args" < /dev/null > /dev/null 2>&1 & + } + } +} +complete-command x11-terminal-window shell + +define-command x11-focus -params ..1 -docstring ' +x11-focus [<kakoune_client>]: focus a given client''s window +If no client is passed, then the current client is used' \ +%{ + evaluate-commands %sh{ + if [ $# -eq 1 ]; then + printf "evaluate-commands -client '%s' focus" "$1" + else + xdotool windowactivate $kak_client_env_WINDOWID > /dev/null || + echo 'fail failed to run x11-focus, see *debug* buffer for details' + fi + } +} +complete-command -menu x11-focus client + +alias global focus x11-focus + +# deprecated +define-command -hidden x11-terminal -params 1.. %{ + x11-terminal-window %arg{@} +} + +} diff --git a/autoload/windowing/zellij.kak b/autoload/windowing/zellij.kak new file mode 100644 index 0000000..71f962e --- /dev/null +++ b/autoload/windowing/zellij.kak @@ -0,0 +1,67 @@ +# https://zellij.dev/ +# ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾ + +provide-module zellij %{ + +# ensure we're running under zellij +evaluate-commands %sh{ + [ -z "${kak_opt_windowing_modules}" ] || [ -n "$ZELLIJ" -a -n "$ZELLIJ_SESSION_NAME" ] || echo 'fail zellij not detected' +} + +define-command -params 1.. zellij-action %{ nop %sh{ + zellij --session "$kak_client_env_ZELLIJ_SESSION_NAME" action "$@" +}} +define-command -hidden -params 2.. zellij-run %{ nop %sh{ + zellij_run_options=$1 + shift + zellij --session "$kak_client_env_ZELLIJ_SESSION_NAME" run $zellij_run_options -- "$@" +}} + +define-command -hidden -params 1.. zellij-terminal-window %{ + zellij-run "--close-on-exit" %arg{@} +} +complete-command zellij-terminal-window shell + +define-command zellij-terminal-vertical -params 1.. -docstring ' +zellij-terminal-vertical <program> [<arguments>]: create a new terminal as a zellij pane +The current pane is split into two, top and bottom +The program passed as argument will be executed in the new terminal' \ +%{ + zellij-run "--direction down" %arg{@} +} +complete-command zellij-terminal-vertical shell + +define-command zellij-terminal-horizontal -params 1.. -docstring ' +zellij-terminal-horizontal <program> [<arguments>]: create a new terminal as a zellij pane +The current pane is split into two, left and right +The program passed as argument will be executed in the new terminal' \ +%{ + zellij-run "--direction right" %arg{@} +} +complete-command zellij-terminal-horizontal shell + +define-command zellij-focus -params ..1 -docstring ' +zellij-focus [<client>]: focus the given client +If no client is passed then the current one is used' \ +%{ evaluate-commands %sh{ + if [ $# -eq 1 ]; then + printf "evaluate-commands -client '%s' focus" "$1" + elif [ -n "${kak_client_env_ZELLIJ}" ]; then + output=$(mktemp -d "${TMPDIR:-/tmp}"/kak-zellij.XXXXXXXX)/dump-screen + pane_count=0 + while [ $((pane_count+=1)) -lt 10 ]; do + if zellij action dump-screen "$output" && grep "${kak_client}@\[$kak_session\]" "$output" > /dev/null ; then + break; + fi + zellij action focus-next-pane + done + rm -r $(dirname $output) + fi +}} +complete-command -menu zellij-focus client + +## The default behaviour for the `new` command is to open an horizontal pane in a zellij session +alias global focus zellij-focus + +} + |