commit 428c60a45e7a5fbf874d5f5f7e6c16cb95b10a62
parent a27940a394ec46743de142c834eebe42f3548fbf
Author: Tinmarino <tinmarino@gmail.com>
Date: Sun, 2 Aug 2020 23:10:44 -0400
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)
Diffstat:
2 files changed, 124 insertions(+), 33 deletions(-)
diff --git a/autoload/vimwiki/base.vim b/autoload/vimwiki/base.vim
@@ -692,16 +692,28 @@ endfunction
" Called: normalize and unnormalize anchor
function! s:get_punctuaction_regex() abort
" From: https://gist.github.com/asabaylus/3071099#gistcomment-2563127
- return '[^0-9a-zA-Z\u4e00-\u9fff_ \-]'
+ 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_ \-]'
+ endif
endfunction
" :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
-function! s:normalize_anchor(anchor) abort
+function! s:normalize_anchor(anchor, ...) abort
" Note: See unormalize
" 0 Get in
let anchor = a:anchor
+ if a:0
+ let previous_anchors = a:1
+ else
+ let previous_anchors = {}
+ endif
" A Trim space
let anchor = vimwiki#u#trim(anchor)
@@ -717,14 +729,25 @@ function! s:normalize_anchor(anchor) abort
" 3 Change any space to a hyphen
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
endfunction
" :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
" Note:
" -- 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
" -- Save the trailing -12
- let sufix = substitute(anchor, '^.*-\(\d\+\)$', '\1', '')
- if sufix !=# ''
- let sufix = '[ \-]' . sufix
+ let anchor_nb = substitute(anchor, '^.*-\(\d\+\)$', '\1', '')
+ if anchor_nb ==# '' || anchor_nb == 0
+ " 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
" -- Remove it
let anchor = substitute(anchor, '\(-\d\+\)$', '', '')
" For each char
- let anchor_r = ''
+ let anchor_loop = ''
for char in split(anchor, '\zs')
" 3 Change any space to a hyphen
if char ==# '-'
- let anchor_r .= '[ \-]'
+ let anchor_loop .= '[ \-]'
" 2 Remove anything that is not a letter, number, CJK character, hyphen or space
" -- So add puncutation regex at each char
else
- let anchor_r .= char . punctuation_rx
+ let anchor_loop .= char . punctuation_rx
endif
endfor
- let anchor = punctuation_rx . anchor_r
+ let anchor = punctuation_rx . anchor_loop
" 1 Downcase the string
let anchor = '\c' . anchor
@@ -763,7 +792,7 @@ function! s:unnormalize_anchor(anchor) abort
" 4.bis Add the optional suffix
let anchor = anchor . '\(' . sufix . '\)\?'
- return anchor
+ return [anchor, anchor_nb]
endfunction
@@ -771,32 +800,60 @@ endfunction
" Called: edit_file
" TODO treat the sufix: -2 -> Go to second anchor
function! s:jump_to_anchor(anchor) abort
+ " Save cursor %% Initialize at top of line
let oldpos = getpos('.')
call cursor(1, 1)
+ " Get segments <= anchor
let anchor = vimwiki#u#escape(a:anchor)
-
let segments = split(anchor, '#', 0)
+ " For markdown: there is only one segment
for segment in segments
" Craft segment pattern so that it is case insensitive and also matches dashes
" 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(
\ vimwiki#vars#get_syntaxlocal('header_match'),
- \ '__Header__', segment, '')
+ \ '__Header__', segment_re, '')
let anchor_bold = s:safesubstitute(
\ vimwiki#vars#get_syntaxlocal('bold_match'),
- \ '__Text__', segment, '')
+ \ '__Text__', segment_re, '')
let anchor_tag = s:safesubstitute(
\ vimwiki#vars#get_syntaxlocal('tag_match'),
- \ '__Tag__', segment, '')
+ \ '__Tag__', segment_re, '')
+
+ " 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)
+ let fail = 1
+ break
+ endif
+ endfor
- if !search(anchor_tag, 'Wc') && !search(anchor_header, 'Wc') && !search(anchor_bold, 'Wc')
- call setpos('.', oldpos)
+ " Check if happy
+ if success_nb == segment_nb || fail == 1
break
endif
+
+ " Or keep on (i.e more than once segment)
let oldpos = getpos('.')
endfor
endfunction
@@ -2296,6 +2353,8 @@ function! vimwiki#base#table_of_contents(create) abort
let startindent = repeat(' ', vimwiki#lst#get_list_margin())
let indentstring = repeat(' ', vimwiki#u#sw())
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
if vimwiki#vars#get_wikilocal('syntax') ==# 'markdown'
let link_tpl = vimwiki#vars#get_syntaxlocal('Weblink2Template')
@@ -2306,7 +2365,7 @@ function! vimwiki#base#table_of_contents(create) abort
endif
" Normalize anchor
- let anchor = s:normalize_anchor(anchor)
+ let anchor = s:normalize_anchor(anchor, previous_anchors)
" Insert link in template
let link = s:safesubstitute(link_tpl, '__LinkUrl__',
diff --git a/test/command_toc.vader b/test/command_toc.vader
@@ -1,5 +1,6 @@
# 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 vimviki_toc_link_format
# 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
# -- 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
-" TODO
-"Given vimwiki (Two same heading {{{1):
-" # One
-" ## two
-" ## Two
-"
-"Execute (Set syntax markdown && Set sw=8):
-" call SetSyntax('markdown')
-" set sw=8
-" VimwikiTOC
-"
-"Expect (Suffix -1 and -2):
-"
+
+
+Given vimwiki (Two same heading (#968) {{{1):
+ # One
+ toto
+ # ONE
+ like
+ ## oNe
+ you
+
+Execute (Set syntax markdown && Set sw=8):
+ 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):
# One !@#@#(!%#&$^(!@