Fix: VimwikiTOC is broken against headers with link (Issue #182)
Problem: VimwikiTOC and follow_link do not support header (anchor) with link in their body Solution: - VimwikiTOC (easy): Create function base.vim s:clean_header_text that converts [DESC](URL) -> DESC - follow_link (hard): -- [[URL]]: was already working due to punctuation removal. -- [DESC](URL): Search for a potential `]([^)]*)` after every character
This commit is contained in:
parent
e4186adc3d
commit
69ead3bf3c
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
[中文](README-cn.md)
|
[中文](README-cn.md)
|
||||||
|
|
||||||
- [Intro](#intro)
|
- [Intro](#introduction)
|
||||||
- [Screenshots](#screenshots)
|
- [Screenshots](#screenshots)
|
||||||
- [Installation](#installation)
|
- [Installation](#installation)
|
||||||
- [Prerequisites](#prerequisites)
|
- [Prerequisites](#prerequisites)
|
||||||
|
@ -761,8 +761,13 @@ function! s:unnormalize_anchor(anchor) abort
|
|||||||
" -- Done after: Add spaces leading and trailing => Later with the template
|
" -- Done after: Add spaces leading and trailing => Later with the template
|
||||||
" Link: Inspired from https://gist.github.com/asabaylus/3071099
|
" Link: Inspired from https://gist.github.com/asabaylus/3071099
|
||||||
" Issue: #664 => Points to all others
|
" Issue: #664 => Points to all others
|
||||||
|
|
||||||
let anchor = a:anchor
|
let anchor = a:anchor
|
||||||
let punctuation_rx = s:get_punctuaction_regex() . '*'
|
let punctuation_rx = s:get_punctuaction_regex()
|
||||||
|
" Permit url part of link: '](www.i.did.it.my.way.cl)'
|
||||||
|
let link_rx = '\%(\]([^)]*)\)'
|
||||||
|
let invisible_rx = '\%( \|-\|' . punctuation_rx . '\|' . link_rx . '\)'
|
||||||
|
|
||||||
|
|
||||||
" 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
|
||||||
@ -773,7 +778,7 @@ function! s:unnormalize_anchor(anchor) abort
|
|||||||
let anchor_nb = 1
|
let anchor_nb = 1
|
||||||
else
|
else
|
||||||
" Yes Sufix: number <- read suffix
|
" Yes Sufix: number <- read suffix
|
||||||
let sufix = '[ \-]' . anchor_nb
|
let sufix = invisible_rx.'*' . anchor_nb . invisible_rx.'*'
|
||||||
let anchor_nb = str2nr(anchor_nb)
|
let anchor_nb = str2nr(anchor_nb)
|
||||||
endif
|
endif
|
||||||
" -- Remove it
|
" -- Remove it
|
||||||
@ -782,22 +787,34 @@ function! s:unnormalize_anchor(anchor) abort
|
|||||||
" For each char
|
" For each char
|
||||||
let anchor_loop = ''
|
let anchor_loop = ''
|
||||||
for char in split(anchor, '\zs')
|
for char in split(anchor, '\zs')
|
||||||
|
" Nest the char for easyer debugging
|
||||||
|
let anchor_loop .= '\%('
|
||||||
|
|
||||||
" 3 Change any space to a hyphen
|
" 3 Change any space to a hyphen
|
||||||
if char ==# '-'
|
if char ==# '-'
|
||||||
let anchor_loop .= '[ \-]\+'
|
" Match Space or hyphen or punctuation or link
|
||||||
|
let anchor_loop .= invisible_rx.'\+'
|
||||||
|
|
||||||
" 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_loop .= char . punctuation_rx
|
" Match My_char . punctuation . ( link . punctuaction )?
|
||||||
|
" Note: Because there may be punctuation before ad after link
|
||||||
|
let anchor_loop .= char . punctuation_rx.'*'
|
||||||
|
let anchor_loop .= '\%(' . link_rx . punctuation_rx.'*' . '\)' . '\?'
|
||||||
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
" Close nest
|
||||||
|
let anchor_loop .= '\)'
|
||||||
endfor
|
endfor
|
||||||
let anchor = punctuation_rx . anchor_loop
|
let anchor = punctuation_rx.'*' . anchor_loop
|
||||||
|
|
||||||
" 1 Downcase the string
|
" 1 Downcase the string
|
||||||
let anchor = '\c' . anchor
|
let anchor = '\c' . anchor
|
||||||
|
|
||||||
" 4.bis Add the optional suffix
|
" 4.bis Add the optional suffix
|
||||||
let anchor = anchor . '\(' . sufix . '\)\?'
|
let anchor = anchor . '\%(' . sufix . '\)\?'
|
||||||
|
|
||||||
return [anchor, anchor_nb]
|
return [anchor, anchor_nb]
|
||||||
endfunction
|
endfunction
|
||||||
@ -833,7 +850,7 @@ function! s:jump_to_anchor(anchor) abort
|
|||||||
|
|
||||||
" Go: Move cursor: maybe more than onces (see markdown suffix)
|
" Go: Move cursor: maybe more than onces (see markdown suffix)
|
||||||
let success_nb = 0
|
let success_nb = 0
|
||||||
let fail = 0
|
let is_last_segment = 0
|
||||||
for i in range(segment_nb)
|
for i in range(segment_nb)
|
||||||
" Search
|
" Search
|
||||||
let pos = 0
|
let pos = 0
|
||||||
@ -841,25 +858,42 @@ function! s:jump_to_anchor(anchor) abort
|
|||||||
let pos = pos != 0 ? pos : search(anchor_header, 'Wc')
|
let pos = pos != 0 ? pos : search(anchor_header, 'Wc')
|
||||||
let pos = pos != 0 ? pos : search(anchor_bold, 'Wc')
|
let pos = pos != 0 ? pos : search(anchor_bold, 'Wc')
|
||||||
|
|
||||||
|
echom 'Tin pos: ' . pos
|
||||||
|
|
||||||
" Get the result and reloop or leave
|
" Get the result and reloop or leave
|
||||||
if pos != 0
|
if pos != 0
|
||||||
" Avance, one line more to not rematch the same pattern if not last segment_nb
|
" 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
|
if success_nb < segment_nb-1
|
||||||
|
let pos += 1
|
||||||
|
let is_last_segment = -1
|
||||||
|
endif
|
||||||
call cursor(pos, 1)
|
call cursor(pos, 1)
|
||||||
let success_nb += 1
|
let success_nb += 1
|
||||||
|
|
||||||
|
" Break if last line (avoid infinite loop)
|
||||||
|
" Anyway leave the loop: (Imagine heading # 7271212 at last line)
|
||||||
|
if pos >= line('$')
|
||||||
|
let is_last_segment = 1
|
||||||
|
break
|
||||||
|
endif
|
||||||
" Do not move
|
" Do not move
|
||||||
" But maybe suffix -2 is not the segment number but the real header suffix
|
" But maybe suffix -2 is not the segment number but the real header suffix
|
||||||
" TODO make this more robust
|
" TODO make this more robust
|
||||||
elseif i == 0
|
else
|
||||||
" Next segment (default syntax)
|
" If fail at first: do not move
|
||||||
call setpos('.', oldpos)
|
if i == 0
|
||||||
let fail = 1
|
call setpos('.', oldpos)
|
||||||
|
endif
|
||||||
|
" Anyway leave the loop: (Imagine heading # 7271212, you do not want to loop all that)
|
||||||
|
" Go one line back: if I advanced too much
|
||||||
|
if is_last_segment == -1 | call cursor(line('.')-1, 1) | endif
|
||||||
|
let is_last_segment = 1
|
||||||
break
|
break
|
||||||
endif
|
endif
|
||||||
endfor
|
endfor
|
||||||
|
|
||||||
" Check if happy
|
" Check if happy
|
||||||
if success_nb == segment_nb || fail == 1
|
if success_nb == segment_nb || is_last_segment == 1
|
||||||
break
|
break
|
||||||
endif
|
endif
|
||||||
|
|
||||||
@ -1840,7 +1874,7 @@ function! vimwiki#base#rename_link(...) abort
|
|||||||
|
|
||||||
" Wipeout the old buffer: avoid surprises <= If it is not the same
|
" Wipeout the old buffer: avoid surprises <= If it is not the same
|
||||||
if buf_old_info[2] != buf_new_nb
|
if buf_old_info[2] != buf_new_nb
|
||||||
exe 'bwipeout! ' . buf_old_info[2]
|
exe 'bwipeout! ' . buf_old_info[2]
|
||||||
else
|
else
|
||||||
" Should not happen
|
" Should not happen
|
||||||
echomsg 'Vimwiki Error: New buffer is the same as old, so will not delete: '
|
echomsg 'Vimwiki Error: New buffer is the same as old, so will not delete: '
|
||||||
@ -2258,6 +2292,22 @@ function! s:current_header(headers, line_number) abort
|
|||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
|
||||||
|
" Returns: heading with link urls
|
||||||
|
" Called: table_of_content
|
||||||
|
function! s:clean_header_text(h_text) abort
|
||||||
|
" Note: I hardcode, who cares ?
|
||||||
|
let h_text = a:h_text
|
||||||
|
|
||||||
|
" Convert: [[url]] -> url
|
||||||
|
let h_text = substitute(h_text, '\[\[\([^]]*\)\]\]', '\1', 'g')
|
||||||
|
|
||||||
|
" Convert: [desc](url) -> url
|
||||||
|
let h_text = substitute(h_text, '\[\([^]]*\)\]([^)]*)', '\1', 'g')
|
||||||
|
|
||||||
|
return h_text
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
|
||||||
" Returns: index of neighbor header
|
" Returns: index of neighbor header
|
||||||
" Called: by header cursor movements
|
" Called: by header cursor movements
|
||||||
function! s:get_another_header(headers, current_index, direction, operation) abort
|
function! s:get_another_header(headers, current_index, direction, operation) abort
|
||||||
@ -2341,7 +2391,7 @@ endfunction
|
|||||||
" a:create == 1: creates or updates TOC in current file
|
" a:create == 1: creates or updates TOC in current file
|
||||||
" a:create == 0: update if TOC exists
|
" a:create == 0: update if TOC exists
|
||||||
function! vimwiki#base#table_of_contents(create) abort
|
function! vimwiki#base#table_of_contents(create) abort
|
||||||
" Collect headers
|
" Gather heading
|
||||||
let headers = s:collect_headers()
|
let headers = s:collect_headers()
|
||||||
let toc_header_text = vimwiki#vars#get_wikilocal('toc_header')
|
let toc_header_text = vimwiki#vars#get_wikilocal('toc_header')
|
||||||
|
|
||||||
@ -2365,7 +2415,7 @@ function! vimwiki#base#table_of_contents(create) abort
|
|||||||
" copy all local variables into dict (add a: if arguments are needed)
|
" copy all local variables into dict (add a: if arguments are needed)
|
||||||
let GeneratorTOC = copy(l:)
|
let GeneratorTOC = copy(l:)
|
||||||
function! GeneratorTOC.f() abort
|
function! GeneratorTOC.f() abort
|
||||||
" Gather heading informations
|
" Clean heading informations
|
||||||
let numbering = vimwiki#vars#get_global('html_header_numbering')
|
let numbering = vimwiki#vars#get_global('html_header_numbering')
|
||||||
" TODO numbering not used !
|
" TODO numbering not used !
|
||||||
let headers_levels = [['', 0], ['', 0], ['', 0], ['', 0], ['', 0], ['', 0]]
|
let headers_levels = [['', 0], ['', 0], ['', 0], ['', 0], ['', 0], ['', 0]]
|
||||||
@ -2373,16 +2423,21 @@ function! vimwiki#base#table_of_contents(create) abort
|
|||||||
for header in self.headers
|
for header in self.headers
|
||||||
let h_text = header[2]
|
let h_text = header[2]
|
||||||
let h_level = header[1]
|
let h_level = header[1]
|
||||||
|
|
||||||
" Don't include the TOC's header itself
|
" Don't include the TOC's header itself
|
||||||
if h_text ==# self.toc_header_text
|
if h_text ==# self.toc_header_text
|
||||||
continue
|
continue
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
" Clean text
|
||||||
|
let h_text = s:clean_header_text(h_text)
|
||||||
|
|
||||||
|
" Treat levels
|
||||||
let headers_levels[h_level-1] = [h_text, headers_levels[h_level-1][1]+1]
|
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
|
for idx in range(h_level, 5) | let headers_levels[idx] = ['', 0] | endfor
|
||||||
|
|
||||||
let h_complete_id = ''
|
|
||||||
|
|
||||||
" Add description to the link if toc_link_format == 1 => extended
|
" Add description to the link if toc_link_format == 1 => extended
|
||||||
|
let h_complete_id = ''
|
||||||
if vimwiki#vars#get_wikilocal('toc_link_format') == 1
|
if vimwiki#vars#get_wikilocal('toc_link_format') == 1
|
||||||
for l in range(h_level-1)
|
for l in range(h_level-1)
|
||||||
if headers_levels[l][0] !=? ''
|
if headers_levels[l][0] !=? ''
|
||||||
@ -2392,6 +2447,7 @@ function! vimwiki#base#table_of_contents(create) abort
|
|||||||
endif
|
endif
|
||||||
let h_complete_id .= headers_levels[h_level-1][0]
|
let h_complete_id .= headers_levels[h_level-1][0]
|
||||||
|
|
||||||
|
" Store
|
||||||
call add(complete_header_infos, [h_level, h_complete_id, h_text])
|
call add(complete_header_infos, [h_level, h_complete_id, h_text])
|
||||||
endfor
|
endfor
|
||||||
|
|
||||||
|
@ -900,14 +900,14 @@ function! s:populate_extra_markdown_vars() abort
|
|||||||
let rxWeblink1Ext = '__FileExtension__'
|
let rxWeblink1Ext = '__FileExtension__'
|
||||||
endif
|
endif
|
||||||
|
|
||||||
" [DESCRIPTION](URL)
|
" [DESCRIPTION](FILE.MD)
|
||||||
let mkd_syntax.Weblink1Template = mkd_syntax.rxWeblink1Prefix . '__LinkDescription__'.
|
let mkd_syntax.Weblink1Template = mkd_syntax.rxWeblink1Prefix . '__LinkDescription__'.
|
||||||
\ mkd_syntax.rxWeblink1Separator. '__LinkUrl__'. rxWeblink1Ext.
|
\ mkd_syntax.rxWeblink1Separator. '__LinkUrl__'. rxWeblink1Ext.
|
||||||
\ mkd_syntax.rxWeblink1Suffix
|
\ mkd_syntax.rxWeblink1Suffix
|
||||||
" [DESCRIPTION](ANCHOR)
|
" [DESCRIPTION](FILE)
|
||||||
let mkd_syntax.Weblink2Template = mkd_syntax.rxWeblink1Prefix . '__LinkDescription__'.
|
let mkd_syntax.Weblink2Template = mkd_syntax.rxWeblink1Prefix . '__LinkDescription__'.
|
||||||
\ mkd_syntax.rxWeblink1Separator. '__LinkUrl__'. mkd_syntax.rxWeblink1Suffix
|
\ mkd_syntax.rxWeblink1Separator. '__LinkUrl__'. mkd_syntax.rxWeblink1Suffix
|
||||||
" [DESCRIPTION](FILE#ANCHOR)
|
" [DESCRIPTION](FILE.MD#ANCHOR)
|
||||||
let mkd_syntax.Weblink3Template = mkd_syntax.rxWeblink1Prefix . '__LinkDescription__'.
|
let mkd_syntax.Weblink3Template = mkd_syntax.rxWeblink1Prefix . '__LinkDescription__'.
|
||||||
\ mkd_syntax.rxWeblink1Separator. '__LinkUrl__'. rxWeblink1Ext.
|
\ mkd_syntax.rxWeblink1Separator. '__LinkUrl__'. rxWeblink1Ext.
|
||||||
\ '#__LinkAnchor__'. mkd_syntax.rxWeblink1Suffix
|
\ '#__LinkAnchor__'. mkd_syntax.rxWeblink1Suffix
|
||||||
|
@ -3743,6 +3743,7 @@ Changed:~
|
|||||||
Removed:~
|
Removed:~
|
||||||
|
|
||||||
Fixed:~
|
Fixed:~
|
||||||
|
* Issue #182: VimwikiTOC support headers with link
|
||||||
* Issue #813: iMap <Cr> interfere with completion (pum)
|
* Issue #813: iMap <Cr> interfere with completion (pum)
|
||||||
* Issue #709: Support inline code spans inside emphasis
|
* Issue #709: Support inline code spans inside emphasis
|
||||||
Refactoring code, del, eq, sup, sub as regions
|
Refactoring code, del, eq, sup, sub as regions
|
||||||
|
@ -141,7 +141,7 @@ else
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
||||||
" Weblink
|
" Weblink [DESCRIPTION](FILE)
|
||||||
call s:add_target_syntax_ON(vimwiki#vars#get_syntaxlocal('rxWeblink'), 'VimwikiLink')
|
call s:add_target_syntax_ON(vimwiki#vars#get_syntaxlocal('rxWeblink'), 'VimwikiLink')
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
# VimwikiTOC {{{1
|
# VimwikiTOC {{{1
|
||||||
#
|
#
|
||||||
# TODO implement: If link in the heading (see README.md)
|
# Just generate the TOC
|
||||||
|
# See: link_* for link movement and creation
|
||||||
|
#
|
||||||
# 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)
|
||||||
@ -28,6 +30,30 @@
|
|||||||
#
|
#
|
||||||
# Start {{{1
|
# Start {{{1
|
||||||
|
|
||||||
|
Given vimwiki (With link header (#182) {{{1):
|
||||||
|
# A [link](anything here) B
|
||||||
|
# t[link](anything here)
|
||||||
|
|
||||||
|
## 7.4.1528
|
||||||
|
|
||||||
|
Execute (VimwikiTOC: Set syntax markdown && Set sw=8):
|
||||||
|
call SetSyntax('markdown')
|
||||||
|
set sw=8
|
||||||
|
VimwikiTOC
|
||||||
|
|
||||||
|
Expect vimwiki (With link header (#182) {{{1):
|
||||||
|
# Contents
|
||||||
|
|
||||||
|
- [A link B](#a-link-b)
|
||||||
|
- [tlink](#tlink)
|
||||||
|
- [7.4.1528](#741528)
|
||||||
|
|
||||||
|
# A [link](anything here) B
|
||||||
|
# t[link](anything here)
|
||||||
|
|
||||||
|
## 7.4.1528
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Given vimwiki (Underline header (SetExt) (#209) {{{1):
|
Given vimwiki (Underline header (SetExt) (#209) {{{1):
|
||||||
First with spaces
|
First with spaces
|
||||||
|
@ -1,7 +1,14 @@
|
|||||||
# Link internal to a file
|
# Link internal to a file
|
||||||
|
#
|
||||||
|
# See: generate_toc.vim
|
||||||
|
#
|
||||||
# See issue #666 for anchor support (then internal links)
|
# See issue #666 for anchor support (then internal links)
|
||||||
# Preambule set file onces and for all {{{1
|
# Preambule set file onces and for all {{{1
|
||||||
# Otherwise the bash script is freezing
|
# Otherwise the bash script is freezing
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Given vimwiki (a):
|
Given vimwiki (a):
|
||||||
a
|
a
|
||||||
|
|
||||||
@ -11,6 +18,52 @@ Execute (Set filename wiki_test.md):
|
|||||||
Expect (a):
|
Expect (a):
|
||||||
a
|
a
|
||||||
|
|
||||||
|
|
||||||
|
Given vimwiki (VimwikiTOC is broken against headers with link #182 {{{1):
|
||||||
|
[A link B](#a-link-b)
|
||||||
|
[tlink](#tlink)
|
||||||
|
[7.4.1528](#741528)
|
||||||
|
[link (333)](#link-333)
|
||||||
|
|
||||||
|
# A [link](anything here) B
|
||||||
|
|
||||||
|
# t[link](anything here)
|
||||||
|
|
||||||
|
## 7.4.1528
|
||||||
|
|
||||||
|
#### [link]() (333)
|
||||||
|
|
||||||
|
|
||||||
|
Execute (VimwikiTOC: Set syntax markdown && Set sw=8):
|
||||||
|
call SetSyntax('markdown')
|
||||||
|
|
||||||
|
|
||||||
|
Do (Enter link):
|
||||||
|
gg\<Cr>
|
||||||
|
A__HERE1__\<Esc>
|
||||||
|
ggj\<Cr>
|
||||||
|
A__HERE2__\<Esc>
|
||||||
|
ggjj\<Cr>
|
||||||
|
A__HERE3__\<Esc>
|
||||||
|
ggjjj\<Cr>
|
||||||
|
A__HERE4__\<Esc>
|
||||||
|
|
||||||
|
Expect vimwiki (Good anchor with link navigation):
|
||||||
|
[A link B](#a-link-b)
|
||||||
|
[tlink](#tlink)
|
||||||
|
[7.4.1528](#741528)
|
||||||
|
[link (333)](#link-333)
|
||||||
|
|
||||||
|
# A [link](anything here) B__HERE1__
|
||||||
|
|
||||||
|
# t[link](anything here)__HERE2__
|
||||||
|
|
||||||
|
## 7.4.1528__HERE3__
|
||||||
|
|
||||||
|
#### [link]() (333)__HERE4__
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Link to anchor in SetExt {{{1
|
# Link to anchor in SetExt {{{1
|
||||||
# Like that
|
# Like that
|
||||||
# -----
|
# -----
|
||||||
|
Loading…
Reference in New Issue
Block a user