Skip to content

Commit

Permalink
plugins/lint: init + test
Browse files Browse the repository at this point in the history
  • Loading branch information
GaetanLepage committed Nov 14, 2023
1 parent bbbbfa2 commit 2fcbe50
Show file tree
Hide file tree
Showing 3 changed files with 372 additions and 0 deletions.
1 change: 1 addition & 0 deletions plugins/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
./languages/julia/julia-cell.nix
./languages/lean.nix
./languages/ledger.nix
./languages/lint.nix
./languages/markdown-preview.nix
./languages/nix.nix
./languages/nvim-jdtls.nix
Expand Down
302 changes: 302 additions & 0 deletions plugins/languages/lint.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,302 @@
{
lib,
helpers,
config,
pkgs,
...
}:
with lib; let
cfg = config.plugins.lint;

linterOptions = with types; {
cmd = {
type = str;
description = "The command to call the linter";
example = "linter_cmd";
mandatory = true;
};

stdin = {
type = bool;
description = ''
Whether this parser supports content input via stdin.
In that case the filename is automatically added to the arguments.
Default: `true`
'';
example = false;
};

append_fname = {
type = bool;
description = ''
Automatically append the file name to `args` if `stdin = false`
Whether this parser supports content input via stdin.
In that case the filename is automatically added to the arguments.
Default: `true`
'';
example = false;
};

args = {
type = listOf (either str helpers.rawType);
description = ''
List of arguments.
Can contain functions with zero arguments that will be evaluated once the linter is used.
Default: `[]`
'';
};

stream = {
type = enum ["stdout" "stderr" "both"];
description = ''
configure the stream to which the linter outputs the linting result.
Default: `"stdout"`
'';
example = "stderr";
};

ignore_exitcode = {
type = bool;
description = ''
Whether the linter exiting with a code !=0 should be considered normal.
Default: `false`
'';
example = true;
};

env = {
type = attrsOf str;
description = ''
Custom environment table to use with the external process.
Note that this replaces the **entire** environment, it is not additive.
'';
example = {
FOO = "bar";
};
};

parser = {
type = str;
description = "The code for your parser function.";
example = ''
require('lint.parser').from_pattern(pattern, groups, severity_map, defaults, opts)
'';
apply = s: helpers.ifNonNull' s (helpers.mkRaw s);
mandatory = true;
};
};

mkLinterOpts = noDefaults:
types.submodule {
freeformType = types.attrs;

options =
mapAttrs
(
optionName: (
{
mandatory ? false,
apply ? x: x,
example ? null,
type,
description,
}:
mkOption (
{
inherit
apply
description
example
;
}
// (
if noDefaults && mandatory
# Make this option mandatory
then {
inherit type;
}
# make it optional
else {
type = types.nullOr type;
default = null;
}
)
)
)
)
linterOptions;
};
in {
options.plugins.lint =
helpers.extraOptionsOptions
// {
enable = mkEnableOption "nvim-lint";

package = helpers.mkPackageOption "nvim-lint" pkgs.vimPlugins.nvim-lint;

lintersByFt = mkOption {
type = with types; attrsOf (listOf str);
default = {};
description = ''
Configure the linters you want to run per file type.
Default:
```nix
{
text = ["vale"];
json = ["jsonlint"];
markdown = ["vale"];
rst = ["vale"];
ruby = ["ruby"];
janet = ["janet"];
inko = ["inko"];
clojure = ["clj-kondo"];
dockerfile = ["hadolint"];
terraform = ["tflint"];
}
```
'';
example = {
markdown = ["vale"];
};
};

linters = mkOption {
type = with types;
attrsOf
(mkLinterOpts false);
default = {};
description = ''
Customize the existing linters by overriding some of their properties.
'';
example = {
phpcs.args = [
"-q"
"--report=json"
"-"
];
};
};

customLinters = mkOption {
type = with types;
attrsOf
(
either
str
(mkLinterOpts true)
);
default = {};
description = ''
Configure the linters you want to run per file type.
It can be both an attrs or a string containing the lua code that returns the appropriate
table.
'';
example = {
};
};

autoCmd = let
defaultEvent = "BufWritePost";
defaultCallback = helpers.mkRaw ''
function()
require('lint').try_lint()
end
'';
in
mkOption {
type = with types;
nullOr (submodule {
options =
helpers.autocmd.autoCmdOptions
// {
event = mkOption {
type = with types;
nullOr
(
either
str
(listOf str)
);
default = defaultEvent;
description = "The event or events that should trigger linting.";
};

callback = mkOption {
type = with types;
nullOr (either str helpers.rawType);
default = defaultCallback;
description = "What action to perform for linting";
};
};
});
description = ''
The configuration for the linting autocommand.
You can disable it by setting this option to `null`.
'';
default = {
event = defaultEvent;
callback = defaultCallback;
};
};
};

config = mkIf cfg.enable {
extraPlugins = [cfg.package];

extraConfigLua =
''
__lint = require('lint')
__lint.linters_by_ft = ${helpers.toLuaObject cfg.lintersByFt}
''
+ (
optionalString
(cfg.linters != {})
(
concatLines
(
flatten
(
mapAttrsToList
(
linter: linterConfig:
mapAttrsToList
(
propName: propValue:
optionalString
(propValue != null)
"__lint.linters.${linter}.${propName} = ${helpers.toLuaObject propValue}"
)
linterConfig
)
cfg.linters
)
)
)
)
+ (
optionalString
(cfg.customLinters != {})
(
concatLines
(
mapAttrsToList
(customLinter: linterConfig: let
linterConfig' =
if isString linterConfig
then helpers.mkRaw linterConfig
else linterConfig;
in "__lint.linters.${customLinter} = ${helpers.toLuaObject linterConfig'}")
cfg.customLinters
)
)
);

# autoCmd = optional (cfg.autoCmd != null) cfg.autoCmd;
};
}
69 changes: 69 additions & 0 deletions tests/test-sources/plugins/languages/lint.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
{
empty = {
plugins.lint.enable = true;
};

example = {
plugins.lint = {
enable = true;

lintersByFt = {
text = ["vale"];
json = ["jsonlint"];
markdown = ["vale"];
rst = ["vale"];
ruby = ["ruby"];
janet = ["janet"];
inko = ["inko"];
clojure = ["clj-kondo"];
dockerfile = ["hadolint"];
terraform = ["tflint"];
};
linters = {
phpcs.args = [
"-q"
"--report=json"
"-"
];
};
customLinters = {
foo = {
cmd = "foo_cmd";
stdin = true;
append_fname = false;
args = [];
stream = "stderr";
ignore_exitcode = false;
env = {
FOO = "bar";
};
parser = ''
require('lint.parser').from_pattern(pattern, groups, severity_map, defaults, opts)
'';
};
foo2 = {
cmd = "foo2_cmd";
parser = ''
require('lint.parser').from_pattern(pattern, groups, severity_map, defaults, opts)
'';
};
bar.__raw = ''
function()
return {
cmd = "foo_cmd",
stdin = true,
append_fname = false,
args = {},
stream = "stderr",
ignore_exitcode = false,
env = {
["FOO"] = "bar",
},
parser = require('lint.parser').from_pattern(pattern, groups, severity_map, defaults, opts),
}
end
'';
};
};
};
}

0 comments on commit 2fcbe50

Please sign in to comment.