Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vim: How to insert command into command history?

I have a mapping where I can select text and type (leader)av to ack for my visual selection with Ack.vim:

" Visual ack, used to ack for highlighted text
function! s:VAck()
    let old = @"
    norm! gvy
    let @z = substitute(escape(@", '\'), '\n', '\\n', 'g')
    let @" = old
endfunction


" Ack for visual selection
vnoremap <Leader>av :<C-u>call <SID>VAck()<CR>:exe "Ack! ".@z.""<CR>

However, I will frequently want to re-ack for the last thing I searched for, so I type :up to search backwards through my command history for it. Problem is, this method doesn't populate the history!

My question is how can I do one of the following:

  • Insert an entry into the command line history using Vimscript -or-
  • Make the command it builds actually execute as a colon command, so history is populated automatically?

I am fully aware of the the :copen and :colder commands to open and browse to an older quickfix list (which Ack.vim populates), but I would like to know how to solve my above problem because I want to re-ack for the same thing when I know parts of my source code have changed.

like image 893
Andy Ray Avatar asked May 09 '26 04:05

Andy Ray


1 Answers

When they are part of a mapping, commands are not added to the command history.

Adding an item to a specific history is done with the histadd() function:

call histadd("cmd", "e $MYVIMRC")

See :help histadd().

You could start by making your function return the search pattern instead of clobbering your registers:

function! VAck()
    let old = @"
    norm! gvy
    let pat = substitute(escape(@", '\'), '\n', '\\n', 'g')
    let @" = old
    return pat
endfunction

which would allow you to simplify your base mapping:

vnoremap <Leader>av :<C-u>exe "Ack! " . VAck()<CR>

that we now could modify to add the command to the history:

vnoremap <Leader>av :<C-u>let cmd = "Ack! " . VAck() <bar> call histadd("cmd", cmd) <bar> execute cmd<CR>

where you:

  1. build your command, let cmd = "Ack! " . VAck()

  2. add that command to the history, call histadd("cmd", cmd)

  3. execute the command, execute cmd.

The end result is exactly the same as if you had actually typed :Ack! foo.


A few comments…

  • I think that's a good idea, I'll change my config (I already have similar functions and mappings) accordingly.

  • You should use xnoremap instead of vnoremap to restrain your mapping to actual visual mode.

  • In VAck(), yanking to the unnamed register will clobber your system clipboard if you have something like clipboard=unnamed in your config. You should use a specific register instead:

    function! VAck()
        let old = @z
        norm! gv"zy
        let pat = substitute(escape(@z, '\'), '\n', '\\n', 'g')
        let @z = old
        return pat
    endfunction
    
like image 72
romainl Avatar answered May 12 '26 10:05

romainl