I've got a file, containing some output log. It consists of several blocks of information, that start and end with some fixed patterns.

I need to put a summary for each block in the beginning of the file.

Additionally, I'd like to study vim scripting.

I've developed a couple of functions: one of them processes line range and returns a string with the summary, and another one puts this string in the first line of a file.

function! GetBlockSummary(first, last)
    " some text processing

function! ProcessBlock() range
    let summary = GetBlockSummary(a:firstline, a:lastline)
    call append(0, summary)

Then I call them: :/startpattern/;/endpattern/ call ProcessBlock()

Now I've got two problems:

  1. There are many blocks in the file, and it is tedious to repeat the command by hands. This can be solved with putting the call into a macro and then calling that macro with count prefix (say, 90@q, if I have known that there are 90 blocks in the file, and have put the call into the @q register)
  2. But different files have different amount of blocks, and I have to call grep to count them.

So, I'm looking for some while loop example, implementing following pattern:

while /startpattern/ is found
    execute :/startpattern/;/endpattern/ call ProcessBlock()

Here is the example.

Original file:

Extracting frames 
Using precomputed keys
Done, 1247 frames
acc1 1
acc2 2
acc3 3
acc4 5
Extracting frames 
Using precomputed keys
Done, 1247 frames
acc1 5
acc2 2
acc3 3
acc4 4

Each block starts from start/.... and ends with end. Numbers after "e" in weights-e... denote block numbers.

For this example I'd like to have this file prepended with block numbers and acc's that equal 5. It is guaranteed that only one acc\d 5 appears in the block:

Block 55: acc4
Block 18: acc1
Extracting frames 
Using precomputed keys
.... the rest of text
  • example of the file you are processing and the result you want to get would be really good to have. – Maxim Kim Feb 27 at 13:28

You can try this approach, using :h global command:

:g/startpattern/.;/endpattern/ call ProcessBlock
  1. :g/startpattern/ search for startpattern
  2. .;/endpattern/call ProcessBlock when found, use range from current line to endpattern and call your function. (it should be defined with range)


function! ProcessBlock() range
    " get block number
    let block = matchstr(getline(a:firstline), '-e\zs\d\d')
    " get acc 5
    let acc = ''
    for linenr in range(a:firstline+1, a:lastline)
        let line = getline(linenr)
        if line =~ 'acc\d 5'
            let acc = matchstr(line, 'acc\d')
    call append(0, printf("Block %s: %s", block, acc))
g/start/.;/end/call ProcessBlock()


enter image description here

| improve this answer | |
  • Wow! How do you make vim process function? – wl2776 Feb 27 at 14:12
  • 1
    my plugin github.com/habamax/vim-evalvim – Maxim Kim Feb 27 at 14:13
  • And you can do it without a plugin of course, I have just added convenience. – Maxim Kim Feb 27 at 14:14
  • And a cherry on a top - sort all summaries by block numbers: nnoremap <F9> :g/start/.;/end/ call ProcessBlock()<CR>gg:.,/start/-1 sort n<cr> – wl2776 Feb 28 at 8:49
  • no need to gg, just use range starting from line 1, smth like :1,/start/-1 sort n<CR> – Maxim Kim Feb 28 at 11:43

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.