From 6c77fd9101f84a32c463ddd1753996ce28beaa03 Mon Sep 17 00:00:00 2001 From: EinfachToll Date: Fri, 15 May 2015 10:56:46 +0200 Subject: [PATCH] :VimwikiRebuildTags! only reads files newer than .tags file Ref #85 --- autoload/vimwiki/tags.vim | 135 +++++++++++++++++++++++--------------- ftplugin/vimwiki.vim | 5 +- 2 files changed, 84 insertions(+), 56 deletions(-) diff --git a/autoload/vimwiki/tags.vim b/autoload/vimwiki/tags.vim index f81ff76..45e86b6 100644 --- a/autoload/vimwiki/tags.vim +++ b/autoload/vimwiki/tags.vim @@ -5,8 +5,8 @@ let s:TAGS_METADATA_FILE_NAME = '.tags' " Tags metadata in-memory format: -" metadata := [ entry, ... ] -" entry := { 'tagname':..., 'pagename':..., 'lineno':..., 'link':... } +" metadata := { 'pagename': [entries, ...] } +" entry := { 'tagname':..., 'lineno':..., 'link':... } " Tags metadata in-file format: " @@ -23,7 +23,9 @@ let s:TAGS_METADATA_FILE_NAME = '.tags' " Update tags metadata. " a:full_rebuild == 1: re-scan entire wiki " a:full_rebuild == 0: only re-scan current page -function! vimwiki#tags#update_tags(full_rebuild) "{{{ +" a:all_files == '': only if the file is newer than .tags +function! vimwiki#tags#update_tags(full_rebuild, all_files) "{{{ + let all_files = a:all_files != '' if !a:full_rebuild " Updating for one page (current) let page_name = VimwikiGet('subdir') . expand('%:t:r') @@ -34,26 +36,31 @@ function! vimwiki#tags#update_tags(full_rebuild) "{{{ " Drop old tags let metadata = s:remove_page_from_tags(metadata, page_name) " Merge in the new ones - let metadata = s:merge_tags(metadata, tags) + let metadata = s:merge_tags(metadata, page_name, tags) " Save call s:write_tags_metadata(metadata) else " full rebuild let files = vimwiki#base#find_files(g:vimwiki_current_idx, 0) - let metadata = [] + let tags_file_last_modification = getftime(s:metadata_file_path()) + let metadata = vimwiki#tags#load_tags_metadata() for file in files - let page_name = fnamemodify(file, ':t:r') - let tags = s:scan_tags(readfile(file), page_name) - let metadata = s:merge_tags(metadata, tags) + if all_files || getftime(file) >= tags_file_last_modification + let page_name = fnamemodify(file, ':t:r') + let tags = s:scan_tags(readfile(file), page_name) + let metadata = s:remove_page_from_tags(metadata, page_name) + let metadata = s:merge_tags(metadata, page_name, tags) + endif endfor call s:write_tags_metadata(metadata) endif endfunction " }}} " s:scan_tags -" Scans the list of text lines (argument) and produces tags metadata. +" Scans the list of text lines (argument) and produces tags metadata as a +" list of tag entries. function! s:scan_tags(lines, page_name) "{{{ - let metadata = [] + let entries = [] let page_name = a:page_name " Code wireframe to scan for headers -- borrowed from @@ -110,7 +117,6 @@ function! s:scan_tags(lines, page_name) "{{{ " Create metadata entry let entry = {} let entry.tagname = tag - let entry.pagename = page_name let entry.lineno = line_nr if line_nr <= (header_line_nr + PROXIMITY_LINES_NR) let entry.link = page_name . '#' . current_complete_anchor @@ -120,12 +126,12 @@ function! s:scan_tags(lines, page_name) "{{{ else let entry.link = page_name . '#' . tag endif - call add(metadata, entry) + call add(entries, entry) endfor endwhile endfor " loop over lines - return metadata + return entries endfunction " }}} " s:metadata_file_path @@ -139,9 +145,9 @@ endfunction " }}} function! vimwiki#tags#load_tags_metadata() abort "{{{ let metadata_path = s:metadata_file_path() if !filereadable(metadata_path) - return [] + return {} endif - let metadata = [] + let metadata = {} for line in readfile(metadata_path) if line =~ '^!_TAG_FILE_' continue @@ -171,12 +177,16 @@ function! vimwiki#tags#load_tags_metadata() abort "{{{ if len(vw_fields) != 2 throw 'VimwikiTags5: Metadata file corrupted' endif + let pagename = vw_fields[0] let entry = {} let entry.tagname = std_fields[0] - let entry.pagename = vw_fields[0] let entry.lineno = std_fields[2] let entry.link = vw_fields[1] - call add(metadata, entry) + if has_key(metadata, pagename) + call add(metadata[pagename], entry) + else + let metadata[pagename] = [entry] + endif endfor return metadata endfunction " }}} @@ -185,47 +195,56 @@ endfunction " }}} " Removes all entries for given page from metadata in-place. Returns updated " metadata (just in case). function! s:remove_page_from_tags(metadata, page_name) "{{{ - let metadata = filter(a:metadata, - \ "v:val.pagename != '" . substitute(a:page_name, "'", "''", '') . "'") - return metadata + if has_key(a:metadata, a:page_name) + call remove(a:metadata, a:page_name) + return a:metadata + else + return a:metadata + endif endfunction " }}} " s:merge_tags -" Merges two tags metadata objects into (new) one. -function! s:merge_tags(metadata1, metadata2) "{{{ - return a:metadata1 + a:metadata2 +" Merges metadata of one file into a:metadata +function! s:merge_tags(metadata, pagename, file_metadata) "{{{ + let metadata = a:metadata + let metadata[a:pagename] = a:file_metadata + return metadata endfunction " }}} " s:write_tags_metadata " Saves metadata object into a file. Throws exceptions in case of problems. function! s:write_tags_metadata(metadata) "{{{ let metadata_path = s:metadata_file_path() - let entries = [] - for entry in a:metadata - let entry_data = entry.pagename . "\t" . entry.link - let entry_data = substitute(entry_data, "\\", '\\\\', 'g') - let entry_data = substitute(entry_data, "\t", '\\t', 'g') - let entry_data = substitute(entry_data, "\r", '\\r', 'g') - let entry_data = substitute(entry_data, "\n", '\\n', 'g') - call add(entries, - \ entry.tagname . "\t" - \ . entry.pagename . VimwikiGet('ext') . "\t" - \ . entry.lineno - \ . ';"' - \ . "\t" . "vimwiki:" . entry_data - \) + let tags = [] + for pagename in keys(a:metadata) + for entry in a:metadata[pagename] + let entry_data = pagename . "\t" . entry.link + let entry_data = substitute(entry_data, "\\", '\\\\', 'g') + let entry_data = substitute(entry_data, "\t", '\\t', 'g') + let entry_data = substitute(entry_data, "\r", '\\r', 'g') + let entry_data = substitute(entry_data, "\n", '\\n', 'g') + call add(tags, + \ entry.tagname . "\t" + \ . pagename . VimwikiGet('ext') . "\t" + \ . entry.lineno + \ . ';"' + \ . "\t" . "vimwiki:" . entry_data + \) + endfor endfor - call sort(entries) - call insert(entries, "!_TAG_FILE_SORTED\t1\t{anything}") - call writefile(entries, metadata_path) + call sort(tags) + call insert(tags, "!_TAG_FILE_SORTED\t1\t{anything}") + call writefile(tags, metadata_path) endfunction " }}} " vimwiki#tags#get_tags " Returns list of unique tags found in metadata function! vimwiki#tags#get_tags(metadata) "{{{ let tags = {} - for entry in a:metadata - let tags[entry.tagname] = 1 + for entries in values(a:metadata) + for entry in entries + let tags[entry.tagname] = 1 + endfor endfor return keys(tags) endfunction " }}} @@ -244,21 +263,29 @@ function! vimwiki#tags#generate_tags(...) abort "{{{ \ '', \ substitute(g:vimwiki_rxH1_Template, '__Header__', 'Generated Tags', '') ]) - call sort(metadata) + " make a dictionary { tag_name: [tag_links, ...] } + let tags_entries = {} + for entries in values(metadata) + for entry in entries + if has_key(tags_entries, entry.tagname) + call add(tags_entries[entry.tagname], entry.link) + else + let tags_entries[entry.tagname] = [entry.link] + endif + endfor + endfor let bullet = repeat(' ', vimwiki#lst#get_list_margin()). \ vimwiki#lst#default_symbol().' ' - let current_tag = '' - for entry in metadata - if need_all_tags || index(specific_tags, entry.tagname) != -1 - if entry.tagname != current_tag - let current_tag = entry.tagname - call append(line('$'), [ - \ '', - \ substitute(g:vimwiki_rxH2_Template, '__Header__', entry.tagname, ''), - \ '' ]) - endif - call append(line('$'), bullet . '[[' . entry.link . ']]') + for tagname in sort(keys(tags_entries)) + if need_all_tags || index(specific_tags, tagname) != -1 + call append(line('$'), [ + \ '', + \ substitute(g:vimwiki_rxH2_Template, '__Header__', tagname, ''), + \ '' ]) + for taglink in tags_entries[tagname] + call append(line('$'), bullet . '[[' . taglink . ']]') + endfor endif endfor endfunction " }}} diff --git a/ftplugin/vimwiki.vim b/ftplugin/vimwiki.vim index 9466e75..f61c7eb 100644 --- a/ftplugin/vimwiki.vim +++ b/ftplugin/vimwiki.vim @@ -310,7 +310,8 @@ command! -buffer VimwikiDiaryNextDay call vimwiki#diary#goto_next_day() command! -buffer VimwikiDiaryPrevDay call vimwiki#diary#goto_prev_day() " tags commands -command! -buffer VimwikiRebuildTags call vimwiki#tags#update_tags(1) +command! -buffer -bang + \ VimwikiRebuildTags call vimwiki#tags#update_tags(1, '') command! -buffer -nargs=* -complete=custom,vimwiki#tags#complete_tags \ VimwikiSearchTags VimwikiSearch /::/ command! -buffer -nargs=* -complete=custom,vimwiki#tags#complete_tags @@ -652,7 +653,7 @@ endif if VimwikiGet('auto_tags') " Automatically update tags metadata on page write. augroup vimwiki - au BufWritePost call vimwiki#tags#update_tags(0) + au BufWritePost call vimwiki#tags#update_tags(0, '') augroup END endif " AUTOCOMMANDS }}}