Process.vim 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. " ___vital___
  2. " NOTE: lines between '" ___vital___' is generated by :Vitalize.
  3. " Do not mofidify the code nor insert new lines before '" ___vital___'
  4. if v:version > 703 || v:version == 703 && has('patch1170')
  5. function! vital#_neocomplete#Process#import() abort
  6. return map({'shellescape': '', 'has_vimproc': '', 'system': '', 'iconv': '', 'spawn': '', 'get_last_status': ''}, 'function("s:" . v:key)')
  7. endfunction
  8. else
  9. function! s:_SID() abort
  10. return matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze__SID$')
  11. endfunction
  12. execute join(['function! vital#_neocomplete#Process#import() abort', printf("return map({'shellescape': '', 'has_vimproc': '', 'system': '', 'iconv': '', 'spawn': '', 'get_last_status': ''}, \"function('<SNR>%s_' . v:key)\")", s:_SID()), 'endfunction'], "\n")
  13. delfunction s:_SID
  14. endif
  15. " ___vital___
  16. " TODO: move all comments to doc file.
  17. "
  18. "
  19. " FIXME: This module name should be Vital.System ?
  20. " But the name has been already taken.
  21. let s:save_cpo = &cpo
  22. set cpo&vim
  23. " FIXME: Unfortunately, can't use s:_vital_loaded() for this purpose.
  24. " Because these variables are used when this script file is loaded.
  25. let s:is_windows = has('win16') || has('win32') || has('win64') || has('win95')
  26. let s:is_unix = has('unix')
  27. " As of 7.4.122, the system()'s 1st argument is converted internally by Vim.
  28. " Note that Patch 7.4.122 does not convert system()'s 2nd argument and
  29. " return-value. We must convert them manually.
  30. let s:need_trans = v:version < 704 || (v:version == 704 && !has('patch122'))
  31. let s:TYPE_DICT = type({})
  32. let s:TYPE_LIST = type([])
  33. let s:TYPE_STRING = type('')
  34. function! s:spawn(expr, ...) abort
  35. let shellslash = 0
  36. if s:is_windows
  37. let shellslash = &l:shellslash
  38. setlocal noshellslash
  39. endif
  40. try
  41. if type(a:expr) is s:TYPE_LIST
  42. let special = 1
  43. let cmdline = join(map(a:expr, 'shellescape(v:val, special)'), ' ')
  44. elseif type(a:expr) is s:TYPE_STRING
  45. let cmdline = a:expr
  46. if a:0 && a:1
  47. " for :! command
  48. let cmdline = substitute(cmdline, '\([!%#]\|<[^<>]\+>\)', '\\\1', 'g')
  49. endif
  50. else
  51. throw 'Process.spawn(): invalid argument (value type:'.type(a:expr).')'
  52. endif
  53. if s:is_windows
  54. silent execute '!start' cmdline
  55. else
  56. silent execute '!' cmdline '&'
  57. endif
  58. finally
  59. if s:is_windows
  60. let &l:shellslash = shellslash
  61. endif
  62. endtry
  63. return ''
  64. endfunction
  65. " iconv() wrapper for safety.
  66. function! s:iconv(expr, from, to) abort
  67. if a:from ==# '' || a:to ==# '' || a:from ==? a:to
  68. return a:expr
  69. endif
  70. let result = iconv(a:expr, a:from, a:to)
  71. return result !=# '' ? result : a:expr
  72. endfunction
  73. " Check vimproc.
  74. function! s:has_vimproc() abort
  75. if !exists('s:exists_vimproc')
  76. try
  77. call vimproc#version()
  78. let s:exists_vimproc = 1
  79. catch
  80. let s:exists_vimproc = 0
  81. endtry
  82. endif
  83. return s:exists_vimproc
  84. endfunction
  85. " * {command} [, {input} [, {timeout}]]
  86. " * {command} [, {dict}]
  87. " {dict} = {
  88. " use_vimproc: bool,
  89. " input: string,
  90. " timeout: bool,
  91. " background: bool,
  92. " }
  93. function! s:system(str, ...) abort
  94. " Process optional arguments at first
  95. " because use_vimproc is required later
  96. " for a:str argument.
  97. let input = ''
  98. let use_vimproc = s:has_vimproc()
  99. let background = 0
  100. let args = []
  101. if a:0 ==# 1
  102. " {command} [, {dict}]
  103. " a:1 = {dict}
  104. if type(a:1) is s:TYPE_DICT
  105. if has_key(a:1, 'use_vimproc')
  106. let use_vimproc = a:1.use_vimproc
  107. endif
  108. if has_key(a:1, 'input')
  109. let args += [s:iconv(a:1.input, &encoding, 'char')]
  110. endif
  111. if use_vimproc && has_key(a:1, 'timeout')
  112. " ignores timeout unless you have vimproc.
  113. let args += [a:1.timeout]
  114. endif
  115. if has_key(a:1, 'background')
  116. let background = a:1.background
  117. endif
  118. elseif type(a:1) is s:TYPE_STRING
  119. let args += [s:iconv(a:1, &encoding, 'char')]
  120. else
  121. throw 'Process.system(): invalid argument (value type:'.type(a:1).')'
  122. endif
  123. elseif a:0 >= 2
  124. " {command} [, {input} [, {timeout}]]
  125. " a:000 = [{input} [, {timeout}]]
  126. let [input; rest] = a:000
  127. let input = s:iconv(input, &encoding, 'char')
  128. let args += [input] + rest
  129. endif
  130. " Process a:str argument.
  131. if type(a:str) is s:TYPE_LIST
  132. let expr = use_vimproc ? '"''" . v:val . "''"' : 's:shellescape(v:val)'
  133. let command = join(map(copy(a:str), expr), ' ')
  134. elseif type(a:str) is s:TYPE_STRING
  135. let command = a:str
  136. else
  137. throw 'Process.system(): invalid argument (value type:'.type(a:str).')'
  138. endif
  139. if s:need_trans
  140. let command = s:iconv(command, &encoding, 'char')
  141. endif
  142. let args = [command] + args
  143. if background && (use_vimproc || !s:is_windows)
  144. let args[0] = args[0] . ' &'
  145. endif
  146. let funcname = use_vimproc ? 'vimproc#system' : 'system'
  147. let output = call(funcname, args)
  148. let output = s:iconv(output, 'char', &encoding)
  149. return output
  150. endfunction
  151. function! s:get_last_status() abort
  152. return s:has_vimproc() ?
  153. \ vimproc#get_last_status() : v:shell_error
  154. endfunction
  155. if s:is_windows
  156. function! s:shellescape(command) abort
  157. return substitute(a:command, '[&()[\]{}^=;!''+,`~]', '^\0', 'g')
  158. endfunction
  159. else
  160. function! s:shellescape(...) abort
  161. return call('shellescape', a:000)
  162. endfunction
  163. endif
  164. let &cpo = s:save_cpo
  165. unlet s:save_cpo
  166. " vim:set et ts=2 sts=2 sw=2 tw=0: