Giter VIP home page Giter VIP logo

nvim-lint's Introduction

nvim-lint

An asynchronous linter plugin for Neovim (>= 0.6.0) complementary to the built-in Language Server Protocol support.

Motivation & Goals

With ale we already got an asynchronous linter, why write yet another one?

Because ale also includes its own language server client.

nvim-lint instead has a more narrow scope: It spawns linters, parses their output, and reports the results via the vim.diagnostic module.

nvim-lint complements the built-in language server client for languages where there are no language servers, or where standalone linters provide better results.

Installation

  • Requires Neovim >= 0.6.0
  • nvim-lint is a regular plugin and can be installed via the :h packages mechanism or via a plugin manager.

For example:

git clone \
    https://github.com/mfussenegger/nvim-lint.git
    ~/.config/nvim/pack/plugins/start/nvim-lint
  • If using vim-plug: Plug 'mfussenegger/nvim-lint'
  • If using packer.nvim: use 'mfussenegger/nvim-lint'

Usage

Configure the linters you want to run per file type. For example:

require('lint').linters_by_ft = {
  markdown = {'vale',}
}

Then setup a autocmd to trigger linting. For example:

au BufWritePost * lua require('lint').try_lint()

or with Lua autocmds (requires 0.7):

vim.api.nvim_create_autocmd({ "BufWritePost" }, {
  callback = function()

    -- try_lint without arguments runs the linters defined in `linters_by_ft`
    -- for the current filetype
    require("lint").try_lint()

    -- You can call `try_lint` with a linter name or a list of names to always
    -- run specific linters, independent of the `linters_by_ft` configuration
    require("lint").try_lint("cspell")
  end,
})

Some linters require a file to be saved to disk, others support linting stdin input. For such linters you could also define a more aggressive autocmd, for example on the InsertLeave or TextChanged events.

If you want to customize how the diagnostics are displayed, read :help vim.diagnostic.config.

Available Linters

There is a generic linter called compiler that uses the makeprg and errorformat options of the current buffer.

Other dedicated linters that are built-in are:

Tool Linter name
Set via makeprg compiler
actionlint actionlint
alex alex
ansible-lint ansible_lint
bandit bandit
bean-check bean_check
biomejs biomejs
blocklint blocklint
buf_lint buf_lint
buildifier buildifier
cfn-lint cfn_lint
cfn_nag cfn_nag
checkmake checkmake
checkpatch.pl checkpatch
checkstyle checkstyle
chktex chktex
clang-tidy clangtidy
clazy clazy
clj-kondo clj-kondo
cmakelint cmakelint
codespell codespell
commitlint commitlint
cppcheck cppcheck
cpplint cpplint
credo credo
cspell cspell
cue cue
curlylint curlylint
dash dash
deadnix deadnix
deno deno
DirectX Shader Compiler dxc
djlint djlint
dotenv-linter dotenv_linter
editorconfig-checker editorconfig-checker
erb-lint erb_lint
ESLint eslint
eslint_d eslint_d
fennel fennel
fish fish
Flake8 flake8
flawfinder flawfinder
gdlint (gdtoolkit) gdlint
GHDL ghdl
gitlint gitlint
glslc glslc
Golangci-lint golangcilint
hadolint hadolint
hlint hlint
htmlhint htmlhint
HTML Tidy tidy
Inko inko
janet janet
joker joker
jshint jshint
jsonlint jsonlint
ktlint ktlint
lacheck lacheck
Languagetool languagetool
luacheck luacheck
markdownlint markdownlint
markdownlint-cli2 markdownlint-cli2
markuplint markuplint
mlint mlint
Mypy mypy
Nagelfar nagelfar
Nix nix
npm-groovy-lint npm-groovy-lint
oelint-adv oelint-adv
opa_check opa_check
oxlint oxlint
perlcritic perlcritic
perlimports perlimports
phpcs phpcs
phpinsights phpinsights
phpmd phpmd
php php
phpstan phpstan
ponyc pony
prisma-lint prisma-lint
proselint proselint
protolint protolint
psalm psalm
puppet-lint puppet-lint
pycodestyle pycodestyle
pydocstyle pydocstyle
Pylint pylint
pyproject-flake8 pflake8
quick-lint-js quick-lint-js
regal regal
Revive revive
rflint rflint
robocop robocop
RPM rpmspec
rstcheck rstcheck
rstlint rstlint
RuboCop rubocop
Ruby ruby
Ruff ruff
salt-lint saltlint
Selene selene
ShellCheck shellcheck
snyk snyk_iac
Solhint solhint
sqlfluff sqlfluff
standardjs standardjs
StandardRB standardrb
statix check statix
stylelint stylelint
SwiftLint swiftlint
systemdlint systemdlint
tflint tflint
tfsec tfsec
tlint tlint
trivy trivy
typos typos
Vala vala_lint
Vale vale
Verilator verilator
vint vint
vulture vulture
woke woke
write-good write_good
yamllint yamllint
zsh zsh

