go.nvim/lua/go/asyncmake.lua

332 lines
8.4 KiB
Lua
Raw Normal View History

2021-04-19 06:10:06 +00:00
-- https://phelipetls.github.io/posts/async-make-in-nvim-with-lua/
local M = {}
local util = require("go.utils")
local log = util.log
2022-05-16 23:47:45 +00:00
local getopt = require("go.alt_getopt")
2022-01-17 06:33:00 +00:00
local function compile_efm()
local efm = [[%-G#\ %.%#]]
efm = efm .. [[,%-G%.%#panic:\ %m]]
efm = efm .. [[,%Ecan\'t\ load\ package:\ %m]]
efm = efm .. [[,%A%\\%%\(%[%^:]%\\+:\ %\\)%\\?%f:%l:%c:\ %m]]
efm = efm .. [[,%A%\\%%\(%[%^:]%\\+:\ %\\)%\\?%f:%l:\ %m]]
efm = efm .. [[,%C%*\\s%m]]
efm = efm .. [[,%-G%.%#]]
return efm
end
local namepath = {}
local function extract_filepath(msg)
msg = msg or ""
--[[ or [[ findAllSubStr_test.go:234: Error inserting caseResult1: operation error DynamoDB: PutItem, exceeded maximum number of attempts]]
local pos, _ = msg:find([[[%w_-]+_test%.go:%d+:]])
if pos == nil then
return
end
local pos2 = msg:find(":")
local s = msg:sub(pos, pos2 - 1)
if namepath[s] ~= nil then
return namepath[s]
end
if vim.fn.executable("find") == 0 then
return
end
local cmd = "find ./ -type f -name " .. s
local path = vim.fn.systemlist(cmd)
if vim.v.shell_error ~= 0 then
util.warn("find failed" .. vim.inspect(path))
return
end
for _, value in pairs(path) do
local st, _ = value:find(s)
2022-05-25 06:06:36 +00:00
log(value, st)
if st then
local p = value:sub(1, st - 1)
namepath[st] = p
return p
end
end
end
2022-05-16 23:47:45 +00:00
local long_opts = {
verbose = "v",
compile = "c",
tags = "t",
bench = "b",
2022-05-24 07:23:53 +00:00
run = "r",
2022-05-16 23:47:45 +00:00
floaterm = "F",
}
2022-05-24 07:23:53 +00:00
local short_opts = "vct:bFr:"
2022-05-16 23:47:45 +00:00
local bench_opts = { "-benchmem", "-cpuprofile", "profile.out" }
2021-07-16 14:37:41 +00:00
function M.make(...)
2021-12-10 00:43:59 +00:00
local args = { ... }
local lines = {}
local errorlines = {}
2021-04-19 06:10:06 +00:00
local winnr = vim.fn.win_getid()
local bufnr = vim.api.nvim_win_get_buf(winnr)
local makeprg = vim.api.nvim_buf_get_option(bufnr, "makeprg")
2021-12-10 00:43:59 +00:00
2022-06-01 11:29:13 +00:00
local optarg, _, reminder = getopt.get_opts(args, short_opts, long_opts)
2022-05-16 23:47:45 +00:00
log(makeprg, args, optarg, reminder)
2022-06-01 11:29:13 +00:00
-- local indent = "%\\%( %\\)"
2021-07-16 14:37:41 +00:00
if not makeprg then
log("makeprog not setup")
2021-07-16 14:37:41 +00:00
return
end
2021-04-19 06:10:06 +00:00
local runner = vim.split(makeprg, " ")[1]
if not require("go.install").install(runner) then
util.warn("please wait for " .. runner .. " to be installed and re-run the command")
return
end
local efm = [[%-G#\ %.%#]]
if makeprg:find("go build") then
2021-12-10 00:43:59 +00:00
vim.cmd([[setl errorformat=%-G#\ %.%#]])
-- if makeprg:find("go build") then
2022-01-17 06:33:00 +00:00
efm = compile_efm()
2021-07-16 14:37:41 +00:00
end
-- end
2021-12-10 00:43:59 +00:00
local runner = "golangci-lint"
2021-12-10 00:43:59 +00:00
if makeprg:find("golangci%-lint") then
2021-04-19 06:10:06 +00:00
-- lint
efm = efm .. [[,%A%\\%%(%[%^:]%\\+:\ %\\)%\\?%f:%l:%c:\ %m]]
efm = efm .. [[,%A%\\%%(%[%^:]%\\+:\ %\\)%\\?%f:%l:\ %m]]
2021-12-16 07:15:21 +00:00
local pwd = util.work_path()
local cfg = pwd .. ".golangci.yml"
if util.file_exists(cfg) then
makeprg = makeprg .. [[\ -c\ ]] .. cfg
-- vim.api.nvim_buf_set_option(bufnr, "makeprg", makeprg)
end
2021-04-19 06:10:06 +00:00
end
2022-01-17 06:33:00 +00:00
local compile_test = false
if makeprg:find("test") then
2022-05-24 07:23:53 +00:00
if optarg["c"] then
2022-01-17 06:33:00 +00:00
log("compile test")
compile_test = true
2022-01-17 06:48:16 +00:00
efm = compile_efm()
2022-01-17 06:33:00 +00:00
end
end
if makeprg:find("go run") then
runner = "go run"
if args == nil or #args == 0 or (#args == 1 and args[1] == "-F") then
makeprg = makeprg .. " ."
end
efm = efm .. [[,%A%\\t%#%f:%l\ +0x%[0-9A-Fa-f]%\\+]]
log("go run", makeprg)
end
if makeprg:find("go vet") then
runner = "go vet"
if args == nil or #args == 0 then
makeprg = makeprg .. " ."
end
2022-01-17 06:33:00 +00:00
efm = compile_efm()
efm = efm .. [[,%-Gexit\ status\ %\\d%\\+]]
2021-07-16 14:37:41 +00:00
end
2021-04-19 06:10:06 +00:00
2022-05-24 07:23:53 +00:00
local cmd = vim.fn.split(makeprg, " ")
2022-05-30 14:04:52 +00:00
if optarg["t"] then
local tag = optarg["t"]
2022-05-30 14:04:52 +00:00
local f = tag:find("=")
if not f then
table.insert(cmd, "-tags=" .. tag)
else
table.insert(cmd, "-tags=" .. tag:sub(f + 1))
2022-05-30 14:04:52 +00:00
end
end
if makeprg:find("test") then
log("go test")
runner = "go test"
2022-01-17 06:48:16 +00:00
efm = compile_efm()
2022-05-24 07:23:53 +00:00
if optarg["v"] then
table.insert(cmd, "-v")
end
if optarg["r"] then
log("run test", efm)
2022-05-24 07:23:53 +00:00
table.insert(cmd, "-run")
end
2022-05-30 14:04:52 +00:00
if compile_test then
table.insert(cmd, "-c")
end
2022-05-24 07:23:53 +00:00
end
2021-07-16 14:37:41 +00:00
if args and #args > 0 then
2022-05-16 23:47:45 +00:00
cmd = vim.list_extend(cmd, reminder)
2021-07-16 14:37:41 +00:00
end
2021-09-03 02:13:15 +00:00
2022-01-11 02:50:11 +00:00
local function handle_color(line)
2022-05-24 07:23:53 +00:00
if _GO_NVIM_CFG.run_in_floaterm or optarg["F"] then
2022-01-11 02:50:11 +00:00
return line
end
if tonumber(vim.fn.match(line, "\\%x1b\\[[0-9;]\\+")) < 0 then
return line
end
if type(line) ~= "string" then
return line
end
line = vim.fn.substitute(line, "\\%x1b\\[[0-9;]\\+[mK]", "", "g")
2022-05-25 06:06:36 +00:00
log(line)
2022-01-11 02:50:11 +00:00
return line
end
2022-05-24 07:23:53 +00:00
if _GO_NVIM_CFG.run_in_floaterm or optarg["F"] then
2022-03-23 02:40:15 +00:00
local term = require("go.term").run
cmd = table.concat(cmd, " ")
2022-03-23 02:40:15 +00:00
term({ cmd = cmd, autoclose = false })
return
end
local failed = false
local itemn = 1
local package_path = cmd[#cmd]
local pkg_len = #package_path
2021-04-19 06:10:06 +00:00
local function on_event(job_id, data, event)
2022-01-11 02:50:11 +00:00
-- log("stdout", data, event)
if event == "stdout" then
2021-04-19 06:10:06 +00:00
if data then
for _, value in ipairs(data) do
if value ~= "" then
if value:find("=== RUN") or value:find("no test file") then
goto continue
end
2022-01-11 02:50:11 +00:00
value = handle_color(value)
if value:find("FAIL") then
failed = true
if value == "FAIL" then
goto continue
end
end
local changed = false
if vim.fn.empty(vim.fn.glob(args[#args])) == 0 then
changed = true
if value:find("FAIL") == nil then
local p = extract_filepath(value)
if p then
value = package_path .. util.sep() .. util.ltrim(value)
end
end
else
local p = extract_filepath(value)
if p then
failed = true
value = p .. util.ltrim(value)
changed = true
end
end
trace(value)
table.insert(lines, value)
if itemn == 1 and failed and changed then
itemn = #lines
end
end
::continue::
end
2021-04-19 06:10:06 +00:00
end
end
if event == "stderr" then
if data then
for _, value in ipairs(data) do
if value ~= "" then
table.insert(errorlines, value)
end
end
end
if next(errorlines) ~= nil and runner == "golangci-lint" then
2022-01-11 02:50:11 +00:00
efm =
[[level=%tarning\ msg="%m:\ [%f:%l:%c:\ %.%#]",level=%tarning\ msg="%m",level=%trror\ msg="%m:\ [%f:%l:%c:\ %.%#]",level=%trror\ msg="%m",%f:%l:%c:\ %m,%f:%l:\ %m,%f:%l\ %m]]
end
end
if event == "exit" then
if type(cmd) == "table" then
cmd = table.concat(cmd, " ")
end
2022-05-30 14:32:26 +00:00
local info = cmd
local level = vim.lsp.log_levels.INFO
if #errorlines > 0 then
if #lines > 0 then
vim.list_extend(errorlines, lines)
end
trace(errorlines)
vim.fn.setqflist({}, " ", {
title = cmd,
lines = errorlines,
efm = efm,
})
failed = true
2022-06-01 11:29:13 +00:00
log(errorlines[1], job_id)
vim.cmd([[echo v:shell_error]])
elseif #lines > 0 then
trace(lines)
vim.fn.setqflist({}, " ", {
title = cmd,
lines = lines,
})
end
if tonumber(data) ~= 0 then
failed = true
info = info .. " exited with code: " .. tostring(data)
level = vim.lsp.log_levels.ERROR
end
_GO_NVIM_CFG.job_id = nil
if failed then
cmd = cmd .. " go test failed"
level = vim.lsp.log_levels.WARN
vim.cmd("botright copen")
end
itemn = 1
2022-05-30 14:32:26 +00:00
if failed then
vim.notify(info .. " failed", level)
2022-05-31 06:16:09 +00:00
else
vim.notify(info .. " succeed", level)
2022-05-30 14:32:26 +00:00
end
failed = false
2021-04-19 06:10:06 +00:00
end
end
2022-05-30 14:04:52 +00:00
local cmdstr = vim.fn.join(cmd, " ") -- cmd list run without shell, cmd string run with shell
-- releative dir does not work without shell
log("cmd ", cmdstr)
_GO_NVIM_CFG.job_id = vim.fn.jobstart(cmdstr, {
2021-07-08 16:16:22 +00:00
on_stderr = on_event,
on_stdout = on_event,
on_exit = on_event,
stdout_buffered = true,
2021-12-10 00:43:59 +00:00
stderr_buffered = true,
2021-07-08 16:16:22 +00:00
})
2022-05-24 07:23:53 +00:00
return cmd
2021-04-19 06:10:06 +00:00
end
M.stopjob = function(id)
id = id or _GO_NVIM_CFG.job_id
if id == nil then
return
end
local r = vim.fn.jobstop(id)
if r == 1 then
_GO_NVIM_CFG.job_id = nil
else
util.warn("failed to stop job " .. tostring(id))
end
end
2021-04-19 06:10:06 +00:00
return M