Feature: Markdown link: VimwikiTOC supports multiple heading with same name (Issue: #968, 666, #664)

Anchor can be suffixed with -1 -2 according to the heading number (in
file) user want to reach.
Implemented with a dictionary for caching anchor names (without sufix)
This commit is contained in:
Tinmarino 2020-08-02 23:10:44 -04:00
parent a27940a394
commit 428c60a45e
2 changed files with 124 additions and 33 deletions

View File

@ -692,16 +692,28 @@ endfunction
" Called: normalize and unnormalize anchor " Called: normalize and unnormalize anchor
function! s:get_punctuaction_regex() abort function! s:get_punctuaction_regex() abort
" From: https://gist.github.com/asabaylus/3071099#gistcomment-2563127 " From: https://gist.github.com/asabaylus/3071099#gistcomment-2563127
if v:version <= 703
" Retrocompatibility: Get invalid range for vim 7.03
return '[^0-9a-zA-Z_ \-]'
else
return '[^0-9a-zA-Z\u4e00-\u9fff_ \-]' return '[^0-9a-zA-Z\u4e00-\u9fff_ \-]'
endif
endfunction endfunction
" :param: anchor <string> <= Heading line " :param: anchor <string> <= Heading line
" :param: (1) previous_anchors <dic[IN/OUT]> of previous normalized anchor
" -- to know if must append -2, updated on the fly
" Return: anchor <string> => link in TOC " Return: anchor <string> => link in TOC
function! s:normalize_anchor(anchor) abort function! s:normalize_anchor(anchor, ...) abort
" Note: See unormalize " Note: See unormalize
" 0 Get in " 0 Get in
let anchor = a:anchor let anchor = a:anchor
if a:0
let previous_anchors = a:1
else
let previous_anchors = {}
endif
" A Trim space " A Trim space
let anchor = vimwiki#u#trim(anchor) let anchor = vimwiki#u#trim(anchor)
@ -717,14 +729,25 @@ function! s:normalize_anchor(anchor) abort
" 3 Change any space to a hyphen " 3 Change any space to a hyphen
let anchor = substitute(anchor, ' ', '-', 'g') let anchor = substitute(anchor, ' ', '-', 'g')
" 4.2 TODO anchor: If that is not unique, add '-1', '-2', '-3',... to make it unique " 4 Append '-1', '-2', '-3',... to make it unique <= If that not unique
if has_key(previous_anchors, anchor)
" Inc anchor number (before modifing the anchor)
let anchor_nb = previous_anchors[anchor] + 1
let previous_anchors[anchor] = anchor_nb
" Append suffix
let anchor .= '-' . string(anchor_nb)
else
" Save anchor in dic
let previous_anchors[anchor] = 1
endif
return anchor return anchor
endfunction endfunction
" :param: anchor <string> <= link " :param: anchor <string> <= link
" Return: anchor <regex> to look for " Return: [anchor_re <regex>, anchor_nb <number>] to look for
" -- Ex: ['toto", 2] => search for the second occurrence of toto
function! s:unnormalize_anchor(anchor) abort function! s:unnormalize_anchor(anchor) abort
" Note: " Note:
" -- Pandoc keep the '_' in anchor " -- Pandoc keep the '_' in anchor
@ -736,26 +759,32 @@ function! s:unnormalize_anchor(anchor) abort
" 4 Add '-1', '-2', '-3',... to make it unique if not unique " 4 Add '-1', '-2', '-3',... to make it unique if not unique
" -- Save the trailing -12 " -- Save the trailing -12
let sufix = substitute(anchor, '^.*-\(\d\+\)$', '\1', '') let anchor_nb = substitute(anchor, '^.*-\(\d\+\)$', '\1', '')
if sufix !=# '' if anchor_nb ==# '' || anchor_nb == 0
let sufix = '[ \-]' . sufix " No Sufix: number = 1
let sufix = ''
let anchor_nb = 1
else
" Yes Sufix: number <- read suffix
let sufix = '[ \-]' . anchor_nb
let anchor_nb = str2nr(anchor_nb)
endif endif
" -- Remove it " -- Remove it
let anchor = substitute(anchor, '\(-\d\+\)$', '', '') let anchor = substitute(anchor, '\(-\d\+\)$', '', '')
" For each char " For each char
let anchor_r = '' let anchor_loop = ''
for char in split(anchor, '\zs') for char in split(anchor, '\zs')
" 3 Change any space to a hyphen " 3 Change any space to a hyphen
if char ==# '-' if char ==# '-'
let anchor_r .= '[ \-]' let anchor_loop .= '[ \-]'
" 2 Remove anything that is not a letter, number, CJK character, hyphen or space " 2 Remove anything that is not a letter, number, CJK character, hyphen or space
" -- So add puncutation regex at each char " -- So add puncutation regex at each char
else else
let anchor_r .= char . punctuation_rx let anchor_loop .= char . punctuation_rx
endif endif
endfor endfor
let anchor = punctuation_rx . anchor_r let anchor = punctuation_rx . anchor_loop
" 1 Downcase the string " 1 Downcase the string
let anchor = '\c' . anchor let anchor = '\c' . anchor
@ -763,7 +792,7 @@ function! s:unnormalize_anchor(anchor) abort
" 4.bis Add the optional suffix " 4.bis Add the optional suffix
let anchor = anchor . '\(' . sufix . '\)\?' let anchor = anchor . '\(' . sufix . '\)\?'
return anchor return [anchor, anchor_nb]
endfunction endfunction
@ -771,32 +800,60 @@ endfunction
" Called: edit_file " Called: edit_file
" TODO treat the sufix: -2 -> Go to second anchor " TODO treat the sufix: -2 -> Go to second anchor
function! s:jump_to_anchor(anchor) abort function! s:jump_to_anchor(anchor) abort
" Save cursor %% Initialize at top of line
let oldpos = getpos('.') let oldpos = getpos('.')
call cursor(1, 1) call cursor(1, 1)
" Get segments <= anchor
let anchor = vimwiki#u#escape(a:anchor) let anchor = vimwiki#u#escape(a:anchor)
let segments = split(anchor, '#', 0) let segments = split(anchor, '#', 0)
" For markdown: there is only one segment
for segment in segments for segment in segments
" Craft segment pattern so that it is case insensitive and also matches dashes " Craft segment pattern so that it is case insensitive and also matches dashes
" in anchor link with spaces in heading " in anchor link with spaces in heading
let segment = s:unnormalize_anchor(segment) let [segment_re, segment_nb] = s:unnormalize_anchor(segment)
let anchor_header = s:safesubstitute( let anchor_header = s:safesubstitute(
\ vimwiki#vars#get_syntaxlocal('header_match'), \ vimwiki#vars#get_syntaxlocal('header_match'),
\ '__Header__', segment, '') \ '__Header__', segment_re, '')
let anchor_bold = s:safesubstitute( let anchor_bold = s:safesubstitute(
\ vimwiki#vars#get_syntaxlocal('bold_match'), \ vimwiki#vars#get_syntaxlocal('bold_match'),
\ '__Text__', segment, '') \ '__Text__', segment_re, '')
let anchor_tag = s:safesubstitute( let anchor_tag = s:safesubstitute(
\ vimwiki#vars#get_syntaxlocal('tag_match'), \ vimwiki#vars#get_syntaxlocal('tag_match'),
\ '__Tag__', segment, '') \ '__Tag__', segment_re, '')
if !search(anchor_tag, 'Wc') && !search(anchor_header, 'Wc') && !search(anchor_bold, 'Wc') " Go: Move cursor: maybe more than onces (see markdown suffix)
let success_nb = 0
let fail = 0
for i in range(segment_nb)
" Search
let pos = 0
let pos = pos != 0 ? pos : search(anchor_tag, 'Wc')
let pos = pos != 0 ? pos : search(anchor_header, 'Wc')
let pos = pos != 0 ? pos : search(anchor_bold, 'Wc')
" Get the result and reloop or leave
if pos != 0
" Avance, one line more to not rematch the same pattern if not last segment_nb
if success_nb < segment_nb-1 | let pos += 1 | endif
call cursor(pos, 1)
let success_nb += 1
else
" Next segment (default syntax)
call setpos('.', oldpos) call setpos('.', oldpos)
let fail = 1
break break
endif endif
endfor
" Check if happy
if success_nb == segment_nb || fail == 1
break
endif
" Or keep on (i.e more than once segment)
let oldpos = getpos('.') let oldpos = getpos('.')
endfor endfor
endfunction endfunction
@ -2296,6 +2353,8 @@ function! vimwiki#base#table_of_contents(create) abort
let startindent = repeat(' ', vimwiki#lst#get_list_margin()) let startindent = repeat(' ', vimwiki#lst#get_list_margin())
let indentstring = repeat(' ', vimwiki#u#sw()) let indentstring = repeat(' ', vimwiki#u#sw())
let bullet = vimwiki#lst#default_symbol().' ' let bullet = vimwiki#lst#default_symbol().' '
" Keep previous anchor => if redundant => add suffix -2
let previous_anchors = {}
for [lvl, anchor, desc] in complete_header_infos for [lvl, anchor, desc] in complete_header_infos
if vimwiki#vars#get_wikilocal('syntax') ==# 'markdown' if vimwiki#vars#get_wikilocal('syntax') ==# 'markdown'
let link_tpl = vimwiki#vars#get_syntaxlocal('Weblink2Template') let link_tpl = vimwiki#vars#get_syntaxlocal('Weblink2Template')
@ -2306,7 +2365,7 @@ function! vimwiki#base#table_of_contents(create) abort
endif endif
" Normalize anchor " Normalize anchor
let anchor = s:normalize_anchor(anchor) let anchor = s:normalize_anchor(anchor, previous_anchors)
" Insert link in template " Insert link in template
let link = s:safesubstitute(link_tpl, '__LinkUrl__', let link = s:safesubstitute(link_tpl, '__LinkUrl__',

View File

@ -1,5 +1,6 @@
# VimwikiTOC {{{1 # VimwikiTOC {{{1
# #
# TODO implement: If link in the heading (see README.md)
# TODO (10min) test if g:vimwiki_to_header well readen # TODO (10min) test if g:vimwiki_to_header well readen
# TODO (10min) test vimviki_toc_link_format # TODO (10min) test vimviki_toc_link_format
# TODO (1h) test if really wiki dependant (for 2 diffrent wikis) # TODO (1h) test if really wiki dependant (for 2 diffrent wikis)
@ -10,21 +11,52 @@
# -- 3. changes any space to a hyphen => OK: from previous big # -- 3. changes any space to a hyphen => OK: from previous big
# -- 4. If that is not unique, add "-1", "-2", "-3",... to make it unique => TODO not implemented # -- 4. If that is not unique, add "-1", "-2", "-3",... to make it unique => TODO not implemented
# #
#
# TODO if link in heading
#Given vimwiki (Two same heading {{{1):
# # Pre [link](anything no parenthesis) Post
#
#Execute (Set syntax markdown && Set sw=8):
# call SetSyntax('markdown')
# set sw=8
# VimwikiTOC
#
#Expect (Suffix -1 and -2):
#
#
#
#
# Start {{{1 # Start {{{1
" TODO
"Given vimwiki (Two same heading {{{1):
" # One Given vimwiki (Two same heading (#968) {{{1):
" ## two # One
" ## Two toto
" # ONE
"Execute (Set syntax markdown && Set sw=8): like
" call SetSyntax('markdown') ## oNe
" set sw=8 you
" VimwikiTOC
" Execute (Set syntax markdown && Set sw=8):
"Expect (Suffix -1 and -2): call SetSyntax('markdown')
" set sw=8
VimwikiTOC
Expect (Suffix -2 and -3):
# Contents
- [One](#one)
- [ONE](#one-2)
- [oNe](#one-3)
# One
toto
# ONE
like
## oNe
you
Given vimwiki (Heading with many bad caracters {{{1): Given vimwiki (Heading with many bad caracters {{{1):
# One !@#@#(!%#&$^(!@ # One !@#@#(!%#&$^(!@