api.vim 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678
  1. " ============================================================================
  2. " Description: Client api used by vim8
  3. " Author: Qiming Zhao <chemzqm@gmail.com>
  4. " Licence: Anti 996 licence
  5. " Last Modified: Jun 03, 2022
  6. " ============================================================================
  7. if has('nvim') | finish | endif
  8. scriptencoding utf-8
  9. let s:funcs = {}
  10. let s:prop_offset = get(g:, 'coc_text_prop_offset', 1000)
  11. let s:namespace_id = 1
  12. let s:namespace_cache = {}
  13. let s:max_src_id = 1000
  14. " bufnr => max textprop id
  15. let s:buffer_id = {}
  16. " srcId => list of types
  17. let s:id_types = {}
  18. " helper {{
  19. function! s:buf_line_count(bufnr) abort
  20. if bufnr('%') == a:bufnr
  21. return line('$')
  22. endif
  23. if exists('*getbufinfo')
  24. let info = getbufinfo(a:bufnr)
  25. if empty(info)
  26. return 0
  27. endif
  28. " vim 8.1 has getbufinfo but no linecount
  29. if has_key(info[0], 'linecount')
  30. return info[0]['linecount']
  31. endif
  32. endif
  33. if exists('*getbufline')
  34. let lines = getbufline(a:bufnr, 1, '$')
  35. return len(lines)
  36. endif
  37. let curr = bufnr('%')
  38. execute 'noa buffer '.a:bufnr
  39. let n = line('$')
  40. execute 'noa buffer '.curr
  41. return n
  42. endfunction
  43. function! s:execute(cmd)
  44. if a:cmd =~# '^echo'
  45. execute a:cmd
  46. else
  47. silent! execute a:cmd
  48. endif
  49. endfunction
  50. " }}"
  51. " nvim client methods {{
  52. function! s:funcs.set_current_dir(dir) abort
  53. execute 'cd '.a:dir
  54. endfunction
  55. function! s:funcs.set_var(name, value) abort
  56. execute 'let g:'.a:name.'= a:value'
  57. endfunction
  58. function! s:funcs.del_var(name) abort
  59. execute 'unlet g:'.a:name
  60. endfunction
  61. function! s:funcs.set_option(name, value) abort
  62. execute 'let &'.a:name.' = a:value'
  63. endfunction
  64. function! s:funcs.set_current_buf(bufnr) abort
  65. if !bufexists(a:bufnr) | return | endif
  66. execute 'buffer '.a:bufnr
  67. endfunction
  68. function! s:funcs.set_current_win(win_id) abort
  69. let [tabnr, winnr] = win_id2tabwin(a:win_id)
  70. if tabnr == 0 | return | endif
  71. execute 'normal! '.tabnr.'gt'
  72. execute winnr.' wincmd w'
  73. endfunction
  74. function! s:funcs.set_current_tabpage(tabnr) abort
  75. execute 'normal! '.a:tabnr.'gt'
  76. endfunction
  77. function! s:funcs.list_wins() abort
  78. return map(getwininfo(), 'v:val["winid"]')
  79. endfunction
  80. function s:inspect_type(v) abort
  81. let types = ['Number', 'String', 'Funcref', 'List', 'Dictionary', 'Float', 'Boolean', 'Null']
  82. return get(types, type(a:v), 'Unknown')
  83. endfunction
  84. function! s:funcs.call_atomic(calls)
  85. let res = []
  86. for i in range(len(a:calls))
  87. let [key, arglist] = a:calls[i]
  88. let name = key[5:]
  89. try
  90. call add(res, call(s:funcs[name], arglist))
  91. catch /.*/
  92. return [res, [i, "VimException(".s:inspect_type(v:exception).")", v:exception . ' on '.v:throwpoint]]
  93. endtry
  94. endfor
  95. return [res, v:null]
  96. endfunction
  97. function! s:funcs.set_client_info(...) abort
  98. endfunction
  99. function! s:funcs.subscribe(...) abort
  100. endfunction
  101. function! s:funcs.unsubscribe(...) abort
  102. endfunction
  103. function! s:funcs.call_function(method, args) abort
  104. return call(a:method, a:args)
  105. endfunction
  106. function! s:funcs.call_dict_function(dict, method, args) abort
  107. return call(a:method, a:args, a:dict)
  108. endfunction
  109. function! s:funcs.command(command) abort
  110. " command that could cause cursor vanish
  111. if a:command =~# '^echo' || a:command =~# '^redraw' || a:command =~# '^sign place'
  112. call timer_start(0, {-> s:execute(a:command)})
  113. else
  114. execute a:command
  115. let err = get(g:, 'errmsg', '')
  116. " get error from python script run.
  117. if !empty(err)
  118. unlet g:errmsg
  119. throw err
  120. endif
  121. endif
  122. endfunction
  123. function! s:funcs.eval(expr) abort
  124. return eval(a:expr)
  125. endfunction
  126. function! s:funcs.get_api_info()
  127. let names = coc#api#func_names()
  128. return [1, {'functions': map(names, '{"name": "nvim_".v:val}')}]
  129. endfunction
  130. function! s:funcs.list_bufs()
  131. return map(getbufinfo({'bufloaded': 1}), 'v:val["bufnr"]')
  132. endfunction
  133. function! s:funcs.feedkeys(keys, mode, escape_csi)
  134. call feedkeys(a:keys, a:mode)
  135. endfunction
  136. function! s:funcs.list_runtime_paths()
  137. return globpath(&runtimepath, '', 0, 1)
  138. endfunction
  139. function! s:funcs.command_output(cmd)
  140. return execute(a:cmd)
  141. endfunction
  142. function! s:funcs.get_current_line()
  143. return getline('.')
  144. endfunction
  145. function! s:funcs.set_current_line(line)
  146. call setline('.', a:line)
  147. endfunction
  148. function! s:funcs.del_current_line(line)
  149. execute 'normal! dd'
  150. endfunction
  151. function! s:funcs.get_var(var)
  152. return get(g:, a:var, v:null)
  153. endfunction
  154. function! s:funcs.get_vvar(var)
  155. return get(v:, a:var, v:null)
  156. endfunction
  157. function! s:funcs.get_option(name)
  158. return eval('&'.a:name)
  159. endfunction
  160. function! s:funcs.get_current_buf()
  161. return bufnr('%')
  162. endfunction
  163. function! s:funcs.get_current_win()
  164. return win_getid()
  165. endfunction
  166. function! s:funcs.get_current_tabpage()
  167. return tabpagenr()
  168. endfunction
  169. function! s:funcs.list_tabpages()
  170. return range(1, tabpagenr('$'))
  171. endfunction
  172. function! s:funcs.get_mode()
  173. return {'blocking': v:false, 'mode': mode()}
  174. endfunction
  175. function! s:funcs.strwidth(str)
  176. return strwidth(a:str)
  177. endfunction
  178. function! s:funcs.out_write(str)
  179. echon a:str
  180. call timer_start(0, {-> s:execute('redraw')})
  181. endfunction
  182. function! s:funcs.err_write(str)
  183. "echoerr a:str
  184. endfunction
  185. function! s:funcs.err_writeln(str)
  186. echohl ErrorMsg
  187. echom a:str
  188. echohl None
  189. call timer_start(0, {-> s:execute('redraw')})
  190. endfunction
  191. function! s:funcs.create_namespace(name) abort
  192. if empty(a:name)
  193. let id = s:namespace_id
  194. let s:namespace_id = s:namespace_id + 1
  195. return id
  196. endif
  197. let id = get(s:namespace_cache, a:name, 0)
  198. if !id
  199. let id = s:namespace_id
  200. let s:namespace_id = s:namespace_id + 1
  201. let s:namespace_cache[a:name] = id
  202. endif
  203. return id
  204. endfunction
  205. " }}
  206. " buffer methods {{
  207. function! s:funcs.buf_set_option(bufnr, name, val)
  208. let val = a:val
  209. if val is v:true
  210. let val = 1
  211. elseif val is v:false
  212. let val = 0
  213. endif
  214. return setbufvar(a:bufnr, '&'.a:name, val)
  215. endfunction
  216. function! s:funcs.buf_get_changedtick(bufnr)
  217. return getbufvar(a:bufnr, 'changedtick')
  218. endfunction
  219. function! s:funcs.buf_is_valid(bufnr)
  220. return bufloaded(a:bufnr) ? v:true : v:false
  221. endfunction
  222. function! s:funcs.buf_get_mark(bufnr, name)
  223. let nr = bufnr('%')
  224. if a:bufnr != 0 || a:bufnr != nr
  225. throw 'buf_get_mark support current buffer only'
  226. endif
  227. return [line("'" . a:name), col("'" . a:name)]
  228. endfunction
  229. function! s:funcs.buf_add_highlight(bufnr, srcId, hlGroup, line, colStart, colEnd, ...) abort
  230. if !has('patch-8.1.1719')
  231. return
  232. endif
  233. if a:srcId == 0
  234. let srcId = s:max_src_id + 1
  235. let s:max_src_id = srcId
  236. else
  237. let srcId = a:srcId
  238. endif
  239. let bufnr = a:bufnr == 0 ? bufnr('%') : a:bufnr
  240. let type = a:hlGroup.'_'.srcId
  241. let types = get(s:id_types, srcId, [])
  242. if index(types, type) == -1
  243. call add(types, type)
  244. let s:id_types[srcId] = types
  245. call prop_type_add(type, extend({'highlight': a:hlGroup}, get(a:, 1, {})))
  246. endif
  247. let end = a:colEnd == -1 ? strlen(getbufline(bufnr, a:line + 1)[0]) + 1 : a:colEnd + 1
  248. if end < a:colStart + 1
  249. return
  250. endif
  251. let id = s:generate_id(a:bufnr)
  252. try
  253. call prop_add(a:line + 1, a:colStart + 1, {'bufnr': bufnr, 'type': type, 'id': id, 'end_col': end})
  254. catch /^Vim\%((\a\+)\)\=:E967/
  255. " ignore 967
  256. endtry
  257. if a:srcId == 0
  258. " return generated srcId
  259. return srcId
  260. endif
  261. endfunction
  262. function! s:funcs.buf_clear_namespace(bufnr, srcId, startLine, endLine) abort
  263. if !has('patch-8.1.1719')
  264. return
  265. endif
  266. let bufnr = a:bufnr == 0 ? bufnr('%') : a:bufnr
  267. let start = a:startLine + 1
  268. let end = a:endLine == -1 ? len(getbufline(bufnr, 1, '$')) : a:endLine
  269. if a:srcId == -1
  270. if has_key(s:buffer_id, a:bufnr)
  271. unlet s:buffer_id[a:bufnr]
  272. endif
  273. call prop_clear(start, end, {'bufnr' : bufnr})
  274. else
  275. for type in get(s:id_types, a:srcId, [])
  276. try
  277. call prop_remove({'bufnr': bufnr, 'all': 1, 'type': type}, start, end)
  278. catch /^Vim\%((\a\+)\)\=:E968/
  279. " ignore 968
  280. endtry
  281. endfor
  282. endif
  283. endfunction
  284. function! s:funcs.buf_line_count(bufnr) abort
  285. return s:buf_line_count(a:bufnr)
  286. endfunction
  287. function! s:funcs.buf_attach(...)
  288. " not supported
  289. return 1
  290. endfunction
  291. function! s:funcs.buf_detach()
  292. " not supported
  293. return 1
  294. endfunction
  295. function! s:funcs.buf_get_lines(bufnr, start, end, strict) abort
  296. let lines = getbufline(a:bufnr, 1, '$')
  297. let start = a:start < 0 ? a:start + 1 : a:start
  298. let end = a:end < 0 ? a:end + 1 : a:end
  299. if a:strict && end > len(lines)
  300. throw 'line number out of range: '. end
  301. endif
  302. return lines[start : end - 1]
  303. endfunction
  304. function! s:funcs.buf_set_lines(bufnr, start, end, strict, ...) abort
  305. let bufnr = a:bufnr == 0 ? bufnr('%') : a:bufnr
  306. if !bufloaded(bufnr)
  307. return
  308. endif
  309. let replacement = get(a:, 1, [])
  310. let lineCount = s:buf_line_count(bufnr)
  311. let startLnum = a:start >= 0 ? a:start + 1 : lineCount + a:start + 2
  312. let end = a:end >= 0 ? a:end : lineCount + a:end + 1
  313. if end == lineCount + 1
  314. let end = lineCount
  315. endif
  316. let delCount = end - (startLnum - 1)
  317. let changeBuffer = 0
  318. let curr = bufnr('%')
  319. if bufnr != curr && !exists('*setbufline')
  320. let changeBuffer = 1
  321. exe 'buffer '.bufnr
  322. endif
  323. if bufnr == curr || changeBuffer
  324. " replace
  325. let storeView = winsaveview()
  326. if delCount == len(replacement)
  327. call setline(startLnum, replacement)
  328. else
  329. if len(replacement)
  330. call append(startLnum - 1, replacement)
  331. endif
  332. if delCount
  333. let start = startLnum + len(replacement)
  334. let saved_reg = @"
  335. let system_reg = @*
  336. if exists('*deletebufline')
  337. silent call deletebufline(curr, start, start + delCount - 1)
  338. else
  339. silent execute start . ','.(start + delCount - 1).'d'
  340. endif
  341. let @" = saved_reg
  342. let @* = system_reg
  343. endif
  344. endif
  345. call winrestview(storeView)
  346. if changeBuffer
  347. exe 'buffer '.curr
  348. endif
  349. elseif exists('*setbufline')
  350. " replace
  351. if delCount == len(replacement)
  352. " 8.0.1039
  353. call setbufline(bufnr, startLnum, replacement)
  354. else
  355. if len(replacement)
  356. " 8.10037
  357. call appendbufline(bufnr, startLnum - 1, replacement)
  358. endif
  359. if delCount
  360. let start = startLnum + len(replacement)
  361. let saved_reg = @"
  362. let system_reg = @*
  363. "8.1.0039
  364. silent call deletebufline(bufnr, start, start + delCount - 1)
  365. let @" = saved_reg
  366. let @* = system_reg
  367. endif
  368. endif
  369. endif
  370. endfunction
  371. function! s:funcs.buf_set_name(bufnr, name) abort
  372. let nr = bufnr('%')
  373. if a:bufnr != nr
  374. throw 'buf_set_name support current buffer only'
  375. else
  376. execute '0f'
  377. execute 'file '.fnameescape(a:name)
  378. endif
  379. endfunction
  380. function! s:funcs.buf_get_var(bufnr, name)
  381. return getbufvar(a:bufnr, a:name)
  382. endfunction
  383. function! s:funcs.buf_set_var(bufnr, name, val)
  384. if !bufloaded(a:bufnr) | return | endif
  385. call setbufvar(a:bufnr, a:name, a:val)
  386. endfunction
  387. function! s:funcs.buf_del_var(bufnr, name)
  388. if bufnr == bufnr('%')
  389. execute 'unlet! b:'.a:name
  390. elseif exists('*win_execute')
  391. let winid = coc#compat#buf_win_id(a:bufnr)
  392. if winid != -1
  393. call win_execute(winid, 'unlet! b:'.a:name)
  394. endif
  395. endif
  396. endfunction
  397. function! s:funcs.buf_get_option(bufnr, name)
  398. return getbufvar(a:bufnr, '&'.a:name)
  399. endfunction
  400. function! s:funcs.buf_get_name(bufnr)
  401. return bufname(a:bufnr)
  402. endfunction
  403. " }}
  404. " window methods {{
  405. function! s:funcs.win_get_buf(winid)
  406. return winbufnr(a:winid)
  407. endfunction
  408. function! s:funcs.win_get_position(win_id) abort
  409. let [row, col] = win_screenpos(a:win_id)
  410. if row == 0 && col == 0
  411. throw 'Invalid window '.a:win_id
  412. endif
  413. return [row - 1, col - 1]
  414. endfunction
  415. function! s:funcs.win_get_height(win_id) abort
  416. return winheight(a:win_id)
  417. endfunction
  418. function! s:funcs.win_get_width(win_id) abort
  419. return winwidth(a:win_id)
  420. endfunction
  421. if exists('*win_execute')
  422. function! s:win_execute(win_id, cmd, ...) abort
  423. let ref = get(a:000, 0, v:null)
  424. let cmd = ref is v:null ? a:cmd : 'let ref["out"] = ' . a:cmd
  425. call win_execute(a:win_id, cmd)
  426. endfunction
  427. else
  428. function! s:win_execute(win_id, cmd, ...) abort
  429. let ref = get(a:000, 0, v:null)
  430. let cmd = ref is v:null ? a:cmd : 'let ref["out"] = ' . a:cmd
  431. let winid = win_getid()
  432. if winid == a:win_id
  433. execute cmd
  434. else
  435. let goto_status = win_gotoid(a:win_id)
  436. if !goto_status
  437. return
  438. endif
  439. execute cmd
  440. call win_gotoid(winid)
  441. endif
  442. endfunction
  443. endif
  444. function! s:get_tabnr(winid) abort
  445. let ref = {}
  446. call s:win_execute(a:winid, 'tabpagenr()', ref)
  447. return get(ref, 'out', 0)
  448. endfunction
  449. function! s:funcs.win_get_cursor(win_id) abort
  450. let ref = {}
  451. call s:win_execute(a:win_id, "[line('.'), col('.')-1]", ref)
  452. return get(ref, 'out', 0)
  453. endfunction
  454. function! s:funcs.win_get_var(win_id, name, ...) abort
  455. let tabnr = s:get_tabnr(a:win_id)
  456. if tabnr
  457. return gettabwinvar(tabnr, a:win_id, a:name, get(a:, 1, v:null))
  458. endif
  459. throw 'window '.a:win_id. ' not a visible window'
  460. endfunction
  461. function! s:funcs.win_set_width(win_id, width) abort
  462. call s:win_execute(a:win_id, 'vertical resize '.a:width)
  463. endfunction
  464. function! s:funcs.win_set_buf(win_id, buf_id) abort
  465. call s:win_execute(a:win_id, 'buffer '.a:buf_id)
  466. endfunction
  467. function! s:funcs.win_get_option(win_id, name) abort
  468. let tabnr = s:get_tabnr(a:win_id)
  469. if tabnr
  470. return gettabwinvar(tabnr, a:win_id, '&'.a:name)
  471. endif
  472. throw 'window '.a:win_id. ' not a valid window'
  473. endfunction
  474. function! s:funcs.win_set_height(win_id, height) abort
  475. return s:win_execute(a:win_id, 'resize '.a:height)
  476. endfunction
  477. function! s:funcs.win_set_option(win_id, name, value) abort
  478. let val = a:value
  479. if val is v:true
  480. let val = 1
  481. elseif val is v:false
  482. let val = 0
  483. endif
  484. let tabnr = s:get_tabnr(a:win_id)
  485. if tabnr
  486. call settabwinvar(tabnr, a:win_id, '&'.a:name, val)
  487. else
  488. throw 'window '.a:win_id. ' not a valid window'
  489. endif
  490. endfunction
  491. function! s:funcs.win_set_var(win_id, name, value) abort
  492. let tabnr = s:get_tabnr(a:win_id)
  493. if tabnr
  494. call settabwinvar(tabnr, a:win_id, a:name, a:value)
  495. else
  496. throw "Invalid window id ".a:win_id
  497. endif
  498. endfunction
  499. function! s:funcs.win_del_var(win_id, name) abort
  500. call s:win_execute(a:win_id, 'unlet! w:'.a:name)
  501. endfunction
  502. function! s:funcs.win_is_valid(win_id) abort
  503. let info = getwininfo(a:win_id)
  504. return empty(info) ? v:false : v:true
  505. endfunction
  506. function! s:funcs.win_get_number(win_id) abort
  507. let info = getwininfo(a:win_id)
  508. if empty(info)
  509. throw 'Invalid window id '.a:win_id
  510. endif
  511. return info[0]['winnr']
  512. endfunction
  513. function! s:funcs.win_set_cursor(win_id, pos) abort
  514. let [line, col] = a:pos
  515. call s:win_execute(a:win_id, 'call cursor('.line.','.(col + 1).')')
  516. endfunction
  517. function! s:funcs.win_close(win_id, ...) abort
  518. let force = get(a:, 1, 0)
  519. call s:win_execute(a:win_id, 'close'.(force ? '!' : ''))
  520. endfunction
  521. function! s:funcs.win_get_tabpage(win_id) abort
  522. let tabnr = s:get_tabnr(a:win_id)
  523. if !tabnr
  524. throw 'Invalid window id '.a:win_id
  525. endif
  526. return tabnr
  527. endfunction
  528. " }}
  529. " tabpage methods {{
  530. function! s:funcs.tabpage_get_number(id)
  531. return a:id
  532. endfunction
  533. function! s:funcs.tabpage_list_wins(tabnr)
  534. let info = getwininfo()
  535. return map(filter(info, 'v:val["tabnr"] == a:tabnr'), 'v:val["winid"]')
  536. endfunction
  537. function! s:funcs.tabpage_get_var(tabnr, name)
  538. return gettabvar(a:tabnr, a:name, v:null)
  539. endfunction
  540. function! s:funcs.tabpage_set_var(tabnr, name, value)
  541. call settabvar(a:tabnr, a:name, a:value)
  542. endfunction
  543. function! s:funcs.tabpage_del_var(tabnr, name)
  544. call settabvar(a:tabnr, a:name, v:null)
  545. endfunction
  546. function! s:funcs.tabpage_is_valid(tabnr)
  547. let max = tabpagenr('$')
  548. return a:tabnr <= max
  549. endfunction
  550. function! s:funcs.tabpage_get_win(tabnr)
  551. let wnr = tabpagewinnr(a:tabnr)
  552. return win_getid(wnr, a:tabnr)
  553. endfunction
  554. function! s:generate_id(bufnr) abort
  555. let max = get(s:buffer_id, a:bufnr, s:prop_offset)
  556. let id = max + 1
  557. let s:buffer_id[a:bufnr] = id
  558. return id
  559. endfunction
  560. " }}
  561. function! coc#api#get_types(srcId) abort
  562. return get(s:id_types, a:srcId, [])
  563. endfunction
  564. function! coc#api#func_names() abort
  565. return keys(s:funcs)
  566. endfunction
  567. function! coc#api#call(method, args) abort
  568. let err = v:null
  569. let res = v:null
  570. try
  571. let res = call(s:funcs[a:method], a:args)
  572. catch /.*/
  573. let err = v:exception .' on api "'.a:method.'" '.json_encode(a:args)
  574. endtry
  575. return [err, res]
  576. endfunction
  577. function! coc#api#exec(method, args) abort
  578. return call(s:funcs[a:method], a:args)
  579. endfunction
  580. function! coc#api#notify(method, args) abort
  581. try
  582. call call(s:funcs[a:method], a:args)
  583. catch /.*/
  584. let g:b = v:exception
  585. call coc#rpc#notify('nvim_error_event', [0, v:exception.' on api "'.a:method.'" '.json_encode(a:args)])
  586. endtry
  587. endfunction
  588. " vim: set sw=2 ts=2 sts=2 et tw=78 foldmarker={{,}} foldmethod=marker foldlevel=0: