From 484853cbd1c393df8c0e2860cae94c0b8ab2cde6 Mon Sep 17 00:00:00 2001 From: Martin Dvorak Date: Mon, 26 Jan 2026 21:33:37 +0100 Subject: [PATCH] fix(insert): :bug: fixing need to hit ENTER twice on system w/o TIOCSTI in Zsh (Bash is impossible to fix) #507 --- man/hstr.1 | 18 +++++++++++---- src/hstr.c | 17 ++++++++++---- test/sh/tiotcsi-function-bash.sh | 30 ++++++++++++++++++++---- test/sh/tiotcsi-function-zsh.sh | 39 +++++++++++++++++++++++++------- 4 files changed, 83 insertions(+), 21 deletions(-) diff --git a/man/hstr.1 b/man/hstr.1 index 4bfed0f5..23df564d 100644 --- a/man/hstr.1 +++ b/man/hstr.1 @@ -231,13 +231,21 @@ setopt histignorespace # skip cmds w/ leading space from history export HSTR_CONFIG=hicolor # get more colors hstr_no_tiocsti() { zle -I - { HSTR_OUT="$( { &1 1>&3 3>&- )"; } 3>&1; - BUFFER="${HSTR_OUT}" - CURSOR=${#BUFFER} - zle redisplay + { HSTR_OUT="$( { &2; } 2>&1 1>&3 3>&-; )"; } 3>&1; + HSTR_OUT="${HSTR_OUT%x}" + if [[ "${HSTR_OUT}" == *$'\\n' ]]; then + BUFFER="${HSTR_OUT%$'\\n'}" + CURSOR=${#BUFFER} + zle redisplay + zle accept-line + else + BUFFER="${HSTR_OUT}" + CURSOR=${#BUFFER} + zle redisplay + fi } zle -N hstr_no_tiocsti -bindkey '\C-r' hstr_no_tiocsti +bindkey '\\C-r' hstr_no_tiocsti export HSTR_TIOCSTI=n .sp .fi diff --git a/src/hstr.c b/src/hstr.c index bdeacb5a..f923d6bd 100644 --- a/src/hstr.c +++ b/src/hstr.c @@ -460,6 +460,7 @@ void print_bash_install_code(void) #endif ); printf("\nexport HSTR_TIOCSTI=n"); + // note: due to Bash 'bind -x' limitations, users need to press ENTER twice on row insertion } printf("\n\n"); @@ -485,10 +486,18 @@ void print_zsh_install_code(void) #endif "\n zle -I" - "\n { HSTR_OUT=\"$( { &1 1>&3 3>&- )\"; } 3>&1;" - "\n BUFFER=\"${HSTR_OUT}\"" - "\n CURSOR=${#BUFFER}" - "\n zle redisplay" + "\n { HSTR_OUT=\"$( { &2; } 2>&1 1>&3 3>&-; )\"; } 3>&1;" + "\n HSTR_OUT=\"${HSTR_OUT%%x}\"" + "\n if [[ \"${HSTR_OUT}\" == *$'\\n' ]]; then" + "\n BUFFER=\"${HSTR_OUT%%$'\\n'}\"" + "\n CURSOR=${#BUFFER}" + "\n zle redisplay" + "\n zle accept-line" + "\n else" + "\n BUFFER=\"${HSTR_OUT}\"" + "\n CURSOR=${#BUFFER}" + "\n zle redisplay" + "\n fi" "\n}" #if defined(__MS_WSL__) diff --git a/test/sh/tiotcsi-function-bash.sh b/test/sh/tiotcsi-function-bash.sh index 18c492f1..ca769d9c 100755 --- a/test/sh/tiotcsi-function-bash.sh +++ b/test/sh/tiotcsi-function-bash.sh @@ -1,5 +1,21 @@ #!/usr/bin/env bash -# This script is used to experiment with Bash functions in order to set +# +# Copyright (C) 2014-2026 Martin Dvorak +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# This script is used to experiment with Bash functions in order to set # the content of the terminal prompt without TIOCSTI ioctl() call. # # IMPORTANT: to use the functions below @ Bash @@ -42,7 +58,7 @@ function mysimple { # HSTR prints out command which user selected after using ^ # ^ is set to READLINE_LINE # prompt cursor is set to the end of line by setting READLINE_POINT to 1000 (blindly) - + { READLINE_LINE=$(foohstr ${PROMPT_STR_BEFORE}) 2>&1; } # move cursor to the end of prompt READLINE_POINT=${#READLINE_LINE} @@ -60,7 +76,7 @@ function hstrdebug { echo "Readline point: '${READLINE_POINT}'" READLINE_POINT=0 - + # OBSERVATIONS: # {hstrout}>&1 ... is VALID expression # {hstrout} > &1 ... is INVALID expression @@ -91,7 +107,7 @@ function hstrdebug { # # bind '"\C-r": "\C-a hstr -- \C-j"' -# - bind +# - bind # ... Bash command which binds key sequence (Ctrl-r) to a command, # bind INSERTS the command to the terminal # - "\C-r" @@ -195,4 +211,10 @@ function hstrnotiocsti { if [[ $- =~ .*i.* ]]; then bind -x '"\C-r": "hstrnotiocsti"'; fi export HSTR_TIOCSTI=n +# NOTE: Due to bash 'bind -x' limitations, commands cannot be auto-executed +# from the bind function. You need to press ENTER twice: once to select +# in HSTR, and once more to execute the command. This is a known bash +# limitation that cannot be worked around. ZSH users can use 'zle accept-line' +# to auto-execute commands. + # eof diff --git a/test/sh/tiotcsi-function-zsh.sh b/test/sh/tiotcsi-function-zsh.sh index 80ee9682..0b081be4 100755 --- a/test/sh/tiotcsi-function-zsh.sh +++ b/test/sh/tiotcsi-function-zsh.sh @@ -1,4 +1,19 @@ #!/usr/bin/env bash +# +# Copyright (C) 2014-2026 Martin Dvorak +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# # ################################################################## # EXAMPLE: NOT WORKING version @@ -26,16 +41,16 @@ foohstr() { hstrnotiocsti() { local word - # we need the WHOLE buffer, not just 0 to cursor: word=${BUFFER[0,CURSOR]} + # we need the WHOLE buffer, not just 0 to cursor: word=${BUFFER[0,CURSOR]} BUFFER="$(foohstr ${BUFFER})" CURSOR=${#BUFFER} - # update the display + # update the display zle redisplay } -# create ZLE widget ~ readline function +# create ZLE widget ~ readline function zle -N hstrnotiocsti -# bind widget to keyboard shortcut +# bind widget to keyboard shortcut bindkey '\C-r' hstrnotiocsti # ################################################################## @@ -87,10 +102,18 @@ export HSTR_TIOCSTI=n hstr_no_tiocsti() { zle -I - { HSTR_OUT="$( { &1 1>&3 3>&- )"; } 3>&1; - BUFFER="${HSTR_OUT}" - CURSOR=${#BUFFER} - zle redisplay + { HSTR_OUT="$( { &2; } 2>&1 1>&3 3>&-; )"; } 3>&1; + HSTR_OUT="${HSTR_OUT%x}" + if [[ "${HSTR_OUT}" == *$'\n' ]]; then + BUFFER="${HSTR_OUT%$'\n'}" + CURSOR=${#BUFFER} + zle redisplay + zle accept-line + else + BUFFER="${HSTR_OUT}" + CURSOR=${#BUFFER} + zle redisplay + fi } zle -N hstr_no_tiocsti bindkey '\C-r' hstr_no_tiocsti