:VimwikiRebuildTags! only reads files newer than .tags file

Ref #85
This commit is contained in:
EinfachToll 2015-05-15 10:56:46 +02:00
parent b53dd48429
commit 6c77fd9101
2 changed files with 84 additions and 56 deletions

View File

@ -5,8 +5,8 @@
let s:TAGS_METADATA_FILE_NAME = '.tags' let s:TAGS_METADATA_FILE_NAME = '.tags'
" Tags metadata in-memory format: " Tags metadata in-memory format:
" metadata := [ entry, ... ] " metadata := { 'pagename': [entries, ...] }
" entry := { 'tagname':..., 'pagename':..., 'lineno':..., 'link':... } " entry := { 'tagname':..., 'lineno':..., 'link':... }
" Tags metadata in-file format: " Tags metadata in-file format:
" "
@ -23,7 +23,9 @@ let s:TAGS_METADATA_FILE_NAME = '.tags'
" Update tags metadata. " Update tags metadata.
" a:full_rebuild == 1: re-scan entire wiki " a:full_rebuild == 1: re-scan entire wiki
" a:full_rebuild == 0: only re-scan current page " 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 if !a:full_rebuild
" Updating for one page (current) " Updating for one page (current)
let page_name = VimwikiGet('subdir') . expand('%:t:r') let page_name = VimwikiGet('subdir') . expand('%:t:r')
@ -34,26 +36,31 @@ function! vimwiki#tags#update_tags(full_rebuild) "{{{
" Drop old tags " Drop old tags
let metadata = s:remove_page_from_tags(metadata, page_name) let metadata = s:remove_page_from_tags(metadata, page_name)
" Merge in the new ones " Merge in the new ones
let metadata = s:merge_tags(metadata, tags) let metadata = s:merge_tags(metadata, page_name, tags)
" Save " Save
call s:write_tags_metadata(metadata) call s:write_tags_metadata(metadata)
else " full rebuild else " full rebuild
let files = vimwiki#base#find_files(g:vimwiki_current_idx, 0) 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 for file in files
if all_files || getftime(file) >= tags_file_last_modification
let page_name = fnamemodify(file, ':t:r') let page_name = fnamemodify(file, ':t:r')
let tags = s:scan_tags(readfile(file), page_name) let tags = s:scan_tags(readfile(file), page_name)
let metadata = s:merge_tags(metadata, tags) let metadata = s:remove_page_from_tags(metadata, page_name)
let metadata = s:merge_tags(metadata, page_name, tags)
endif
endfor endfor
call s:write_tags_metadata(metadata) call s:write_tags_metadata(metadata)
endif endif
endfunction " }}} endfunction " }}}
" s:scan_tags " 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) "{{{ function! s:scan_tags(lines, page_name) "{{{
let metadata = [] let entries = []
let page_name = a:page_name let page_name = a:page_name
" Code wireframe to scan for headers -- borrowed from " Code wireframe to scan for headers -- borrowed from
@ -110,7 +117,6 @@ function! s:scan_tags(lines, page_name) "{{{
" Create metadata entry " Create metadata entry
let entry = {} let entry = {}
let entry.tagname = tag let entry.tagname = tag
let entry.pagename = page_name
let entry.lineno = line_nr let entry.lineno = line_nr
if line_nr <= (header_line_nr + PROXIMITY_LINES_NR) if line_nr <= (header_line_nr + PROXIMITY_LINES_NR)
let entry.link = page_name . '#' . current_complete_anchor let entry.link = page_name . '#' . current_complete_anchor
@ -120,12 +126,12 @@ function! s:scan_tags(lines, page_name) "{{{
else else
let entry.link = page_name . '#' . tag let entry.link = page_name . '#' . tag
endif endif
call add(metadata, entry) call add(entries, entry)
endfor endfor
endwhile endwhile
endfor " loop over lines endfor " loop over lines
return metadata return entries
endfunction " }}} endfunction " }}}
" s:metadata_file_path " s:metadata_file_path
@ -139,9 +145,9 @@ endfunction " }}}
function! vimwiki#tags#load_tags_metadata() abort "{{{ function! vimwiki#tags#load_tags_metadata() abort "{{{
let metadata_path = s:metadata_file_path() let metadata_path = s:metadata_file_path()
if !filereadable(metadata_path) if !filereadable(metadata_path)
return [] return {}
endif endif
let metadata = [] let metadata = {}
for line in readfile(metadata_path) for line in readfile(metadata_path)
if line =~ '^!_TAG_FILE_' if line =~ '^!_TAG_FILE_'
continue continue
@ -171,12 +177,16 @@ function! vimwiki#tags#load_tags_metadata() abort "{{{
if len(vw_fields) != 2 if len(vw_fields) != 2
throw 'VimwikiTags5: Metadata file corrupted' throw 'VimwikiTags5: Metadata file corrupted'
endif endif
let pagename = vw_fields[0]
let entry = {} let entry = {}
let entry.tagname = std_fields[0] let entry.tagname = std_fields[0]
let entry.pagename = vw_fields[0]
let entry.lineno = std_fields[2] let entry.lineno = std_fields[2]
let entry.link = vw_fields[1] 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 endfor
return metadata return metadata
endfunction " }}} endfunction " }}}
@ -185,48 +195,57 @@ endfunction " }}}
" Removes all entries for given page from metadata in-place. Returns updated " Removes all entries for given page from metadata in-place. Returns updated
" metadata (just in case). " metadata (just in case).
function! s:remove_page_from_tags(metadata, page_name) "{{{ function! s:remove_page_from_tags(metadata, page_name) "{{{
let metadata = filter(a:metadata, if has_key(a:metadata, a:page_name)
\ "v:val.pagename != '" . substitute(a:page_name, "'", "''", '') . "'") call remove(a:metadata, a:page_name)
return metadata return a:metadata
else
return a:metadata
endif
endfunction " }}} endfunction " }}}
" s:merge_tags " s:merge_tags
" Merges two tags metadata objects into (new) one. " Merges metadata of one file into a:metadata
function! s:merge_tags(metadata1, metadata2) "{{{ function! s:merge_tags(metadata, pagename, file_metadata) "{{{
return a:metadata1 + a:metadata2 let metadata = a:metadata
let metadata[a:pagename] = a:file_metadata
return metadata
endfunction " }}} endfunction " }}}
" s:write_tags_metadata " s:write_tags_metadata
" Saves metadata object into a file. Throws exceptions in case of problems. " Saves metadata object into a file. Throws exceptions in case of problems.
function! s:write_tags_metadata(metadata) "{{{ function! s:write_tags_metadata(metadata) "{{{
let metadata_path = s:metadata_file_path() let metadata_path = s:metadata_file_path()
let entries = [] let tags = []
for entry in a:metadata for pagename in keys(a:metadata)
let entry_data = entry.pagename . "\t" . entry.link 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, "\\", '\\\\', 'g')
let entry_data = substitute(entry_data, "\t", '\\t', '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, "\r", '\\r', 'g')
let entry_data = substitute(entry_data, "\n", '\\n', 'g') let entry_data = substitute(entry_data, "\n", '\\n', 'g')
call add(entries, call add(tags,
\ entry.tagname . "\t" \ entry.tagname . "\t"
\ . entry.pagename . VimwikiGet('ext') . "\t" \ . pagename . VimwikiGet('ext') . "\t"
\ . entry.lineno \ . entry.lineno
\ . ';"' \ . ';"'
\ . "\t" . "vimwiki:" . entry_data \ . "\t" . "vimwiki:" . entry_data
\) \)
endfor endfor
call sort(entries) endfor
call insert(entries, "!_TAG_FILE_SORTED\t1\t{anything}") call sort(tags)
call writefile(entries, metadata_path) call insert(tags, "!_TAG_FILE_SORTED\t1\t{anything}")
call writefile(tags, metadata_path)
endfunction " }}} endfunction " }}}
" vimwiki#tags#get_tags " vimwiki#tags#get_tags
" Returns list of unique tags found in metadata " Returns list of unique tags found in metadata
function! vimwiki#tags#get_tags(metadata) "{{{ function! vimwiki#tags#get_tags(metadata) "{{{
let tags = {} let tags = {}
for entry in a:metadata for entries in values(a:metadata)
for entry in entries
let tags[entry.tagname] = 1 let tags[entry.tagname] = 1
endfor endfor
endfor
return keys(tags) return keys(tags)
endfunction " }}} endfunction " }}}
@ -244,21 +263,29 @@ function! vimwiki#tags#generate_tags(...) abort "{{{
\ '', \ '',
\ substitute(g:vimwiki_rxH1_Template, '__Header__', 'Generated Tags', '') ]) \ 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()). let bullet = repeat(' ', vimwiki#lst#get_list_margin()).
\ vimwiki#lst#default_symbol().' ' \ vimwiki#lst#default_symbol().' '
let current_tag = '' for tagname in sort(keys(tags_entries))
for entry in metadata if need_all_tags || index(specific_tags, tagname) != -1
if need_all_tags || index(specific_tags, entry.tagname) != -1
if entry.tagname != current_tag
let current_tag = entry.tagname
call append(line('$'), [ call append(line('$'), [
\ '', \ '',
\ substitute(g:vimwiki_rxH2_Template, '__Header__', entry.tagname, ''), \ substitute(g:vimwiki_rxH2_Template, '__Header__', tagname, ''),
\ '' ]) \ '' ])
endif for taglink in tags_entries[tagname]
call append(line('$'), bullet . '[[' . entry.link . ']]') call append(line('$'), bullet . '[[' . taglink . ']]')
endfor
endif endif
endfor endfor
endfunction " }}} endfunction " }}}

