From c61f9371cdaaec40cccf0783ff968bee83df5bda Mon Sep 17 00:00:00 2001 From: rayx Date: Tue, 8 Aug 2023 17:04:43 -0700 Subject: [PATCH] Fix github pipeline. Make gopls fmt/import async (#366) * fillstruct updates * gopls async fmt/import * github action fix * add gopls tests --- lua/go/format.lua | 34 +++++----- lua/go/lsp.lua | 47 ++++++++------ lua/go/reftool.lua | 58 ++++++++--------- .../fixtures/fill/fill_struct_golden.txt | 7 +- lua/tests/fixtures/fmt/goimports2.go | 2 +- lua/tests/go_fillstruct_spec.lua | 37 ++++++----- lua/tests/go_fmt_spec.lua | 65 +++---------------- lua/tests/go_gopls_spec.lua | 64 ++++++++++++++++++ 8 files changed, 168 insertions(+), 146 deletions(-) create mode 100644 lua/tests/go_gopls_spec.lua diff --git a/lua/go/format.lua b/lua/go/format.lua index b3a5555..81759dd 100644 --- a/lua/go/format.lua +++ b/lua/go/format.lua @@ -7,10 +7,11 @@ local max_len = _GO_NVIM_CFG.max_line_len or 120 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 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 { @@ -151,25 +152,26 @@ M.gofmt = function(...) 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 +M.org_imports = function() + local r = require('go.lsp').codeaction( + '', 'source.organizeImports', function() + if _GO_NVIM_CFG.lsp_fmt_async then + vim.defer_fn(function() + vim.lsp.buf.format({ async = true }) + end, 1) + else + vim.lsp.buf.format({ async = false }) + end + end) end M.goimport = function(...) local goimport = _GO_NVIM_CFG.goimport or 'goimports' local args = { ... } log(args, goimport) - if _GO_NVIM_CFG.goimport == 'gopls' then + if goimport == 'gopls' then if vfn.empty(args) == 1 then - return M.org_imports(1000) + return M.org_imports() else local path = select(1, ...) local gopls = require('go.gopls') diff --git a/lua/go/lsp.lua b/lua/go/lsp.lua index 65ce671..2394cba 100644 --- a/lua/go/lsp.lua +++ b/lua/go/lsp.lua @@ -239,38 +239,43 @@ write", "source", "source.organizeImports" } -- action / fix to take -- only this action 'refactor.rewrite' source.organizeImports -M.codeaction = function(action, only, wait_ms) - wait_ms = wait_ms or 1000 +M.codeaction = function(action, only, hdlr) local params = vim.lsp.util.make_range_params() log(action, only) if only then params.context = { only = { only } } end - local result = vim.lsp.buf_request_sync(0, 'textDocument/codeAction', params, wait_ms) - if not result or next(result) == nil then + local bufnr = vim.api.nvim_get_current_buf() + vim.lsp.buf_request_all(bufnr, 'textDocument/codeAction', params, function(result) + print(vim.inspect(result)) + if not result or next(result) == nil then log('nil result') - return - end - log('code action result', result) - local c = M.client() - for _, res in pairs(result) do - for _, r in pairs(res.result or {}) do - if r.edit and not vim.tbl_isempty(r.edit) then - local re = vim.lsp.util.apply_workspace_edit(r.edit, c.offset_encoding) - log('workspace edit', r, re) - end - if type(r.command) == 'table' then - if type(r.command) == 'table' and r.command.arguments then - for _, arg in pairs(r.command.arguments) do - if action == nil or arg['Fix'] == action then - vim.lsp.buf.execute_command(r.command) - return + return + end + log('code action result', result) + local c = M.client() + for _, res in pairs(result) do + for _, r in pairs(res.result or {}) do + if r.edit and not vim.tbl_isempty(r.edit) then + local re = vim.lsp.util.apply_workspace_edit(r.edit, c.offset_encoding) + log('workspace edit', r, re) + end + if type(r.command) == 'table' then + if type(r.command) == 'table' and r.command.arguments then + for _, arg in pairs(r.command.arguments) do + if action == nil or arg['Fix'] == action then + vim.lsp.buf.execute_command(r.command) + return + end end end end end end - end + if hdlr then + hdlr(result) + end + end) end M.gopls_on_attach = on_attach diff --git a/lua/go/reftool.lua b/lua/go/reftool.lua index 954e95f..61eb008 100644 --- a/lua/go/reftool.lua +++ b/lua/go/reftool.lua @@ -1,59 +1,59 @@ local reftool = {} -local utils = require("go.utils") +local utils = require('go.utils') local log = utils.log local vfn = vim.fn local function insert_result(result) local curpos = vfn.getcurpos() - local goto_l = string.format("goto %d", result["start"] + 1) + local goto_l = string.format('goto %d', result['start'] + 1) vim.cmd(goto_l) local inserts = result.code - inserts = vim.split(inserts, "\n") - local change = string.format("normal! %ds%s", result["end"] - result.start, inserts[1]) + inserts = vim.split(inserts, '\n') + local change = string.format('normal! %ds%s', result['end'] - result.start, inserts[1]) vim.cmd(change) - vim.cmd("startinsert!") + vim.cmd('startinsert!') log(change) local curline = curpos[2] for i = 2, #inserts do - log("append ", curline, inserts[i]) + log('append ', curline, inserts[i]) vfn.append(curline, inserts[i]) curline = curline + 1 end - vim.cmd("stopinsert!") - vim.cmd("write") + vim.cmd('stopinsert!') + vim.cmd('write') -- format(#inserts, curpos) - vfn.setpos(".", curpos) + vfn.setpos('.', curpos) require('go.format').gofmt() end -- can only be fillstruct and fillswitch local function fill(cmd) - if cmd ~= "fillstruct" and cmd ~= "fillswitch" then - log(cmd, "not found") - error("cmd not supported by go.nvim", cmd) + if cmd ~= 'fillstruct' and cmd ~= 'fillswitch' then + log(cmd, 'not found') + error('cmd not supported by go.nvim', cmd) end - require("go.install").install(cmd) + require('go.install').install(cmd) log(cmd) - local file = vfn.expand("%:p") - local line = vfn.line(".") + local file = vfn.expand('%:p') + local line = vfn.line('.') -- local run = string.format("%s -file=%s -line=%d 2>/dev/null", cmd, file, line) - local farg = string.format("-file=%s", file) - local larg = string.format("-line=%d", line) - local args = { cmd, farg, larg, "2>/dev/null" } + local farg = string.format('-file=%s', file) + local larg = string.format('-line=%d', line) + local args = { cmd, farg, larg, '2>/dev/null' } log(args) vfn.jobstart(args, { on_stdout = function(_, str, _) log(str) if #str < 2 then - log("reftools", cmd, "finished with no result") + log('reftools', cmd, 'finished with no result') return end local json = vfn.json_decode(str) if #json == 0 then - vim.notify("reftools " .. cmd .. " finished with no result", vim.log.levels.DEBUG) + vim.notify('reftools ' .. cmd .. ' finished with no result', vim.log.levels.DEBUG) end local result = json[1] @@ -62,23 +62,23 @@ local function fill(cmd) }) end -local function gopls_fillstruct(timeout_ms) - log("fill struct with gopls") - local codeaction = require("go.lsp").codeaction - codeaction("fill_struct", "refactor.rewrite", timeout_ms) +local function gopls_fillstruct() + log('fill struct with gopls') + local codeaction = require('go.lsp').codeaction + codeaction('fill_struct', 'refactor.rewrite') end function reftool.fillstruct() - if _GO_NVIM_CFG.fillstruct == "gopls" then - gopls_fillstruct(1000) + if _GO_NVIM_CFG.fillstruct == 'gopls' then + gopls_fillstruct() else - log("fillstruct") - fill("fillstruct") + log('fillstruct') + fill('fillstruct') end end reftool.fillswitch = function() - fill("fillswitch") + fill('fillswitch') end return reftool diff --git a/lua/tests/fixtures/fill/fill_struct_golden.txt b/lua/tests/fixtures/fill/fill_struct_golden.txt index 6f10459..e7c551e 100644 --- a/lua/tests/fixtures/fill/fill_struct_golden.txt +++ b/lua/tests/fixtures/fill/fill_struct_golden.txt @@ -25,11 +25,8 @@ func fillServer() { Empty: "", Example: 0, Example2: "", - Bar: struct { - Four string - Five string - }{}, - Lala: nil, + Bar: struct{Four string; Five string}{}, + Lala: nil, } _ = sv } diff --git a/lua/tests/fixtures/fmt/goimports2.go b/lua/tests/fixtures/fmt/goimports2.go index ccc3f73..1c45ecc 100644 --- a/lua/tests/fixtures/fmt/goimports2.go +++ b/lua/tests/fixtures/fmt/goimports2.go @@ -2,5 +2,5 @@ package main func foo() { fmt.Println("go.nvim") - time.Date(2020, 1, 1, 1, 1, 1, 1, nil) + time.Date(2020, 1, 1, 1, 1, 1, 1, nil) } diff --git a/lua/tests/go_fillstruct_spec.lua b/lua/tests/go_fillstruct_spec.lua index d129857..db829c6 100644 --- a/lua/tests/go_fillstruct_spec.lua +++ b/lua/tests/go_fillstruct_spec.lua @@ -1,45 +1,46 @@ -local _ = require("plenary/busted") +local _ = require('plenary/busted') local eq = assert.are.same -local cur_dir = vim.fn.expand("%:p:h") +local cur_dir = vim.fn.expand('%:p:h') -- local status = require("plenary.reload").reload_module("go.nvim") -- status = require("plenary.reload").reload_module("nvim-treesitter") -- local ulog = require('go.utils').log -describe("should run fillstruct", function() +describe('should run fillstruct', function() vim.cmd([[packadd go.nvim]]) - require("plenary.reload").reload_module("go.nvim") - require("go").setup({ verbose = true }) -- _GO_NVIM_CFG.fillstruct = "fillstruct" - it("should run fillstruct", function() + it('should run fillstruct', function() -- - local name = vim.fn.tempname() .. ".go" - local path = cur_dir .. "/lua/tests/fixtures/fill/fill_struct_input.go" -- %:p:h ? %:p + local name = vim.fn.tempname() .. '.go' + local path = cur_dir .. '/lua/tests/fixtures/fill/fill_struct_input.go' -- %:p:h ? %:p local lines = vim.fn.readfile(path) vim.fn.writefile(lines, name) - vim.o.ft = "go" - local expected = vim.fn.join(vim.fn.readfile(cur_dir .. "/lua/tests/fixtures/fill/fill_struct_golden.txt"), "\n") + vim.o.ft = 'go' + local expected = vim.fn.join( + vim.fn.readfile(cur_dir .. '/lua/tests/fixtures/fill/fill_struct_golden.txt'), + '\n' + ) local cmd = " silent exe 'e " .. path .. "'" vim.cmd(cmd) + require('plenary.reload').reload_module('go.nvim') + require('go').setup({ verbose = true, lsp_cfg = true }) - vim.cmd("sleep 1000m") -- allow gopls startup - vim.fn.setpos(".", { 0, 20, 14, 0 }) + vim.cmd('sleep 1000m') -- allow gopls startup + vim.fn.setpos('.', { 0, 20, 14, 0 }) - vim.bo.filetype = "go" + vim.bo.filetype = 'go' - require("go.reftool").fillstruct() - require("go.reftool").fillstruct() -- pipeline only, not sure why I need fire a few requests - require("go.reftool").fillstruct() + require('go.reftool').fillstruct() - vim.cmd("sleep 500m") -- allow cleanup + vim.cmd('sleep 500m') -- allow cleanup vim.wait(100, function() local filled = vim.api.nvim_buf_get_lines(0, 0, 40, false) -- local path = cur_dir .. "/lua/tests/fixtures/fill/fill_struct_input.go2" -- %:p:h ? %:p -- vim.fn.writefile(filled, path) - filled = vim.fn.join(filled, "\n") + filled = vim.fn.join(filled, '\n') eq(expected, filled) end) end) diff --git a/lua/tests/go_fmt_spec.lua b/lua/tests/go_fmt_spec.lua index bd8e281..ec64c84 100644 --- a/lua/tests/go_fmt_spec.lua +++ b/lua/tests/go_fmt_spec.lua @@ -14,7 +14,8 @@ describe('should run gofmt', function() print('test:' .. path) local lines = vim.fn.readfile(path) vim.fn.writefile(lines, name) - local expected = vim.fn.join(vim.fn.readfile(cur_dir .. '/lua/tests/fixtures/fmt/hello_golden.go'), '\n') + local expected = + vim.fn.join(vim.fn.readfile(cur_dir .. '/lua/tests/fixtures/fmt/hello_golden.go'), '\n') local cmd = " silent exe 'e " .. name .. "'" vim.cmd(cmd) local l = vim.api.nvim_buf_get_lines(0, 0, -1, true) @@ -44,7 +45,8 @@ describe('should run gofmt', function() print('test:' .. path) local lines = vim.fn.readfile(path) vim.fn.writefile(lines, name) - local expected = vim.fn.join(vim.fn.readfile(cur_dir .. '/lua/tests/fixtures/fmt/hello_golden.go'), '\n') + local expected = + vim.fn.join(vim.fn.readfile(cur_dir .. '/lua/tests/fixtures/fmt/hello_golden.go'), '\n') local cmd = " silent exe 'e " .. name .. "'" vim.cmd(cmd) @@ -70,7 +72,8 @@ describe('should run gofmt', function() end) it('should run import from file with goimports', function() local path = cur_dir .. '/lua/tests/fixtures/fmt/goimports.go' -- %:p:h ? %:p - local expected = vim.fn.join(vim.fn.readfile(cur_dir .. '/lua/tests/fixtures/fmt/goimports_golden.go'), '\n') + local expected = + vim.fn.join(vim.fn.readfile(cur_dir .. '/lua/tests/fixtures/fmt/goimports_golden.go'), '\n') local name = vim.fn.tempname() .. '.go' print(name) local lines = vim.fn.readfile(path) @@ -92,7 +95,8 @@ describe('should run gofmt', function() end) it('should run import from file with goimport with package name', function() local path = cur_dir .. '/lua/tests/fixtures/fmt/goimports.go' -- %:p:h ? %:p - local expected = vim.fn.join(vim.fn.readfile(cur_dir .. '/lua/tests/fixtures/fmt/goimports_golden.go'), '\n') + local expected = + vim.fn.join(vim.fn.readfile(cur_dir .. '/lua/tests/fixtures/fmt/goimports_golden.go'), '\n') local name = vim.fn.tempname() .. '.go' print(name) local lines = vim.fn.readfile(path) @@ -112,57 +116,6 @@ describe('should run gofmt', function() print(fmt) eq(expected, fmt) - end) - - it('should run import from file with gopls', function() - local path = cur_dir .. '/lua/tests/fixtures/fmt/goimports2.go' -- %:p:h ? %:p - local expected = vim.fn.join(vim.fn.readfile(cur_dir .. '/lua/tests/fixtures/fmt/goimports2_golden.go'), '\n') - - local cmd = " silent exe 'e " .. path .. "'" - vim.cmd(cmd) - - vim.cmd([[cd %:p:h]]) - vim.cmd([[packadd go.nvim]]) - require('go').setup({ goimport = 'gopls', lsp_cfg = true }) - _GO_NVIM_CFG.goimport = 'gopls' - vim.wait(1000, function() end) - - require('go.format').goimport() - - print('workspaces:', vim.inspect(vim.lsp.buf.list_workspace_folders())) - vim.wait(700, function() end) - vim.cmd([[w]]) - local fmt = vim.fn.join(vim.fn.readfile(path), '\n') - print(vim.inspect(fmt)) - eq(expected, fmt) - eq(1, 1) -- still not working - cmd = 'bd! ' .. path - vim.cmd(cmd) - end) - it('should run import from file with gopls', function() - local path = cur_dir .. '/lua/tests/fixtures/fmt/goimports3.go' -- %:p:h ? %:p - local expected = vim.fn.join(vim.fn.readfile(cur_dir .. '/lua/tests/fixtures/fmt/goimports3_golden.go'), '\n') - - local cmd = " silent exe 'e " .. path .. "'" - vim.cmd(cmd) - - vim.cmd([[cd %:p:h]]) - vim.cmd([[packadd go.nvim]]) - require('go').setup({ goimport = 'gopls', lsp_cfg = true }) - - _GO_NVIM_CFG.goimport = 'gopls' - vim.wait(2000, function() end) - - require('go.format').goimport() - - print('workspaces:', vim.inspect(vim.lsp.buf.list_workspace_folders())) - vim.wait(500, function() end) - vim.cmd([[w]]) - local fmt = vim.fn.join(vim.fn.readfile(path), '\n') - print(vim.inspect(fmt)) - eq(expected, fmt) - eq(1, 1) -- still not working - cmd = 'bd! ' .. path - vim.cmd(cmd) + vim.cmd('%bdelete!') end) end) diff --git a/lua/tests/go_gopls_spec.lua b/lua/tests/go_gopls_spec.lua new file mode 100644 index 0000000..1cd8f7e --- /dev/null +++ b/lua/tests/go_gopls_spec.lua @@ -0,0 +1,64 @@ +local eq = assert.are.same +local cur_dir = vim.fn.expand('%:p:h') +local busted = require('plenary/busted') + +describe('should run gopls releated functions', function() + -- vim.fn.readfile('minimal.vim') + -- vim.fn.writefile(vim.fn.readfile('fixtures/fmt/hello.go'), name) + require('plenary.reload').reload_module('go.nvim') + local cmd = " silent exe 'e temp.go'" + vim.cmd(cmd) + require('go').setup({ goimport = 'gopls', lsp_cfg = true }) + it('should run import from file with gopls', function() + local path = cur_dir .. '/lua/tests/fixtures/fmt/goimports2.go' -- %:p:h ? %:p + local expected = + vim.fn.join(vim.fn.readfile(cur_dir .. '/lua/tests/fixtures/fmt/goimports2_golden.go'), '\n') + + vim.cmd('%bdelete!') + local cmd = " silent exe 'e " .. path .. "'" + vim.cmd(cmd) + + vim.cmd([[cd %:p:h]]) + _GO_NVIM_CFG.goimport = 'gopls' + vim.wait(2000, function() + return false + end) + require('go.format').goimport() + vim.wait(100, function() + return false + end) + + print('workspaces:', vim.inspect(vim.lsp.buf.list_workspace_folders())) + vim.wait(1000, function() end) + vim.cmd([[wa]]) + local fmt = vim.fn.join(vim.fn.readfile(path), '\n') + print(vim.inspect(fmt)) + eq(expected, fmt) + -- eq(1, 1) -- still not working + cmd = 'bd! ' .. path + vim.cmd(cmd) + end) + it('should run import from file with gopls', function() + vim.cmd('%bdelete!') + local path = cur_dir .. '/lua/tests/fixtures/fmt/goimports3.go' -- %:p:h ? %:p + local expected = + vim.fn.join(vim.fn.readfile(cur_dir .. '/lua/tests/fixtures/fmt/goimports3_golden.go'), '\n') + local cmd = " silent exe 'e " .. path .. "'" + vim.cmd(cmd) + + vim.cmd([[cd %:p:h]]) + vim.wait(500, function() + return false + end) + require('go.format').goimport() + vim.wait(200, function() end) + vim.cmd([[wa]]) + print('workspaces:', vim.inspect(vim.lsp.buf.list_workspace_folders())) + local fmt = vim.fn.join(vim.fn.readfile(path), '\n') + print(vim.inspect(fmt)) + eq(expected, fmt) + -- eq(1, 1) -- still not working + cmd = 'bd! ' .. path + vim.cmd(cmd) + end) +end)