Vim: How to number paragraphs automatically and how to refer to this numbering?

Here's one way to do the ref numbers, with a pair of functions:

function! MakeRefMarkers()
     " Remove spaces from empty lines:
     %s/^ \+$//
     " Mark all spots for ref number:
     %s/^\_$\_.\zs\(\s\|\S\)/_parref_/
     " Initialize ref val:
     let s:i = 0
     " Replace with ref nums:
     %s/^_parref_/\=GetRef()/
endfunction

function! GetRef()
     let s:i += 1
     return s:i . '.  '
endfunction

Then just do it by calling MakeRefMarkers(). It doesn't remove existing ref numbers if they're there, that would require another step. And it doesn't catch first paragraph if it's first line in file (i.e, without preceding blank line). But it does handle situations where there's more than one blank line between paragraphs.


Question One

Here is a function to enumerate paragraphs. Simply do :call EnumeratePara() anywhere in your file. The variable indent can be adjusted as you wish. Let me know if anything needs correcting or explaining.

function! EnumeratePara()
    let indent = 5
    let lnum = 1
    let para = 1
    let next_is_new_para = 1
    while lnum <= line("$")
        let this = getline(lnum)
        if this =~ "^ *$"
            let next_is_new_para=1
        elseif next_is_new_para == 1 && this !~ "^ *$"
            call cursor(lnum, 1)
            sil exe "normal i" . para . repeat(" ", indent-len(para))
            let para+=1
            let next_is_new_para = 0
        else
            call cursor(lnum, 1)
            sil exe "normal i" . repeat(" ", indent)
        endif
        let lnum += 1
    endwhile
endfunction

Question Two

This isn't a very elegant approach, but it seems to work. First of all, here's a function that maps each line in the file to a paragraph number:

function! MapLinesToParagraphs()
    let lnum = 1
    let para_lines = []
    let next_is_new_para = 1
    let current_para = 0
    while lnum <= line("$")
        let this = getline(lnum)
        if this =~ "^ *$"
            let next_is_new_para = 1
        elseif next_is_new_para == 1
            let current_para += 1
            let next_is_new_para = 0
        endif
        call add(para_lines, current_para)
        let lnum += 1
    endwhile
    return para_lines
endfunction

So that para_lines[i] will give the paragraph of line i.

Now we can use the existing IndexByWord() function, and use MapLinesToParagraph() to convert the line numbers into paragraph numbers before we return them:

function! IndexByParagraph(wordlist)
    let temp_dict = {}
    let para_lines = MapLinesToParagraphs()
    for word in a:wordlist
        redir => result
        sil! exe ':g/' . word . '/#'
        redir END
        let tmp_list = split(strtrans(result), "\\^\@ *")
        let res_list = []
        call map(tmp_list, 'add(res_list, str2nr(matchstr(v:val, "^[0-9]*")))')
        call map(res_list, 'para_lines[v:val]')
        let temp_dict[word] = res_list
    endfor
    let result_list = []
    for key in sort(keys(temp_dict))
        call add(result_list, key . ' : ' . string(temp_dict[key])[1:-2])
    endfor
    return join(result_list, "\n")
endfunction

I have not tested these functions very thoroughly, but they seem to work okay, at least in your example text. Let me know how you get on!

Tags:

Vim