mirror of
https://github.com/neovim/neovim.git
synced 2025-10-02 16:08:36 +00:00
Merge pull request #15259 from muniter/muniter/checkhealth-from-lua
feat(checkhealth): support Lua healthchecks
This commit is contained in:
@@ -26,8 +26,8 @@ endfunction
|
|||||||
" Runs all discovered healthchecks if a:plugin_names is empty.
|
" Runs all discovered healthchecks if a:plugin_names is empty.
|
||||||
function! health#check(plugin_names) abort
|
function! health#check(plugin_names) abort
|
||||||
let healthchecks = empty(a:plugin_names)
|
let healthchecks = empty(a:plugin_names)
|
||||||
\ ? s:discover_health_checks()
|
\ ? s:discover_healthchecks()
|
||||||
\ : s:to_fn_names(a:plugin_names)
|
\ : s:get_healthcheck(a:plugin_names)
|
||||||
|
|
||||||
tabnew
|
tabnew
|
||||||
setlocal wrap breakindent linebreak
|
setlocal wrap breakindent linebreak
|
||||||
@@ -42,24 +42,28 @@ function! health#check(plugin_names) abort
|
|||||||
else
|
else
|
||||||
redraw|echo 'Running healthchecks...'
|
redraw|echo 'Running healthchecks...'
|
||||||
for c in healthchecks
|
for c in healthchecks
|
||||||
let output = ''
|
let [name, func, type] = c
|
||||||
call append('$', split(printf("\n%s\n%s", c, repeat('=',72)), "\n"))
|
let s:output = []
|
||||||
try
|
try
|
||||||
let output = "\n\n".execute('call '.c.'()')
|
if func == ''
|
||||||
|
throw 'healthcheck_not_found'
|
||||||
|
endif
|
||||||
|
eval type == 'v' ? call(func, []) : luaeval(func)
|
||||||
catch
|
catch
|
||||||
if v:exception =~# '^Vim\%((\a\+)\)\=:E117.*\V'.c
|
let s:output = [] " Clear the output
|
||||||
let output = execute(
|
if v:exception =~# 'healthcheck_not_found'
|
||||||
\ 'call health#report_error(''No healthcheck found for "'
|
call health#report_error('No healthcheck found for "'.name.'" plugin.')
|
||||||
\ .s:to_plugin_name(c)
|
|
||||||
\ .'" plugin.'')')
|
|
||||||
else
|
else
|
||||||
let output = execute(
|
call health#report_error(printf(
|
||||||
\ 'call health#report_error(''Failed to run healthcheck for "'
|
\ "Failed to run healthcheck for \"%s\" plugin. Exception:\n%s\n%s",
|
||||||
\ .s:to_plugin_name(c)
|
\ name, v:throwpoint, v:exception))
|
||||||
\ .'" plugin. Exception:''."\n".v:throwpoint."\n".v:exception)')
|
|
||||||
endif
|
endif
|
||||||
endtry
|
endtry
|
||||||
call append('$', split(output, "\n") + [''])
|
let header = [name. ': ' . func, repeat('=', 72)]
|
||||||
|
" 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
|
redraw
|
||||||
endfor
|
endfor
|
||||||
endif
|
endif
|
||||||
@@ -71,9 +75,13 @@ function! health#check(plugin_names) abort
|
|||||||
redraw|echo ''
|
redraw|echo ''
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
function! s:collect_output(output)
|
||||||
|
let s:output += split(a:output, "\n", 1)
|
||||||
|
endfunction
|
||||||
|
|
||||||
" Starts a new report.
|
" Starts a new report.
|
||||||
function! health#report_start(name) abort
|
function! health#report_start(name) abort
|
||||||
echo "\n## " . a:name
|
call s:collect_output("\n## " . a:name)
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
" Indents lines *except* line 1 of a string if it contains newlines.
|
" Indents lines *except* line 1 of a string if it contains newlines.
|
||||||
@@ -119,21 +127,21 @@ endfunction " }}}
|
|||||||
|
|
||||||
" Use {msg} to report information in the current section
|
" Use {msg} to report information in the current section
|
||||||
function! health#report_info(msg) abort " {{{
|
function! health#report_info(msg) abort " {{{
|
||||||
echo s:format_report_message('INFO', a:msg)
|
call s:collect_output(s:format_report_message('INFO', a:msg))
|
||||||
endfunction " }}}
|
endfunction " }}}
|
||||||
|
|
||||||
" Reports a successful healthcheck.
|
" Reports a successful healthcheck.
|
||||||
function! health#report_ok(msg) abort " {{{
|
function! health#report_ok(msg) abort " {{{
|
||||||
echo s:format_report_message('OK', a:msg)
|
call s:collect_output(s:format_report_message('OK', a:msg))
|
||||||
endfunction " }}}
|
endfunction " }}}
|
||||||
|
|
||||||
" Reports a health warning.
|
" Reports a health warning.
|
||||||
" a:1: Optional advice (string or list)
|
" a:1: Optional advice (string or list)
|
||||||
function! health#report_warn(msg, ...) abort " {{{
|
function! health#report_warn(msg, ...) abort " {{{
|
||||||
if a:0 > 0
|
if a:0 > 0
|
||||||
echo s:format_report_message('WARNING', a:msg, a:1)
|
call s:collect_output(s:format_report_message('WARNING', a:msg, a:1))
|
||||||
else
|
else
|
||||||
echo s:format_report_message('WARNING', a:msg)
|
call s:collect_output(s:format_report_message('WARNING', a:msg))
|
||||||
endif
|
endif
|
||||||
endfunction " }}}
|
endfunction " }}}
|
||||||
|
|
||||||
@@ -141,37 +149,52 @@ endfunction " }}}
|
|||||||
" a:1: Optional advice (string or list)
|
" a:1: Optional advice (string or list)
|
||||||
function! health#report_error(msg, ...) abort " {{{
|
function! health#report_error(msg, ...) abort " {{{
|
||||||
if a:0 > 0
|
if a:0 > 0
|
||||||
echo s:format_report_message('ERROR', a:msg, a:1)
|
call s:collect_output(s:format_report_message('ERROR', a:msg, a:1))
|
||||||
else
|
else
|
||||||
echo s:format_report_message('ERROR', a:msg)
|
call s:collect_output(s:format_report_message('ERROR', a:msg))
|
||||||
endif
|
endif
|
||||||
endfunction " }}}
|
endfunction " }}}
|
||||||
|
|
||||||
function! s:filepath_to_function(name) abort
|
" From a path return a list [{name}, {func}, {type}] representing a healthcheck
|
||||||
return substitute(substitute(substitute(a:name, '.*autoload[\/]', '', ''),
|
function! s:filepath_to_healthcheck(path) abort
|
||||||
\ '\.vim', '#check', ''), '[\/]', '#', 'g')
|
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
|
endfunction
|
||||||
|
|
||||||
function! s:discover_health_checks() abort
|
function! s:discover_healthchecks() abort
|
||||||
let healthchecks = globpath(&runtimepath, 'autoload/health/*.vim', 1, 1)
|
return s:get_healthcheck('*')
|
||||||
let healthchecks = map(healthchecks, '<SID>filepath_to_function(v:val)')
|
|
||||||
return healthchecks
|
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
" Translates a list of plugin names to healthcheck function names.
|
" Returns list of lists [ [{name}, {func}, {type}] ] representing healthchecks
|
||||||
function! s:to_fn_names(plugin_names) abort
|
function! s:get_healthcheck(plugin_names) abort
|
||||||
let healthchecks = []
|
let healthchecks = []
|
||||||
let plugin_names = type('') ==# type(a:plugin_names)
|
let plugin_names = type('') == type(a:plugin_names)
|
||||||
\ ? split(a:plugin_names, '', v:false)
|
\ ? split(a:plugin_names, ' ', v:false)
|
||||||
\ : a:plugin_names
|
\ : a:plugin_names
|
||||||
for p in plugin_names
|
for p in plugin_names
|
||||||
call add(healthchecks, 'health#'.p.'#check')
|
" 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, '', '']] " healthchek not found
|
||||||
|
else
|
||||||
|
let healthchecks += map(uniq(sort(paths)),
|
||||||
|
\'<SID>filepath_to_healthcheck(v:val)')
|
||||||
|
end
|
||||||
endfor
|
endfor
|
||||||
return healthchecks
|
return healthchecks
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
" Extracts 'foo' from 'health#foo#check'.
|
|
||||||
function! s:to_plugin_name(fn_name) abort
|
|
||||||
return substitute(a:fn_name,
|
|
||||||
\ '\v.*health\#(.+)\#check.*', '\1', '')
|
|
||||||
endfunction
|
|
||||||
|
@@ -23,27 +23,102 @@ Commands *health-commands*
|
|||||||
*:checkhealth* *:CheckHealth*
|
*:checkhealth* *:CheckHealth*
|
||||||
:checkhealth Run all healthchecks.
|
:checkhealth Run all healthchecks.
|
||||||
*E5009*
|
*E5009*
|
||||||
Nvim depends on |$VIMRUNTIME| and 'runtimepath' to find
|
Nvim depends on |$VIMRUNTIME|, 'runtimepath' and 'packpath' to
|
||||||
the standard "runtime files" for syntax highlighting,
|
find the standard "runtime files" for syntax highlighting,
|
||||||
filetype-specific behavior, and standard plugins
|
filetype-specific behavior, and standard plugins (including
|
||||||
(including :checkhealth). If the runtime files cannot
|
:checkhealth). If the runtime files cannot be found then
|
||||||
be found then those features will not work.
|
those features will not work.
|
||||||
|
|
||||||
:checkhealth {plugins}
|
:checkhealth {plugins}
|
||||||
Run healthcheck(s) for one or more plugins. E.g. to run
|
Run healthcheck(s) for one or more plugins. E.g. to run only
|
||||||
only the standard Nvim healthcheck: >
|
the standard Nvim healthcheck: >
|
||||||
:checkhealth nvim
|
:checkhealth nvim
|
||||||
< To run the healthchecks for the "foo" and "bar" plugins
|
<
|
||||||
(assuming these plugins are on your 'runtimepath' and
|
To run the healthchecks for the "foo" and "bar" plugins
|
||||||
they have implemented health#foo#check() and
|
(assuming these plugins are on 'runtimepath' or 'packpath' and
|
||||||
health#bar#check(), respectively): >
|
they have implemented the Lua or Vimscript interface
|
||||||
|
require("foo.health").check() and health#bar#check(),
|
||||||
|
respectively): >
|
||||||
:checkhealth foo bar
|
:checkhealth foo bar
|
||||||
|
<
|
||||||
|
To run healthchecks for lua submodules, use dot notation or
|
||||||
|
"*" to refer to all submodules. For example nvim provides
|
||||||
|
`vim.lsp` and `vim.treesitter` >
|
||||||
|
:checkhealth vim.lsp vim.treesitter
|
||||||
|
:checkhealth vim*
|
||||||
<
|
<
|
||||||
==============================================================================
|
==============================================================================
|
||||||
Functions *health-functions*
|
Lua Functions *health-functions-lua* *health-lua*
|
||||||
|
|
||||||
health.vim functions are for creating new healthchecks. They mostly just do
|
The Lua "health" module can be used to create new healthchecks (see also
|
||||||
some layout and formatting, to give users a consistent presentation.
|
|health-functions-vim|). To get started, simply use: >
|
||||||
|
local health = require('health')
|
||||||
|
<
|
||||||
|
health.report_start({name}) *health.report_start()*
|
||||||
|
Starts a new report. Most plugins should call this only once, but if
|
||||||
|
you want different sections to appear in your report, call this once
|
||||||
|
per section.
|
||||||
|
|
||||||
|
health.report_info({msg}) *health.report_info()*
|
||||||
|
Reports an informational message.
|
||||||
|
|
||||||
|
health.report_ok({msg}) *health.report_ok()*
|
||||||
|
Reports a "success" message.
|
||||||
|
|
||||||
|
health.report_warn({msg} [, {advice}]) *health.report_warn()*
|
||||||
|
Reports a warning. {advice} is an optional List of suggestions.
|
||||||
|
|
||||||
|
health.report_error({msg} [, {advice}]) *health.report_error()*
|
||||||
|
Reports an error. {advice} is an optional List of suggestions.
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
Create a Lua healthcheck *health-dev-lua*
|
||||||
|
|
||||||
|
Healthchecks are functions that check the user environment, configuration,
|
||||||
|
etc. Nvim has built-in healthchecks in $VIMRUNTIME/autoload/health/.
|
||||||
|
|
||||||
|
To add a new healthcheck for your own plugin, simply define a Lua module in
|
||||||
|
your plugin that returns a table with a "check()" function. |:checkhealth|
|
||||||
|
will automatically find and invoke this function.
|
||||||
|
|
||||||
|
If your plugin is named "foo", then its healthcheck module should be a file in
|
||||||
|
one of these locations on 'runtimepath' or 'packpath':
|
||||||
|
- `lua/foo/health/init.lua`
|
||||||
|
- `lua/foo/health.lua`
|
||||||
|
|
||||||
|
If your plugin provides a submodule named "bar" for which you want a separate
|
||||||
|
healthcheck, define the healthcheck at one of these locations on 'runtimepath'
|
||||||
|
or 'packpath':
|
||||||
|
- `lua/foo/bar/health/init.lua`
|
||||||
|
- `lua/foo/bar/health.lua`
|
||||||
|
|
||||||
|
All submodules should return a Lua table containing the method `check()`.
|
||||||
|
|
||||||
|
Copy this sample code into `lua/foo/health/init.lua` or `lua/foo/health.lua`,
|
||||||
|
replacing "foo" in the path with your plugin name: >
|
||||||
|
|
||||||
|
local M = {}
|
||||||
|
local health = require("health")
|
||||||
|
|
||||||
|
M.check = function()
|
||||||
|
health.report_start("my_plugin report")
|
||||||
|
-- make sure setup function parameters are ok
|
||||||
|
if check_setup() then
|
||||||
|
health.report_ok("Setup function is correct")
|
||||||
|
else
|
||||||
|
health.report_error("Setup function is incorrect")
|
||||||
|
end
|
||||||
|
-- do some more checking
|
||||||
|
-- ...
|
||||||
|
end
|
||||||
|
|
||||||
|
return M
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
Vimscript Functions *health-functions-vimscript* *health-vimscript*
|
||||||
|
|
||||||
|
health.vim functions are for creating new healthchecks. (See also
|
||||||
|
|health-functions-lua|)
|
||||||
|
|
||||||
health#report_start({name}) *health#report_start*
|
health#report_start({name}) *health#report_start*
|
||||||
Starts a new report. Most plugins should call this only once, but if
|
Starts a new report. Most plugins should call this only once, but if
|
||||||
@@ -56,10 +131,10 @@ health#report_info({msg}) *health#report_info*
|
|||||||
health#report_ok({msg}) *health#report_ok*
|
health#report_ok({msg}) *health#report_ok*
|
||||||
Reports a "success" message.
|
Reports a "success" message.
|
||||||
|
|
||||||
health#report_warn({msg}, [{advice}]) *health#report_warn*
|
health#report_warn({msg} [, {advice}]) *health#report_warn*
|
||||||
Reports a warning. {advice} is an optional List of suggestions.
|
Reports a warning. {advice} is an optional List of suggestions.
|
||||||
|
|
||||||
health#report_error({msg}, [{advice}]) *health#report_error*
|
health#report_error({msg} [, {advice}]) *health#report_error*
|
||||||
Reports an error. {advice} is an optional List of suggestions.
|
Reports an error. {advice} is an optional List of suggestions.
|
||||||
|
|
||||||
health#{plugin}#check() *health.user_checker*
|
health#{plugin}#check() *health.user_checker*
|
||||||
@@ -71,12 +146,8 @@ health#{plugin}#check() *health.user_checker*
|
|||||||
silent call s:check_python_configuration()
|
silent call s:check_python_configuration()
|
||||||
endfunction
|
endfunction
|
||||||
<
|
<
|
||||||
All output will be captured from the healthcheck. Use the
|
|
||||||
health#report_* functions so that your healthcheck has a format
|
|
||||||
consistent with the standard healthchecks.
|
|
||||||
|
|
||||||
==============================================================================
|
==============================================================================
|
||||||
Create a healthcheck *health-dev*
|
Create a healthcheck *health-dev-vim*
|
||||||
|
|
||||||
Healthchecks are functions that check the user environment, configuration,
|
Healthchecks are functions that check the user environment, configuration,
|
||||||
etc. Nvim has built-in healthchecks in $VIMRUNTIME/autoload/health/.
|
etc. Nvim has built-in healthchecks in $VIMRUNTIME/autoload/health/.
|
||||||
@@ -88,7 +159,7 @@ health#{plugin}#check() function in autoload/health/{plugin}.vim.
|
|||||||
If your plugin is named "foo", then its healthcheck function must be >
|
If your plugin is named "foo", then its healthcheck function must be >
|
||||||
health#foo#check()
|
health#foo#check()
|
||||||
|
|
||||||
defined in this file on 'runtimepath': >
|
defined in this file on 'runtimepath' or 'packpath': >
|
||||||
autoload/health/foo.vim
|
autoload/health/foo.vim
|
||||||
|
|
||||||
Copy this sample code into autoload/health/foo.vim and replace "foo" with your
|
Copy this sample code into autoload/health/foo.vim and replace "foo" with your
|
||||||
@@ -106,6 +177,4 @@ plugin name: >
|
|||||||
endif
|
endif
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
==============================================================================
|
vim:noet tw=78:ts=8:ft=help:fdm=marker
|
||||||
|
|
||||||
vim:tw=78:ts=8:ft=help:fdm=marker
|
|
||||||
|
23
runtime/lua/health.lua
Normal file
23
runtime/lua/health.lua
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
local M = {}
|
||||||
|
|
||||||
|
function M.report_start(msg)
|
||||||
|
vim.fn['health#report_start'](msg)
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.report_info(msg)
|
||||||
|
vim.fn['health#report_info'](msg)
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.report_ok(msg)
|
||||||
|
vim.fn['health#report_ok'](msg)
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.report_warn(msg, ...)
|
||||||
|
vim.fn['health#report_warn'](msg, ...)
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.report_error(msg, ...)
|
||||||
|
vim.fn['health#report_error'](msg, ...)
|
||||||
|
end
|
||||||
|
|
||||||
|
return M
|
@@ -230,7 +230,22 @@ static int compl_match_arraysize;
|
|||||||
static int compl_startcol;
|
static int compl_startcol;
|
||||||
static int compl_selected;
|
static int compl_selected;
|
||||||
|
|
||||||
|
/// |:checkhealth| completion items
|
||||||
|
///
|
||||||
|
/// Regenerates on every new command line prompt, to accomodate changes on the
|
||||||
|
/// runtime files.
|
||||||
|
typedef struct {
|
||||||
|
garray_T names; // healthcheck names
|
||||||
|
unsigned last_gen; // last_prompt_id where names were generated
|
||||||
|
} CheckhealthComp;
|
||||||
|
|
||||||
|
/// Cookie used when converting filepath to name
|
||||||
|
struct healthchecks_cookie {
|
||||||
|
garray_T *names; // global healthchecks
|
||||||
|
bool is_lua; // true if the current entry is a Lua healthcheck
|
||||||
|
};
|
||||||
|
|
||||||
|
static CheckhealthComp healthchecks = { GA_INIT(sizeof(char_u *), 10), 0 };
|
||||||
|
|
||||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||||
# include "ex_getln.c.generated.h"
|
# include "ex_getln.c.generated.h"
|
||||||
@@ -273,6 +288,68 @@ static void init_incsearch_state(incsearch_state_T *s)
|
|||||||
save_viewstate(&s->old_viewstate);
|
save_viewstate(&s->old_viewstate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Completion for |:checkhealth| command.
|
||||||
|
///
|
||||||
|
/// Given to ExpandGeneric() to obtain all available heathcheck names.
|
||||||
|
/// @param[in] idx Index of the healthcheck item.
|
||||||
|
/// @param[in] xp Not used.
|
||||||
|
static char_u *get_healthcheck_names(expand_T *xp, int idx)
|
||||||
|
{
|
||||||
|
// Generate the first time or on new prompt.
|
||||||
|
if (healthchecks.last_gen == 0 || healthchecks.last_gen != last_prompt_id) {
|
||||||
|
ga_clear_strings(&healthchecks.names);
|
||||||
|
char *patterns[3] = { "autoload/health/**.vim", "lua/**/**/health/init.lua", // NOLINT
|
||||||
|
"lua/**/**/health.lua" }; // NOLINT
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
struct healthchecks_cookie hcookie = { .names = &healthchecks.names, .is_lua = i != 0 };
|
||||||
|
do_in_runtimepath((char_u *)patterns[i], DIP_ALL, get_healthcheck_cb, &hcookie);
|
||||||
|
|
||||||
|
if (healthchecks.names.ga_len > 0) {
|
||||||
|
ga_remove_duplicate_strings(&healthchecks.names);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Tracked to regenerate items on next prompt.
|
||||||
|
healthchecks.last_gen = last_prompt_id;
|
||||||
|
}
|
||||||
|
return idx <
|
||||||
|
(int)healthchecks.names.ga_len ? ((char_u **)(healthchecks.names.ga_data))[idx] : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Transform healthcheck file path into it's name.
|
||||||
|
///
|
||||||
|
/// Used as a callback for do_in_runtimepath
|
||||||
|
/// @param[in] path Expanded path to a possible healthcheck.
|
||||||
|
/// @param[out] cookie Array where names will be inserted.
|
||||||
|
static void get_healthcheck_cb(char_u *path, void *cookie)
|
||||||
|
{
|
||||||
|
if (path != NULL) {
|
||||||
|
struct healthchecks_cookie *hcookie = (struct healthchecks_cookie *)cookie;
|
||||||
|
char *pattern;
|
||||||
|
char *sub = "\\1";
|
||||||
|
char_u *res;
|
||||||
|
|
||||||
|
if (hcookie->is_lua) {
|
||||||
|
// Lua: transform "../lua/vim/lsp/health.lua" into "vim.lsp"
|
||||||
|
pattern = ".*lua[\\/]\\(.\\{-}\\)[\\/]health\\([\\/]init\\)\\?\\.lua$";
|
||||||
|
} else {
|
||||||
|
// Vim: transform "../autoload/health/provider.vim" into "provider"
|
||||||
|
pattern = ".*[\\/]\\([^\\/]*\\)\\.vim$";
|
||||||
|
}
|
||||||
|
|
||||||
|
res = do_string_sub(path, (char_u *)pattern, (char_u *)sub, NULL, (char_u *)"g");
|
||||||
|
if (hcookie->is_lua && res != NULL) {
|
||||||
|
// Replace slashes with dots as represented by the healthcheck plugin.
|
||||||
|
char_u *ares = do_string_sub(res, (char_u *)"[\\/]", (char_u *)".", NULL, (char_u *)"g");
|
||||||
|
xfree(res);
|
||||||
|
res = ares;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res != NULL) {
|
||||||
|
GA_APPEND(char_u *, hcookie->names, res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Return true when 'incsearch' highlighting is to be done.
|
// Return true when 'incsearch' highlighting is to be done.
|
||||||
// Sets search_first_line and search_last_line to the address range.
|
// Sets search_first_line and search_last_line to the address range.
|
||||||
static bool do_incsearch_highlighting(int firstc, int *search_delim, incsearch_state_T *s,
|
static bool do_incsearch_highlighting(int firstc, int *search_delim, incsearch_state_T *s,
|
||||||
@@ -4902,10 +4979,6 @@ static int ExpandFromContext(expand_T *xp, char_u *pat, int *num_file, char_u **
|
|||||||
char *directories[] = { "syntax", "indent", "ftplugin", NULL };
|
char *directories[] = { "syntax", "indent", "ftplugin", NULL };
|
||||||
return ExpandRTDir(pat, DIP_LUA, num_file, file, directories);
|
return ExpandRTDir(pat, DIP_LUA, num_file, file, directories);
|
||||||
}
|
}
|
||||||
if (xp->xp_context == EXPAND_CHECKHEALTH) {
|
|
||||||
char *directories[] = { "autoload/health", NULL };
|
|
||||||
return ExpandRTDir(pat, 0, num_file, file, directories);
|
|
||||||
}
|
|
||||||
if (xp->xp_context == EXPAND_USER_LIST) {
|
if (xp->xp_context == EXPAND_USER_LIST) {
|
||||||
return ExpandUserList(xp, num_file, file);
|
return ExpandUserList(xp, num_file, file);
|
||||||
}
|
}
|
||||||
@@ -4982,6 +5055,7 @@ static int ExpandFromContext(expand_T *xp, char_u *pat, int *num_file, char_u **
|
|||||||
{ EXPAND_ENV_VARS, get_env_name, true, true },
|
{ EXPAND_ENV_VARS, get_env_name, true, true },
|
||||||
{ EXPAND_USER, get_users, true, false },
|
{ EXPAND_USER, get_users, true, false },
|
||||||
{ EXPAND_ARGLIST, get_arglist_name, true, false },
|
{ EXPAND_ARGLIST, get_arglist_name, true, false },
|
||||||
|
{ EXPAND_CHECKHEALTH, get_healthcheck_names, true, false },
|
||||||
};
|
};
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
8
test/functional/fixtures/autoload/health/full_render.vim
Normal file
8
test/functional/fixtures/autoload/health/full_render.vim
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
function! health#full_render#check()
|
||||||
|
call health#report_start("report 1")
|
||||||
|
call health#report_ok("life is fine")
|
||||||
|
call health#report_warn("no what installed", ["pip what", "make what"])
|
||||||
|
call health#report_start("report 2")
|
||||||
|
call health#report_info("stuff is stable")
|
||||||
|
call health#report_error("why no hardcopy", [":h :hardcopy", ":h :TOhtml"])
|
||||||
|
endfunction
|
11
test/functional/fixtures/lua/test_plug/health/init.lua
Normal file
11
test/functional/fixtures/lua/test_plug/health/init.lua
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
local M = {}
|
||||||
|
local health = require("health")
|
||||||
|
|
||||||
|
M.check = function()
|
||||||
|
health.report_start("report 1")
|
||||||
|
health.report_ok("everything is fine")
|
||||||
|
health.report_start("report 2")
|
||||||
|
health.report_ok("nothing to see here")
|
||||||
|
end
|
||||||
|
|
||||||
|
return M
|
11
test/functional/fixtures/lua/test_plug/submodule/health.lua
Normal file
11
test/functional/fixtures/lua/test_plug/submodule/health.lua
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
local M = {}
|
||||||
|
local health = require("health")
|
||||||
|
|
||||||
|
M.check = function()
|
||||||
|
health.report_start("report 1")
|
||||||
|
health.report_ok("everything is fine")
|
||||||
|
health.report_start("report 2")
|
||||||
|
health.report_ok("nothing to see here")
|
||||||
|
end
|
||||||
|
|
||||||
|
return M
|
@@ -0,0 +1,12 @@
|
|||||||
|
local M = {}
|
||||||
|
local health = require("health")
|
||||||
|
|
||||||
|
M.check = function()
|
||||||
|
health.report_start("report 1")
|
||||||
|
health.report_ok("everything is fine")
|
||||||
|
health.report_warn("About to add a number to nil")
|
||||||
|
local a = nil + 2
|
||||||
|
return a
|
||||||
|
end
|
||||||
|
|
||||||
|
return M
|
@@ -1,4 +1,5 @@
|
|||||||
local helpers = require('test.functional.helpers')(after_each)
|
local helpers = require('test.functional.helpers')(after_each)
|
||||||
|
local global_helpers = require('test.helpers')
|
||||||
local Screen = require('test.functional.ui.screen')
|
local Screen = require('test.functional.ui.screen')
|
||||||
|
|
||||||
local clear = helpers.clear
|
local clear = helpers.clear
|
||||||
@@ -35,6 +36,7 @@ describe(':checkhealth', function()
|
|||||||
clear()
|
clear()
|
||||||
eq('nvim', getcompletion('nvim', 'checkhealth')[1])
|
eq('nvim', getcompletion('nvim', 'checkhealth')[1])
|
||||||
eq('provider', getcompletion('prov', 'checkhealth')[1])
|
eq('provider', getcompletion('prov', 'checkhealth')[1])
|
||||||
|
eq('vim.lsp', getcompletion('vim.ls', 'checkhealth')[1])
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
@@ -48,42 +50,34 @@ describe('health.vim', function()
|
|||||||
command("set runtimepath+=test/functional/fixtures")
|
command("set runtimepath+=test/functional/fixtures")
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it("health#report_*()", function()
|
|
||||||
helpers.source([[
|
|
||||||
let g:health_report = execute([
|
|
||||||
\ "call health#report_start('Check Bar')",
|
|
||||||
\ "call health#report_ok('Bar status')",
|
|
||||||
\ "call health#report_ok('Other Bar status')",
|
|
||||||
\ "call health#report_warn('Zub')",
|
|
||||||
\ "call health#report_start('Baz')",
|
|
||||||
\ "call health#report_warn('Zim', ['suggestion 1', 'suggestion 2'])"
|
|
||||||
\ ])
|
|
||||||
]])
|
|
||||||
local result = helpers.eval("g:health_report")
|
|
||||||
|
|
||||||
helpers.eq(helpers.dedent([[
|
|
||||||
|
|
||||||
|
|
||||||
## Check Bar
|
|
||||||
- OK: Bar status
|
|
||||||
- OK: Other Bar status
|
|
||||||
- WARNING: Zub
|
|
||||||
|
|
||||||
## Baz
|
|
||||||
- WARNING: Zim
|
|
||||||
- ADVICE:
|
|
||||||
- suggestion 1
|
|
||||||
- suggestion 2]]),
|
|
||||||
result)
|
|
||||||
end)
|
|
||||||
|
|
||||||
|
|
||||||
describe(":checkhealth", function()
|
describe(":checkhealth", function()
|
||||||
it("concatenates multiple reports", function()
|
it("functions health#report_*() render correctly", function()
|
||||||
command("checkhealth success1 success2")
|
command("checkhealth full_render")
|
||||||
helpers.expect([[
|
helpers.expect([[
|
||||||
|
|
||||||
health#success1#check
|
full_render: health#full_render#check
|
||||||
|
========================================================================
|
||||||
|
## report 1
|
||||||
|
- OK: life is fine
|
||||||
|
- WARNING: no what installed
|
||||||
|
- ADVICE:
|
||||||
|
- pip what
|
||||||
|
- make what
|
||||||
|
|
||||||
|
## report 2
|
||||||
|
- INFO: stuff is stable
|
||||||
|
- ERROR: why no hardcopy
|
||||||
|
- ADVICE:
|
||||||
|
- :help |:hardcopy|
|
||||||
|
- :help |:TOhtml|
|
||||||
|
]])
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("concatenates multiple reports", function()
|
||||||
|
command("checkhealth success1 success2 test_plug")
|
||||||
|
helpers.expect([[
|
||||||
|
|
||||||
|
success1: health#success1#check
|
||||||
========================================================================
|
========================================================================
|
||||||
## report 1
|
## report 1
|
||||||
- OK: everything is fine
|
- OK: everything is fine
|
||||||
@@ -91,25 +85,109 @@ describe('health.vim', function()
|
|||||||
## report 2
|
## report 2
|
||||||
- OK: nothing to see here
|
- OK: nothing to see here
|
||||||
|
|
||||||
health#success2#check
|
success2: health#success2#check
|
||||||
========================================================================
|
========================================================================
|
||||||
## another 1
|
## another 1
|
||||||
- OK: ok
|
- OK: ok
|
||||||
|
|
||||||
|
test_plug: require("test_plug.health").check()
|
||||||
|
========================================================================
|
||||||
|
## report 1
|
||||||
|
- OK: everything is fine
|
||||||
|
|
||||||
|
## report 2
|
||||||
|
- OK: nothing to see here
|
||||||
]])
|
]])
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
it("lua plugins", function()
|
||||||
|
command("checkhealth test_plug")
|
||||||
|
helpers.expect([[
|
||||||
|
|
||||||
|
test_plug: require("test_plug.health").check()
|
||||||
|
========================================================================
|
||||||
|
## report 1
|
||||||
|
- OK: everything is fine
|
||||||
|
|
||||||
|
## report 2
|
||||||
|
- OK: nothing to see here
|
||||||
|
]])
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("lua plugins submodules", function()
|
||||||
|
command("checkhealth test_plug.submodule")
|
||||||
|
helpers.expect([[
|
||||||
|
|
||||||
|
test_plug.submodule: require("test_plug.submodule.health").check()
|
||||||
|
========================================================================
|
||||||
|
## report 1
|
||||||
|
- OK: everything is fine
|
||||||
|
|
||||||
|
## report 2
|
||||||
|
- OK: nothing to see here
|
||||||
|
]])
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("lua plugins submodules with expression '*'", function()
|
||||||
|
command("checkhealth test_plug*")
|
||||||
|
local buf_lines = helpers.curbuf('get_lines', 0, -1, true)
|
||||||
|
-- avoid dealing with path separators
|
||||||
|
local received = table.concat(buf_lines, '\n', 1, #buf_lines - 2)
|
||||||
|
local expected = helpers.dedent([[
|
||||||
|
|
||||||
|
test_plug: require("test_plug.health").check()
|
||||||
|
========================================================================
|
||||||
|
## report 1
|
||||||
|
- OK: everything is fine
|
||||||
|
|
||||||
|
## report 2
|
||||||
|
- OK: nothing to see here
|
||||||
|
|
||||||
|
test_plug.submodule: require("test_plug.submodule.health").check()
|
||||||
|
========================================================================
|
||||||
|
## report 1
|
||||||
|
- OK: everything is fine
|
||||||
|
|
||||||
|
## report 2
|
||||||
|
- OK: nothing to see here
|
||||||
|
|
||||||
|
test_plug.submodule_failed: require("test_plug.submodule_failed.health").check()
|
||||||
|
========================================================================
|
||||||
|
- ERROR: Failed to run healthcheck for "test_plug.submodule_failed" plugin. Exception:
|
||||||
|
function health#check, line 24]])
|
||||||
|
eq(expected, received)
|
||||||
|
end)
|
||||||
|
|
||||||
it("gracefully handles broken healthcheck", function()
|
it("gracefully handles broken healthcheck", function()
|
||||||
command("checkhealth broken")
|
command("checkhealth broken")
|
||||||
helpers.expect([[
|
helpers.expect([[
|
||||||
|
|
||||||
health#broken#check
|
broken: health#broken#check
|
||||||
========================================================================
|
========================================================================
|
||||||
- ERROR: Failed to run healthcheck for "broken" plugin. Exception:
|
- ERROR: Failed to run healthcheck for "broken" plugin. Exception:
|
||||||
function health#check[21]..health#broken#check, line 1
|
function health#check[24]..health#broken#check, line 1
|
||||||
caused an error
|
caused an error
|
||||||
]])
|
]])
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
it("gracefully handles broken lua healthcheck", function()
|
||||||
|
command("checkhealth test_plug.submodule_failed")
|
||||||
|
local buf_lines = helpers.curbuf('get_lines', 0, -1, true)
|
||||||
|
local received = table.concat(buf_lines, '\n', 1, #buf_lines - 2)
|
||||||
|
-- avoid dealing with path separators
|
||||||
|
local lua_err = "attempt to perform arithmetic on a nil value"
|
||||||
|
local last_line = buf_lines[#buf_lines - 1]
|
||||||
|
assert(string.find(last_line, lua_err) ~= nil, "Lua error not present")
|
||||||
|
|
||||||
|
local expected = global_helpers.dedent([[
|
||||||
|
|
||||||
|
test_plug.submodule_failed: require("test_plug.submodule_failed.health").check()
|
||||||
|
========================================================================
|
||||||
|
- ERROR: Failed to run healthcheck for "test_plug.submodule_failed" plugin. Exception:
|
||||||
|
function health#check, line 24]])
|
||||||
|
eq(expected, received)
|
||||||
|
end)
|
||||||
|
|
||||||
it("highlights OK, ERROR", function()
|
it("highlights OK, ERROR", function()
|
||||||
local screen = Screen.new(72, 10)
|
local screen = Screen.new(72, 10)
|
||||||
screen:attach()
|
screen:attach()
|
||||||
@@ -126,11 +204,11 @@ describe('health.vim', function()
|
|||||||
command("set laststatus=0")
|
command("set laststatus=0")
|
||||||
screen:expect{grid=[[
|
screen:expect{grid=[[
|
||||||
^ |
|
^ |
|
||||||
{Heading:health#foo#check} |
|
{Heading:foo: } |
|
||||||
{Bar:========================================================================}|
|
{Bar:========================================================================}|
|
||||||
{Bullet: -} {Error:ERROR:} No healthcheck found for "foo" plugin. |
|
{Bullet: -} {Error:ERROR:} No healthcheck found for "foo" plugin. |
|
||||||
|
|
|
|
||||||
{Heading:health#success1#check} |
|
{Heading:success1: health#success1#check} |
|
||||||
{Bar:========================================================================}|
|
{Bar:========================================================================}|
|
||||||
{Heading2:##}{Heading: report 1} |
|
{Heading2:##}{Heading: report 1} |
|
||||||
{Bullet: -} {Ok:OK:} everything is fine |
|
{Bullet: -} {Ok:OK:} everything is fine |
|
||||||
@@ -140,9 +218,10 @@ describe('health.vim', function()
|
|||||||
|
|
||||||
it("gracefully handles invalid healthcheck", function()
|
it("gracefully handles invalid healthcheck", function()
|
||||||
command("checkhealth non_existent_healthcheck")
|
command("checkhealth non_existent_healthcheck")
|
||||||
|
-- luacheck: ignore 613
|
||||||
helpers.expect([[
|
helpers.expect([[
|
||||||
|
|
||||||
health#non_existent_healthcheck#check
|
non_existent_healthcheck:
|
||||||
========================================================================
|
========================================================================
|
||||||
- ERROR: No healthcheck found for "non_existent_healthcheck" plugin.
|
- ERROR: No healthcheck found for "non_existent_healthcheck" plugin.
|
||||||
]])
|
]])
|
||||||
|
Reference in New Issue
Block a user