9

For my Windows Terminal using Powershell I have the plugin PSReadline which gives me some pretty handy features. For instance a navigatable list view of my history when I start typing. So if I type cd it gives me a list of the 10 most recents commands I used containing cd, and I can move up and down that list and select one.

Screenshot of PSReadline - scrollable history

Another feature I love is that I can type cd and press Tab to display a list of all subdirectories I can navigate to. I can also press up/down/left/right to select a directory in this list and jump to it.

Screenshot of PSReadline - directory selection

Is it possible to make something similar for the WSL (Ubuntu) prompt? I am using oh-my-posh for the prompt in both Powershell and WSL btw. I suspect that oh-my-zsh might have something for this, but I would love to avoid installing it as I have spent a lot of time setting up my theme for oh-my-posh. Unless there's a way of using oh-my-zsh plugins without the themes.

2
  • 1
    I'm voting to close this question as too broad because it's unlikely that there is a particular piece of software that has exactly the same behavior as PSReadLine. You should ask one question per feature. Also, it's unclear whether you're asking about bash or about zsh: pick one. Commented Nov 18, 2021 at 17:38
  • What you describe here looks like built-in features, but not enabled by default or with different key bindings. For the first feature, look for something like “history completion”. For the second feature, look for “menu completion”. Commented Nov 18, 2021 at 17:40

4 Answers 4

4

Bash, which is the default shell in Ubuntu and most GNU/Linux distribution, does not come with support for most of these fancy features. Though you can get closer with a couple tweaks to the configuration file. Zsh is another shell that has extra functionalities. There is no interactive menu-based completion in Bash, while there is in Zsh. In both Zsh and Bash, you have a couple of ways to get history search.

To install Zsh on Ubuntu, run sudo apt install zsh and then you can change your default shell using chsh or just run zsh from Bash to switch to Zsh once. You need to run Zsh once to generate the default configuration file. The configuration files of Bash and Zsh are in your home folder, ~/.bashrc and ~/.zshrc respectively. Close and open the shell (terminal) after modifying the config file for it to take effect. I personally don't recommend the use of oh-my-zsh as it is a 3rd party plugin system that is unnecessary and slow. Everything it does can be done manually.

Also, Oh My Posh works for any shell, including Zsh. You don't have to give it up if you switch to Zsh.
Here is the official documentation. Click on "zsh" in the list to get the Zsh configuration instructions. It requires adding eval "$(oh-my-posh init zsh)" to your .zshrc
This should be all you have to do if you already got Oh My Posh working in Bash, and it should use the same theme.

Menu-based completion in Zsh

This stuff is required for basic auto-completion in Zsh and might already be in your .zshrc

autoload -Uz compinit
compinit

If you get a compinit insecure directories error, it is probably because you didn't go trough the assisted default .zshrc generation and enabled compinit. Try to run compinit -C or compaudit | xargs chmod g-w. More info about this here.

Now that you have basic auto-completion, the following configuration line will enable the interactive menu.

zstyle ':completion:*' menu yes select

With the configuration above, you will be able to hit tab to get an interactive menu that you can navigate with the arrow keys. Arrow keys will control the menu instead of the cursor the second that you hit tab once. If you want to have to press tab a second time before getting "in" the menu, remove "yes".

zstyle ':completion:*' menu select

History Searching

Ctrl+R - out of the box searching

Bash

<Ctrl>-R searches the command history as you type.

                     👇 # what we type will display here
