Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

hstr stops working on linux >=6.2.0 (depending on kernel config) #478

Open
leapfog opened this issue Feb 20, 2023 · 65 comments
Open

hstr stops working on linux >=6.2.0 (depending on kernel config) #478

leapfog opened this issue Feb 20, 2023 · 65 comments

Comments

@leapfog
Copy link

leapfog commented Feb 20, 2023

Just wanted to leave a note, that hstr stops working with linux kernel 6.2.0, when CONFIG_LEGACY_TIOCSTI isn't set. So maybe you want to add that information to a trouble shooting guide or FAQ or something.

(re: "stops working": the history can still be browsed, but cannot be inserted anymore)

@BlueMax
Copy link

BlueMax commented Feb 28, 2023

Edit: Never mind, probably only switchable with CONFIG_LEGACY_TIOCSTI=y.

How is this meant to be done?

This functionality can be changed at runtime with the dev.tty.legacy_tiocsti sysctl. This configuration option sets the default value of the sysctl.
https://cateee.net/lkddb/web-lkddb/LEGACY_TIOCSTI.html

It can't be set though.

# sysctl -w dev.tty.legacy_tiocsti=1
sysctl: setting key "dev.tty.legacy_tiocsti": Invalid argument
# echo 1 > /proc/sys/dev/tty/legacy_tiocsti
bash: echo: write error: Invalid argument

Arch Linux 6.2.1

@sxe
Copy link

sxe commented Mar 2, 2023

I came here as well cause hstr stopped working.
Could we get an official reply on how this situation will be handled? Will hstr be adjusted to work without it?
I would rather not enable a legacy option.

Cheers

@rajakesar
Copy link

❯ uname -r
6.2.1-arch1-1

❯ date
Thu Mar 2 10:38:30 AM EST 2023

Hstr is confirmed NOT working on the above kernel as of the time above.

@jakedane
Copy link

jakedane commented Mar 2, 2023

If you run zgrep CONFIG_LEGACY_TIOCSTI /proc/config.gz you can see CONFIG_LEGACY_TIOCSTI is not set for 6.2.1-arch1-1. If indeed hstr insertion is not working because CONFIG_LEGACY_TIOCSTI is not set then this is why for 6.2.1-arch1-1.

@mmeier86
Copy link

mmeier86 commented Mar 2, 2023

I can confirm that it's the CONFIG_LEGACY_TIOCSTI option. I had the same problem after I updated my Gentoo to 6.2, and after reenabling that option in my Kernel, it started to work again with 6.2.

@leapfog
Copy link
Author

leapfog commented Mar 3, 2023

Seems fzf's history search is still working, even without CONFIG_LEGACY_TIOCSTI, so there is a way.

@jakedane
Copy link

jakedane commented Mar 4, 2023

Seems fzf's history search is still working, even without CONFIG_LEGACY_TIOCSTI, so there is a way.

fzf has a bash function around it for the history function, that sets the readline input buffer with the history line that was selected in fzf. The same can be done with hstr!

What I did:

  1. Build hstr with DEBUG_NO_TIOCSTI set. You just need to uncomment this line and recompile hstr: https://github.com/dvorka/hstr/blob/master/src/hstr_utils.c#L29. With DEBUG_NO_TIOCSTI set hstr doesn't use the insecure TIOCSTI and instead prints the selected history line to stderr. On Arch Linux I did this with:
auracle download hstr
cd hstr
makepkg -so
sed -i -r 's|//(#define DEBUG_NO_TIOCSTI)|\1|' src/hstr-*/src/hstr_utils.c
makepkg -e
sudo pacman -U hstr-*.zst
  1. We don't want the selected history line on stderr, we want it in the readline input buffer. I couldn't fully follow how fzf was doing that but on the wiki there is an example for bash: https://github.com/junegunn/fzf/wiki/Examples#with-write-to-terminal-capabilities. I used the 3rd example, the one starting with # re-wrote the script above, and adjusted it a bit for hstr. Basically: call hstr, redirect its stderr to a file so that can be read back into a variable and then pass that variable to the function from the wiki that sets the readline input buffer. Add this to your ~/.bashrc:
bind '"\C-r": "\C-x1\e^\er"'
bind -x '"\C-x1": __hstr';

__hstr ()
{
	hstr 2> ~/.hstr.tmp
	hstr_tmp=$(< ~/.hstr.tmp)
	__ehc "$hstr_tmp"
}

__ehc()
{
if
        [[ -n $1 ]]
then
        bind '"\er": redraw-current-line'
        bind '"\e^": magic-space'
        READLINE_LINE=${READLINE_LINE:+${READLINE_LINE:0:READLINE_POINT}}${1}${READLINE_LINE:+${READLINE_LINE:READLINE_POINT}}
        READLINE_POINT=$(( READLINE_POINT + ${#1} ))
else
        bind '"\er":'
        bind '"\e^":'
fi
}
  1. And you need to disable the default hstr keybindings in your ~/.bashrc so comment out these lines:
# if this is interactive shell, then bind hstr to Ctrl-r (for Vi mode check doc)
if [[ $- =~ .*i.* ]]; then bind '"\C-r": "\C-a hstr -- \C-j"'; fi
# if this is interactive shell, then bind 'kill last command' to Ctrl-x k
if [[ $- =~ .*i.* ]]; then bind '"\C-xk": "\C-a hstr -k \C-j"'; fi

Now if I open a new terminal, press Ctrl+R, hstr works again and the selected history line is placed on the readline input.

I don't fully understand all of the above — and it can probably be cleaned up and made nicer — but at least I have a working hstr again.

@BlueMax
Copy link

BlueMax commented Mar 4, 2023

CopyQ is another candidate that still works. I'm not sure but i think they load the clipboard and send a keystroke via X11 to paste the text.

@papavlos
Copy link

papavlos commented Mar 4, 2023

Thanks @jakedane for the workaround. It works!
There is a small issue - pressing Enter on selected command in history places the command into input buffer but without automatic execution. I have to press Enter again, but this is very small issue.

@Mte90
Copy link

Mte90 commented Mar 8, 2023

I am on debian sid and stopped working too with 6.2.2-2-siduction-amd64 #1 SMP PREEMPT_DYNAMIC siduction 6.2-2.1 (2023-03-06) x86_64 GNU/Linux

apt source hstr
sed -i -r 's|//(#define DEBUG_NO_TIOCSTI)|\1|' src/hstr_utils.c
debuild -uc -us

Compiled with the patch, it still not work. I just get the command in the terminal after the selection compared to before.

immagine

@jakedane
Copy link

jakedane commented Mar 8, 2023

Compiled with the patch, it still not work. I just get the command in the terminal after the selection compared to before.

That sounds like you did step 1 from #478 (comment) but didn't proceed with step 2 and 3 to modify your .bashrc file (and open a new terminal after).

@Mte90
Copy link

Mte90 commented Mar 9, 2023

So I tried that bash changes and in this way works only Ctrl+r not hh as example (I tried changing the bash-completion script):

#
# Copyright (C) 2014-2022  Martin Dvorak <martin.dvorak@mindforger.com>
#
# 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.

# Bash completion support for HSTR

# Source this file or install it to /usr/share/bash-completion/completions or /etc/bash_completion.d/
# See https://iridakos.com/tutorials/2018/03/01/bash-programmable-completion-tutorial.html
# help complete
# complete -W "--favorites --kill-last-command --non-interactive --show-configuration --show-zsd-configuration --show-blacklist --version --help" hstr

bind '"\C-r": "\C-x1\e^\er"'
bind -x '"\C-x1": _hstr';

#_hstr()
#{
#        local cur prev OPTS
#        COMPREPLY=()
#        cur="${COMP_WORDS[COMP_CWORD]}"
#        prev="${COMP_WORDS[COMP_CWORD-1]}"
#        case $prev in
#                '-h'|'--help'|'-v'|'--version')
#                        return 0
#                        ;;
#        esac
#        case $cur in
#                -*)
#                        OPTS="--favorites --kill-last-command --non-interactive --show-configuration --show-zsd-configuration --show-blacklist --version --help"
#                        COMPREPLY=( $(compgen -W "${OPTS[*]}" -- $cur) )
#                        return 0
#                        ;;
#        esac
#        compopt -o bashdefault
#        COMPREPLY=( $(compgen -c -- $cur) )
#        return 0
#}

_hstr ()
{
	hstr 2> /tmp/.hstr.tmp
	hstr_tmp=$(< /tmp/.hstr.tmp)
	__ehc "$hstr_tmp"
}

__ehc()
{
if
        [[ -n $1 ]]
then
        bind '"\er": redraw-current-line'
        bind '"\e^": magic-space'
        READLINE_LINE=${READLINE_LINE:+${READLINE_LINE:0:READLINE_POINT}}${1}${READLINE_LINE:+${READLINE_LINE:READLINE_POINT}}
        READLINE_POINT=$(( READLINE_POINT + ${#1} ))
else
        bind '"\er":'
        bind '"\e^":'
fi
}
complete -F _hstr hstr
complete -F _hstr hh

# eof

@leapfog
Copy link
Author

leapfog commented Mar 14, 2023

While I still hope for hstr to be modified to work without CONFIG_LEGACY_TIOCSTI, kernel 6.2.x has been fixed, so re-enabling it at runtime is now possible:

# sysctl -w dev.tty.legacy_tiocsti=1 # fix hstr
dev.tty.legacy_tiocsti = 1

I only confirmed that with linux-6.2.6 today, but it might also have worked earlier.

@karlovskiy
Copy link

I can confirm that with 6.2.5-arch1-1 re-enabling sysctl -w dev.tty.legacy_tiocsti=1 is now also works.

@Mte90
Copy link

Mte90 commented Mar 16, 2023

I can confirm too on Debian sid (siduction) with 6.2.6-1 the hstr package from debian repository works again.

@chrischmo
Copy link

chrischmo commented Mar 16, 2023

Re-enabling sysctl -w dev.tty.legacy_tiocsti=1 also works on OpenSUSE Tumbleweed (6.2.4-1-default) with hstr from the lemmy04 repo.

@dvorka dvorka added the :finnadie: blocker label Mar 18, 2023
@dvorka dvorka self-assigned this Mar 18, 2023
@dvorka dvorka pinned this issue Mar 18, 2023
@dvorka dvorka added this to the 2.7 Pipe and pattern editor milestone Mar 18, 2023
dvorka added a commit that referenced this issue Mar 18, 2023
@dvorka dvorka linked a pull request Mar 18, 2023 that will close this issue
@dvorka
Copy link
Owner

dvorka commented Mar 18, 2023

@Mte90 @chrischmo @karlovskiy @leapfog @jakedane @papavlos @mmeier86 thank you all for detailed descriptions of the problem, root cause identification and proposed solutions!

I worked on a version of HSTR for Cygwin and WSL where TIOCSTI is not available in the past. If you are able to build HSTR and you use Bash, can you please try #481?

The PR just enables existing HSTR functionality to work w/o TIOCSTI w/ the new define. I did not used it in the past because it requires shell command (and many users will not (be able to) do such configuration).

Anyway if the PR will work for you, I will fix it also for zsh (which I use on 90% of my machines) and release a new version.

Do you think that it would make sense to release HSTR with a TIOCSTI parameter allowing to run version with or without TIOCSTI use? Is there any way how to safely detect TIOCSTI availability? Will it compile on systems with new kernel?

Thank you all your interest in HSTR and your help!

@jakedane
Copy link

@dvorka I built hstr with #481 and with LINUX_KERNEL_6 defined, I put the new config in my .bashrc and with that Ctrl+R works properly in Bash. Thank you!

I'm on Arch Linux with kernel 6.2.6. No issue compiling.

I don't know how to safely detect TIOCSTI is available. Probably too hacky and not portable but on Linux if sysctl -ne dev.tty.legacy_tiocsti prints 0 (zero) that means TIOCSTI is disabled.

@dvorka
Copy link
Owner

dvorka commented Mar 18, 2023

Preliminary TIOCSTI design:

  • .bashrc/.zshrc function:
    • detects TIOCSTI and based on that:
      • call the right Bash/zsh function which binds to the shortcut
      • hstr command w/ or w/o --no-tiocsti parameter
  • hstr binary:
    • detects TIOCSTI and based on that it either uses it or not
      • hstr binary supports both modes
      • #define is not used to compile only one option

.bashrc

  • detect whether TIOCSTI is supported by the kernel @ Bash
  • based on whether TIOCSTI is available bind keyword shortcuts
    either to hstr command or hstrcygwin Bash function
# detect TIOCSTI
function is_tiocsti {
    if test -w /dev/tty && { stty -echo; echo -n a | tioctl TIOCSTI; stty echo; } >/dev/null 2>&1; then
        echo "TIOCSTI is supported by the kernel."
    else
        echo "TIOCSTI is not supported by the kernel."
    fi
}

# command binding
if is_tiocsti
then
    # if this is interactive shell, then bind hstr to Ctrl-r (for Vi mode check doc)
    if [[ $- =~ .*i.* ]]; then bind '"\C-r": "\C-a hstr -- \C-j"'; fi
    # if this is interactive shell, then bind 'kill last command' to Ctrl-x k
    if [[ $- =~ .*i.* ]]; then bind '"\C-xk": "\C-a hstr -k \C-j"'; fi
else
    if [[ $- =~ .*i.* ]]; then bind -x '"\C-r": "hstrcygwin"'; fi
fi 

Detect TIOCSTI from C:

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
#include <sys/ioctl.h>

int main() {
   int fd;
   struct termios t;
   fd = open("/dev/tty", O_RDWR);
   if (fd < 0) {
      perror("open /dev/tty");
      exit(1);
   }
   if (tcgetattr(fd, &t) < 0) {
      perror("tcgetattr");
      exit(1);
   }
   if (!ioctl(fd, TIOCSTI, "a")) {
      printf("TIOCSTI supported\n");
   } else {
      printf("TIOCSTI not supported\n");
   }
   close(fd);
   return 0;
}

@jakedane
Copy link

jakedane commented Mar 18, 2023

The C code detects TIOCSTI correctly. I tested it both with dev.tty.legacy_tiocsti=0 and dev.tty.legacy_tiocsti=1.

The bash code does not detect it correctly. is_tiocsti always responds "TIOCSTI is supported by the kernel."

Edit: ah, removing the redirect to /dev/null I get tioctl: command not found.

@dvorka
Copy link
Owner

dvorka commented Mar 19, 2023

@jakedane thank you for testing the code! It really helped. As tioctl command does not have to be present on the system, I will always hstr - I will create a hstr parameter which will make the test (and use it in .bashrc/.zshrc).

dvorka added a commit that referenced this issue Mar 19, 2023
…, updating year to 2023, removing WIP defines for TIOCSTI debugging #478
@dvorka
Copy link
Owner

dvorka commented Mar 19, 2023

FYI working on the fix @ dev-2.7.0 branch.

@Gooberpatrol66
Copy link

oh, i didn't see the bashrc changed

@eleius
Copy link

eleius commented Sep 27, 2023

I forgot I was still using the sysctl "fix", so I removed it and now hstr doesn't work for me.

I'm using hstr 3.1.0 on arch linux, kernel 6.5.5, and my bashrc has the same lines as in jakedane's comment above.

I can search history but pressing enter doesn't select the entry, it only echo'es it.
If I set dev.tty.legacy_tiocsti=1 it works.

@jakedane
Copy link

I can search history but pressing enter doesn't select the entry, it only echo'es it.

You have to press Enter twice. 1st Enter puts the selected history item on the bash prompt, 2nd Enter runs it.

If any expect hstr to work differently (that 1st Enter runs the command directly), I think that needs to be a separate issue.

@jessienab
Copy link

I can search history but pressing enter doesn't select the entry, it only echo'es it.

You have to press Enter twice. 1st Enter puts the selected history item on the bash prompt, 2nd Enter runs it.

If any expect hstr to work differently (that 1st Enter runs the command directly), I think that needs to be a separate issue.

@eleius another suggestion is to select your command, use TAB to bring it to your prompt, and then press enter; removing the need to hit Enter twice.

@eleius
Copy link

eleius commented Sep 28, 2023

@jakedane @jasonnab I've already tried Tab+Enter and Enter+Enter, but for some reason when I press either Tab or Enter, the selected history item is just displayed as when you type the echo command (hstr doesn't bring it to the bash prompt.)
I've tried deleting my current .bashrc and only placing the hstr lines in it, but still same issue. Don't know why it doesn't work.

@quicktrick
Copy link

@eleius, don't be upset. I have hstr behaving exactly the same way on Void Linux 6.3.13.

@Mte90
Copy link

Mte90 commented Dec 5, 2023

any update for this issue?
when it is planned a new release?

@jakedane
Copy link

jakedane commented Dec 5, 2023

@Mte90 hstr 3.1.0 fixed the issue. Currently with bash 5.2.21 in gnome-terminal 3.50.1 (vte 0.74.1) on Arch Linux, kernel 6.6.3, with the output of hstr --show-configuration in the .bashrc file, that works without problems. The kernel is not compiled with CONFIG_LEGACY_TIOCSTI set and dev.tty.legacy_tiocsti is also not set.

If it doesn't work for you, what specifically are you using?

@Mte90
Copy link

Mte90 commented Dec 5, 2023

I didn't saw the new parameter for bash export HSTR_TIOCSTI=y I think that now it should work.

@Dennysium
Copy link

I have the same problem on Ubuntu, since the upgrade to 24.04. That is kernel 6.8.0-31-generic and hstr 3.1.0 from the Ubuntu repos.

@jakedane
Copy link

@Dennysium it's your configuration. Compare hstr --show-configuration output with what you have in your .bashrc file.

@Dennysium
Copy link

@Dennysium it's your configuration. Compare hstr --show-configuration output with what you have in your .bashrc file.

Thank you. I have appended the hstr --show-configuration output to my .bashrc, but still having the problem.

@Dennysium
Copy link

Dennysium commented May 21, 2024

I have updated a second pc to Ubuntu 24.04 (This is a Kubuntu machine). I have appended the output of hstr --show-configuration to my .bashrc file and run source ~/.bashrc. I have the described problem.

@jakedane
Copy link

The NO_TIOCSTI issues were fixed with hstr 3.1.0. There's no problem with hstr on Ubuntu 24.04 for me. If it doesn't work for you, your configuration is wrong. Did you scrub the old configuration? It only works with bash or zsh.

@Dennysium
Copy link

@jakedane
Thank you for the clarification.
I run bash, this is my bashrc. The latter part is what I appended from hstrt --show-configuration:

 # ~/.bashrc: executed by bash(1) for non-login shells.
 # see /usr/share/doc/bash/examples/startup-files (in the package bash-doc)
 # for examples
 
 # If not running interactively, don't do anything
 case $- in
     *i*) ;;
       *) return;;
 esac
 
 # don't put duplicate lines or lines starting with space in the history.
 # See bash(1) for more options
 #HISTCONTROL=ignoreboth
 
 # append to the history file, don't overwrite it
 shopt -s histappend
 
 # for setting history length see HISTSIZE and HISTFILESIZE in bash(1)
 #HISTSIZE=1000
 #HISTFILESIZE=2000
 
 # check the window size after each command and, if necessary,
 # update the values of LINES and COLUMNS.
 shopt -s checkwinsize
 
 # If set, the pattern "**" used in a pathname expansion context will
 # match all files and zero or more directories and subdirectories.
 #shopt -s globstar
 
 # make less more friendly for non-text input files, see lesspipe(1)
 [ -x /usr/bin/lesspipe ] && eval "$(SHELL=/bin/sh lesspipe)"
 
 # set variable identifying the chroot you work in (used in the prompt below)
 if [ -z "${debian_chroot:-}" ] && [ -r /etc/debian_chroot ]; then
     debian_chroot=$(cat /etc/debian_chroot)
 fi
 
 # set a fancy prompt (non-color, unless we know we "want" color)
 case "$TERM" in
     xterm-color|*-256color) color_prompt=yes;;
 esac
 
 # uncomment for a colored prompt, if the terminal has the capability; turned
 # off by default to not distract the user: the focus in a terminal window
 # should be on the output of commands, not on the prompt
 #force_color_prompt=yes
 
 if [ -n "$force_color_prompt" ]; then
     if [ -x /usr/bin/tput ] && tput setaf 1 >&/dev/null; then
 	# We have color support; assume it's compliant with Ecma-48
 	# (ISO/IEC-6429). (Lack of such support is extremely rare, and such
 	# a case would tend to support setf rather than setaf.)
 	color_prompt=yes
     else
 	color_prompt=
     fi
 fi
 
 if [ "$color_prompt" = yes ]; then
     PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '
 else
     PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ '
 fi
 unset color_prompt force_color_prompt
 
 # If this is an xterm set the title to user@host:dir
 case "$TERM" in
 xterm*|rxvt*)
     PS1="\[\e]0;${debian_chroot:+($debian_chroot)}\u@\h: \w\a\]$PS1"
     ;;
 *)
     ;;
 esac
 
 # enable color support of ls and also add handy aliases
 if [ -x /usr/bin/dircolors ]; then
     test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval "$(dircolors -b)"
     alias ls='ls --color=auto'
     #alias dir='dir --color=auto'
     #alias vdir='vdir --color=auto'
 
     alias grep='grep --color=auto'
     alias fgrep='fgrep --color=auto'
     alias egrep='egrep --color=auto'
 fi
 
 # colored GCC warnings and errors
 #export GCC_COLORS='error=01;31:warning=01;35:note=01;36:caret=01;32:locus=01:quote=01'
 
 # some more ls aliases
 alias ll='ls -alF'
 alias la='ls -A'
 alias l='ls -CF'
 
 # Add an "alert" alias for long running commands.  Use like so:
 #   sleep 10; alert
 alias alert='notify-send --urgency=low -i "$([ $? = 0 ] && echo terminal || echo error)" "$(history|tail -n1|sed -e '\''s/^\s*[0-9]\+\s*//;s/[;&|]\s*alert$//'\'')"'
 
 # Alias definitions.
 # You may want to put all your additions into a separate file like
 # ~/.bash_aliases, instead of adding them here directly.
 # See /usr/share/doc/bash-doc/examples in the bash-doc package.
 
 if [ -f ~/.bash_aliases ]; then
     . ~/.bash_aliases
 fi
 
 # enable programmable completion features (you don't need to enable
 # this, if it's already enabled in /etc/bash.bashrc and /etc/profile
 # sources /etc/bash.bashrc).
 if ! shopt -oq posix; then
   if [ -f /usr/share/bash-completion/bash_completion ]; then
     . /usr/share/bash-completion/bash_completion
   elif [ -f /etc/bash_completion ]; then
     . /etc/bash_completion
   fi
 fi
 #My custom aliases
 alias libreoffice="flatpak run org.libreoffice.LibreOffice/x86_64/stable"
 
 
 # HSTR configuration - add this to ~/.bashrc
 alias hh=hstr                    # hh to be alias for hstr
 export HSTR_CONFIG=hicolor       # get more colors
 shopt -s histappend              # append new history items to .bash_history
 export HISTCONTROL=ignorespace   # leading space hides commands from history
 export HISTFILESIZE=10000        # increase history file size (default is 500)
 export HISTSIZE=${HISTFILESIZE}  # increase history size (default is 500)
 # ensure synchronization between bash memory and history file
 export PROMPT_COMMAND="history -a; history -n; ${PROMPT_COMMAND}"
 function hstrnotiocsti {
     { READLINE_LINE="$( { </dev/tty hstr ${READLINE_LINE}; } 2>&1 1>&3 3>&- )"; } 3>&1;
     READLINE_POINT=${#READLINE_LINE}
 }
 # if this is interactive shell, then bind hstr to Ctrl-r (for Vi mode check doc)
 if [[ $- =~ .*i.* ]]; then bind -x '"\C-r": "hstrnotiocsti"'; fi
 export HSTR_TIOCSTI=n

@Dennysium
Copy link

Just one more important note:
Whe I use Ctrl + R ton invoke hstr, it works as expected. It does not work with hstr searchterm

@sbrl
Copy link

sbrl commented Jun 17, 2024

On Linux DEVICE_NAME 6.9.4-artix1-1 #1 SMP PREEMPT_DYNAMIC Wed, 12 Jun 2024 21:17:50 +0000 x86_64 GNU/Linux, hstr behaves as I would expect with the following in my .bashrc:

if [ "${NO_HH}" != "true" ] && [[ $- =~ .*i.* ]]; then
	# hh / hstr configuration (https://github.com/dvorka/hstr/)
	export HSTR_CONFIG=hicolor	# get more colors
	
	hstr_loc="";
	if which hh >/dev/null 2>&1; then
		hstr_loc="hh";
	elif which hstr >/dev/null 2>&1; then
		hstr_loc="hstr";
	fi
	
	hstr_mode="$($hstr_loc --is-tiocsti)";
	
	if [[ "${hstr_mode}" == "n" ]]; then
		# erk, no tiocsti available.
		function hstrnotiocsti {
			{ READLINE_LINE="$( { </dev/tty ${hstr_loc} ${READLINE_LINE}; } 2>&1 1>&3 3>&- )"; } 3>&1;
			READLINE_POINT=${#READLINE_LINE}
		}
		# if this is interactive shell, then bind hstr to Ctrl-r (for Vi mode check doc)
		if [[ $- =~ .*i.* ]]; then bind -x '"\C-r": "hstrnotiocsti"'; fi
		export HSTR_TIOCSTI=n

	else
		# tiocsti is enabled, bind as normal
		bind '"\C-r": "\C-a '"${hstr_loc}"' \C-j"';
	fi
	
	unset hstr_mode
	unset hstr_loc
fi

....in other words, hstr puts the command you select into the command prompt for you to review, and then hitting enter again will execute the command.

....if you are like me and have a version-controlled bin and .bashrc, then this may be useful if you simultaneously use machines with kernel versions both above and below 6.2.0.

Edit: it's mysteriously stopped working today. Investigating.

@pavel-kalmykov
Copy link

For the record, it does not work with kernel 6.9.3-76060903-generic and zsh either. My .zshrc file has the same contents as in hstr --show-configuration.

@epistax1s
Copy link

July 18, 2024

Kernel version: 6.8.0-38-generic
hstr version: 3.1.0 (2023-04-18T08:50:00)
I have placed hstr --show-configuration in my ~/.zshrc file.

It still doesn't work. The command is just printed but not executed (it worked on earlier versions of Linux).

@caretech-ca
Copy link

caretech-ca commented Aug 13, 2024

Same issue here: command is echoed, not executed.

Mint 22, using bash
Kernel version: 6.8.0-40-generic #40-Ubuntu SMP PREEMPT_DYNAMIC
hstr version: "3.1.0" (2023-04-18T08:50:00)

hstr --show-configuration contents are appended to ~/.bashrc

It works from a root prompt ( sudo -i ) but not as regular user.

@mortan
Copy link

mortan commented Sep 5, 2024

Same behavior for me (commands are echo'd but not executed):

uname -r
6.10.7-arch1-1

ZSH shell.

Is there any workaround for this problem?

Edit: ok this seems to work: #452 (comment)

@rickardlindberg
Copy link

I use my own selection program instead of hstr. I also ran in to the problem that TIOCSTI does not work on newer Linux kernel versions. After much searching and reading, I figured out how to fix it.

Even though I use my own selection program, I think I got the Bash integration from hstr initially. Here is the snipped I used in .bashrc:

if [[ $- =~ .*i.* ]]; then bind '"\C-r": "\C-a rlselect-history \C-j"'; fi

Here is how rlselect-history looked like:

set -e

result=$(tac ~/.bash_history | rlselect --tab --action -- "$@")

python - "$result" << EOF
import fcntl
import sys
import termios

action, selection = sys.argv[1].split("\n", 1)

if action != "tab":
    selection += "\n"

for ch in selection:
    fcntl.ioctl(sys.stdout.fileno(), termios.TIOCSTI, ch)
EOF

It calls rlselect, my selection program, and then has the Bash integration which I think I got the idea from from hstr. (rlselect outputs two lines. The first is the action taken within the program, and the second is the selection itself.) If enter was pressed, a newline is appended to the selection to simulate enter being pressed in the terminal which makes it execute the selection.

The new snippet that I came up with for .bashrc looks like this:

rlselect-history() {
    local action
    local selection
    {
        read action
        read selection
    } < <(tac ~/.bash_history | rlselect --tab --action -- "${READLINE_LINE}")
    if [ "$action" = "tab" ]; then
        READLINE_LINE="${selection}"
        READLINE_POINT=${#READLINE_LINE}
        bind '"\C-x2":' # Bind Ctrl+x+2 to do nothing
    elif [ "$action" = "enter" ]; then
        READLINE_LINE="${selection}"
        READLINE_POINT=${#READLINE_LINE}
        bind '"\C-x2": accept-line' # Bind Ctrl+x+2 to accept line
    else
        bind '"\C-x2":' # Bind Ctrl+x+2 to do nothing
    fi
}

if [[ $- =~ .*i.* ]]; then
    # Bind history commands to Ctrl+x+1 followed by Ctrl+x+2:
    bind '"\C-r": "\C-x1\C-x2"'
    # Bind Ctrl+x+1 to execute rlselect-history which does two things:
    # 1. Sets READLINE_*
    # 2. Binds Ctrl+x+2 to either accept line or do nothing.
    bind -x '"\C-x1": rlselect-history'
fi

The trick to finding this solution for me was understanding Bash key bindings. This answer on StackOverflow writes the following:

With bind, you can bind keys to do one of three things, but no combination of them:

  • Execute a readline command: bind '"key": command'
  • Execute a series of keystrokes: bind '"key":"keystrokes"'
  • Execute a shell command: bind -x '"key": shell-command'

The old key binding can then be explained as follows:

if [[ $- =~ .*i.* ]]; then bind '"\C-r": "\C-a rlselect-history \C-j"'; fi
  • Ctrl+R is bound to a series of keystrokes.
  • First, Ctrl+A is simulated which takes the cursor to the beginning of the line.
  • Then <space>rlselect-history<space> is typed.
  • Then Ctrl+J is simulated which means accept the current line. Or execute it. The initial space entered in the previous step ensures that the rlselect-history command does not end up in the history. The moving of the cursor to the beginning of the line ensures that anything typed at the prompt is passed as an argument to rlselect-history.

(This also makes the text rlselect-history ... appear in the terminal. The new solution makes that go away.)

Let's break down the new key bindings the same way:

if [[ $- =~ .*i.* ]]; then
    # Bind history commands to Ctrl+x+1 followed by Ctrl+x+2:
    bind '"\C-r": "\C-x1\C-x2"'
    # Bind Ctrl+x+1 to execute rlselect-history which does two things:
    # 1. Sets READLINE_*
    # 2. Binds Ctrl+x+2 to either accept line or do nothing.
    bind -x '"\C-x1": rlselect-history'
fi
  • Ctrl+R is bound to a series of keystrokes.

  • First Ctrl+X+1 is simualted.

  • Then Ctrl+X+2 is simulated.

  • Ctrl+X+1 is bound to execute the command rlselect-history. The -x to bind ensures that variables READLINE_* can be set. From man bash on set -x:

    Cause shell-command to be executed whenever keyseq is entered. When shell-command is executed, the shell sets the READLINE_LINE variable to the contents of the readline line buffer and the READLINE_POINT and READLINE_MARK variables [...] If the executed command changes the value of any of READLINE_LINE, READLINE_POINT, or READLINE_MARK, those new values will be reflected in the editing state.

  • rlselect-history is defined as a Bash function which allows it to reconfigure the key binding for Ctrl+X+2. Depending on if the current selection should be executed or not, it binds Ctrl+X+2 to either accept-line or nothing.

So the new mechanism relies on using two extra key bindings: Ctrl+X+1 and Ctrl+X+2. I chose them because I don't use them otherwise. But they can be any two key bindings.

Perhaps that makes it difficult to provide as a default config for hstr. But I thought I'd share my findings here in case it would help anyone.

I think a similar solution is presented in this thread and in other places. I didn't fully understand those examples when I first read them. I think now I do becasue of my new understanding of how Bash works. Hopefully my explanation can add value to someone.

@dvorka
Copy link
Owner

dvorka commented Jan 27, 2025

I'm reopening this issue because it's not completely resolved...

@dvorka dvorka reopened this Jan 27, 2025
@dvorka dvorka pinned this issue Jan 27, 2025
@dvorka dvorka unpinned this issue Jan 27, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.