term.vim 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. if has('nvim') && !exists("g:go_term_mode")
  2. let g:go_term_mode = 'vsplit'
  3. endif
  4. " new creates a new terminal with the given command. Mode is set based on the
  5. " global variable g:go_term_mode, which is by default set to :vsplit
  6. function! go#term#new(bang, cmd) abort
  7. return go#term#newmode(a:bang, a:cmd, g:go_term_mode)
  8. endfunction
  9. " new creates a new terminal with the given command and window mode.
  10. function! go#term#newmode(bang, cmd, mode) abort
  11. let mode = a:mode
  12. if empty(mode)
  13. let mode = g:go_term_mode
  14. endif
  15. let state = {
  16. \ 'cmd': a:cmd,
  17. \ 'bang' : a:bang,
  18. \ 'winnr': winnr(),
  19. \ 'stdout': [],
  20. \ 'stderr': []
  21. \ }
  22. " execute go build in the files directory
  23. let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd '
  24. let dir = getcwd()
  25. execute cd . fnameescape(expand("%:p:h"))
  26. execute mode.' __go_term__'
  27. setlocal filetype=goterm
  28. setlocal bufhidden=delete
  29. setlocal winfixheight
  30. setlocal noswapfile
  31. setlocal nobuflisted
  32. " explicitly bind callbacks to state so that within them, self will always
  33. " refer to state. See :help Partial for more information.
  34. let job = {
  35. \ 'on_stdout': function('s:on_stdout', [], state),
  36. \ 'on_stderr': function('s:on_stderr', [], state),
  37. \ 'on_exit' : function('s:on_exit', [], state),
  38. \ }
  39. let state.id = termopen(a:cmd, job)
  40. let state.termwinnr = winnr()
  41. execute cd . fnameescape(dir)
  42. startinsert
  43. " resize new term if needed.
  44. let height = get(g:, 'go_term_height', winheight(0))
  45. let width = get(g:, 'go_term_width', winwidth(0))
  46. " Adjust the window width or height depending on whether it's a vertical or
  47. " horizontal split.
  48. if mode =~ "vertical" || mode =~ "vsplit" || mode =~ "vnew"
  49. exe 'vertical resize ' . width
  50. elseif mode =~ "split" || mode =~ "new"
  51. exe 'resize ' . height
  52. endif
  53. " we also need to resize the pty, so there you go...
  54. call jobresize(state.id, width, height)
  55. stopinsert
  56. if state.winnr !=# winnr()
  57. exe state.winnr . "wincmd w"
  58. endif
  59. return state.id
  60. endfunction
  61. function! s:on_stdout(job_id, data, event) dict abort
  62. call extend(self.stdout, a:data)
  63. endfunction
  64. function! s:on_stderr(job_id, data, event) dict abort
  65. call extend(self.stderr, a:data)
  66. endfunction
  67. function! s:on_exit(job_id, exit_status, event) dict abort
  68. let l:listtype = go#list#Type("_term")
  69. " usually there is always output so never branch into this clause
  70. if empty(self.stdout)
  71. call s:cleanlist(self.winnr, l:listtype)
  72. return
  73. endif
  74. let errors = go#tool#ParseErrors(self.stdout)
  75. let errors = go#tool#FilterValids(errors)
  76. if !empty(errors)
  77. " close terminal; we don't need it anymore
  78. execute self.termwinnr . "close"
  79. if self.winnr !=# winnr()
  80. execute self.winnr . "wincmd w"
  81. endif
  82. call go#list#Populate(l:listtype, errors, self.cmd)
  83. call go#list#Window(l:listtype, len(errors))
  84. if !self.bang
  85. call go#list#JumpToFirst(l:listtype)
  86. endif
  87. return
  88. endif
  89. call s:cleanlist(self.winnr, l:listtype)
  90. endfunction
  91. function s:cleanlist(winnr, listtype) abort
  92. " There are no errors. Clean and close the list. Jump to the window to which
  93. " the location list is attached, close the list, and then jump back to the
  94. " current window.
  95. let l:winnr = winnr()
  96. execute a:winnr . "wincmd w"
  97. call go#list#Clean(a:listtype)
  98. execute l:winnr . "wincmd w"
  99. endfunction
  100. " vim: sw=2 ts=2 et