vimwiki

Personal wiki for vim
git clone https://github.com/vimwiki/vimwiki.git
Log | Files | Refs | README | LICENSE

commit 8f5d38365bcd73fc44847b4de5d9f4b10c64461f
parent 7d82c7541de59598831f37dce4b6143d007a79cb
Author: Eric Langlois <eric@langlois.xyz>
Date:   Tue, 19 Mar 2019 22:59:24 -0400

Added optional extra caption levels to diary index.

Added the option 'diary_caption_level', which controls the presence of
captions in the diary index linking to headers within the diary pages.

Possible values:
-1:  No headers are read from the diary page.
 0:  The first header from the diary page is used as the caption.
       There are no sub-captions.
 1:  Captions are created for headers of level 1 in the diary page.
 2:  Captions are created for headers up to level 2 in the diary page.
 etc.

When the value is >= 1, the primary caption of each diary page is set to
the first header read from that page if it is the unique lowest-level
header.

Diffstat:
Mautoload/vimwiki/diary.vim | 125++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------
Mautoload/vimwiki/vars.vim | 7++++++-
Mdoc/vimwiki.txt | 20++++++++++++++++++++
3 files changed, 131 insertions(+), 21 deletions(-)

diff --git a/autoload/vimwiki/diary.vim b/autoload/vimwiki/diary.vim @@ -63,26 +63,98 @@ function! s:get_month_name(month) return vimwiki#vars#get_global('diary_months')[str2nr(a:month)] endfunction +function! s:get_first_header(fl) + " Get the first header in the file within the first s:vimwiki_max_scan_for_caption lines. + let header_rx = vimwiki#vars#get_syntaxlocal('rxHeader') + + for line in readfile(a:fl, '', s:vimwiki_max_scan_for_caption) + if line =~# header_rx + return vimwiki#u#trim(matchstr(line, header_rx)) + endif + endfor + return '' +endfunction + +function! s:get_all_headers(fl, maxlevel) + " Get a list of all headers in a file up to a given level. + " Returns a list whose elements are pairs [level, title] + let headers_rx = {} + for i in range(1, a:maxlevel) + let headers_rx[i] = vimwiki#vars#get_syntaxlocal('rxH'.i.'_Text') + endfor + + let headers = [] + for line in readfile(a:fl, '') + for [i, header_rx] in items(headers_rx) + if line =~# header_rx + call add(headers, [i, vimwiki#u#trim(matchstr(line, header_rx))]) + break + endif + endfor + endfor + return headers +endfunction + +function! s:count_headers_level_less_equal(headers, maxlevel) + " Count headers with level <= maxlevel in a list of [level, title] pairs. + let l:count = 0 + for [header_level, _] in a:headers + if header_level <= a:maxlevel + let l:count += 1 + endif + endfor + return l:count +endfunction + +function! s:get_min_header_level(headers) + " The minimum level of any header in a list of [level, title] pairs. + if len(a:headers) == 0 + return 0 + endif + let minlevel = a:headers[0][0] + for [level, _] in a:headers + let minlevel = min([minlevel, level]) + endfor + return minlevel +endfunction + function! s:read_captions(files) let result = {} - let rx_header = vimwiki#vars#get_syntaxlocal('rxHeader') + let caption_level = vimwiki#vars#get_wikilocal('diary_caption_level') + for fl in a:files " remove paths and extensions - let fl_key = substitute(fnamemodify(fl, ':t'), vimwiki#vars#get_wikilocal('ext').'$', '', '') + let fl_captions = {} + + " Default; no captions from the file. + let fl_captions['top'] = '' + let fl_captions['rest'] = [] + + if caption_level >= 0 && filereadable(fl) + if caption_level == 0 + " Take first header of any level as the top caption. + let fl_captions['top'] = s:get_first_header(fl) + else + let headers = s:get_all_headers(fl, caption_level) + if len(headers) > 0 + " If first header is the only one at its level or less, then make it the top caption. + let [first_level, first_header] = headers[0] + if s:count_headers_level_less_equal(headers, first_level) == 1 + let fl_captions['top'] = first_header + call remove(headers, 0) + endif - if filereadable(fl) - for line in readfile(fl, '', s:vimwiki_max_scan_for_caption) - if line =~# rx_header && !has_key(result, fl_key) - let result[fl_key] = vimwiki#u#trim(matchstr(line, rx_header)) + let min_header_level = s:get_min_header_level(headers) + for [level, header] in headers + call add(fl_captions['rest'], [level - min_header_level, header]) + endfor endif - endfor - endif - - if !has_key(result, fl_key) - let result[fl_key] = '' + endif endif + let fl_key = substitute(fnamemodify(fl, ':t'), vimwiki#vars#get_wikilocal('ext').'$', '', '') + let result[fl_key] = fl_captions endfor return result endfunction @@ -149,22 +221,36 @@ function! s:format_diary() call add(result, substitute(vimwiki#vars#get_syntaxlocal('rxH3_Template'), \ '__Header__', s:get_month_name(month), '')) - for [fl, cap] in s:sort(items(g_files[year][month])) + for [fl, captions] in s:sort(items(g_files[year][month])) + let topcap = captions['top'] let link_tpl = vimwiki#vars#get_global('WikiLinkTemplate2') if vimwiki#vars#get_wikilocal('syntax') == 'markdown' let link_tpl = vimwiki#vars#get_syntaxlocal('Weblink1Template') - if empty(cap) " When using markdown syntax, we should ensure we always have a link description. - let cap = fl + if empty(topcap) " When using markdown syntax, we should ensure we always have a link description. + let topcap = fl endif - elseif empty(cap) - let link_tpl = vimwiki#vars#get_global('WikiLinkTemplate1') endif - let entry = substitute(link_tpl, '__LinkUrl__', fl, '') - let entry = substitute(entry, '__LinkDescription__', cap, '') + if empty(topcap) + let top_link_tpl = vimwiki#vars#get_global('WikiLinkTemplate1') + else + let top_link_tpl = link_tpl + endif + + let entry = substitute(top_link_tpl, '__LinkUrl__', fl, '') + let entry = substitute(entry, '__LinkDescription__', topcap, '') call add(result, repeat(' ', vimwiki#lst#get_list_margin()).'* '.entry) + + for [depth, subcap] in captions['rest'] + if empty(subcap) + continue + endif + let entry = substitute(link_tpl, '__LinkUrl__', fl.'#'.subcap, '') + let entry = substitute(entry, '__LinkDescription__', subcap, '') + call add(result, repeat(' ', vimwiki#lst#get_list_margin() * (2 + depth)).'- '.entry) + endfor endfor endfor @@ -285,7 +371,7 @@ 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) - let content_rx = '^\%(\s*\* \)\|\%(^\s*$\)\|\%('.vimwiki#vars#get_syntaxlocal('rxHeader').'\)' + let content_rx = '^\%(\s*[*-] \)\|\%(^\s*$\)\|\%('.vimwiki#vars#get_syntaxlocal('rxHeader').'\)' call vimwiki#base#update_listing_in_buffer(s:format_diary(), \ vimwiki#vars#get_wikilocal('diary_header'), content_rx, line('$')+1, 1, 1) else @@ -324,4 +410,3 @@ function vimwiki#diary#calendar_sign(day, month, year) \ a:year.'-'.month.'-'.day.vimwiki#vars#get_wikilocal('ext') return filereadable(expand(sfile)) endfunction - diff --git a/autoload/vimwiki/vars.vim b/autoload/vimwiki/vars.vim @@ -254,6 +254,7 @@ function! s:populate_wikilocal_options() \ 'diary_header': {'type': type(''), 'default': 'Diary', 'min_length': 1}, \ 'diary_index': {'type': type(''), 'default': 'diary', 'min_length': 1}, \ 'diary_rel_path': {'type': type(''), 'default': 'diary/', 'min_length': 1}, + \ 'diary_caption_level': {'type': type(0), 'default': 0, 'min': -1, 'max': 6}, \ 'diary_sort': {'type': type(''), 'default': 'desc', 'possible_values': ['asc', 'desc']}, \ 'ext': {'type': type(''), 'default': '.wiki', 'min_length': 1}, \ 'index': {'type': type(''), 'default': 'index', 'min_length': 1}, @@ -444,6 +445,9 @@ function! vimwiki#vars#populate_syntax_vars(syntax) let g:vimwiki_syntax_variables[a:syntax]['rxH'.i] = \ '^\s*'.header_symbol.'\{'.i.'}[^'.header_symbol.'].*[^'.header_symbol.']' \ .header_symbol.'\{'.i.'}\s*$' + let g:vimwiki_syntax_variables[a:syntax]['rxH'.i.'_Text'] = + \ '^\s*'.header_symbol.'\{'.i.'}\zs[^'.header_symbol.'].*[^'.header_symbol.']\ze' + \ .header_symbol.'\{'.i.'}\s*$' let g:vimwiki_syntax_variables[a:syntax]['rxH'.i.'_Start'] = \ '^\s*'.header_symbol.'\{'.i.'}[^'.header_symbol.'].*[^'.header_symbol.']' \ .header_symbol.'\{'.i.'}\s*$' @@ -460,6 +464,8 @@ function! vimwiki#vars#populate_syntax_vars(syntax) \ repeat(header_symbol, i).' __Header__' let g:vimwiki_syntax_variables[a:syntax]['rxH'.i] = \ '^\s*'.header_symbol.'\{'.i.'}[^'.header_symbol.'].*$' + let g:vimwiki_syntax_variables[a:syntax]['rxH'.i.'_Text'] = + \ '^\s*'.header_symbol.'\{'.i.'}\zs[^'.header_symbol.'].*\ze$' let g:vimwiki_syntax_variables[a:syntax]['rxH'.i.'_Start'] = \ '^\s*'.header_symbol.'\{'.i.'}[^'.header_symbol.'].*$' let g:vimwiki_syntax_variables[a:syntax]['rxH'.i.'_End'] = @@ -857,4 +863,3 @@ endfunction function! vimwiki#vars#number_of_wikis() return len(g:vimwiki_wikilocal_vars) - 1 endfunction - diff --git a/doc/vimwiki.txt b/doc/vimwiki.txt @@ -2244,6 +2244,26 @@ Description~ Sort links in a diary index page. +*vimwiki-option-diary_caption_level* +------------------------------------------------------------------------------ +Key Default value~ +diary_caption_level 0 + +Description~ +Controls the presence of captions in the diary index linking to headers within +the diary pages. + +Possible values: +-1: No headers are read from the diary page. + 0: The first header from the diary page is used as the caption. + There are no sub-captions. + 1: Captions are created for headers of level 1 in the diary page. + 2: Captions are created for headers up to level 2 in the diary page. + etc. + +When the value is >= 1, the primary caption of each diary page is set to the +first header read from that page if it is the unique lowest-level header. + *vimwiki-option-custom_wiki2html* ------------------------------------------------------------------------------ Key Default value~