Skip to content

Commit

Permalink
feat: add custom linter event logic
Browse files Browse the repository at this point in the history
  • Loading branch information
xiaoshihou514 committed Dec 23, 2024
1 parent 7bb6967 commit 1eda07b
Show file tree
Hide file tree
Showing 8 changed files with 100 additions and 91 deletions.
8 changes: 6 additions & 2 deletions lua/guard/api.lua
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ function M.enable_fmt(bufnr)
local ft = vim.bo[buf].ft
local head = vim.tbl_get(ft_handler, ft, 'formatter', 1)
if type(head) == 'table' and type(head.events) == 'table' then
events.attach_custom(ft, head.events)
events.fmt_attach_custom(ft, head.events)
else
events.try_attach_fmt_to_buf(buf)
end
Expand All @@ -45,7 +45,11 @@ function M.enable_lint(bufnr)
local buf = bufnr or api.nvim_get_current_buf()
local ft = require('guard.filetype')[vim.bo[buf].ft] or {}
if ft.linter and #ft.linter > 0 then
events.try_attach_lint_to_buf(buf, require('guard.util').linter_events(ft.linter[1]), ft)
events.try_attach_lint_to_buf(
buf,
require('guard.util').linter_events(ft.linter[1]),
vim.bo[buf].ft
)
end
end

Expand Down
10 changes: 6 additions & 4 deletions lua/guard/events.lua
Original file line number Diff line number Diff line change
Expand Up @@ -259,18 +259,20 @@ function M.fmt_attach_custom(ft, events)
end)
end

