From d265df42f59973512d457a1d3c2d9906f5206661 Mon Sep 17 00:00:00 2001 From: Ivan Tishchenko Date: Fri, 27 Nov 2015 03:05:39 +0300 Subject: [PATCH 1/5] Prevent cursor moving up/down when TOC changes. getpos()/setpos() combination does not account for changes of lines count. So if you do getpos, then remove lines _above_ it, then do setpos -- it's going to be off. The fix calculates the "diff", and adjusts saved position for that diff (if any). --- autoload/vimwiki/base.vim | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/autoload/vimwiki/base.vim b/autoload/vimwiki/base.vim index b3c1a2d..da68849 100644 --- a/autoload/vimwiki/base.vim +++ b/autoload/vimwiki/base.vim @@ -1144,6 +1144,10 @@ function! vimwiki#base#update_listing_in_buffer(strings, start_header, endif let old_cursor_pos = getpos('.') + let cursor_line = old_cursor_pos[1] + let is_cursor_after_listing = 0 + + let lines_diff = 0 if already_there " delete the old listing @@ -1152,9 +1156,19 @@ function! vimwiki#base#update_listing_in_buffer(strings, start_header, while end_lnum <= line('$') && getline(end_lnum) =~# a:content_regex let end_lnum += 1 endwhile + let is_cursor_after_listing = ( cursor_line >= end_lnum ) + " We'll be removing a range. But, apparently, if folds are enabled, Vim + " won't let you remove a range that overlaps with closed fold -- the entire + " fold gets deleted. So we temporarily disable folds, and then reenable + " them right back. + let foldenable_save = &l:foldenable + setlo nofoldenable silent exe start_lnum.','.string(end_lnum - 1).'delete _' + let &l:foldenable = foldenable_save + let lines_diff = 0 - (end_lnum - start_lnum) else let start_lnum = a:default_lnum + let is_cursor_after_listing = ( cursor_line > a:default_lnum ) let whitespaces_in_first_line = '' endif @@ -1164,6 +1178,7 @@ function! vimwiki#base#update_listing_in_buffer(strings, start_header, \ '__Header__', '\='."'".a:start_header."'", '') call append(start_lnum - 1, new_header) let start_lnum += 1 + let lines_diff += 1 + len(a:strings) for string in a:strings call append(start_lnum - 1, string) let start_lnum += 1 @@ -1171,8 +1186,12 @@ function! vimwiki#base#update_listing_in_buffer(strings, start_header, " append an empty line if there is not one if start_lnum <= line('$') && getline(start_lnum) !~# '\m^\s*$' call append(start_lnum - 1, '') + let lines_diff += 1 endif + if is_cursor_after_listing + let old_cursor_pos[1] += lines_diff + endif call setpos('.', old_cursor_pos) endfunction "}}} From 0d3f526a884d4f24915f2b78fb655a3237898620 Mon Sep 17 00:00:00 2001 From: Ivan Tishchenko Date: Fri, 27 Nov 2015 03:13:25 +0300 Subject: [PATCH 2/5] Preserve fold open/close status of the TOC on save. Since TOC is completely recreated, Vim loses its fold open/close status. If your TOC was open, after you save it gets closed. Fix will save fold status, and restore it after TOC is updated. --- autoload/vimwiki/base.vim | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/autoload/vimwiki/base.vim b/autoload/vimwiki/base.vim index da68849..2b8cabd 100644 --- a/autoload/vimwiki/base.vim +++ b/autoload/vimwiki/base.vim @@ -1147,9 +1147,12 @@ function! vimwiki#base#update_listing_in_buffer(strings, start_header, let cursor_line = old_cursor_pos[1] let is_cursor_after_listing = 0 + let is_fold_closed = 1 + let lines_diff = 0 if already_there + let is_fold_closed = ( foldclosed(start_lnum) > 1 ) " delete the old listing let whitespaces_in_first_line = matchstr(getline(start_lnum), '\m^\s*') let end_lnum = start_lnum + 1 @@ -1189,6 +1192,12 @@ function! vimwiki#base#update_listing_in_buffer(strings, start_header, let lines_diff += 1 endif + " Open fold, if needed + if !is_fold_closed + exe start_lnum + norm zo + endif + if is_cursor_after_listing let old_cursor_pos[1] += lines_diff endif From 5247de4a0bb6eea640f0535b8ff1e7ca02d753dc Mon Sep 17 00:00:00 2001 From: Ivan Tishchenko Date: Fri, 27 Nov 2015 03:20:44 +0300 Subject: [PATCH 3/5] Prevent scrolling of large folds while filesave updates TOC. During TOC update, screen sometimes scrolls -- most often I've seen this when I'm working inside large enough fold (does not fit in one screen). Fix uses winsaveview()/winrestview() instead of getpos()/setpos(). Winview pair would also manage scroll position on screen, not just cursor position in text. --- autoload/vimwiki/base.vim | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/autoload/vimwiki/base.vim b/autoload/vimwiki/base.vim index 2b8cabd..7968f86 100644 --- a/autoload/vimwiki/base.vim +++ b/autoload/vimwiki/base.vim @@ -1143,8 +1143,8 @@ function! vimwiki#base#update_listing_in_buffer(strings, start_header, return endif - let old_cursor_pos = getpos('.') - let cursor_line = old_cursor_pos[1] + let winview_save = winsaveview() + let cursor_line = winview_save.lnum let is_cursor_after_listing = 0 let is_fold_closed = 1 @@ -1199,9 +1199,9 @@ function! vimwiki#base#update_listing_in_buffer(strings, start_header, endif if is_cursor_after_listing - let old_cursor_pos[1] += lines_diff + let winview_save.lnum += lines_diff endif - call setpos('.', old_cursor_pos) + call winrestview(winview_save) endfunction "}}} " WIKI link following functions {{{ From 77fca9080c88f43119087ac62643ca2288320d9b Mon Sep 17 00:00:00 2001 From: Ivan Tishchenko Date: Tue, 1 Dec 2015 22:41:50 +0300 Subject: [PATCH 4/5] Fix code review notes on 'norm zo': - Only issue 'zo' if there is any fold at all. - Correct possible bug, code was using 'start_lnum' var, but it was changed/incremented which could lead to wrong results. - Use bang with norm, to prevent user re-mapping interfere with standard ones. --- autoload/vimwiki/base.vim | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/autoload/vimwiki/base.vim b/autoload/vimwiki/base.vim index 7968f86..4f56f59 100644 --- a/autoload/vimwiki/base.vim +++ b/autoload/vimwiki/base.vim @@ -1175,6 +1175,8 @@ function! vimwiki#base#update_listing_in_buffer(strings, start_header, let whitespaces_in_first_line = '' endif + let start_of_listing = start_lnum + " write new listing let new_header = whitespaces_in_first_line \ . substitute(g:vimwiki_rxH1_Template, @@ -1193,9 +1195,9 @@ function! vimwiki#base#update_listing_in_buffer(strings, start_header, endif " Open fold, if needed - if !is_fold_closed - exe start_lnum - norm zo + if !is_fold_closed && foldclosed(start_of_listing) + exe start_of_listing + norm! zo endif if is_cursor_after_listing From c2b0fd843bffa8798d247d5dbc08964182d0296d Mon Sep 17 00:00:00 2001 From: Ivan Tishchenko Date: Fri, 4 Dec 2015 15:33:03 +0400 Subject: [PATCH 5/5] Fix bug: saving a page would err out trying to open fold if folds are disabled or are configured differently. --- autoload/vimwiki/base.vim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/autoload/vimwiki/base.vim b/autoload/vimwiki/base.vim index 4f56f59..d231415 100644 --- a/autoload/vimwiki/base.vim +++ b/autoload/vimwiki/base.vim @@ -1152,7 +1152,7 @@ function! vimwiki#base#update_listing_in_buffer(strings, start_header, let lines_diff = 0 if already_there - let is_fold_closed = ( foldclosed(start_lnum) > 1 ) + let is_fold_closed = ( foldclosed(start_lnum) > -1 ) " delete the old listing let whitespaces_in_first_line = matchstr(getline(start_lnum), '\m^\s*') let end_lnum = start_lnum + 1 @@ -1195,7 +1195,7 @@ function! vimwiki#base#update_listing_in_buffer(strings, start_header, endif " Open fold, if needed - if !is_fold_closed && foldclosed(start_of_listing) + if !is_fold_closed && ( foldclosed(start_of_listing) > -1 ) exe start_of_listing norm! zo endif