Bash usage of vi or emacs - bash

From a programming standpoint, when you set the bash shell to use vi or emacs via
set -o vi
or
set -o emacs
What is actually going on here? I've been reading a book where it claims the bash shell uses either of these editors for the input to the shell itself, but I thought it may have used readline.

Bash is still using readline. Readline uses either emacs or vi mode and setting the mode switches between the various editor modes. You can check the lib/readline folder in the base source code to see the various key bindings.

According to the man page BASH_BUILTINS(1) (on Fedora 8):
set [--abefhkmnptuvxBCHP] [-o option] [arg ...]
... (skipping all the single letter options)
-o option-name
The option-name can be one of the following:
...
emacs Use an emacs-style command line editing interface. This is
enabled by default when the shell is interactive, unless the
shell is started with the --noediting option.
...
vi Use a vi-style command line editing interface.
I interpret that to mean that bash is directly interpreting the commands for line editing. This option simply sets which command set to use. See the man page for readline(3).

It uses the keystrokes that are familiar to users of one of those editors to edit the command line.
Readline is the facility that provides that feature to Bash and other programs.
From man bash:
READLINE
This is the library that handles reading input when using an interac‐
tive shell, unless the --noediting option is given at shell invocation.
Line editing is also used when using the -e option to the read builtin.
By default, the line editing commands are similar to those of emacs. A
vi-style line editing interface is also available. Line editing can be
enabled at any time using the -o emacs or -o vi options to the set
builtin (see SHELL BUILTIN COMMANDS below). To turn off line editing
after the shell is running, use the +o emacs or +o vi options to the
set builtin.

