Micro: Clarification for adding linter support

Created on 9 Jul 2020  路  5Comments  路  Source: zyedidia/micro

First I want to say I love Micro. It's got just the right blend of functionality and simplicity that works for much of what I do. I typically stay away from bloated IDE's, and my normal go-to is Sublime but sometimes even that is a bit more than I want. I like the minimal linting provided by Micro but jshint is a little dated. A lot of people are moving to ESLint for JavaScript.

Micro's built-in linter doesn't support ESLint by default. This was also the subject of https://github.com/zyedidia/micro/issues/1089.

I'm generalizing this issue to adding support for any linter.

I am willing to do that myself and make a PR, but I'm a little confused as to how to go about it. From what I can tell, I should make my own plugin first and make sure it works. > help linter tells me

The linter plugin also allows users to extend the supported filetypes. From inside another micro plugin, the function linter.makeLinter can be called to register a new filetype. Here is the spec for the makeLinter function:

 linter.makeLinter(name, filetype, cmd, args, errorformat, os, whitelist, domatch, loffset, coffset, callback)

Then, it gives an example.

Below is an example for including a linter for any filetype using the misspell linter which checks for misspelled words in a file.

local config = import("micro/config")

config.RegisterCommonOption("misspell", true)

function init()
    -- uses the default linter plugin
    -- matches any filetype
    linter.makeLinter("misspell", "", "misspell", {"%f"}, "%f:%l:%c: %m", {}, false, true, 0, 0, hasMisspell)
end

function hasMisspell(buf)
    return buf.Settings["misspell"]
end

So let me get this straight. config.Registerregisters a new plugin called misspell and has it default to being enabled. hasMisspell is a check for whether it is enabled in Micro's settings. linter.makeLinter is the line that defines the linter in Micro. Once I get that working, I can submit a PR with the makeLinter call included in https://github.com/zyedidia/micro/blob/04f281bf1d79d2f8178e99ff0f2443b411e4dc1d/runtime/plugins/linter/linter.lua#L68-L86

Version: 2.0.6
Commit hash: 60846f5
Compiled on June 24, 2020

All 5 comments

ok here's what I've got:
ESLint on an example file splash-page.js with eslint -f compact splash-page.js outputs

/home/efrem/Dropbox/Coding/Projects/Heatflask/frontend/src/js/splash-page.js: line 13, col 7, Error - 'ga' is assigned a value but never used. (no-unused-vars)
/home/efrem/Dropbox/Coding/Projects/Heatflask/frontend/src/js/splash-page.js: line 20, col 1, Error - Mixed spaces and tabs. (no-mixed-spaces-and-tabs)

so for eslint.lua I have

local config = import("micro/config")
config.RegisterCommonOption("eslint", true)

function init()
    -- linter.makeLinter("eslint", "javascript", "eslint", {"-f","compact","%f"}, "%f: line %l,.+,  %m", {}, false, true, 0, 0, hasESLint)
    linter.makeLinter("eslint", "javascript", "eslint", {"-f","compact","%f"}, ".+: line %l,.+,  %m", {})
end

function hasESLint(buf)
    return buf.Settings["eslint"]
end

When starting micro I get the error

eslint:4: invalid number of function arguments (3 expected, got 2)
stack traceback:
    [G]: in function 'RegisterCommonOption'
    eslint:4: in main chunk
    [G]: ?

According to plugins.md,

RegisterCommonOption(pl string, name string, defaultvalue interface{}): registers a new option with for the given plugin. The name of the option will be pl.name, and will have the given default value. Since this registers a common option, the option will be modifiable on a per-buffer basis, while also having a global value (in the GlobalSettings map).

I'm confused by this.

Also I tried removing the RegisterCommonOption call and removing the hasESLint callback but then no linting happens.

Thanks in advance for any suggestions!

Ah sorry about that it appears the documentation example for the linter is slightly outdated. Now plugins all automatically have an option associated with them (to enable or disable individual plugins) so there is no need to register a "misspell" option to enable/disable the plugin functionality. FYI the third argument is the default value for that option, i.e. true, or false, or 1, etc... The interface{} type means in Go-speak that the argument may be any type.

For your case, you can just get rid of all the option stuff, and make sure you use the %f directive in your regex so that the filename is parsed from the error message. The following plugin worked for me (I put this code in ~/.config/micro/init.lua, but it could also be a separate plugin in ~/.config/micro/plug/eslint/ for example):

function init()
    linter.makeLinter("eslint", "javascript", "eslint", {"-f","compact","%f"}, "%f: line %l, col %c, %m")
end

I also added %c since you may as well match the column number as well because eslint includes it.

Since you say that eslint is the new standard for javascript, I have gone ahead and added it to the default linter plugin.

Thanks @zyedidia! One more thing: I tried updating with > plugin update linter and got

Checking for plugin updates
unable to find a matching version for "linter"

In fact I cannot update at all. If I do a general > plugin update I get

Checking for plugin updates
unable to find a matching version for "filemanager"

I guess because filemanager is the first plugin it tries and then quits there. For now I'll just put what you did in ~/.config/micro/init.lua.

The linter plugin is a default plugin, meaning it is bundled directly inside the micro binary. This means that it can't be updated like a normal plugin. The way to update it would be to download a new version of micro (i.e. the nightly build). Of course you can also just put the code from above in init.lua.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ns-cweber picture ns-cweber  路  4Comments

Bigguy34 picture Bigguy34  路  3Comments

zanglebert picture zanglebert  路  4Comments

johnmbaughman picture johnmbaughman  路  3Comments

Rbagman picture Rbagman  路  4Comments