Custom Linters

You can register custom linters by adding them to the linters table, but please consider contributing a linter if it is missing.

require('lint').linters.your_linter_name = {
  cmd = 'linter_cmd',
  stdin = true, -- or false if it doesn't support content input via stdin. In that case the filename is automatically added to the arguments.
  append_fname = true, -- Automatically append the file name to `args` if `stdin = false` (default: true)
  args = {}, -- list of arguments. Can contain functions with zero arguments that will be evaluated once the linter is used.
  stream = nil, -- ('stdout' | 'stderr' | 'both') configure the stream to which the linter outputs the linting result.
  ignore_exitcode = false, -- set this to true if the linter exits with a code != 0 and that's considered normal.
  env = nil, -- custom environment table to use with the external process. Note that this replaces the *entire* environment, it is not additive.
  parser = your_parse_function
}

Instead of declaring the linter as a table, you can also declare it as a function which returns the linter table in case you want to dynamically generate some of the properties.

your_parse_function can be a function which takes three arguments:

  • output
  • bufnr
  • linter_cwd

The output is the output generated by the linter command. The function must return a list of diagnostics as specified in :help diagnostic-structure.

You can override the environment that the linting process runs in by setting the env key, e.g.

env = { ["FOO"] = "bar" }

Note that this completely overrides the environment, it does not add new environment variables. The one exception is that the PATH variable will be preserved if it is not explicitly set.

You can generate a parse function from a Lua pattern or from an errorformat using the function in the lint.parser module:

from_errorformat

parser = require('lint.parser').from_errorformat(errorformat)

The function takes two arguments: errorformat and skeleton (optional).

from_pattern

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: The regular expression pattern applied on each line of the output
  • groups: The groups specified by the pattern

Available groups:

  • lnum
  • end_lnum
  • col
  • end_col
  • message
  • file
  • severity
  • code

The order of the groups must match the order of the captures within the pattern. An example:

local pattern = '[^:]+:(%d+):(%d+):(%w+):(.+)'
local groups = { 'lnum', 'col', 'code', 'message' }
  • severity: A mapping from severity codes to diagnostic codes
default_severity = {
['error'] = vim.diagnostic.severity.ERROR,
['warning'] = vim.diagnostic.severity.WARN,
['information'] = vim.diagnostic.severity.INFO,
['hint'] = vim.diagnostic.severity.HINT,
}
  • defaults: The defaults diagnostic values
defaults = {["source"] = "mylint-name"}
  • opts: 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

You can import a linter and modify its properties. An example:

local phpcs = require('lint').linters.phpcs
phpcs.args = {
  '-q',
  -- <- Add a new parameter here
  '--report=json',
  '-'
}

You can also post-process the diagnostics produced by a linter by wrapping it. For example, to change the severity of all diagnostics created by cspell:

local lint = require("lint")
lint.linters.cspell = require("lint.util").wrap(lint.linters.cspell, function(diagnostic)
  diagnostic.severity = vim.diagnostic.severity.HINT
  return diagnostic
end)

Display configuration

See :help vim.diagnostic.config.

If you want to have different settings per linter, you can get the namespace for a linter via require("lint").get_namespace("linter_name"). An example:

local ns = require("lint").get_namespace("my_linter_name")
vim.diagnostic.config({ virtual_text = true }, ns)

Get the current running linters for your buffer

You can see which linters are running with require("lint").get_running(). To include the running linters in the status line you could format them like this:

local lint_progress = function()
  local linters = require("lint").get_running()
  if #linters == 0 then
      return "󰦕"
  end
  return "󱉶 " .. table.concat(linters, ", ")
end

Alternatives

Development ☢️

Run tests

Running tests requires busted.

See neorocks or Using Neovim as Lua interpreter with Luarocks for installation instructions.

busted tests/

nvim-lint's People

Contributors

antznin avatar chrisgrieser avatar cyntheticfox avatar danrot avatar devkvlt avatar dhruvmanila avatar dimbleby avatar emmanueltouzery avatar fbuchlak avatar felipelema avatar gegoune avatar geraint avatar gpanders avatar kalmbach avatar lewis6991 avatar lispyclouds avatar lithammer avatar mekpavit avatar mflova avatar mfussenegger avatar misaflo avatar nat-418 avatar pbnj avatar sqve avatar stackline avatar stephen-huan avatar tastyep avatar whoissethdaniel avatar xenrox avatar yutsuten avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

