aboutsummaryrefslogtreecommitdiff
path: root/runtime/autoload/health/provider.vim
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/autoload/health/provider.vim')
-rw-r--r--runtime/autoload/health/provider.vim131
1 files changed, 81 insertions, 50 deletions
diff --git a/runtime/autoload/health/provider.vim b/runtime/autoload/health/provider.vim
index 417426c101..26db5b77b7 100644
--- a/runtime/autoload/health/provider.vim
+++ b/runtime/autoload/health/provider.vim
@@ -8,6 +8,11 @@ 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
+
" Simple version comparison.
function! s:version_cmp(a, b) abort
let a = split(a:a, '\.', 0)
@@ -26,13 +31,23 @@ endfunction
" Handler for s:system() function.
function! s:system_handler(jobid, data, event) dict abort
- if a:event == 'stdout' || a:event == 'stderr'
+ if a:event ==# 'stdout' || a:event ==# 'stderr'
let self.output .= join(a:data, '')
- elseif a:event == 'exit'
+ 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 : ''
@@ -49,8 +64,7 @@ function! s:system(cmd, ...) abort
let jobid = jobstart(a:cmd, opts)
if jobid < 1
- call health#report_error(printf('Command error %d: %s', jobid,
- \ type(a:cmd) == type([]) ? join(a:cmd) : a:cmd)))
+ call health#report_error(printf('Command error (job=%d): %s', jobid, s:shellify(a:cmd)))
let s:shell_error = 1
return opts.output
endif
@@ -61,13 +75,11 @@ function! s:system(cmd, ...) abort
let res = jobwait([jobid], 30000)
if res[0] == -1
- call health#report_error(printf('Command timed out: %s',
- \ type(a:cmd) == type([]) ? join(a:cmd) : a:cmd))
+ call health#report_error(printf('Command timed out: %s', s:shellify(a:cmd)))
call jobstop(jobid)
elseif s:shell_error != 0 && !ignore_error
- call health#report_error(printf("Command error (%d) %s: %s", jobid,
- \ type(a:cmd) == type([]) ? join(a:cmd) : a:cmd,
- \ opts.output))
+ call health#report_error(printf("Command error (job=%d): %s\nOutput: %s", jobid,
+ \ s:shellify(a:cmd), opts.output))
endif
return opts.output
@@ -106,13 +118,17 @@ endfunction
" Check for clipboard tools.
function! s:check_clipboard() abort
- call health#report_start('Clipboard')
+ call health#report_start('Clipboard (optional)')
let clipboard_tool = provider#clipboard#Executable()
- if empty(clipboard_tool)
+ 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 will not work.",
- \ ['See ":help clipboard".'])
+ \ 'No clipboard tool found. Clipboard registers (`"+` and `"*`) will not work.',
+ \ [':help clipboard'])
else
call health#report_ok('Clipboard tool found: '. clipboard_tool)
endif
@@ -152,7 +168,7 @@ function! s:version_info(python) abort
\ ]))
if empty(python_version)
- let python_version = 'unable to parse python response'
+ let python_version = 'unable to parse '.a:python.' response'
endif
let nvim_path = s:trim(s:system([
@@ -164,14 +180,14 @@ function! s:version_info(python) abort
" Assuming that multiple versions of a package are installed, sort them
" numerically in descending order.
- function! s:compare(metapath1, metapath2)
+ 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(['python', '-c',
+ 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)
@@ -208,7 +224,7 @@ endfunction
" Check the Python interpreter's usability.
function! s:check_bin(bin) abort
- if !filereadable(a:bin)
+ 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
@@ -219,22 +235,28 @@ function! s:check_bin(bin) abort
endfunction
function! s:check_python(version) abort
- call health#report_start('Python ' . a:version . ' provider')
+ call health#report_start('Python ' . a:version . ' provider (optional)')
- let python_bin_name = 'python'.(a:version == 2 ? '' : '3')
+ let pyname = 'python'.(a:version == 2 ? '' : '3')
let pyenv = resolve(exepath('pyenv'))
let pyenv_root = exists('$PYENV_ROOT') ? resolve($PYENV_ROOT) : 'n'
let venv = exists('$VIRTUAL_ENV') ? resolve($VIRTUAL_ENV) : ''
- let host_prog_var = python_bin_name.'_host_prog'
+ let host_prog_var = pyname.'_host_prog'
+ let loaded_var = 'g:loaded_'.pyname.'_provider'
let python_bin = ''
let python_multiple = []
+ if exists(loaded_var) && !exists('*provider#'.pyname.'#Call')
+ call health#report_info('Disabled. '.loaded_var.'='.eval(loaded_var))
+ return
+ endif
+
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 [python_bin_name, pythonx_errs] = provider#pythonx#Detect(a:version)
- if empty(python_bin_name)
+ let [pyname, pythonx_errs] = provider#pythonx#Detect(a:version)
+ if empty(pyname)
call health#report_warn('No Python interpreter was found with the neovim '
\ . 'module. Using the first available for diagnostics.')
if !empty(pythonx_errs)
@@ -242,21 +264,21 @@ function! s:check_python(version) abort
endif
endif
- if !empty(python_bin_name)
+ if !empty(pyname)
if exists('g:'.host_prog_var)
- let python_bin = exepath(python_bin_name)
+ let python_bin = exepath(pyname)
endif
- let python_bin_name = fnamemodify(python_bin_name, ':t')
+ let pyname = fnamemodify(pyname, ':t')
endif
if !empty(pythonx_errs)
call health#report_error('Python provider error', pythonx_errs)
endif
- if !empty(python_bin_name) && empty(python_bin) && empty(pythonx_errs)
+ if !empty(pyname) && empty(python_bin) && empty(pythonx_errs)
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, python_bin_name))
+ \ . '%s in the environment.', host_prog_var, pyname))
endif
if !empty(pyenv)
@@ -269,20 +291,21 @@ function! s:check_python(version) abort
call health#report_ok(printf('pyenv found: "%s"', pyenv))
endif
- let python_bin = s:trim(s:system([pyenv, 'which', python_bin_name], '', 1))
+ let python_bin = s:trim(s:system([pyenv, 'which', pyname], '', 1))
if empty(python_bin)
- call health#report_warn(printf('pyenv could not find %s.', python_bin_name))
+ call health#report_warn(printf('pyenv could not find %s.', pyname))
endif
endif
if empty(python_bin)
- let python_bin = exepath(python_bin_name)
+ let python_bin = exepath(pyname)
if exists('$PATH')
- for path in split($PATH, ':')
- let path_bin = path.'/'.python_bin_name
- if path_bin != python_bin && index(python_multiple, path_bin) == -1
+ for path in split($PATH, has('win32') ? ';' : ':')
+ let path_bin = s:normalize_path(path.'/'.pyname)
+ if path_bin != s:normalize_path(python_bin)
+ \ && index(python_multiple, path_bin) == -1
\ && executable(path_bin)
call add(python_multiple, path_bin)
endif
@@ -292,7 +315,7 @@ function! s:check_python(version) abort
" This is worth noting since the user may install something
" that changes $PATH, like homebrew.
call health#report_info(printf('Multiple %s executables found. '
- \ . 'Set `g:%s` to avoid surprises.', python_bin_name, host_prog_var))
+ \ . 'Set `g:%s` to avoid surprises.', pyname, host_prog_var))
endif
if python_bin =~# '\<shims\>'
@@ -333,9 +356,9 @@ function! s:check_python(version) abort
endif
endif
- if empty(python_bin) && !empty(python_bin_name)
+ if empty(python_bin) && !empty(pyname)
" An error message should have already printed.
- call health#report_error(printf('`%s` was not found.', python_bin_name))
+ call health#report_error(printf('`%s` was not found.', pyname))
elseif !empty(python_bin) && !s:check_bin(python_bin)
let python_bin = ''
endif
@@ -349,7 +372,7 @@ function! s:check_python(version) abort
if $VIRTUAL_ENV != pyenv_prefix
let virtualenv_inactive = 1
endif
- elseif !empty(python_bin_name) && exepath(python_bin_name) !~# '^'.$VIRTUAL_ENV.'/'
+ elseif !empty(pyname) && exepath(pyname) !~# '^'.$VIRTUAL_ENV.'/'
let virtualenv_inactive = 1
endif
endif
@@ -381,9 +404,9 @@ function! s:check_python(version) abort
call health#report_info('Python'.a:version.' version: ' . pyversion)
if s:is_bad_response(status)
- call health#report_info(printf('%s-neovim version: %s (%s)', python_bin_name, current, status))
+ call health#report_info(printf('%s-neovim version: %s (%s)', pyname, current, status))
else
- call health#report_info(printf('%s-neovim version: %s', python_bin_name, current))
+ call health#report_info(printf('%s-neovim version: %s', pyname, current))
endif
if s:is_bad_response(current)
@@ -397,22 +420,28 @@ function! s:check_python(version) abort
call health#report_error('HTTP request failed: '.latest)
elseif s:is_bad_response(status)
call health#report_warn(printf('Latest %s-neovim is NOT installed: %s',
- \ python_bin_name, latest))
+ \ pyname, latest))
elseif !s:is_bad_response(current)
call health#report_ok(printf('Latest %s-neovim is installed: %s',
- \ python_bin_name, latest))
+ \ pyname, latest))
endif
endif
endfunction
function! s:check_ruby() abort
- call health#report_start('Ruby provider')
+ call health#report_start('Ruby provider (optional)')
+
+ let loaded_var = 'g:loaded_ruby_provider'
+ if exists(loaded_var) && !exists('*provider#ruby#Call')
+ call health#report_info('Disabled. '.loaded_var.'='.eval(loaded_var))
+ return
+ endif
if !executable('ruby') || !executable('gem')
call health#report_warn(
- \ "`ruby` and `gem` must be in $PATH.",
- \ ["Install Ruby and verify that `ruby` and `gem` commands work."])
+ \ '`ruby` and `gem` must be in $PATH.',
+ \ ['Install Ruby and verify that `ruby` and `gem` commands work.'])
return
endif
call health#report_info('Ruby: '. s:system('ruby -v'))
@@ -420,26 +449,28 @@ function! s:check_ruby() abort
let host = provider#ruby#Detect()
if empty(host)
call health#report_warn('Missing "neovim" gem.',
- \ ['Run in shell: gem install neovim'])
+ \ ['Run in shell: gem install neovim',
+ \ 'Is the gem bin directory in $PATH? Check `gem environment`.',
+ \ 'If you are using rvm/rbenv/chruby, try "rehashing".'])
return
endif
call health#report_info('Host: '. host)
- let latest_gem_cmd = 'gem list -ra ^neovim$'
+ let latest_gem_cmd = has('win32') ? 'cmd /c gem list -ra ^^neovim$' : 'gem list -ra ^neovim$'
let latest_gem = s:system(split(latest_gem_cmd))
if s:shell_error || empty(latest_gem)
call health#report_error('Failed to run: '. latest_gem_cmd,
\ ["Make sure you're connected to the internet.",
- \ "Are you behind a firewall or proxy?"])
+ \ 'Are you behind a firewall or proxy?'])
return
endif
- let latest_gem = get(split(latest_gem, ' (\|, \|)$' ), 1, 'not found')
+ let latest_gem = get(split(latest_gem, 'neovim (\|, \|)$' ), 1, 'not found')
let current_gem_cmd = host .' --version'
let current_gem = s:system(current_gem_cmd)
if s:shell_error
call health#report_error('Failed to run: '. current_gem_cmd,
- \ ["Report this issue with the output of: ", current_gem_cmd])
+ \ ['Report this issue with the output of: ', current_gem_cmd])
return
endif
@@ -449,7 +480,7 @@ function! s:check_ruby() abort
\ current_gem, latest_gem),
\ ['Run in shell: gem update neovim'])
else
- call health#report_ok('Gem "neovim" is up-to-date: '. current_gem)
+ call health#report_ok('Latest "neovim" gem is installed: '. current_gem)
endif
endfunction