Rework 'terminal' commands

* Arguments of the kakoune command are now preserved in the shell call
* Escaping logic is moved from 'new' to 'terminal'
This commit is contained in:
Olivier Perret 2018-12-21 18:14:28 +01:00
parent 02fa967476
commit 5146f7ba33
6 changed files with 125 additions and 62 deletions

View File

@ -4,11 +4,7 @@ The ''terminal'' alias is being used to determine the user''s preferred terminal
The optional arguments are passed as commands to the new client' \ The optional arguments are passed as commands to the new client' \
%{ %{
try %{ try %{
terminal %sh{ terminal kak -c %val{session} -e "%arg{@}"
# double-up single-quotes
escaped=$(printf %s "$*" | sed -e "s|'|''|g")
printf "kak -c '%s' -e '%s'" "$kak_session" "$escaped"
}
} catch %{ } catch %{
fail "The 'terminal' alias must be defined to use this command" fail "The 'terminal' alias must be defined to use this command"
} }

View File

@ -9,35 +9,46 @@ hook -group GNUscreen global KakBegin .* %sh{
" "
} }
define-command screen-terminal-impl -hidden -params 3 %{ define-command screen-terminal-impl -hidden -params 3.. %{
nop %sh{ nop %sh{
tty="$(ps -o tty ${kak_client_pid} | tail -n 1)" tty="$(ps -o tty ${kak_client_pid} | tail -n 1)"
screen -X eval "$1" "$2" screen -X eval "$1" "$2"
screen -X screen sh -c "$3; screen -X remove" < "/dev/$tty" shift 2
# see x11.kak for what this achieves
args=$(
for i in "$@"; do
if [ "$i" = '' ]; then
printf "'' "
else
printf %s "$i" | sed -e "s|'|'\\\\''|g; s|^|'|; s|$|' |"
fi
done
)
screen -X screen sh -c "${args} ; screen -X remove" < "/dev/$tty"
} }
} }
define-command screen-terminal-vertical -params 1 -shell-completion -docstring ' define-command screen-terminal-vertical -params 1.. -shell-completion -docstring '
screen-terminal-vertical <program>: create a new terminal as a screen pane screen-terminal-vertical <program> [<arguments>] [<arguments>]: create a new terminal as a screen pane
The current pane is split into two, left and right The current pane is split into two, left and right
The shell program passed as argument will be executed in the new terminal' \ The program passed as argument will be executed in the new terminal' \
%{ %{
screen-terminal-impl 'split -v' 'focus right' %arg{@} screen-terminal-impl 'split -v' 'focus right' %arg{@}
} }
define-command screen-terminal-horizontal -params 1 -shell-completion -docstring ' define-command screen-terminal-horizontal -params 1.. -shell-completion -docstring '
screen-terminal-horizontal <program>: create a new terminal as a screen pane screen-terminal-horizontal <program> [<arguments>]: create a new terminal as a screen pane
The current pane is split into two, top and bottom The current pane is split into two, top and bottom
The shell program passed as argument will be executed in the new terminal' \ The program passed as argument will be executed in the new terminal' \
%{ %{
screen-terminal-impl 'split -h' 'focus down' %arg{@} screen-terminal-impl 'split -h' 'focus down' %arg{@}
} }
define-command screen-terminal-window -params 1 -shell-completion -docstring ' define-command screen-terminal-window -params 1.. -shell-completion -docstring '
screen-terminal-window <program>: create a new terminal as a screen window screen-terminal-window <program> [<arguments>]: create a new terminal as a screen window
The shell program passed as argument will be executed in the new terminal' \ The program passed as argument will be executed in the new terminal' \
%{ %{
nop %sh{ nop %sh{
tty="$(ps -o tty ${kak_client_pid} | tail -n 1)" tty="$(ps -o tty ${kak_client_pid} | tail -n 1)"
screen -X screen sh -c "$*" < "/dev/$tty" screen -X screen "$@" < "/dev/$tty"
} }
} }

View File

@ -11,7 +11,7 @@ hook global KakBegin .* %sh{
fi fi
} }
define-command -hidden -params 2 tmux-terminal-impl %{ define-command -hidden -params 2.. tmux-terminal-impl %{
evaluate-commands %sh{ evaluate-commands %sh{
tmux=${kak_client_env_TMUX:-$TMUX} tmux=${kak_client_env_TMUX:-$TMUX}
if [ -z "$tmux" ]; then if [ -z "$tmux" ]; then
@ -19,29 +19,32 @@ define-command -hidden -params 2 tmux-terminal-impl %{
exit exit
fi fi
tmux_args="$1" tmux_args="$1"
TMUX=$tmux tmux $tmux_args env TMPDIR="$TMPDIR" sh -c "$2" < /dev/null > /dev/null 2>&1 & shift
# ideally we should escape single ';' to stop tmux from interpreting it as a new command
# but that's probably too rare to care
TMUX=$tmux tmux $tmux_args env TMPDIR="$TMPDIR" "$@" < /dev/null > /dev/null 2>&1 &
} }
} }
define-command tmux-terminal-vertical -params 1 -shell-completion -docstring ' define-command tmux-terminal-vertical -params 1.. -shell-completion -docstring '
tmux-terminal-vertical <program>: create a new terminal as a tmux pane tmux-terminal-vertical <program> [<arguments>]: create a new terminal as a tmux pane
The current pane is split into two, top and bottom The current pane is split into two, top and bottom
The shell program passed as argument will be executed in the new terminal' \ The program passed as argument will be executed in the new terminal' \
%{ %{
tmux-terminal-impl 'split-window -v' %arg{1} tmux-terminal-impl 'split-window -v' %arg{@}
} }
define-command tmux-terminal-horizontal -params 1 -shell-completion -docstring ' define-command tmux-terminal-horizontal -params 1.. -shell-completion -docstring '
tmux-terminal-horizontal <program>: create a new terminal as a tmux pane tmux-terminal-horizontal <program> [<arguments>]: create a new terminal as a tmux pane
The current pane is split into two, left and right The current pane is split into two, left and right
The shell program passed as argument will be executed in the new terminal' \ The program passed as argument will be executed in the new terminal' \
%{ %{
tmux-terminal-impl 'split-window -h' %arg{1} tmux-terminal-impl 'split-window -h' %arg{@}
} }
define-command tmux-terminal-window -params 1 -shell-completion -docstring ' define-command tmux-terminal-window -params 1.. -shell-completion -docstring '
tmux-terminal-window <program> [<arguments>]: create a new terminal as a tmux window tmux-terminal-window <program> [<arguments>] [<arguments>]: create a new terminal as a tmux window
The shell program passed as argument will be executed in the new terminal' \ The program passed as argument will be executed in the new terminal' \
%{ %{
tmux-terminal-impl 'new-window' %arg{1} tmux-terminal-impl 'new-window' %arg{@}
} }
define-command tmux-focus -params ..1 -client-completion -docstring ' define-command tmux-focus -params ..1 -client-completion -docstring '

View File

@ -22,16 +22,36 @@ A shell command is appended to the one set in this option at runtime} \
done done
} }
define-command x11-terminal -params 1 -shell-completion -docstring ' define-command x11-terminal -params 1.. -shell-completion -docstring '
x11-terminal <program>: create a new terminal as an x11 window x11-terminal <program> [<arguments>]: create a new terminal as an x11 window
The shell program passed as argument will be executed in the new terminal' \ The program passed as argument will be executed in the new terminal' \
%{ %{
evaluate-commands %sh{ evaluate-commands %sh{
if [ -z "${kak_opt_termcmd}" ]; then if [ -z "${kak_opt_termcmd}" ]; then
echo "fail 'termcmd option is not set'" echo "fail 'termcmd option is not set'"
exit exit
fi fi
setsid ${kak_opt_termcmd} "$1" < /dev/null > /dev/null 2>&1 & # join arguments into a single string, in which they're delimited
# by single quotes, and with single quotes inside transformed to '\''
# so that sh -c "$args" will re-split the arguments properly
# example:
# $1 = ab
# $2 = foo bar
# $3 =
# $4 = foo'bar
# $args = 'ab' 'foo bar' '' 'foo'\''bar'
# would be nicer to do in a single sed/awk call but that's difficult
args=$(
for i in "$@"; do
# special case to preserve empty variables as sed won't touch these
if [ "$i" = '' ]; then
printf "'' "
else
printf %s "$i" | sed -e "s|'|'\\\\''|g; s|^|'|; s|$|' |"
fi
done
)
setsid ${kak_opt_termcmd} "$args" < /dev/null > /dev/null 2>&1 &
} }
} }

