PageRenderTime 1552ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/Plugins/Shell/Plugin/autoload/vimshell/interactive.vim

https://bitbucket.org/WscriChy/vim-configuration
Vim Script | 899 lines | 685 code | 140 blank | 74 comment | 222 complexity | 42aeab9aea2d44d84447797b9e6927b9 MD5 | raw file
  1. "=============================================================================
  2. " FILE: interactive.vim
  3. " AUTHOR: Shougo Matsushita <Shougo.Matsu@gmail.com>
  4. " License: MIT license {{{
  5. " Permission is hereby granted, free of charge, to any person obtaining
  6. " a copy of this software and associated documentation files (the
  7. " "Software"), to deal in the Software without restriction, including
  8. " without limitation the rights to use, copy, modify, merge, publish,
  9. " distribute, sublicense, and/or sell copies of the Software, and to
  10. " permit persons to whom the Software is furnished to do so, subject to
  11. " the following conditions:
  12. "
  13. " The above copyright notice and this permission notice shall be included
  14. " in all copies or substantial portions of the Software.
  15. "
  16. " THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  17. " OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  18. " MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  19. " IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
  20. " CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  21. " TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  22. " SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  23. " }}}
  24. "=============================================================================
  25. " Utility functions.
  26. let s:character_regex = ''
  27. let s:update_time_save = &updatetime
  28. augroup vimshell
  29. autocmd VimLeave * call s:vimleave()
  30. autocmd CursorMovedI *
  31. \ call s:check_all_output(0)
  32. autocmd CursorHold,CursorHoldI *
  33. \ call s:check_all_output(1)
  34. autocmd BufWinEnter,WinEnter *
  35. \ call s:winenter()
  36. autocmd BufWinLeave,WinLeave *
  37. \ call s:winleave(expand('<afile>'))
  38. autocmd VimResized *
  39. \ call s:resize()
  40. augroup END
  41. let s:is_insert_char_pre = v:version > 703
  42. \ || v:version == 703 && has('patch418')
  43. if s:is_insert_char_pre
  44. autocmd vimshell InsertCharPre *
  45. \ call s:enable_auto_complete()
  46. endif
  47. call vimshell#commands#iexe#define()
  48. " Dummy.
  49. function! vimshell#interactive#init() "{{{
  50. endfunction"}}}
  51. function! vimshell#interactive#get_cur_text() "{{{
  52. if !exists('b:interactive')
  53. return vimshell#get_cur_line()
  54. endif
  55. " Get cursor text without prompt.
  56. return s:chomp_prompt(vimshell#get_cur_line(), line('.'), b:interactive)
  57. endfunction"}}}
  58. function! vimshell#interactive#get_cur_line(line, ...) "{{{
  59. " Get cursor text without prompt.
  60. let interactive = a:0 > 0 ? a:1 : b:interactive
  61. return s:chomp_prompt(getline(a:line), a:line, interactive)
  62. endfunction"}}}
  63. function! vimshell#interactive#get_prompt(...) "{{{
  64. let line = get(a:000, 0, line('.'))
  65. let interactive = get(a:000, 1,
  66. \ exists('b:interactive') ? b:interactive : {})
  67. if empty(interactive)
  68. return ''
  69. endif
  70. " Get prompt line.
  71. return get(get(b:interactive, 'prompt_history', {}), line, '')
  72. endfunction"}}}
  73. function! s:chomp_prompt(cur_text, line, interactive) "{{{
  74. return a:cur_text[len(vimshell#get_prompt(a:line, a:interactive)): ]
  75. endfunction"}}}
  76. function! vimshell#interactive#execute_pty_inout(is_insert) "{{{
  77. let in = vimshell#interactive#get_cur_line(line('.'))
  78. call vimshell#history#append(in)
  79. if in !~ "\<C-d>$"
  80. let in .= vimshell#util#is_windows() ? "\<LF>" : "\<CR>"
  81. endif
  82. let b:interactive.prompt_nr = line('.')
  83. call s:iexe_send_string(in, a:is_insert, line('.'))
  84. endfunction"}}}
  85. function! vimshell#interactive#iexe_send_string(string, is_insert, ...) "{{{
  86. let linenr = get(a:000, 0, line('$'))
  87. call s:iexe_send_string(a:string, 1, linenr)
  88. endfunction"}}}
  89. function! vimshell#interactive#send_input() "{{{
  90. let input = input('Please input send string: ', vimshell#interactive#get_cur_line(line('.')))
  91. call vimshell#helpers#imdisable()
  92. call setline('.', vimshell#interactive#get_prompt() . ' ')
  93. call cursor(0, col('$')-1)
  94. call vimshell#interactive#iexe_send_string(input, 1)
  95. endfunction"}}}
  96. function! vimshell#interactive#send_char(char) "{{{
  97. if !b:interactive.process.is_valid
  98. return
  99. endif
  100. setlocal modifiable
  101. if type(a:char) != type([])
  102. let char = nr2char(a:char)
  103. else
  104. let char = ''
  105. for c in a:char
  106. let char .= nr2char(c)
  107. endfor
  108. endif
  109. call b:interactive.process.stdin.write(char)
  110. call vimshell#interactive#execute_process_out(1)
  111. endfunction"}}}
  112. function! vimshell#interactive#send_region(line1, line2, string) "{{{
  113. let string = a:string
  114. if string == ''
  115. let string = join(getline(a:line1, a:line2), "\<LF>")
  116. endif
  117. let string .= "\<LF>"
  118. return vimshell#interactive#send(string)
  119. endfunction"}}}
  120. function! vimshell#interactive#send(expr) "{{{
  121. if !exists('t:vimshell')
  122. call vimshell#init#tab_variable()
  123. endif
  124. if vimshell#util#is_cmdwin()
  125. return
  126. endif
  127. let last_interactive_bufnr = t:vimshell.last_interactive_bufnr
  128. if last_interactive_bufnr <= 0
  129. let command =
  130. \ has_key(g:vimshell_interactive_interpreter_commands, &filetype) ?
  131. \ g:vimshell_interactive_interpreter_commands[&filetype] :
  132. \ input('Please input interpreter command : ',
  133. \ '', 'customlist,vimshell#helpers#vimshell_execute_complete')
  134. execute 'VimShellInteractive' command
  135. let last_interactive_bufnr = t:vimshell.last_interactive_bufnr
  136. if last_interactive_bufnr <= 0
  137. " Error.
  138. return
  139. endif
  140. endif
  141. let winnr = bufwinnr(last_interactive_bufnr)
  142. if winnr <= 0
  143. " Open buffer.
  144. let [new_pos, old_pos] = vimshell#helpers#split(
  145. \ g:vimshell_split_command)
  146. execute 'buffer' last_interactive_bufnr
  147. else
  148. let [new_pos, old_pos] = vimshell#helpers#split('')
  149. execute winnr 'wincmd w'
  150. endif
  151. let [new_pos[2], new_pos[3]] = [bufnr('%'), getpos('.')]
  152. " Check alternate buffer.
  153. let interactive = getbufvar(last_interactive_bufnr,
  154. \ 'interactive')
  155. if type(interactive) != type({})
  156. return
  157. endif
  158. let type = interactive.type
  159. if type !=# 'interactive' && type !=# 'terminal'
  160. \ && type !=# 'vimshell'
  161. return
  162. endif
  163. call cursor(line('$'), 0)
  164. call cursor(0, col('$'))
  165. let list = type(a:expr) == type('') ?
  166. \ [a:expr] : a:expr
  167. " Send string.
  168. if type ==# 'vimshell'
  169. let string = join(list, '; ')
  170. if !empty(b:vimshell.continuation)
  171. if !vimshell#util#input_yesno(
  172. \ 'The process is running. Kill it?')
  173. return
  174. endif
  175. " Kill process.
  176. call vimshell#interactive#hang_up(bufname('%'))
  177. let context = {
  178. \ 'has_head_spaces' : 0,
  179. \ 'is_interactive' : 1,
  180. \ 'is_insert' : 0,
  181. \ 'fd' : { 'stdin' : '', 'stdout' : '', 'stderr' : '' },
  182. \ }
  183. call vimshell#print_prompt(context)
  184. endif
  185. let line = substitute(substitute(
  186. \ string, "\<LF>", '; ', 'g'), '; $', '', '')
  187. call vimshell#view#_set_prompt_command(line)
  188. let line = vimshell#hook#call_filter(
  189. \ 'preparse', vimshell#get_context(), line)
  190. let ret = vimshell#execute_async(line)
  191. if ret == 0
  192. call vimshell#next_prompt(vimshell#get_context(), 0)
  193. endif
  194. else
  195. let string = join(list, "\<LF>")
  196. if string !~ '\n$'
  197. let string .= "\<LF>"
  198. endif
  199. let prompt = vimshell#interactive#get_prompt(line('$'))
  200. call setline('$', split(prompt . string, "\<LF>")[0])
  201. call vimshell#interactive#iexe_send_string(string, mode() ==# 'i')
  202. endif
  203. stopinsert
  204. noautocmd call vimshell#helpers#restore_pos(old_pos)
  205. endfunction"}}}
  206. function! vimshell#interactive#send_string(...) "{{{
  207. echohl WarningMsg | echomsg 'vimshell#interactive#send_string() is deprecated; use vimshell#interactive#send() instead' | echohl None
  208. return call('vimshell#interactive#send', a:000)
  209. endfunction"}}}
  210. function! s:iexe_send_string(string, is_insert, linenr) "{{{
  211. if !b:interactive.process.is_valid
  212. return
  213. endif
  214. setlocal modifiable
  215. let in = a:string
  216. let context = vimshell#get_context()
  217. let context.is_interactive = 1
  218. let in = vimshell#hook#call_filter('preinput', context, in)
  219. if b:interactive.encoding != ''
  220. \ && &encoding != b:interactive.encoding
  221. " Convert encoding.
  222. let in = vimproc#util#iconv(in, &encoding, b:interactive.encoding)
  223. endif
  224. try
  225. let b:interactive.echoback_linenr = a:linenr
  226. if in =~ "\<C-d>$"
  227. " EOF.
  228. let eof = (b:interactive.is_pty ? "\<C-d>" : "\<C-z>")
  229. call b:interactive.process.stdin.write(in[:-2] . eof)
  230. else
  231. call b:interactive.process.stdin.write(in)
  232. endif
  233. catch
  234. " Error.
  235. call vimshell#error_line(context.fd, v:exception . ' ' . v:throwpoint)
  236. call vimshell#interactive#exit()
  237. endtry
  238. call vimshell#interactive#execute_process_out(a:is_insert)
  239. call s:set_output_pos(a:is_insert)
  240. " Call postinput hook.
  241. call vimshell#hook#call('postinput', context, in)
  242. endfunction"}}}
  243. function! vimshell#interactive#set_send_buffer(bufname) "{{{
  244. if !exists('t:vimshell')
  245. call vimshell#init#tab_variable()
  246. endif
  247. let bufname = a:bufname == '' ? bufname('%') : a:bufname
  248. let t:vimshell.last_interactive_bufnr = bufnr(bufname)
  249. endfunction"}}}
  250. function! vimshell#interactive#execute_process_out(is_insert) "{{{
  251. if !b:interactive.process.is_valid
  252. return
  253. endif
  254. " Check cache.
  255. let read = b:interactive.stderr_cache
  256. if !b:interactive.process.stderr.eof
  257. let read .= b:interactive.process.stderr.read(-1, 0)
  258. endif
  259. call vimshell#interactive#error_buffer(b:interactive.fd, read)
  260. let b:interactive.stderr_cache = ''
  261. " Check cache.
  262. let read = b:interactive.stdout_cache
  263. if !b:interactive.process.stdout.eof
  264. let read .= b:interactive.process.stdout.read(-1, 0)
  265. endif
  266. call vimshell#interactive#print_buffer(b:interactive.fd, read)
  267. let b:interactive.stdout_cache = ''
  268. call s:set_output_pos(a:is_insert)
  269. if b:interactive.process.stdout.eof && b:interactive.process.stderr.eof
  270. call vimshell#interactive#exit()
  271. endif
  272. endfunction"}}}
  273. function! s:set_output_pos(is_insert) "{{{
  274. " There are cases when this variable doesn't exist
  275. " USE: 'b:interactive.is_close_immediately = 1' to replicate
  276. if !exists('b:interactive')
  277. return
  278. end
  279. if b:interactive.type !=# 'terminal' &&
  280. \ has_key(b:interactive.process, 'stdout')
  281. \ && (!b:interactive.process.stdout.eof ||
  282. \ !b:interactive.process.stderr.eof)
  283. call vimshell#view#_simple_insert(a:is_insert)
  284. let b:interactive.output_pos = getpos('.')
  285. endif
  286. endfunction"}}}
  287. function! vimshell#interactive#quit_buffer() "{{{
  288. if get(b:interactive.process, 'is_valid', 0)
  289. echohl WarningMsg
  290. let input = input('Process is running. Force exit? [y/N] ')
  291. echohl None
  292. if input !~? 'y\%[es]'
  293. return
  294. endif
  295. call vimshell#interactive#force_exit()
  296. endif
  297. if b:interactive.type ==# 'terminal'
  298. call vimshell#commands#texe#restore_cursor()
  299. endif
  300. call vimshell#util#delete_buffer()
  301. call vimshell#echo_error('')
  302. if winnr('$') != 1
  303. close
  304. endif
  305. endfunction"}}}
  306. function! vimshell#interactive#exit() "{{{
  307. if !b:interactive.process.is_valid
  308. return
  309. endif
  310. " Get status.
  311. let [cond, status] = s:kill_process(b:interactive)
  312. let b:interactive.status = str2nr(status)
  313. let b:interactive.cond = cond
  314. let interactive = b:interactive
  315. let context = vimshell#get_context()
  316. " Call postexit hook.
  317. call vimshell#hook#call('postexit', context,
  318. \ [interactive.command, interactive.cmdline])
  319. if &filetype !=# 'vimshell'
  320. stopinsert
  321. if exists('b:interactive.is_close_immediately')
  322. \ && b:interactive.is_close_immediately
  323. " Close buffer immediately.
  324. call vimshell#util#delete_buffer()
  325. else
  326. syn match InteractiveMessage '\*\%(Exit\|Killed\)\*'
  327. hi def link InteractiveMessage WarningMsg
  328. setlocal modifiable
  329. call append('$', '*Exit*')
  330. call cursor(line('$'), 0)
  331. endif
  332. endif
  333. endfunction"}}}
  334. function! vimshell#interactive#force_exit() "{{{
  335. if !b:interactive.process.is_valid
  336. return
  337. endif
  338. " Kill processes.
  339. call s:kill_process(b:interactive)
  340. if &filetype !=# 'vimshell'
  341. syn match InteractiveMessage '\*\%(Exit\|Killed\)\*'
  342. hi def link InteractiveMessage WarningMsg
  343. setlocal modifiable
  344. call append('$', '*Killed*')
  345. call cursor(line('$'), 0)
  346. stopinsert
  347. endif
  348. endfunction"}}}
  349. function! vimshell#interactive#hang_up(afile) "{{{
  350. let interactive = getbufvar(a:afile, 'interactive')
  351. let vimshell = getbufvar(a:afile, 'vimshell')
  352. if type(interactive) == type('')
  353. return
  354. endif
  355. if get(interactive.process, 'is_valid', 0)
  356. call s:kill_process(interactive)
  357. endif
  358. let interactive.process.is_valid = 0
  359. if interactive.type ==# 'vimshell'
  360. " Clear continuation.
  361. let vimshell.continuation = {}
  362. endif
  363. if bufname('%') == a:afile && interactive.type !=# 'vimshell'
  364. syn match InteractiveMessage '\*\%(Exit\|Killed\)\*'
  365. hi def link InteractiveMessage WarningMsg
  366. setlocal modifiable
  367. call append('$', '*Killed*')
  368. call cursor(line('$'), 0)
  369. stopinsert
  370. endif
  371. endfunction"}}}
  372. function! vimshell#interactive#decode_signal(signal) "{{{
  373. if a:signal == 2
  374. return 'SIGINT'
  375. elseif a:signal == 3
  376. return 'SIGQUIT'
  377. elseif a:signal == 4
  378. return 'SIGILL'
  379. elseif a:signal == 6
  380. return 'SIGABRT'
  381. elseif a:signal == 8
  382. return 'SIGFPE'
  383. elseif a:signal == 9
  384. return 'SIGKILL'
  385. elseif a:signal == 11
  386. return 'SIGSEGV'
  387. elseif a:signal == 13
  388. return 'SIGPIPE'
  389. elseif a:signal == 14
  390. return 'SIGALRM'
  391. elseif a:signal == 15
  392. return 'SIGTERM'
  393. elseif a:signal == 10
  394. return 'SIGUSR1'
  395. elseif a:signal == 12
  396. return 'SIGUSR2'
  397. elseif a:signal == 17
  398. return 'SIGCHLD'
  399. elseif a:signal == 18
  400. return 'SIGCONT'
  401. elseif a:signal == 19
  402. return 'SIGSTOP'
  403. elseif a:signal == 20
  404. return 'SIGTSTP'
  405. elseif a:signal == 21
  406. return 'SIGTTIN'
  407. elseif a:signal == 22
  408. return 'SIGTTOU'
  409. else
  410. return 'UNKNOWN'
  411. endif
  412. endfunction"}}}
  413. function! vimshell#interactive#read(fd) "{{{
  414. if empty(a:fd) || a:fd.stdin == ''
  415. return ''
  416. endif
  417. if a:fd.stdout == '/dev/null'
  418. " Nothing.
  419. return ''
  420. elseif a:fd.stdout == '/dev/clip'
  421. " Write to clipboard.
  422. return @+
  423. else
  424. " Read from file.
  425. if !vimshell#util#is_windows()
  426. let ff = "\<CR>\<LF>"
  427. else
  428. let ff = "\<LF>"
  429. endif
  430. return join(readfile(a:fd.stdin), ff) . ff
  431. endif
  432. endfunction"}}}
  433. function! vimshell#interactive#print_buffer(fd, string) "{{{
  434. if a:string == '' || !exists('b:interactive')
  435. \|| !&l:modifiable
  436. return
  437. endif
  438. if !empty(a:fd) && a:fd.stdout != ''
  439. let mode = 'w'
  440. let fd = a:fd.stdout
  441. if fd =~ '^>'
  442. let mode = 'a'
  443. let fd = fd[1:]
  444. endif
  445. return vimproc#write(fd, a:string, mode)
  446. endif
  447. " Convert encoding.
  448. let string =
  449. \ (b:interactive.encoding != '' && &encoding != b:interactive.encoding) ?
  450. \ vimproc#util#iconv(a:string, b:interactive.encoding, &encoding) : a:string
  451. call vimshell#terminal#print(string, 0)
  452. call s:check_password_input(string)
  453. call s:check_scrollback()
  454. let b:interactive.output_pos = getpos('.')
  455. if has_key(b:interactive, 'prompt_history')
  456. \ && line('.') != b:interactive.echoback_linenr && getline('.') != ''
  457. let b:interactive.prompt_history[line('.')] = getline('.')
  458. endif
  459. endfunction"}}}
  460. function! vimshell#interactive#error_buffer(fd, string) "{{{
  461. if a:string == ''
  462. return
  463. endif
  464. if !exists('b:interactive') || !&l:modifiable
  465. echohl WarningMsg | echomsg a:string | echohl None
  466. return
  467. endif
  468. if !empty(a:fd) && a:fd.stderr != ''
  469. let mode = 'w'
  470. let fd = a:fd.stderr
  471. if fd =~ '^>'
  472. let mode = 'a'
  473. let fd = fd[1:]
  474. endif
  475. return vimproc#write(fd, a:string, mode)
  476. endif
  477. " Convert encoding.
  478. let string =
  479. \ (b:interactive.encoding != '' && &encoding != b:interactive.encoding) ?
  480. \ vimproc#util#iconv(a:string, b:interactive.encoding, &encoding) : a:string
  481. " Print buffer.
  482. call vimshell#terminal#print(string, 1)
  483. call s:check_password_input(string)
  484. call s:check_scrollback()
  485. let b:interactive.output_pos = getpos('.')
  486. redraw
  487. if has_key(b:interactive, 'prompt_history')
  488. \ && line('.') != b:interactive.echoback_linenr && getline('.') != ''
  489. let b:interactive.prompt_history[line('.')] = getline('.')
  490. endif
  491. endfunction"}}}
  492. function! s:check_password_input(string) "{{{
  493. let current_line = substitute(getline('.'), '!!!', '', 'g')
  494. if !exists('g:vimproc_password_pattern')
  495. \ || (current_line !~# g:vimproc_password_pattern
  496. \ && a:string !~# g:vimproc_password_pattern)
  497. \ || (b:interactive.type != 'interactive'
  498. \ && b:interactive.type != 'vimshell')
  499. \ || a:string[matchend(a:string,
  500. \ g:vimproc_password_pattern) :] =~ '\n'
  501. return
  502. endif
  503. redraw
  504. " Password input.
  505. set imsearch=0
  506. let in = inputsecret('Input Secret : ')
  507. if b:interactive.encoding != '' && &encoding != b:interactive.encoding
  508. " Convert encoding.
  509. let in = vimproc#util#iconv(in, &encoding, b:interactive.encoding)
  510. endif
  511. try
  512. call b:interactive.process.stdin.write(in . "\<NL>")
  513. catch
  514. call b:interactive.process.waitpid()
  515. " Error.
  516. let context = vimshell#get_context()
  517. call vimshell#error_line(context.fd, v:exception . ' ' . v:throwpoint)
  518. let b:vimshell.continuation = {}
  519. call vimshell#print_prompt(context)
  520. call vimshell#start_insert(mode() ==# 'i')
  521. endtry
  522. endfunction"}}}
  523. function! s:check_scrollback() "{{{
  524. let prompt_nr = get(b:interactive, 'prompt_nr', 0)
  525. let output_lines = line('.') - prompt_nr
  526. if output_lines > g:vimshell_scrollback_limit
  527. let pos = getpos('.')
  528. " Delete output.
  529. silent execute printf('%d,%ddelete _', prompt_nr+1,
  530. \ (line('.')-g:vimshell_scrollback_limit+1))
  531. if pos != getpos('.')
  532. call setpos('.', pos)
  533. endif
  534. endif
  535. endfunction"}}}
  536. function! vimshell#interactive#get_default_encoding(commands) "{{{
  537. if empty(a:commands[0].args)
  538. return ''
  539. endif
  540. let full_command = tolower(
  541. \ vimshell#helpers#get_command_path(a:commands[0].args[0]))
  542. let command = fnamemodify(full_command, ':t:r')
  543. for [path, encoding] in items(g:vimshell_interactive_encodings)
  544. if (path =~ '/' && stridx(full_command, tolower(path)) >= 0)
  545. \ || path ==? command
  546. return encoding
  547. endif
  548. endfor
  549. " Default.
  550. return 'char'
  551. endfunction"}}}
  552. " Autocmd functions.
  553. function! s:check_all_output(is_hold) "{{{
  554. if vimshell#util#is_cmdwin()
  555. return
  556. endif
  557. let updated = 0
  558. if mode() ==# 'n'
  559. for bufnr in filter(range(1, bufnr('$')),
  560. \ "type(getbufvar(v:val, 'interactive')) == type({})")
  561. let interactive = getbufvar(bufnr, 'interactive')
  562. let updated = 1
  563. " Check output.
  564. call s:check_output(interactive, bufnr, bufnr('%'))
  565. endfor
  566. elseif mode() ==# 'i'
  567. \ && exists('b:interactive') && line('.') == line('$')
  568. call s:check_output(b:interactive, bufnr('%'), bufnr('%'))
  569. endif
  570. if !s:is_insert_char_pre && exists('b:interactive')
  571. \ && vimshell#get_prompt() != ''
  572. " For old Vim.
  573. call vimshell#util#enable_auto_complete()
  574. endif
  575. if exists('b:interactive') || updated
  576. if g:vimshell_interactive_update_time > 0
  577. \ && &updatetime > g:vimshell_interactive_update_time
  578. " Change updatetime.
  579. let s:update_time_save = &updatetime
  580. let &updatetime = g:vimshell_interactive_update_time
  581. endif
  582. " Ignore key sequences.
  583. if mode() ==# 'n'
  584. call feedkeys("g\<ESC>" . (v:count > 0 ? v:count : ''), 'n')
  585. elseif mode() ==# 'i'
  586. if exists('b:interactive') &&
  587. \ !empty(b:interactive.process)
  588. \ && b:interactive.process.is_valid
  589. let is_complete_hold = vimshell#util#is_complete_hold()
  590. if a:is_hold != is_complete_hold
  591. setlocal modifiable
  592. " Prevent screen flick
  593. set vb t_vb=
  594. call feedkeys("]\<BS>", 'n')
  595. endif
  596. endif
  597. endif
  598. elseif g:vimshell_interactive_update_time > 0
  599. \ && &updatetime == g:vimshell_interactive_update_time
  600. \ && &filetype !=# 'unite'
  601. " Restore updatetime.
  602. let &updatetime = s:update_time_save
  603. endif
  604. endfunction"}}}
  605. function! s:check_output(interactive, bufnr, bufnr_save) "{{{
  606. " Output cache.
  607. if exists('b:interactive') && (s:is_skk_enabled()
  608. \ || (b:interactive.type ==# 'interactive'
  609. \ && line('.') != b:interactive.echoback_linenr
  610. \ && (vimshell#interactive#get_cur_line(
  611. \ line('.'), b:interactive) != ''
  612. \ || vimshell#interactive#get_cur_line(
  613. \ line('$'), b:interactive) != '')))
  614. return 1
  615. endif
  616. if a:interactive.type ==# 'less'
  617. \ || (!s:cache_output(a:interactive) && !exists('b:interactive'))
  618. \ || vimshell#util#is_cmdwin()
  619. \ || (a:bufnr != a:bufnr_save && bufwinnr(a:bufnr) < 0)
  620. return
  621. endif
  622. if a:bufnr != a:bufnr_save
  623. execute bufwinnr(a:bufnr) . 'wincmd w'
  624. endif
  625. let type = a:interactive.type
  626. if (type ==# 'vimshell'
  627. \ && empty(b:vimshell.continuation))
  628. if a:bufnr != a:bufnr_save && bufexists(a:bufnr_save)
  629. execute bufwinnr(a:bufnr_save) . 'wincmd w'
  630. endif
  631. return
  632. endif
  633. let pos = getpos('.')
  634. let is_last_line = line('.') == line('$')
  635. if has_key(a:interactive, 'output_pos')
  636. call setpos('.', a:interactive.output_pos)
  637. endif
  638. let is_insert = mode() ==# 'i'
  639. if type ==# 'background'
  640. setlocal modifiable
  641. call vimshell#interactive#execute_process_out(is_insert)
  642. setlocal nomodifiable
  643. elseif type ==# 'vimshell'
  644. try
  645. call vimshell#parser#execute_continuation(is_insert)
  646. catch
  647. " Error.
  648. let context = vimshell#get_context()
  649. if v:exception !~# '^Vim:Interrupt'
  650. call vimshell#error_line(
  651. \ context.fd, v:exception . ' ' . v:throwpoint)
  652. endif
  653. let b:vimshell.continuation = {}
  654. call vimshell#print_prompt(context)
  655. call vimshell#start_insert(is_insert)
  656. endtry
  657. elseif type ==# 'interactive' || type ==# 'terminal'
  658. setlocal modifiable
  659. call vimshell#interactive#execute_process_out(is_insert)
  660. if type ==# 'terminal'
  661. setlocal nomodifiable
  662. elseif (!a:interactive.process.stdout.eof
  663. \ || !a:interactive.process.stderr.eof)
  664. \ && is_insert
  665. call vimshell#view#_simple_insert(is_insert)
  666. endif
  667. endif
  668. if (!is_last_line || vimshell#interactive#get_cur_text() != '')
  669. \ && pos != getpos('.')
  670. \ && exists('b:interactive')
  671. \ && b:interactive.process.is_valid
  672. call setpos('.', pos)
  673. endif
  674. " Check window size.
  675. if vimshell#helpers#get_winwidth() != a:interactive.width
  676. " Set new window size.
  677. call a:interactive.process.set_winsize(
  678. \ vimshell#helpers#get_winwidth(), g:vimshell_scrollback_limit)
  679. endif
  680. if a:bufnr != a:bufnr_save && bufexists(a:bufnr_save)
  681. execute bufwinnr(a:bufnr_save) . 'wincmd w'
  682. endif
  683. endfunction"}}}
  684. function! s:cache_output(interactive) "{{{
  685. if empty(a:interactive.process) ||
  686. \ !a:interactive.process.is_valid
  687. return 0
  688. endif
  689. if !a:interactive.process.stdout.eof
  690. let a:interactive.stdout_cache .=
  691. \ a:interactive.process.stdout.read(-1, 0)
  692. endif
  693. if !a:interactive.process.stderr.eof
  694. let a:interactive.stderr_cache .=
  695. \ a:interactive.process.stderr.read(-1, 0)
  696. endif
  697. if a:interactive.process.stderr.eof &&
  698. \ a:interactive.process.stdout.eof
  699. return 2
  700. endif
  701. return a:interactive.stdout_cache != '' ||
  702. \ a:interactive.stderr_cache != ''
  703. endfunction"}}}
  704. function! s:is_skk_enabled() "{{{
  705. return (exists('b:skk_on') && b:skk_on)
  706. \ || (exists('*eskk#is_enabled') && eskk#is_enabled())
  707. endfunction"}}}
  708. function! s:enable_auto_complete() "{{{
  709. if exists('b:interactive') && v:char != ']'
  710. call vimshell#util#enable_auto_complete()
  711. endif
  712. endfunction"}}}
  713. function! s:winenter() "{{{
  714. if exists('b:interactive')
  715. call vimshell#terminal#set_title()
  716. endif
  717. call s:resize()
  718. endfunction"}}}
  719. function! s:winleave(bufname) "{{{
  720. if !exists('b:interactive')
  721. return
  722. endif
  723. if !exists('t:vimshell')
  724. call vimshell#init#tab_variable()
  725. endif
  726. let t:vimshell.last_interactive_bufnr = bufnr(a:bufname)
  727. call vimshell#terminal#restore_title()
  728. endfunction"}}}
  729. function! s:vimleave() "{{{
  730. " Kill all processes.
  731. for interactive in map(filter(range(1, bufnr('$')),
  732. \ "type(getbufvar(v:val, 'interactive')) == type({})
  733. \ && get(get(getbufvar(v:val, 'interactive'),
  734. \ 'process', {}), 'is_valid', 0)"),
  735. \ "getbufvar(v:val, 'interactive')")
  736. call s:kill_process(interactive)
  737. endfor
  738. endfunction"}}}
  739. function! s:resize() "{{{
  740. if exists('b:interactive') && !empty(b:interactive.process)
  741. call b:interactive.process.set_winsize(
  742. \ vimshell#helpers#get_winwidth(), g:vimshell_scrollback_limit)
  743. endif
  744. endfunction"}}}
  745. function! s:kill_process(interactive) "{{{
  746. " Get status.
  747. let [cond, status] = a:interactive.process.waitpid()
  748. if cond != 'exit'
  749. try
  750. " Kill process.
  751. " 15 == SIGTERM
  752. call a:interactive.process.kill(g:vimproc#SIGTERM)
  753. call a:interactive.process.waitpid()
  754. catch
  755. endtry
  756. endif
  757. return [cond, status]
  758. endfunction"}}}
  759. " vim: foldmethod=marker