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!