Files
dotfiles/vim/.vim/autoload/quickui/utils.vim
2024-02-19 17:02:19 +01:00

915 lines
24 KiB
VimL

"======================================================================
"
" utils.vim -
"
" Created by skywind on 2019/12/19
" Last Modified: 2023/07/23 18:44
"
"======================================================================
" vim: set noet fenc=utf-8 ff=unix sts=4 sw=4 ts=4 :
"----------------------------------------------------------------------
" parse description into item object
"----------------------------------------------------------------------
function! quickui#utils#item_parse(description)
let obj = {'text':'', 'key_pos':-1, 'key_char':'', 'is_sep':0, 'help':''}
let text = ''
let child = 0
if type(a:description) == v:t_string
let text = a:description
let obj.help = ''
let obj.cmd = ''
elseif type(a:description) == v:t_list
let size = len(a:description)
let text = (size >= 1)? a:description[0] : ''
let obj.help = (size >= 3)? a:description[2] : ''
let obj.cmd = ''
if size >= 2
if type(a:description[1]) == v:t_string
let obj.cmd = a:description[1]
elseif type(a:description[1]) == v:t_list
let obj.cmd = ''
let obj.child = a:description[1]
let child = 1
endif
endif
endif
if text =~ '^-\+$'
let obj.is_sep = 1
let obj.text = ""
let obj.desc = ""
let obj.text_width = 0
let obj.desc_width = 0
let obj.enable = 0
else
let text = quickui#core#expand_text(text)
let obj.enable = 1
if strpart(text, 0, 1) == '~'
let text = strpart(text, 1)
let obj.enable = 0
endif
let pos = stridx(text, "\t")
let sep = ">"
if pos < 0
let obj.text = text
let obj.desc = ""
else
let obj.text = strpart(text, 0, pos)
let obj.desc = strpart(text, pos + 1)
let obj.desc = substitute(obj.desc, "\t", " ", "g")
endif
let obj.desc = (child == 0)? obj.desc : sep
let text = obj.text
let rest = ''
let start = 0
while 1
let pos = stridx(text, "&", start)
if pos < 0
let rest .= strpart(text, start)
break
end
let rest .= strpart(text, start, pos - start)
let key = strpart(text, pos + 1, 1)
let start = pos + 2
if key == '&'
let rest .= '&'
elseif key == '~'
let rest .= '~'
else
let obj.key_char = key
let obj.key_pos = strwidth(rest)
let rest .= key
endif
endwhile
let obj.text = rest
let obj.text_width = strwidth(obj.text)
let obj.desc_width = strwidth(obj.desc)
end
return obj
endfunc
"----------------------------------------------------------------------
" alignment
"----------------------------------------------------------------------
function! quickui#utils#context_align(item, left_size, right_size)
let obj = a:item
let middle = (a:right_size > 0)? 2 : 0
let size = a:left_size + a:right_size + middle
if obj.is_sep
let obj.content = repeat('-', size)
else
if obj.text_width < a:left_size
let delta = a:left_size - obj.text_width
let obj.text_left = obj.text . repeat(' ', delta)
else
let obj.text_left = obj.text
endif
if obj.desc_width < a:right_size
let delta = a:right_size - obj.desc_width
let obj.text_right = repeat(' ', delta) . obj.desc
else
let obj.text_right = obj.desc
endif
if a:right_size > 0
let obj.content = obj.text_left . ' ' . obj.text_right
else
let obj.content = obj.text_left
endif
endif
return obj
endfunc
"----------------------------------------------------------------------
" style: default
"----------------------------------------------------------------------
function! quickui#utils#highlight(style)
let style = (type(a:style) == v:t_number)? (''. a:style) : a:style
let style = tolower(style)
if style == '' || style == '0' || style == 'default' || style == 'Pmenu'
hi! link TVisionBG Pmenu
hi! link TVisionKey Keyword
hi! link TVisionOff Comment
hi! link TVisionSel PmenuSel
hi! link TVisionHelp Title
elseif style == 'borland'
endif
endfunc
"----------------------------------------------------------------------
" build map
"----------------------------------------------------------------------
let s:maps = {}
let s:maps["\<ESC>"] = 'ESC'
let s:maps["\<CR>"] = 'ENTER'
let s:maps["\<SPACE>"] = 'ENTER'
let s:maps["\<UP>"] = 'UP'
let s:maps["\<DOWN>"] = 'DOWN'
let s:maps["\<LEFT>"] = 'LEFT'
let s:maps["\<RIGHT>"] = 'RIGHT'
let s:maps["\<HOME>"] = 'HOME'
let s:maps["\<END>"] = 'END'
let s:maps["\<c-j>"] = 'DOWN'
let s:maps["\<c-k>"] = 'UP'
let s:maps["\<c-h>"] = 'LEFT'
let s:maps["\<c-l>"] = 'RIGHT'
let s:maps["\<c-n>"] = 'NEXT'
let s:maps["\<c-p>"] = 'PREV'
let s:maps["\<c-b>"] = 'PAGEUP'
let s:maps["\<c-f>"] = 'PAGEDOWN'
let s:maps["\<c-u>"] = 'HALFUP'
let s:maps["\<c-d>"] = 'HALFDOWN'
let s:maps["\<PageUp>"] = 'PAGEUP'
let s:maps["\<PageDown>"] = 'PAGEDOWN'
let s:maps["\<c-g>"] = 'NOHL'
let s:maps['j'] = 'DOWN'
let s:maps['k'] = 'UP'
let s:maps['h'] = 'LEFT'
let s:maps['l'] = 'RIGHT'
let s:maps['J'] = 'HALFDOWN'
let s:maps['K'] = 'HALFUP'
let s:maps['H'] = 'PAGEUP'
let s:maps['L'] = 'PAGEDOWN'
let s:maps["g"] = 'TOP'
let s:maps["G"] = 'BOTTOM'
let s:maps['q'] = 'ESC'
let s:maps['n'] = 'NEXT'
let s:maps['N'] = 'PREV'
function! quickui#utils#keymap()
return deepcopy(s:maps)
endfunc
"----------------------------------------------------------------------
" python simulate system() on window to prevent temporary window
"----------------------------------------------------------------------
function! s:python_system(cmd, version)
if has('nvim')
let hr = system(a:cmd)
elseif has('win32') || has('win64') || has('win95') || has('win16')
if a:version < 0 || (has('python3') == 0 && has('python2') == 0)
let hr = system(a:cmd)
let s:shell_error = v:shell_error
return hr
elseif a:version == 3
let pyx = 'py3 '
let python_eval = 'py3eval'
elseif a:version == 2
let pyx = 'py2 '
let python_eval = 'pyeval'
else
let pyx = 'pyx '
let python_eval = 'pyxeval'
endif
exec pyx . 'import subprocess, vim'
exec pyx . '__argv = {"args":vim.eval("a:cmd"), "shell":True}'
exec pyx . '__argv["stdout"] = subprocess.PIPE'
exec pyx . '__argv["stderr"] = subprocess.STDOUT'
exec pyx . '__pp = subprocess.Popen(**__argv)'
exec pyx . '__return_text = __pp.stdout.read()'
exec pyx . '__pp.stdout.close()'
exec pyx . '__return_code = __pp.wait()'
exec 'let l:hr = '. python_eval .'("__return_text")'
exec 'let l:pc = '. python_eval .'("__return_code")'
let s:shell_error = l:pc
return l:hr
else
let hr = system(a:cmd)
endif
let s:shell_error = v:shell_error
return hr
endfunc
"----------------------------------------------------------------------
" execute external program and return its output
"----------------------------------------------------------------------
function! quickui#utils#system(cmd)
let hr = s:python_system(a:cmd, get(g:, 'quickui_python', 0))
let g:quickui#utils#shell_error = s:shell_error
return hr
endfunc
"----------------------------------------------------------------------
" display a error msg
"----------------------------------------------------------------------
function! quickui#utils#errmsg(what)
redraw
echohl ErrorMsg
echom a:what
echohl None
endfunc
"----------------------------------------------------------------------
" safe print
"----------------------------------------------------------------------
function! quickui#utils#print(content, highlight, ...)
let saveshow = &showmode
set noshowmode
let wincols = &columns
let statusline = (&laststatus==1 && winnr('$')>1) || (&laststatus==2)
let reqspaces_lastline = (statusline || !&ruler) ? 12 : 29
let width = len(a:content)
let limit = wincols - reqspaces_lastline
let l:content = a:content
if width + 1 > limit
let l:content = strpart(l:content, 0, limit - 1)
let width = len(l:content)
endif
" prevent scrolling caused by multiple echo
let needredraw = (a:0 >= 1)? a:1 : 1
if needredraw != 0
redraw
endif
if a:highlight != 0
echohl Type
echo l:content
echohl NONE
else
echo l:content
endif
if saveshow != 0
set showmode
endif
endfunc
"----------------------------------------------------------------------
" max height
"----------------------------------------------------------------------
function! quickui#utils#max_height(percentage)
return (&lines) * a:percentage / 100
endfunc
"----------------------------------------------------------------------
" cursor movement
"----------------------------------------------------------------------
function! quickui#utils#movement(offset)
let height = winheight(0)
let winline = winline()
let curline = line('.')
let topline = curline - winline + 1
let topline = (topline < 1)? 1 : topline
let botline = topline + height - 1
let offset = 0
if type(a:offset) == v:t_number
let offset = a:offset
elseif type(a:offset) == v:t_string
if a:offset == 'PAGEUP'
let offset = -height
elseif a:offset == 'PAGEDOWN'
let offset = height
elseif a:offset == 'HALFUP' || a:offset == 'LEFT'
let offset = -(height / 2)
elseif a:offset == 'HALFDOWN' || a:offset == 'RIGHT'
let offset = height / 2
elseif a:offset == 'UP'
let offset = -1
elseif a:offset == 'DOWN'
let offset = 1
elseif a:offset == 'TOP'
exec "noautocmd normal gg"
return
elseif a:offset == 'BOTTOM'
exec "noautocmd normal G"
return
endif
endif
" echom "offset: ". offset
if offset > 0
exec "noautocmd normal ". offset . "\<C-E>"
elseif offset < 0
exec "noautocmd normal ". (-offset) . "\<C-Y>"
endif
endfunc
"----------------------------------------------------------------------
" cursor scroll
"----------------------------------------------------------------------
function! quickui#utils#scroll(winid, offset)
if type(a:offset) == v:t_number
let cmd = 'call quickui#utils#movement(' . a:offset . ')'
call quickui#core#win_execute(a:winid, cmd)
else
let cmd = 'call quickui#utils#movement("' . a:offset . '")'
call quickui#core#win_execute(a:winid, cmd)
endif
endfunc
"----------------------------------------------------------------------
" centerize
"----------------------------------------------------------------------
function! quickui#utils#center(winid, ...)
if g:quickui#core#has_nvim == 0
let pos = popup_getpos(a:winid)
else
let pos = {}
let pos.width = nvim_win_get_width(a:winid)
let pos.height = nvim_win_get_height(a:winid)
endif
let h = pos.height
let w = pos.width
let mode = (a:0 < 1)? 0 : (a:1)
let scale = (mode == 0)? 80 : 68
let limit1 = (&lines - 2) * scale / 100
let limit2 = (&lines - 2)
let opts = {}
if h + 4 < limit1
let opts.line = (limit1 - h) / 2
else
let opts.line = (limit2 - h) / 2
endif
let opts.col = (&columns - w) / 2
let opts.col = (opts.col < 1)? 1 : (opts.col)
let hr = quickui#core#screen_fit(opts.line, opts.col, w, h)
let opts.col = hr[1]
let opts.line = hr[0]
if g:quickui#core#has_nvim == 0
call popup_move(a:winid, opts)
else
let no = {'col': opts.col - 1, 'row': opts.line - 1}
let no.relative = 'editor'
call nvim_win_set_config(a:winid, no)
endif
endfunc
"----------------------------------------------------------------------
" show cursorline in textbox
"----------------------------------------------------------------------
function! quickui#utils#show_cursor(winid, row)
let height = winheight(0)
let winline = winline()
let curline = line('.')
let topline = curline - winline + 1
let topline = (topline < 1)? 1 : topline
let botline = topline + height - 1
let w:__quickui_line__ = get(w:, '__quickui_line__', -1)
if a:row >= topline && a:row <= botline
exec ":" . a:row
if w:__quickui_line__ != 1
if g:quickui#core#has_nvim == 0
call popup_setoptions(a:winid, {'cursorline': 1})
else
call quickui#core#win_execute(a:winid, 'setl cursorline')
if exists('+cursorlineopt')
call quickui#core#win_execute(a:winid, 'setl cursorlineopt=both')
endif
endif
endif
let w:__quickui_line__ = 1
else
if w:__quickui_line__ != 0
if g:quickui#core#has_nvim == 0
call popup_setoptions(a:winid, {'cursorline': 0})
else
call quickui#core#win_execute(a:winid, 'setl nocursorline')
endif
endif
let w:__quickui_line__ = 0
endif
endfunc
"----------------------------------------------------------------------
" update cursor line
"----------------------------------------------------------------------
function! quickui#utils#update_cursor(winid)
let bid = winbufnr(a:winid)
let row = getbufvar(bid, '__quickui_cursor__', -1)
let cmd = 'call quickui#utils#show_cursor('. a:winid .', '.row.')'
call quickui#core#win_execute(a:winid, cmd)
endfunc
"----------------------------------------------------------------------
" get window line
"----------------------------------------------------------------------
function! quickui#utils#get_cursor(winid)
let g:quickui#utils#__cursor_index__ = -1
let cmd = 'let g:quickui#utils#__cursor_index__ = line(".")'
noautocmd call quickui#core#win_execute(a:winid, cmd)
return g:quickui#utils#__cursor_index__
endfunc
"----------------------------------------------------------------------
" get topline in current window
"----------------------------------------------------------------------
function! quickui#utils#current_topline()
let height = winheight(0)
let winline = winline()
let curline = line('.')
let topline = curline - winline + 1
return topline
endfunc
"----------------------------------------------------------------------
" get first cursorline
"----------------------------------------------------------------------
function! quickui#utils#get_topline(winid)
let g:quickui#utils#__cursor_topline__ = -1
let cmd = 'let g:quickui#utils#__cursor_topline__ = '
let cmd = cmd . 'quickui#utils#current_topline()'
call quickui#core#win_execute(a:winid, cmd)
return g:quickui#utils#__cursor_topline__
endfunc
"----------------------------------------------------------------------
" make border
"----------------------------------------------------------------------
function! quickui#utils#make_border(width, height, border, title, ...)
let pattern = quickui#core#border_get(a:border)
let image = []
let w = a:width
let h = a:height
let text = pattern[0] . repeat(pattern[1], w) . pattern[2]
let image += [text]
let index = 0
while index < h
let text = pattern[3] . repeat(' ', w) . pattern[5]
let image += [text]
let index += 1
endwhile
let text = pattern[6] . repeat(pattern[7], w) . pattern[8]
let image += [text]
let button = (a:0 > 0)? (a:1) : 0
let align = (a:0 > 1)? (a:2) : ''
let text = image[0]
let title = quickui#core#string_fit(a:title, w)
if align == '' || align == 'l'
let text = quickui#core#string_compose(text, 1, title)
elseif align == 'm'
let left = (w + 2 - len(title)) / 2
let text = quickui#core#string_compose(text, left, title)
elseif align == 'r'
let left = w + 2 - len(title) - 1
let text = quickui#core#string_compose(text, left, title)
endif
if button != 0
let text = quickui#core#string_compose(text, w + 1, 'X')
endif
let image[0] = text
return image
endfunc
"----------------------------------------------------------------------
" search or jump
"----------------------------------------------------------------------
function! quickui#utils#search_or_jump(winid, cmd)
if a:cmd == '/' || a:cmd == '?'
let prompt = (a:cmd == '/')? '/' : '?'
" let prompt = (a:cmd == '/')? '(search): ' : '(search backwards): '
let t = quickui#core#input(prompt, '')
if t != '' && t != "\<c-c>"
try
silent call quickui#core#win_execute(a:winid, a:cmd . t)
catch /^Vim\%((\a\+)\)\=:E486:/
call quickui#utils#errmsg('E486: Pattern not find: '. t)
endtry
silent! call quickui#core#win_execute(a:winid, 'nohl')
call setwinvar(a:winid, '__quickui_search_cmd', a:cmd)
call setwinvar(a:winid, '__quickui_search_key', t)
endif
elseif a:cmd == ':'
let prompt = ':'
" let prompt = '(goto): '
let t = quickui#core#input(prompt, '')
if t != ''
call quickui#core#win_execute(a:winid, ':' . t)
endif
endif
endfunc
"----------------------------------------------------------------------
" search next
"----------------------------------------------------------------------
function! quickui#utils#search_next(winid, cmd)
let prev_cmd = getwinvar(a:winid, '__quickui_search_cmd', '')
let prev_key = getwinvar(a:winid, '__quickui_search_key', '')
if prev_key != ''
if a:cmd ==# 'n' || a:cmd == 'NEXT'
let cmd = (prev_cmd == '/')? '/' : '?'
else
let cmd = (prev_cmd == '/')? '?' : '/'
endif
try
silent call quickui#core#win_execute(a:winid, cmd . prev_key)
catch /^Vim\%((\a\+)\)\=:E486:/
endtry
noautocmd call quickui#core#win_execute(a:winid, 'nohl')
endif
let cmds = ['exec line(".")']
let cmds += ['normal! 0']
silent call quickui#core#win_execute(a:winid, cmds)
endfunc
"----------------------------------------------------------------------
" size can be in '24' or '24%' or '0.25'
"----------------------------------------------------------------------
function! quickui#utils#read_size(text, maxsize)
if type(a:text) == v:t_number
return a:text
elseif type(a:text) == v:t_string
let text = trim(a:text)
if text =~ '%$'
let text = strpart(text, 0, len(text) - 1)
let ratio = str2nr(text)
let num = (a:maxsize) * ratio / 100
return (num < a:maxsize)? num : a:maxsize
else
let fsize = str2float(a:text)
if fsize <= 1.0
return float2nr(fsize * a:maxsize)
endif
let size = float2nr(fsize)
return (size > a:maxsize)? a:maxsize : size
endif
elseif type(a:text) == v:t_float
let fsize = a:text
if fsize <= 1.0
return float2nr(fsize * a:maxsize)
endif
let size = float2nr(fsize)
return (size > a:maxsize)? a:maxsize : size
endif
endfunc
"----------------------------------------------------------------------
" get default tools width
"----------------------------------------------------------------------
function! quickui#utils#tools_width()
let width = get(g:, 'quickui_tools_width', '60%')
let size = quickui#utils#read_size(width, &columns)
let minimal = (60 < &columns)? 60 : &columns
let size = (size < minimal)? minimal : size
return (size > &columns)? &columns : size
endfunc
"----------------------------------------------------------------------
" read from register or evaluation
"----------------------------------------------------------------------
function! quickui#utils#read_eval(...)
let opts = (a:0 == 0)? {} : (a:1)
try
let code = getchar()
catch /^Vim:Interrupt$/
let code = "\<C-C>"
endtry
let ch = (type(code) == v:t_number)? nr2char(code) : code
if ch == "\<c-c>"
return ''
elseif ch == "\<esc>" || ch == "\<cr>"
return ''
elseif ch == "="
let e = input('=')
if e == ''
return ''
endif
return eval(e)
elseif ch == "\<c-w>"
let x = expand('<cword>')
return x
elseif len(ch) == 1
let x = eval('@' . ch)
return x
endif
return ''
endfunc
"----------------------------------------------------------------------
" normalize textlist
"----------------------------------------------------------------------
function! quickui#utils#text_list_normalize(textlist)
if type(a:textlist) == v:t_list
let textlist = a:textlist
else
let textlist = split('' . a:textlist, '\n', 1)
endif
let out = []
for text in textlist
let text = substitute(text, '[\r\n\t]', ' ', 'g')
let out += [text]
endfor
return out
endfunc
"----------------------------------------------------------------------
" getchar
"----------------------------------------------------------------------
function! quickui#utils#getchar(wait)
try
if a:wait != 0
let code = getchar()
else
let code = getchar(0)
endif
catch /^Vim:Interrupt$/
let code = "\<C-C>"
endtry
if type(code) == v:t_number && code == 0
try
exec 'sleep 15m'
continue
catch /^Vim:Interrupt$/
let code = "\<c-c>"
endtry
endif
let ch = (type(code) == v:t_number)? nr2char(code) : code
return ch
endfunc
"----------------------------------------------------------------------
" switch buffer
"----------------------------------------------------------------------
function! quickui#utils#switch(filename, opts)
let switch = get(g:, 'quickui_switch_mode', &switchbuf)
let switch = get(a:opts, 'switch', switch)
let method = split(switch, ',')
let goto = get(a:opts, 'goto', -1)
let ft = get(a:opts, 'ft', '')
let cmds = get(a:opts, 'command', [])
if type(a:filename) == type('')
let filename = expand(a:filename)
if filereadable(filename) == 0
if get(a:opts, 'exist', 0) != 0
echohl ErrorMsg
echom "E484: Can't open file " . (a:filename)
echohl None
return 0
endif
endif
let bid = bufnr(filename)
else
let bid = a:filename
if bid < 0
return 0
endif
endif
if index(method, 'useopen') >= 0
for wid in range(winnr('$'))
let b = winbufnr(wid + 1)
if b == bid
silent exec ''. (wid + 1) . 'wincmd w'
if goto > 0
silent exec ':' . goto
endif
for cmd in cmds
exec cmd
endfor
return 1
endif
endfor
endif
if index(method, 'usetab') >= 0
for tid in range(tabpagenr('$'))
let buflist = tabpagebuflist(tid + 1)
for wid in range(len(buflist))
if bid == buflist[wid]
silent exec 'tabn ' . (tid + 1)
silent exec '' . (wid + 1) . 'wincmd w'
if goto > 0
silent exec ':' . goto
endif
for cmd in cmds
exec cmd
endfor
return 1
endif
endfor
endfor
endif
if index(method, 'newtab') >= 0
silent exec 'tab split'
elseif index(method, 'uselast') >= 0
silent exec 'wincmd p'
elseif index(method, 'edit') >= 0
silent exec ''
elseif index(method, 'drop') >= 0
else
if &buftype != ''
silent exec 'wincmd p'
endif
for i in range(winnr('$'))
if &buftype == ''
break
endif
silent exec 'wincmd w'
endfor
let mods = get(a:opts, 'mods', '')
if index(method, 'auto') >= 0
if winwidth(0) >= 160
exec mods . ' vsplit'
else
exec mods . ' split'
endif
elseif index(method, 'split') >= 0
exec mods . ' split'
elseif index(method, 'vsplit') >= 0
exec mods . ' vsplit'
endif
endif
try
let force = ((get(a:opts, 'force', 0) != 0)? '!' : '')
if bid >= 0
exec 'b' . force . ' ' . bid
else
exec 'edit' . force . ' ' . fnameescape(expand(a:filename))
endif
catch /^Vim\%((\a\+)\)\=:E37:/
echohl ErrorMsg
echo 'E37: No write since last change (set force=1 to override)'
echohl None
return 0
endtry
if goto > 0
exec ':' . goto
endif
if ft != ''
exec 'setlocal ft=' . fnameescape(ft)
endif
for cmd in cmds
exec cmd
endfor
return 1
endfunc
"----------------------------------------------------------------------
" returns 1 if filetype matches pattern, otherwise returns 0
"----------------------------------------------------------------------
function! quickui#utils#match_ft(filetype, pattern)
let pattern = quickui#core#string_strip(a:pattern)
let ft = a:filetype
if pattern == ''
return 0
elseif pattern =~ '^/'
let pattern = strpart(pattern, 1)
if match(ft, pattern) >= 0
return 1
endif
elseif pattern =~ '^!'
let pattern = strpart(pattern, 1)
if match(ft, pattern) < 0
return 1
endif
endif
let blacklist = []
let whitelist = []
for check in split(pattern, ',')
if pattern[0] == '-'
let blacklist += [check]
else
let whitelist += [check]
endif
endfor
if index(blacklist, '-' . ft) >= 0
return 0
endif
if empty(whitelist) || index(whitelist, ft) >= 0
return 1
endif
return 0
endfunc
"----------------------------------------------------------------------
" format table
"----------------------------------------------------------------------
function! quickui#utils#tabulify(rows)
let content = []
let rows = []
let nrows = len(a:rows)
let ncols = 0
for row in a:rows
if len(row) > ncols
let ncols = len(row)
endif
endfor
if nrows == 0 || ncols == 0
return content
endif
let sizes = repeat([0], ncols)
let index = range(ncols)
for row in a:rows
let newrow = deepcopy(row)
if len(newrow) < ncols
let newrow += repeat([''], ncols - len(newrow))
endif
for i in index
let size = strwidth(newrow[i])
let sizes[i] = (sizes[i] < size)? size : sizes[i]
endfor
let rows += [newrow]
endfor
for row in rows
let ni = []
for i in index
let x = row[i]
let size = strwidth(x)
if size < sizes[i]
let x = x . repeat(' ', sizes[i] - size)
endif
let ni += [x]
endfor
let content += [ni]
endfor
return content
endfunc
"----------------------------------------------------------------------
" print table
"----------------------------------------------------------------------
function! quickui#utils#print_table(rows, highmap)
let content = quickui#utils#tabulify(a:rows)
let index = 0
for line in content
let col = 0
echon (index == 0)? " " : "\n "
for cell in line
let key = index . ',' . col
if !has_key(a:highmap, key)
echohl None
else
exec 'echohl ' . a:highmap[key]
endif
echon cell . ' '
let col += 1
endfor
let index += 1
endfor
echohl None
endfunc