View File

@ -310,7 +310,8 @@ command! -buffer VimwikiDiaryNextDay call vimwiki#diary#goto_next_day()
command! -buffer VimwikiDiaryPrevDay call vimwiki#diary#goto_prev_day() command! -buffer VimwikiDiaryPrevDay call vimwiki#diary#goto_prev_day()
" tags commands " tags commands
command! -buffer VimwikiRebuildTags call vimwiki#tags#update_tags(1) command! -buffer -bang
\ VimwikiRebuildTags call vimwiki#tags#update_tags(1, '<bang>')
command! -buffer -nargs=* -complete=custom,vimwiki#tags#complete_tags command! -buffer -nargs=* -complete=custom,vimwiki#tags#complete_tags
\ VimwikiSearchTags VimwikiSearch /:<args>:/ \ VimwikiSearchTags VimwikiSearch /:<args>:/
command! -buffer -nargs=* -complete=custom,vimwiki#tags#complete_tags command! -buffer -nargs=* -complete=custom,vimwiki#tags#complete_tags
@ -652,7 +653,7 @@ endif
if VimwikiGet('auto_tags') if VimwikiGet('auto_tags')
" Automatically update tags metadata on page write. " Automatically update tags metadata on page write.
augroup vimwiki augroup vimwiki
au BufWritePost <buffer> call vimwiki#tags#update_tags(0) au BufWritePost <buffer> call vimwiki#tags#update_tags(0, '')
augroup END augroup END
endif endif
" AUTOCOMMANDS }}} " AUTOCOMMANDS }}}