View File

@ -11,12 +11,25 @@ hook global KakBegin .* %sh{
fi fi
} }
define-command -hidden -params 2 iterm-terminal-split-impl %{ define-command -hidden -params 2.. iterm-terminal-split-impl %{
nop %sh{ nop %sh{
# replace ' with '\\'' in the command
escaped=$(printf %s "$2" | sed -e "s|'|'\\\\\\\\''|g")
direction="$1" direction="$1"
cmd="env PATH='${PATH}' TMPDIR='${TMPDIR}' sh -c '$escaped'" shift
# join the arguments as one string for the shell execution (see x11.kak)
args=$(
for i in "$@"; do
if [ "$i" = '' ]; then
printf "'' "
else
printf %s "$i" | sed -e "s|'|'\\\\''|g; s|^|'|; s|$|' |"
fi
done
)
# go through another round of escaping for osascript
# \ -> \\
# " -> \"
escaped=$(printf %s "$args" | sed -e 's|\|\\\\|g; s|"|\\"|g')
cmd="env PATH='${PATH}' TMPDIR='${TMPDIR}' $escaped"
osascript \ osascript \
-e "tell application \"iTerm\"" \ -e "tell application \"iTerm\"" \
-e " tell current session of current window" \ -e " tell current session of current window" \
@ -26,28 +39,38 @@ define-command -hidden -params 2 iterm-terminal-split-impl %{
} }
} }
define-command iterm-terminal-vertical -params 1 -shell-completion -docstring ' define-command iterm-terminal-vertical -params 1.. -shell-completion -docstring '
iterm-terminal-vertical <program>: create a new terminal as an iterm pane iterm-terminal-vertical <program> [<arguments>]: create a new terminal as an iterm pane
The current pane is split into two, top and bottom The current pane is split into two, top and bottom
The shell program passed as argument will be executed in the new terminal'\ The program passed as argument will be executed in the new terminal'\
%{ %{
iterm-terminal-split-impl 'vertically' %arg{1} iterm-terminal-split-impl 'vertically' %arg{1}
} }
define-command iterm-terminal-horizontal -params 1 -shell-completion -docstring ' define-command iterm-terminal-horizontal -params 1.. -shell-completion -docstring '
iterm-terminal-horizontal <program>: create a new terminal as an iterm pane iterm-terminal-horizontal <program> [<arguments>]: create a new terminal as an iterm pane
The current pane is split into two, left and right The current pane is split into two, left and right
The shell program passed as argument will be executed in the new terminal'\ The program passed as argument will be executed in the new terminal'\
%{ %{
iterm-terminal-split-impl 'horizontally' %arg{1} iterm-terminal-split-impl 'horizontally' %arg{1}
} }
define-command iterm-terminal-tab -params 1 -shell-completion -docstring ' define-command iterm-terminal-tab -params 1.. -shell-completion -docstring '
iterm-terminal-tab <program>: create a new terminal as an iterm tab iterm-terminal-tab <program> [<arguments>]: create a new terminal as an iterm tab
The shell program passed as argument will be executed in the new terminal'\ The program passed as argument will be executed in the new terminal'\
%{ %{
nop %sh{ nop %sh{
escaped=$(printf %s "$1" | sed -e "s|'|'\\\\\\\\''|g") # see above
cmd="env PATH='${PATH}' TMPDIR='${TMPDIR}' sh -c '$escaped'" args=$(
for i in "$@"; do
if [ "$i" = '' ]; then
printf "'' "
else
printf %s "$i" | sed -e "s|'|'\\\\''|g; s|^|'|; s|$|' |"
fi
done
)
escaped=$(printf %s "$args" | sed -e 's|\|\\\\|g; s|"|\\"|g')
cmd="env PATH='${PATH}' TMPDIR='${TMPDIR}' $escaped"
osascript \ osascript \
-e "tell application \"iTerm\"" \ -e "tell application \"iTerm\"" \
-e " tell current window" \ -e " tell current window" \
@ -58,12 +81,22 @@ The shell program passed as argument will be executed in the new terminal'\
} }
define-command iterm-terminal-window -params 1 -shell-completion -docstring ' define-command iterm-terminal-window -params 1 -shell-completion -docstring '
iterm-terminal-window <program>: create a new terminal as an iterm window iterm-terminal-window <program> [<arguments>]: create a new terminal as an iterm window
The shell program passed as argument will be executed in the new terminal'\ The program passed as argument will be executed in the new terminal'\
%{ %{
nop %sh{ nop %sh{
escaped=$(printf %s "$1" | sed -e "s|'|'\\\\\\\\''|g") # see above
cmd="env PATH='${PATH}' TMPDIR='${TMPDIR}' sh -c '$escaped'" args=$(
for i in "$@"; do
if [ "$i" = '' ]; then
printf "'' "
else
printf %s "$i" | sed -e "s|'|'\\\\''|g; s|^|'|; s|$|' |"
fi
done
)
escaped=$(printf %s "$args" | sed -e 's|\|\\\\|g; s|"|\\"|g')
cmd="env PATH='${PATH}' TMPDIR='${TMPDIR}' $escaped"
osascript \ osascript \
-e "tell application \"iTerm\"" \ -e "tell application \"iTerm\"" \
-e " create window with default profile command \"${cmd}\"" \ -e " create window with default profile command \"${cmd}\"" \

View File

@ -12,21 +12,21 @@ hook -group kitty-hooks global KakBegin .* %sh{
fi fi
} }
define-command kitty-terminal -params 1 -shell-completion -docstring ' define-command kitty-terminal -params 1.. -shell-completion -docstring '
kitty-terminal <program>: create a new terminal as a kitty window kitty-terminal <program> [<arguments>]: create a new terminal as a kitty window
The shell program passed as argument will be executed in the new terminal' \ The program passed as argument will be executed in the new terminal' \
%{ %{
nop %sh{ nop %sh{
kitty @ new-window --no-response --window-type $kak_opt_kitty_window_type sh -c "$1" kitty @ new-window --no-response --window-type $kak_opt_kitty_window_type "$@"
} }
} }
define-command kitty-terminal-tab -params 1 -shell-completion -docstring ' define-command kitty-terminal-tab -params 1.. -shell-completion -docstring '
kitty-terminal-tab <program>: create a new terminal as kitty tab kitty-terminal-tab <program> [<arguments>]: create a new terminal as kitty tab
The shell program passed as argument will be executed in the new terminal' \ The program passed as argument will be executed in the new terminal' \
%{ %{
nop %sh{ nop %sh{
kitty @ new-window --no-response --new-tab sh -c "$1" kitty @ new-window --no-response --new-tab "$@"
} }
} }