2

I often have a situation where I will direct some output to a file then open it in vim and use ex commands (substitution, keep lines, delete lines, etc) to massage the output to a form I want. However sometimes I end up wanting to apply the same transformation to another set of text soon afterwards. I have to up arrow through all the commands and try and apply them in the same order again, which is slow and error prone.

I am trying to see if there is something like Ctrl-o in the shell where you can select a certain history item then just replay all the commands after that in order by repeating a key. Does such a thing exist in vim?

(Just to preempt any comments that try to point this out, I know that if I was going to be doing this transformation frequently I should just make a shell command. This is for one-off jobs where the feedback in vim is useful.)

2

FWIW, I have a similar mapping on C-o.

Extracted as a standalone script, it should give something like this:

cno <expr> <c-o> <sid>operate_and_get_next()

augroup operate_and_get_next
    au!
    au CmdlineEnter : call timer_start(0, {-> s:operate_and_get_next_remember('on_leave')})
augroup END

let s:HISTORY_MAX_SIZE = 10
fu s:operate_and_get_next() abort
    let cmdline = getcmdline()
    let history = get(s:, 'cmdline_history', [])
    let s:pos_in_history = (index(history, cmdline) + 1) % len(history)
    if len(history) == 0
        return ''
    endif
    let seq = history[s:pos_in_history]
    return "\<cr>:"..seq
endfu

fu s:operate_and_get_next_remember(when) abort
    if mode() isnot# 'c'
        return
    endif
    if a:when is# 'on_leave'
        au CmdlineLeave : ++once call s:operate_and_get_next_remember('now')
    else
        let cmdline = getcmdline()
        let history = get(s:, 'cmdline_history', [])
        if cmdline is# ''
            return
        endif
        let s:cmdline_history = history + [cmdline]
        if len(history) > s:HISTORY_MAX_SIZE
            call remove(s:cmdline_history, 0)
        endif
    endif
endfu

No idea how reliable it is because in practice, I rarely use it.

| improve this answer | |
2

One great way to have access to multiple commands in your history is to use the command-line window, which you can access with the q: normal-mode command, or by pressing Ctrl+F from the Ex : command-line prompt.

From that window, you can yank the sequence of commands you're interested on (e.g. using a motion or visual mode), then quit the command window (with :q) and put the commands back into a normal buffer.

From there, you can edit/tweak/reorder your Ex commands and then use any method to store and execute multiple Ex commands repeatedly.

The easiest way to do it probably being storing the sequence of commands into a *.vim file and then using the :source command to execute the script.

Or you can turn the sequence into a function and storing it in your vimrc or a file that gets loaded automatically when Vim is started (such as a file named *.vim under ~/.vim/plugin/), then use :call to invoke the function or perhaps define a user command for improved usability.

Finally, one quick way to reuse them that doesn't involve creating new files is to yank the sequence of commands into a register and use the :@" command (assuming the default register, :@a to use "a, etc.) to execute the contents of the register as an Ex command.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.