vis-lint

vis plugin for linting code
git clone anongit@rnpnr.xyz:vis-lint.git
Log | Files | Refs | Feed | README | LICENSE

init.lua (2967B)


      1 local lint = {}
      2 
      3 lint.linters = {}
      4 lint.linters["bash"] = {"shellcheck -"}
      5 lint.linters["json"] = {"jq"}
      6 lint.linters["lua"] = {"luacheck --no-color -"}
      7 lint.linters["man"] = {"mandoc -T lint"}
      8 lint.linters["meson"] = {"muon check -"}
      9 lint.linters["python"] = {"black --quiet --check -", "isort --check -"}
     10 lint.linters["rust"] = {"rustfmt --check", "clippy-driver -"}
     11 
     12 lint.fixers = {}
     13 lint.fixers["json"] = {"jq"}
     14 lint.fixers["meson"] = {"muon fmt -"}
     15 lint.fixers["python"] = {"black -", "isort -"}
     16 lint.fixers["rust"] = {"rustfmt"}
     17 
     18 lint.log = {}
     19 lint.log.INFO = 1
     20 lint.log.ERROR = 2
     21 lint.log.OUTPUT = 3
     22 
     23 lint.logger = function(str, level)
     24 	if level == lint.log.INFO then
     25 		vis:info(str)
     26 	else
     27 		vis:message(str)
     28 	end
     29 end
     30 
     31 local run_on_file = function(cmd, file, range, modify)
     32 	if range == nil or range.finish - range.start <= 1 then
     33 		range = {start = 0, finish = file.size}
     34 	end
     35 	local ret, ostr, estr = vis:pipe(file, range, cmd)
     36 	if ostr ~= nil or estr ~= nil then
     37 		if (modify and ostr) then
     38 			local pos = vis.win.selection.pos
     39 			file:delete(range.start, range.finish)
     40 			file:insert(range.start, ostr)
     41 			vis.win.selection.pos = pos
     42 		else
     43 			if ostr then lint.logger(ostr, lint.log.OUTPUT) end
     44 		end
     45 		if estr then lint.logger(estr, lint.log.ERROR) end
     46 		vis:redraw()
     47 	end
     48 	return ret
     49 end
     50 
     51 local run_actions_on_file = function(actions, file, range, modify)
     52 	local cmds = actions[vis.win.syntax]
     53 	if cmds == nil or #cmds == 0 then
     54 		lint.logger("vis-lint: action not defined for vis.win.syntax = "
     55 			.. (vis.win.syntax or "undefined"), lint.log.INFO)
     56 		return
     57 	end
     58 	-- print this to separate different outputs in the message buffer
     59 	local prefix = "--- "
     60 	lint.logger(prefix .. "vis-lint: (" .. os.date() .. ")")
     61 	local all_succeeded = true
     62 	local failure_count = 0
     63 	for _, cmd in ipairs(cmds) do
     64 		lint.logger(prefix .. "piping "
     65 			.. (file.name or "buffer")
     66 			.. (range and "<" .. range.start ..  "," .. range.finish .. ">" or "")
     67 			.. " to `" .. cmd .. "`")
     68 		local ret = run_on_file(cmd, file, range, modify)
     69 		if ret ~= 0 then
     70 			all_succeeded = false
     71 			failure_count = failure_count + 1
     72 			-- exit early if modify was specified
     73 			if modify then
     74 				lint.logger("Command failed with exit code: " .. ret, lint.log.ERROR)
     75 				return false
     76 			end
     77 		end
     78 	end
     79 	lint.logger(prefix .. #cmds .. " commands done, " .. failure_count .. " reported a problem")
     80 	return all_succeeded
     81 end
     82 
     83 lint.lint = function(file, range)
     84 	return run_actions_on_file(lint.linters, file, range)
     85 end
     86 
     87 lint.fix = function(file, range)
     88 	return run_actions_on_file(lint.fixers, file, range, true)
     89 end
     90 
     91 vis:command_register("lint", function(argv, force, win, selection, range)
     92 	return lint.lint(win.file, range)
     93 end, "Lint the current file and display output in the message window")
     94 
     95 vis:command_register("fix", function(argv, force, win, selection, range)
     96 	return lint.fix(win.file, range)
     97 end, "Pipe the current file through defined fixers. Modifies the buffer.")
     98 
     99 return lint