From b79977d6b8bc28414081746ec76890a291b55a67 Mon Sep 17 00:00:00 2001 From: Alexey Radkov Date: Sun, 4 May 2014 15:46:19 +0400 Subject: [PATCH 01/14] further large table optimizations 1. s:get_aligned_rows(): getting 2 last rows is enough for having been formatted tables 2. vimwiki#tbl#get_cells(): using faster strpart() instead concatenating every new character into variables cell and quote 3. checking by getline() whether the line was changed before setline() does matter on slower computers --- autoload/vimwiki/tbl.vim | 74 ++++++++++++++++++++++++++-------------- 1 file changed, 48 insertions(+), 26 deletions(-) diff --git a/autoload/vimwiki/tbl.vim b/autoload/vimwiki/tbl.vim index de05e63..aa13202 100644 --- a/autoload/vimwiki/tbl.vim +++ b/autoload/vimwiki/tbl.vim @@ -124,11 +124,10 @@ function! s:create_row_sep(cols) "{{{ return row endfunction "}}} -function! vimwiki#tbl#get_cells(line) "{{{ +function! vimwiki#tbl#get_cells(line, ...) "{{{ let result = [] - let cell = '' - let quote = '' let state = 'NONE' + let cell_start = -1 " 'Simple' FSM for idx in range(strlen(a:line)) @@ -136,44 +135,39 @@ function! vimwiki#tbl#get_cells(line) "{{{ let ch = a:line[idx] if state == 'NONE' if ch == '|' + let cell_start = idx + 1 let state = 'CELL' endif elseif state == 'CELL' if ch == '[' || ch == '{' let state = 'BEFORE_QUOTE_START' - let quote = ch elseif ch == '|' - call add(result, vimwiki#u#trim(cell)) - let cell = "" - else - let cell .= ch + let cell = strpart(a:line, cell_start, idx - cell_start) + if a:0 && a:1 + let cell = substitute(cell, '^ \(.*\) $', '\1', '') + else + let cell = vimwiki#u#trim(cell) + endif + call add(result, cell) + let cell_start = idx + 1 endif elseif state == 'BEFORE_QUOTE_START' if ch == '[' || ch == '{' let state = 'QUOTE' - let quote .= ch else let state = 'CELL' - let cell .= quote.ch - let quote = '' endif elseif state == 'QUOTE' if ch == ']' || ch == '}' let state = 'BEFORE_QUOTE_END' endif - let quote .= ch elseif state == 'BEFORE_QUOTE_END' if ch == ']' || ch == '}' let state = 'CELL' endif - let cell .= quote.ch - let quote = '' endif endfor - if cell.quote != '' - call add(result, vimwiki#u#trim(cell.quote, '|')) - endif return result endfunction "}}} @@ -201,7 +195,7 @@ function! s:get_indent(lnum) "{{{ return indent endfunction " }}} -function! s:get_rows(lnum) "{{{ +function! s:get_rows(lnum, ...) "{{{ if !s:is_table(getline(a:lnum)) return endif @@ -210,7 +204,9 @@ function! s:get_rows(lnum) "{{{ let lower_rows = [] let lnum = a:lnum - 1 - while lnum >= 1 + let depth = a:0 > 0 ? a:1 : 0 + let ldepth = 0 + while lnum >= 1 && (depth == 0 || ldepth < depth) let line = getline(lnum) if s:is_table(line) call add(upper_rows, [lnum, line]) @@ -218,6 +214,7 @@ function! s:get_rows(lnum) "{{{ break endif let lnum -= 1 + let ldepth += 1 endwhile call reverse(upper_rows) @@ -229,6 +226,9 @@ function! s:get_rows(lnum) "{{{ else break endif + if depth > 0 + break + endif let lnum += 1 endwhile @@ -237,7 +237,8 @@ endfunction "}}} function! s:get_cell_max_lens(lnum, ...) "{{{ let max_lens = {} - for [lnum, row] in s:get_rows(a:lnum) + let rows = a:0 > 2 ? a:3 : s:get_rows(a:lnum) + for [lnum, row] in rows if s:is_separator(row) continue endif @@ -255,13 +256,32 @@ function! s:get_cell_max_lens(lnum, ...) "{{{ endfunction "}}} function! s:get_aligned_rows(lnum, col1, col2) "{{{ - let rows = s:get_rows(a:lnum) + " getting 2 last rows is enough for having been formatted tables + let depth = 2 + let rows = s:get_rows(a:lnum, depth) let startlnum = rows[0][0] let cells = [] - for [lnum, row] in rows - call add(cells, vimwiki#tbl#get_cells(row)) - endfor - let max_lens = s:get_cell_max_lens(a:lnum, cells, startlnum) + let max_lens = {} + let lrows = len(rows) + if lrows == depth + 1 + let i = 1 + for [lnum, row] in rows + call add(cells, vimwiki#tbl#get_cells(row, i == lrows - 1 ? 0 : 1)) + let i += 1 + endfor + let max_lens = s:get_cell_max_lens(a:lnum, cells, startlnum, rows) + let fst_lens = s:get_cell_max_lens(a:lnum, cells, startlnum, rows[0:0]) + if max_lens != fst_lens + " all the table must be re-formatted + let rows = s:get_rows(a:lnum) + let startlnum = rows[0][0] + let cells = [] + for [lnum, row] in rows + call add(cells, vimwiki#tbl#get_cells(row)) + endfor + let max_lens = s:get_cell_max_lens(a:lnum, cells, startlnum, rows) + endif + endif let result = [] for [lnum, row] in rows if s:is_separator(row) @@ -520,7 +540,9 @@ function! vimwiki#tbl#format(lnum, ...) "{{{ for [lnum, row] in s:get_aligned_rows(a:lnum, col1, col2) let row = indentstring.row - call setline(lnum, row) + if getline(lnum) != row + call setline(lnum, row) + endif endfor let &tw = s:textwidth From cd25233cc826000192b92f94e84b0522afce730b Mon Sep 17 00:00:00 2001 From: Alexey Radkov Date: Sun, 4 May 2014 17:09:42 +0400 Subject: [PATCH 02/14] fast and in Insert mode this also fixes Tab navigation in a new added line --- autoload/vimwiki/tbl.vim | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/autoload/vimwiki/tbl.vim b/autoload/vimwiki/tbl.vim index aa13202..368dcd5 100644 --- a/autoload/vimwiki/tbl.vim +++ b/autoload/vimwiki/tbl.vim @@ -408,7 +408,13 @@ function! vimwiki#tbl#goto_next_col() "{{{ let curcol = virtcol('.') let lnum = line('.') let newcol = s:get_indent(lnum) - let max_lens = s:get_cell_max_lens(lnum) + let rows = s:get_rows(lnum, 2) + let startlnum = rows[0][0] + let cells = [] + for [lnum, row] in rows + call add(cells, vimwiki#tbl#get_cells(row, 1)) + endfor + let max_lens = s:get_cell_max_lens(lnum, cells, startlnum, rows) for cell_len in values(max_lens) if newcol >= curcol-1 break @@ -434,7 +440,13 @@ function! vimwiki#tbl#goto_prev_col() "{{{ let curcol = virtcol('.') let lnum = line('.') let newcol = s:get_indent(lnum) - let max_lens = s:get_cell_max_lens(lnum) + let rows = s:get_rows(lnum, 2) + let startlnum = rows[0][0] + let cells = [] + for [lnum, row] in rows + call add(cells, vimwiki#tbl#get_cells(row, 1)) + endfor + let max_lens = s:get_cell_max_lens(lnum, cells, startlnum, rows) let prev_cell_len = 0 echom string(max_lens) for cell_len in values(max_lens) From 4d1bb91dbe2d6ba8bc7d6619b4f66a239c642329 Mon Sep 17 00:00:00 2001 From: Alexey Radkov Date: Sun, 4 May 2014 18:42:00 +0400 Subject: [PATCH 03/14] small fix in s:get_aligned_rows() --- autoload/vimwiki/tbl.vim | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/autoload/vimwiki/tbl.vim b/autoload/vimwiki/tbl.vim index 368dcd5..46712b3 100644 --- a/autoload/vimwiki/tbl.vim +++ b/autoload/vimwiki/tbl.vim @@ -263,6 +263,7 @@ function! s:get_aligned_rows(lnum, col1, col2) "{{{ let cells = [] let max_lens = {} let lrows = len(rows) + let check_all = 1 if lrows == depth + 1 let i = 1 for [lnum, row] in rows @@ -271,16 +272,17 @@ function! s:get_aligned_rows(lnum, col1, col2) "{{{ endfor let max_lens = s:get_cell_max_lens(a:lnum, cells, startlnum, rows) let fst_lens = s:get_cell_max_lens(a:lnum, cells, startlnum, rows[0:0]) - if max_lens != fst_lens - " all the table must be re-formatted - let rows = s:get_rows(a:lnum) - let startlnum = rows[0][0] - let cells = [] - for [lnum, row] in rows - call add(cells, vimwiki#tbl#get_cells(row)) - endfor - let max_lens = s:get_cell_max_lens(a:lnum, cells, startlnum, rows) - endif + let check_all = max_lens != fst_lens + endif + if check_all + " all the table must be re-formatted + let rows = s:get_rows(a:lnum) + let startlnum = rows[0][0] + let cells = [] + for [lnum, row] in rows + call add(cells, vimwiki#tbl#get_cells(row)) + endfor + let max_lens = s:get_cell_max_lens(a:lnum, cells, startlnum, rows) endif let result = [] for [lnum, row] in rows From 72ad6d1b16de450b916e45f63ae9a72f23d8d22d Mon Sep 17 00:00:00 2001 From: Alexey Radkov Date: Sun, 4 May 2014 20:46:00 +0400 Subject: [PATCH 04/14] minor stylistic change --- autoload/vimwiki/tbl.vim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/autoload/vimwiki/tbl.vim b/autoload/vimwiki/tbl.vim index 46712b3..d383f73 100644 --- a/autoload/vimwiki/tbl.vim +++ b/autoload/vimwiki/tbl.vim @@ -267,7 +267,7 @@ function! s:get_aligned_rows(lnum, col1, col2) "{{{ if lrows == depth + 1 let i = 1 for [lnum, row] in rows - call add(cells, vimwiki#tbl#get_cells(row, i == lrows - 1 ? 0 : 1)) + call add(cells, vimwiki#tbl#get_cells(row, i != lrows - 1)) let i += 1 endfor let max_lens = s:get_cell_max_lens(a:lnum, cells, startlnum, rows) From 920f41b318831cca3e18684f8521e4527608e14f Mon Sep 17 00:00:00 2001 From: Alexey Radkov Date: Fri, 9 May 2014 12:47:21 +0400 Subject: [PATCH 05/14] fixed get_cells() FSM and gqq command - get_cells() FSM correctly treats unclosed quotes now, - fixed gqq command: now it aligns all the table - proposed 'fast' variant of gqq: gq1 that aligns current + 2 above rows --- autoload/vimwiki/tbl.vim | 129 ++++++++++++++++++++++----------------- ftplugin/vimwiki.vim | 6 +- 2 files changed, 77 insertions(+), 58 deletions(-) diff --git a/autoload/vimwiki/tbl.vim b/autoload/vimwiki/tbl.vim index d383f73..bf6a206 100644 --- a/autoload/vimwiki/tbl.vim +++ b/autoload/vimwiki/tbl.vim @@ -127,46 +127,58 @@ endfunction "}}} function! vimwiki#tbl#get_cells(line, ...) "{{{ let result = [] let state = 'NONE' - let cell_start = -1 + let cell_start = 0 + let quote_start = 0 + let len = strlen(a:line) - 1 " 'Simple' FSM - for idx in range(strlen(a:line)) - " The only way I know Vim can do Unicode... - let ch = a:line[idx] - if state == 'NONE' - if ch == '|' - let cell_start = idx + 1 - let state = 'CELL' - endif - elseif state == 'CELL' - if ch == '[' || ch == '{' - let state = 'BEFORE_QUOTE_START' - elseif ch == '|' - let cell = strpart(a:line, cell_start, idx - cell_start) - if a:0 && a:1 - let cell = substitute(cell, '^ \(.*\) $', '\1', '') - else - let cell = vimwiki#u#trim(cell) - endif - call add(result, cell) - let cell_start = idx + 1 - endif - elseif state == 'BEFORE_QUOTE_START' - if ch == '[' || ch == '{' - let state = 'QUOTE' - else - let state = 'CELL' - endif - elseif state == 'QUOTE' - if ch == ']' || ch == '}' - let state = 'BEFORE_QUOTE_END' - endif - elseif state == 'BEFORE_QUOTE_END' - if ch == ']' || ch == '}' - let state = 'CELL' - endif + while state != 'CELL' + if quote_start != 0 && state != 'CELL' + let state = 'CELL' endif - endfor + for idx in range(quote_start, len) + " The only way I know Vim can do Unicode... + let ch = a:line[idx] + if state == 'NONE' + if ch == '|' + let cell_start = idx + 1 + let state = 'CELL' + endif + elseif state == 'CELL' + if ch == '[' || ch == '{' + let state = 'BEFORE_QUOTE_START' + let quote_start = idx + elseif ch == '|' + let cell = strpart(a:line, cell_start, idx - cell_start) + if a:0 && a:1 + let cell = substitute(cell, '^ \(.*\) $', '\1', '') + else + let cell = vimwiki#u#trim(cell) + endif + call add(result, cell) + let cell_start = idx + 1 + endif + elseif state == 'BEFORE_QUOTE_START' + if ch == '[' || ch == '{' + let state = 'QUOTE' + let quote_start = idx + else + let state = 'CELL' + endif + elseif state == 'QUOTE' + if ch == ']' || ch == '}' + let state = 'BEFORE_QUOTE_END' + endif + elseif state == 'BEFORE_QUOTE_END' + if ch == ']' || ch == '}' + let state = 'CELL' + endif + endif + endfor + if state == 'NONE' + break + endif + endwhile return result endfunction "}}} @@ -255,24 +267,26 @@ function! s:get_cell_max_lens(lnum, ...) "{{{ return max_lens endfunction "}}} -function! s:get_aligned_rows(lnum, col1, col2) "{{{ - " getting 2 last rows is enough for having been formatted tables - let depth = 2 - let rows = s:get_rows(a:lnum, depth) - let startlnum = rows[0][0] +function! s:get_aligned_rows(lnum, col1, col2, depth) "{{{ + let rows = [] + let startlnum = 0 let cells = [] let max_lens = {} - let lrows = len(rows) let check_all = 1 - if lrows == depth + 1 - let i = 1 - for [lnum, row] in rows - call add(cells, vimwiki#tbl#get_cells(row, i != lrows - 1)) - let i += 1 - endfor - let max_lens = s:get_cell_max_lens(a:lnum, cells, startlnum, rows) - let fst_lens = s:get_cell_max_lens(a:lnum, cells, startlnum, rows[0:0]) - let check_all = max_lens != fst_lens + if a:depth > 0 + let rows = s:get_rows(a:lnum, a:depth) + let startlnum = rows[0][0] + let lrows = len(rows) + if lrows == a:depth + 1 + let i = 1 + for [lnum, row] in rows + call add(cells, vimwiki#tbl#get_cells(row, i != lrows - 1)) + let i += 1 + endfor + let max_lens = s:get_cell_max_lens(a:lnum, cells, startlnum, rows) + let fst_lens = s:get_cell_max_lens(a:lnum, cells, startlnum, rows[0:0]) + let check_all = max_lens != fst_lens + endif endif if check_all " all the table must be re-formatted @@ -376,7 +390,7 @@ endfunction "}}} " Keyboard functions "{{{ function! s:kbd_create_new_row(cols, goto_first) "{{{ let cmd = "\o".s:create_empty_row(a:cols) - let cmd .= "\:call vimwiki#tbl#format(line('.'))\" + let cmd .= "\:call vimwiki#tbl#format(line('.'), 2)\" let cmd .= "\0" if a:goto_first let cmd .= ":call search('\\(".s:rxSep()."\\)\\zs', 'c', line('.'))\" @@ -537,6 +551,8 @@ function! vimwiki#tbl#format(lnum, ...) "{{{ return endif + let depth = a:0 == 1 ? a:1 : 0 + if a:0 == 2 let col1 = a:1 let col2 = a:2 @@ -552,7 +568,8 @@ function! vimwiki#tbl#format(lnum, ...) "{{{ let indentstring = repeat(' ', indent / &tabstop) . repeat(' ', indent % &tabstop) endif - for [lnum, row] in s:get_aligned_rows(a:lnum, col1, col2) + " getting N = depth last rows is enough for having been formatted tables + for [lnum, row] in s:get_aligned_rows(a:lnum, col1, col2, depth) let row = indentstring.row if getline(lnum) != row call setline(lnum, row) @@ -597,9 +614,9 @@ function! vimwiki#tbl#create(...) "{{{ call append(line('.'), lines) endfunction "}}} -function! vimwiki#tbl#align_or_cmd(cmd) "{{{ +function! vimwiki#tbl#align_or_cmd(cmd, ...) "{{{ if s:is_table(getline('.')) - call vimwiki#tbl#format(line('.')) + call call('vimwiki#tbl#format', [line('.')] + a:000) else exe 'normal! '.a:cmd endif diff --git a/ftplugin/vimwiki.vim b/ftplugin/vimwiki.vim index b0bc3f1..06e7a9f 100644 --- a/ftplugin/vimwiki.vim +++ b/ftplugin/vimwiki.vim @@ -342,8 +342,8 @@ command! -buffer VimwikiListToggle call vimwiki#lst#toggle_list_item() " table commands command! -buffer -nargs=* VimwikiTable call vimwiki#tbl#create() -command! -buffer VimwikiTableAlignQ call vimwiki#tbl#align_or_cmd('gqq') -command! -buffer VimwikiTableAlignW call vimwiki#tbl#align_or_cmd('gww') +command! -buffer -nargs=? VimwikiTableAlignQ call vimwiki#tbl#align_or_cmd('gqq', ) +command! -buffer -nargs=? VimwikiTableAlignW call vimwiki#tbl#align_or_cmd('gww', ) command! -buffer VimwikiTableMoveColumnLeft call vimwiki#tbl#move_column_left() command! -buffer VimwikiTableMoveColumnRight call vimwiki#tbl#move_column_right() @@ -614,6 +614,8 @@ endif nnoremap gqq :VimwikiTableAlignQ nnoremap gww :VimwikiTableAlignW +nnoremap gq1 :VimwikiTableAlignQ 2 +nnoremap gw1 :VimwikiTableAlignW 2 if !hasmapto('VimwikiTableMoveColumnLeft') nmap VimwikiTableMoveColumnLeft endif From a74e0821b01e4b5acc25ac07c4b97b91ad730645 Mon Sep 17 00:00:00 2001 From: lyokha Date: Thu, 14 Mar 2019 13:36:51 +0300 Subject: [PATCH 06/14] resolved conflicts in tbl.vim --- README.md | 4 +- autoload/vimwiki/tbl.vim | 296 +++++++++++++++++++++------------------ 2 files changed, 164 insertions(+), 136 deletions(-) diff --git a/README.md b/README.md index b1154b1..3d6a564 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ With vimwiki you can: * manage todo-lists; * write documentation. -To do a quick start press ``ww (this is usually \ww) to go to your index +To do a quick start press ww (this is usually \ww) to go to your index wiki file. By default it is located in: ~/vimwiki/index.wiki @@ -102,7 +102,7 @@ normal mode: * `wd` -- Delete wiki file you are in. * `wr` -- Rename wiki file you are in. * `` -- Folow/Create wiki link - * `` -- Split and follow/create wiki link + * `` -- Split and folow/create wiki link * `` -- Vertical split and folow/create wiki link * `` -- Go back to parent(previous) wiki link * `` -- Find next wiki link diff --git a/autoload/vimwiki/tbl.vim b/autoload/vimwiki/tbl.vim index bf6a206..385823d 100644 --- a/autoload/vimwiki/tbl.vim +++ b/autoload/vimwiki/tbl.vim @@ -1,36 +1,36 @@ -" vim:tabstop=2:shiftwidth=2:expandtab:foldmethod=marker:textwidth=79 +" vim:tabstop=2:shiftwidth=2:expandtab:textwidth=99 " Vimwiki autoload plugin file -" Desc: Tables +" Description: Tables " | Easily | manageable | text | tables | ! | " |--------|------------|-------|--------|---------| " | Have | fun! | Drink | tea | Period. | " -" Author: Maxim Kim -" Home: http://code.google.com/p/vimwiki/ +" Home: https://github.com/vimwiki/vimwiki/ + + -" Load only once {{{ if exists("g:loaded_vimwiki_tbl_auto") || &cp finish endif let g:loaded_vimwiki_tbl_auto = 1 -"}}} + let s:textwidth = &tw -" Misc functions {{{ -function! s:rxSep() "{{{ - return g:vimwiki_rxTableSep -endfunction "}}} +function! s:rxSep() + return vimwiki#vars#get_syntaxlocal('rxTableSep') +endfunction -function! s:wide_len(str) "{{{ + +function! s:wide_len(str) " vim73 has new function that gives correct string width. if exists("*strdisplaywidth") return strdisplaywidth(a:str) endif " get str display width in vim ver < 7.2 - if !g:vimwiki_CJK_length + if !vimwiki#vars#get_global('CJK_length') let ret = strlen(substitute(a:str, '.', 'x', 'g')) else let savemodified = &modified @@ -43,42 +43,49 @@ function! s:wide_len(str) "{{{ let &modified = savemodified endif return ret -endfunction "}}} +endfunction -function! s:cell_splitter() "{{{ + +function! s:cell_splitter() return '\s*'.s:rxSep().'\s*' -endfunction "}}} +endfunction -function! s:sep_splitter() "{{{ + +function! s:sep_splitter() return '-'.s:rxSep().'-' -endfunction "}}} +endfunction -function! s:is_table(line) "{{{ - return s:is_separator(a:line) || (a:line !~ s:rxSep().s:rxSep() && a:line =~ '^\s*'.s:rxSep().'.\+'.s:rxSep().'\s*$') -endfunction "}}} -function! s:is_separator(line) "{{{ - return a:line =~ '^\s*'.s:rxSep().'\(--\+'.s:rxSep().'\)\+\s*$' -endfunction "}}} +function! s:is_table(line) + return s:is_separator(a:line) || + \ (a:line !~# s:rxSep().s:rxSep() && a:line =~# '^\s*'.s:rxSep().'.\+'.s:rxSep().'\s*$') +endfunction -function! s:is_separator_tail(line) "{{{ - return a:line =~ '^\{-1}\%(\s*\|-*\)\%('.s:rxSep().'-\+\)\+'.s:rxSep().'\s*$' -endfunction "}}} -function! s:is_last_column(lnum, cnum) "{{{ +function! s:is_separator(line) + return a:line =~# '^\s*'.s:rxSep().'\(--\+'.s:rxSep().'\)\+\s*$' +endfunction + + +function! s:is_separator_tail(line) + return a:line =~# '^\{-1}\%(\s*\|-*\)\%('.s:rxSep().'-\+\)\+'.s:rxSep().'\s*$' +endfunction + + +function! s:is_last_column(lnum, cnum) let line = strpart(getline(a:lnum), a:cnum - 1) - "echomsg "DEBUG is_last_column> ".(line =~ s:rxSep().'\s*$' && line !~ s:rxSep().'.*'.s:rxSep().'\s*$') - return line =~ s:rxSep().'\s*$' && line !~ s:rxSep().'.*'.s:rxSep().'\s*$' - -endfunction "}}} + return line =~# s:rxSep().'\s*$' && line !~# s:rxSep().'.*'.s:rxSep().'\s*$' +endfunction -function! s:is_first_column(lnum, cnum) "{{{ + +function! s:is_first_column(lnum, cnum) let line = strpart(getline(a:lnum), 0, a:cnum - 1) - "echomsg "DEBUG is_first_column> ".(line =~ '^\s*'.s:rxSep() && line !~ '^\s*'.s:rxSep().'.*'.s:rxSep()) - return line =~ '^\s*$' || (line =~ '^\s*'.s:rxSep() && line !~ '^\s*'.s:rxSep().'.*'.s:rxSep()) -endfunction "}}} + return line =~# '^\s*$' || + \ (line =~# '^\s*'.s:rxSep() && line !~# '^\s*'.s:rxSep().'.*'.s:rxSep()) +endfunction -function! s:count_separators_up(lnum) "{{{ + +function! s:count_separators_up(lnum) let lnum = a:lnum - 1 while lnum > 1 if !s:is_separator(getline(lnum)) @@ -88,9 +95,10 @@ function! s:count_separators_up(lnum) "{{{ endwhile return (a:lnum-lnum) -endfunction "}}} +endfunction -function! s:count_separators_down(lnum) "{{{ + +function! s:count_separators_down(lnum) let lnum = a:lnum + 1 while lnum < line('$') if !s:is_separator(getline(lnum)) @@ -100,9 +108,10 @@ function! s:count_separators_down(lnum) "{{{ endwhile return (lnum-a:lnum) -endfunction "}}} +endfunction -function! s:create_empty_row(cols) "{{{ + +function! s:create_empty_row(cols) let row = s:rxSep() let cell = " ".s:rxSep() @@ -111,9 +120,10 @@ function! s:create_empty_row(cols) "{{{ endfor return row -endfunction "}}} +endfunction -function! s:create_row_sep(cols) "{{{ + +function! s:create_row_sep(cols) let row = s:rxSep() let cell = "---".s:rxSep() @@ -122,9 +132,10 @@ function! s:create_row_sep(cols) "{{{ endfor return row -endfunction "}}} +endfunction -function! vimwiki#tbl#get_cells(line, ...) "{{{ + +function! vimwiki#tbl#get_cells(line, ...) let result = [] let state = 'NONE' let cell_start = 0 @@ -139,12 +150,12 @@ function! vimwiki#tbl#get_cells(line, ...) "{{{ for idx in range(quote_start, len) " The only way I know Vim can do Unicode... let ch = a:line[idx] - if state == 'NONE' + if state ==# 'NONE' if ch == '|' let cell_start = idx + 1 let state = 'CELL' endif - elseif state == 'CELL' + elseif state ==# 'CELL' if ch == '[' || ch == '{' let state = 'BEFORE_QUOTE_START' let quote_start = idx @@ -158,18 +169,18 @@ function! vimwiki#tbl#get_cells(line, ...) "{{{ call add(result, cell) let cell_start = idx + 1 endif - elseif state == 'BEFORE_QUOTE_START' + elseif state ==# 'BEFORE_QUOTE_START' if ch == '[' || ch == '{' let state = 'QUOTE' let quote_start = idx else let state = 'CELL' endif - elseif state == 'QUOTE' + elseif state ==# 'QUOTE' if ch == ']' || ch == '}' let state = 'BEFORE_QUOTE_END' endif - elseif state == 'BEFORE_QUOTE_END' + elseif state ==# 'BEFORE_QUOTE_END' if ch == ']' || ch == '}' let state = 'CELL' endif @@ -181,13 +192,15 @@ function! vimwiki#tbl#get_cells(line, ...) "{{{ endwhile return result -endfunction "}}} +endfunction -function! s:col_count(lnum) "{{{ + +function! s:col_count(lnum) return len(vimwiki#tbl#get_cells(getline(a:lnum))) -endfunction "}}} +endfunction -function! s:get_indent(lnum) "{{{ + +function! s:get_indent(lnum) if !s:is_table(getline(a:lnum)) return endif @@ -205,9 +218,10 @@ function! s:get_indent(lnum) "{{{ endwhile return indent -endfunction " }}} +endfunction -function! s:get_rows(lnum, ...) "{{{ + +function! s:get_rows(lnum, ...) if !s:is_table(getline(a:lnum)) return endif @@ -245,9 +259,10 @@ function! s:get_rows(lnum, ...) "{{{ endwhile return upper_rows + lower_rows -endfunction "}}} +endfunction -function! s:get_cell_max_lens(lnum, ...) "{{{ + +function! s:get_cell_max_lens(lnum, ...) let max_lens = {} let rows = a:0 > 2 ? a:3 : s:get_rows(a:lnum) for [lnum, row] in rows @@ -265,9 +280,10 @@ function! s:get_cell_max_lens(lnum, ...) "{{{ endfor endfor return max_lens -endfunction "}}} +endfunction -function! s:get_aligned_rows(lnum, col1, col2, depth) "{{{ + +function! s:get_aligned_rows(lnum, col1, col2, depth) let rows = [] let startlnum = 0 let cells = [] @@ -308,10 +324,11 @@ function! s:get_aligned_rows(lnum, col1, col2, depth) "{{{ call add(result, [lnum, new_row]) endfor return result -endfunction "}}} +endfunction + " Number of the current column. Starts from 0. -function! s:cur_column() "{{{ +function! s:cur_column() let line = getline('.') if !s:is_table(line) return -1 @@ -328,12 +345,10 @@ function! s:cur_column() "{{{ endif endwhile return col -endfunction "}}} +endfunction -" }}} -" Format functions {{{ -function! s:fmt_cell(cell, max_len) "{{{ +function! s:fmt_cell(cell, max_len) let cell = ' '.a:cell.' ' let diff = a:max_len - s:wide_len(a:cell) @@ -343,9 +358,10 @@ function! s:fmt_cell(cell, max_len) "{{{ let cell .= repeat(' ', diff) return cell -endfunction "}}} +endfunction -function! s:fmt_row(cells, max_lens, col1, col2) "{{{ + +function! s:fmt_row(cells, max_lens, col1, col2) let new_line = s:rxSep() for idx in range(len(a:cells)) if idx == a:col1 @@ -363,17 +379,19 @@ function! s:fmt_row(cells, max_lens, col1, col2) "{{{ let idx += 1 endwhile return new_line -endfunction "}}} +endfunction -function! s:fmt_cell_sep(max_len) "{{{ + +function! s:fmt_cell_sep(max_len) if a:max_len == 0 return repeat('-', 3) else return repeat('-', a:max_len+2) endif -endfunction "}}} +endfunction -function! s:fmt_sep(max_lens, col1, col2) "{{{ + +function! s:fmt_sep(max_lens, col1, col2) let new_line = s:rxSep() for idx in range(len(a:max_lens)) if idx == a:col1 @@ -384,11 +402,10 @@ function! s:fmt_sep(max_lens, col1, col2) "{{{ let new_line .= s:fmt_cell_sep(a:max_lens[idx]).s:rxSep() endfor return new_line -endfunction "}}} -"}}} +endfunction -" Keyboard functions "{{{ -function! s:kbd_create_new_row(cols, goto_first) "{{{ + +function! s:kbd_create_new_row(cols, goto_first) let cmd = "\o".s:create_empty_row(a:cols) let cmd .= "\:call vimwiki#tbl#format(line('.'), 2)\" let cmd .= "\0" @@ -401,26 +418,29 @@ function! s:kbd_create_new_row(cols, goto_first) "{{{ let cmd .= "a" return cmd -endfunction "}}} +endfunction -function! s:kbd_goto_next_row() "{{{ + +function! s:kbd_goto_next_row() let cmd = "\j" let cmd .= ":call search('.\\(".s:rxSep()."\\)', 'c', line('.'))\" let cmd .= ":call search('\\(".s:rxSep()."\\)\\zs', 'bc', line('.'))\" let cmd .= "a" return cmd -endfunction "}}} +endfunction -function! s:kbd_goto_prev_row() "{{{ + +function! s:kbd_goto_prev_row() let cmd = "\k" let cmd .= ":call search('.\\(".s:rxSep()."\\)', 'c', line('.'))\" let cmd .= ":call search('\\(".s:rxSep()."\\)\\zs', 'bc', line('.'))\" let cmd .= "a" return cmd -endfunction "}}} +endfunction + " Used in s:kbd_goto_next_col -function! vimwiki#tbl#goto_next_col() "{{{ +function! vimwiki#tbl#goto_next_col() let curcol = virtcol('.') let lnum = line('.') let newcol = s:get_indent(lnum) @@ -439,9 +459,10 @@ function! vimwiki#tbl#goto_next_col() "{{{ endfor let newcol += 2 " +2 == 1 separator + 1 space |... if newcol + delta > curcol-1 @@ -478,9 +499,10 @@ function! vimwiki#tbl#goto_prev_col() "{{{ endfor let newcol += 2 " +2 == 1 separator + 1 space | ".cmd return cmd -endfunction "}}} +endfunction -"}}} -" Global functions {{{ -function! vimwiki#tbl#kbd_cr() "{{{ +function! vimwiki#tbl#kbd_cr() let lnum = line('.') if !s:is_table(getline(lnum)) return "" @@ -509,9 +529,10 @@ function! vimwiki#tbl#kbd_cr() "{{{ else return s:kbd_goto_next_row() endif -endfunction "}}} +endfunction -function! vimwiki#tbl#kbd_tab() "{{{ + +function! vimwiki#tbl#kbd_tab() let lnum = line('.') if !s:is_table(getline(lnum)) return "\" @@ -525,9 +546,10 @@ function! vimwiki#tbl#kbd_tab() "{{{ return s:kbd_create_new_row(cols, 1) endif return s:kbd_goto_next_col(is_sep || last) -endfunction "}}} +endfunction -function! vimwiki#tbl#kbd_shift_tab() "{{{ + +function! vimwiki#tbl#kbd_shift_tab() let lnum = line('.') if !s:is_table(getline(lnum)) return "\" @@ -540,10 +562,11 @@ function! vimwiki#tbl#kbd_shift_tab() "{{{ return "" endif return s:kbd_goto_prev_col(is_sep || first) -endfunction "}}} +endfunction -function! vimwiki#tbl#format(lnum, ...) "{{{ - if !(&filetype == 'vimwiki') + +function! vimwiki#tbl#format(lnum, ...) + if !(&filetype ==? 'vimwiki') return endif let line = getline(a:lnum) @@ -575,11 +598,12 @@ function! vimwiki#tbl#format(lnum, ...) "{{{ call setline(lnum, row) endif endfor - - let &tw = s:textwidth -endfunction "}}} -function! vimwiki#tbl#create(...) "{{{ + let &tw = s:textwidth +endfunction + + +function! vimwiki#tbl#create(...) if a:0 > 1 let cols = a:1 let rows = a:2 @@ -610,34 +634,36 @@ function! vimwiki#tbl#create(...) "{{{ for r in range(rows - 1) call add(lines, row) endfor - - call append(line('.'), lines) -endfunction "}}} -function! vimwiki#tbl#align_or_cmd(cmd, ...) "{{{ + call append(line('.'), lines) +endfunction + + +function! vimwiki#tbl#align_or_cmd(cmd, ...) if s:is_table(getline('.')) call call('vimwiki#tbl#format', [line('.')] + a:000) else exe 'normal! '.a:cmd endif -endfunction "}}} +endfunction -function! vimwiki#tbl#reset_tw(lnum) "{{{ - if !(&filetype == 'vimwiki') + +function! vimwiki#tbl#reset_tw(lnum) + if !(&filetype ==? 'vimwiki') return endif let line = getline(a:lnum) if !s:is_table(line) return endif - + let s:textwidth = &tw let &tw = 0 -endfunction "}}} +endfunction -" TODO: move_column_left and move_column_right are good candidates to be -" refactored. -function! vimwiki#tbl#move_column_left() "{{{ + +" TODO: move_column_left and move_column_right are good candidates to be refactored. +function! vimwiki#tbl#move_column_left() "echomsg "DEBUG move_column_left: " @@ -653,7 +679,7 @@ function! vimwiki#tbl#move_column_left() "{{{ endif if cur_col > 0 - call vimwiki#tbl#format(line('.'), cur_col-1, cur_col) + call vimwiki#tbl#format(line('.'), cur_col-1, cur_col) call cursor(line('.'), 1) let sep = '\('.s:rxSep().'\).\zs' @@ -663,16 +689,16 @@ function! vimwiki#tbl#move_column_left() "{{{ let mpos = match(line, sep, mpos+1) if mpos != -1 let col += 1 - else + else break endif endwhile endif +endfunction -endfunction "}}} -function! vimwiki#tbl#move_column_right() "{{{ +function! vimwiki#tbl#move_column_right() let line = getline('.') @@ -686,7 +712,7 @@ function! vimwiki#tbl#move_column_right() "{{{ endif if cur_col < s:col_count(line('.'))-1 - call vimwiki#tbl#format(line('.'), cur_col, cur_col+1) + call vimwiki#tbl#format(line('.'), cur_col, cur_col+1) call cursor(line('.'), 1) let sep = '\('.s:rxSep().'\).\zs' @@ -696,33 +722,35 @@ function! vimwiki#tbl#move_column_right() "{{{ let mpos = match(line, sep, mpos+1) if mpos != -1 let col += 1 - else + else break endif endwhile - endif +endfunction -endfunction "}}} -function! vimwiki#tbl#get_rows(lnum) "{{{ +function! vimwiki#tbl#get_rows(lnum) return s:get_rows(a:lnum) -endfunction "}}} +endfunction -function! vimwiki#tbl#is_table(line) "{{{ + +function! vimwiki#tbl#is_table(line) return s:is_table(a:line) -endfunction "}}} +endfunction -function! vimwiki#tbl#is_separator(line) "{{{ + +function! vimwiki#tbl#is_separator(line) return s:is_separator(a:line) -endfunction "}}} +endfunction -function! vimwiki#tbl#cell_splitter() "{{{ + +function! vimwiki#tbl#cell_splitter() return s:cell_splitter() -endfunction "}}} +endfunction -function! vimwiki#tbl#sep_splitter() "{{{ + +function! vimwiki#tbl#sep_splitter() return s:sep_splitter() -endfunction "}}} +endfunction -"}}} From bfbfa2783e874b943320e9c7d2871093a91c7770 Mon Sep 17 00:00:00 2001 From: lyokha Date: Thu, 14 Mar 2019 14:21:28 +0300 Subject: [PATCH 07/14] synced README.md with the remote dev branch --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index dec2b9a..cb70ec4 100644 --- a/README.md +++ b/README.md @@ -115,6 +115,16 @@ Changing Wiki Syntax Vimwiki currently ships with 3 syntaxes: Vimwiki (default), Markdown (markdown), and MediaWiki (media) + If you would prefer to use either Markdown or MediaWiki syntaxes, set the following option in your .vimrc: + ``` + let g:vimwiki_list = [{'path': '~/vimwiki/', + \ 'syntax': 'markdown', 'ext': '.md'}] + ``` + + +Installation +============================================================================== + Prerequisites ------------------------------------------------------------------------------ From 7e176c659b180c76d66d02f192171ec98a8d816a Mon Sep 17 00:00:00 2001 From: lyokha Date: Thu, 14 Mar 2019 14:24:13 +0300 Subject: [PATCH 08/14] synced README.md with the remote dev branch (2) --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index cb70ec4..a2b10cd 100644 --- a/README.md +++ b/README.md @@ -121,7 +121,6 @@ Changing Wiki Syntax \ 'syntax': 'markdown', 'ext': '.md'}] ``` - Installation ============================================================================== From 30c0bdffaafacff0a34ef8e86493a167dfe43c51 Mon Sep 17 00:00:00 2001 From: lyokha Date: Thu, 14 Mar 2019 14:25:35 +0300 Subject: [PATCH 09/14] synced README.md with the remote dev branch (3) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a2b10cd..3ce36f5 100644 --- a/README.md +++ b/README.md @@ -121,10 +121,10 @@ Changing Wiki Syntax \ 'syntax': 'markdown', 'ext': '.md'}] ``` + Installation ============================================================================== - Prerequisites ------------------------------------------------------------------------------ From 07ba7339f15b4c975aef83ecf79ebf9d6c656b37 Mon Sep 17 00:00:00 2001 From: lyokha Date: Thu, 14 Mar 2019 14:44:08 +0300 Subject: [PATCH 10/14] added docs about new commands gq1 and gw1 --- doc/vimwiki.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/doc/vimwiki.txt b/doc/vimwiki.txt index 4f935e5..ac41297 100644 --- a/doc/vimwiki.txt +++ b/doc/vimwiki.txt @@ -513,6 +513,12 @@ gqq Format table. If you made some changes to a table or without swapping insert/normal modes this command gww will reformat it. + *vimwiki_gq1* *vimwiki_gw1* +gq1 Fast format table. The same as the previous, except + or that only a few lines above the current line are +gw1 tested. If the alignment of the current line differs, + then the whole table gets reformatted. + *vimwiki_* Move current table column to the left. See |:VimwikiTableMoveColumnLeft| From 5e4a89c89889c2e630cc97c620bc138c7efa5adf Mon Sep 17 00:00:00 2001 From: lyokha Date: Fri, 15 Mar 2019 15:31:28 +0300 Subject: [PATCH 11/14] faster table format on InsertLeave; faster s:get_rows() --- autoload/vimwiki/tbl.vim | 14 ++++++++------ plugin/vimwiki.vim | 2 +- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/autoload/vimwiki/tbl.vim b/autoload/vimwiki/tbl.vim index 385823d..dfa3649 100644 --- a/autoload/vimwiki/tbl.vim +++ b/autoload/vimwiki/tbl.vim @@ -226,8 +226,7 @@ function! s:get_rows(lnum, ...) return endif - let upper_rows = [] - let lower_rows = [] + let rows = [] let lnum = a:lnum - 1 let depth = a:0 > 0 ? a:1 : 0 @@ -235,20 +234,23 @@ function! s:get_rows(lnum, ...) while lnum >= 1 && (depth == 0 || ldepth < depth) let line = getline(lnum) if s:is_table(line) - call add(upper_rows, [lnum, line]) + call insert(rows, [lnum, line]) else break endif let lnum -= 1 let ldepth += 1 endwhile - call reverse(upper_rows) let lnum = a:lnum while lnum <= line('$') let line = getline(lnum) if s:is_table(line) - call add(lower_rows, [lnum, line]) + if lnum == a:lnum + let cells = vimwiki#tbl#get_cells(line) + let line = s:fmt_row(cells, repeat([0], len(cells)), 0, 0) + endif + call add(rows, [lnum, line]) else break endif @@ -258,7 +260,7 @@ function! s:get_rows(lnum, ...) let lnum += 1 endwhile - return upper_rows + lower_rows + return rows endfunction diff --git a/plugin/vimwiki.vim b/plugin/vimwiki.vim index 211e39c..17c43ac 100644 --- a/plugin/vimwiki.vim +++ b/plugin/vimwiki.vim @@ -261,7 +261,7 @@ augroup vimwiki " Format tables when exit from insert mode. Do not use textwidth to " autowrap tables. if vimwiki#vars#get_global('table_auto_fmt') - exe 'autocmd InsertLeave *'.s:ext.' call vimwiki#tbl#format(line("."))' + exe 'autocmd InsertLeave *'.s:ext.' call vimwiki#tbl#format(line("."), 2)' exe 'autocmd InsertEnter *'.s:ext.' call vimwiki#tbl#reset_tw(line("."))' endif if vimwiki#vars#get_global('folding') =~? ':quick$' From 88a6820e9eefe4db4785dc20dd9b453340286591 Mon Sep 17 00:00:00 2001 From: lyokha Date: Fri, 15 Mar 2019 16:07:52 +0300 Subject: [PATCH 12/14] updated for the new aligns feature --- autoload/vimwiki/tbl.vim | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/autoload/vimwiki/tbl.vim b/autoload/vimwiki/tbl.vim index c2af1db..5c3f97d 100644 --- a/autoload/vimwiki/tbl.vim +++ b/autoload/vimwiki/tbl.vim @@ -253,7 +253,10 @@ function! s:get_rows(lnum, ...) if s:is_table(line) if lnum == a:lnum let cells = vimwiki#tbl#get_cells(line) - let line = s:fmt_row(cells, repeat([0], len(cells)), 0, 0) + let clen = len(cells) + let max_lens = repeat([0], clen) + let aligns = repeat(['left'], clen) + let line = s:fmt_row(cells, max_lens, aligns, 0, 0) endif call add(rows, [lnum, line]) else From 1f4fb8ca58806edb370db5267ab49892a98c6e5c Mon Sep 17 00:00:00 2001 From: lyokha Date: Mon, 18 Mar 2019 16:02:52 +0300 Subject: [PATCH 13/14] notes on the newer table formatting algorithm --- DesignNotes.wiki | 183 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 183 insertions(+) diff --git a/DesignNotes.wiki b/DesignNotes.wiki index 2b8705c..f9ef39c 100644 --- a/DesignNotes.wiki +++ b/DesignNotes.wiki @@ -3,3 +3,186 @@ This file is meant to document design decisions and algorithms inside vimwiki which are too large for code comments, and not necessarily interesting to users. Please create a new section to document each behavior. + +== Formatting tables == + +In vimwiki, formatting tables occurs dynamically, when navigating between cells +and adding new rows in a table in the Insert mode, or statically, when pressing +`gqq` or `gqw` (which are mappings for commands `VimwikiTableAlignQ` and +`VimwikiTableAlignW` respectively) in the Normal mode. It also triggers when +leaving Insert mode, provided variable `g:vimwiki_table_auto_fmt` is set. In +this section, the original and the newer optimized algorithms of table +formatting will be described and compared. + +=== The older table formatting algorithm and why this is not optimal === + +Let's consider a simple example. Open a new file, say _tmp.wiki_, and create a +new table with command `VimwikiTable`. This should create a blank table. + +{{{ +| | | | | | +|---|---|---|---|---| +| | | | | | +}}} + +Let's put the cursor in the first header column of the table, enter the Insert +mode and type a name, say _Col1_. Then press _Tab_: the cursor will move to the +second column of the header and the table will get aligned (in the context of +the table formatting story, words _aligned_ and _formatted_ are considered as +synonyms). Now the table looks as in the following snippet. + +{{{ +| Col1 | | | | | +|------|---|---|---|---| +| | | | | | +}}} + +Then, when moving cursor to the first data row (i.e. to the third line of the +table below the separator line) and typing anything here and there while +navigating using _Tab_ or _Enter_ (pressing this creates a new row below the +current row), the table shall keep formatting. Below is a result of such a +random edit. + +{{{ +| Col1 | | | | | +|------|-------|---|-------|----------| +| | Data1 | | Data2 | | +| | | | | New data | +}}} + +The lowest row gets aligned when leaving the Insert mode. Let's copy _Data1_ +(using `viwy` or another keystroke) and paste it (using `p`) in the second data +row of the first column. Now the table looks mis-aligned (as we did not enter +the Insert mode). + +{{{ +| Col1 | | | | | +|------|-------|---|-------|----------| +| | Data1 | | Data2 | | +| Data1 | | | | New data | +}}} + +This is not a big problem though, because we can put the cursor at _any_ place +in the table and press `gqq`: the table will get aligned. + +{{{ +| Col1 | | | | | +|-------|-------|---|-------|----------| +| | Data1 | | Data2 | | +| Data1 | | | | New data | +}}} + +Now let's make real problems! Move the cursor to the lowest row and copy it +with `yy`. Then 500-fold paste it with `500p`. Now the table very long. Move +the cursor to the lowest row (by pressing `G`), enter the Insert mode, and try +a new random editing session by typing anything in cells with _Tab_ and _Enter_ +navigation interleaves. The editing got painfully slow, did not? + +The reason of the slowing down is the older table formatting algorithm. Every +time _Tab_ or _Enter_ get pressed down, all rows in the table get visited to +calculate a new alignment. Moreover, by design it may happen even more than +once per one press! + +{{{vim +function! s:kbd_create_new_row(cols, goto_first) + let cmd = "\o".s:create_empty_row(a:cols) + let cmd .= "\:call vimwiki#tbl#format(line('.'))\" + let cmd .= "\0" + if a:goto_first + let cmd .= ":call search('\\(".s:rxSep()."\\)\\zs', 'c', line('.'))\" + else + let cmd .= (col('.')-1)."l" + let cmd .= ":call search('\\(".s:rxSep()."\\)\\zs', 'bc', line('.'))\" + endif + let cmd .= "a" + + return cmd +endfunction +}}} + +Function `s:kbd_create_new_row()` is called when _Tab_ or _Enter_ get pressed. +Formatting of the whole table happens in function `vimwiki#tbl#format()`. But +remember that leaving the Insert mode triggers re-formatting of a table when +variable `g:vimwiki_table_auto_fmt` is set. This means that formatting of the +whole table is called on all those multiple interleaves between the Insert and +the Normal mode in `s:kbd_create_new_row` (notice `\`, `o`, etc.). + +=== The newer table formating algorithm === + +The newer algorithm was introduced to struggle against performance issues when +formatting large tables. + +Let's take the table from the previous example in an intermediate state. + +{{{ +| Col1 | | | | | +|------|-------|---|-------|----------| +| | Data1 | | Data2 | | +| Data1 | | | | New data | +}}} + +Then move the cursor to the first data row, copy it with `yy`, go down to the +mis-aligned line, and press `5p`. Now we have a slightly bigger mis-aligned +table. + +{{{ +| Col1 | | | | | +|------|-------|---|-------|----------| +| | Data1 | | Data2 | | +| Data1 | | | | New data | +| | Data1 | | Data2 | | +| | Data1 | | Data2 | | +| | Data1 | | Data2 | | +| | Data1 | | Data2 | | +| | Data1 | | Data2 | | +}}} + +Go down to the lowest, the 7th, data row and press `gq1`. Nothing happened. +Let's go to the second or the third data row and press `gq1` once again. Now +the table gets aligned. Let's undo formatting with `u`, go to the fourth row, +and press `gq1`. Now the table should look like in the following snippet. + +{{{ +| Col1 | | | | | +|------|-------|---|-------|----------| +| | Data1 | | Data2 | | +| Data1 | | | | New data | +| | Data1 | | Data2 | | +| | Data1 | | Data2 | | +| | Data1 | | Data2 | | +| | Data1 | | Data2 | | +| | Data1 | | Data2 | | +}}} + +What a peculiar command! Does using it make any sense? Not much, honestly. +Except it shows how the newer optimized table formatting algorithm works in the +Insert mode. + +Indeed, the newer table formatting algorithm introduces a _viewport_ on a table. +Now, when pressing _Tab_ or _Enter_ in the Insert mode, only a small part of +rows are checked for possible formatting: two rows above the current line and +the current line itself (the latter gets preliminary shrunk with function +`s:fmt_row()`). If all three lines in the viewport are of the same length, then +nothing happens (case 1 in the example). If the second or the shrunk current +line is longer then the topmost line in the viewport, then the algorithm falls +back to the older formatting algorithm and the whole table gets aligned +(case 2). If the topmost line in the viewport is longer than the second +and the shrunk current line, then the two lowest lines get aligned according to +the topmost line (case 3). + +Performance of the newer formatting algorithm should not depend on the height +of the table (*beware*: something still makes table editing speed linear with +respect to its height, perhaps syntax tracking or some uncovered parts of the +formatting algorithm). The newer algorithm should also be consistent with +respect to user editing experience. Indeed, as soon as a table should normally +be edited linearly, row by row, dynamic formatting should be both fast +(watching only three rows in a table, re-formatting only when the shrunk +current row gets longer than any of the two rows above) and eager (a table +should look formatted on every pressing on _Tab_ and _Enter_). However, the +newer algorithm differs from the older algorithm when starting editing a +mis-aligned table in an area where mis-aligned rows do not get into the +viewport: in this case the newer algorithm formats the table partly, in the +rows of the viewport, while the older algorithm re-formats the whole table on +every pressing of _Tab_ and _Enter_. In this case the whole table can be +formatted by pressing `gqq` in the Normal mode. + From ad6a3bceb6871e30e55e2dc64e1ca1c4595a1acb Mon Sep 17 00:00:00 2001 From: lyokha Date: Mon, 18 Mar 2019 17:49:13 +0300 Subject: [PATCH 14/14] the cause of the linear slowing down was fixed --- DesignNotes.wiki | 23 +++++++++++------------ autoload/vimwiki/tbl.vim | 23 ++++++++++++++--------- 2 files changed, 25 insertions(+), 21 deletions(-) diff --git a/DesignNotes.wiki b/DesignNotes.wiki index f9ef39c..a9f5662 100644 --- a/DesignNotes.wiki +++ b/DesignNotes.wiki @@ -171,18 +171,17 @@ and the shrunk current line, then the two lowest lines get aligned according to the topmost line (case 3). Performance of the newer formatting algorithm should not depend on the height -of the table (*beware*: something still makes table editing speed linear with -respect to its height, perhaps syntax tracking or some uncovered parts of the -formatting algorithm). The newer algorithm should also be consistent with -respect to user editing experience. Indeed, as soon as a table should normally -be edited linearly, row by row, dynamic formatting should be both fast +of the table. The newer algorithm should also be consistent with respect to +user editing experience. Indeed, as soon as a table should normally be edited +row by row from the top to the bottom, dynamic formatting should be both fast (watching only three rows in a table, re-formatting only when the shrunk current row gets longer than any of the two rows above) and eager (a table -should look formatted on every pressing on _Tab_ and _Enter_). However, the -newer algorithm differs from the older algorithm when starting editing a -mis-aligned table in an area where mis-aligned rows do not get into the -viewport: in this case the newer algorithm formats the table partly, in the -rows of the viewport, while the older algorithm re-formats the whole table on -every pressing of _Tab_ and _Enter_. In this case the whole table can be -formatted by pressing `gqq` in the Normal mode. +should look formatted on every press on _Tab_ and _Enter_). However, the newer +algorithm differs from the older algorithm when starting editing a mis-aligned +table in an area where mis-aligned rows do not get into the viewport: in this +case the newer algorithm will format the table partly (in the rows of the +viewport) until one of the being edited cells grows in length to a value big +enough to trigger the older algorithm and the whole table gets aligned. When +partial formatting is not desirable, the whole table can be formatted by +pressing `gqq` in the Normal mode. diff --git a/autoload/vimwiki/tbl.vim b/autoload/vimwiki/tbl.vim index 5c3f97d..0e67c68 100644 --- a/autoload/vimwiki/tbl.vim +++ b/autoload/vimwiki/tbl.vim @@ -205,7 +205,7 @@ function! s:col_count(lnum) endfunction -function! s:get_indent(lnum) +function! s:get_indent(lnum, depth) if !s:is_table(getline(a:lnum)) return endif @@ -220,6 +220,9 @@ function! s:get_indent(lnum) break endif let lnum -= 1 + if a:depth > 0 && lnum < a:lnum - a:depth + break + endif endwhile return indent @@ -272,9 +275,9 @@ function! s:get_rows(lnum, ...) endfunction -function! s:get_cell_aligns(lnum) +function! s:get_cell_aligns(lnum, depth) let aligns = {} - for [lnum, row] in s:get_rows(a:lnum) + for [lnum, row] in s:get_rows(a:lnum, a:depth) let found_separator = s:is_separator(row) if found_separator let cells = vimwiki#tbl#get_cells(row) @@ -353,7 +356,7 @@ function! s:get_aligned_rows(lnum, col1, col2, depth) endfor let max_lens = s:get_cell_max_lens(a:lnum, cells, startlnum, rows) endif - let aligns = s:get_cell_aligns(a:lnum) + let aligns = s:get_cell_aligns(a:lnum, a:depth) let result = [] for [lnum, row] in rows if s:is_separator(row) @@ -496,8 +499,9 @@ endfunction function! vimwiki#tbl#goto_next_col() let curcol = virtcol('.') let lnum = line('.') - let newcol = s:get_indent(lnum) - let rows = s:get_rows(lnum, 2) + let depth = 2 + let newcol = s:get_indent(lnum, depth) + let rows = s:get_rows(lnum, depth) let startlnum = rows[0][0] let cells = [] for [lnum, row] in rows @@ -530,8 +534,9 @@ endfunction function! vimwiki#tbl#goto_prev_col() let curcol = virtcol('.') let lnum = line('.') - let newcol = s:get_indent(lnum) - let rows = s:get_rows(lnum, 2) + let depth = 2 + let newcol = s:get_indent(lnum, depth) + let rows = s:get_rows(lnum, depth) let startlnum = rows[0][0] let cells = [] for [lnum, row] in rows @@ -637,7 +642,7 @@ function! vimwiki#tbl#format(lnum, ...) let col2 = 0 endif - let indent = s:get_indent(a:lnum) + let indent = s:get_indent(a:lnum, depth) if &expandtab let indentstring = repeat(' ', indent) else