mirror of
https://github.com/neovim/neovim.git
synced 2026-05-06 08:26:45 -04:00
test: lint EXX error codes #8155
Problem: - Choosing a new EXX error code is tedious. - It's possible to accidentally use an EXX error code for different purposes. Solution: Add a lint check which requires EXX error codes to have a :help tag. This also avoids duplicates because `make doc` does `:helptags ++t doc` which fails if duplicates are found.
This commit is contained in:
@@ -27,5 +27,8 @@ jobs:
|
||||
git diff --color --exit-code
|
||||
fi
|
||||
|
||||
- name: Validate docs
|
||||
- name: lintdoc
|
||||
run: make lintdoc
|
||||
|
||||
- name: linterrcodes
|
||||
run: make linterrcodes
|
||||
|
||||
@@ -288,6 +288,11 @@ add_custom_target(lintcommit
|
||||
COMMAND $<TARGET_FILE:nvim_bin> --clean -l ${PROJECT_SOURCE_DIR}/scripts/lintcommit.lua main)
|
||||
add_dependencies(lintcommit nvim_bin)
|
||||
|
||||
add_custom_target(linterrcodes
|
||||
COMMAND $<TARGET_FILE:nvim_bin> --clean -l ${PROJECT_SOURCE_DIR}/scripts/linterrcodes.lua
|
||||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR})
|
||||
add_dependencies(linterrcodes nvim_bin)
|
||||
|
||||
add_custom_target(lint)
|
||||
add_dependencies(lint lintc lintlua lintsh lintquery)
|
||||
|
||||
|
||||
@@ -147,7 +147,7 @@ functionaltest-lua: | nvim
|
||||
$(CMAKE) --build build --target functionaltest
|
||||
|
||||
FORMAT=formatc formatlua formatquery format
|
||||
LINT=lintlua lintsh lintc clang-analyzer lintcommit lintdoc lintdocurls lint luals lintquery
|
||||
LINT=lintlua lintsh lintc clang-analyzer lintcommit lintdoc lintdocurls lint luals lintquery linterrcodes
|
||||
TEST=functionaltest unittest
|
||||
generated-sources benchmark $(FORMAT) $(LINT) $(TEST) doc: | build/.ran-cmake
|
||||
$(CMAKE) --build build --target $@
|
||||
|
||||
+1
-1
@@ -408,7 +408,7 @@ after adding them, the returned |extmark| id can be used. >lua
|
||||
See also |vim.hl.range()|.
|
||||
|
||||
==============================================================================
|
||||
Floating windows *api-floatwin* *floating-windows*
|
||||
Floating windows *api-floatwin* *floating-windows* *E5601* *E5602*
|
||||
|
||||
Floating windows ("floats") are displayed on top of normal windows. This is
|
||||
useful to implement simple widgets, such as tooltips displayed next to the
|
||||
|
||||
@@ -20,7 +20,7 @@ files matching `*.c`. You can also use autocommands to implement advanced
|
||||
features, such as editing compressed files (see |gzip-example|). The usual
|
||||
place to put autocommands is in your vimrc file.
|
||||
|
||||
*E203* *E204* *E143* *E855* *E937* *E952*
|
||||
*E203* *E204* *E143* *E855* *E937* *E952* *E1312*
|
||||
WARNING: Using autocommands is very powerful, and may lead to unexpected side
|
||||
effects. Be careful not to destroy your text.
|
||||
- It's a good idea to do some testing on an expendable copy of a file first.
|
||||
@@ -201,7 +201,7 @@ was last defined. Example: >
|
||||
See |:verbose-cmd| for more information.
|
||||
|
||||
==============================================================================
|
||||
5. Events *autocmd-events* *E215* *E216*
|
||||
5. Events *autocmd-events* *E215* *E216* *E1155*
|
||||
|
||||
You can specify a comma-separated list of event names. No white space can be
|
||||
used in this list. The command applies to all the events in the list.
|
||||
@@ -711,7 +711,7 @@ FocusGained Nvim got focus.
|
||||
*FocusLost*
|
||||
FocusLost Nvim lost focus. Also (potentially) when
|
||||
a GUI dialog pops up.
|
||||
*FuncUndefined*
|
||||
*FuncUndefined* *E454*
|
||||
FuncUndefined When a user function is used but it isn't
|
||||
defined. Useful for defining a function only
|
||||
when it's used. The pattern is matched
|
||||
|
||||
@@ -42,7 +42,7 @@ Channels opened by Vimscript functions operate with raw bytes by default. For
|
||||
a job channel using RPC, bytes can still be read over its stderr. Similarly,
|
||||
only bytes can be written to Nvim's own stderr.
|
||||
|
||||
*channel-callback*
|
||||
*channel-callback* *E904* *E906* *E921* *E5407*
|
||||
- on_stdout({chan-id}, {data}, {name}) *on_stdout*
|
||||
- on_stderr({chan-id}, {data}, {name}) *on_stderr*
|
||||
- on_stdin({chan-id}, {data}, {name}) *on_stdin*
|
||||
|
||||
@@ -1184,7 +1184,7 @@ variable, it needs to be preceded by a backslash. Therefore you need to use
|
||||
Also see |`=|.
|
||||
|
||||
==============================================================================
|
||||
7. Command-line window *cmdline-window* *cmdwin*
|
||||
7. Command-line window *cmdline-window* *cmdwin* *E1292*
|
||||
*command-line-window*
|
||||
In the command-line window the command line can be edited just like editing
|
||||
text in any window. It is a special kind of window, because you cannot leave
|
||||
|
||||
+35
-21
@@ -80,8 +80,8 @@ include the kitchen sink... but it's good for plumbing."
|
||||
==============================================================================
|
||||
Developer guidelines *dev-guidelines*
|
||||
|
||||
|
||||
PROVIDERS *dev-provider*
|
||||
------------------------------------------------------------------------------
|
||||
Providers *dev-provider*
|
||||
|
||||
A primary goal of Nvim is to allow extension of the editor without special
|
||||
knowledge in the core. Some core functions are delegated to "providers"
|
||||
@@ -123,7 +123,8 @@ Sometimes a GUI or other application may want to force a provider to
|
||||
:runtime autoload/provider/clipboard.vim
|
||||
|
||||
|
||||
DOCUMENTATION *dev-doc*
|
||||
------------------------------------------------------------------------------
|
||||
Documentation *dev-doc*
|
||||
|
||||
- "Just say it". Avoid mushy, colloquial phrasing in all documentation
|
||||
(docstrings, user manual, website materials, newsletters, …). Don't mince
|
||||
@@ -165,7 +166,7 @@ DOCUMENTATION *dev-doc*
|
||||
`treesitter.txt`
|
||||
- Otherwise, add them to `lua.txt`
|
||||
|
||||
Documentation format ~
|
||||
DOCUMENTATION FORMAT
|
||||
|
||||
For Nvim-owned docs, use the following strict subset of "vimdoc" to ensure
|
||||
the help doc renders nicely in other formats (such as HTML:
|
||||
@@ -184,7 +185,7 @@ Strict "vimdoc" subset:
|
||||
- Parameters and fields are documented as `{foo}`.
|
||||
- Optional parameters and fields are documented as `{foo}?`.
|
||||
|
||||
C docstrings ~
|
||||
C DOCSTRINGS
|
||||
|
||||
Nvim API documentation lives in the source code, as docstrings (doc
|
||||
comments) on the function definitions. The |api| :help is generated
|
||||
@@ -231,8 +232,7 @@ in src/nvim/api/win_config.c like this: >
|
||||
/// @return Window handle, or 0 on error
|
||||
|
||||
|
||||
Lua docstrings ~
|
||||
*dev-lua-doc*
|
||||
LUA DOCSTRINGS *dev-lua-doc*
|
||||
Lua documentation lives in the source code, as docstrings on the function
|
||||
definitions. The |lua-vim| :help is generated from the docstrings.
|
||||
|
||||
@@ -300,7 +300,19 @@ vim.paste in runtime/lua/vim/_core/editor.lua like this: >
|
||||
--- @returns false if client should cancel the paste.
|
||||
|
||||
|
||||
STDLIB DESIGN GUIDELINES *dev-lua*
|
||||
EXX ERROR CODES *dev-error-codes*
|
||||
|
||||
To choose a new "EXX" error code (e.g. |E5555|), just print a message with
|
||||
a new EXX number: >
|
||||
emsg(_("E996: Invalid thing"));
|
||||
<
|
||||
You can confirm that the new error code isn't used by running: >
|
||||
make linterrcodes
|
||||
<
|
||||
The `linterrcodes.lua` check requires the new error code to have a help tag.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
Stdlib design *dev-lua*
|
||||
|
||||
See also |dev-naming|.
|
||||
|
||||
@@ -343,8 +355,8 @@ preference):
|
||||
5. `vim.notify` (sometimes with optional `opts.silent` (async, visitors))
|
||||
- High-level / application-level messages. End-user invokes these directly.
|
||||
|
||||
*dev-patterns*
|
||||
Interface conventions ~
|
||||
|
||||
INTERFACE CONVENTIONS *dev-patterns*
|
||||
|
||||
Where applicable, these patterns apply to _both_ Lua and the API:
|
||||
|
||||
@@ -390,7 +402,8 @@ Where applicable, these patterns apply to _both_ Lua and the API:
|
||||
end)
|
||||
<
|
||||
|
||||
API DESIGN GUIDELINES *dev-api*
|
||||
------------------------------------------------------------------------------
|
||||
API design *dev-api*
|
||||
|
||||
See also |dev-naming|.
|
||||
|
||||
@@ -409,7 +422,7 @@ See also |dev-naming|.
|
||||
- Avoid functions that depend on cursor position, current buffer, etc. Instead
|
||||
the function should take a position parameter, buffer parameter, etc.
|
||||
|
||||
Where things go ~
|
||||
WHERE THINGS GO
|
||||
|
||||
- API (libnvim/RPC): exposes low-level internals, or fundamental things (such
|
||||
as `nvim_exec_lua()`) needed by clients or C consumers.
|
||||
@@ -425,8 +438,6 @@ burden. Discoverability encourages code re-use and likewise avoids redundant,
|
||||
overlapping mechanisms, which reduces code surface-area, and thereby minimizes
|
||||
bugs...
|
||||
|
||||
Naming conventions ~
|
||||
|
||||
In general, look for precedent when choosing a name, that is, look at existing
|
||||
(non-deprecated) functions. In particular, see below...
|
||||
|
||||
@@ -600,7 +611,8 @@ recommended (compare these 12(!) functions to the above 3 functions): >
|
||||
nvim_win_get_ns(…)
|
||||
nvim_tabpage_get_ns(…)
|
||||
|
||||
API-CLIENT *dev-api-client*
|
||||
------------------------------------------------------------------------------
|
||||
API client *dev-api-client*
|
||||
|
||||
*api-client*
|
||||
API clients wrap the Nvim |API| to provide idiomatic "SDKs" for their
|
||||
@@ -615,7 +627,7 @@ These clients can be considered the "reference implementation" for API clients:
|
||||
- https://github.com/neovim/node-client
|
||||
- https://github.com/neovim/pynvim
|
||||
|
||||
Standard Features ~
|
||||
STANDARD FEATURES
|
||||
|
||||
- API clients exist to hide msgpack-rpc details. The wrappers can be
|
||||
automatically generated by reading the |api-metadata| from Nvim. |api-mapping|
|
||||
@@ -625,7 +637,7 @@ Standard Features ~
|
||||
- Clients should handle |nvim_error_event| notifications, which will be sent
|
||||
if an async request to nvim was rejected or caused an error.
|
||||
|
||||
Package Naming ~
|
||||
PACKAGE NAMING
|
||||
|
||||
API client packages should NOT be named something ambiguous like "neovim" or
|
||||
"python-client". Use "nvim" as a prefix/suffix to some other identifier
|
||||
@@ -641,7 +653,7 @@ Examples of API-client package names:
|
||||
- ❌ NO: python-client
|
||||
- ❌ NO: neovim_
|
||||
|
||||
API client implementation guidelines ~
|
||||
API CLIENT IMPLEMENTATION GUIDELINES
|
||||
|
||||
- Separate the transport layer from the rest of the library. |rpc-connecting|
|
||||
- Use a MessagePack library that implements at least version 5 of the
|
||||
@@ -664,6 +676,7 @@ API client implementation guidelines ~
|
||||
https://github.com/msgpack-rpc/msgpack-rpc
|
||||
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
EXTERNAL UI *dev-ui*
|
||||
|
||||
External UIs should be aware of the |api-contract|. In particular, future
|
||||
@@ -671,7 +684,7 @@ versions of Nvim may add new items to existing events. The API is strongly
|
||||
backwards-compatible, but clients must not break if new (optional) fields are
|
||||
added to existing events.
|
||||
|
||||
Standard Features ~
|
||||
STANDARD FEATURES
|
||||
|
||||
External UIs are expected to implement these common features:
|
||||
|
||||
@@ -695,8 +708,9 @@ External UIs are expected to implement these common features:
|
||||
- Handle the "restart" UI event so that |:restart| works.
|
||||
- Detect capslock and show an indicator if capslock is active.
|
||||
|
||||
Multigrid UI ~
|
||||
*dev-ui-multigrid*
|
||||
|
||||
MULTIGRID UI *dev-ui-multigrid*
|
||||
|
||||
- A multigrid UI should display floating windows using one of the following
|
||||
methods, using the `win_float_pos` |ui-multigrid| event. Different methods
|
||||
can be selected for each window as needed.
|
||||
|
||||
@@ -325,7 +325,7 @@ name or a part of a buffer name. Examples:
|
||||
diff mode (e.g., "file.c.v2")
|
||||
|
||||
==============================================================================
|
||||
5. Diff anchors *diff-anchors*
|
||||
5. Diff anchors *diff-anchors* *E1549*
|
||||
|
||||
Diff anchors allow you to control where the diff algorithm aligns and
|
||||
synchronize text across files. Each anchor matches each other in each file,
|
||||
|
||||
+1
-1
@@ -456,7 +456,7 @@ Creating New Menus *creating-menus*
|
||||
|
||||
*:me* *:menu* *:noreme* *:noremenu*
|
||||
*E330* *E327* *E331* *E336* *E333*
|
||||
*E328* *E329* *E337* *E792*
|
||||
*E328* *E329* *E337* *E792* *E1310*
|
||||
To create a new menu item, use the ":menu" commands. They are mostly like
|
||||
the ":map" set of commands (see |map-modes|), but the first argument is a menu
|
||||
item name, given as a path of menus and submenus with a '.' between them,
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
NVIM REFERENCE MANUAL by Thiago de Arruda
|
||||
|
||||
|
||||
Nvim job control *job* *job-control*
|
||||
Nvim job control *job* *job-control* *E901* *E903* *E947* *E948*
|
||||
|
||||
Job control is a way to perform multitasking in Nvim, so scripts can spawn and
|
||||
control multiple processes without blocking the current Nvim instance.
|
||||
|
||||
+1
-1
@@ -359,7 +359,7 @@ numbers. To disambiguate these cases, we define:
|
||||
3. Table with string keys, at least one of which contains NUL byte, is also
|
||||
considered to be a dictionary, but this time it is converted to
|
||||
a |msgpack-special-map|.
|
||||
*lua-special-tbl*
|
||||
*lua-special-tbl* *E5100* *E5101* *E5102*
|
||||
4. Table with `vim.type_idx` key may be a dictionary, a list or floating-point
|
||||
value:
|
||||
- `{[vim.type_idx]=vim.types.float, [vim.val_idx]=1}` is converted to
|
||||
|
||||
@@ -353,7 +353,7 @@ conversion needs to be done. These conversions are supported:
|
||||
Try getting another iconv() implementation.
|
||||
|
||||
==============================================================================
|
||||
Input with a keymap *mbyte-keymap*
|
||||
Input with a keymap *mbyte-keymap* *E544*
|
||||
|
||||
When the keyboard doesn't produce the characters you want to enter in your
|
||||
text, you can use the 'keymap' option. This will translate one or more
|
||||
|
||||
@@ -889,9 +889,10 @@ Create or update a progress-message by calling |nvim_echo()| with
|
||||
existing progress-message.
|
||||
|
||||
Events: ~
|
||||
• msg_show |ui-messages| event is fired for ext-ui upon creation/update of a
|
||||
progress-message
|
||||
• Updating or creating a progress message also triggers the |Progress| autocommand.
|
||||
• msg_show |ui-messages| event is fired for ext-ui upon creation/update of
|
||||
a progress-message
|
||||
• Updating or creating a progress message also triggers the |Progress|
|
||||
autocommand.
|
||||
|
||||
Example: >lua
|
||||
local progress = {
|
||||
|
||||
@@ -6115,7 +6115,7 @@ A jump table for the options with a short description can be found at |Q_op|.
|
||||
designated regions of the buffer are spellchecked in
|
||||
this case.
|
||||
|
||||
*'spellsuggest'* *'sps'*
|
||||
*'spellsuggest'* *'sps'* *E5700*
|
||||
'spellsuggest' 'sps' string (default "best")
|
||||
global
|
||||
Disallowed in |modeline|. |no-modeline-option|
|
||||
|
||||
@@ -12,7 +12,7 @@ explanations are in chapter 27 |usr_27.txt|.
|
||||
Type |gO| to see the table of contents.
|
||||
|
||||
==============================================================================
|
||||
1. Search commands *search-commands*
|
||||
1. Search commands *search-commands* *E654*
|
||||
|
||||
*/*
|
||||
/{pattern}[/]<CR> Search forward for the [count]'th occurrence of
|
||||
@@ -401,7 +401,7 @@ prepend one of the following to the pattern:
|
||||
|
||||
You can also use the 'regexpengine' option to change the default.
|
||||
|
||||
*E864* *E868* *E874* *E875* *E876* *E877* *E878*
|
||||
*E864* *E868* *E874* *E875* *E876* *E877* *E878* *E1273* *E1279*
|
||||
If selecting the NFA engine and it runs into something that is not implemented
|
||||
the pattern will not match. This is only useful when debugging Vim.
|
||||
|
||||
|
||||
@@ -359,7 +359,7 @@ If there is a file with exactly the same name as the ".spl" file but ending in
|
||||
".sug", that file will be used for giving better suggestions. It isn't loaded
|
||||
before suggestions are made to reduce memory use.
|
||||
|
||||
*E758* *E759* *E778* *E779* *E780* *E782*
|
||||
*E758* *E759* *E778* *E779* *E780* *E782* *E5042*
|
||||
When loading a spell file Vim checks that it is properly formatted. If you
|
||||
get an error the file may be truncated, modified or intended for another Vim
|
||||
version.
|
||||
|
||||
@@ -1157,7 +1157,7 @@ running) you have additional options:
|
||||
already set (registers, marks, |v:oldfiles|, etc.)
|
||||
will be overwritten.
|
||||
|
||||
*:wsh* *:wshada* *E137*
|
||||
*:wsh* *:wshada* *E137* *E138*
|
||||
:wsh[ada][!] [file] Write to ShaDa file [file] (default: see above).
|
||||
The information in the file is first read in to make
|
||||
a merge between old and new info. When [!] is used,
|
||||
@@ -1341,7 +1341,7 @@ exactly four MessagePack objects:
|
||||
- `*` (Unknown) Any other entry type is allowed for compatibility
|
||||
reasons, see |shada-compatibility|.
|
||||
|
||||
*E575* *E576*
|
||||
*E574* *E575* *E576*
|
||||
Errors in ShaDa file may have two types:
|
||||
1. E575 for “logical” errors.
|
||||
2. E576 for “critical” errors.
|
||||
|
||||
@@ -37,7 +37,7 @@ instead of "s:" when the mapping is expanded outside of the script.
|
||||
There are only script-local functions, no buffer-local or window-local
|
||||
functions.
|
||||
|
||||
*:fu* *:function* *E128* *E129* *E123*
|
||||
*:fu* *:function* *E128* *E129* *E123* *E1058* *E1068*
|
||||
:fu[nction] List all functions and their arguments.
|
||||
|
||||
:fu[nction][!] {name} List function {name}, annotated with line numbers
|
||||
@@ -206,7 +206,7 @@ See |:verbose-cmd| for more information.
|
||||
*function-argument* *a:var*
|
||||
An argument can be defined by giving its name. In the function this can then
|
||||
be used as "a:name" ("a:" for argument).
|
||||
*a:0* *a:1* *a:000* *E740* *...*
|
||||
*a:0* *a:1* *a:000* *E740* *E1132* *...*
|
||||
Up to 20 arguments can be given, separated by commas. After the named
|
||||
arguments an argument "..." can be specified, which means that more arguments
|
||||
may optionally be following. In the function the extra arguments can be used
|
||||
|
||||
@@ -20,7 +20,7 @@ CTRL-L Clears and redraws the screen. The redraw may happen
|
||||
|:nohlsearch| and updates diffs |:diffupdate|.
|
||||
|default-mappings|
|
||||
|
||||
*:mod* *:mode*
|
||||
*:mod* *:mode* *E359*
|
||||
:mod[e] Clears and redraws the screen.
|
||||
See also |nvim__redraw()|.
|
||||
|
||||
|
||||
@@ -14,7 +14,12 @@ Using expressions is introduced in chapter 41 of the user manual |usr_41.txt|.
|
||||
1. Variables *variables*
|
||||
|
||||
1.1 Variable types ~
|
||||
*E712* *E896* *E897* *E899*
|
||||
*E712* *E896* *E897* *E899* *E908* *E909*
|
||||
*E928* *E964* *E966* *E1023* *E1098* *E1174* *E1175*
|
||||
*E1203* *E1206* *E1210* *E1211* *E1212* *E1219* *E1220*
|
||||
*E1222* *E1225* *E1226* *E1238* *E1250* *E1252* *E1256*
|
||||
*E1265* *E1297* *E5010* *E5050* *E5060* *E5070* *E5071*
|
||||
*E5299* *E5300* *E5401* *E5420* *E6000*
|
||||
There are seven types of variables:
|
||||
|
||||
*Number* *Integer*
|
||||
@@ -1573,7 +1578,7 @@ See below |internal-variables|.
|
||||
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
function call *expr-function* *E116* *E118* *E119* *E120*
|
||||
function call *expr-function* *E116* *E118* *E119* *E120* *E130*
|
||||
|
||||
function(expr1, ...) function call
|
||||
See below |functions|.
|
||||
@@ -3733,7 +3738,7 @@ the output of `scriptnames` this code can be used: >
|
||||
unlet scriptnames_output
|
||||
|
||||
==============================================================================
|
||||
The sandbox *eval-sandbox* *sandbox*
|
||||
The sandbox *eval-sandbox* *sandbox* *E523*
|
||||
|
||||
The 'foldexpr', 'formatexpr', 'includeexpr', 'indentexpr', 'statusline' and
|
||||
'foldtext' options may be evaluated in a sandbox. This means that you are
|
||||
|
||||
@@ -0,0 +1,241 @@
|
||||
-- Checks mismatches between "EXX" error codes (E123, E1234) defined in C sources and those
|
||||
-- documented in `runtime/doc/*.txt`.
|
||||
--
|
||||
-- Usage: nvim -l scripts/linterrcodes.lua
|
||||
|
||||
--- Error codes allowed to appear in more than one place. Value is the exact expected
|
||||
--- occurrence count. A mismatch (actual > or < expected) is reported, to avoid
|
||||
--- accidental duplicates from slipping in.
|
||||
--- @type table<string, integer>
|
||||
local dup_allowed = {
|
||||
E109 = 2,
|
||||
E1098 = 2,
|
||||
E110 = 2,
|
||||
E112 = 2,
|
||||
E114 = 2,
|
||||
E115 = 2,
|
||||
E1159 = 2,
|
||||
E116 = 2,
|
||||
E121 = 2,
|
||||
E1502 = 4,
|
||||
E151 = 2,
|
||||
E155 = 3,
|
||||
E158 = 2,
|
||||
E170 = 2,
|
||||
E173 = 2,
|
||||
E180 = 2,
|
||||
E212 = 2,
|
||||
E216 = 2,
|
||||
E298 = 3,
|
||||
E303 = 3,
|
||||
E312 = 2,
|
||||
E317 = 4,
|
||||
E319 = 2,
|
||||
E423 = 3,
|
||||
E474 = 52,
|
||||
E475 = 6,
|
||||
E482 = 3,
|
||||
E484 = 2,
|
||||
E488 = 2,
|
||||
E5000 = 2,
|
||||
E5001 = 2,
|
||||
E5002 = 2,
|
||||
E5009 = 3,
|
||||
E502 = 2,
|
||||
E503 = 3,
|
||||
E504 = 2,
|
||||
E505 = 2,
|
||||
E509 = 2,
|
||||
E5101 = 2,
|
||||
E5102 = 2,
|
||||
E5108 = 4,
|
||||
E5111 = 2,
|
||||
E513 = 2,
|
||||
E521 = 2,
|
||||
E546 = 2,
|
||||
E588 = 2,
|
||||
E678 = 2,
|
||||
E685 = 5,
|
||||
E697 = 2,
|
||||
E703 = 2,
|
||||
E716 = 2,
|
||||
E723 = 2,
|
||||
E724 = 3,
|
||||
E728 = 2,
|
||||
E741 = 2,
|
||||
E742 = 2,
|
||||
E745 = 2,
|
||||
E798 = 2,
|
||||
E805 = 2,
|
||||
E856 = 2,
|
||||
E867 = 2,
|
||||
E900 = 3,
|
||||
E903 = 2,
|
||||
E905 = 2,
|
||||
E906 = 2,
|
||||
E948 = 2,
|
||||
E970 = 2,
|
||||
E974 = 2,
|
||||
E996 = 5,
|
||||
}
|
||||
|
||||
--- Runs a command, returns stdout lines. Errors on non-zero exit.
|
||||
--- @param cmd string[]
|
||||
--- @return string[]
|
||||
local function run(cmd)
|
||||
local result = vim.system(cmd, { text = true }):wait()
|
||||
if result.code ~= 0 then
|
||||
error('command failed: ' .. table.concat(cmd, ' ') .. '\n' .. (result.stderr or ''))
|
||||
end
|
||||
return vim.split(result.stdout, '\n', { trimempty = true })
|
||||
end
|
||||
|
||||
--- Extracts error codes from a line of C source, excluding hex literals (0xE000),
|
||||
--- identifiers (FOO_E123), and inline comments (`//`).
|
||||
--- @param line string
|
||||
--- @return string[]
|
||||
local function extract_codes(line)
|
||||
local codes = {} --- @type string[]
|
||||
local cmt = line:find('//')
|
||||
for pos, code in line:gmatch('()(E%d%d%d%d?)') do
|
||||
--- @cast pos integer
|
||||
local in_comment = cmt and pos > cmt
|
||||
-- Preceded by a word char means the `E` is part of something else.
|
||||
local prev = pos > 1 and line:sub(pos - 1, pos - 1) or ''
|
||||
local in_word = prev:match('[%w_]') ~= nil
|
||||
if not in_comment and not in_word then
|
||||
codes[#codes + 1] = code
|
||||
end
|
||||
end
|
||||
return codes
|
||||
end
|
||||
|
||||
--- @return table<string, true> Set of error codes documented in help docs.
|
||||
local function collect_help_codes()
|
||||
local lines = run({
|
||||
'git',
|
||||
'grep',
|
||||
'-hE',
|
||||
[[\*E[0-9]{3,4}\*]],
|
||||
'--',
|
||||
'runtime/doc/*.txt',
|
||||
})
|
||||
local codes = {} --- @type table<string, true>
|
||||
for _, line in ipairs(lines) do
|
||||
for code in line:gmatch('E%d%d%d%d?') do
|
||||
codes[code] = true
|
||||
end
|
||||
end
|
||||
return codes
|
||||
end
|
||||
|
||||
--- @return table<string, string[]> Map of error code to its occurrences in C sources.
|
||||
local function collect_c_codes()
|
||||
local lines = run({
|
||||
'git',
|
||||
'grep',
|
||||
'-nE',
|
||||
'E[0-9]{3,4}',
|
||||
'--',
|
||||
'src/nvim/*.c',
|
||||
'src/nvim/*.h',
|
||||
})
|
||||
local codes = {} --- @type table<string, string[]>
|
||||
for _, line in ipairs(lines) do
|
||||
for _, code in ipairs(extract_codes(line)) do
|
||||
codes[code] = codes[code] or {}
|
||||
table.insert(codes[code], line)
|
||||
end
|
||||
end
|
||||
return codes
|
||||
end
|
||||
|
||||
--- @param a string
|
||||
--- @param b string
|
||||
--- @return boolean
|
||||
local function errcode_lt(a, b)
|
||||
return tonumber(a:sub(2)) < tonumber(b:sub(2))
|
||||
end
|
||||
|
||||
--- @param c_codes table<string, string[]>
|
||||
--- @param help_codes table<string, true>
|
||||
--- @return integer missing Number of codes missing from help docs.
|
||||
--- @return integer dups Number of codes with unexpected duplicate usage.
|
||||
local function report(c_codes, help_codes)
|
||||
local missing = {} --- @type string[]
|
||||
for code in pairs(c_codes) do
|
||||
if not help_codes[code] then
|
||||
missing[#missing + 1] = code
|
||||
end
|
||||
end
|
||||
table.sort(missing, errcode_lt)
|
||||
|
||||
local dup_codes = {} --- @type string[]
|
||||
for code, occurrences in pairs(c_codes) do
|
||||
local allowed = dup_allowed[code]
|
||||
if allowed then
|
||||
-- Whitelisted: only flag if the actual count doesn't match the expected count.
|
||||
if #occurrences ~= allowed then
|
||||
dup_codes[#dup_codes + 1] = code
|
||||
end
|
||||
elseif #occurrences > 1 then
|
||||
dup_codes[#dup_codes + 1] = code
|
||||
end
|
||||
end
|
||||
table.sort(dup_codes, errcode_lt)
|
||||
|
||||
if #missing > 0 then
|
||||
print('Error codes missing from help docs:')
|
||||
for _, code in ipairs(missing) do
|
||||
print(' ' .. code)
|
||||
end
|
||||
print('')
|
||||
end
|
||||
|
||||
if #dup_codes > 0 then
|
||||
print('Error codes used in more than one place:')
|
||||
for _, code in ipairs(dup_codes) do
|
||||
print(string.format(' %s (%d occurrences):', code, #c_codes[code]))
|
||||
for _, loc in ipairs(c_codes[code]) do
|
||||
print(' ' .. loc)
|
||||
end
|
||||
end
|
||||
print('')
|
||||
end
|
||||
|
||||
local max_code = 0
|
||||
for code in pairs(c_codes) do
|
||||
local n = tonumber(code:sub(2)) or 0
|
||||
if n > max_code then
|
||||
max_code = n
|
||||
end
|
||||
end
|
||||
|
||||
local n_errcodes = 0
|
||||
for _ in pairs(c_codes) do
|
||||
n_errcodes = n_errcodes + 1
|
||||
end
|
||||
|
||||
print(
|
||||
string.format(
|
||||
'errcodes=%d dup-codes=%d missing-help=%d highest=E%d',
|
||||
n_errcodes,
|
||||
#dup_codes,
|
||||
#missing,
|
||||
max_code
|
||||
)
|
||||
)
|
||||
|
||||
return #missing, #dup_codes
|
||||
end
|
||||
|
||||
local function main()
|
||||
local help_codes = collect_help_codes()
|
||||
local c_codes = collect_c_codes()
|
||||
local missing, dups = report(c_codes, help_codes)
|
||||
if missing > 0 or dups > 0 then
|
||||
os.exit(1)
|
||||
end
|
||||
end
|
||||
|
||||
main()
|
||||
@@ -8575,6 +8575,7 @@ local options = {
|
||||
scope = { 'global' },
|
||||
secure = true,
|
||||
short_desc = N_('method(s) used to suggest spelling corrections'),
|
||||
tags = { 'E5700' },
|
||||
type = 'string',
|
||||
varname = 'p_sps',
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user