go.nvim/lua/go/null_ls.lua

178 lines
5.2 KiB
Lua

local vim, fn = vim, vim.fn
local utils = require('go.utils')
local log = utils.log
local extract_filepath = utils.extract_filepath
local function handler()
local severities = { error = 1, warning = 2, information = 3, hint = 4 }
return function(msg, done)
if msg == nil or msg.output == nil then
return
end
if msg.lsp_method == 'textDocument/didChange' or msg.method == 'NULL_LS_DIAGNOSTICS' then
-- there is no need to run on didChange, has to run until fil saved
return log('skip didChange')
end
if vim.fn.empty(msg.err) == 0 then
log('error', msg.err)
return
end
log(msg.method)
local msgs = msg.output
msgs = vim.split(msgs, '\n', true)
local diags = {}
local package, filename, line
-- the output is jsonencoded
local output = ''
local qf = {}
for _, m in pairs(msgs) do
if vim.fn.empty(m) == 0 then
local entry = vim.fn.json_decode(m)
if entry.Action == 'run' then
package = entry.Package
output = ''
elseif entry.Action == 'output' then
if vim.fn.empty(entry.Output) == 0 then
local ma = vim.fn.matchlist(entry.Output, [[\v\s*(\w+.+\.go):(\d+):]])
if ma[2] then
log(ma)
filename = package .. utils.sep() .. ma[2]
if fn.filereadable(filename) == 0 then
filename = fn.fnamemodify(fn.expand('%:h'), ':~:.') .. utils.sep() .. ma[2]
end
line = ma[3]
end
output = output .. (entry.Output or '')
-- log(output or 'nil')
end
elseif entry.Action == 'pass' or entry.Action == 'skip' then
-- log(entry)
-- reset
output = ''
elseif entry.Action == 'fail' and vim.fn.empty(output) == 0 then
log(entry)
if filename:find(fn.expand('%:t')) then -- can be output from other files
table.insert(diags, {
file = filename,
row = tonumber(line),
col = 1,
message = output,
severity = severities.error,
source = 'go test',
})
end
local qflines = vim.split(output, '\n')
for i, value in ipairs(qflines) do
local p = extract_filepath(value)
if p then
value = p .. utils.ltrim(value)
end
qflines[i] = value
end
vim.list_extend(qf, qflines)
output = ''
end
end
if #qf > 0 then
local efm = require('go.gotest').efm()
vim.fn.setqflist({}, ' ', { title = 'gotest', lines = qf, efm = efm })
end
end
log(diags)
-- local ok, d = pcall(vim.fn.json_decode, msg)
return done(diags)
end
end
-- register with
-- null_ls.register(gotest)
return {
gotest = function()
local nulls = utils.load_plugin('null-ls', 'null-ls')
if nulls == nil then
vim.notify('failed to load null-ls', vim.lsp.log_levels.WARN)
return
end
local null_ls = require('null-ls')
local methods = require('null-ls.methods')
return {
name = 'gotest',
method = null_ls.methods.DIAGNOSTICS_ON_SAVE,
filetypes = { 'go' },
generator = null_ls.generator({
command = 'go',
args = function()
local a = { 'test', '-json' }
local pkg = require('go.gotest').get_test_path()
table.insert(a, pkg)
log(a)
return a
end,
to_stdin = false,
method = methods.internal.DIAGNOSTICS_ON_SAVE,
from_stderr = false,
format = 'raw',
check_exit_code = function(code, stderr)
local success = code <= 1
log(code, stderr)
if not success then
-- can be noisy for things that run often (e.g. diagnostics), but can
-- be useful for things that run on demand (e.g. formatting)
vim.notify('go test failed: ' .. tostring(stderr))
end
return true
end,
on_output = handler(),
}),
}
end,
gotest_action = function()
return {
name = 'gotest nearest',
meta = {
url = 'https://github.com/ray-x/go.nvim',
description = 'test go code',
},
method = require('null-ls.methods').internal.CODE_ACTION,
filetypes = { 'go' },
generator = {
fn = function(params)
local f, _, is_test = require('go.alternate').is_test_file()
if not is_test then
return
end
local actions = {}
local gt = require('go.gotest')
local cb = function()
local test_actions = gt.test_func
if not test_actions then
return
end
log('gotest action')
test_actions()
end
local fname = gt.get_test_func_name()
log(fname)
if fname then
-- local mode = vim.api.nvim_get_mode().mode
table.insert(actions, {
title = 'gotest ' .. fname.name,
action = function()
vim.api.nvim_buf_call(params.bufnr, cb)
end,
})
end
return actions
end,
},
}
end,
}