diff --git a/autoload/vimwiki/base.vim b/autoload/vimwiki/base.vim index 9bb7e9f..1e59779 100644 --- a/autoload/vimwiki/base.vim +++ b/autoload/vimwiki/base.vim @@ -465,10 +465,9 @@ endfunction " }}} " vimwiki#base#generate_links function! vimwiki#base#generate_links() "{{{ + let lines = [] + let links = vimwiki#base#get_wikilinks(g:vimwiki_current_idx, 0) - - call append(line('$'), substitute(g:vimwiki_rxH1_Template, '__Header__', 'Generated Links', '')) - call sort(links) let bullet = repeat(' ', vimwiki#lst#get_list_margin()). @@ -476,10 +475,15 @@ function! vimwiki#base#generate_links() "{{{ for link in links let abs_filepath = vimwiki#path#abs_path_of_link(link) if !s:is_diary_file(abs_filepath) - call append(line('$'), bullet. + call add(lines, bullet. \ substitute(g:vimwiki_WikiLinkTemplate1, '__LinkUrl__', '\='."'".link."'", '')) endif endfor + + let links_rx = '\m^\s*'.vimwiki#u#escape(vimwiki#lst#default_symbol()).' ' + + call vimwiki#base#update_listing_in_buffer(lines, 'Generated Links', links_rx, + \ line('$')+1, 1) endfunction " }}} " vimwiki#base#goto @@ -1087,6 +1091,74 @@ function! vimwiki#base#nested_syntax(filetype, start, end, textSnipHl) abort "{{ endif endfunction "}}} +" creates or updates auto-generated listings in a wiki file, like TOC, diary +" links, tags list etc. +" - the listing consists of a level 1 header and a list of strings as content +" - a:content_regex is used to determine how long a potentially existing list is +" - a:default_lnum is the line number where the new listing should be placed if +" it's not already present +" - if a:create is true, it will be created if it doesn't exist, otherwise it +" will only be updated if it already exists +function! vimwiki#base#update_listing_in_buffer(strings, start_header, + \ content_regex, default_lnum, create) "{{{ + " apparently, Vim behaves strange when files change while in diff mode + if &diff || &readonly + return + endif + + " check if the listing is already there + let already_there = 0 + + let header_rx = '\m^\s*'. + \ substitute(g:vimwiki_rxH1_Template, '__Header__', a:start_header, '') + \ .'\s*$' + + let start_lnum = 1 + while start_lnum <= line('$') + if getline(start_lnum) =~# header_rx + let already_there = 1 + break + endif + let start_lnum += 1 + endwhile + + if !already_there && !a:create + return + endif + + let old_cursor_pos = getpos('.') + + if already_there + " delete the old listing + let whitespaces_in_first_line = matchstr(getline(start_lnum), '\m^\s*') + let end_lnum = start_lnum + 1 + while end_lnum <= line('$') && getline(end_lnum) =~# a:content_regex + let end_lnum += 1 + endwhile + silent exe start_lnum.','.string(end_lnum - 1).'delete _' + else + let start_lnum = a:default_lnum + let whitespaces_in_first_line = '' + endif + + " write new listing + let new_header = whitespaces_in_first_line + \ . substitute(g:vimwiki_rxH1_Template, + \ '__Header__', '\='."'".a:start_header."'", '') + call append(start_lnum - 1, new_header) + let start_lnum += 1 + for string in a:strings + call append(start_lnum - 1, string) + let start_lnum += 1 + endfor + " append an empty line if there is not one + if start_lnum <= line('$') && getline(start_lnum) !~# '\m^\s*$' + call append(start_lnum - 1, '') + endif + + call setpos('.', old_cursor_pos) +endfunction "}}} + " WIKI link following functions {{{ " vimwiki#base#find_next_link function! vimwiki#base#find_next_link() "{{{ @@ -1630,44 +1702,6 @@ endfunction " }}} " a:create == 1: creates or updates TOC in current file " a:create == 0: update if TOC exists function! vimwiki#base#table_of_contents(create) - " apparently, Vim behaves strange when files change while in diff mode - if &diff - return - endif - - " look for existing TOC - let toc_header = '^\s*'.substitute(g:vimwiki_rxH1_Template, '__Header__', - \ '\='."'".g:vimwiki_toc_header."'", '').'\s*$' - let toc_line = 0 - let lnum = 1 - while lnum <= &modelines + 2 && lnum <= line('$') - if getline(lnum) =~# toc_header - let toc_line = lnum - break - endif - let lnum += 1 - endwhile - - if !a:create && toc_line <= 0 - return - endif - - let old_cursor_pos = getpos('.') - let bullet = vimwiki#lst#default_symbol().' ' - let rx_bullet = vimwiki#u#escape(bullet) - let whitespaces = matchstr(getline(toc_line), '^\s*') - - " delete old TOC - if toc_line > 0 - let endoftoc = toc_line+1 - while endoftoc <= line('$') && getline(endoftoc) =~# '^\s*'.rx_bullet.g:vimwiki_rxWikiLink.'\s*$' - let endoftoc += 1 - endwhile - silent exe toc_line.','.string(endoftoc-1).'delete _' - else - let toc_line = 1 - endif - " collect new headers let headers = [] let headers_levels = [['', 0], ['', 0], ['', 0], ['', 0], ['', 0], ['', 0]] @@ -1678,6 +1712,9 @@ function! vimwiki#base#table_of_contents(create) endif let h_level = vimwiki#u#count_first_sym(line_content) let h_text = vimwiki#u#trim(matchstr(line_content, g:vimwiki_rxHeader)) + if h_text ==# g:vimwiki_toc_header " don't include the TOC's header itself + continue + endif let headers_levels[h_level-1] = [h_text, headers_levels[h_level-1][1]+1] for idx in range(h_level, 5) | let headers_levels[idx] = ['', 0] | endfor @@ -1700,25 +1737,23 @@ function! vimwiki#base#table_of_contents(create) call add(headers, [h_level, h_complete_id, h_text]) endfor - " write new TOC - call append(toc_line-1, whitespaces . substitute(g:vimwiki_rxH1_Template, - \ '__Header__', '\='."'".g:vimwiki_toc_header."'", '')) - + let lines = [] let startindent = repeat(' ', vimwiki#lst#get_list_margin()) let indentstring = repeat(' ', vimwiki#u#sw()) + let bullet = vimwiki#lst#default_symbol().' ' for [lvl, link, desc] in headers let esc_link = substitute(link, "'", "''", 'g') let esc_desc = substitute(desc, "'", "''", 'g') let link = substitute(g:vimwiki_WikiLinkTemplate2, '__LinkUrl__', \ '\='."'".'#'.esc_link."'", '') let link = substitute(link, '__LinkDescription__', '\='."'".esc_desc."'", '') - call append(toc_line, startindent.repeat(indentstring, lvl-1).bullet.link) - let toc_line += 1 + call add(lines, startindent.repeat(indentstring, lvl-1).bullet.link) endfor - if getline(toc_line+1) !~# '^\s*$' - call append(toc_line, '') - endif - call setpos('.', old_cursor_pos) + + let links_rx = '\m^\s*'.vimwiki#u#escape(vimwiki#lst#default_symbol()).' ' + + call vimwiki#base#update_listing_in_buffer(lines, g:vimwiki_toc_header, links_rx, + \ 1, a:create) endfunction "}}} diff --git a/autoload/vimwiki/diary.vim b/autoload/vimwiki/diary.vim index d131efe..540a766 100644 --- a/autoload/vimwiki/diary.vim +++ b/autoload/vimwiki/diary.vim @@ -121,36 +121,31 @@ fun! s:group_links(links) "{{{ return result endfun "}}} -fun! s:sort(lst) "{{{ +function! s:sort(lst) "{{{ if VimwikiGet("diary_sort") ==? 'desc' return reverse(sort(a:lst)) else return sort(a:lst) endif -endfun "}}} +endfunction "}}} -fun! s:format_diary(...) "{{{ +function! s:format_diary(...) "{{{ let result = [] - call add(result, substitute(g:vimwiki_rxH1_Template, '__Header__', VimwikiGet('diary_header'), '')) - if a:0 let g_files = s:group_links(s:get_diary_links(a:1)) else let g_files = s:group_links(s:get_diary_links()) endif - " for year in s:rev(sort(keys(g_files))) for year in s:sort(keys(g_files)) call add(result, '') call add(result, substitute(g:vimwiki_rxH2_Template, '__Header__', year , '')) - " for month in s:rev(sort(keys(g_files[year]))) for month in s:sort(keys(g_files[year])) call add(result, '') call add(result, substitute(g:vimwiki_rxH3_Template, '__Header__', s:get_month_name(month), '')) - " for [fl, cap] in s:rev(sort(items(g_files[year][month]))) for [fl, cap] in s:sort(items(g_files[year][month])) if empty(cap) let entry = substitute(g:vimwiki_WikiLinkTemplate1, '__LinkUrl__', fl, '') @@ -165,46 +160,8 @@ fun! s:format_diary(...) "{{{ endfor endfor - call add(result, '') return result -endfun "}}} - -function! s:delete_diary_section() "{{{ - " remove diary section - let old_pos = getpos('.') - let ln_start = -1 - let ln_end = -1 - call cursor(1, 1) - if search(substitute(g:vimwiki_rxH1_Template, '__Header__', VimwikiGet('diary_header'), ''), 'Wc') - let ln_start = line('.') - if search(g:vimwiki_rxH1, 'W') - let ln_end = line('.') - 1 - else - let ln_end = line('$') - endif - endif - - if ln_start < 0 || ln_end < 0 - call setpos('.', old_pos) - return - endif - - if !&readonly - exe ln_start.",".ln_end."delete _" - endif - - call setpos('.', old_pos) -endfunction "}}} - -function! s:insert_diary_section() "{{{ - if !&readonly - let ln = line('.') - call append(ln, s:format_diary()) - if ln == 1 && getline(ln) == '' - 1,1delete - endif - endif endfunction "}}} " Diary index stuff }}} @@ -300,8 +257,9 @@ function! vimwiki#diary#generate_diary_section() "{{{ let current_file = vimwiki#path#path_norm(expand("%:p")) let diary_file = vimwiki#path#path_norm(s:diary_index()) if vimwiki#path#is_equal(current_file, diary_file) - call s:delete_diary_section() - call s:insert_diary_section() + let content_rx = '^\%(\s*\* \)\|\%(^\s*$\)\|\%('.g:vimwiki_rxHeader.'\)' + call vimwiki#base#update_listing_in_buffer(s:format_diary(), + \ VimwikiGet('diary_header'), content_rx, line('$')+1, 1) else echom "vimwiki: You can generate diary links only in a diary index page!" endif diff --git a/autoload/vimwiki/tags.vim b/autoload/vimwiki/tags.vim index 1191673..4bd13a9 100644 --- a/autoload/vimwiki/tags.vim +++ b/autoload/vimwiki/tags.vim @@ -261,10 +261,6 @@ function! vimwiki#tags#generate_tags(...) abort "{{{ let metadata = s:load_tags_metadata() - call append(line('$'), [ - \ '', - \ substitute(g:vimwiki_rxH1_Template, '__Header__', 'Generated Tags', '') ]) - " make a dictionary { tag_name: [tag_links, ...] } let tags_entries = {} for entries in values(metadata) @@ -277,19 +273,28 @@ function! vimwiki#tags#generate_tags(...) abort "{{{ endfor endfor + let lines = [] let bullet = repeat(' ', vimwiki#lst#get_list_margin()). \ vimwiki#lst#default_symbol().' ' for tagname in sort(keys(tags_entries)) if need_all_tags || index(specific_tags, tagname) != -1 - call append(line('$'), [ + call extend(lines, [ \ '', \ substitute(g:vimwiki_rxH2_Template, '__Header__', tagname, ''), \ '' ]) for taglink in tags_entries[tagname] - call append(line('$'), bullet . '[[' . taglink . ']]') + call add(lines, bullet . + \ substitute(g:vimwiki_WikiLinkTemplate1, '__LinkUrl__', taglink, '')) endfor endif endfor + + let links_rx = '\m\%(^\s*$\)\|\%('.g:vimwiki_rxH2.'\)\|\%(^\s*' + \ .vimwiki#u#escape(vimwiki#lst#default_symbol()).' ' + \ .g:vimwiki_rxWikiLink.'$\)' + + call vimwiki#base#update_listing_in_buffer(lines, 'Generated Tags', links_rx, + \ line('$')+1, 1) endfunction " }}} " vimwiki#tags#complete_tags