---@param events EventOption[]
---@param config LintConfig
---@param ft string
function M.lint_attach_custom(ft, events)
function M.lint_attach_custom(ft, config)
M.user_lint_autocmds[ft] = {}
-- we don't know what autocmds are passed in, so these are attached asap
iter(events):each(function(event)
iter(config.events):each(function(event)
table.insert(
M.user_fmt_autocmds[ft],
api.nvim_create_autocmd(
event.name,
maybe_fill_auoption(event.opt or {}, function(opt)
-- TODO
coroutine.resume(coroutine.create(function()
require('guard.lint').do_lint_single(opt.buf, config, true)
end))
end)
)
)
Expand Down
2 changes: 1 addition & 1 deletion lua/guard/filetype.lua
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ local function box(ft)

if type(config) == 'table' and config.events then
-- use user's custom events
events.lint_attach_custom(it, config.events)
events.lint_attach_custom(it, config)
else
events.lint_watch_ft(it, evs)
end
Expand Down
3 changes: 1 addition & 2 deletions lua/guard/format.lua
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,7 @@ local function do_fmt(buf)
if config.fn then
return config.fn(buf, range, acc)
else
config.cwd = config.cwd or cwd
local result = spawn.transform(util.get_cmd(config, fname), config, acc)
local result = spawn.transform(util.get_cmd(config, fname), cwd, config, acc)
if type(result) == 'table' then
-- indicates error
errno = result
Expand Down
99 changes: 58 additions & 41 deletions lua/guard/lint.lua
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
local api = vim.api
local util = require('guard.util')
local ns = api.nvim_create_namespace('Guard')
local spawn = require('guard.spawn')
local vd = vim.diagnostic

local M = {}
local ns = api.nvim_create_namespace('Guard')
local custom_ns = {}

---@param buf number?
function M.do_lint(buf)
Expand All @@ -15,57 +17,72 @@ function M.do_lint(buf)
vim.tbl_map(util.toolcopy, (ft_handler[vim.bo[buf].filetype] or ft_handler['*'] or {}).linter)
)

-- check run condition
local fname, cwd = util.buf_get_info(buf)
linters = vim.tbl_filter(function(config)
return util.should_run(config, buf)
end, linters)

local prev_lines = api.nvim_buf_get_lines(buf, 0, -1, false)
vd.reset(ns, buf)

coroutine.resume(coroutine.create(function()
local results = {}

for _, lint in ipairs(linters) do
---@type string
local data

if lint.cmd then
lint.cwd = lint.cwd or cwd
local out = spawn.transform(util.get_cmd(lint, fname), lint, prev_lines)

-- TODO: unify this error handling logic with formatter
if type(out) == 'table' then
-- indicates error
vim.notify(
'[Guard]: ' .. ('%s exited with code %d\n%s'):format(out.cmd, out.code, out.stderr),
vim.log.levels.WARN
)
data = ''
end
else
data = lint.fn(prev_lines)
end

if #data > 0 then
vim.list_extend(results, lint.parse(data, buf))
end
end

vim.schedule(function()
if not api.nvim_buf_is_valid(buf) or #results == 0 then
return
end
vd.set(ns, buf, results)
vd.reset(ns, buf)
vim.iter(linters):each(function(linter)
M.do_lint_single(buf, linter, false)
end)
end))
end

---@param buf number
---@param config LintConfig
local function do_lint_single(buf, config)
-- TODO
---@param custom boolean
function M.do_lint_single(buf, config, custom)
local lint = util.eval1(config)

-- check run condition
local fname, cwd = util.buf_get_info(buf)
if not util.should_run(lint, buf) then
return
end

local prev_lines = api.nvim_buf_get_lines(buf, 0, -1, false)
if custom and not custom_ns[config] then
custom_ns[config] = custom_ns[config] or api.nvim_create_namespace('')
end
local cns = custom and custom_ns[config] or ns
if custom then
vd.reset(cns, buf)
end

local results = {}

---@type string
local data

if lint.cmd then
local out = spawn.transform(util.get_cmd(lint, fname), cwd, lint, prev_lines)

-- TODO: unify this error handling logic with formatter
if type(out) == 'table' then
-- indicates error
vim.notify(
'[Guard]: ' .. ('%s exited with code %d\n%s'):format(out.cmd, out.code, out.stderr),
vim.log.levels.WARN
)
data = ''
end
else
data = lint.fn(prev_lines)
end

if #data > 0 then
results = lint.parse(data, buf)
end

vim.schedule(function()
if api.nvim_buf_is_valid(buf) and #results ~= 0 then
if not custom then
vim.list_extend(results, vd.get(buf))
end
vd.set(cns, buf, results)
end
end)
end

---@param buf number
Expand Down
10 changes: 7 additions & 3 deletions lua/guard/spawn.lua
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
local M = {}

-- @return table | string
function M.transform(cmd, config, lines)
---@param cmd string[]
---@param cwd string
---@param config FmtConfigTable|LintConfigTable
---@param lines string|string[]
---@return table | string
function M.transform(cmd, cwd, config, lines)
local co = assert(coroutine.running())
local handle = vim.system(cmd, {
stdin = true,
cwd = config.cwd,
cwd = cwd,
env = config.env,
timeout = config.timeout,
}, function(result)
Expand Down
20 changes: 10 additions & 10 deletions lua/guard/util.lua
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ function M.should_run(config, buf)
return true
end

---@return string, string?
---@return string, string
function M.buf_get_info(buf)
local fname = vim.fn.fnameescape(api.nvim_buf_get_name(buf))
---@diagnostic disable-next-line: undefined-field
Expand Down Expand Up @@ -208,18 +208,18 @@ function M.open_info_win()
api.nvim_buf_set_keymap(buf, 'n', 'q', '<cmd>quit!<cr>', {})
end

function M.eval1(x)
if type(x) == 'function' then
return x()
else
return x
end
end

---@param xs (FmtConfig | LintConfig)[]
---@return (FmtConfigTable | LintConfigTable)[]
function M.eval(xs)
return xs
and vim.tbl_map(function(x)
if type(x) == 'function' then
return x()
else
return x
end
end, xs)
or {}
return xs and vim.tbl_map(M.eval1, xs) or {}
end

---@param config LintConfig
Expand Down
39 changes: 11 additions & 28 deletions spec/settings_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ local gapi = require('guard.api')

describe('settings', function()
local bufnr
local ill_lua = {
'local a',
' =42',
}
before_each(function()
if bufnr then
vim.cmd('bdelete! ' .. bufnr)
Expand All @@ -31,10 +35,7 @@ describe('settings', function()
stdin = true,
})

api.nvim_buf_set_lines(bufnr, 0, -1, false, {
'local a',
' =42',
})
api.nvim_buf_set_lines(bufnr, 0, -1, false, ill_lua)
vim.cmd('silent! write')
vim.wait(500)
same({
Expand All @@ -50,10 +51,7 @@ describe('settings', function()
stdin = true,
})

api.nvim_buf_set_lines(bufnr, 0, -1, false, {
'local a',
' =42',
})
api.nvim_buf_set_lines(bufnr, 0, -1, false, ill_lua)
same(true, util.getopt('fmt_on_save'))
vim.cmd('silent! write')
vim.wait(500)
Expand All @@ -64,16 +62,10 @@ describe('settings', function()
vim.g.guard_config = { fmt_on_save = false }

same(false, util.getopt('fmt_on_save'))
api.nvim_buf_set_lines(bufnr, 0, -1, false, {
'local a',
' =42',
})
api.nvim_buf_set_lines(bufnr, 0, -1, false, ill_lua)
vim.cmd('silent! write')
vim.wait(500)
same({
'local a',
' =42',
}, api.nvim_buf_get_lines(bufnr, 0, -1, false))
same(ill_lua, api.nvim_buf_get_lines(bufnr, 0, -1, false))
end)

it('can override save_on_fmt before setting up formatter', function()
Expand All @@ -87,10 +79,7 @@ describe('settings', function()
stdin = true,
})

api.nvim_buf_set_lines(bufnr, 0, -1, false, {
'local a',
' =42',
})
api.nvim_buf_set_lines(bufnr, 0, -1, false, ill_lua)
vim.cmd('silent! write')
vim.wait(100)
gapi.fmt()
Expand All @@ -105,10 +94,7 @@ describe('settings', function()
stdin = true,
})

api.nvim_buf_set_lines(bufnr, 0, -1, false, {
'local a',
' =42',
})
api.nvim_buf_set_lines(bufnr, 0, -1, false, ill_lua)
same(true, util.getopt('save_on_fmt'))
gapi.fmt()
vim.wait(500)
Expand All @@ -127,10 +113,7 @@ describe('settings', function()
vim.wait(500)
same(true, vim.bo[bufnr].modified)

api.nvim_buf_set_lines(bufnr, 0, -1, false, {
'local a',
' =42',
})
api.nvim_buf_set_lines(bufnr, 0, -1, false, ill_lua)
gapi.fmt()
vim.wait(500)
same(true, vim.bo[bufnr].modified)
Expand Down

0 comments on commit 1eda07b

Please sign in to comment.