4

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
endfunction

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

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()
endwile

Here is the example.

Original file:

start/weights-e55_ta0.98_va0.96.ckpt
Extracting frames 
Using precomputed keys
Done, 1247 frames
acc1 1
acc2 2
acc3 3
acc4 5
end
start/weights-e18_ta0.84_va0.12.ckpt
Extracting frames 
Using precomputed keys
Done, 1247 frames
acc1 5
acc2 2
acc3 3
acc4 4
end

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
start/weights-e55_ta0.98_va0.96.ckpt
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
3

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)

ADD

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')
            break
        endif
    endfor
    call append(0, printf("Block %s: %s", block, acc))
endfunction
g/start/.;/end/call ProcessBlock()

PS

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.