nvim-lint's Issues

Use a path for linter

How can I provide a path to a linter?

I currently have this:

require('lint').linters_by_ft = { python = {'flake8',} }

However, I would like to provide a path for this filetype, like this:

require('lint').linters_by_ft = { python = {'/some/path/to/flake8',} }

Is it possible?

Thanks in advance

Autocommand not working with ChkTeX

I'm trying to get the autocommand to work in my lua config with

require('lint').linters_by_ft = {
	tex = {'chktex'}
}

and

vim.cmd([[au BufWritePost <buffer> lua require('lint').try_lint()]]) 

but it's not working. When I run only lua require('lint').try_lint on a .tex buffer, it works, but the autocmd doesn't.

I'm using Windows 11 with Neovim 6.0. I'm trying to build a lua only neovim config, so I'm not using .vimrc or any .vim file. Will try though, if anything else fails.

Support for dynamic commands

Some linters may need a dynamic command. For example, RuboCop (https://rubocop.org/) is a popular Ruby linter. Projects managing their Ruby dependencies using Bundler (https://bundler.io/) would have to run RuboCop using bundle exec rubocop .... Projects not using Bundler in turn have to use just rubocop.

Looking at the code of nvim-lint, there's only support for a static linter command (i.e. a string). This makes it impossible (I think?) to change the command to run based on the presence of a certain file (or some other condition).

Would it be possible to extend nvim-lint so the cmd field can be a function? In that case it would have to return the command to run. Argument wise I think it would only need the buffer number, as that should be enough to derive all the needed information (e.g. the directory of the buffer file).

Integration with folke/trouble.nvim?

Thanks for a great plugin - just discovered it!

I've set up golangcilint and it's working properly. The only issue is the display. I use trouble.nvim to keep a quicklist of issues, but nvim-lint isn't using it the way I'd like.

First, the diagnostics are printed inline (which I don't want; see screenshot "lint1").

Second, lint results don't automatically toggle trouble (which I've set up to only appear if there are problems in the code). I have to type :TroubleToggle to get the results into the quickfix list.

Any ideas on how to fix these two (minor) usability issues?

lint1

Help adding a new linter- hlint

Hi, I would like some help in adding a new linter, hlint.

In the command line, it can output JSON (after auto-formatting) like so:

✦ ❯ hlint Main.hs --json
[{
	"module": [],
	"decl": [],
	"severity": "Error",
	"hint": "Parse error: possibly incorrect indentation or mismatched brackets",
	"file": "Main.hs",
	"startLine": 3,
	"startColumn": 1,
	"endLine": 3,
	"endColumn": 1,
	"from": "  main = do\n    putStrLn (\"1 + 2 = \" ++ show (1 + 2)\n> \n",
	"to": null,
	"note": [],
	"refactorings": "[]"
}]

Basing off of this I have tried:

local severities = {
   Error = vim.lsp.protocol.DiagnosticSeverity.Error,
}

require("lint").linters.hlint = {
   cmd = "hlint",
   stdin = true,
   args = {
      "--json",
   },
   ignore_exitcode = true,
   parser = function(output)
      local diagnostics = {}
      local items = #output > 0 and vim.fn.json_decode(output) or {}
      for _, item in ipairs(items) do
         table.insert(diagnostics, {
            range = {
               ["start"] = { line = item.startLine, character = item.startColumn },
               ["end"] = { line = item.endLine, character = item.endColumn },
            },
            severity = severities[item.severity],
            source = "hlint",
            message = item.hint,
         })
      end

      return diagnostics
   end,
}

After require-ing this in my init.lua, I'm not seeing anything. I try :lua require('lint').try_lint('hlint') I get:

Error executing vim.schedule lua callback: Vim:E474: Unidentified byte: hlint [OPTIONS] [FIL
E/DIR]

Common flags:
  -r --report[=FILE]                       Generate a report in HTML
  -h --hint=FILE                           Hint/ignore file to use
     --with-group=GROUP                    Extra hint groups to use
  -g --git                                 Run on files tracked by git
  -c --color[=always/never/auto] --colour  Color output (requires an ANSI
                                           terminal; 'auto' means on if the
                                           standard output channel can support
                                           ANSI; by itself, selects 'always')
  -j --threads[=INT] --cmdthreads          Number of threads to use (-j for
                                           all)
  -i --ignore=HINT                         Ignore a particular hint
  -s --show                                Show all ignored ideas
  -e --extension=EXT                       File extensions to search (default

Help appreciated, happy to wrap this in a PR once I've got it working.

pylint doesn't work

Hi.

I've installed this plugin as described in readme. I've set my linters:

require('lint').linters_by_ft = {
      python = {'pylint',}
  }

and autocmd

au BufWritePost <buffer> lua require('lint').try_lint()

When editing a python file, pylint doesn't seem to be ran. No errors/warnings are added while I run pylint via terminal I get some errors.

vim.schedule uri nil value

Hi,

Thank you for all the work on nvim-lint.

I am getting an error when saving a file after updating nvin-lint to latest version. Linting was working prior to the update.

"Error executing vim.schedule lua callback: .../.local/nvim/share/nvim/runtime/lua/vim/uri.lua:116: attempt to index local 'uri' (a nil value)"

Config:
require("lint").linters_by_ft = {
python = {
"pylint",

}

}

vim.cmd("au BufWritePost lua require('lint').try_lint()")

Languagetool Linter Throws Error

languagetool throws an error:

Here is a minimal working example

local fn = vim.fn
local install_path = '/tmp/nvim/site/pack/packer/start/packer.nvim'

vim.cmd [[set packpath=/tmp/nvim/site]]

local function load_plugins()
    local use = require('packer').use
    require('packer').startup {
        function()
            use {
                'mfussenegger/nvim-lint',
                config = function()
                    local lint = require('lint')
                    lint.linters_by_ft = {text = {'languagetool'}}
                    vim.cmd(
                        [[au BufEnter <buffer> lua require('lint').try_lint() ]])
                    vim.cmd(
                        [[au BufWritePost <buffer> lua require('lint').try_lint() ]])
                end
            }
        end,
        config = {package_root = '/tmp/nvim/site/pack'}
    }
end

-- install packer
if fn.isdirectory(install_path) == 0 then
    fn.system {
        'git', 'clone', 'https://github.com/wbthomason/packer.nvim',
        install_path
    }
    load_plugins()
    require('packer').sync()
    vim.cmd 'autocmd User PackerComplete ++once lua load_config()'
else
    load_plugins()
end

This is the error message

Error executing vim.schedule lua callback: ...vim/site/pack/packer/start/nvim-lint/lua/lint
/parser.lua:114: Vim:E474: Unidentified byte: Working on /tmp/words.txt...
Using English for file /tmp/words.txt

This is my languagetool wrapper script

#!/bin/env bash

LT=~/.local/share/LanguageTool-5.4/languagetool-commandline.jar

java -jar $LT $@

It seems like it tries to parse JSON on the first chunk of the response, i.e., “Working on …”.

Any plans to support multiple linters per ft?

This project is really exciting, I'm looking forward to ditch efm :)

I know this is extremely early-stage, but since I didn't see a todo note in the readme I figured I could open an issue: are there plans to support multiples linters per filetype?

Windows: call on `try_lint()` on RST with Vale results in black window blink

Vale works fine from command line in Windows and when run in Neovim with :!vale document.rst or type document.rst | vale --ext=.rst, but for some reason a black window with C:\Python\python.exe title appears and disappeart instanty every time the function try_lint() is called.

Vale calls rst2html Python script internally to convert RST to HTML, but this does not lead to black Window blinking in other cases.

Linters that operate at directory or repository level

Right now, one of the linters I added (vulture, the best linter I have found based on dead and unused variables) is adding lots of false positives.
It seems that this linter works perfectly when the full directory is provided as input, as it scans all the files where the variables might have been used. This can be the repository or even greater scope, to analyze which functions might have been used in other repositories in just less than a few seconds.
However, in nvim-lint you can only specify the filename when the parameter stdin is set to false, which limits the scope of some linters to analize out of the current file.

Is there any linter added that uses a greater scope than the filename and then filter all those errors to only ones that belong to the current file? I would like to implement a fix, but I am not sure where to start. I might try something in the meantime.

error on saving

i get this error on saving my nvim lua config. if i revert to commit fe16081 it works.

".config/nvim/init.lua" 571L, 18653C written
Error detected while processing BufWritePost Autocommands for "<buffer=1>":
E5108: Error executing lua vim/shared.lua:187: t: expected table, got nil
stack traceback:
        [C]: in function 'error'
        vim/shared.lua:608: in function 'validate'
        vim/shared.lua:187: in function 'tbl_map'
        ...share/nvim/site/pack/packer/start/nvim-lint/lua/lint.lua:91: in function 'try_lint'
        [string ":lua"]:1: in main chunk

here is the config:

            use {
                "mfussenegger/nvim-lint",
                config = function()
                    local lint = require "lint"
                    lint.linters.golangcilint.args = {
                        "run",
                        "--enable-all",
                        "--disable=godox,tagliatelle,exhaustivestruct,varnamelen",
                        "--build-tags=integration",
                        "--out-format",
                        "json"
                    }
                    lint.linters_by_ft = {
                        go = {"golangcilint"},
                        sh = {"shellcheck"},
                        ansible = {"ansible_lint"}
                    }
                end
            }

and

local function nvim_create_augroups(definitions)
    for group_name, definition in pairs(definitions) do
        api.nvim_command("augroup " .. group_name)
        api.nvim_command("autocmd!")
        for _, def in ipairs(definition) do
            -- if type(def) == 'table' and type(def[#def]) == 'function' then
            -- 	def[#def] = lua_callback(def[#def])
            -- end
            local command = table.concat(vim.tbl_flatten {"autocmd", def}, " ")
            api.nvim_command(command)
        end
        api.nvim_command("augroup END")
    end
end

nvim_create_augroups({lint = {{"BufWritePost", "<buffer>", "lua require('lint').try_lint()"}}})

Markdownlint is not working on windows

Hello.

Thank you for your great works.

I have been using markdownlint of nvim-lint on Linux.
But the following error appears and it doesn't work normally on windows.

lint.lua:162: Error running markdownlint: ENOENT: no such file of directory

So I replaced "markdownlint" with "markdownlint.cmd" in the following code.

cmd = 'markdownlint',
ignore_exitcode = true,

Then a console window only blinks and the lint does not work.

Animation

Thank you for reading. Have a good day.

When running the Vale linter without a configuration value, NeoVim errors when parsing the JSON

This is actually true for any linter that uses NeoVim's json_decode function: when the output argument is an empty string, this function throws an error. This can happen when a linter is running, but errors. For example, the Vale linter errors when its configuration file is missing.

Perhaps a simple wrapper function is needed that just returns an empty table if the input string is empty?

Source as a top-level option

Would it be possible to have the source as a top-level option to the linter rather than to be part of the parser function?

In this way it would be easier to reuse an existing linter configuration, for example as:

lint = require('lint')
lint.linters.mylinter = copy_tbl(lint.linters.mypy)
lint.linters.mylinter.source = 'mylinter'

Vale throws error even when configured

On Arch I am receiving an error whenever I run 'checkhealth' with the vale 'attempt to decode a blank string' I was receiving all the time prior to configuring it for markdown. This admittedly is extremely frustrating since it was just the other day I realized how to fix the error and now it is coming back again. I would love to just disable vale, as I do not use it, but unfortunately have not found a way to.

edit: changing vale to run on txt instead of markdowns fixed it. If vale can't handle the formatting of checkhealth it really needs to be disabled by default.

Support fixers?

I really like the idea of this plugin, however, I'm currently also using ALE for fixing / autoformatting as well as linting. Are there any plans on supporting that from this plugin as well / a companion plugin?

Does golangci-lint really accepts file as stdin?

The configuration for golangcilint sets stdin = true, which means that the linter accepts file content through stdin. I haven't found any traces of such functionality in the official documentation. I tried running it like

$ golangci-lint run --out-format=json --

but I just keep getting an error

ERRO [linters context] typechecking error: pattern ./...: directory prefix . outside available modules

This is because it starts golangci-lint without a filename.
Changing stdin = true to append_fname = true fixes the problem. But I saw other people were using this linter without such problem, so I'm curious if something is wrong on my side or is this really a bug?

from_errorformat should strip leading newlines and whitespace from result of getqflist item text field

When neovim (or vim) parses lines of text with an errorformat string, where errorformat is mutli-line, the text matching %m can end up starting with a newline character regardless of the position of %m within the line, if it exists on a matching line that isn't the first one.

To see this, run the following in neovim/vim and note the output begins with a blank line:

:echo getqflist({'efm': '%Afoo,%Zbar %m', 'lines': ['foo', 'bar baz']})[0]['text']

In other words, the 'text' field above is '\nbaz' rather than just the expected 'baz'. AFAIK, this is a quirk of the internals of how errorformat string parsing works (if anyone knows differently please comment because I'd love a general solution to this vim problem).

When neovim/vim displays the quickfix list, there is code which explicitly strips leading newlines and spaces from the resultant message to account for this situation. See the qf_fmt_text function here and its use when adding new content to the quickfix buffer here and here.

However, in this project, from_errorformat() calls getqflist() here to parse an errorformat string (which may contain the above situation) and the result is returned to be displayed as it is. The result is that any linter configuration created that has the above condition will wind up with a newline displayed before the error message text. So, for example, diagnostics might look like this:

Diagnostics:
1.
Some error message
2.
Another error message

Consequently, I'd like to recommend nvim-lint maintain parity with the behavior of the quickfix list and strip leading newlines and spaces from error messages in from_errorformat(). It would probably also be a good idea to strip trailing whitespace at the same time while at it. Specifically, change this line to:

  message = item.text:match("^%s*(.-)%s*$"),

To work around this issue currently, one needs to intercept the message somewhere in the neovim config and strip it themselves. For example, I have my diagnostics display in floating windows and use version 0.6, so I do this:

vim.diagnostic.config({
  float = {
    format = function(diag)
      return diag.message:match("^%s*(.-)%s*$")
    end
  }
})

Issues with 'compiler' linter

Thank you for creating this plugin. I've just found it and it looks very nice. 👍

Since I was using my own async lmake before, my linters are defined as compiler.

Having a vim file open and running compiler vint and then lua require('lint').try_lint('compiler') doesn't emit any error but also doesn't highlight anything.
Using lua require('lint').try_lint('vint') or lmake does both work correctly.
Using compiler! vint lua require('lint').try_lint('compiler') does say "Failed to get value for option 'errorformat'". Even though set errorformat? is correct.

You can find my vint here

Eslint Setup Help

I am having trouble setting this plugin up so I can lint JS files with eslint. Would you be able to provide so examples or any pointers on how to get started? I don't see anywhere on the Readme about how the errors from the linter are displayed, is that handled by neovim's LSP instead or something else I would need to setup?

Here is my nvim-lint config.

local lint = require "lint"

lint.linters_by_ft = {
  javascript = {"eslint"}
}

vim.cmd([[au BufEnter *.js lua require('lint').try_lint() ]])
vim.cmd([[au BufWritePost *.js lua require('lint').try_lint() ]])

Some things I have tried to get it to work:

  • I have tried using eslint as both a global package as well as a dev dependency
  • Explicitly specified elsint's args like mentioned in #31
  • tried setting lint.linters.eslint.cmd = "node_modules/.bin/eslint" when i installed the eslint package as a dev dependency

Any help is appreciated!

[Question] How to show error code?

With ale I was able to configure my messages to show the flake8 error code (e.g. E501) like this: let g:ale_echo_msg_format = '[%linter%] %code%: %s [%severity%]'

How can I do the same with nvim-lint?

Cppcheck >1.84 required ({column} required)

Can we add a note in the readme that states cppcheck version 1.84 or greater is required? I went through a lot of debugging to find out that 1.82 that in Ubuntu's repo doesn't support {column} in the template argument. No indication was given by nvim-lint that cppcheck was failing.
(Is there a good way to debug this tool and the parser? LspInfo doesn't show anything.)

Unable to disable inline diagnostics

I added the following code to my init.lua to disable inline diagnostics:

vim.lsp.handlers["textDocument/publishDiagnostics"] = vim.lsp.with(
    vim.lsp.diagnostic.on_publish_diagnostics, {
        virtual_text = false
    }
)

Found the code here.

This worked for Language Servers (pyls), but it is not being applied for diagnostics generated by nvim-lint. Is it a bug or nvim-lint provides a different way to disable inline diagnostics?

Thank you!

markdownlint does not report all findings

Hello

Currently, the markdownlinter uses the following settings:

local pattern = '(.*):(%d+):(%d+) (.*)'
local groups  = { '_', 'line', 'start_col', 'message'}

Let's say we have the following output from markdownlint:

README.md:35 MD022/blanks-around-headings/blanks-around-headers Headings should be surrounded by blank lines [Expected: 1; Actual: 0; Below] [Context: "## What's in this repo?"]
README.md:36 MD032/blanks-around-lists Lists should be surrounded by blank lines [Context: "- `dotfiles`"]
README.md:47:81 MD013/line-length Line length [Expected: 80; Actual: 114]
README.md:55:81 MD013/line-length Line length [Expected: 80; Actual: 244]

The parser finds the Line length just fine, but fails to find the other errors. This is obviously due to the output not containing a start column.

Could a solution be to make start_col optional in a group and set it to zero if not found?

Diagnostic error messages cut off at punctuation marks

Example LSP diagnostic errors from nvim-lint, using vim.lsp.diagnostic.set_loclist():

web/src/index.ts|5 col 5 error| Promises must be handled appropriately or explicitly marked as ignored with the
web/src/index.ts|15 col 5 error| Unsafe member access
web/src/index.ts|15 col 5 error| Unsafe call of an
web/src/index.ts|16 col 5 error| Unsafe member access
web/src/index.ts|16 col 5 error| Unsafe call of an

And the output from eslint run on the same file:

web/src
❯ eslint index.ts

/path/to/web/src/index.ts
   5:5  error  Promises must be handled appropriately or explicitly marked as ignored with the `void` operator  @typescript-eslint/no-floating-promises
  15:5  error  Unsafe member access .accept on an `any` value                                                   @typescript-eslint/no-unsafe-member-access
  15:5  error  Unsafe call of an `any` typed value                                                              @typescript-eslint/no-unsafe-call
  16:5  error  Unsafe member access .dispose on an `any` value                                                  @typescript-eslint/no-unsafe-member-access
  16:5  error  Unsafe call of an `any` typed value                                                              @typescript-eslint/no-unsafe-call

✖ 5 problems (5 errors, 0 warnings)

It seems that error messages get cut off for both backticks and periods, though I'm not sure if other punctuation marks create the same behavior.

Conditionally enable linters

Some linters are very verbose by default, unless you specify a custom configuration file of sorts. For example, https://github.com/jorisroovers/gitlint is such a linter. When using ALE I would disable such linters by default, and only enable them when a configuration file is found. For example:

" Only enable gitlint if there is a .gitlint config file, as by default gitlint
" is a bit too pedantic.
let config = findfile('.gitlint', expand('%:p:h') . ';')

if empty(config)
  let b:ale_linters = []
else
  let b:ale_linters = ['gitlint']
  let b:ale_gitcommit_gitlint_options = '-C ' . fnamemodify(config, ':p')
end

This takes advantage of ALE's buffer-local settings.

While I think using buffer local settings for everything is a bad idea (it gets messy quickly), I'm wondering what the best way of handling this would be. One option would be to add some sort of run_if hook that returns true by default. Users would then have to somehow override it. For example, using something like this:

local linters = require('lint').linters

linters.gitlint.run_if = function(bufnr)
  if vim.fn.findfile('.gitlint', vim.fn.expand('%:p:h') .. ';') then
    return true
  else
    return false
  end
end

This is just an idea though, and there may be better ways of approaching this.

Pylint should ignore the exit code

Pylint will only have exit code 0 if there's no error messages, so I think we should ignore the exit code to prevent the message show up again and again.

Help setting up LanguageTool

I have been trying to set this linter up. From languagetool.lua I could see that the executed command that should retrieve the corrections is languagetool --json --stdin. However, in my case, the languagetoolexecutable I found always opens a separate window with a graphic interface. (And actually this is what happens when I activate this linter through nvim-lint and execute the try_lint command)
Where can I get the languagetool version used to implement this neovim integrated version?

Error on try_lint()

I encountered this error when trying to set up cpplint:

Packer setup used:

use { 'mfussenegger/nvim-lint',
  run = 'pip3 install cpplint --upgrade',
  config = function()
      require('lint').linters_by_ft = {
        cpp = {'cpplint',}
      }
  end
}

Running :lua require('lint').try_lint() gives me this error:

E5108: Error executing lua vim/shared.lua:187: t: expected table, got string
stack traceback:
        [C]: in function 'error'
        vim/shared.lua:608: in function 'validate'
        vim/shared.lua:187: in function 'tbl_map'
        ...share/nvim/site/pack/packer/start/nvim-lint/lua/lint.lua:91: in function 'try_lint'
        [string ":lua"]:1: in main chunk

cpplint by itself works.

[Help] golangci-lint results don't show up reliably

Thanks for building this plugin.
I'm currently testing it out and really like the Trouble integration.
However, it is currently not reliably working and I'd need some help debugging.

The config:

lua require('nvim-lint-config')
autocmd BufWritePost <buffer> lua require('lint').try_lint()
local lint = require('lint')

lint.linters_by_ft = {
  go = {'golangcilint'}
}

running golanglint-ci manually works just fine and return results.

sometimes, nvim-lint picks up the results, sometimes it doesn't.

:messages: doesn't show anything either.
What's the right way to debug this?

from_pattern does not set source

From the documentation of from_pattern in README.md and the usage in multiple linters, it looks like from_pattern is supposed to accept a source setting in defaults that should be included in the generated diagnostics.

This does not seem to work as from_pattern only uses values from defaults for severity values or if there is a corresponding group_handler. Maybe a group_handler like the following is the only thing missing here as the source shouldn't be entry specific:

source = function(entries)
  return defaults['source']
end

How to configure arguments for linters

I'm trying to use revive and need to pass in my config.
I see that lua/lint/linters/revive.lua has an args field, but I don't see how to set it.

Is the intended way to define it as a custom linter?

Thanks for the great lib, very clean and minimal, good work 👍

cppcheck: Linter command cppcheck exited with code 1

cppcheck fails if compile_commands.json is not in build/

this fixes the problem for me:

diff --git a/lua/lint/linters/cppcheck.lua b/lua/lint/linters/cppcheck.lua
index 0908ca1..259e6fb 100644
--- a/lua/lint/linters/cppcheck.lua
+++ b/lua/lint/linters/cppcheck.lua
@@ -4,7 +4,7 @@ return {
   stdin = false,
   args = {
     '--enable=warning,style,performance,information', '--language=c++',
-    '--project=build/compile_commands.json', '--inline-suppr', '--quiet',
+    '--inline-suppr', '--quiet',
     '--cppcheck-build-dir=build', '--template={file}:{line}:{column}: [{id}] {severity}: {message}'
   },
   stream = 'stderr',

How to iterate current buffer linters with their id's to draw their summary in status line?

Hello. Thank you for the plugin. I think direct spawning of linter.cmd and reading from its stdout is better than spawning intermediate headless neovim instances like other plugins do.
To draw diagnostics summary in status line, I use vim.lsp.diagnostic.get_count(0, severiry, client_id) which requires clinet_id. But it seems there is no way to get client_id from nvim-lint except looking in its code and finding local CLIENT_ID_OFFSET = 1000. Maybe there should be some public API?

Error executing vim.schedule lua callback with latest Neovim nightly

Hey, I just upgraded from the 0.5 stable version to the latest nightly build (NVIM v0.6.0-dev+284-gc2a65921d) from commit c2a6592. I also have the latest nvim-lint version.

Since then I always get this error when I open a Python file (I have an autocmd that calls try-lint() on BufEnter):

Error executing vim.schedule lua callback: vim/shared.lua:225: after the second argument: expected table, got number
stack traceback:
        vim/shared.lua:225: in function 'tbl_deep_extend'
        ....mount_nvimJNlEFY/usr/share/nvim/runtime/lua/vim/lsp.lua:1502: in function <....mou
nt_nvimJNlEFY/usr/share/nvim/runtime/lua/vim/lsp.lua:1501>
        /home/jonas/.vim/plugged/nvim-lint/lua/lint.lua:51: in function 'cb'
        vim.lua:281: in function <vim.lua:281>

Can you help with this? Thanks in advance.

How to handle files without-linter

Hi,

I have the following setting in my init.vim:

au BufWritePost <buffer> lua require('lint').try_lint()

And I have the following configuration for nvim-lint:

require('lint').linters_by_ft = {
    python = {'flake8'},
    vim = {'vint'},
    lua = {'luacheck'},
}

So whenever I save a buffer, I get the hints from the linters, and it's working perfectly!

But I wonder how I can handle the case of non-linted files, like languages without linting configured. Is there something like:

require('lint').linters_by_ft = {
    ... -- python, vim, lua, etc.
    all = {}
}

I know I could simply add a shortcut and trigger the linting on the supported file types, but I want to keep the "on save" flow.

Sends extra blank line to stdin-reading linters

For some linters, a trailing blank line is a problem. But nvim-lint always sends a trailing blank line to stdin-reading linters.

For instance, I am using black via flake8-black via flake8 (for formatting python code). On a well-formatted file I get the warnings 'blank line at end of file' and 'Black would make changes' - neither of which is true.

Is the fix as simple as: don't insert the extra newline here?

I think that solves the immediate problem: but even then nvim-lint will always present a newline at the end of the file, which might not actually be present. Some linters perhaps would like to warn about files that don't end in a newline, which they can never do because all lines that nvim-lint sends do have a newline appended. But that seems less important.

Doesn't work with compound filetypes.

I have a really niche use case here. Both Vim and Neovim have a handy feature that allows a file to be recognized as multiple filetypes, then various scripts and autogroup actions can be ran for each of the filetypes that applies. As an example I'm using the Vimwiki plugin to edit markdown files, some types of markdown can also be considered a pandoc file as well. In neovim if I open a markdown file and issue the command :set filetype it shows the current filetype as vimwiki.markdown.pandoc as expected. However, this plugin doesn't recognize this as a list of filetypes. Instead, as far as I can tell, it recognizes a single filetype vimwiki.markdown.pandoc and doesn't load until I issue the command set filetype=markdown. At any rate, thanks again for this rad plugin!

How to lint golangci

I think the command to run is
lua require'lint'.try_lint('golangcilint')
But there is nothing come out after the command. Is there anything else need to do other than:

  require('lint').linters_by_ft = {
    markdown = {'vale',},
    go = {'golangcilint'},
  }

How to Pass Arguments to Linters?

I was going to use this to run shellcheck for POSIX script (i.e. shellcheck -s sh ), but I can't find how to pass arguments to my linters. Is this supported?

Does nvim-lint has a file length limit?

I'm linting my RST with Vale and found out nvim-lint does not show diagnostics after ~1000th line. When the problematic text is copied to another file, the diagnostics shows fine. In command-line Vale reports the error in text mode and JSON mode. So why is the diagnostics lost?

I've tried Neovim 6.0 and it's even more buggy (misplaced selections, diagnostics goes to DiagnosticsAll).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.