fix(checkhealth): mitigate issues with duplicate healthchecks #15919

* fix(runtime/health): mitigate issues with duplicate healthchecks
  Previously if a healthcheck was found as Lua and Vim it was executed
  both times.
  This new implementations prefers Lua, therefore if two are found It only
  runs the Lua one, this way a plugin can mantain both implementations the
  Lua one with the method `check()` and the autoload function `#check()`
  (for none HEAD nvim versions).
  **Note: This will require plugins to use `check()` as the function name,
  since the autoload function that wraps the lua implementation won't be
  called**
* docs(health): use spaces and don't overuse backtics

followup to #15259
This commit is contained in:
Javier Lopez 2021-10-05 17:37:39 -05:00 committed by GitHub
parent 6a930a9dc4
commit acd5e831b6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 125 additions and 98 deletions

View File

@ -41,8 +41,8 @@ function! health#check(plugin_names) abort
call setline(1, 'ERROR: No healthchecks found.') call setline(1, 'ERROR: No healthchecks found.')
else else
redraw|echo 'Running healthchecks...' redraw|echo 'Running healthchecks...'
for c in healthchecks for name in sort(keys(healthchecks))
let [name, func, type] = c let [func, type] = healthchecks[name]
let s:output = [] let s:output = []
try try
if func == '' if func == ''
@ -176,8 +176,30 @@ function! s:discover_healthchecks() abort
return s:get_healthcheck('*') return s:get_healthcheck('*')
endfunction endfunction
" Returns list of lists [ [{name}, {func}, {type}] ] representing healthchecks " Returns Dictionary {name: [func, type], ..} representing healthchecks
function! s:get_healthcheck(plugin_names) abort 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 name = c[0]
let existent = get(healthchecks, name, [])
" If an entry with the same name exists and is from vim, prefer Lua so
" overwrite it.
if existent != []
if existent[1] == "v"
let healthchecks[name] = c[1:]
else
continue
endif
else
let healthchecks[name] = c[1:]
endif
endfor
return healthchecks
endfunction
" Returns list of lists [ [{name}, {func}, {type}] ] representing healthchecks
function! s:get_healthcheck_list(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)

View File