From what I know, readline is what provides the line-editing functionality for bash.
One proviso: when you press v in vi command mode, you get the full blown vi editor to edit your command line.
From man bash:
READLINE
This is the library that handles reading input when using an interactive shell, unless the --noediting option is given at shell invocation. By default, the line editing commands are similar to those of emacs. A vi-style line editing interface is also available. To turn off line editing after the shell is running, use the +o emacs or +o vi options to the set builtin.
When the shell presents you with a prompt (unless you're in non-editing mode), you're already using readline. You'll either be in emacs mode or vi insert mode (which is why you can just use ESC to get back to vi command mode).

Related

How to NOT execute a command using GNU readline in vi mode on linux

I am used to using readline's vi mode for bash and found this. My question is, from vi mode, having entered some characters, I want to do one of the following:
exit vi mode and discard the command[s] and leave bash at the prompt. I would have thought :q or :q! would do it. I could delete the contents of the buffer and exit I guess but was thinking there was something more elegant.
exit vi mode and leave the the contents of the buffer on the bash command line without executing it.
Note, I did not see the answer in man 3 readline for GNU Readline 8.1

Ctrl-P doesn't work on vi mode of command line editing on mac terminal

https://www.gnu.org/software/bash/manual/html_node/Readline-vi-Mode.html
said we could do set -o vi to use vi mode instead of emacs mode for command line editing.
And the help: ex-edit-index sais
c_CTRL-P CTRL-P after using 'wildchar' with multiple matches:
go to previous match, otherwise: recall older
command-line from history.
However when I press CTRL-P I just got ^P
May I know why ?
Readline's "vi mode" is neither vi nor Vim. It is a partial emulation of vi shoehorned into the command line context.
That <C-p> you are referring to is a Vim command so there is no reason whatsoever to expect it to do anything in that context. Vim's documentation is totally irrelevant in this case.
Search for Vim Mode bindings in $ man readline for the actual bindings at your disposal in that "mode".

How to bind clear to ^L in Ksh

How can i replicate the following bash functionality in KornShell:
bind "\C-l":"clear-screen"
I needed that bind because i'm using set -o vi in bash, and
plan on using it in ksh too.
Trying to use it in ksh prints out an error:
ksh: bind: not found
Sorry to break the news, but as you've noticed this a different between ksh and bash: bind or the ability to define key mappings is not there. Nor is programmable command completion. Historically the Korn shell focused on language design and features and not on interactive terminal capabilities.
GNU bash provides key bindings via the GNU Readline library which was developed and maintained by the same person, Chet Ramey. ksh even in its most recent versions doesn't use this library nor does it provide an equivalant library, as far as I know.
A workaround is to see if you can program the terminal to provide such capabilities. In tmux if you put this in your .tmux.conf configuration file:
bind-key C-l send-keys clear
Then tmux will interpret the Control-l before ksh has a chance to see it and will expand with the string "clear". (Underneath I bet tmux is using the GNU Readline library)
The POSIX standard (which ksh and bash both follow) defines an "alias" command. However an alias name isn't defined to allow control characters. A particular implemenation may do that, but ksh doesn't.
See also https://unix.stackexchange.com/questions/82223/how-to-setup-keyboard-shortcut-that-enters-predefined-text-into-x11-xterminal-vi

Without Emacs, how does Bash command line editing work in Emacs mode?

Without Emacs installed on my Linux system, Bash command line editing default mode is still Emacs. How does this work without Emacs present?
I tried to search the Bash source code, but still can't understand. Does Bash integrate Emacs within itself?
$ set -o
allexport off
braceexpand on
emacs on
: :
vi off
xtrace off
The GNU(1) readline library is what does the heavy lifting for bash (and any other interactive input systems that choose to use it).
That's the source code you should be looking at, if you want to understand how it works.
The readline packages are hosted alongside bash.
(1) Yes, the same GNU that's responsible for the emacs editor.
The reference to emacs has little to do with the emacs editor itself. It refers to the 'style' of key bindings used by the GNU readline library which bash uses. Readline supports two key binding modes - emacs style and vi style. The default is usually emacs style. The readline library is very powerful, but to be honest, in 25 years of Linux use, I've never bothered with most of the advanced features and have never even tried the vi mode (even when VI was my default editor).
Read the section on readline in the bash manual for more details.

bash: vim mode instead of vi mode?

I noticed when in vi mode in bash (i.e. the mode enabled with "set -o vi"), that some commands, such as "diw", that work in vim but not in vi, don't work on the bash command line. Is there an easy way to configure bash so that its keybindings will support vim commands? I would like to be able to enter vim commands on the command line without having to actually start the vim program, as described in this question.
The best way of doing this that I know of would be to use athame.
It can be a surprisingly powerful experience in some cases. I particularly like it for interacting with a repl.
Athame patches your shell to add full Vim support by routing your keystrokes through an actual Vim process. Athame can currently be used to patch readline (used by bash, gdb, python, etc) and/or zsh (which doesn't use readline).
Alternatively I find spacemacs with the eshell to be a reasonably functional if strange solution.
Teach vi-command-mode diw to any software that uses readline (such as bash) by adding this to your ~/.inputrc:
set keymap vi-command
"diw": "bde"
First, the "vi mode" you get with set -o vi is not vi itself. It's an incomplete approximation of vi's behavior built into readline, the command-line editing library used by bash under the hood.
Second, because it is incomplete there's no reason whatsoever to expect every vi command to work.
Third, no, there's no "vim mode" so even less reason to expect any vim commands to work.
Fourth, if you absolutely want to edit the current command-line with Vim-like commands, why don't you go all the way and… actually use Vim:
<C-x><C-e>
That said, $ man readline tells you everything you need to customize its behavior and add bindings.
You can use ble.sh. Which is a command line editor written in pure Bash which replaces the default GNU Readline. I like to call it "zsh for bash".
Appart from vim-style navigation it gives you:
Enhanced completion
Syntax highlighting
Other interesting features
After installation don't forget to add (recommended) to your .bashrc:
# at the start of your .bashrc file
[[ $- == *i* ]] && source /usr/share/blesh/ble.sh --noattach
...
#for vim-style mode
set -o vi
...
#at the end of your .bashrc file
[[ ${BLE_VERSION-} ]] && ble-attach
or you can just:
# at the start of your .bashrc file
source /usr/share/blesh/ble.sh
but this may not work as expected - read this.

Resources