From 2941913ccc2ca1e5bd2f482c770407a712810c1b Mon Sep 17 00:00:00 2001 From: EinfachToll Date: Fri, 6 Apr 2018 21:11:40 +0200 Subject: [PATCH] Add keys for motions between headers Fix #462 Inspired by #23 --- autoload/vimwiki/base.vim | 113 +++++++++++++++++++++++++++++--------- doc/vimwiki.txt | 28 ++++++++++ ftplugin/vimwiki.vim | 30 ++++++++++ 3 files changed, 146 insertions(+), 25 deletions(-) diff --git a/autoload/vimwiki/base.vim b/autoload/vimwiki/base.vim index 671a441..ddad388 100644 --- a/autoload/vimwiki/base.vim +++ b/autoload/vimwiki/base.vim @@ -1365,15 +1365,7 @@ function! vimwiki#base#TO_header(inner, including_subheaders, count) let current_line = line('.') - " look for the header under which the cursor sits - if current_line >= headers[-1][0] - let current_header_index = len(headers) - 1 - else - let current_header_index = -1 - while headers[current_header_index+1][0] <= current_line - let current_header_index += 1 - endwhile - endif + let current_header_index = s:current_header(headers, current_line) if current_header_index < 0 return @@ -1418,22 +1410,6 @@ function! vimwiki#base#TO_header(inner, including_subheaders, count) endfunction -function! s:get_another_header(headers, current_index, direction, operation) - let current_level = a:headers[a:current_index][1] - let index = a:current_index + a:direction - - while 1 - if index < 0 || index >= len(a:headers) - return -1 - endif - if eval('a:headers[index][1] ' . a:operation . ' current_level') - return index - endif - let index += a:direction - endwhile -endfunction - - " vimwiki#base#TO_table_cell function! vimwiki#base#TO_table_cell(inner, visual) "{{{ if col('.') == col('$')-1 @@ -1713,6 +1689,93 @@ function! s:collect_headers() endfunction +function! s:current_header(headers, line_number) + if empty(a:headers) + return -1 + endif + + if a:line_number >= a:headers[-1][0] + return len(a:headers) - 1 + endif + + let current_header_index = -1 + while a:headers[current_header_index+1][0] <= a:line_number + let current_header_index += 1 + endwhile + return current_header_index +endfunction + + +function! s:get_another_header(headers, current_index, direction, operation) + if empty(a:headers) || a:current_index < 0 + return -1 + endif + let current_level = a:headers[a:current_index][1] + let index = a:current_index + a:direction + + while 1 + if index < 0 || index >= len(a:headers) + return -1 + endif + if eval('a:headers[index][1] ' . a:operation . ' current_level') + return index + endif + let index += a:direction + endwhile +endfunction + + +function! vimwiki#base#goto_parent_header() + let headers = s:collect_headers() + let current_header_index = s:current_header(headers, line('.')) + let parent_header = s:get_another_header(headers, current_header_index, -1, '<') + if parent_header >= 0 + call cursor(headers[parent_header][0], 1) + else + echo 'Vimwiki: no parent header found' + endif +endfunction + + +function! vimwiki#base#goto_next_header() + let headers = s:collect_headers() + let current_header_index = s:current_header(headers, line('.')) + if current_header_index >= 0 && current_header_index < len(headers) - 1 + call cursor(headers[current_header_index + 1][0], 1) + else + echo 'Vimwiki: no next header found' + endif +endfunction + + +function! vimwiki#base#goto_prev_header() + let headers = s:collect_headers() + let current_header_index = s:current_header(headers, line('.')) + " if the cursor already was on a header, jump to the previous one + if current_header_index >= 1 && headers[current_header_index][0] == line('.') + let current_header_index -= 1 + endif + if current_header_index >= 0 + call cursor(headers[current_header_index][0], 1) + else + echom 'Vimwiki: no previous header found' + endif +endfunction + + +function! vimwiki#base#goto_sibling(direction) + let headers = s:collect_headers() + let current_header_index = s:current_header(headers, line('.')) + let next_potential_sibling = s:get_another_header(headers, current_header_index, a:direction, '<=') + if next_potential_sibling >= 0 && headers[next_potential_sibling][1] == + \ headers[current_header_index][1] + call cursor(headers[next_potential_sibling][0], 1) + else + echo 'Vimwiki: no sibling header found' + endif +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) diff --git a/doc/vimwiki.txt b/doc/vimwiki.txt index 30b407d..bcca97a 100644 --- a/doc/vimwiki.txt +++ b/doc/vimwiki.txt @@ -324,6 +324,34 @@ NORMAL MODE *vimwiki-local-mappings* - Remove header level. To remap: > :nmap -- VimwikiRemoveHeaderLevel +< + *vimwiki_[[* +[[ Go to the previous header in the buffer. + To remap: > + :nmap <- VimwikiGoToPrevHeader +< + *vimwiki_]]* +]] Go to the next header in the buffer. + To remap: > + :nmap -> VimwikiGoToNextHeader +< + *vimwiki_[=* +[= Go to the previous header which has the same level as + the header the cursor is currently under. + To remap: > + :nmap <= VimwikiGoToPrevSiblingHeader +< + *vimwiki_]=* +]= Go to the next header which has the same level as the + header the cursor is currently under. + To remap: > + :nmap => VimwikiGoToNextSiblingHeader +< + *vimwiki_]u* *vimwiki_[u* +]u [u Go one level up -- that is, to the parent header of + the header the cursor is currently under. + To remap: > + :nmap -^ VimwikiGoToParentHeader < *vimwiki_+* + Create and/or decorate links. Depending on the diff --git a/ftplugin/vimwiki.vim b/ftplugin/vimwiki.vim index 8ae421c..9d33bd7 100644 --- a/ftplugin/vimwiki.vim +++ b/ftplugin/vimwiki.vim @@ -662,6 +662,36 @@ endif nnoremap VimwikiRemoveHeaderLevel : \call vimwiki#base#RemoveHeaderLevel() +if !hasmapto('VimwikiGoToParentHeader') + nmap ]u VimwikiGoToParentHeader + nmap [u VimwikiGoToParentHeader +endif +nnoremap VimwikiGoToParentHeader : + \call vimwiki#base#goto_parent_header() + +if !hasmapto('VimwikiGoToNextHeader') + nmap ]] VimwikiGoToNextHeader +endif +nnoremap VimwikiGoToNextHeader : + \call vimwiki#base#goto_next_header() + +if !hasmapto('VimwikiGoToPrevHeader') + nmap [[ VimwikiGoToPrevHeader +endif +nnoremap VimwikiGoToPrevHeader : + \call vimwiki#base#goto_prev_header() + +if !hasmapto('VimwikiGoToNextSiblingHeader') + nmap ]= VimwikiGoToNextSiblingHeader +endif +nnoremap VimwikiGoToNextSiblingHeader : + \call vimwiki#base#goto_sibling(+1) + +if !hasmapto('VimwikiGoToPrevSiblingHeader') + nmap [= VimwikiGoToPrevSiblingHeader +endif +nnoremap VimwikiGoToPrevSiblingHeader : + \call vimwiki#base#goto_sibling(-1) " }}}