72
votes

Is modal editing possible in command-line mode?

Some examples:

  • After writing !ls ~/foo/bar I want to db to delete bar
  • I executed the above command and now I want to change ls to mv and jump back to $
6

6 Answers

122
votes

By default you can press Control + f (or otherwise see set cedit) when on the Vim command-line, which opens the command-line window where you can edit the command using normal-mode Vim editing keys. Enter will run the command or Control + c will return you to the standard command-line.

So in your specific example, you could press Control + f on the Vim command-line then db and it would do what you want.

When I have to do more sophisticated editing commands I use the above approach because I'm more familiar with Vim editing keys than I am with the alternatives. I also find the normal-mode vim keys more powerful.

See :help c_ctrl-f for more information.

27
votes

in vim's command line mode: <ctrl-w> deletes a word

in normal mode: q: goes to the command history (which can be edited with vim commands)

see :help cmdline-editing and :help cmdline-window for more commands.

16
votes

Built-in hotkeys for movement and editing in Command-line mode

<Esc>        abandon command-line without executing it
CTRL-C       abandon command-line without executing it

CTRL-B       cursor to begin of command-line
CTRL-E       cursor to end   of command-line

CTRL-F       opens the command-line window (unless a different key is specified in 'cedit')

CTRL-H       delete the character  in front of the cursor (same as <Backspace>)
CTRL-W       delete the word       in front of the cursor
CTRL-U       delete all characters in front of the cursor

CTRL-P       recall previous command-line from history (that matches pattern in front of the cursor)
CTRL-N       recall next     command-line from history (that matches pattern in front of the cursor)
<Up>         recall previous command-line from history (that matches pattern in front of the cursor)
<Down>       recall next     command-line from history (that matches pattern in front of the cursor)
<S-Up>       recall previous command-line from history
<S-Down>     recall next     command-line from history
<PageUp>     recall previous command-line from history
<PageDown>   recall next     command-line from history

<S-Left>     cursor one word left
<C-Left>     cursor one word left
<S-Right>    cursor one word right
<C-Right>    cursor one word right

<LeftMouse>  cursor at mouse click

Reference: :help ex-edit-index

(Sorry for the overlap with older answers. Hopefully this complete°, structured overview is useful nevertheless.)
° as of 2014 – new keyboard shortcuts may have been added since then

8
votes

Search for :help cmdline-editingin Vim.

It will give a list of shortcut working in command line mode.

An extract for your current problem :

CTRL-B or <Home>                    *c_CTRL-B* *c_<Home>*
    cursor to beginning of command-line
CTRL-E or <End>                     *c_CTRL-E* *c_<End>*
    cursor to end of command-line
<S-Left> or <C-Left>                    *c_<C-Left>*
    cursor one WORD left
                        *c_<S-Right>*
<S-Right> or <C-Right>                  *c_<C-Right>*
    cursor one WORD right

or use q: as mentioned by Rene which allows you to edit previous typed commands in different modes.

5
votes

Plugins for "Normal mode"-like Command-line editing

emacscommandline makes the command-line mode behave more like the Unix command line, by adding Emacs-style mappings (like in the Bash shell). Some of the mappings just map existing vim commands, but the rest implement functionality that is not available natively.

conomode.vim implements a kind of Normal mode ( "Cmdline-Normal mode" ) on top of the Command line. Purpose is similar to the cmdline-window (q:), but navigation and editing can be done in-place. Of course the cmdline-window is much more powerful.

Conomode does not replace Vim's native emacs-style command line editing, it just adds one key: CTRL-O (see below).

  • enter with c_ (press CTRL-O while in Command-line mode)
  • mode indicator is a colon ":", moved along with the cursor, hiding the char under it
  • quit to Cmdline-mode with I, i, a, A, : or any unmapped key (which then executes or inserts itself), or wait 60 seconds.
  • quit to Normal mode with Esc

(Admittedly, I don't understand the point of this plugin, since instead of hitting Ctrl+O to enter its Cono-mode, you could just as quickly pop up the command-line window with Ctrl+F.)

There might be other plugins out there. → https://www.google.com/webhp?q=command-line+editing+plugin+vim

Instead of employing a full-blown plugin, or as a complement to it, you can define your own mappings. → See my other answer.

3
votes

Custom mappings that replicate Normal mode commands

You can manually map specific Normal commands to keystrokes in Command-line mode.

For example the following set of mappings will make Alt+h in Command-line mode go one character left, Alt+k recall the previous Ex command and so on, analogously to hjkl in Normal mode.

" provide hjkl movements in Command-line mode via the <Alt> modifier key
cnoremap <expr> <A-h> &cedit. 'h' .'<C-c>'
cnoremap <expr> <A-j> &cedit. 'j' .'<C-c>'
cnoremap <expr> <A-k> &cedit. 'k' .'<C-c>'
cnoremap <expr> <A-l> &cedit. 'l' .'<C-c>'

Since the Alt modifier key is not mapped (to something important) by default, you can in the same fashion pull other (or all) functionality from Normal mode to Insert mode. E.g.: Moving to the beginning of the current word with Alt+b:

" Normal mode command(s) go… --v <-- here
cnoremap <expr> <A-b> &cedit. 'b' .'<C-c>'
cnoremap <expr> <A-w> &cedit. 'w' .'<C-c>'

" make <Alt>+<i> change the first word (typically 
"   the last run Ex :command or the last range, given the case)
cnoremap <expr> <A-i> &cedit. '^cw' .'<C-c>'

You have to copy that code into your vimrc file to have it loaded every time you start vim (you can open that by typing :new $myvimrc starting in Normal mode).