915 lines
24 KiB
VimL
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
|
|
|
|
|
|
|
|
|