diff options
Diffstat (limited to 'autoload/vital/_crystal/Process.vim')
-rw-r--r-- | autoload/vital/_crystal/Process.vim | 185 |
1 files changed, 185 insertions, 0 deletions
diff --git a/autoload/vital/_crystal/Process.vim b/autoload/vital/_crystal/Process.vim new file mode 100644 index 00000000..c2deb9e5 --- /dev/null +++ b/autoload/vital/_crystal/Process.vim @@ -0,0 +1,185 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'crystal') == -1 + +" TODO: move all comments to doc file. +" +" +" FIXME: This module name should be Vital.System ? +" But the name has been already taken. + +let s:save_cpo = &cpo +set cpo&vim + + +" FIXME: Unfortunately, can't use s:_vital_loaded() for this purpose. +" Because these variables are used when this script file is loaded. +let s:is_windows = has('win16') || has('win32') || has('win64') || has('win95') +let s:is_unix = has('unix') +" As of 7.4.122, the system()'s 1st argument is converted internally by Vim. +" Note that Patch 7.4.122 does not convert system()'s 2nd argument and +" return-value. We must convert them manually. +let s:need_trans = v:version < 704 || (v:version == 704 && !has('patch122')) + +let s:TYPE_DICT = type({}) +let s:TYPE_LIST = type([]) +let s:TYPE_STRING = type("") + + +" Execute program in the background from Vim. +" Return an empty string always. +" +" If a:expr is a List, shellescape() each argument. +" If a:expr is a String, the arguments are passed as-is. +" +" Windows: +" Using :!start , execute program without via cmd.exe. +" Spawning 'expr' with 'noshellslash' +" keep special characters from unwanted expansion. +" (see :help shellescape()) +" +" Unix: +" using :! , execute program in the background by shell. +function! s:spawn(expr, ...) abort + let shellslash = 0 + if s:is_windows + let shellslash = &l:shellslash + setlocal noshellslash + endif + try + if type(a:expr) is s:TYPE_LIST + let special = 1 + let cmdline = join(map(a:expr, 'shellescape(v:val, special)'), ' ') + elseif type(a:expr) is s:TYPE_STRING + let cmdline = a:expr + if a:0 && a:1 + " for :! command + let cmdline = substitute(cmdline, '\([!%#]\|<[^<>]\+>\)', '\\\1', 'g') + endif + else + throw 'Process.spawn(): invalid argument (value type:'.type(a:expr).')' + endif + if s:is_windows + silent execute '!start' cmdline + else + silent execute '!' cmdline '&' + endif + finally + if s:is_windows + let &l:shellslash = shellslash + endif + endtry + return '' +endfunction + +" iconv() wrapper for safety. +function! s:iconv(expr, from, to) abort + if a:from == '' || a:to == '' || a:from ==? a:to + return a:expr + endif + let result = iconv(a:expr, a:from, a:to) + return result != '' ? result : a:expr +endfunction + +" Check vimproc. +function! s:has_vimproc() abort + if !exists('s:exists_vimproc') + try + call vimproc#version() + let s:exists_vimproc = 1 + catch + let s:exists_vimproc = 0 + endtry + endif + return s:exists_vimproc +endfunction + +" * {command} [, {input} [, {timeout}]] +" * {command} [, {dict}] +" {dict} = { +" use_vimproc: bool, +" input: string, +" timeout: bool, +" background: bool, +" } +function! s:system(str, ...) abort + " Process optional arguments at first + " because use_vimproc is required later + " for a:str argument. + let input = '' + let use_vimproc = s:has_vimproc() + let background = 0 + let args = [] + if a:0 ==# 1 + " {command} [, {dict}] + " a:1 = {dict} + if type(a:1) is s:TYPE_DICT + if has_key(a:1, 'use_vimproc') + let use_vimproc = a:1.use_vimproc + endif + if has_key(a:1, 'input') + let args += [s:iconv(a:1.input, &encoding, 'char')] + endif + if use_vimproc && has_key(a:1, 'timeout') + " ignores timeout unless you have vimproc. + let args += [a:1.timeout] + endif + if has_key(a:1, 'background') + let background = a:1.background + endif + elseif type(a:1) is s:TYPE_STRING + let args += [s:iconv(a:1, &encoding, 'char')] + else + throw 'Process.system(): invalid argument (value type:'.type(a:1).')' + endif + elseif a:0 >= 2 + " {command} [, {input} [, {timeout}]] + " a:000 = [{input} [, {timeout}]] + let [input; rest] = a:000 + let input = s:iconv(input, &encoding, 'char') + let args += [input] + rest + endif + + " Process a:str argument. + if type(a:str) is s:TYPE_LIST + let expr = use_vimproc ? '"''" . v:val . "''"' : 's:shellescape(v:val)' + let command = join(map(copy(a:str), expr), ' ') + elseif type(a:str) is s:TYPE_STRING + let command = a:str + else + throw 'Process.system(): invalid argument (value type:'.type(a:str).')' + endif + if s:need_trans + let command = s:iconv(command, &encoding, 'char') + endif + let args = [command] + args + if background && (use_vimproc || !s:is_windows) + let args[0] = args[0] . ' &' + endif + + let funcname = use_vimproc ? 'vimproc#system' : 'system' + let output = call(funcname, args) + let output = s:iconv(output, 'char', &encoding) + return output +endfunction + +function! s:get_last_status() abort + return s:has_vimproc() ? + \ vimproc#get_last_status() : v:shell_error +endfunction + +if s:is_windows + function! s:shellescape(command) abort + return substitute(a:command, '[&()[\]{}^=;!''+,`~]', '^\0', 'g') + endfunction +else + function! s:shellescape(...) abort + return call('shellescape', a:000) + endfunction +endif + + +let &cpo = s:save_cpo +unlet s:save_cpo + +" vim:set et ts=2 sts=2 sw=2 tw=0: + +endif |