Merge branch 'tags' into dev

Ref #85
This commit is contained in:
EinfachToll 2015-11-12 11:56:03 +01:00
commit 0931685ba2
13 changed files with 586 additions and 112 deletions

View File

@ -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
@ -498,7 +502,7 @@ function! vimwiki#base#backlinks() "{{{
let locations = []
for idx in range(len(g:vimwiki_list))
let syntax = VimwikiGet('syntax', idx)
let wikifiles = s:find_files(idx, 0)
let wikifiles = vimwiki#base#find_files(idx, 0)
for source_file in wikifiles
let links = s:get_links(source_file, idx)
for [target_file, _, lnum, col] in links
@ -522,7 +526,7 @@ endfunction "}}}
" Returns: a list containing all files of the given wiki as absolute file path.
" If the given wiki number is negative, the diary of the current wiki is used
" If the second argument is not zero, only directories are found
function! s:find_files(wiki_nr, directories_only)
function! vimwiki#base#find_files(wiki_nr, directories_only)
let wiki_nr = a:wiki_nr
if wiki_nr >= 0
let root_directory = VimwikiGet('path', wiki_nr)
@ -551,7 +555,7 @@ endfunction
" If the given wiki number is negative, the diary of the current wiki is used.
" If also_absolute_links is nonzero, also return links of the form /file
function! vimwiki#base#get_wikilinks(wiki_nr, also_absolute_links)
let files = s:find_files(a:wiki_nr, 0)
let files = vimwiki#base#find_files(a:wiki_nr, 0)
if a:wiki_nr == g:vimwiki_current_idx
let cwd = vimwiki#path#wikify_path(expand('%:p:h'))
elseif a:wiki_nr < 0
@ -582,7 +586,7 @@ endfunction
" Returns: a list containing the links to all directories from the current file
function! vimwiki#base#get_wiki_directories(wiki_nr)
let dirs = s:find_files(a:wiki_nr, 1)
let dirs = vimwiki#base#find_files(a:wiki_nr, 1)
if a:wiki_nr == g:vimwiki_current_idx
let cwd = vimwiki#path#wikify_path(expand('%:p:h'))
let root_dir = VimwikiGet('path')
@ -608,6 +612,7 @@ function! vimwiki#base#get_anchors(filename, syntax) "{{{
let rxheader = g:vimwiki_{a:syntax}_header_search
let rxbold = g:vimwiki_{a:syntax}_bold_search
let rxtag = g:vimwiki_{a:syntax}_tag_search
let anchor_level = ['', '', '', '', '', '', '']
let anchors = []
@ -652,6 +657,22 @@ function! vimwiki#base#get_anchors(filename, syntax) "{{{
let bold_count += 1
endwhile
" collect tags text (there can be several in one line)
let tag_count = 1
while 1
let tag_group_text = matchstr(line, rxtag, 0, tag_count)
if tag_group_text == ''
break
endif
for tag_text in split(tag_group_text, ':')
call add(anchors, tag_text)
if current_complete_anchor != ''
call add(anchors, current_complete_anchor.'#'.tag_text)
endif
endfor
let tag_count += 1
endwhile
endfor
return anchors
@ -672,8 +693,12 @@ function! s:jump_to_anchor(anchor) "{{{
\ '__Header__', "\\='".segment."'", '')
let anchor_bold = substitute(g:vimwiki_{VimwikiGet('syntax')}_bold_match,
\ '__Text__', "\\='".segment."'", '')
let anchor_tag = substitute(g:vimwiki_{VimwikiGet('syntax')}_tag_match,
\ '__Tag__', "\\='".segment."'", '')
if !search(anchor_header, 'Wc') && !search(anchor_bold, 'Wc')
if !search(anchor_tag, 'Wc')
\ && !search(anchor_header, 'Wc')
\ && !search(anchor_bold, 'Wc')
call setpos('.', oldpos)
break
endif
@ -723,7 +748,7 @@ function! vimwiki#base#check_links() "{{{
let errors = []
for idx in range(len(g:vimwiki_list))
let syntax = VimwikiGet('syntax', idx)
let wikifiles = s:find_files(idx, 0)
let wikifiles = vimwiki#base#find_files(idx, 0)
for wikifile in wikifiles
let links_of_files[wikifile] = s:get_links(wikifile, idx)
let anchors_of_files[wikifile] = vimwiki#base#get_anchors(wikifile, syntax)
@ -1066,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() "{{{
@ -1143,6 +1236,9 @@ function! vimwiki#base#go_back_link() "{{{
let prev_word = b:vimwiki_prev_link
execute ":e ".substitute(prev_word[0], '\s', '\\\0', 'g')
call setpos('.', prev_word[1])
else
" maybe we came here by jumping to a tag -> pop from the tag stack
silent! pop!
endif
endfunction " }}}
@ -1606,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]]
@ -1654,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
@ -1676,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
"}}}

View File

@ -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

View File

@ -289,6 +289,27 @@ function! s:tag_strong(value, header_ids) "{{{
\ .id.'">'.text.'</strong>'
endfunction "}}}
function! s:tag_tags(value, header_ids) "{{{
let complete_id = ''
for level in range(6)
if a:header_ids[level][0] != ''
let complete_id .= a:header_ids[level][0].'-'
endif
endfor
if a:header_ids[5][0] == ''
let complete_id = complete_id[:-2]
endif
let complete_id = s:safe_html_anchor(complete_id)
let result = []
for tag in split(a:value, ':')
let id = s:safe_html_anchor(tag)
call add(result, '<span id="'.complete_id.'-'.id.'"></span><span class="tag" id="'
\ .id.'">'.tag.'</span>')
endfor
return join(result)
endfunction "}}}
function! s:tag_todo(value) "{{{
return '<span class="todo">'.a:value.'</span>'
endfunction "}}}
@ -554,6 +575,7 @@ function! s:process_tags_typefaces(line, header_ids) "{{{
let line = s:make_tag(line, g:vimwiki_rxSubScript, 's:tag_sub')
let line = s:make_tag(line, g:vimwiki_rxCode, 's:tag_code')
let line = s:make_tag(line, g:vimwiki_rxEqIn, 's:tag_eqin')
let line = s:make_tag(line, g:vimwiki_rxTags, 's:tag_tags', a:header_ids)
return line
endfunction " }}}

View File

@ -24,6 +24,7 @@ del {text-decoration: line-through; color: #777777;}
.justright {text-align: right;}
.justcenter {text-align: center;}
.center {margin-left: auto; margin-right: auto;}
.tag {background-color: #eeeeee; font-family: monospace; padding: 2px;}
/* classes for items of todo lists */
.done0 {

307
autoload/vimwiki/tags.vim Normal file
View File

@ -0,0 +1,307 @@
" vim:tabstop=2:shiftwidth=2:expandtab:foldmethod=marker:textwidth=79
" Vimwiki autoload plugin file
let s:TAGS_METADATA_FILE_NAME = '.tags'
" Tags metadata in-memory format:
" metadata := { 'pagename': [entries, ...] }
" entry := { 'tagname':..., 'lineno':..., 'link':... }
" Tags metadata in-file format:
"
" Is based on CTags format (see |tags-file-format|).
"
" {tagaddress} is set to lineno. We'll let vim search by exact line number; we
" can afford that, we assume metadata file is always updated before use.
"
" Pagename and link are not saved in standard ctags fields, so we'll add
" an optional field, "vimwiki:". In this field, we encode tab-separated values
" of missing parameters -- "pagename" and "link".
" vimwiki#tags#update_tags
" Update tags metadata.
" a:full_rebuild == 1: re-scan entire wiki
" a:full_rebuild == 0: only re-scan current page
" 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')
" Collect tags in current file
let tags = s:scan_tags(getline(1, '$'), page_name)
" Load metadata file
let metadata = s:load_tags_metadata()
" Drop old tags
let metadata = s:remove_page_from_tags(metadata, page_name)
" Merge in the new ones
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 tags_file_last_modification =
\ getftime(vimwiki#tags#metadata_file_path())
let metadata = s:load_tags_metadata()
for file in files
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 as a
" list of tag entries.
function! s:scan_tags(lines, page_name) "{{{
let entries = []
let page_name = a:page_name
" Code wireframe to scan for headers -- borrowed from
" vimwiki#base#get_anchors(), with minor modifications.
let rxheader = g:vimwiki_{VimwikiGet('syntax')}_header_search
let rxtag = g:vimwiki_{VimwikiGet('syntax')}_tag_search
let anchor_level = ['', '', '', '', '', '', '']
let current_complete_anchor = ''
let PROXIMITY_LINES_NR = 5
let header_line_nr = - (2 * PROXIMITY_LINES_NR)
for line_nr in range(1, len(a:lines))
let line = a:lines[line_nr - 1]
" process headers
let h_match = matchlist(line, rxheader)
if !empty(h_match) " got a header
let header_line_nr = line_nr
let header = vimwiki#u#trim(h_match[2])
let level = len(h_match[1])
let anchor_level[level-1] = header
for l in range(level, 6)
let anchor_level[l] = ''
endfor
if level == 1
let current_complete_anchor = header
else
let current_complete_anchor = ''
for l in range(level-1)
if anchor_level[l] != ''
let current_complete_anchor .= anchor_level[l].'#'
endif
endfor
let current_complete_anchor .= header
endif
continue " tags are not allowed in headers
endif
" TODO ignore verbatim blocks
" Scan line for tags. There can be many of them.
let str = line
while 1
let tag_group = matchstr(str, rxtag)
if tag_group == ''
break
endif
let tagend = matchend(str, rxtag)
let str = str[(tagend):]
for tag in split(tag_group, ':')
" Create metadata entry
let entry = {}
let entry.tagname = tag
let entry.lineno = line_nr
if line_nr <= PROXIMITY_LINES_NR && header_line_nr < 0
" Tag appeared at the top of the file
let entry.link = page_name
elseif line_nr <= (header_line_nr + PROXIMITY_LINES_NR)
let entry.link = page_name . '#' . current_complete_anchor
else
let entry.link = page_name . '#' . tag
endif
call add(entries, entry)
endfor
endwhile
endfor " loop over lines
return entries
endfunction " }}}
" vimwiki#tags#metadata_file_path
" Returns tags metadata file path
function! vimwiki#tags#metadata_file_path() abort "{{{
return fnamemodify(VimwikiGet('path') . '/' . s:TAGS_METADATA_FILE_NAME, ':p')
endfunction " }}}
" s:load_tags_metadata
" Loads tags metadata from file, returns a dictionary
function! s:load_tags_metadata() abort "{{{
let metadata_path = vimwiki#tags#metadata_file_path()
if !filereadable(metadata_path)
return {}
endif
let metadata = {}
for line in readfile(metadata_path)
if line =~ '^!_TAG_FILE_'
continue
endif
let parts = matchlist(line, '^\(.\{-}\);"\(.*\)$')
if parts[0] == '' || parts[1] == '' || parts[2] == ''
throw 'VimwikiTags1: Metadata file corrupted'
endif
let std_fields = split(parts[1], '\t')
if len(std_fields) != 3
throw 'VimwikiTags2: Metadata file corrupted'
endif
let vw_part = parts[2]
if vw_part[0] != "\t"
throw 'VimwikiTags3: Metadata file corrupted'
endif
let vw_fields = split(vw_part[1:], "\t")
if len(vw_fields) != 1 || vw_fields[0] !~ '^vimwiki:'
throw 'VimwikiTags4: Metadata file corrupted'
endif
let vw_data = substitute(vw_fields[0], '^vimwiki:', '', '')
let vw_data = substitute(vw_data, '\\n', "\n", 'g')
let vw_data = substitute(vw_data, '\\r', "\r", 'g')
let vw_data = substitute(vw_data, '\\t', "\t", 'g')
let vw_data = substitute(vw_data, '\\\\', "\\", 'g')
let vw_fields = split(vw_data, "\t")
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.lineno = std_fields[2]
let entry.link = vw_fields[1]
if has_key(metadata, pagename)
call add(metadata[pagename], entry)
else
let metadata[pagename] = [entry]
endif
endfor
return metadata
endfunction " }}}
" s:remove_page_from_tags
" 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) "{{{
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 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 = vimwiki#tags#metadata_file_path()
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(tags)
call insert(tags, "!_TAG_FILE_SORTED\t1\t")
call writefile(tags, metadata_path)
endfunction " }}}
" vimwiki#tags#get_tags
" Returns list of unique tags found in the .tags file
function! vimwiki#tags#get_tags() "{{{
let metadata = s:load_tags_metadata()
let tags = {}
for entries in values(metadata)
for entry in entries
let tags[entry.tagname] = 1
endfor
endfor
return keys(tags)
endfunction " }}}
" vimwiki#tags#generate_tags
" Similar to vimwiki#base#generate_links. In the current buffer, appends
" tags and references to all their instances. If no arguments (tags) are
" specified, outputs all tags.
function! vimwiki#tags#generate_tags(...) abort "{{{
let need_all_tags = (a:0 == 0)
let specific_tags = a:000
let metadata = s:load_tags_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 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 extend(lines, [
\ '',
\ substitute(g:vimwiki_rxH2_Template, '__Header__', tagname, ''),
\ '' ])
for taglink in tags_entries[tagname]
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
function! vimwiki#tags#complete_tags(ArgLead, CmdLine, CursorPos) abort " {{{
" We can safely ignore args if we use -custom=complete option, Vim engine
" will do the job of filtering.
let taglist = vimwiki#tags#get_tags()
return join(taglist, "\n")
endfunction " }}}

View File

@ -38,6 +38,7 @@ CONTENTS *vimwiki-contents*
5.12. Schemes |vimwiki-syntax-schemes|
5.13. Transclusions |vimwiki-syntax-transclude|
5.14. Thumbnails |vimwiki-syntax-thumbnails|
5.15. Tags |vimwiki-syntax-tags|
6. Folding/Outline |vimwiki-folding|
7. Placeholders |vimwiki-placeholders|
8. Lists |vimwiki-lists|
@ -595,7 +596,7 @@ il A single list item.
*:VimwikiGoto*
Goto link provided by an argument. For example: >
:VimwikiGoto HelloWorld
< opens opens/creates HelloWorld wiki page.
< opens opens/creates HelloWorld wiki page.
Supports |cmdline-completion| for link name.
@ -703,6 +704,21 @@ il A single list item.
files are reachable from the index file. Errors are shown in the quickfix
window.
*:VimwikiRebuildTags*
Rebuilds the tags metadata file for the current wiki file.
Necessary for all tags related commands: |vimwiki-syntax-tags|.
:VimwikiRebuildTags! does the same for all files in the current wiki.
*:VimwikiSearchTags*
Searches over the pages in current wiki and finds all locations of a given
tag. Supports |cmdline-completion|.
*:VimwikiGenerateTags*
Similar to |:VimwikiGenerateLinks|. In the current buffer, appends tags
and references to all their instances. Supports |cmdline-completion|. If
no arguments (tags) are specified, outputs all tags.
==============================================================================
5. Wiki syntax *vimwiki-syntax*
@ -1227,6 +1243,45 @@ in HTML: >
<img src="http://../thumbnail.jpg /></a>
------------------------------------------------------------------------------
5.15. Tags *vimwiki-syntax-tags*
Tags~
>
Vimwiki supports notion of tags. A tag is a sequence of non-space characters
between two colons: >
:tag-example:
<
It is allowed to concatenate multiple tags in one line: >
:tag-one:tag-two:
<
A tag can be placed anywhere in a file (except for header line, and wikilink).
If placed under a header, within 5 lines below it, the header is then "tagged"
with this tag, and tag search commands will jump to this specific header.
Otherwise the entire page is tagged, and search commands will jump
accordingly.
Typing tags can be simplified by using Vim's omni completion (see
|compl-omni|) like so: >
:ind<C-X><C-O>
which opens up a popup menu with all tags defined in the wiki starting with
"ind".
Tags are also treated as |vimwiki-anchors| (similar to bold text).
Note that tag search/jump/completion commands need certain metadata saved in
the wiki folder. This metadata can be manually updated by running
|:VimwikiRebuildTags|. There is an option |vimwiki-option-auto_tags|, when
enabled, tags metadata will be auto-updated on each page save.
Once tags metadata has been built, one can use Vim's built-in tag search
functionality (see |tagsrch.txt|).
Tags-related commands and options:
* |:VimwikiRebuildTags|
* |:VimwikiGenerateTags|
* |:VimwikiSearchTags|
* |vimwiki-option-auto_tags|
==============================================================================
@ -1581,12 +1636,13 @@ See |g:vimwiki_use_calendar| option to turn it off/on.
==============================================================================
12. Anchors *vimwiki-anchors*
Every header and every bold text is an anchor. To jump to it, use a wikilink
Every header, tag, and bold text is an anchor. To jump to it, use a wikilink
of the form >
[[file#anchor]]
For example, consider the following file "Todo.wiki": >
= My tasks =
:todo-lists:
== Home ==
- [ ] bathe my dog
== Work ==
@ -1602,6 +1658,9 @@ Then, to jump from your index.wiki directly to your knitting projects, use: >
Or, to jump to an individual project, use this link: >
[[Todo#pig]]
Or, to jump to a tag, use this link: >
[[Todo#todo-lists]]
If there are multiple instances of an anchor, you can use the long form which
consists of the complete header hierarchy, separated by '#': >
[[Todo#My tasks#Knitting club#Knitting projects#dog]]
@ -2048,6 +2107,18 @@ local mappings |vimwiki_glstar|, |vimwiki_gl#| |vimwiki_gl-|, |vimwiki_gl-|,
Note: if you use MediaWiki syntax, you probably would like to set this option
to 0, because every indented line is considered verbatim text.
*vimwiki-option-auto_tags*
------------------------------------------------------------------------------
Key Default value Values~
auto_tags 0 0, 1
Description~
Set this option to 1 to automatically update the tags metadata when the
current wiki page is saved: >
let g:vimwiki_list = [{'path': '~/my_site/', 'auto_tags': 1}]
------------------------------------------------------------------------------
12.4 Global Options *vimwiki-global-options*
@ -2646,6 +2717,7 @@ Vim plugins: http://www.vim.org/scripts/script.php?script_id=2226
???~
* Support for tags.
* Support for wiki links absolute to the wiki root
* The "file:" and "local:" schemes semantic changed slightly
* Added the |VimwikiLinkConverter| function

View File

@ -31,26 +31,49 @@ execute 'setlocal suffixesadd='.VimwikiGet('ext')
setlocal isfname-=[,]
" gf}}}
exe "setlocal tags+=" . vimwiki#tags#metadata_file_path()
" MISC }}}
" COMPLETION {{{
function! Complete_wikifiles(findstart, base)
if a:findstart == 1
let column = col('.')-1
let column = col('.')-2
let line = getline('.')[:column]
let startoflink = match(line, '\[\[\zs[^\\[]*$')
let startoflink = match(line, '\[\[\zs[^\\[\]]*$')
if startoflink != -1
let s:line_context = '['
return startoflink
endif
if VimwikiGet('syntax') ==? 'markdown'
let startofinlinelink = match(line, '\[.*\](\zs.*$')
let startofinlinelink = match(line, '\[.*\](\zs[^)]*$')
if startofinlinelink != -1
let s:line_context = '['
return startofinlinelink
endif
endif
let startoftag = match(line, ':\zs[^:[:space:]]*$')
if startoftag != -1
let s:line_context = ':'
return startoftag
endif
let s:line_context = ''
return -1
else
if a:base !~# '#'
" Completion works for wikilinks/anchors, and for tags. s:line_content
" tells us, which string came before a:base. There seems to be no easier
" solution, because calling col('.') here returns garbage.
if s:line_context == ''
return []
elseif s:line_context == ':'
" Tags completion
let tags = vimwiki#tags#get_tags()
if a:base != ''
call filter(tags,
\ "v:val[:" . (len(a:base)-1) . "] == '" . substitute(a:base, "'", "''", '') . "'" )
endif
return tags
elseif a:base !~# '#'
" we look for wiki files
if a:base =~# '^wiki\d:'
@ -290,6 +313,14 @@ command! -buffer VimwikiTableMoveColumnRight call vimwiki#tbl#move_column_right(
command! -buffer VimwikiDiaryNextDay call vimwiki#diary#goto_next_day()
command! -buffer VimwikiDiaryPrevDay call vimwiki#diary#goto_prev_day()
" tags commands
command! -buffer -bang
\ VimwikiRebuildTags call vimwiki#tags#update_tags(1, '<bang>')
command! -buffer -nargs=* -complete=custom,vimwiki#tags#complete_tags
\ VimwikiSearchTags VimwikiSearch /:<args>:/
command! -buffer -nargs=* -complete=custom,vimwiki#tags#complete_tags
\ VimwikiGenerateTags call vimwiki#tags#generate_tags(<f-args>)
" COMMANDS }}}
" KEYBINDINGS {{{
@ -622,6 +653,13 @@ if VimwikiGet('auto_toc')
au BufWritePre <buffer> call vimwiki#base#table_of_contents(0)
augroup END
endif
if VimwikiGet('auto_tags')
" Automatically update tags metadata on page write.
augroup vimwiki
au BufWritePost <buffer> call vimwiki#tags#update_tags(0, '')
augroup END
endif
" AUTOCOMMANDS }}}
" PASTE, CAT URL {{{

View File

@ -414,6 +414,8 @@ let s:vimwiki_defaults.diary_link_fmt = '%Y-%m-%d'
let s:vimwiki_defaults.custom_wiki2html = ''
"
let s:vimwiki_defaults.list_margin = -1
let s:vimwiki_defaults.auto_tags = 0
"}}}
" DEFAULT options {{{

View File

@ -13,12 +13,16 @@ let g:vimwiki_default_header_match = '^\s*\(=\{1,6}\)=\@!\s*__Header__\s*\1=\@!\
let g:vimwiki_default_bold_search = '\%(^\|\s\|[[:punct:]]\)\@<=\*\zs\%([^*`[:space:]][^*`]*[^*`[:space:]]\|[^*`[:space:]]\)\ze\*\%([[:punct:]]\|\s\|$\)\@='
let g:vimwiki_default_bold_match = '\%(^\|\s\|[[:punct:]]\)\@<=\*__Text__\*\%([[:punct:]]\|\s\|$\)\@='
let g:vimwiki_default_wikilink = '\[\[\zs[^\\\]|]\+\ze\%(|[^\\\]]\+\)\?\]\]'
let g:vimwiki_default_tag_search = '\(^\|\s\)\zs:\([^:''[:space:]]\+:\)\+\ze\(\s\|$\)'
let g:vimwiki_default_tag_match = '\(^\|\s\):\([^:''[:space:]]\+:\)*__Tag__:\([^:[:space:]]\+:\)*\(\s\|$\)'
let g:vimwiki_markdown_header_search = '^\s*\(#\{1,6}\)\([^#].*\)$'
let g:vimwiki_markdown_header_match = '^\s*\(#\{1,6}\)#\@!\s*__Header__\s*$'
let g:vimwiki_markdown_bold_search = '\%(^\|\s\|[[:punct:]]\)\@<=\*\zs\%([^*`[:space:]][^*`]*[^*`[:space:]]\|[^*`[:space:]]\)\ze\*\%([[:punct:]]\|\s\|$\)\@='
let g:vimwiki_markdown_bold_match = '\%(^\|\s\|[[:punct:]]\)\@<=\*__Text__\*\%([[:punct:]]\|\s\|$\)\@='
let g:vimwiki_markdown_wikilink = g:vimwiki_default_wikilink "XXX plus markdown-style links
let g:vimwiki_markdown_tag_search = g:vimwiki_default_tag_search
let g:vimwiki_markdown_tag_match = g:vimwiki_default_tag_match
let g:vimwiki_media_header_search = '^\s*\(=\{1,6}\)\([^=].*[^=]\)\1\s*$'
let g:vimwiki_media_header_match = '^\s*\(=\{1,6}\)=\@!\s*__Header__\s*\1=\@!\s*$'
@ -27,3 +31,5 @@ let g:vimwiki_media_bold_match = '''''''__Text__'''''''
" ^- this strange looking thing is equivalent to "'''__Text__'''" but since we later
" want to call escape() on this string, we must keep it in single quotes
let g:vimwiki_media_wikilink = g:vimwiki_default_wikilink
let g:vimwiki_media_tag_search = g:vimwiki_default_tag_search " XXX rework to mediawiki categories format?
let g:vimwiki_media_tag_match = g:vimwiki_default_tag_match " XXX rework to mediawiki categories format?

View File

@ -489,6 +489,10 @@ if g:vimwiki_valid_html_tags != ''
execute 'syntax match VimwikiComment /'.g:vimwiki_rxComment.'/ contains=@Spell'
endif
" tags
execute 'syntax match VimwikiTag /'.g:vimwiki_rxTags.'/'
" }}}
" header groups highlighting "{{{
@ -554,6 +558,7 @@ hi def link VimwikiListTodo VimwikiList
hi def link VimwikiCheckBoxDone Comment
hi def link VimwikiEmoticons Character
hi def link VimwikiHR Identifier
hi def link VimwikiTag Keyword
hi def link VimwikiDelText Constant
hi def link VimwikiDelTextT VimwikiDelText

View File

@ -91,3 +91,5 @@ let g:vimwiki_rxMathStart = '{{\$'
let g:vimwiki_rxMathEnd = '}}\$'
let g:vimwiki_rxComment = '^\s*%%.*$'
let g:vimwiki_rxTags = '\%(^\|\s\)\@<=:\%([^:''[:space:]]\+:\)\+\%(\s\|$\)\@='
" see also g:vimwiki_default_tag_search

View File

@ -88,3 +88,4 @@ let g:vimwiki_rxMathStart = '\$\$'
let g:vimwiki_rxMathEnd = '\$\$'
let g:vimwiki_rxComment = '^\s*%%.*$'
let g:vimwiki_rxTags = '\%(^\|\s\)\@<=:\%([^:[:space:]]\+:\)\+\%(\s\|$\)\@='

View File

@ -69,3 +69,4 @@ let g:vimwiki_rxMathStart = '{{\$'
let g:vimwiki_rxMathEnd = '}}\$'
let g:vimwiki_rxComment = '^\s*%%.*$'
let g:vimwiki_rxTags = '\%(^\|\s\)\@<=:\%([^:[:space:]]\+:\)\+\%(\s\|$\)\@='