From 26561eea1da8cbce7869fb3ec27aeb37933c556f Mon Sep 17 00:00:00 2001 From: Philipp Jungkamp Date: Sun, 4 Aug 2024 22:44:13 +0200 Subject: [PATCH 1/4] Add -echo argument to provide reliable quoting in shell scripts --- doc/kak.1 | 10 ++++++++++ src/main.cc | 8 ++++++++ 2 files changed, 18 insertions(+) diff --git a/doc/kak.1 b/doc/kak.1 index 37fab36bbf..a12dec232f 100644 --- a/doc/kak.1 +++ b/doc/kak.1 @@ -24,6 +24,10 @@ .Op Ar file ... . .Nm +.Fl quote Sy raw|shell|kakoune +.Op Ar string ... +. +.Nm .Fl p Ar session_id . .Nm @@ -151,6 +155,12 @@ Begin in .Em readonly mode , all the buffers opened will not be written to disk. . +.It Fl quote Sy raw|shell|kakoune Op Ar string ... +Escape one or more +.Ar strings +for interpolation into kakoune or shell scripts. +Multiple strings will be escaped first and then joined with spaces inbetween. +. .It Sy + Ns Ar line Ns Oo Sy \&: Ns Ar column Oc | Sy +: Specify a target line and column for the first file. When the plus sign is followed by only a colon, then the cursor is sent diff --git a/src/main.cc b/src/main.cc index e86ffae3ba..1a0468e7e7 100644 --- a/src/main.cc +++ b/src/main.cc @@ -1103,6 +1103,7 @@ int main(int argc, char* argv[]) { "debug", { ArgCompleter{}, "initial debug option value" } }, { "version", { {}, "display kakoune version and exit" } }, { "ro", { {}, "readonly mode" } }, + { "quote", { ArgCompleter{}, "echo each argument with the given quoting (raw, kakoune, or shell)" } }, { "help", { {}, "display a help message and quit" } } } }; @@ -1153,6 +1154,13 @@ int main(int argc, char* argv[]) return 0; } + if (auto quoting = parser.get_switch("quote")) + { + write_stdout(join(parser | transform(quoter(option_from_string(Meta::Type{}, *quoting))), + ' ', false)); + return 0; + } + if (auto session = parser.get_switch("p")) { for (auto opt : { "c", "n", "s", "d", "e", "E", "ro" }) From 38e71f45add0176721a151b2b7d7603190ec81f0 Mon Sep 17 00:00:00 2001 From: Philipp Jungkamp Date: Sun, 4 Aug 2024 23:48:24 +0200 Subject: [PATCH 2/4] menu.kak: Replace sed with kak -quote --- rc/tools/menu.kak | 57 +++++++++++++++++++++++------------------------ 1 file changed, 28 insertions(+), 29 deletions(-) diff --git a/rc/tools/menu.kak b/rc/tools/menu.kak index 4fd7dde4f5..453269a999 100644 --- a/rc/tools/menu.kak +++ b/rc/tools/menu.kak @@ -31,9 +31,6 @@ define-command menu -params 1.. -docstring %{ printf %s "$2" exit fi - shellquote() { - printf "'%s'" "$(printf %s "$1" | sed "s/'/'\\\\''/g; s/§/§§/g; $2")" - } cases= select_cases= completion= @@ -43,43 +40,45 @@ define-command menu -params 1.. -docstring %{ command=$2 completion="${completion}${title}${nl}" cases="${cases} - ($(shellquote "$title" s/¶/¶¶/g)) - printf '%s\\n' $(shellquote "$command" s/¶/¶¶/g) + $(kak -quote shell -- "$title")) + printf '%s\\n' $(kak -quote shell -- "$command") ;;" if $select_cmds; then select_command=$3 select_cases="${select_cases} - ($(shellquote "$title" s/¶/¶¶/g)) - printf '%s\\n' $(shellquote "$select_command" s/¶/¶¶/g) + $(kak -quote shell -- "$title")) + printf '%s\\n' $(kak -quote shell -- "$select_command") ;;" fi shift $stride done - printf "\ - prompt '' %%§ - evaluate-commands %%sh¶ - case \"\$kak_text\" in \ - %s - (*) echo fail -- no such item: \"'\$(printf %%s \"\$kak_text\" | sed \"s/'/''/g\")'\" ;; - esac - ¶ - §" "$cases" + + printf "%s" "prompt '' $(kak -quote kakoune -- " + evaluate-commands %sh$(kak -quote kakoune -- ' + case "$kak_text" in + '"${cases}"' + *) echo fail -- no such item: "$(kak -quote kakoune -- "$kak_text")" + esac + ') + ")" + if $select_cmds; then - printf " \ - -on-change %%§ - evaluate-commands %%sh¶ - case \"\$kak_text\" in \ - %s - (*) : ;; - esac - ¶ - §" "$select_cases" + printf "%s" " -on-change $(kak -quote kakoune -- " + evaluate-commands %sh$(kak -quote kakoune -- ' + case "$kak_text" in + '"$select_cases"' + *) : ;; + esac + ') + ")" fi + if [ -n "$on_abort" ]; then - printf " -on-abort '%s'" "$(printf %s "$on_abort" | sed "s/'/''/g")" + printf "%s" " -on-abort $(kak -quote kakoune -- "$on_abort")" fi - printf ' -menu -shell-script-candidates %%§ - printf %%s %s - §\n' "$(shellquote "$completion")" + + printf "%s\n" " -menu -shell-script-candidates $(kak -quote kakoune -- " + printf %s $(kak -quote shell -- "$completion") + ")" } } From f9570947eb95d45bad427cf52e2af1e196087f54 Mon Sep 17 00:00:00 2001 From: Philipp Jungkamp Date: Sun, 4 Aug 2024 23:50:00 +0200 Subject: [PATCH 3/4] git.kak: Replace sed with kak -quote --- rc/tools/git.kak | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/rc/tools/git.kak b/rc/tools/git.kak index 68717fc798..677e6c3b46 100644 --- a/rc/tools/git.kak +++ b/rc/tools/git.kak @@ -148,9 +148,6 @@ define-command -params 1.. \ exit 1 } } - kakquote() { - printf "%s" "$1" | sed "s/'/''/g; 1s/^/'/; \$s/\$/'/" - } show_git_cmd_output() { local filetype @@ -255,7 +252,7 @@ define-command -params 1.. \ n=$# eval set -- "$(cat ${kak_response_fifo})" "$@" if [ $# -eq $((n+1)) ]; then - echo fail -- "$(kakquote "$1")" + echo fail -- "$(kak -quote kakoune -- "$1")" exit fi commit=$1 @@ -266,15 +263,15 @@ define-command -params 1.. \ # Log commit and file name because they are only echoed briefly # and not shown elsewhere (we don't have a :messages buffer). message="Blaming $file as of $(git rev-parse --short $commit)" - echo "echo -debug -- $(kakquote "$message")" + echo "echo -debug -- $(kak -quote kakoune -- "$message")" on_close_fifo=" execute-keys -client ${kak_client} ${cursor_line}g${cursor_column}lh evaluate-commands -client ${kak_client} %{ - set-option buffer git_blob $(kakquote "$commit:$file") - git blame $(for arg; do kakquote "$arg"; printf " "; done) + set-option buffer git_blob $(kak -quote kakoune -- "$commit:$file") + git blame $(kak -quote kakoune -- "$@") hook -once window NormalIdle .* %{ execute-keys vv - echo -markup -- $(kakquote "{Information}{\\}$message. Press to jump to blamed commit") + echo -markup -- $(kak -quote kakoune -- "{Information}{\\}$message. Press to jump to blamed commit") } } " show_git_cmd_output show "$commit:$file" @@ -565,7 +562,7 @@ define-command -params 1.. \ ' eval set -- "$(cat ${kak_response_fifo})" if [ $# -eq 1 ]; then - echo fail -- "$(kakquote "$1")" + echo fail -- "$(kak -quote kakoune -- "$1")" exit fi starting_commit=$1 From 714d3fddac774a810fe62cc16f8fde487e4387c1 Mon Sep 17 00:00:00 2001 From: Philipp Jungkamp Date: Sun, 4 Aug 2024 23:50:30 +0200 Subject: [PATCH 4/4] modeline.kak: Replace sed with kak -quote --- rc/detection/modeline.kak | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/rc/detection/modeline.kak b/rc/detection/modeline.kak index 6e067b1abd..166e89dc0d 100644 --- a/rc/detection/modeline.kak +++ b/rc/detection/modeline.kak @@ -12,8 +12,6 @@ declare-option -docstring "amount of lines that will be checked at the beginning define-command -hidden modeline-parse-impl %{ evaluate-commands %sh{ - kakquote() { printf "%s" "$*" | sed "s/'/''/g; 1s/^/'/; \$s/\$/'/"; } - # Translate a vim option into the corresponding kakoune one translate_opt_vim() { local key="$1" @@ -54,7 +52,7 @@ define-command -hidden modeline-parse-impl %{ return;; esac - printf 'set-option buffer %s %s\n' "${key}" "$(kakquote "${value}")" + printf 'set-option buffer %s %s\n' "${key}" "$(kak -quote kakoune -- "${value}")" } # Pass a few whitelisted options to kakoune directly @@ -64,19 +62,19 @@ define-command -hidden modeline-parse-impl %{ case "${key}" in scrolloff|tabstop|indentwidth|autowrap_column|eolformat|filetype|BOM|spell_lang);; - *) printf 'echo -debug %s' "$(kakquote "Unsupported kakoune variable: ${key}")" \ + *) printf 'echo -debug %s' "$(kak -quote kakoune -- "Unsupported kakoune variable: ${key}")" \ | kak -p "${kak_session}" return;; esac - printf 'set-option buffer %s %s\n' "${key}" "$(kakquote "${value}")" + printf 'set-option buffer %s %s\n' "${key}" "$(kak -quote kakoune -- "${value}")" } case "${kak_selection}" in *vi:*|*vim:*) type_selection="vim";; *kak:*|*kakoune:*) type_selection="kakoune";; *) - printf 'fail %s\n' "$(kakquote "Unsupported modeline format: ${kak_selection}")" + printf 'fail %s\n' "$(kak -quote kakoune -- "Unsupported modeline format: ${kak_selection}")" exit 1 ;; esac