@ -5,7 +5,7 @@ Author: TJ DeVries <devries.timothyj@gmail.com>
Type |gO| to see the table of contents. Type |gO| to see the table of contents.
============================================================================== ==============================================================================
Introduction *health* Introduction *health*
health.vim is a minimal framework to help with troubleshooting user health.vim is a minimal framework to help with troubleshooting user
configuration. Nvim ships with healthchecks for configuration, performance, configuration. Nvim ships with healthchecks for configuration, performance,
@ -13,66 +13,66 @@ python support, ruby support, clipboard support, and more.
To run the healthchecks, use this command: > To run the healthchecks, use this command: >
:checkhealth :checkhealth
< <
Plugin authors are encouraged to write new healthchecks. |health-dev| Plugin authors are encouraged to write new healthchecks. |health-dev|
============================================================================== ==============================================================================
Commands *health-commands* Commands *health-commands*
*:checkhealth* *:CheckHealth* *:checkhealth* *:CheckHealth*
:checkhealth Run all healthchecks. :checkhealth Run all healthchecks.
*E5009* *E5009*
Nvim depends on |$VIMRUNTIME|, 'runtimepath' and 'packpath' to Nvim depends on |$VIMRUNTIME|, 'runtimepath' and 'packpath' to
find the standard "runtime files" for syntax highlighting, find the standard "runtime files" for syntax highlighting,
filetype-specific behavior, and standard plugins (including filetype-specific behavior, and standard plugins (including
:checkhealth). If the runtime files cannot be found then :checkhealth). If the runtime files cannot 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 only Run healthcheck(s) for one or more plugins. E.g. to run only
the standard Nvim healthcheck: > the standard Nvim healthcheck: >
:checkhealth nvim :checkhealth nvim
< <
To run the healthchecks for the "foo" and "bar" plugins To run the healthchecks for the "foo" and "bar" plugins
(assuming these plugins are on 'runtimepath' or 'packpath' and (assuming these plugins are on 'runtimepath' or 'packpath' and
they have implemented the Lua or Vimscript interface they have implemented the Lua or Vimscript interface
require("foo.health").check() and health#bar#check(), require("foo.health").check() and health#bar#check(),
respectively): > respectively): >
:checkhealth foo bar :checkhealth foo bar
< <
To run healthchecks for lua submodules, use dot notation or To run healthchecks for lua submodules, use dot notation or
"*" to refer to all submodules. For example nvim provides "*" to refer to all submodules. For example nvim provides
`vim.lsp` and `vim.treesitter` > `vim.lsp` and `vim.treesitter` >
:checkhealth vim.lsp vim.treesitter :checkhealth vim.lsp vim.treesitter
:checkhealth vim* :checkhealth vim*
< <
============================================================================== ==============================================================================
Lua Functions *health-functions-lua* *health-lua* Lua Functions *health-functions-lua* *health-lua*
The Lua "health" module can be used to create new healthchecks (see also The Lua "health" module can be used to create new healthchecks (see also
|health-functions-vim|). To get started, simply use: > |health-functions-vim|). To get started, simply use: >
local health = require('health') local health = require('health')
< <
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
you want different sections to appear in your report, call this once you want different sections to appear in your report, call this once
per section. per section.
health.report_info({msg}) *health.report_info()* health.report_info({msg}) *health.report_info()*
Reports an informational message. Reports an informational message.
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.
============================================================================== ==============================================================================
Create a Lua healthcheck *health-dev-lua* Create a Lua healthcheck *health-dev-lua*
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/.
@ -83,71 +83,71 @@ will automatically find and invoke this function.
If your plugin is named "foo", then its healthcheck module should be a file in If your plugin is named "foo", then its healthcheck module should be a file in
one of these locations on 'runtimepath' or 'packpath': one of these locations on 'runtimepath' or 'packpath':
- `lua/foo/health/init.lua` - lua/foo/health/init.lua
- `lua/foo/health.lua` - lua/foo/health.lua
If your plugin provides a submodule named "bar" for which you want a separate 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' healthcheck, define the healthcheck at one of these locations on 'runtimepath'
or 'packpath': or 'packpath':
- `lua/foo/bar/health/init.lua` - lua/foo/bar/health/init.lua
- `lua/foo/bar/health.lua` - lua/foo/bar/health.lua
All submodules should return a Lua table containing the method `check()`. 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`, Copy this sample code into `lua/foo/health/init.lua` or `lua/foo/health.lua`,
replacing "foo" in the path with your plugin name: > replacing "foo" in the path with your plugin name: >
local M = {} local M = {}
local health = require("health") local health = require("health")
M.check = function() M.check = function()
health.report_start("my_plugin report") health.report_start("my_plugin report")
-- make sure setup function parameters are ok -- make sure setup function parameters are ok
if check_setup() then if check_setup() then
health.report_ok("Setup function is correct") health.report_ok("Setup function is correct")
else else
health.report_error("Setup function is incorrect") health.report_error("Setup function is incorrect")
end end
-- do some more checking -- do some more checking
-- ... -- ...
end end
return M return M
============================================================================== ==============================================================================
Vimscript Functions *health-functions-vimscript* *health-vimscript* Vimscript Functions *health-functions-vimscript* *health-vimscript*
health.vim functions are for creating new healthchecks. (See also health.vim functions are for creating new healthchecks. (See also
|health-functions-lua|) |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
you want different sections to appear in your report, call this once you want different sections to appear in your report, call this once
per section. per section.
health#report_info({msg}) *health#report_info* health#report_info({msg}) *health#report_info*
Reports an informational message. Reports an informational message.
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*
Healthcheck function for {plugin}. Called by |:checkhealth| Healthcheck function for {plugin}. Called by |:checkhealth|
automatically. Example: > automatically. Example: >
function! health#my_plug#check() abort function! health#my_plug#check() abort
silent call s:check_environment_vars() silent call s:check_environment_vars()
silent call s:check_python_configuration() silent call s:check_python_configuration()
endfunction endfunction
< <
============================================================================== ==============================================================================
Create a healthcheck *health-dev-vim* 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/.
@ -157,24 +157,24 @@ health#{plugin}#check() function in autoload/health/{plugin}.vim.
|:checkhealth| automatically finds and invokes such functions. |:checkhealth| automatically finds and invokes such functions.
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' or 'packpath': > 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
plugin name: > plugin name: >
function! health#foo#check() abort function! health#foo#check() abort
call health#report_start('sanity checks') call health#report_start('sanity checks')
" perform arbitrary checks " perform arbitrary checks
" ... " ...
if looks_good if looks_good
call health#report_ok('found required dependencies') call health#report_ok('found required dependencies')
else else
call health#report_error('cannot find foo', call health#report_error('cannot find foo',
\ ['npm install --save foo']) \ ['npm install --save foo'])
endif endif
endfunction endfunction
vim:noet tw=78:ts=8:ft=help:fdm=marker vim:et:tw=78:ts=8:ft=help:fdm=marker

View File

@ -0,0 +1,3 @@
function! health#success1#check()
call health#report_start("If you see this I'm broken")
endfunction

View File

@ -100,8 +100,10 @@ describe('health.vim', function()
]]) ]])
end) end)
it("lua plugins", function() it("lua plugins, skips vimscript healthchecks with the same name", function()
command("checkhealth test_plug") command("checkhealth test_plug")
-- Existing file in test/functional/fixtures/lua/test_plug/autoload/health/test_plug.vim
-- and the Lua healthcheck is used instead.
helpers.expect([[ helpers.expect([[
test_plug: require("test_plug.health").check() test_plug: require("test_plug.health").check()