$ (reverse-i-search)`test': python -m unittest reverse_singly_linked_list.py
                                          👆 # match begins here (is highlighted)

You can hit <Ctrl>-R again while searching to go to the second matching result, and so on. When you see the command you want to use, you can press enter to run it or the left/right arrow keys to edit it. If you hit the up/down arrow, you will navigate the history above and below the command. You can press <Ctrl>-C or <Ctrl>-G to exit the search.

Zsh

In Zsh it works the same, but it looks a little different.

               👇 #  match begins here (is underlined)
% python -m unittest reverse_singly_linked_list.py
bck-i-search: test_
              👆 # what we type will display here

The search box and search result are not on the same line for added clarity.

History search with arrow keys

By default, in both Bash and Zsh, pressing <Ctrl>-P/<Ctrl>-N or using the up/down arrows allows you to navigate your command history in chronological order without any search functionality.
You can configure both Bash and Zsh to search your command history, just like you use the up and down arrow keys to navigate it. For instance, if you type cd and press a custom keybinding, you can quickly see the last command that starts with cd.
Here is how to replace <Ctrl>-P/<Ctrl>-N or up/down arrow with the history search functionality. Personally, I replace <Ctrl>-P/<Ctrl>-N so that the arrow keys keep their default behaviour.

Bash

Replace <Ctrl>-P/<Ctrl>-N:

bind '"\C-p": history-search-backward'
bind '"\C-n": history-search-forward'

Replace up and down arrow:

bind '"\e[A": history-search-backward'
bind '"\e[B": history-search-forward'

Zsh

Replace <Ctrl>-P/<Ctrl>-N:

bindkey "^P" history-beginning-search-backward
bindkey "^N" history-beginning-search-forward

Replace up and down arrow:

bindkey '\e[A' history-beginning-search-backward
bindkey '\e[B' history-beginning-search-forward

3rd party programs

These 3rd party programs can get you extremely close to the functionality of PSReadLine.

fzf

fzf allows you to quickly filter and select items from a list by typing a few characters, and it will present a live, interactive interface that updates as you type. It can be used in simple shell scripts for multiple use cases, like for searching for files on your system, or in our case, command history.

Installing fzf on Ubuntu: sudo apt install fzf

Then add this to your shell's config file to replace <Ctrl>-R with fzf:

Bash:

source /usr/share/doc/fzf/examples/key-bindings.bash

Zsh:

source /usr/share/doc/fzf/examples/key-bindings.zsh

There is also this fzf script for Zsh. It might do more thing than the built-in fzf history search?

HSTR

HSTR is a replacement for <Ctrl>+R written in C for both Bash and Zsh. HSTR can also manage your command history.

Installing HSTR on Ubuntu: sudo apt install hstr

Check the documentation for configuration

zsh-history-substring-search

zsh-history-substring-search is similar to the "history search with arrow keys" config, but with this, you can search for any part of the command, it does not have to be with the start. For example, if you have run man cd in the past, and you type cd <up arrow>, you will get man cd. Only for Zsh.


Reference

"Stop pressing the up (arrow) to find a previous command" by David W
"A Guide to the Zsh Completion with Examples" by Matthieu Cneude
"A Practical Guide to fzf: Shell Integration" by Matthieu Cneude
Bash Keyboard Shortcuts
Bash Reference Manual
The Z Shell Manual
Luke Smith's .zshrc

2
  • I accidentally gave my bounty to another answer 🤡 Thank you
    – Expurple
    Commented Nov 3, 2023 at 6:12
  • sadly, none of the above does exactly what the question asks for ! I mean it is close enough, but how hard is it to make the shell shows a list of history commands as you type without using any key or shortcut or a script?
    – Nour
    Commented Jun 23 at 12:33
0

hstr allows to search and navigate history as a list, but I don't know how to do that for regular tab completion (commands/files). Hopefully, somebody answers

0
+50

Does it have to be PSReadLine compatible? This does not give you exactly the same behavior, but maybe it is sufficient for your operational purpose:

  1. The bash built-in history command gives you an indexed list of the last N commands (with N being configured by your distribution). If you want to execute the command at index 1013 you type !1013 at the bash prompt.
  2. The key combination <Ctrl>-R allows you to enter a search string and will present you with the last matching command as you continue typing. If you enter <Ctrl>-R again, an earlier match is searched. If you have found the right command press <Enter> to execute it. If you want to edit it instead, use the arrow key left. If you want to leave the search enter <Ctrl>-G.

There are more options to work with bash history. You may want to rephrase your question ignoring PSReadLine, if working with bash history is sufficient for your use case.

1
  • Misclicked the bounty, I wanted to give it to @mutageneral
    – Expurple
    Commented Nov 3, 2023 at 6:15
0

I finally figured out how to do the exact behavior. ZSH is the only one that could give me identical results:

#!/bin/bash
# This is done in bash; we'll switch to zsh when we're ready
# install dependencies: zsh and git.
sudo apt install -y zsh git

# Get the oh-my-zsh plugins and copy over the example zsh config
git clone https://github.com/ohmyzsh/ohmyzsh.git ~/.oh-my-zsh
cp ~/.oh-my-zsh/templates/zshrc.zsh-template ~/.zshrc

# clone the zsh-autocomplete plugin
git clone https://github.com/marlonrichert/zsh-autocomplete.git ~/.oh-my-zsh/plugins/zsh-autocomplete

# add the plugin to .zshrc:
sed -i 's/plugins=(/&zsh-autocomplete /' ~/.zshrc

# configure the autocomplete to show history commands rather than suggested commands
echo "zstyle ':autocomplete:*' default-context history-incremental-search-backward" >> $ZSH/oh-my-zsh.sh

# configure the list to be shown only when you type (the default is always visible)
echo "zstyle ':autocomplete:*' min-input 1" >> $ZSH/oh-my-zsh.sh

# eliminate duplication in the list
echo "setopt HIST_FIND_NO_DUPS" >> $ZSH/oh-my-zsh.sh;

source ~/.zshrc

Of course don't forget to switch to zsh (if you are installing it for the first time) for this to work.

enter image description here

1

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .