2022-05-18 13:29:28 -04:00
|
|
|
scriptencoding utf-8
|
|
|
|
let s:is_vim = !has('nvim')
|
|
|
|
let s:root = expand('<sfile>:h:h:h')
|
|
|
|
let s:prompt_win_bufnr = 0
|
2022-05-19 10:14:37 -04:00
|
|
|
let s:list_win_bufnr = 0
|
2022-05-18 13:29:28 -04:00
|
|
|
let s:prompt_win_width = get(g:, 'coc_prompt_win_width', 32)
|
|
|
|
let s:float_supported = exists('*nvim_open_win') || has('patch-8.1.1719')
|
|
|
|
let s:frames = ['· ', '·· ', '···', ' ··', ' ·', ' ']
|
2022-05-19 10:14:37 -04:00
|
|
|
let s:sign_group = 'PopUpCocDialog'
|
2022-05-18 13:29:28 -04:00
|
|
|
|
|
|
|
" Float window aside pum
|
|
|
|
function! coc#dialog#create_pum_float(winid, bufnr, lines, config) abort
|
|
|
|
if !pumvisible() || !s:float_supported
|
|
|
|
return v:null
|
|
|
|
endif
|
|
|
|
let pumbounding = a:config['pumbounding']
|
|
|
|
let pw = pumbounding['width'] + get(pumbounding, 'scrollbar', 0)
|
|
|
|
let rp = &columns - pumbounding['col'] - pw
|
|
|
|
let showRight = pumbounding['col'] > rp ? 0 : 1
|
|
|
|
let maxWidth = showRight ? coc#math#min(rp - 1, a:config['maxWidth']) : coc#math#min(pumbounding['col'] - 1, a:config['maxWidth'])
|
|
|
|
let border = get(a:config, 'border', [])
|
|
|
|
let bh = get(border, 0 ,0) + get(border, 2, 0)
|
|
|
|
let maxHeight = &lines - pumbounding['row'] - &cmdheight - 1 - bh
|
|
|
|
if maxWidth <= 2 || maxHeight < 1
|
|
|
|
return v:null
|
|
|
|
endif
|
|
|
|
let ch = 0
|
|
|
|
let width = 0
|
|
|
|
for line in a:lines
|
|
|
|
let dw = max([1, strdisplaywidth(line)])
|
|
|
|
let width = max([width, dw + 2])
|
|
|
|
let ch += float2nr(ceil(str2float(string(dw))/(maxWidth - 2)))
|
|
|
|
endfor
|
|
|
|
let width = float2nr(coc#math#min(maxWidth, width))
|
|
|
|
let height = float2nr(coc#math#min(maxHeight, ch))
|
|
|
|
let lines = map(a:lines, {_, s -> s =~# '^─' ? repeat('─', width - 2 + (s:is_vim && ch > height ? -1 : 0)) : s})
|
|
|
|
let opts = {
|
|
|
|
\ 'lines': lines,
|
|
|
|
\ 'highlights': get(a:config, 'highlights', []),
|
|
|
|
\ 'relative': 'editor',
|
|
|
|
\ 'col': showRight ? pumbounding['col'] + pw : pumbounding['col'] - width - 1,
|
|
|
|
\ 'row': pumbounding['row'],
|
|
|
|
\ 'height': height,
|
|
|
|
\ 'width': width - 2 + (s:is_vim && ch > height ? -1 : 0),
|
|
|
|
\ 'codes': get(a:config, 'codes', []),
|
|
|
|
\ }
|
|
|
|
for key in ['border', 'highlight', 'borderhighlight', 'winblend', 'focusable', 'shadow']
|
|
|
|
if has_key(a:config, key)
|
|
|
|
let opts[key] = a:config[key]
|
|
|
|
endif
|
|
|
|
endfor
|
|
|
|
call s:close_auto_hide_wins(a:winid)
|
|
|
|
let res = coc#float#create_float_win(a:winid, a:bufnr, opts)
|
|
|
|
if empty(res)
|
|
|
|
return v:null
|
|
|
|
endif
|
|
|
|
call setwinvar(res[0], 'kind', 'pum')
|
|
|
|
if has('nvim')
|
|
|
|
call coc#float#nvim_scrollbar(res[0])
|
|
|
|
endif
|
|
|
|
return res
|
|
|
|
endfunction
|
|
|
|
|
|
|
|
" Float window below/above cursor
|
|
|
|
function! coc#dialog#create_cursor_float(winid, bufnr, lines, config) abort
|
|
|
|
if !s:float_supported || coc#prompt#activated()
|
|
|
|
return v:null
|
|
|
|
endif
|
|
|
|
let pumAlignTop = get(a:config, 'pumAlignTop', 0)
|
|
|
|
let modes = get(a:config, 'modes', ['n', 'i', 'ic', 's'])
|
|
|
|
let mode = mode()
|
|
|
|
let currbuf = bufnr('%')
|
|
|
|
let pos = [line('.'), col('.')]
|
|
|
|
if index(modes, mode) == -1
|
|
|
|
return v:null
|
|
|
|
endif
|
|
|
|
if has('nvim') && mode ==# 'i'
|
|
|
|
" helps to fix undo issue, don't know why.
|
|
|
|
call feedkeys("\<C-g>u", 'n')
|
|
|
|
endif
|
|
|
|
let dimension = coc#dialog#get_config_cursor(a:lines, a:config)
|
|
|
|
if empty(dimension)
|
|
|
|
return v:null
|
|
|
|
endif
|
|
|
|
if pumvisible() && ((pumAlignTop && dimension['row'] <0)|| (!pumAlignTop && dimension['row'] > 0))
|
|
|
|
return v:null
|
|
|
|
endif
|
|
|
|
let width = dimension['width']
|
|
|
|
let lines = map(a:lines, {_, s -> s =~# '^─' ? repeat('─', width) : s})
|
|
|
|
let config = extend(extend({'lines': lines, 'relative': 'cursor'}, a:config), dimension)
|
|
|
|
call s:close_auto_hide_wins(a:winid)
|
|
|
|
let res = coc#float#create_float_win(a:winid, a:bufnr, config)
|
|
|
|
if empty(res)
|
|
|
|
return v:null
|
|
|
|
endif
|
|
|
|
let alignTop = dimension['row'] < 0
|
|
|
|
let winid = res[0]
|
|
|
|
let bufnr = res[1]
|
|
|
|
redraw
|
|
|
|
if has('nvim')
|
|
|
|
call coc#float#nvim_scrollbar(winid)
|
|
|
|
endif
|
|
|
|
return [currbuf, pos, winid, bufnr, alignTop]
|
|
|
|
endfunction
|
|
|
|
|
|
|
|
" Create float window for input
|
|
|
|
function! coc#dialog#create_prompt_win(title, default, opts) abort
|
|
|
|
call s:close_auto_hide_wins()
|
|
|
|
let bufnr = has('nvim') ? s:prompt_win_bufnr : 0
|
|
|
|
if s:is_vim
|
|
|
|
execute 'hi link CocPopupTerminal '.get(a:opts, 'highlight', 'CocFloating')
|
|
|
|
let node = expand(get(g:, 'coc_node_path', 'node'))
|
|
|
|
let bufnr = term_start([node, s:root . '/bin/prompt.js', a:default], {
|
2022-05-19 10:14:37 -04:00
|
|
|
\ 'term_rows': 1,
|
2022-05-18 13:29:28 -04:00
|
|
|
\ 'term_highlight': 'CocPopupTerminal',
|
|
|
|
\ 'hidden': 1,
|
|
|
|
\ 'term_finish': 'close'
|
|
|
|
\ })
|
|
|
|
call term_setapi(bufnr, 'Coc')
|
2022-05-19 10:14:37 -04:00
|
|
|
call setbufvar(bufnr, 'current', type(a:default) == v:t_string ? a:default : '')
|
2022-05-18 13:29:28 -04:00
|
|
|
endif
|
|
|
|
let config = s:get_prompt_dimension(a:title, a:default, a:opts)
|
|
|
|
let res = coc#float#create_float_win(0, bufnr, extend(config, {
|
|
|
|
\ 'style': 'minimal',
|
|
|
|
\ 'border': get(a:opts, 'border', [1,1,1,1]),
|
|
|
|
\ 'rounded': get(a:opts, 'rounded', 1),
|
|
|
|
\ 'prompt': 1,
|
|
|
|
\ 'title': a:title,
|
|
|
|
\ 'lines': s:is_vim ? v:null : [a:default],
|
|
|
|
\ 'highlight': get(a:opts, 'highlight', 'CocFloating'),
|
|
|
|
\ 'borderhighlight': [get(a:opts, 'borderhighlight', 'CocFloating')],
|
|
|
|
\ }))
|
|
|
|
if empty(res)
|
|
|
|
return
|
|
|
|
endif
|
|
|
|
let winid = res[0]
|
|
|
|
let bufnr = res[1]
|
|
|
|
if has('nvim')
|
|
|
|
let s:prompt_win_bufnr = res[1]
|
|
|
|
execute 'sign unplace 6 buffer='.s:prompt_win_bufnr
|
|
|
|
call nvim_set_current_win(winid)
|
|
|
|
inoremap <buffer> <C-a> <Home>
|
|
|
|
inoremap <buffer><expr><C-e> pumvisible() ? "\<C-e>" : "\<End>"
|
2022-05-19 10:14:37 -04:00
|
|
|
exe 'imap <silent><nowait><buffer> <esc> <esc><esc>'
|
2022-05-18 13:29:28 -04:00
|
|
|
exe 'nnoremap <silent><buffer> <esc> :call coc#float#close('.winid.')<CR>'
|
|
|
|
exe 'inoremap <silent><expr><nowait><buffer> <cr> "\<C-r>=coc#dialog#prompt_insert(getline(''.''))\<cr>\<esc>"'
|
2022-05-19 10:14:37 -04:00
|
|
|
if get(a:opts, 'list', 0)
|
|
|
|
for key in ['<C-j>', '<C-k>', '<C-n>', '<C-p>', '<up>', '<down>', '<C-f>', '<C-b>', '<C-space>']
|
|
|
|
" Can't use < in remap
|
|
|
|
let escaped = key ==# '<C-space>' ? "C-@" : strcharpart(key, 1, strchars(key) - 2)
|
|
|
|
exe 'inoremap <nowait><buffer> '.key.' <Cmd>call coc#rpc#notify("PromptKeyPress", ['.bufnr.', "'.escaped.'"])<CR>'
|
|
|
|
endfor
|
|
|
|
endif
|
2022-05-18 13:29:28 -04:00
|
|
|
call feedkeys('A', 'in')
|
|
|
|
endif
|
|
|
|
call coc#util#do_autocmd('CocOpenFloatPrompt')
|
|
|
|
if s:is_vim
|
|
|
|
let pos = popup_getpos(winid)
|
|
|
|
" width height row col
|
2022-05-19 10:14:37 -04:00
|
|
|
let dimension = [pos['width'], pos['height'], pos['line'] - 1, pos['col'] - 1]
|
2022-05-18 13:29:28 -04:00
|
|
|
else
|
|
|
|
let id = coc#float#get_related(winid, 'border')
|
2022-05-19 10:14:37 -04:00
|
|
|
if !has('nvim-0.6.0')
|
|
|
|
redraw
|
|
|
|
endif
|
2022-05-18 13:29:28 -04:00
|
|
|
let pos = nvim_win_get_position(id)
|
|
|
|
let dimension = [nvim_win_get_width(id), nvim_win_get_height(id), pos[0], pos[1]]
|
|
|
|
endif
|
|
|
|
return [bufnr, winid, dimension]
|
|
|
|
endfunction
|
|
|
|
|
2022-05-19 10:14:37 -04:00
|
|
|
" Create list window under target window
|
|
|
|
function! coc#dialog#create_list(target, dimension, opts) abort
|
|
|
|
let maxHeight = get(a:opts, 'maxHeight', 10)
|
|
|
|
let height = max([1, len(get(a:opts, 'lines', []))])
|
|
|
|
let height = min([maxHeight, height, &lines - &cmdheight - 1 - a:dimension['row'] + a:dimension['height']])
|
|
|
|
let chars = get(a:opts, 'rounded', 1) ? ['╯', '╰'] : ['┘', '└']
|
|
|
|
let config = extend(copy(a:opts), {
|
|
|
|
\ 'relative': 'editor',
|
|
|
|
\ 'row': a:dimension['row'] + a:dimension['height'],
|
|
|
|
\ 'col': a:dimension['col'],
|
|
|
|
\ 'width': a:dimension['width'] - 2,
|
|
|
|
\ 'height': height,
|
|
|
|
\ 'border': [1, 1, 1, 1],
|
|
|
|
\ 'scrollinside': 1,
|
|
|
|
\ 'borderchars': extend(['─', '│', '─', '│', '├', '┤'], chars)
|
|
|
|
\ })
|
|
|
|
let bufnr = 0
|
|
|
|
let result = coc#float#create_float_win(0, s:list_win_bufnr, config)
|
|
|
|
if empty(result)
|
|
|
|
return
|
|
|
|
endif
|
|
|
|
let winid = result[0]
|
|
|
|
call coc#float#add_related(winid, a:target)
|
|
|
|
call setwinvar(winid, 'auto_height', get(a:opts, 'autoHeight', 1))
|
|
|
|
call setwinvar(winid, 'max_height', maxHeight)
|
|
|
|
call setwinvar(winid, 'target_winid', a:target)
|
|
|
|
call setwinvar(winid, 'kind', 'list')
|
|
|
|
call coc#dialog#check_scroll_vim(a:target)
|
|
|
|
return result
|
|
|
|
endfunction
|
|
|
|
|
2022-05-18 13:29:28 -04:00
|
|
|
" Create menu picker for pick single item
|
|
|
|
function! coc#dialog#create_menu(lines, config) abort
|
|
|
|
call s:close_auto_hide_wins()
|
|
|
|
let highlight = get(a:config, 'highlight', 'CocFloating')
|
|
|
|
let borderhighlight = get(a:config, 'borderhighlight', [highlight])
|
|
|
|
let relative = get(a:config, 'relative', 'cursor')
|
|
|
|
let opts = {
|
|
|
|
\ 'lines': a:lines,
|
|
|
|
\ 'highlight': highlight,
|
|
|
|
\ 'title': get(a:config, 'title', ''),
|
|
|
|
\ 'borderhighlight': borderhighlight,
|
|
|
|
\ 'maxWidth': get(a:config, 'maxWidth', 80),
|
|
|
|
\ 'maxHeight': get(a:config, 'maxHeight', 80),
|
|
|
|
\ 'rounded': get(a:config, 'rounded', 0),
|
|
|
|
\ 'border': [1, 1, 1, 1],
|
|
|
|
\ 'highlights': get(a:config, 'highlights', []),
|
|
|
|
\ 'relative': relative,
|
|
|
|
\ }
|
|
|
|
if relative ==# 'editor'
|
|
|
|
let dimension = coc#dialog#get_config_editor(a:lines, opts)
|
|
|
|
else
|
|
|
|
let dimension = coc#dialog#get_config_cursor(a:lines, opts)
|
|
|
|
endif
|
|
|
|
call extend(opts, dimension)
|
|
|
|
let res = coc#float#create_float_win(0, s:prompt_win_bufnr, opts)
|
|
|
|
if empty(res)
|
|
|
|
return
|
|
|
|
endif
|
|
|
|
let s:prompt_win_bufnr = res[1]
|
2022-05-19 10:14:37 -04:00
|
|
|
call s:place_sign(s:prompt_win_bufnr, 1)
|
2022-05-18 13:29:28 -04:00
|
|
|
redraw
|
|
|
|
if has('nvim')
|
|
|
|
call coc#float#nvim_scrollbar(res[0])
|
|
|
|
endif
|
|
|
|
return res
|
|
|
|
endfunction
|
|
|
|
|
|
|
|
" Create dialog at center of screen
|
|
|
|
function! coc#dialog#create_dialog(lines, config) abort
|
|
|
|
call s:close_auto_hide_wins()
|
|
|
|
" dialog always have borders
|
|
|
|
let title = get(a:config, 'title', '')
|
|
|
|
let buttons = get(a:config, 'buttons', [])
|
|
|
|
let highlight = get(a:config, 'highlight', 'CocFloating')
|
|
|
|
let borderhighlight = get(a:config, 'borderhighlight', [highlight])
|
|
|
|
let opts = {
|
|
|
|
\ 'title': title,
|
|
|
|
\ 'rounded': get(a:config, 'rounded', 0),
|
|
|
|
\ 'relative': 'editor',
|
|
|
|
\ 'border': [1,1,1,1],
|
|
|
|
\ 'close': get(a:config, 'close', 1),
|
|
|
|
\ 'highlight': highlight,
|
|
|
|
\ 'highlights': get(a:config, 'highlights', []),
|
|
|
|
\ 'buttons': buttons,
|
|
|
|
\ 'borderhighlight': borderhighlight,
|
|
|
|
\ 'getchar': get(a:config, 'getchar', 0)
|
|
|
|
\ }
|
|
|
|
call extend(opts, coc#dialog#get_config_editor(a:lines, a:config))
|
|
|
|
let bufnr = coc#float#create_buf(0, a:lines)
|
|
|
|
let res = coc#float#create_float_win(0, bufnr, opts)
|
|
|
|
if empty(res)
|
|
|
|
return
|
|
|
|
endif
|
2022-05-19 10:14:37 -04:00
|
|
|
if get(a:config, 'cursorline', 0)
|
|
|
|
call s:place_sign(bufnr, 1)
|
|
|
|
endif
|
2022-05-18 13:29:28 -04:00
|
|
|
if has('nvim')
|
|
|
|
redraw
|
|
|
|
call coc#float#nvim_scrollbar(res[0])
|
|
|
|
endif
|
|
|
|
return res
|
|
|
|
endfunction
|
|
|
|
|
|
|
|
function! coc#dialog#prompt_confirm(title, cb) abort
|
|
|
|
call s:close_auto_hide_wins()
|
|
|
|
if s:is_vim && exists('*popup_dialog')
|
|
|
|
try
|
|
|
|
call popup_dialog(a:title. ' (y/n)?', {
|
|
|
|
\ 'highlight': 'Normal',
|
|
|
|
\ 'filter': 'popup_filter_yesno',
|
|
|
|
\ 'callback': {id, res -> a:cb(v:null, res)},
|
|
|
|
\ 'borderchars': get(g:, 'coc_borderchars', ['─', '│', '─', '│', '╭', '╮', '╯', '╰']),
|
|
|
|
\ 'borderhighlight': ['MoreMsg']
|
|
|
|
\ })
|
|
|
|
catch /.*/
|
|
|
|
call a:cb(v:exception)
|
|
|
|
endtry
|
|
|
|
return
|
|
|
|
endif
|
|
|
|
if has('nvim-0.4.0')
|
|
|
|
let text = ' '. a:title . ' (y/n)? '
|
|
|
|
let maxWidth = coc#math#min(78, &columns - 2)
|
|
|
|
let width = coc#math#min(maxWidth, strdisplaywidth(text))
|
|
|
|
let maxHeight = &lines - &cmdheight - 1
|
|
|
|
let height = coc#math#min(maxHeight, float2nr(ceil(str2float(string(strdisplaywidth(text)))/width)))
|
|
|
|
let arr = coc#float#create_float_win(0, s:prompt_win_bufnr, {
|
|
|
|
\ 'col': &columns/2 - width/2 - 1,
|
|
|
|
\ 'row': maxHeight/2 - height/2 - 1,
|
|
|
|
\ 'width': width,
|
|
|
|
\ 'height': height,
|
|
|
|
\ 'border': [1,1,1,1],
|
|
|
|
\ 'focusable': v:false,
|
|
|
|
\ 'relative': 'editor',
|
|
|
|
\ 'highlight': 'Normal',
|
|
|
|
\ 'borderhighlight': ['MoreMsg'],
|
|
|
|
\ 'style': 'minimal',
|
|
|
|
\ 'lines': [text],
|
|
|
|
\ })
|
|
|
|
if empty(arr)
|
|
|
|
call a:cb('Window create failed!')
|
|
|
|
return
|
|
|
|
endif
|
|
|
|
let winid = arr[0]
|
|
|
|
let s:prompt_win_bufnr = arr[1]
|
|
|
|
let res = 0
|
|
|
|
redraw
|
|
|
|
" same result as vim
|
|
|
|
while 1
|
|
|
|
let key = nr2char(getchar())
|
|
|
|
if key == "\<C-c>"
|
|
|
|
let res = -1
|
|
|
|
break
|
|
|
|
elseif key == "\<esc>" || key == 'n' || key == 'N'
|
|
|
|
let res = 0
|
|
|
|
break
|
|
|
|
elseif key == 'y' || key == 'Y'
|
|
|
|
let res = 1
|
|
|
|
break
|
|
|
|
endif
|
|
|
|
endw
|
|
|
|
call coc#float#close(winid)
|
|
|
|
call a:cb(v:null, res)
|
|
|
|
" use relative editor since neovim doesn't support center position
|
|
|
|
elseif exists('*confirm')
|
|
|
|
let choice = confirm(a:title, "&Yes\n&No")
|
|
|
|
call a:cb(v:null, choice == 1)
|
|
|
|
else
|
|
|
|
echohl MoreMsg
|
|
|
|
echom a:title.' (y/n)'
|
|
|
|
echohl None
|
|
|
|
let confirm = nr2char(getchar())
|
|
|
|
redraw!
|
|
|
|
if !(confirm ==? "y" || confirm ==? "\r")
|
|
|
|
echohl Moremsg | echo 'Cancelled.' | echohl None
|
|
|
|
return 0
|
|
|
|
call a:cb(v:null, 0)
|
|
|
|
end
|
|
|
|
call a:cb(v:null, 1)
|
|
|
|
endif
|
|
|
|
endfunction
|
|
|
|
|
|
|
|
function! coc#dialog#get_config_editor(lines, config) abort
|
|
|
|
let title = get(a:config, 'title', '')
|
|
|
|
let maxheight = min([get(a:config, 'maxHeight', 78), &lines - &cmdheight - 6])
|
|
|
|
let maxwidth = min([get(a:config, 'maxWidth', 78), &columns - 2])
|
|
|
|
let buttons = get(a:config, 'buttons', [])
|
|
|
|
let minwidth = s:min_btns_width(buttons)
|
|
|
|
if maxheight <= 0 || maxwidth <= 0 || minwidth > maxwidth
|
|
|
|
throw 'Not enough spaces for float window'
|
|
|
|
endif
|
|
|
|
let ch = 0
|
|
|
|
let width = min([strdisplaywidth(title) + 1, maxwidth])
|
|
|
|
for line in a:lines
|
|
|
|
let dw = max([1, strdisplaywidth(line)])
|
|
|
|
if dw < maxwidth && dw > width
|
|
|
|
let width = dw
|
|
|
|
elseif dw >= maxwidth
|
|
|
|
let width = maxwidth
|
|
|
|
endif
|
|
|
|
let ch += float2nr(ceil(str2float(string(dw))/maxwidth))
|
|
|
|
endfor
|
|
|
|
let width = max([minwidth, width])
|
|
|
|
let height = coc#math#min(ch ,maxheight)
|
|
|
|
return {
|
|
|
|
\ 'row': &lines/2 - (height + 4)/2,
|
|
|
|
\ 'col': &columns/2 - (width + 2)/2,
|
|
|
|
\ 'width': width,
|
|
|
|
\ 'height': height,
|
|
|
|
\ }
|
|
|
|
endfunction
|
|
|
|
|
|
|
|
function! coc#dialog#prompt_insert(text) abort
|
|
|
|
call coc#rpc#notify('PromptInsert', [a:text, bufnr('%')])
|
|
|
|
return ''
|
|
|
|
endfunction
|
|
|
|
|
|
|
|
" Dimension of window with lines relative to cursor
|
|
|
|
" Width & height excludes border & padding
|
|
|
|
function! coc#dialog#get_config_cursor(lines, config) abort
|
|
|
|
let preferTop = get(a:config, 'preferTop', 0)
|
|
|
|
let title = get(a:config, 'title', '')
|
|
|
|
let border = get(a:config, 'border', [])
|
|
|
|
if empty(border) && len(title)
|
|
|
|
let border = [1, 1, 1, 1]
|
|
|
|
endif
|
|
|
|
let bh = get(border, 0, 0) + get(border, 2, 0)
|
|
|
|
let vh = &lines - &cmdheight - 1
|
|
|
|
if vh <= 0
|
|
|
|
return v:null
|
|
|
|
endif
|
|
|
|
let maxWidth = coc#math#min(get(a:config, 'maxWidth', &columns - 1), &columns - 1)
|
|
|
|
if maxWidth < 3
|
|
|
|
return v:null
|
|
|
|
endif
|
|
|
|
let maxHeight = coc#math#min(get(a:config, 'maxHeight', vh), vh)
|
|
|
|
let ch = 0
|
|
|
|
let width = coc#math#min(40, strdisplaywidth(title)) + 3
|
|
|
|
for line in a:lines
|
|
|
|
let dw = max([1, strdisplaywidth(line)])
|
|
|
|
let width = max([width, dw + 2])
|
|
|
|
let ch += float2nr(ceil(str2float(string(dw))/(maxWidth - 2)))
|
|
|
|
endfor
|
|
|
|
let width = coc#math#min(maxWidth, width)
|
|
|
|
let [lineIdx, colIdx] = coc#cursor#screen_pos()
|
|
|
|
" How much we should move left
|
|
|
|
let offsetX = coc#math#min(get(a:config, 'offsetX', 0), colIdx)
|
|
|
|
let showTop = 0
|
|
|
|
let hb = vh - lineIdx -1
|
|
|
|
if lineIdx > bh + 2 && (preferTop || (lineIdx > hb && hb < ch + bh))
|
|
|
|
let showTop = 1
|
|
|
|
endif
|
|
|
|
let height = coc#math#min(maxHeight, ch + bh, showTop ? lineIdx - 1 : hb)
|
|
|
|
if height <= bh
|
|
|
|
return v:null
|
|
|
|
endif
|
|
|
|
let col = - max([offsetX, colIdx - (&columns - 1 - width)])
|
|
|
|
let row = showTop ? - height + bh : 1
|
|
|
|
return {
|
|
|
|
\ 'row': row,
|
|
|
|
\ 'col': col,
|
|
|
|
\ 'width': width - 2,
|
|
|
|
\ 'height': height - bh
|
|
|
|
\ }
|
|
|
|
endfunction
|
|
|
|
|
|
|
|
function! coc#dialog#change_border_hl(winid, hlgroup) abort
|
|
|
|
if !hlexists(a:hlgroup)
|
|
|
|
return
|
|
|
|
endif
|
|
|
|
if s:is_vim
|
|
|
|
if coc#float#valid(a:winid)
|
|
|
|
call popup_setoptions(a:winid, {'borderhighlight': repeat([a:hlgroup], 4)})
|
|
|
|
redraw
|
|
|
|
endif
|
|
|
|
else
|
|
|
|
let winid = coc#float#get_related(a:winid, 'border')
|
|
|
|
if winid > 0
|
|
|
|
call setwinvar(winid, '&winhl', 'Normal:'.a:hlgroup.',NormalNC:'.a:hlgroup)
|
|
|
|
endif
|
|
|
|
endif
|
|
|
|
endfunction
|
|
|
|
|
|
|
|
function! coc#dialog#change_title(winid, title) abort
|
|
|
|
if s:is_vim
|
|
|
|
if coc#float#valid(a:winid)
|
|
|
|
call popup_setoptions(a:winid, {'title': a:title})
|
|
|
|
redraw
|
|
|
|
endif
|
|
|
|
else
|
|
|
|
let winid = coc#float#get_related(a:winid, 'border')
|
|
|
|
if winid > 0
|
|
|
|
let bufnr = winbufnr(winid)
|
|
|
|
let line = getbufline(bufnr, 1)[0]
|
|
|
|
let top = strcharpart(line, 0, 1)
|
|
|
|
\.repeat('─', strchars(line) - 2)
|
|
|
|
\.strcharpart(line, strchars(line) - 1, 1)
|
|
|
|
if !empty(a:title)
|
|
|
|
let top = coc#string#compose(top, 1, a:title.' ')
|
|
|
|
endif
|
|
|
|
call nvim_buf_set_lines(bufnr, 0, 1, v:false, [top])
|
|
|
|
endif
|
|
|
|
endif
|
|
|
|
endfunction
|
|
|
|
|
|
|
|
function! coc#dialog#change_loading(winid, loading) abort
|
|
|
|
if coc#float#valid(a:winid)
|
|
|
|
let winid = coc#float#get_related(a:winid, 'loading')
|
|
|
|
if !a:loading && winid > 0
|
|
|
|
call coc#float#close(winid)
|
|
|
|
endif
|
|
|
|
if a:loading && winid == 0
|
|
|
|
let bufnr = s:create_loading_buf()
|
|
|
|
if s:is_vim
|
|
|
|
let pos = popup_getpos(a:winid)
|
|
|
|
let winid = popup_create(bufnr, {
|
|
|
|
\ 'line': pos['line'] + 1,
|
|
|
|
\ 'col': pos['col'] + pos['width'] - 4,
|
|
|
|
\ 'maxheight': 1,
|
|
|
|
\ 'maxwidth': 3,
|
|
|
|
\ 'zindex': 999,
|
|
|
|
\ 'highlight': get(popup_getoptions(a:winid), 'highlight', 'CocFloating')
|
|
|
|
\ })
|
|
|
|
else
|
|
|
|
let pos = nvim_win_get_position(a:winid)
|
|
|
|
let width = nvim_win_get_width(a:winid)
|
|
|
|
let opts = {
|
|
|
|
\ 'relative': 'editor',
|
|
|
|
\ 'row': pos[0],
|
|
|
|
\ 'col': pos[1] + width - 3,
|
|
|
|
\ 'focusable': v:false,
|
|
|
|
\ 'width': 3,
|
|
|
|
\ 'height': 1,
|
|
|
|
\ 'style': 'minimal',
|
|
|
|
\ }
|
|
|
|
if has('nvim-0.5.1')
|
|
|
|
let opts['zindex'] = 900
|
|
|
|
endif
|
|
|
|
let winid = nvim_open_win(bufnr, v:false, opts)
|
|
|
|
call setwinvar(winid, '&winhl', getwinvar(a:winid, '&winhl'))
|
|
|
|
endif
|
|
|
|
call setwinvar(winid, 'kind', 'loading')
|
2022-05-19 10:14:37 -04:00
|
|
|
call setbufvar(bufnr, 'target_winid', a:winid)
|
2022-05-18 13:29:28 -04:00
|
|
|
call setbufvar(bufnr, 'popup', winid)
|
|
|
|
call coc#float#add_related(winid, a:winid)
|
|
|
|
endif
|
|
|
|
endif
|
|
|
|
endfunction
|
|
|
|
|
2022-05-19 10:14:37 -04:00
|
|
|
" Update list with new lines and highlights
|
|
|
|
function! coc#dialog#update_list(winid, bufnr, lines, highlights) abort
|
|
|
|
if coc#window#tabnr(a:winid) == tabpagenr()
|
|
|
|
if getwinvar(a:winid, 'auto_height', 0)
|
|
|
|
let row = coc#float#get_row(a:winid)
|
|
|
|
" core height
|
|
|
|
let height = max([1, len(copy(a:lines))])
|
|
|
|
let height = min([getwinvar(a:winid, 'max_height', 10), height, &lines - &cmdheight - 1 - row])
|
|
|
|
let curr = s:is_vim ? popup_getpos(a:winid)['core_height'] : nvim_win_get_height(a:winid)
|
|
|
|
let delta = height - curr
|
|
|
|
if delta != 0
|
|
|
|
call coc#float#change_height(a:winid, delta)
|
|
|
|
endif
|
|
|
|
endif
|
|
|
|
call coc#compat#buf_set_lines(a:bufnr, 0, -1, a:lines)
|
|
|
|
call coc#highlight#add_highlights(a:winid, [], a:highlights)
|
|
|
|
if s:is_vim
|
|
|
|
let target = getwinvar(a:winid, 'target_winid', -1)
|
|
|
|
if target != -1
|
|
|
|
call coc#dialog#check_scroll_vim(target)
|
|
|
|
endif
|
|
|
|
call win_execute(a:winid, 'exe 1')
|
|
|
|
endif
|
|
|
|
endif
|
|
|
|
endfunction
|
|
|
|
|
|
|
|
" Fix width of prompt window same as list window on scrollbar change
|
|
|
|
function! coc#dialog#check_scroll_vim(winid) abort
|
|
|
|
if s:is_vim && coc#float#valid(a:winid)
|
|
|
|
let winid = coc#float#get_related(a:winid, 'list')
|
|
|
|
if winid
|
|
|
|
redraw
|
|
|
|
let pos = popup_getpos(winid)
|
|
|
|
let width = pos['width'] + (pos['scrollbar'] ? 1 : 0)
|
|
|
|
if width != popup_getpos(a:winid)['width']
|
|
|
|
call popup_move(a:winid, {
|
|
|
|
\ 'minwidth': width - 2,
|
|
|
|
\ 'maxwidth': width - 2,
|
|
|
|
\ })
|
|
|
|
endif
|
|
|
|
endif
|
|
|
|
endif
|
|
|
|
endfunction
|
|
|
|
|
|
|
|
function! coc#dialog#set_cursor(winid, bufnr, line) abort
|
|
|
|
if s:is_vim
|
|
|
|
call coc#compat#execute(a:winid, 'exe '.a:line, 'silent!')
|
|
|
|
call popup_setoptions(a:winid, {'cursorline' : 1})
|
|
|
|
call popup_setoptions(a:winid, {'cursorline' : 0})
|
|
|
|
else
|
|
|
|
call nvim_win_set_cursor(a:winid, [a:line, 0])
|
|
|
|
endif
|
|
|
|
call s:place_sign(a:bufnr, a:line)
|
|
|
|
endfunction
|
|
|
|
|
2022-05-18 13:29:28 -04:00
|
|
|
" Could be center(with optional marginTop) or cursor
|
|
|
|
function! s:get_prompt_dimension(title, default, opts) abort
|
|
|
|
let relative = get(a:opts, 'position', 'cursor') ==# 'cursor' ? 'cursor' : 'editor'
|
|
|
|
let curr = win_screenpos(winnr())[1] + wincol() - 2
|
|
|
|
let minWidth = get(a:opts, 'minWidth', s:prompt_win_width)
|
|
|
|
let width = min([max([strwidth(a:default) + 2, strwidth(a:title) + 2, minWidth]), &columns - 2])
|
|
|
|
if get(a:opts, 'maxWidth', 0)
|
|
|
|
let width = min([width, a:opts['maxWidth']])
|
|
|
|
endif
|
|
|
|
if relative ==# 'cursor'
|
|
|
|
let [lineIdx, colIdx] = coc#cursor#screen_pos()
|
|
|
|
if width == &columns - 2
|
|
|
|
let col = 0 - curr
|
|
|
|
else
|
|
|
|
let col = curr + width <= &columns - 2 ? 0 : curr + width - &columns + 2
|
|
|
|
endif
|
|
|
|
let config = {
|
|
|
|
\ 'row': lineIdx == 0 ? 1 : 0,
|
|
|
|
\ 'col': colIdx == 0 ? 0 : col - 1,
|
|
|
|
\ }
|
|
|
|
else
|
|
|
|
let marginTop = get(a:opts, 'marginTop', v:null)
|
|
|
|
if marginTop is v:null
|
|
|
|
let row = (&lines - &cmdheight - 2) / 2
|
|
|
|
else
|
|
|
|
let row = marginTop < 2 ? 1 : min([marginTop, &columns - &cmdheight])
|
|
|
|
endif
|
|
|
|
let config = {
|
|
|
|
\ 'col': float2nr((&columns - width) / 2),
|
2022-05-19 10:14:37 -04:00
|
|
|
\ 'row': row - s:is_vim,
|
2022-05-18 13:29:28 -04:00
|
|
|
\ }
|
|
|
|
endif
|
|
|
|
return extend(config, {'relative': relative, 'width': width, 'height': 1})
|
|
|
|
endfunction
|
|
|
|
|
|
|
|
function! s:min_btns_width(buttons) abort
|
|
|
|
if empty(a:buttons)
|
|
|
|
return 0
|
|
|
|
endif
|
|
|
|
let minwidth = len(a:buttons)*3 - 1
|
|
|
|
for txt in a:buttons
|
|
|
|
let minwidth = minwidth + strdisplaywidth(txt)
|
|
|
|
endfor
|
|
|
|
return minwidth
|
|
|
|
endfunction
|
|
|
|
|
|
|
|
" Close windows that should auto hide
|
|
|
|
function! s:close_auto_hide_wins(...) abort
|
|
|
|
let winids = coc#float#get_float_win_list()
|
|
|
|
let except = get(a:, 1, 0)
|
|
|
|
for id in winids
|
|
|
|
if except && id == except
|
|
|
|
continue
|
|
|
|
endif
|
|
|
|
if coc#window#get_var(id, 'autohide', 0)
|
|
|
|
call coc#float#close(id)
|
|
|
|
endif
|
|
|
|
endfor
|
|
|
|
endfunction
|
|
|
|
|
|
|
|
function! s:create_loading_buf() abort
|
|
|
|
let bufnr = coc#float#create_buf(0)
|
|
|
|
call s:change_loading_buf(bufnr, 0)
|
|
|
|
return bufnr
|
|
|
|
endfunction
|
|
|
|
|
|
|
|
function! s:change_loading_buf(bufnr, idx) abort
|
|
|
|
if bufloaded(a:bufnr)
|
2022-05-19 10:14:37 -04:00
|
|
|
let target = getbufvar(a:bufnr, 'target_winid', v:null)
|
2022-05-18 13:29:28 -04:00
|
|
|
if !empty(target) && !coc#float#valid(target)
|
|
|
|
call coc#float#close(getbufvar(a:bufnr, 'popup'))
|
|
|
|
return
|
|
|
|
endif
|
|
|
|
let line = get(s:frames, a:idx, ' ')
|
|
|
|
call setbufline(a:bufnr, 1, line)
|
|
|
|
call coc#highlight#add_highlight(a:bufnr, -1, 'CocNotificationProgress', 0, 0, -1)
|
|
|
|
let idx = a:idx == len(s:frames) - 1 ? 0 : a:idx + 1
|
|
|
|
call timer_start(100, { -> s:change_loading_buf(a:bufnr, idx)})
|
|
|
|
endif
|
|
|
|
endfunction
|
2022-05-19 10:14:37 -04:00
|
|
|
|
|
|
|
function! s:place_sign(bufnr, line) abort
|
|
|
|
call sign_unplace(s:sign_group, { 'buffer': a:bufnr })
|
|
|
|
call sign_place(6, s:sign_group, 'CocCurrentLine', a:bufnr, {'lnum': a:line})
|
|
|
|
endfunction
|