X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=runtime%2Fplugins%2Flinter%2Flinter.lua;h=b4f759432c2f436e076a90dd942f175c4ed88a24;hb=f9ce549663cb271f3e0391cce4d680615a57ade6;hp=46be745bfd54a360518488177e4536af2306a87d;hpb=4027081e0e31ec90050f51209c4888def57ac1cb;p=micro.git diff --git a/runtime/plugins/linter/linter.lua b/runtime/plugins/linter/linter.lua index 46be745b..b4f75943 100644 --- a/runtime/plugins/linter/linter.lua +++ b/runtime/plugins/linter/linter.lua @@ -1,8 +1,9 @@ +local micro = import("micro") local runtime = import("runtime") local filepath = import("path/filepath") local shell = import("micro/shell") local buffer = import("micro/buffer") -local micro = import("micro") +local config = import("micro/config") local linters = {} @@ -18,14 +19,20 @@ local linters = {} -- errorformat: how to parse the linter/compiler process output -- %f: file, %l: line number, %m: error/warning message -- os: list of OSs this linter is supported or unsupported on --- optional param, default: [] +-- optional param, default: {} -- whitelist: should the OS list be a blacklist (do not run the linter for these OSs) --- or a whitelist (only run the linter for these OSs) +-- or a whitelist (only run the linter for these OSs) -- optional param, default: false (should blacklist) -- domatch: should the filetype be interpreted as a lua pattern to match with --- the actual filetype, or should the linter only activate on an exact match +-- the actual filetype, or should the linter only activate on an exact match -- optional param, default: false (require exact match) -function makeLinter(name, filetype, cmd, args, errorformat, os, whitelist, domatch) +-- loffset: line offset will be added to the line number returned by the linter +-- useful if the linter returns 0-indexed lines +-- optional param, default: 0 +-- coffset: column offset will be added to the col number returned by the linter +-- useful if the linter returns 0-indexed columns +-- optional param, default: 0 +function makeLinter(name, filetype, cmd, args, errorformat, os, whitelist, domatch, loffset, coffset) if linters[name] == nil then linters[name] = {} linters[name].filetype = filetype @@ -35,6 +42,8 @@ function makeLinter(name, filetype, cmd, args, errorformat, os, whitelist, domat linters[name].os = os or {} linters[name].whitelist = whitelist or false linters[name].domatch = domatch or false + linters[name].loffset = loffset or 0 + linters[name].coffset = coffset or 0 end end @@ -48,24 +57,31 @@ function init() devnull = "NUL" end - makeLinter("gcc", "c", "gcc", {"-fsyntax-only", "-Wall", "-Wextra", "%f"}, "%f:%l:%d+:.+: %m") - makeLinter("gcc", "c++", "gcc", {"-fsyntax-only","-std=c++14", "-Wall", "-Wextra", "%f"}, "%f:%l:%d+:.+: %m") + makeLinter("gcc", "c", "gcc", {"-fsyntax-only", "-Wall", "-Wextra", "%f"}, "%f:%l:%c:.+: %m") + makeLinter("gcc", "c++", "gcc", {"-fsyntax-only","-std=c++14", "-Wall", "-Wextra", "%f"}, "%f:%l:%c:.+: %m") makeLinter("dmd", "d", "dmd", {"-color=off", "-o-", "-w", "-wi", "-c", "%f"}, "%f%(%l%):.+: %m") - makeLinter("gobuild", "go", "go", {"build", "-o", devnull}, "%f:%l: %m") - makeLinter("golint", "go", "golint", {"%f"}, "%f:%l:%d+: %m") + makeLinter("gobuild", "go", "go", {"build", "-o", devnull}, "%f:%l:%c:? %m") + -- makeLinter("golint", "go", "golint", {"%f"}, "%f:%l:%c: %m") makeLinter("javac", "java", "javac", {"-d", "%d", "%f"}, "%f:%l: error: %m") makeLinter("jshint", "javascript", "jshint", {"%f"}, "%f: line %l,.+, %m") makeLinter("literate", "literate", "lit", {"-c", "%f"}, "%f:%l:%m", {}, false, true) - makeLinter("luacheck", "lua", "luacheck", {"--no-color", "%f"}, "%f:%l:%d+: %m") - makeLinter("nim", "nim", "nim", {"check", "--listFullPaths", "--stdout", "--hints:off", "%f"}, "%f.%l, %d+. %m") - makeLinter("clang", "objective-c", "xcrun", {"clang", "-fsyntax-only", "-Wall", "-Wextra", "%f"}, "%f:%l:%d+:.+: %m") + makeLinter("luacheck", "lua", "luacheck", {"--no-color", "%f"}, "%f:%l:%c: %m") + makeLinter("nim", "nim", "nim", {"check", "--listFullPaths", "--stdout", "--hints:off", "%f"}, "%f.%l, %c. %m") + makeLinter("clang", "objective-c", "xcrun", {"clang", "-fsyntax-only", "-Wall", "-Wextra", "%f"}, "%f:%l:%c:.+: %m") makeLinter("pyflakes", "python", "pyflakes", {"%f"}, "%f:%l:.-:? %m") makeLinter("mypy", "python", "mypy", {"%f"}, "%f:%l: %m") makeLinter("pylint", "python", "pylint", {"--output-format=parseable", "--reports=no", "%f"}, "%f:%l: %m") - makeLinter("shfmt", "shell", "shfmt", {"%f"}, "%f:%l:%d+: %m") - makeLinter("switfc", "swift", "xcrun", {"swiftc", "%f"}, "%f:%l:%d+:.+: %m", {"darwin"}, true) - makeLinter("switfc", "swiftc", {"%f"}, "%f:%l:%d+:.+: %m", {"linux"}, true) - makeLinter("yaml", "yaml", "yamllint", {"--format", "parsable", "%f"}, "%f:%l:%d+:.+ %m") + makeLinter("shfmt", "shell", "shfmt", {"%f"}, "%f:%l:%c: %m") + makeLinter("swiftc", "swift", "xcrun", {"swiftc", "%f"}, "%f:%l:%c:.+: %m", {"darwin"}, true) + makeLinter("swiftc", "swiftc", {"%f"}, "%f:%l:%c:.+: %m", {"linux"}, true) + makeLinter("yaml", "yaml", "yamllint", {"--format", "parsable", "%f"}, "%f:%l:%c:.+ %m") + + config.MakeCommand("lint", "linter.lintCmd", config.NoComplete) +end + +function lintCmd(bp, args) + bp:Save() + runLinter(bp.Buf) end function contains(list, element) @@ -96,41 +112,55 @@ function runLinter(buf) ftmatch = false end + local args = {} for k, arg in pairs(v.args) do - v.args[k] = arg:gsub("%%f", file):gsub("%%d", dir) + args[k] = arg:gsub("%%f", file):gsub("%%d", dir) end if ftmatch then - lint(buf, k, v.cmd, v.args, v.errorformat) + lint(buf, k, v.cmd, args, v.errorformat, v.loffset, v.coffset) end end end function onSave(bp) - micro.Log("SAVE") runLinter(bp.Buf) - return false + return true end -function lint(buf, linter, cmd, args, errorformat) - buf:ClearMessages("linter") +function lint(buf, linter, cmd, args, errorformat, loff, coff) + buf:ClearMessages(linter) - shell.JobSpawn(cmd, args, "", "", "linter.onExit", buf, linter, errorformat) + shell.JobSpawn(cmd, args, "", "", "linter.onExit", buf, linter, errorformat, loff, coff) end -function onExit(output, buf, linter, errorformat) - micro.Log("ONEXIT") - micro.Log(output) +function onExit(output, args) + local buf, linter, errorformat, loff, coff = args[1], args[2], args[3], args[4], args[5] local lines = split(output, "\n") - local regex = errorformat:gsub("%%f", "(..-)"):gsub("%%l", "(%d+)"):gsub("%%m", "(.+)") + local regex = errorformat:gsub("%%f", "(..-)"):gsub("%%l", "(%d+)"):gsub("%%c", "(%d+)"):gsub("%%m", "(.+)") for _,line in ipairs(lines) do -- Trim whitespace line = line:match("^%s*(.+)%s*$") if string.find(line, regex) then - local file, line, msg = string.match(line, regex) + local file, line, col, msg = string.match(line, regex) + local hascol = true + if not string.find(errorformat, "%%c") then + hascol = false + msg = col + elseif col == nil then + hascol = false + end + micro.Log(basename(buf.Path), basename(file)) if basename(buf.Path) == basename(file) then - local bmsg = buffer.NewMessageAtLine("linter", msg, tonumber(line), buffer.MTError) + local bmsg = nil + if hascol then + local mstart = buffer.Loc(tonumber(col-1+coff), tonumber(line-1+loff)) + local mend = buffer.Loc(tonumber(col+coff), tonumber(line-1+loff)) + bmsg = buffer.NewMessage(linter, msg, mstart, mend, buffer.MTError) + else + bmsg = buffer.NewMessageAtLine(linter, msg, tonumber(line+loff), buffer.MTError) + end buf:AddMessage(bmsg) end end