From 0303021abde8cb39500d9c1612216c8b755afae6 Mon Sep 17 00:00:00 2001 From: lyokha Date: Thu, 4 Apr 2019 15:05:57 +0300 Subject: [PATCH] Fast aligns check The optimized table formatting algorithm was still O(n) because calculating aligns required traversal to the separator line on the top of a table. This heuristic algorithm calculates aligns in O(1) in the best case by looking at cells in two rows above. Say, if two above rows are | uau | uauyaya | ya | | ua | uaua | uaaua | | | | | then the aligns can be figured out without need to find the separator line. If aligns cannot be figured out after this fast check then the algorithm falls back to O(n) with searching for the separator line. --- autoload/vimwiki/tbl.vim | 67 ++++++++++++++++++++++++++++++++++------ 1 file changed, 57 insertions(+), 10 deletions(-) diff --git a/autoload/vimwiki/tbl.vim b/autoload/vimwiki/tbl.vim index 5a8a429..bd340a5 100644 --- a/autoload/vimwiki/tbl.vim +++ b/autoload/vimwiki/tbl.vim @@ -254,13 +254,6 @@ function! s:get_rows(lnum, ...) while lnum <= line('$') let line = getline(lnum) if s:is_table(line) - if lnum == a:lnum && !s:is_separator(line) - let cells = vimwiki#tbl#get_cells(line) - 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 break @@ -275,9 +268,10 @@ function! s:get_rows(lnum, ...) endfunction -function! s:get_cell_aligns(lnum) +function! s:get_cell_aligns(lnum, ...) let aligns = {} - for [lnum, row] in s:get_rows(a:lnum) + let depth = a:0 > 0 ? a:1 : 0 + for [lnum, row] in s:get_rows(a:lnum, depth) if s:is_separator(row) let cells = vimwiki#tbl#get_cells(row) for idx in range(len(cells)) @@ -303,6 +297,46 @@ function! s:get_cell_aligns(lnum) endfunction +function! s:get_cell_fast_aligns(rows) + let aligns = {} + let clen = 0 + for [lnum, row] in a:rows + if s:is_separator(row) + return s:get_cell_aligns(lnum, 1) + endif + let cells = vimwiki#tbl#get_cells(row, 1) + let clen = len(cells) + for idx in range(clen) + let cell = cells[idx] + if !has_key(aligns, idx) + let cs = matchlist(cell, '^\(\s*\)[^[:space:]].\{-}\(\s*\)$') + if !empty(cs) + let lstart = len(cs[1]) + let lend = len(cs[2]) + if lstart > 0 || lend > 0 + if lstart > 0 && lend > 0 + let aligns[idx] = 'center' + else + if lend > 0 + let aligns[idx] = 'left' + elseif lstart > 0 + let aligns[idx] = 'right' + endif + endif + endif + endif + endif + endfor + endfor + for idx in range(clen) + if !has_key(aligns, idx) + return {} + endif + endfor + return aligns +endfunction + + function! s:get_cell_max_lens(lnum, ...) let max_lens = {} let rows = a:0 > 2 ? a:3 : s:get_rows(a:lnum) @@ -326,6 +360,7 @@ endfunction function! s:get_aligned_rows(lnum, col1, col2, depth) let rows = [] + let aligns = {} let startlnum = 0 let cells = [] let max_lens = {} @@ -335,6 +370,14 @@ function! s:get_aligned_rows(lnum, col1, col2, depth) let startlnum = rows[0][0] let lrows = len(rows) if lrows == a:depth + 1 + let line = rows[-1][1] + if !s:is_separator(line) + let lcells = vimwiki#tbl#get_cells(line) + let lclen = len(lcells) + let lmax_lens = repeat([0], lclen) + let laligns = repeat(['left'], lclen) + let rows[-1][1] = s:fmt_row(lcells, lmax_lens, laligns, 0, 0) + endif let i = 1 for [lnum, row] in rows call add(cells, vimwiki#tbl#get_cells(row, i != lrows - 1)) @@ -348,6 +391,8 @@ function! s:get_aligned_rows(lnum, col1, col2, depth) endif let fst_lens = s:get_cell_max_lens(a:lnum, cells, startlnum, rows[0:0]) let check_all = max_lens != fst_lens + let aligns = s:get_cell_fast_aligns(rows[0:-2]) + let rows[-1][1] = line endif endif if check_all @@ -365,7 +410,9 @@ function! s:get_aligned_rows(lnum, col1, col2, depth) let max_lens[last_index] = 1 endif endif - let aligns = s:get_cell_aligns(a:lnum) + if empty(aligns) + let aligns = s:get_cell_aligns(a:lnum) + endif let result = [] for [lnum, row] in rows if s:is_separator(row)