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   |
| <cursor> |                 |         |

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.
This commit is contained in:
lyokha 2019-04-04 15:05:57 +03:00 committed by Лёха
parent 3c0ae2ff97
commit 0303021abd

View File

@ -254,13 +254,6 @@ function! s:get_rows(lnum, ...)
while lnum <= line('$') while lnum <= line('$')
let line = getline(lnum) let line = getline(lnum)
if s:is_table(line) 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]) call add(rows, [lnum, line])
else else
break break
@ -275,9 +268,10 @@ function! s:get_rows(lnum, ...)
endfunction endfunction
function! s:get_cell_aligns(lnum) function! s:get_cell_aligns(lnum, ...)
let aligns = {} 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) if s:is_separator(row)
let cells = vimwiki#tbl#get_cells(row) let cells = vimwiki#tbl#get_cells(row)
for idx in range(len(cells)) for idx in range(len(cells))
@ -303,6 +297,46 @@ function! s:get_cell_aligns(lnum)
endfunction 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, ...) function! s:get_cell_max_lens(lnum, ...)
let max_lens = {} let max_lens = {}
let rows = a:0 > 2 ? a:3 : s:get_rows(a:lnum) 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) function! s:get_aligned_rows(lnum, col1, col2, depth)
let rows = [] let rows = []
let aligns = {}
let startlnum = 0 let startlnum = 0
let cells = [] let cells = []
let max_lens = {} let max_lens = {}
@ -335,6 +370,14 @@ function! s:get_aligned_rows(lnum, col1, col2, depth)
let startlnum = rows[0][0] let startlnum = rows[0][0]
let lrows = len(rows) let lrows = len(rows)
if lrows == a:depth + 1 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 let i = 1
for [lnum, row] in rows for [lnum, row] in rows
call add(cells, vimwiki#tbl#get_cells(row, i != lrows - 1)) 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 endif
let fst_lens = s:get_cell_max_lens(a:lnum, cells, startlnum, rows[0:0]) let fst_lens = s:get_cell_max_lens(a:lnum, cells, startlnum, rows[0:0])
let check_all = max_lens != fst_lens let check_all = max_lens != fst_lens
let aligns = s:get_cell_fast_aligns(rows[0:-2])
let rows[-1][1] = line
endif endif
endif endif
if check_all if check_all
@ -365,7 +410,9 @@ function! s:get_aligned_rows(lnum, col1, col2, depth)
let max_lens[last_index] = 1 let max_lens[last_index] = 1
endif endif
endif endif
let aligns = s:get_cell_aligns(a:lnum) if empty(aligns)
let aligns = s:get_cell_aligns(a:lnum)
endif
let result = [] let result = []
for [lnum, row] in rows for [lnum, row] in rows
if s:is_separator(row) if s:is_separator(row)