123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446 |
- let s:is_vim = !has('nvim')
- let s:is_win = has('win32') || has('win64')
- let s:is_mac = has('mac')
- let s:sign_api = exists('*sign_getplaced') && exists('*sign_place')
- let s:sign_groups = []
- " Check <Tab> and <CR>
- function! coc#ui#check_pum_keymappings() abort
- let keys = []
- for key in ['<cr>', '<tab>']
- if maparg(key, 'i') =~# 'pumvisible()'
- call add(keys, key)
- endif
- endfor
- if len(keys)
- let lines = [
- \ 'coc.nvim switched to custom popup menu from 0.0.82',
- \ 'you have to change key-mappings for '.join(keys, ', ').' to make them work.',
- \ 'see :h coc-completion-example']
- call coc#notify#create(lines, {
- \ 'borderhighlight': 'CocInfoSign',
- \ 'timeout': 30000,
- \ 'kind': 'warning',
- \ })
- endif
- endfunction
- function! coc#ui#quickpick(title, items, cb) abort
- if exists('*popup_menu')
- function! s:QuickpickHandler(id, result) closure
- call a:cb(v:null, a:result)
- endfunction
- function! s:QuickpickFilter(id, key) closure
- for i in range(1, len(a:items))
- if a:key == string(i)
- call popup_close(a:id, i)
- return 1
- endif
- endfor
- " No shortcut, pass to generic filter
- return popup_filter_menu(a:id, a:key)
- endfunction
- try
- call popup_menu(a:items, {
- \ 'title': a:title,
- \ 'filter': function('s:QuickpickFilter'),
- \ 'callback': function('s:QuickpickHandler'),
- \ })
- redraw
- catch /.*/
- call a:cb(v:exception)
- endtry
- else
- let res = inputlist([a:title] + a:items)
- call a:cb(v:null, res)
- endif
- endfunction
- " cmd, cwd
- function! coc#ui#open_terminal(opts) abort
- if s:is_vim && !exists('*term_start')
- echohl WarningMsg | echon "Your vim doesn't have terminal support!" | echohl None
- return
- endif
- if get(a:opts, 'position', 'bottom') ==# 'bottom'
- let p = '5new'
- else
- let p = 'vnew'
- endif
- execute 'belowright '.p.' +setl\ buftype=nofile '
- setl buftype=nofile
- setl winfixheight
- setl norelativenumber
- setl nonumber
- setl bufhidden=wipe
- if exists('#User#CocTerminalOpen')
- exe 'doautocmd <nomodeline> User CocTerminalOpen'
- endif
- let cmd = get(a:opts, 'cmd', '')
- let autoclose = get(a:opts, 'autoclose', 1)
- if empty(cmd)
- throw 'command required!'
- endif
- let cwd = get(a:opts, 'cwd', getcwd())
- let keepfocus = get(a:opts, 'keepfocus', 0)
- let bufnr = bufnr('%')
- let Callback = get(a:opts, 'Callback', v:null)
- function! s:OnExit(status) closure
- let content = join(getbufline(bufnr, 1, '$'), "\n")
- if a:status == 0 && autoclose == 1
- execute 'silent! bd! '.bufnr
- endif
- if !empty(Callback)
- call call(Callback, [a:status, bufnr, content])
- endif
- endfunction
- if has('nvim')
- call termopen(cmd, {
- \ 'cwd': cwd,
- \ 'on_exit': {job, status -> s:OnExit(status)},
- \})
- else
- if s:is_win
- let cmd = 'cmd.exe /C "'.cmd.'"'
- endif
- call term_start(cmd, {
- \ 'cwd': cwd,
- \ 'exit_cb': {job, status -> s:OnExit(status)},
- \ 'curwin': 1,
- \})
- endif
- if keepfocus
- wincmd p
- endif
- return bufnr
- endfunction
- " run command in terminal
- function! coc#ui#run_terminal(opts, cb)
- let cmd = get(a:opts, 'cmd', '')
- if empty(cmd)
- return a:cb('command required for terminal')
- endif
- let opts = {
- \ 'cmd': cmd,
- \ 'cwd': get(a:opts, 'cwd', getcwd()),
- \ 'keepfocus': get(a:opts, 'keepfocus', 0),
- \ 'Callback': {status, bufnr, content -> a:cb(v:null, {'success': status == 0 ? v:true : v:false, 'bufnr': bufnr, 'content': content})}
- \}
- call coc#ui#open_terminal(opts)
- endfunction
- function! coc#ui#echo_hover(msg)
- echohl MoreMsg
- echo a:msg
- echohl None
- let g:coc_last_hover_message = a:msg
- endfunction
- function! coc#ui#echo_messages(hl, msgs)
- if a:hl !~# 'Error' && (mode() !~# '\v^(i|n)$')
- return
- endif
- let msgs = filter(copy(a:msgs), '!empty(v:val)')
- if empty(msgs)
- return
- endif
- execute 'echohl '.a:hl
- echom a:msgs[0]
- redraw
- echo join(msgs, "\n")
- echohl None
- endfunction
- function! coc#ui#preview_info(lines, filetype, ...) abort
- pclose
- keepalt new +setlocal\ previewwindow|setlocal\ buftype=nofile|setlocal\ noswapfile|setlocal\ wrap [Document]
- setl bufhidden=wipe
- setl nobuflisted
- setl nospell
- exe 'setl filetype='.a:filetype
- setl conceallevel=0
- setl nofoldenable
- for command in a:000
- execute command
- endfor
- call append(0, a:lines)
- exe "normal! z" . len(a:lines) . "\<cr>"
- exe "normal! gg"
- wincmd p
- endfunction
- function! coc#ui#open_files(files)
- let bufnrs = []
- " added on latest vim8
- if exists('*bufadd') && exists('*bufload')
- for file in a:files
- let file = fnamemodify(file, ':.')
- if bufloaded(file)
- call add(bufnrs, bufnr(file))
- else
- let bufnr = bufadd(file)
- call bufload(file)
- call add(bufnrs, bufnr)
- call setbufvar(bufnr, '&buflisted', 1)
- endif
- endfor
- else
- noa keepalt 1new +setl\ bufhidden=wipe
- for file in a:files
- let file = fnamemodify(file, ':.')
- execute 'noa edit +setl\ bufhidden=hide '.fnameescape(file)
- if &filetype ==# ''
- filetype detect
- endif
- call add(bufnrs, bufnr('%'))
- endfor
- noa close
- endif
- doautocmd BufEnter
- return bufnrs
- endfunction
- function! coc#ui#echo_lines(lines)
- echo join(a:lines, "\n")
- endfunction
- function! coc#ui#echo_signatures(signatures) abort
- if pumvisible() | return | endif
- echo ""
- for i in range(len(a:signatures))
- call s:echo_signature(a:signatures[i])
- if i != len(a:signatures) - 1
- echon "\n"
- endif
- endfor
- endfunction
- function! s:echo_signature(parts)
- for part in a:parts
- let hl = get(part, 'type', 'Normal')
- let text = get(part, 'text', '')
- if !empty(text)
- execute 'echohl '.hl
- execute "echon '".substitute(text, "'", "''", 'g')."'"
- echohl None
- endif
- endfor
- endfunction
- function! coc#ui#iterm_open(dir)
- return s:osascript(
- \ 'if application "iTerm2" is not running',
- \ 'error',
- \ 'end if') && s:osascript(
- \ 'tell application "iTerm2"',
- \ 'tell current window',
- \ 'create tab with default profile',
- \ 'tell current session',
- \ 'write text "cd ' . a:dir . '"',
- \ 'write text "clear"',
- \ 'activate',
- \ 'end tell',
- \ 'end tell',
- \ 'end tell')
- endfunction
- function! s:osascript(...) abort
- let args = join(map(copy(a:000), '" -e ".shellescape(v:val)'), '')
- call s:system('osascript'. args)
- return !v:shell_error
- endfunction
- function! s:system(cmd)
- let output = system(a:cmd)
- if v:shell_error && output !=# ""
- echohl Error | echom output | echohl None
- return
- endif
- return output
- endfunction
- function! coc#ui#set_lines(bufnr, changedtick, original, replacement, start, end, changes, cursor, col) abort
- if !bufloaded(a:bufnr)
- return
- endif
- let delta = 0
- if !empty(a:col)
- let delta = col('.') - a:col
- endif
- if getbufvar(a:bufnr, 'changedtick') > a:changedtick && bufnr('%') == a:bufnr
- " try apply current line change
- let lnum = line('.')
- " change for current line
- if a:end - a:start == 1 && a:end == lnum && len(a:replacement) == 1
- let idx = a:start - lnum + 1
- let previous = get(a:original, idx, 0)
- if type(previous) == 1
- let content = getline('.')
- if previous !=# content
- let diff = coc#string#diff(content, previous, col('.'))
- let changed = get(a:replacement, idx, 0)
- if type(changed) == 1 && strcharpart(previous, 0, diff['end']) ==# strcharpart(changed, 0, diff['end'])
- let applied = coc#string#apply(changed, diff)
- let replacement = copy(a:replacement)
- let replacement[idx] = applied
- call coc#compat#buf_set_lines(a:bufnr, a:start, a:end, replacement)
- return
- endif
- endif
- endif
- endif
- endif
- if exists('*nvim_buf_set_text') && !empty(a:changes)
- for item in reverse(copy(a:changes))
- call nvim_buf_set_text(a:bufnr, item[1], item[2], item[3], item[4], item[0])
- endfor
- else
- call coc#compat#buf_set_lines(a:bufnr, a:start, a:end, a:replacement)
- endif
- if !empty(a:cursor)
- call cursor(a:cursor[0], a:cursor[1] + delta)
- endif
- endfunction
- function! coc#ui#change_lines(bufnr, list) abort
- if !bufloaded(a:bufnr) | return v:null | endif
- undojoin
- if exists('*setbufline')
- for [lnum, line] in a:list
- call setbufline(a:bufnr, lnum + 1, line)
- endfor
- elseif a:bufnr == bufnr('%')
- for [lnum, line] in a:list
- call setline(lnum + 1, line)
- endfor
- else
- let bufnr = bufnr('%')
- exe 'noa buffer '.a:bufnr
- for [lnum, line] in a:list
- call setline(lnum + 1, line)
- endfor
- exe 'noa buffer '.bufnr
- endif
- endfunction
- function! coc#ui#open_url(url)
- if has('mac') && executable('open')
- call system('open '.a:url)
- return
- endif
- if executable('xdg-open')
- call system('xdg-open '.a:url)
- return
- endif
- call system('cmd /c start "" /b '. substitute(a:url, '&', '^&', 'g'))
- if v:shell_error
- echohl Error | echom 'Failed to open '.a:url | echohl None
- return
- endif
- endfunction
- function! coc#ui#rename_file(oldPath, newPath, write) abort
- let bufnr = bufnr(a:oldPath)
- if bufnr == -1
- throw 'Unable to get bufnr of '.a:oldPath
- endif
- if a:oldPath =~? a:newPath && (s:is_mac || s:is_win)
- return coc#ui#safe_rename(bufnr, a:oldPath, a:newPath, a:write)
- endif
- if bufloaded(a:newPath)
- execute 'silent bdelete! '.bufnr(a:newPath)
- endif
- let current = bufnr == bufnr('%')
- let bufname = fnamemodify(a:newPath, ":~:.")
- let filepath = fnamemodify(bufname(bufnr), '%:p')
- let winid = coc#compat#buf_win_id(bufnr)
- let curr = -1
- if winid == -1
- let curr = win_getid()
- let file = fnamemodify(bufname(bufnr), ':.')
- execute 'keepalt tab drop '.fnameescape(bufname(bufnr))
- let winid = win_getid()
- endif
- call coc#compat#execute(winid, 'keepalt file '.fnameescape(bufname), 'silent')
- call coc#compat#execute(winid, 'doautocmd BufEnter')
- if a:write
- call coc#compat#execute(winid, 'noa write!', 'silent')
- call delete(filepath, '')
- endif
- if curr != -1
- call win_gotoid(curr)
- endif
- return bufnr
- endfunction
- " System is case in sensitive and newPath have different case.
- function! coc#ui#safe_rename(bufnr, oldPath, newPath, write) abort
- let winid = win_getid()
- let lines = getbufline(a:bufnr, 1, '$')
- execute 'keepalt tab drop '.fnameescape(fnamemodify(a:oldPath, ':.'))
- let view = winsaveview()
- execute 'keepalt bwipeout! '.a:bufnr
- if a:write
- call delete(a:oldPath, '')
- endif
- execute 'keepalt edit '.fnameescape(fnamemodify(a:newPath, ':~:.'))
- let bufnr = bufnr('%')
- call coc#compat#buf_set_lines(bufnr, 0, -1, lines)
- if a:write
- execute 'noa write'
- endif
- call winrestview(view)
- call win_gotoid(winid)
- return bufnr
- endfunction
- function! coc#ui#sign_unplace() abort
- if exists('*sign_unplace')
- for group in s:sign_groups
- call sign_unplace(group)
- endfor
- endif
- endfunction
- function! coc#ui#update_signs(bufnr, group, signs) abort
- if !s:sign_api || !bufloaded(a:bufnr)
- return
- endif
- if len(a:signs)
- call add(s:sign_groups, a:group)
- endif
- let current = get(get(sign_getplaced(a:bufnr, {'group': a:group}), 0, {}), 'signs', [])
- let exists = []
- let unplaceList = []
- for item in current
- let index = 0
- let placed = 0
- for def in a:signs
- if def['name'] ==# item['name'] && def['lnum'] == item['lnum']
- let placed = 1
- call add(exists, index)
- break
- endif
- let index = index + 1
- endfor
- if !placed
- call add(unplaceList, item['id'])
- endif
- endfor
- for idx in range(0, len(a:signs) - 1)
- if index(exists, idx) == -1
- let def = a:signs[idx]
- let opts = {'lnum': def['lnum']}
- if has_key(def, 'priority')
- let opts['priority'] = def['priority']
- endif
- call sign_place(0, a:group, def['name'], a:bufnr, opts)
- endif
- endfor
- for id in unplaceList
- call sign_unplace(a:group, {'buffer': a:bufnr, 'id': id})
- endfor
- endfunction
|