1

Update generated neovim config

This commit is contained in:
2024-09-22 20:41:25 +02:00
parent 1743764e48
commit aa1271c42c
1247 changed files with 26512 additions and 15067 deletions

View File

@ -6,8 +6,11 @@
"workspace": {
"library": [
"$VIMRUNTIME",
"${3rd}/luv/library"
"${3rd}/luv/library",
"${3rd}/busted/library",
"${3rd}/luassert/library",
"lua"
],
"checkThirdParty": false
},
}
}

View File

@ -104,6 +104,7 @@ Other dedicated linters that are built-in are:
| [chktex][20] | `chktex` |
| [clang-tidy][23] | `clangtidy` |
| [clazy][30] | `clazy` |
| [clippy][clippy] | `clippy` |
| [clj-kondo][24] | `clj-kondo` |
| [cmakelint][cmakelint] | `cmakelint` |
| [codespell][18] | `codespell` |
@ -124,6 +125,7 @@ Other dedicated linters that are built-in are:
| [erb-lint][erb-lint] | `erb_lint` |
| [ESLint][25] | `eslint` |
| [eslint_d][37] | `eslint_d` |
| [eugene][eugene] | `eugene` |
| [fennel][fennel] | `fennel` |
| [fish][fish] | `fish` |
| [Flake8][13] | `flake8` |
@ -134,6 +136,7 @@ Other dedicated linters that are built-in are:
| [glslc][glslc] | `glslc` |
| [Golangci-lint][16] | `golangcilint` |
| [hadolint][28] | `hadolint` |
| [hledger][hledger] | `hledger` |
| [hlint][32] | `hlint` |
| [htmlhint][htmlhint] | `htmlhint` |
| [HTML Tidy][12] | `tidy` |
@ -197,6 +200,7 @@ Other dedicated linters that are built-in are:
| [statix check][33] | `statix` |
| [stylelint][29] | `stylelint` |
| [SwiftLint][swiftlint] | `swiftlint` |
| [systemd-analyze][systemd-analyze] | `systemd-analyze` |
| [systemdlint][systemdlint] | `systemdlint` |
| [tflint][tflint] | `tflint` |
| [tfsec][tfsec] | `tfsec` |
@ -273,15 +277,26 @@ The function takes two arguments: `errorformat` and `skeleton` (optional).
### from_pattern
Creates a parser function from a pattern.
```lua
parser = require('lint.parser').from_pattern(pattern, groups, severity_map, defaults, opts)
```
The function allows to parse the linter's output using a Lua regular expression pattern.
### pattern
- pattern: The regular expression pattern applied on each line of the output
- groups: The groups specified by the pattern
The function allows to parse the linter's output using a pattern which can be either:
- A Lua pattern. See `:help lua-patterns`.
- A LPEG pattern object. See `:help vim.lpeg`.
- A function (`fun(line: string):string[]`). It takes one parameter - a line
from the linter output and must return a string array with the matches. The
array should be empty if there was no match.
### groups
The groups specify the result format of the pattern.
Available groups:
- `lnum`
@ -301,7 +316,11 @@ local pattern = '[^:]+:(%d+):(%d+):(%w+):(.+)'
local groups = { 'lnum', 'col', 'code', 'message' }
```
- severity: A mapping from severity codes to diagnostic codes
The captures in the pattern correspond to the group at the same position.
### severity
A mapping from severity codes to diagnostic codes
``` lua
default_severity = {
@ -312,18 +331,22 @@ default_severity = {
}
```
- defaults: The defaults diagnostic values
### defaults
The defaults diagnostic values
```lua
defaults = {["source"] = "mylint-name"}
```
- opts: Additional options
### opts
- `lnum_offset`: Added to `lnum`. Defaults to 0
- `end_lnum_offset`: Added to `end_lnum`. Defaults to 0
- `end_col_offset`: offset added to `end_col`. Defaults to `-1`, assuming
that the end-column position is exclusive.
Additional options
- `lnum_offset`: Added to `lnum`. Defaults to 0
- `end_lnum_offset`: Added to `end_lnum`. Defaults to 0
- `end_col_offset`: offset added to `end_col`. Defaults to `-1`, assuming
that the end-column position is exclusive.
## Customize built-in linters
@ -537,3 +560,7 @@ busted tests/
[swiftlint]: https://github.com/realm/SwiftLint
[tflint]: https://github.com/terraform-linters/tflint
[ameba]: https://github.com/crystal-ameba/ameba
[eugene]: https://github.com/kaaveland/eugene
[clippy]: https://github.com/rust-lang/rust-clippy
[hledger]: https://hledger.org/
[systemd-analyze]: https://man.archlinux.org/man/systemd-analyze.1

View File

@ -4,6 +4,8 @@ local notify = vim.notify_once or vim.notify
local M = {}
---@alias lint.parse fun(output:string, bufnr:number, linter_cwd:string):vim.Diagnostic[]
---@class lint.Parser
---@field on_chunk fun(chunk: string)
---@field on_done fun(publish: fun(diagnostics: vim.Diagnostic[]), bufnr: number, linter_cwd: string)
@ -19,7 +21,7 @@ local M = {}
---@field ignore_exitcode? boolean if exit code != 1 should be ignored or result in a warning. Defaults to false
---@field env? table
---@field cwd? string
---@field parser lint.Parser|fun(output:string, bufnr:number, linter_cwd:string):vim.Diagnostic[]
---@field parser lint.Parser|lint.parse
---@class lint.LintProc
@ -321,6 +323,10 @@ function M.lint(linter, opts)
-- pop up shortly.
detached = not iswin
}
-- prevents cmd.exe taking over the tab title
if iswin then
linter_opts.hide = true
end
local cmd = eval_fn_or_id(linter.cmd)
assert(cmd, 'Linter definition must have a `cmd` set: ' .. vim.inspect(linter))
handle, pid_or_err = uv.spawn(cmd, linter_opts, function(code)

View File

@ -0,0 +1,52 @@
local severities = {
note = vim.diagnostic.severity.INFO,
warning = vim.diagnostic.severity.WARN,
help = vim.diagnostic.severity.HINT,
}
local function parse(diagnostics, file_name, item)
for _, span in ipairs(item.spans) do
if span.file_name == file_name then
local message = item.message
if span.suggested_replacement ~= vim.NIL then
message = message .. "\nSuggested replacement:\n\n" .. tostring(span.suggested_replacement)
end
table.insert(diagnostics, {
lnum = span.line_start - 1,
end_lnum = span.line_end - 1,
col = span.column_start - 1,
end_col = span.column_end - 1,
severity = severities[item.level],
source = "clippy",
message = message
})
end
end
for _, child in ipairs(item.children) do
parse(diagnostics, file_name, child)
end
end
return {
cmd = "cargo",
args = { "clippy", "--message-format=json" },
stdin = false,
append_fname = false,
parser = function(output, bufnr)
local diagnostics = {}
local items = #output > 0 and vim.split(output, "\n") or {}
local file_name = vim.api.nvim_buf_get_name(bufnr)
file_name = vim.fn.fnamemodify(file_name, ":.")
for _, i in ipairs(items) do
local item = i ~= "" and vim.json.decode(i) or {}
-- cargo also outputs build artifacts messages in addition to diagnostics
if item and item.reason == "compiler-message" then
parse(diagnostics, file_name, item.message)
end
end
return diagnostics
end,
}

View File

@ -1,15 +1,35 @@
-- stdout output in the form "63: resourcs ==> resources, resource"
local api = vim.api
local pattern = "(%d+): (.*)"
local groups = { "lnum", "message" }
local severities = nil -- none provided
local parser = require('lint.parser').from_pattern(pattern, groups, severities, {
source = 'codespell',
severity = vim.diagnostic.severity.INFO,
})
return {
cmd = 'codespell',
args = { '--stdin-single-line', "-" },
stdin = true,
ignore_exitcode = true,
parser = require('lint.parser').from_pattern(pattern, groups, severities, {
source = 'codespell',
severity = vim.diagnostic.severity.INFO,
}),
parser = function(output, bufnr, cwd)
local result = parser(output, bufnr, cwd)
for _, d in ipairs(result) do
local start, _, capture = d.message:find("(.*) ==>")
if start then
-- lenient - lint is async and buffer can change between lint start and result parsing
local ok, lines = pcall(api.nvim_buf_get_lines, bufnr, d.lnum, d.lnum + 1, true)
if ok then
local line = lines[1] or ""
local end_
start, end_ = line:find(vim.pesc(capture))
if start then
d.col = start - 1
d.end_col = end_
end
end
end
end
return result
end,
}

View File

@ -20,7 +20,7 @@ return {
local lnum = math.max(0, item.lnum - 1)
local col = math.max(0, item.col - 1)
local end_lnum = item.end_lnum > 0 and (item.end_lnum - 1) or lnum
local end_col = col + word:len() - 2 or col
local end_col = col + vim.fn.strdisplaywidth(word) - 2 or col
local diagnostic = {
lnum = lnum,
col = col,

View File

@ -0,0 +1,26 @@
return {
cmd = 'eugene',
args = {
'lint',
'--format=json',
},
stdin = false,
parser = function(output, _)
local diagnostics = {}
if #output > 0 then
local decoded = vim.json.decode(output)
for _, stmt in ipairs(decoded.statements) do
for _, tr in ipairs(stmt.triggered_rules) do
table.insert(diagnostics, {
source = 'eugene',
lnum = stmt.line_number,
col = 0,
severity = vim.diagnostic.severity.ERROR,
message = string.format('%s: %s: %s', tr.id, tr.name, tr.url),
})
end
end
end
return diagnostics
end,
}

View File

@ -0,0 +1,27 @@
return {
cmd = "hledger",
stdin = true,
args = {"check", "-s", "-f", "-"},
stream = "stderr",
ignore_exitcode = true,
parser = function(output)
--- hledger currently outputs at most one error.
---@type vim.Diagnostic[]
local result = {}
local pattern = "hledger: Error: %-:(%d+)(%-?(%d*)):(.*)"
local lnum, _, end_lnum, msg = output:match(pattern)
lnum = tonumber(lnum)
end_lnum = tonumber(end_lnum)
if (lnum or 0) > 0 then
table.insert(result, {
message = msg,
col = 0,
lnum = lnum - 1,
end_lnum = end_lnum and (end_lnum - 1) or nil,
severity = vim.diagnostic.severity.ERROR,
source = "hledger"
})
end
return result
end
}

View File

@ -19,6 +19,10 @@ return {
'--no-color-output',
'--no-error-summary',
'--no-pretty',
'--python-executable',
function()
return vim.fn.exepath 'python3' or vim.fn.exepath 'python'
end
},
parser = require('lint.parser').from_pattern(
pattern,

View File

@ -9,11 +9,17 @@ local severities = {
return {
cmd = 'pylint',
stdin = false,
stdin = true,
args = {
'-f', 'json'
'-f',
'json',
'--from-stdin',
function()
return vim.api.nvim_buf_get_name(0)
end,
},
ignore_exitcode = true,
stream = 'stdout',
parser = function(output, bufnr)
if output == "" then return {} end
local diagnostics = {}

View File

@ -33,11 +33,15 @@ return {
local diagnostics = {}
for _, i_filepath in ipairs(per_filepath) do
for _, violation in ipairs(i_filepath.violations) do
local severity = vim.diagnostic.severity.WARN
if violation.code == "PRS" then
severity = vim.diagnostic.severity.ERROR
end
table.insert(diagnostics, {
source = 'sqlfluff',
lnum = (violation.line_no or violation.start_line_no) - 1,
col = (violation.line_pos or violation.start_line_pos) - 1,
severity = vim.diagnostic.severity.ERROR,
severity = severity,
message = violation.description,
user_data = {lsp = {code = violation.code}},
})

View File

@ -0,0 +1,11 @@
return {
cmd = "systemd-analyze",
args = {"verify"},
ignore_exitcode = true,
stdin = false,
stream = "stderr",
parser = require("lint.parser").from_errorformat("%f:%l:%m", {
source = "systemd",
severity = vim.diagnostic.severity.WARN
})
}

View File

@ -17,6 +17,7 @@ return {
cmd = 'tidy',
stdin = true,
stream = 'stderr',
ignore_exitcode = true,
args = {
'-quiet',
'-errors',

View File

@ -10,6 +10,9 @@ local severity_by_qftype = {
-- Return a parse function that uses an errorformat to parse the output.
-- See `:help errorformat`
---@param efm string
---@param skeleton table<string, any> | vim.Diagnostic
---@return lint.parse
function M.from_errorformat(efm, skeleton)
skeleton = skeleton or {}
skeleton.severity = skeleton.severity or vd.severity.ERROR
@ -17,7 +20,7 @@ function M.from_errorformat(efm, skeleton)
local lines = vim.split(output, '\n')
local qflist = vim.fn.getqflist({ efm = efm, lines = lines })
local result = {}
for _, item in pairs(qflist.items) do
for _, item in ipairs(qflist.items) do
if item.valid == 1 and (bufnr == nil or item.bufnr == 0 or item.bufnr == bufnr) then
local lnum = math.max(0, item.lnum - 1)
local col = math.max(0, item.col - 1)
@ -46,19 +49,39 @@ local normalize = (vim.fs ~= nil and vim.fs.normalize ~= nil)
--- Parse a linter's output using a Lua pattern
---
---@param pattern string
---@param pattern string|vim.lpeg.Pattern|fun(line: string):string[]
---@param groups string[]
---@param severity_map? table<string, vim.diagnostic.Severity>
---@param defaults? table
---@param opts? {col_offset?: integer, end_col_offset?: integer, lnum_offset?: integer, end_lnum_offset?: integer}
---@return lint.parse
function M.from_pattern(pattern, groups, severity_map, defaults, opts)
defaults = defaults or {}
severity_map = severity_map or {}
opts = opts or {}
local type_ = type(pattern)
local matchline
if type_ == "string" then
matchline = function(line)
return { line:match(pattern) }
end
elseif type_ == "function" then
matchline = pattern
else
matchline = function(line)
return { pattern:match(line) }
end
end
-- Like vim.diagnostic.match but also checks if a `file` group matches the buffer path
-- Some linters produce diagnostics for the full project and this should only produce buffer diagnostics
local match = function(linter_cwd, buffer_path, line)
local matches = { line:match(pattern) }
local ok, matches = pcall(matchline, line)
if not ok then
error(string.format("pattern match failed on line: %s with error: %q", line, matches))
end
if not next(matches) then
return nil
end
@ -112,7 +135,9 @@ function M.from_pattern(pattern, groups, severity_map, defaults, opts)
end
local result = {}
local buffer_path = vim.fn.fnamemodify(vim.api.nvim_buf_get_name(bufnr), ":p")
for _, line in ipairs(vim.fn.split(output, '\n')) do
--- bwc for 0.6 requires boolean arg instead of table
---@diagnostic disable-next-line: param-type-mismatch
for line in vim.gsplit(output, "\n", true) do
local diagnostic = match(linter_cwd, buffer_path, line)
if diagnostic then
table.insert(result, diagnostic)
@ -130,6 +155,11 @@ Output from linter:
%s
]]
--- Turn a parse function into a parser table
---
---@param parse fun(output: string, bufnr: integer, cwd: string):vim.Diagnostic[]
---@return lint.Parser
function M.accumulate_chunks(parse)
local chunks = {}
return {

View File

@ -0,0 +1,21 @@
local api = vim.api
describe("codespell", function()
it("provides end_col", function()
local parser = require("lint.linters.codespell").parser
local bufnr = api.nvim_create_buf(false, true)
api.nvim_buf_set_lines(bufnr, 0, -1, true, {' error("hello crate test")'})
local result = parser("1: crate ==> create", bufnr)
local expected = {
{
col = 15,
end_col = 20,
end_lnum = 0,
lnum = 0,
message = 'crate ==> create',
severity = vim.diagnostic.severity.INFO,
source = 'codespell',
}
}
assert.are.same(expected, result)
end)
end)

View File

@ -0,0 +1,59 @@
describe("hledger", function()
local parser = require("lint.linters.hledger").parser
it("no diagnostics on empty output", function()
assert.are.same({}, parser(""))
end)
it("returns error diagnostic on error output", function()
-- editorconfig-checker-disable
local msg = [[
| 2024-08-10 * payment
| revenue:dev:customer -1.234,00 EUR
14 | assets:receivable:customer 1.234,00 EUR
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Strict account checking is enabled, and
account "assets:receivable:customer" has not been declared.
Consider adding an account directive. Examples:
account assets:receivable:customer
account assets:receivable:customer ; type:A ; (L,E,R,X,C,V)
]]
-- editorconfig-checker-enable
local output = "hledger: Error: -:14:" .. msg
local expected = {
{
message = msg,
col = 0,
lnum = 13,
severity = vim.diagnostic.severity.ERROR,
source = "hledger"
},
}
assert.are.same(expected, parser(output))
end)
it("supports column-ranges", function()
-- editorconfig-checker-disable
local msg = [[
109 | 2024-08-16 assert balance
| assets:checking 4 EUR = 68,59 EUR
This transaction is unbalanced.
The real postings' sum should be 0 but is: 4 EUR
Consider adjusting this entry's amounts, or adding missing postings.
]]
-- editorconfig-checker-enable
local output = "hledger: Error: -:109-110:" .. msg
local expected = {
{
message = msg,
col = 0,
lnum = 108,
end_lnum = 109,
severity = vim.diagnostic.severity.ERROR,
source = "hledger"
},
}
assert.are.same(expected, parser(output))
end)
end)

View File

@ -73,4 +73,58 @@ bar:209:14 Bigger mistake
}
assert.are.same(expected, result)
end)
it("supports lpeg pattern", function()
if not vim.re then
return
end
local pattern = vim.re.compile("{[0-9]+} ':' { (.*) }")
local groups = { 'lnum', 'message' }
local parser = require('lint.parser').from_pattern(pattern, groups)
local output = [[
10:Big mistake
14:Bigger mistake
]]
local result = parser(output, 0)
local expected = {
{
message = 'Big mistake',
lnum = 9,
end_lnum = 9,
col = 0,
end_col = 0,
severity = vim.diagnostic.severity.ERROR,
},
{
message = 'Bigger mistake',
lnum = 13,
col = 0,
end_lnum = 13,
end_col = 0,
severity = vim.diagnostic.severity.ERROR,
},
}
assert.are.same(expected, result)
assert.are.same({}, parser("no-match", 0))
end)
it("supports match function", function()
local pattern = function(_)
return { 10, "hello" }
end
local groups = { 'lnum', 'message' }
local parser = require('lint.parser').from_pattern(pattern, groups)
local result = parser("foo", 0)
local expected = {
{
message = "hello",
lnum = 9,
col = 0,
end_lnum = 9,
end_col = 0,
severity = vim.diagnostic.severity.ERROR
},
}
assert.are.same(expected, result)
end)
end)

View File

@ -3,6 +3,7 @@ describe('linter.sqlfluff', function()
local parser = require('lint.linters.sqlfluff').parser
local bufnr = vim.uri_to_bufnr('file:///non-existent.sql')
-- actual output I got from running sqlfluff
-- NB: These tests do not address parsing failures
local result = parser([[
[{"filepath": "stdin", "violations": [{"start_line_no": 68, "start_line_pos": 1, "code": "L003", "description": "Expected 1 indentation, found 0 [compared to line 52]"}, {"start_line_no": 68, "start_line_pos": 1, "code": "L013", "description": "Column expression without alias. Use explicit `AS` clause."}]}]
@ -15,7 +16,7 @@ describe('linter.sqlfluff', function()
message = 'Expected 1 indentation, found 0 [compared to line 52]',
lnum = 67, -- mind the line indexing
col = 0, -- mind the column indexing
severity = vim.diagnostic.severity.ERROR,
severity = vim.diagnostic.severity.WARN,
user_data = {lsp = {code = 'L003'}},
}
assert.are.same(expected[1], result[1])
@ -25,7 +26,7 @@ describe('linter.sqlfluff', function()
message = 'Column expression without alias. Use explicit `AS` clause.',
lnum = 67,
col = 0,
severity = vim.diagnostic.severity.ERROR,
severity = vim.diagnostic.severity.WARN,
user_data = {lsp = {code = 'L013'}},
}
assert.are.same(expected[2], result[2])
@ -47,7 +48,7 @@ describe('linter.sqlfluff', function()
message = 'Expected 1 indentation, found 0 [compared to line 52]',
lnum = 67, -- mind the line indexing
col = 0, -- mind the column indexing
severity = vim.diagnostic.severity.ERROR,
severity = vim.diagnostic.severity.WARN,
user_data = {lsp = {code = 'L003'}},
}
assert.are.same(expected[1], result[1])
@ -57,7 +58,7 @@ describe('linter.sqlfluff', function()
message = 'Column expression without alias. Use explicit `AS` clause.',
lnum = 67,
col = 0,
severity = vim.diagnostic.severity.ERROR,
severity = vim.diagnostic.severity.WARN,
user_data = {lsp = {code = 'L013'}},
}
assert.are.same(expected[2], result[2])