1
0
mirror of https://github.com/SpaceVim/SpaceVim.git synced 2025-03-14 02:35:41 +08:00
SpaceVim/autoload/SpaceVim/api/vim/compatible.vim
2021-08-14 09:30:57 +08:00

366 lines
9.5 KiB
VimL

"=============================================================================
" compatible.vim --- SpaceVim compatible API
" Copyright (c) 2016-2020 Wang Shidong & Contributors
" Author: Wang Shidong < wsdjeg at 163.com >
" URL: https://spacevim.org
" License: GPLv3
"=============================================================================
scriptencoding utf-8
let s:has_cache = {}
let s:SYS = SpaceVim#api#import('system')
""
" @section vim#compatible, api-vim-compatible
" @parentsection api
"
" @subsection Functions
"
" execute(cmd)
"
" run vim command, and return the output of such command.
"
" system(cmd)
"
" like |system()| but can accept list as argv.
"
" systemlist(cmd)
"
" like |systemlist()| but can accept list as argv.
"
" has(feature)
"
" check if {feature} is supported in current version.
"
" getjumplist()
"
" return a list of jump position, like result of |:jump|
" Load SpaceVim API:
let s:STRING = SpaceVim#api#import('data#string')
let s:self = {}
function! s:self.has(feature) abort
if has_key(s:has_cache, a:feature)
return s:has_cache[a:feature]
endif
if a:feature ==# 'python'
try
py import vim
let s:has_cache['python'] = 1
return 1
catch
let s:has_cache['python'] = 0
return 0
endtry
elseif a:feature ==# 'python3'
try
py3 import vim
let s:has_cache['python3'] = 1
return 1
catch
let s:has_cache['python3'] = 0
return 0
endtry
elseif a:feature ==# 'pythonx'
try
pyx import vim
let s:has_cache['pythonx'] = 1
return 1
catch
let s:has_cache['pythonx'] = 0
return 0
endtry
else
return has(a:feature)
endif
endfunction
if has('patch-8.0.1364')
function! s:self.win_screenpos(nr) abort
return win_screenpos(a:nr)
endfunction
elseif s:self.has('python')
function! s:self.win_screenpos(nr) abort
if winnr('$') < a:nr || a:nr < 0
return [0, 0]
elseif a:nr == 0
return [pyeval('vim.current.window.row'),
\ pyeval('vim.current.window.col')]
endif
return [pyeval('vim.windows[' . a:nr . '].row'),
\ pyeval('vim.windows[' . a:nr . '].col')]
endfunction
elseif s:self.has('python3')
function! s:self.win_screenpos(nr) abort
if winnr('$') < a:nr || a:nr < 0
return [0, 0]
elseif a:nr == 0
return [py3eval('vim.current.window.row'),
\ py3eval('vim.current.window.col')]
endif
return [py3eval('vim.windows[' . a:nr . '].row'),
\ py3eval('vim.windows[' . a:nr . '].col')]
endfunction
else
" @vimlint(EVL103, 1, a:nr)
function! s:self.win_screenpos(nr) abort
return [0, 0]
endfunction
" @vimlint(EVL103, 0, a:nr)
endif
if exists('*execute')
function! s:self.execute(cmd, ...) abort
return call('execute', [a:cmd] + a:000)
endfunction
else
function! s:self.execute(cmd, ...) abort
if a:0 == 0
let s = 'silent'
else
let s = a:1
endif
let output = ''
redir => output
if s ==# 'silent'
silent execute a:cmd
elseif s ==# 'silent!'
silent! execute a:cmd
else
execute a:cmd
endif
redir END
return output
endfunction
endif
if has('nvim')
function! s:self.system(cmd, ...) abort
return a:0 == 0 ? system(a:cmd) : system(a:cmd, a:1)
endfunction
function! s:self.systemlist(cmd, ...) abort
return a:0 == 0 ? systemlist(a:cmd) : systemlist(a:cmd, a:1)
endfunction
else
function! s:self.system(cmd, ...) abort
if type(a:cmd) == 3
let cmd = map(a:cmd, 'shellescape(v:val)')
let cmd = join(cmd, ' ')
return a:0 == 0 ? system(cmd) : system(cmd, a:1)
else
return a:0 == 0 ? system(a:cmd) : system(a:cmd, a:1)
endif
endfunction
if exists('*systemlist')
function! s:self.systemlist(cmd, ...) abort
if type(a:cmd) == 3
let cmd = map(a:cmd, 'shellescape(v:val)')
let excmd = join(cmd, ' ')
return a:0 == 0 ? systemlist(excmd) : systemlist(excmd, a:1)
else
return a:0 == 0 ? systemlist(a:cmd) : systemlist(a:cmd, a:1)
endif
endfunction
else
function! s:self.systemlist(cmd, ...) abort
if type(a:cmd) == 3
let cmd = map(a:cmd, 'shellescape(v:val)')
let excmd = join(cmd, ' ')
return a:0 == 0 ? split(system(excmd), "\n")
\ : split(system(excmd, a:1), "\n")
else
return a:0 == 0 ? split(system(a:cmd), "\n")
\ : split(system(a:cmd, a:1), "\n")
endif
endfunction
endif
endif
if has('patch-7.4.279')
function! s:self.globpath(dir, expr) abort
return globpath(a:dir, a:expr, 1, 1)
endfunction
else
function! s:self.globpath(dir, expr) abort
return split(globpath(a:dir, a:expr), '\n')
endfunction
endif
if has('nvim')
function! s:self.version() abort
let v = api_info().version
return v.major . '.' . v.minor . '.' . v.patch
endfunction
else
function! s:self.version() abort
redir => l:msg
silent! execute ':version'
redir END
return s:parser(matchstr(l:msg,'\(Included\ patches:\ \)\@<=[^\n]*'))
endfunction
function! s:parser(version) abort
let v_list = split(a:version, ',')
if len(v_list) == 1
let patch = split(v_list[0], '-')[1]
let v = v:version[0:0] . '.' . v:version[2:2] . '.' . patch
else
let v = v:version[0:0] . '.' . v:version[2:2] . '(' . a:version . ')'
endif
return v
endfunction
endif
" patch 7.4.330 add function matchaddpos()
" patch 7.4.792 add dict argv to matchaddpos() (only conceal)
" patch 7.4.1740 syn-cchar defined with matchadd() does not appear
" patch 8.1.0218 update dict argv (add window)
" - A number. This whole line will be highlighted. The first
" line has number 1.
" - A list with one number, e.g., [23]. The whole line with this
" number will be highlighted.
" - A list with two numbers, e.g., [23, 11]. The first number is
" the line number, the second one is the column number (first
" column is 1, the value must correspond to the byte index as
" |col()| would return). The character at this position will
" be highlighted.
" - A list with three numbers, e.g., [23, 11, 3]. As above, but
" the third number gives the length of the highlight in bytes.
if exists('*matchaddpos')
function! s:self.matchaddpos(group, pos, ...) abort
let priority = get(a:000, 0, 10)
let id = get(a:000, 1, -1)
let argv = [priority, id]
if has('patch-7.4.792')
let dict = get(a:000, 2, {})
call add(argv, dict)
endif
return call('matchaddpos', [a:group, a:pos] + argv)
endfunction
else
function! s:self.matchaddpos(group, pos, ...) abort
let priority = get(a:000, 0, 10)
let id = get(a:000, 1, -1)
let argv = [priority, id]
if has('patch-7.4.792')
let dict = get(a:000, 2, {})
call add(argv, dict)
endif
let pos1 = a:pos[0]
if type(pos1) == 0
let id = call('matchadd', [a:group, '\%' . pos1 . 'l'] + argv)
elseif type(pos1) == 3
if len(pos1) == 1
let id = call('matchadd', [a:group, '\%' . pos1[0] . 'l'] + argv)
elseif len(pos1) == 2
let id = call('matchadd', [a:group, '\%' . pos1[0] . 'l\%' . pos1[1] . 'c'] + argv)
elseif len(pos1) == 3
let id = call('matchadd', [a:group, '\%' . pos1[0] . 'l\%>' . pos1[1] . 'c\%<' . pos1[2] . 'c'] + argv)
endif
endif
if len(a:pos) > 1
for pos1 in a:pos[1:]
if type(pos1) == 0
let id = call('matchadd', [a:group, '\%' . pos1 . 'l'] + argv)
elseif type(pos1) == 3
if len(pos1) == 1
let id = call('matchadd', [a:group, '\%' . pos1[0] . 'l'] + argv)
elseif len(pos1) == 2
let id = call('matchadd', [a:group, '\%' . pos1[0] . 'l\%' . pos1[1] . 'c'] + argv)
elseif len(pos1) == 3
let id = call('matchadd', [a:group, '\%' . pos1[0] . 'l\%>' . pos1[1] . 'c\%<' . pos1[2] . 'c'] + argv)
endif
endif
endfor
endif
return id
endfunction
endif
function! s:self.set_buf_line() abort
endfunction
if exists('*getjumplist')
function! s:self.getjumplist() abort
return getjumplist()
endfunction
else
"
" the following entries:
" bufnr buffer number
" col column number
" coladd column offset for 'virtualedit'
" filename filename if available
" lnum line number
function! s:self.getjumplist() abort
let jumpinfo = split(self.execute(':jumps'), "\n")[1:-2]
let result = []
" 20 281 23 -invalid-
for info in jumpinfo
let [jump, line, col] = s:STRING.split(info, '', 0, 4)[0:2]
call add(result, {
\ 'bufnr' : jump,
\ 'lnum' : line,
\ 'col' : col,
\ 'coladd' : 0,
\ })
endfor
return result
endfunction
endif
if s:SYS.isWindows
function! s:self.resolve(path) abort
let cmd = 'dir /a ' . shellescape(a:path) . ' | findstr SYMLINK'
" 2018/12/07 周五 下午 10:23 <SYMLINK> vimfiles [C:\Users\Administrator\.SpaceVim]
" ref: https://superuser.com/questions/524669/checking-where-a-symbolic-link-points-at-in-windows-7
silent let rst = system(cmd)
if !v:shell_error
let dir = split(rst)[-1][1:-2]
return dir
endif
return a:path
endfunction
else
function! s:self.resolve(path) abort
return resolve(a:path)
endfunction
endif
" this function is only for test
function! s:self.luaeval(expr) abort
let rst = luaeval(a:expr)
if type(rst) ==# 5
return float2nr(rst)
else
return rst
endif
endfunction
function! SpaceVim#api#vim#compatible#get() abort
return deepcopy(s:self)
endfunction
" vim:set et sw=2 cc=80: