go.nvim/lua/go/format.lua
2022-08-01 17:02:21 +10:00

182 lines
4.7 KiB
Lua

-- golines A golang formatter that fixes long lines
-- golines + goimport
local api = vim.api
local utils = require("go.utils")
local log = utils.log
local max_len = _GO_NVIM_CFG.max_line_len or 120
local goimport = _GO_NVIM_CFG.goimport or "goimports"
local gofmt = _GO_NVIM_CFG.gofmt or "gofumpt"
local vfn = vim.fn
local install = require("go.install").install
local gofmt_args = _GO_NVIM_CFG.gofmt_args or {
"--max-len=" .. tostring(max_len),
"--base-formatter=" .. gofmt,
}
local goimport_args = _GO_NVIM_CFG.goimport_args or {
"--max-len=" .. tostring(max_len),
"--base-formatter=goimports",
}
if vim.lsp.buf.format == nil then
-- vim.notify('the vim.lsp.buf.format is not available, some feature is missing if you are running old version of neovim (<0.8.0)', vim.lsp.log_levels.DEBUG)
-- neovim < 0.7 only
require('go.lsp') -- this set default value of format
end
local run = function(fmtargs, bufnr, cmd)
log(fmtargs, bufnr, cmd)
bufnr = bufnr or 0
if _GO_NVIM_CFG.gofmt == "gopls" then
if not vim.api.nvim_buf_is_loaded(bufnr) then
vfn.bufload(bufnr)
end
vim.cmd("write")
vim.lsp.buf.format({ async = _GO_NVIM_CFG.lsp_fmt_async, bufnr = bufnr, name = "gopls" })
return
end
local args = vim.deepcopy(fmtargs)
table.insert(args, api.nvim_buf_get_name(bufnr))
log("formatting buffer... " .. vim.inspect(args), vim.lsp.log_levels.DEBUG)
if bufnr == 0 then
if vfn.getbufinfo("%")[1].changed == 1 then
vim.cmd("write")
end
end
local old_lines = api.nvim_buf_get_lines(0, 0, -1, true)
if cmd then
table.insert(args, 1, cmd)
else
table.insert(args, 1, "golines")
end
log("fmt cmd:", args)
local j = vfn.jobstart(args, {
on_stdout = function(_, data, _)
data = utils.handle_job_data(data)
if not data then
return
end
if not utils.check_same(old_lines, data) then
vim.notify("updating codes", vim.lsp.log_levels.DEBUG)
api.nvim_buf_set_lines(0, 0, -1, false, data)
vim.cmd("write")
else
vim.notify("already formatted", vim.lsp.log_levels.DEBUG)
end
-- log("stdout" .. vim.inspect(data))
old_lines = nil
end,
on_stderr = function(_, data, _)
data = utils.handle_job_data(data)
log(vim.inspect(data) .. "from stderr")
end,
on_exit = function(_, data, _) -- id, data, event
-- log(vim.inspect(data) .. "exit")
if data ~= 0 then
return vim.notify("golines failed " .. tostring(data), vim.lsp.log_levels.ERROR)
end
old_lines = nil
vim.defer_fn(function()
if vfn.getbufinfo("%")[1].changed == 1 then
vim.cmd("write")
end
end, 300)
end,
stdout_buffered = true,
stderr_buffered = true,
})
vfn.chansend(j, old_lines)
vfn.chanclose(j, "stdin")
end
local M = {}
M.gofmt = function(...)
local long_opts = {
all = "a",
}
local short_opts = "a"
local args = ... or {}
local getopt = require("go.alt_getopt")
local optarg = getopt.get_opts(args, short_opts, long_opts)
log(optarg)
vim.env.GO_FMT = "gofumpt"
local all_buf = false
if optarg["a"] then
all_buf = true
end
if not install(gofmt) then
utils.warn("installing " .. gofmt .. " please retry after installation")
return
end
if not install("golines") then
utils.warn("installing golines , please rerun format after install finished")
return
end
local a = {}
utils.copy_array(gofmt_args, a)
if all_buf then
log("fmt all buffers")
vim.cmd("wall")
local bufs = utils.get_active_buf()
log(bufs)
for _, b in ipairs(bufs) do
log(a, b)
run(a, b.bufnr)
end
else
if vfn.getbufinfo("%")[1].changed == 1 then
vim.cmd("write")
end
run(a, 0)
end
end
M.org_imports = function(wait_ms)
local codeaction = require("go.lsp").codeaction
codeaction("", "source.organizeImports", wait_ms)
if _GO_NVIM_CFG.lsp_fmt_async then
vim.defer_fn(function()
vim.lsp.buf.format({ async = true })
end, 100)
else
vim.lsp.buf.format({ async = false })
end
end
M.goimport = function(...)
local args = { ... }
if _GO_NVIM_CFG.goimport == "gopls" then
if vfn.empty(args) == 1 then
return M.org_imports(1000)
else
local path = select(1, ...)
local gopls = require("go.gopls")
return gopls.import(path)
end
end
local buf = vim.api.nvim_get_current_buf()
require("go.install").install(goimport)
-- specified the pkg name
if #args > 0 then -- dont use golines
return run(args, buf, "goimports")
end
-- golines base formatter is goimports
local a = {}
if goimport == "golines" then
a = vim.deepcopy(goimport_args)
end
run(a, buf, goimport)
end
return M