aboutsummaryrefslogtreecommitdiff
path: root/runtime/autoload
diff options
context:
space:
mode:
authorJosh Rahm <joshuarahm@gmail.com>2023-11-30 20:35:25 +0000
committerJosh Rahm <joshuarahm@gmail.com>2023-11-30 20:35:25 +0000
commit1b7b916b7631ddf73c38e3a0070d64e4636cb2f3 (patch)
treecd08258054db80bb9a11b1061bb091c70b76926a /runtime/autoload
parenteaa89c11d0f8aefbb512de769c6c82f61a8baca3 (diff)
parent4a8bf24ac690004aedf5540fa440e788459e5e34 (diff)
downloadrneovim-aucmd_textputpost.tar.gz
rneovim-aucmd_textputpost.tar.bz2
rneovim-aucmd_textputpost.zip
Merge remote-tracking branch 'upstream/master' into aucmd_textputpostaucmd_textputpost
Diffstat (limited to 'runtime/autoload')
-rw-r--r--runtime/autoload/cargo.vim149
-rw-r--r--runtime/autoload/cargo/quickfix.vim29
-rw-r--r--runtime/autoload/ccomplete.lua7
-rw-r--r--runtime/autoload/dist/vim.vim32
-rw-r--r--runtime/autoload/gzip.vim12
-rw-r--r--runtime/autoload/health.vim211
-rw-r--r--runtime/autoload/health/provider.vim771
-rw-r--r--runtime/autoload/javascriptcomplete.vim6
-rw-r--r--runtime/autoload/msgpack.vim8
-rw-r--r--runtime/autoload/netrw.vim319
-rw-r--r--runtime/autoload/netrwSettings.vim8
-rw-r--r--runtime/autoload/paste.vim5
-rw-r--r--runtime/autoload/phpcomplete.vim2
-rw-r--r--runtime/autoload/provider/clipboard.vim11
-rw-r--r--runtime/autoload/provider/node.vim18
-rw-r--r--runtime/autoload/provider/pythonx.vim9
-rw-r--r--runtime/autoload/python.vim9
-rw-r--r--runtime/autoload/rust.vim773
-rw-r--r--runtime/autoload/rust/debugging.vim105
-rw-r--r--runtime/autoload/rustfmt.vim300
-rw-r--r--runtime/autoload/shada.vim2
-rw-r--r--runtime/autoload/tar.vim112
-rw-r--r--runtime/autoload/tohtml.vim463
-rw-r--r--runtime/autoload/tutor.vim12
-rw-r--r--runtime/autoload/zip.vim17
25 files changed, 1584 insertions, 1806 deletions
diff --git a/runtime/autoload/cargo.vim b/runtime/autoload/cargo.vim
new file mode 100644
index 0000000000..6696b3105f
--- /dev/null
+++ b/runtime/autoload/cargo.vim
@@ -0,0 +1,149 @@
+" Last Modified: 2023-09-11
+
+function! cargo#Load()
+ " Utility call to get this script loaded, for debugging
+endfunction
+
+function! cargo#cmd(args) abort
+ " Trim trailing spaces. This is necessary since :terminal command parses
+ " trailing spaces as an empty argument.
+ let args = substitute(a:args, '\s\+$', '', '')
+ if exists('g:cargo_shell_command_runner')
+ let cmd = g:cargo_shell_command_runner
+ elseif has('terminal')
+ let cmd = 'terminal'
+ elseif has('nvim')
+ let cmd = 'noautocmd new | terminal'
+ else
+ let cmd = '!'
+ endif
+ execute cmd 'cargo' args
+endfunction
+
+function! s:nearest_cargo(...) abort
+ " If the second argument is not specified, the first argument determines
+ " whether we will start from the current directory or the directory of the
+ " current buffer, otherwise, we start with the provided path on the
+ " second argument.
+
+ let l:is_getcwd = get(a:, 1, 0)
+ if l:is_getcwd
+ let l:starting_path = get(a:, 2, getcwd())
+ else
+ let l:starting_path = get(a:, 2, expand('%:p:h'))
+ endif
+
+ return findfile('Cargo.toml', l:starting_path . ';')
+endfunction
+
+function! cargo#nearestCargo(is_getcwd) abort
+ return s:nearest_cargo(a:is_getcwd)
+endfunction
+
+function! cargo#nearestWorkspaceCargo(is_getcwd) abort
+ let l:nearest = s:nearest_cargo(a:is_getcwd)
+ while l:nearest !=# ''
+ for l:line in readfile(l:nearest, '', 0x100)
+ if l:line =~# '\V[workspace]'
+ return l:nearest
+ endif
+ endfor
+ let l:next = fnamemodify(l:nearest, ':p:h:h')
+ let l:nearest = s:nearest_cargo(0, l:next)
+ endwhile
+ return ''
+endfunction
+
+function! cargo#nearestRootCargo(is_getcwd) abort
+ " Try to find a workspace Cargo.toml, and if not found, take the nearest
+ " regular Cargo.toml
+ let l:workspace_cargo = cargo#nearestWorkspaceCargo(a:is_getcwd)
+ if l:workspace_cargo !=# ''
+ return l:workspace_cargo
+ endif
+ return s:nearest_cargo(a:is_getcwd)
+endfunction
+
+
+function! cargo#build(args)
+ call cargo#cmd("build " . a:args)
+endfunction
+
+function! cargo#check(args)
+ call cargo#cmd("check " . a:args)
+endfunction
+
+function! cargo#clean(args)
+ call cargo#cmd("clean " . a:args)
+endfunction
+
+function! cargo#doc(args)
+ call cargo#cmd("doc " . a:args)
+endfunction
+
+function! cargo#new(args)
+ call cargo#cmd("new " . a:args)
+ cd `=a:args`
+endfunction
+
+function! cargo#init(args)
+ call cargo#cmd("init " . a:args)
+endfunction
+
+function! cargo#run(args)
+ call cargo#cmd("run " . a:args)
+endfunction
+
+function! cargo#test(args)
+ call cargo#cmd("test " . a:args)
+endfunction
+
+function! cargo#bench(args)
+ call cargo#cmd("bench " . a:args)
+endfunction
+
+function! cargo#update(args)
+ call cargo#cmd("update " . a:args)
+endfunction
+
+function! cargo#search(args)
+ call cargo#cmd("search " . a:args)
+endfunction
+
+function! cargo#publish(args)
+ call cargo#cmd("publish " . a:args)
+endfunction
+
+function! cargo#install(args)
+ call cargo#cmd("install " . a:args)
+endfunction
+
+function! cargo#runtarget(args)
+ let l:filename = expand('%:p')
+ let l:read_manifest = system('cargo read-manifest')
+ let l:metadata = json_decode(l:read_manifest)
+ let l:targets = get(l:metadata, 'targets', [])
+ let l:did_run = 0
+ for l:target in l:targets
+ let l:src_path = get(l:target, 'src_path', '')
+ let l:kinds = get(l:target, 'kind', [])
+ let l:name = get(l:target, 'name', '')
+ if l:src_path == l:filename
+ if index(l:kinds, 'example') != -1
+ let l:did_run = 1
+ call cargo#run("--example " . shellescape(l:name) . " " . a:args)
+ return
+ elseif index(l:kinds, 'bin') != -1
+ let l:did_run = 1
+ call cargo#run("--bin " . shellescape(l:name) . " " . a:args)
+ return
+ endif
+ endif
+ endfor
+ if l:did_run != 1
+ call cargo#run(a:args)
+ return
+ endif
+endfunction
+
+" vim: set et sw=4 sts=4 ts=8:
diff --git a/runtime/autoload/cargo/quickfix.vim b/runtime/autoload/cargo/quickfix.vim
new file mode 100644
index 0000000000..f2a006f6c5
--- /dev/null
+++ b/runtime/autoload/cargo/quickfix.vim
@@ -0,0 +1,29 @@
+" Last Modified: 2023-09-11
+
+function! cargo#quickfix#CmdPre() abort
+ if &filetype ==# 'rust' && get(b:, 'current_compiler', '') ==# 'cargo' &&
+ \ &makeprg =~ '\V\^cargo\ \.\*'
+ " Preserve the current directory, and 'lcd' to the nearest Cargo file.
+ let b:rust_compiler_cargo_qf_has_lcd = haslocaldir()
+ let b:rust_compiler_cargo_qf_prev_cd = getcwd()
+ let b:rust_compiler_cargo_qf_prev_cd_saved = 1
+ let l:nearest = fnamemodify(cargo#nearestRootCargo(0), ':h')
+ execute 'lchdir! '.l:nearest
+ else
+ let b:rust_compiler_cargo_qf_prev_cd_saved = 0
+ endif
+endfunction
+
+function! cargo#quickfix#CmdPost() abort
+ if exists("b:rust_compiler_cargo_qf_prev_cd_saved") && b:rust_compiler_cargo_qf_prev_cd_saved
+ " Restore the current directory.
+ if b:rust_compiler_cargo_qf_has_lcd
+ execute 'lchdir! '.b:rust_compiler_cargo_qf_prev_cd
+ else
+ execute 'chdir! '.b:rust_compiler_cargo_qf_prev_cd
+ endif
+ let b:rust_compiler_cargo_qf_prev_cd_saved = 0
+ endif
+endfunction
+
+" vim: set et sw=4 sts=4 ts=8:
diff --git a/runtime/autoload/ccomplete.lua b/runtime/autoload/ccomplete.lua
index f4a3eabd9a..ce85e84f7a 100644
--- a/runtime/autoload/ccomplete.lua
+++ b/runtime/autoload/ccomplete.lua
@@ -24,10 +24,11 @@ local SearchMembers = nil
-- vim9script
-- # Vim completion script
--- # Language: C
--- # Maintainer: Bram Moolenaar <Bram@vim.org>
+-- # Language: C
+-- # Maintainer: The Vim Project <https://github.com/vim/vim>
+-- # Last Change: 2023 Aug 10
-- # Rewritten in Vim9 script by github user lacygoill
--- # Last Change: 2022 Jan 31
+-- # Former Maintainer: Bram Moolenaar <Bram@vim.org>
prepended = ''
grepCache = vim.empty_dict()
diff --git a/runtime/autoload/dist/vim.vim b/runtime/autoload/dist/vim.vim
new file mode 100644
index 0000000000..021244c93b
--- /dev/null
+++ b/runtime/autoload/dist/vim.vim
@@ -0,0 +1,32 @@
+" Vim runtime support library,
+" runs the vim9 script version or legacy script version
+" on demand (mostly for Neovim compatability)
+"
+" Maintainer: The Vim Project <https://github.com/vim/vim>
+" Last Change: 2023 Nov 04
+
+
+" enable the zip and gzip plugin by default, if not set
+if !exists('g:zip_exec')
+ let g:zip_exec = 1
+endif
+
+if !exists('g:gzip_exec')
+ let g:gzip_exec = 1
+endif
+
+if !has('vim9script')
+ function dist#vim#IsSafeExecutable(filetype, executable)
+ let cwd = getcwd()
+ return get(g:, a:filetype .. '_exec', get(g:, 'plugin_exec', 0)) &&
+ \ (fnamemodify(exepath(a:executable), ':p:h') !=# cwd
+ \ || (split($PATH, has('win32') ? ';' : ':')->index(cwd) != -1 &&
+ \ cwd != '.'))
+ endfunction
+
+ finish
+endif
+
+def dist#vim#IsSafeExecutable(filetype: string, executable: string): bool
+ return dist#vim9#IsSafeExecutable(filetype, executable)
+enddef
diff --git a/runtime/autoload/gzip.vim b/runtime/autoload/gzip.vim
index e4adec0947..26b1cda034 100644
--- a/runtime/autoload/gzip.vim
+++ b/runtime/autoload/gzip.vim
@@ -1,6 +1,7 @@
" Vim autoload file for editing compressed files.
-" Maintainer: Bram Moolenaar <Bram@vim.org>
-" Last Change: 2016 Sep 28
+" Maintainer: The Vim Project <https://github.com/vim/vim>
+" Last Change: 2023 Aug 10
+" Former Maintainer: Bram Moolenaar <Bram@vim.org>
" These functions are used by the gzip plugin.
@@ -9,12 +10,17 @@
fun s:check(cmd)
let name = substitute(a:cmd, '\(\S*\).*', '\1', '')
if !exists("s:have_" . name)
+ " safety check, don't execute anything from the current directory
+ let f = dist#vim#IsSafeExecutable('gzip', name)
+ if !f
+ echoerr "Warning: NOT executing " .. name .. " from current directory!"
+ endif
let e = executable(name)
if e < 0
let r = system(name . " --version")
let e = (r !~ "not found" && r != "")
endif
- exe "let s:have_" . name . "=" . e
+ exe "let s:have_" . name . "=" . (e && f)
endif
exe "return s:have_" . name
endfun
diff --git a/runtime/autoload/health.vim b/runtime/autoload/health.vim
index 5fd4627b11..a7dbedab08 100644
--- a/runtime/autoload/health.vim
+++ b/runtime/autoload/health.vim
@@ -1,207 +1,40 @@
-" Runs the specified healthchecks.
-" Runs all discovered healthchecks if a:plugin_names is empty.
-function! health#check(plugin_names) abort
- let healthchecks = empty(a:plugin_names)
- \ ? s:discover_healthchecks()
- \ : s:get_healthcheck(a:plugin_names)
-
- " Create buffer and open in a tab, unless this is the default buffer when Nvim starts.
- let emptybuf = (bufnr('$') == 1 && empty(getline(1)) && 1 == line('$'))
- execute (emptybuf ? 'buffer' : 'tab sbuffer') nvim_create_buf(v:true, v:true)
- if bufexists('health://')
- bwipe health://
- endif
- file health://
- setfiletype checkhealth
-
- if empty(healthchecks)
- call setline(1, 'ERROR: No healthchecks found.')
- else
- redraw|echo 'Running healthchecks...'
- for name in sort(keys(healthchecks))
- let [func, type] = healthchecks[name]
- let s:output = []
- try
- if func == ''
- throw 'healthcheck_not_found'
- endif
- eval type == 'v' ? call(func, []) : luaeval(func)
- " in the event the healthcheck doesn't return anything
- " (the plugin author should avoid this possibility)
- if len(s:output) == 0
- throw 'healthcheck_no_return_value'
- endif
- catch
- let s:output = [] " Clear the output
- if v:exception =~# 'healthcheck_not_found'
- call health#report_error('No healthcheck found for "'.name.'" plugin.')
- elseif v:exception =~# 'healthcheck_no_return_value'
- call health#report_error('The healthcheck report for "'.name.'" plugin is empty.')
- else
- call health#report_error(printf(
- \ "Failed to run healthcheck for \"%s\" plugin. Exception:\n%s\n%s",
- \ name, v:throwpoint, v:exception))
- endif
- endtry
- let header = [repeat('=', 78), name .. ': ' .. func, '']
- " remove empty line after header from report_start
- let s:output = s:output[0] == '' ? s:output[1:] : s:output
- let s:output = header + s:output + ['']
- call append('$', s:output)
- redraw
- endfor
+function! s:deprecate(type) abort
+ let deprecate = v:lua.vim.deprecate('health#report_' . a:type, 'vim.health.' . a:type, '0.11')
+ redraw | echo 'Running healthchecks...'
+ if deprecate isnot v:null
+ call v:lua.vim.health.warn(deprecate)
endif
-
- " Clear the 'Running healthchecks...' message.
- redraw|echo ''
-endfunction
-
-function! s:collect_output(output)
- let s:output += split(a:output, "\n", 1)
endfunction
-" Starts a new report.
function! health#report_start(name) abort
- call s:collect_output(printf("\n%s ~", a:name))
+ call v:lua.vim.health.start(a:name)
+ call s:deprecate('start')
endfunction
-" Indents lines *except* line 1 of a string if it contains newlines.
-function! s:indent_after_line1(s, columns) abort
- let lines = split(a:s, "\n", 0)
- if len(lines) < 2 " We do not indent line 1, so nothing to do.
- return a:s
- endif
- for i in range(1, len(lines)-1) " Indent lines after the first.
- let lines[i] = substitute(lines[i], '^\s*', repeat(' ', a:columns), 'g')
- endfor
- return join(lines, "\n")
+function! health#report_info(msg) abort
+ call v:lua.vim.health.info(a:msg)
+ call s:deprecate('info')
endfunction
-" Changes ':h clipboard' to ':help |clipboard|'.
-function! s:help_to_link(s) abort
- return substitute(a:s, '\v:h%[elp] ([^|][^"\r\n ]+)', ':help |\1|', 'g')
+function! health#report_ok(msg) abort
+ call v:lua.vim.health.ok(a:msg)
+ call s:deprecate('ok')
endfunction
-" Format a message for a specific report item.
-" a:1: Optional advice (string or list)
-function! s:format_report_message(status, msg, ...) abort " {{{
- let output = '- ' .. a:status .. (empty(a:status) ? '' : ' ') .. s:indent_after_line1(a:msg, 2)
-
- " Optional parameters
+function! health#report_warn(msg, ...) abort
if a:0 > 0
- let advice = type(a:1) == type('') ? [a:1] : a:1
- if type(advice) != type([])
- throw 'a:1: expected String or List'
- endif
-
- " Report each suggestion
- if !empty(advice)
- let output .= "\n - ADVICE:"
- for suggestion in advice
- let output .= "\n - " . s:indent_after_line1(suggestion, 6)
- endfor
- endif
- endif
-
- return s:help_to_link(output)
-endfunction " }}}
-
-" Reports a message as a listitem in the current section.
-function! health#report_info(msg) abort " {{{
- call s:collect_output(s:format_report_message('', a:msg))
-endfunction " }}}
-
-" Reports a successful healthcheck.
-function! health#report_ok(msg) abort " {{{
- call s:collect_output(s:format_report_message('OK', a:msg))
-endfunction " }}}
-
-" Reports a health warning.
-" a:1: Optional advice (string or list)
-function! health#report_warn(msg, ...) abort " {{{
- if a:0 > 0
- call s:collect_output(s:format_report_message('WARNING', a:msg, a:1))
+ call v:lua.vim.health.warn(a:msg, a:1)
else
- call s:collect_output(s:format_report_message('WARNING', a:msg))
+ call v:lua.vim.health.warn(a:msg)
endif
-endfunction " }}}
+ call s:deprecate('warn')
+endfunction
-" Reports a failed healthcheck.
-" a:1: Optional advice (string or list)
-function! health#report_error(msg, ...) abort " {{{
+function! health#report_error(msg, ...) abort
if a:0 > 0
- call s:collect_output(s:format_report_message('ERROR', a:msg, a:1))
+ call v:lua.vim.health.error(a:msg, a:1)
else
- call s:collect_output(s:format_report_message('ERROR', a:msg))
+ call v:lua.vim.health.error(a:msg)
endif
-endfunction " }}}
-
-" From a path return a list [{name}, {func}, {type}] representing a healthcheck
-function! s:filepath_to_healthcheck(path) abort
- if a:path =~# 'vim$'
- let name = matchstr(a:path, '\zs[^\/]*\ze\.vim$')
- let func = 'health#'.name.'#check'
- let type = 'v'
- else
- let base_path = substitute(a:path,
- \ '.*lua[\/]\(.\{-}\)[\/]health\([\/]init\)\?\.lua$',
- \ '\1', '')
- let name = substitute(base_path, '[\/]', '.', 'g')
- let func = 'require("'.name.'.health").check()'
- let type = 'l'
- endif
- return [name, func, type]
-endfunction
-
-function! s:discover_healthchecks() abort
- return s:get_healthcheck('*')
-endfunction
-
-" Returns Dictionary {name: [func, type], ..} representing healthchecks
-function! s:get_healthcheck(plugin_names) abort
- let health_list = s:get_healthcheck_list(a:plugin_names)
- let healthchecks = {}
- for c in health_list
- let normalized_name = substitute(c[0], '-', '_', 'g')
- let existent = get(healthchecks, normalized_name, [])
- " Prefer Lua over vim entries
- if existent != [] && existent[2] == 'l'
- continue
- else
- let healthchecks[normalized_name] = c
- endif
- endfor
- let output = {}
- for v in values(healthchecks)
- let output[v[0]] = v[1:]
- endfor
- try
- " vim.health is not a healthcheck, skip it
- call remove(output, 'vim')
- catch
- endtry
- return output
-endfunction
-
-" Returns list of lists [ [{name}, {func}, {type}] ] representing healthchecks
-function! s:get_healthcheck_list(plugin_names) abort
- let healthchecks = []
- let plugin_names = type('') == type(a:plugin_names)
- \ ? split(a:plugin_names, ' ', v:false)
- \ : a:plugin_names
- for p in plugin_names
- " support vim/lsp/health{/init/}.lua as :checkhealth vim.lsp
- let p = substitute(p, '\.', '/', 'g')
- let p = substitute(p, '*$', '**', 'g') " find all submodule e.g vim*
- let paths = nvim_get_runtime_file('autoload/health/'.p.'.vim', v:true)
- \ + nvim_get_runtime_file('lua/**/'.p.'/health/init.lua', v:true)
- \ + nvim_get_runtime_file('lua/**/'.p.'/health.lua', v:true)
- if len(paths) == 0
- let healthchecks += [[p, '', '']] " healthcheck not found
- else
- let healthchecks += map(uniq(sort(paths)),
- \'<SID>filepath_to_healthcheck(v:val)')
- end
- endfor
- return healthchecks
+ call s:deprecate('error')
endfunction
diff --git a/runtime/autoload/health/provider.vim b/runtime/autoload/health/provider.vim
deleted file mode 100644
index d104bcfd67..0000000000
--- a/runtime/autoload/health/provider.vim
+++ /dev/null
@@ -1,771 +0,0 @@
-let s:shell_error = 0
-
-function! s:is_bad_response(s) abort
- return a:s =~? '\v(^unable)|(^error)|(^outdated)'
-endfunction
-
-function! s:trim(s) abort
- return substitute(a:s, '^\_s*\|\_s*$', '', 'g')
-endfunction
-
-" Convert '\' to '/'. Collapse '//' and '/./'.
-function! s:normalize_path(s) abort
- return substitute(substitute(a:s, '\', '/', 'g'), '/\./\|/\+', '/', 'g')
-endfunction
-
-" Returns TRUE if `cmd` exits with success, else FALSE.
-function! s:cmd_ok(cmd) abort
- call system(a:cmd)
- return v:shell_error == 0
-endfunction
-
-" Simple version comparison.
-function! s:version_cmp(a, b) abort
- let a = split(a:a, '\.', 0)
- let b = split(a:b, '\.', 0)
-
- for i in range(len(a))
- if str2nr(a[i]) > str2nr(b[i])
- return 1
- elseif str2nr(a[i]) < str2nr(b[i])
- return -1
- endif
- endfor
-
- return 0
-endfunction
-
-" Handler for s:system() function.
-function! s:system_handler(jobid, data, event) dict abort
- if a:event ==# 'stderr'
- if self.add_stderr_to_output
- let self.output .= join(a:data, '')
- else
- let self.stderr .= join(a:data, '')
- endif
- elseif a:event ==# 'stdout'
- let self.output .= join(a:data, '')
- elseif a:event ==# 'exit'
- let s:shell_error = a:data
- endif
-endfunction
-
-" Attempts to construct a shell command from an args list.
-" Only for display, to help users debug a failed command.
-function! s:shellify(cmd) abort
- if type(a:cmd) != type([])
- return a:cmd
- endif
- return join(map(copy(a:cmd),
- \'v:val =~# ''\m[^\-.a-zA-Z_/]'' ? shellescape(v:val) : v:val'), ' ')
-endfunction
-
-" Run a system command and timeout after 30 seconds.
-function! s:system(cmd, ...) abort
- let stdin = a:0 ? a:1 : ''
- let ignore_error = a:0 > 2 ? a:3 : 0
- let opts = {
- \ 'add_stderr_to_output': a:0 > 1 ? a:2 : 0,
- \ 'output': '',
- \ 'stderr': '',
- \ 'on_stdout': function('s:system_handler'),
- \ 'on_stderr': function('s:system_handler'),
- \ 'on_exit': function('s:system_handler'),
- \ }
- let jobid = jobstart(a:cmd, opts)
-
- if jobid < 1
- call health#report_error(printf('Command error (job=%d): `%s` (in %s)',
- \ jobid, s:shellify(a:cmd), string(getcwd())))
- let s:shell_error = 1
- return opts.output
- endif
-
- if !empty(stdin)
- call jobsend(jobid, stdin)
- endif
-
- let res = jobwait([jobid], 30000)
- if res[0] == -1
- call health#report_error(printf('Command timed out: %s', s:shellify(a:cmd)))
- call jobstop(jobid)
- elseif s:shell_error != 0 && !ignore_error
- let emsg = printf("Command error (job=%d, exit code %d): `%s` (in %s)",
- \ jobid, s:shell_error, s:shellify(a:cmd), string(getcwd()))
- if !empty(opts.output)
- let emsg .= "\noutput: " . opts.output
- end
- if !empty(opts.stderr)
- let emsg .= "\nstderr: " . opts.stderr
- end
- call health#report_error(emsg)
- endif
-
- return opts.output
-endfunction
-
-function! s:systemlist(cmd, ...) abort
- let stdout = split(s:system(a:cmd, a:0 ? a:1 : ''), "\n")
- if a:0 > 1 && !empty(a:2)
- return filter(stdout, '!empty(v:val)')
- endif
- return stdout
-endfunction
-
-" Fetch the contents of a URL.
-function! s:download(url) abort
- let has_curl = executable('curl')
- if has_curl && system(['curl', '-V']) =~# 'Protocols:.*https'
- let rv = s:system(['curl', '-sL', a:url], '', 1, 1)
- return s:shell_error ? 'curl error with '.a:url.': '.s:shell_error : rv
- elseif executable('python')
- let script = "
- \try:\n
- \ from urllib.request import urlopen\n
- \except ImportError:\n
- \ from urllib2 import urlopen\n
- \\n
- \response = urlopen('".a:url."')\n
- \print(response.read().decode('utf8'))\n
- \"
- let rv = s:system(['python', '-c', script])
- return empty(rv) && s:shell_error
- \ ? 'python urllib.request error: '.s:shell_error
- \ : rv
- endif
- return 'missing `curl` '
- \ .(has_curl ? '(with HTTPS support) ' : '')
- \ .'and `python`, cannot make web request'
-endfunction
-
-" Check for clipboard tools.
-function! s:check_clipboard() abort
- call health#report_start('Clipboard (optional)')
-
- if !empty($TMUX) && executable('tmux') && executable('pbpaste') && !s:cmd_ok('pbpaste')
- let tmux_version = matchstr(system('tmux -V'), '\d\+\.\d\+')
- call health#report_error('pbcopy does not work with tmux version: '.tmux_version,
- \ ['Install tmux 2.6+. https://superuser.com/q/231130',
- \ 'or use tmux with reattach-to-user-namespace. https://superuser.com/a/413233'])
- endif
-
- let clipboard_tool = provider#clipboard#Executable()
- if exists('g:clipboard') && empty(clipboard_tool)
- call health#report_error(
- \ provider#clipboard#Error(),
- \ ["Use the example in :help g:clipboard as a template, or don't set g:clipboard at all."])
- elseif empty(clipboard_tool)
- call health#report_warn(
- \ 'No clipboard tool found. Clipboard registers (`"+` and `"*`) will not work.',
- \ [':help clipboard'])
- else
- call health#report_ok('Clipboard tool found: '. clipboard_tool)
- endif
-endfunction
-
-" Get the latest Nvim Python client (pynvim) version from PyPI.
-function! s:latest_pypi_version() abort
- let pypi_version = 'unable to get pypi response'
- let pypi_response = s:download('https://pypi.python.org/pypi/pynvim/json')
- if !empty(pypi_response)
- try
- let pypi_data = json_decode(pypi_response)
- catch /E474/
- return 'error: '.pypi_response
- endtry
- let pypi_version = get(get(pypi_data, 'info', {}), 'version', 'unable to parse')
- endif
- return pypi_version
-endfunction
-
-" Get version information using the specified interpreter. The interpreter is
-" used directly in case breaking changes were introduced since the last time
-" Nvim's Python client was updated.
-"
-" Returns: [
-" {python executable version},
-" {current nvim version},
-" {current pypi nvim status},
-" {installed version status}
-" ]
-function! s:version_info(python) abort
- let pypi_version = s:latest_pypi_version()
- let python_version = s:trim(s:system([
- \ a:python,
- \ '-c',
- \ 'import sys; print(".".join(str(x) for x in sys.version_info[:3]))',
- \ ]))
-
- if empty(python_version)
- let python_version = 'unable to parse '.a:python.' response'
- endif
-
- let nvim_path = s:trim(s:system([
- \ a:python, '-c',
- \ 'import sys; ' .
- \ 'sys.path = [p for p in sys.path if p != ""]; ' .
- \ 'import neovim; print(neovim.__file__)']))
- if s:shell_error || empty(nvim_path)
- return [python_version, 'unable to load neovim Python module', pypi_version,
- \ nvim_path]
- endif
-
- " Assuming that multiple versions of a package are installed, sort them
- " numerically in descending order.
- function! s:compare(metapath1, metapath2) abort
- let a = matchstr(fnamemodify(a:metapath1, ':p:h:t'), '[0-9.]\+')
- let b = matchstr(fnamemodify(a:metapath2, ':p:h:t'), '[0-9.]\+')
- return a == b ? 0 : a > b ? 1 : -1
- endfunction
-
- " Try to get neovim.VERSION (added in 0.1.11dev).
- let nvim_version = s:system([a:python, '-c',
- \ 'from neovim import VERSION as v; '.
- \ 'print("{}.{}.{}{}".format(v.major, v.minor, v.patch, v.prerelease))'],
- \ '', 1, 1)
- if empty(nvim_version)
- let nvim_version = 'unable to find pynvim module version'
- let base = fnamemodify(nvim_path, ':h')
- let metas = glob(base.'-*/METADATA', 1, 1)
- \ + glob(base.'-*/PKG-INFO', 1, 1)
- \ + glob(base.'.egg-info/PKG-INFO', 1, 1)
- let metas = sort(metas, 's:compare')
-
- if !empty(metas)
- for meta_line in readfile(metas[0])
- if meta_line =~# '^Version:'
- let nvim_version = matchstr(meta_line, '^Version: \zs\S\+')
- break
- endif
- endfor
- endif
- endif
-
- let nvim_path_base = fnamemodify(nvim_path, ':~:h')
- let version_status = 'unknown; '.nvim_path_base
- if !s:is_bad_response(nvim_version) && !s:is_bad_response(pypi_version)
- if s:version_cmp(nvim_version, pypi_version) == -1
- let version_status = 'outdated; from '.nvim_path_base
- else
- let version_status = 'up to date'
- endif
- endif
-
- return [python_version, nvim_version, pypi_version, version_status]
-endfunction
-
-" Check the Python interpreter's usability.
-function! s:check_bin(bin) abort
- if !filereadable(a:bin) && (!has('win32') || !filereadable(a:bin.'.exe'))
- call health#report_error(printf('"%s" was not found.', a:bin))
- return 0
- elseif executable(a:bin) != 1
- call health#report_error(printf('"%s" is not executable.', a:bin))
- return 0
- endif
- return 1
-endfunction
-
-" Check "loaded" var for given a:provider.
-" Returns 1 if the caller should return (skip checks).
-function! s:disabled_via_loaded_var(provider) abort
- let loaded_var = 'g:loaded_'.a:provider.'_provider'
- if exists(loaded_var) && !exists('*provider#'.a:provider.'#Call')
- let v = eval(loaded_var)
- if 0 is v
- call health#report_info('Disabled ('.loaded_var.'='.v.').')
- return 1
- else
- call health#report_info('Disabled ('.loaded_var.'='.v.'). This might be due to some previous error.')
- endif
- endif
- return 0
-endfunction
-
-function! s:check_python() abort
- call health#report_start('Python 3 provider (optional)')
-
- let pyname = 'python3'
- let python_exe = ''
- let venv = exists('$VIRTUAL_ENV') ? resolve($VIRTUAL_ENV) : ''
- let host_prog_var = pyname.'_host_prog'
- let python_multiple = []
-
- if s:disabled_via_loaded_var(pyname)
- return
- endif
-
- let [pyenv, pyenv_root] = s:check_for_pyenv()
-
- if exists('g:'.host_prog_var)
- call health#report_info(printf('Using: g:%s = "%s"', host_prog_var, get(g:, host_prog_var)))
- endif
-
- let [pyname, pythonx_warnings] = provider#pythonx#Detect(3)
-
- if empty(pyname)
- call health#report_warn('No Python executable found that can `import neovim`. '
- \ . 'Using the first available executable for diagnostics.')
- elseif exists('g:'.host_prog_var)
- let python_exe = pyname
- endif
-
- " No Python executable could `import neovim`, or host_prog_var was used.
- if !empty(pythonx_warnings)
- call health#report_warn(pythonx_warnings, ['See :help provider-python for more information.',
- \ 'You may disable this provider (and warning) by adding `let g:loaded_python3_provider = 0` to your init.vim'])
-
- elseif !empty(pyname) && empty(python_exe)
- if !exists('g:'.host_prog_var)
- call health#report_info(printf('`g:%s` is not set. Searching for '
- \ . '%s in the environment.', host_prog_var, pyname))
- endif
-
- if !empty(pyenv)
- let python_exe = s:trim(s:system([pyenv, 'which', pyname], '', 1))
-
- if empty(python_exe)
- call health#report_warn(printf('pyenv could not find %s.', pyname))
- endif
- endif