From 1ec6e664afc29957d9f3f596fd4433b4ebb1f7a7 Mon Sep 17 00:00:00 2001 From: Brad Kollmyer Date: Fri, 10 Jul 2026 17:20:13 -0700 Subject: cli: T9077: insert literal '?' inside quoted values instead of triggering help The '?' key is a raw readline binding (possible-completions), so a literal question mark can never be typed into a value: readline intercepts the keystroke before bash parsing begins and quoting cannot protect it. Values like remote-group URLs with query strings get silently corrupted ('.../blacklist?key=x' is stored as '.../blacklistkey=x') with no error at any stage. Rebind '?' to a bind -x handler that scans the line left of the cursor for an open single/double quote or a pending backslash escape. Inside a quote or escape the key self-inserts; otherwise it triggers the standard help via a DSR round-trip (printf '\e[5n' with the terminal's reply ESC [ 0 n bound to possible-completions), keeping the help path and output identical to the previous behavior. 'set terminal key query-help enable' now restores the quote-aware handler instead of the raw binding; 'disable' keeps its existing self-insert override, which takes precedence at login as before. Co-Authored-By: Claude Fable 5 --- src/etc/bash_completion.d/vyatta-op | 36 +++++++++++++++++++++++++++++++++++- src/op_mode/toggle_help_binding.sh | 3 ++- 2 files changed, 37 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/etc/bash_completion.d/vyatta-op b/src/etc/bash_completion.d/vyatta-op index cedbcfbc1..11f0db6ed 100644 --- a/src/etc/bash_completion.d/vyatta-op +++ b/src/etc/bash_completion.d/vyatta-op @@ -35,6 +35,39 @@ test -z "$_vyatta_default_pager" && \ test -z "$VYATTA_PAGER" && \ declare -x VYATTA_PAGER=$_vyatta_default_pager +# Handler for the '?' key. Outside of a quoted string, '?' shows the +# completion help as before. Inside a quoted string (or after a +# backslash), it self-inserts, so values like URLs with query strings +# can be typed without Ctrl-V: +# set firewall group remote-group X url 'https://example.com/list?key=abc' +_vyatta_question_mark () +{ + local head=${READLINE_LINE:0:READLINE_POINT} + local i c in_sq='' in_dq='' esc='' + for (( i=0; i<${#head}; i++ )); do + c=${head:i:1} + if [[ -n $esc ]]; then + esc='' + continue + fi + case $c in + \\) [[ -z $in_sq ]] && esc=1 ;; + \') [[ -z $in_dq ]] && { [[ -n $in_sq ]] && in_sq='' || in_sq=1; } ;; + \") [[ -z $in_sq ]] && { [[ -n $in_dq ]] && in_dq='' || in_dq=1; } ;; + esac + done + if [[ -n $in_sq || -n $in_dq || -n $esc ]]; then + READLINE_LINE=${READLINE_LINE:0:READLINE_POINT}\?${READLINE_LINE:READLINE_POINT} + (( READLINE_POINT++ )) + else + # 'bind -x' handlers cannot invoke readline functions directly, so + # ask the terminal for a Device Status Report (DSR); the terminal's + # reply (ESC [ 0 n) is bound to possible-completions below, which + # re-enters the standard help path with the line unchanged. + printf '\e[5n' + fi +} + _vyatta_op_do_key_bindings () { if [[ "$SHELL" != "/bin/vbash" && "$SHELL" != "/sbin/radius_shell" ]]; then @@ -45,7 +78,8 @@ _vyatta_op_do_key_bindings () shopt -u nullglob case "$-" in *i*) - bind '"?": possible-completions' + bind -x '"?": _vyatta_question_mark' + bind '"\e[0n": possible-completions' bind 'set show-all-if-ambiguous on' bind_cmds=$(grep '^bind .* # vyatta key binding$' $HOME/.bashrc) eval $bind_cmds diff --git a/src/op_mode/toggle_help_binding.sh b/src/op_mode/toggle_help_binding.sh index 7c8bc05ce..23550bff6 100755 --- a/src/op_mode/toggle_help_binding.sh +++ b/src/op_mode/toggle_help_binding.sh @@ -21,5 +21,6 @@ if [ "$1" == 'disable' ]; then bind '"?": self-insert' else sed -i "/^bind '\"?\": .* # vyatta key binding$/d" $HOME/.bashrc - bind '"?": possible-completions' + # default binding: quote-aware help handler from bash_completion.d/vyatta-op + bind -x '"?": _vyatta_question_mark' fi -- cgit v1.2.3