From df512d695fb711ee70633aa626e39df2e9221471 Mon Sep 17 00:00:00 2001 From: ray-x Date: Mon, 18 Apr 2022 22:31:17 +1000 Subject: [PATCH] issue #94 GoImport autocomplete --- README.md | 1 + lua/go/format.lua | 13 ++++++-- lua/go/godoc.lua | 2 +- lua/go/gopls.lua | 55 ++++++++++++++++++++++++++-------- lua/go/gotest.lua | 75 +++++++++++++++++++++++++++++++++++++++++++++++ lua/go/ts/go.lua | 21 +++++++++++-- 6 files changed, 148 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 65ea931..01c6137 100644 --- a/README.md +++ b/README.md @@ -258,6 +258,7 @@ gofmt) | -------- | --------------------------- | | GoFmt | goline + gofumpt | | GoImport | goline + goimport + gofumpt | +| GoImport package_path | gopls add_import package | ## GoImpl diff --git a/lua/go/format.lua b/lua/go/format.lua index 2e199ff..552e834 100644 --- a/lua/go/format.lua +++ b/lua/go/format.lua @@ -90,9 +90,16 @@ end M.goimport = function(...) local args = { ... } - if vim.fn.empty(args) == 1 and _GO_NVIM_CFG.goimport == "gopls" then - M.org_imports(1000) - return + if _GO_NVIM_CFG.goimport == "gopls" then + if vim.fn.empty(args) == 1 then + M.org_imports(1000) + return + else + local path = select(1, ...) + local gopls = require("go.gopls") + gopls.import(path) + return + end end local a1 = select(1, args) local buf = true diff --git a/lua/go/godoc.lua b/lua/go/godoc.lua index 7a08553..b43418e 100644 --- a/lua/go/godoc.lua +++ b/lua/go/godoc.lua @@ -98,7 +98,6 @@ function m.doc_complete(arglead, cmdline, cursorpos) local pkgs = gopls.list_pkgs() if pkgs then local match = {} - trace(pkgs) if #words > 1 and #words[#words] > 0 then for _, value in ipairs(pkgs) do if string.match(value, words[#words]) then @@ -108,6 +107,7 @@ function m.doc_complete(arglead, cmdline, cursorpos) else match = pkgs end + log(match) return table.concat(match or {}, "\n") end end diff --git a/lua/go/gopls.lua b/lua/go/gopls.lua index f61cd8b..950808d 100644 --- a/lua/go/gopls.lua +++ b/lua/go/gopls.lua @@ -2,6 +2,7 @@ local utils = require("go.utils") local log = utils.log local M = {} +local cmds = {} -- https://go.googlesource.com/tools/+/refs/heads/master/gopls/doc/commands.md -- "executeCommandProvider":{"commands":["gopls.add_dependency","gopls.add_import","gopls.apply_fix","gopls.check_upgrades","gopls.gc_details","gopls.generate","gopls.generate_gopls_mod","gopls.go_get_package","gopls.list_known_packages","gopls.regenerate_cgo","gopls.remove_dependency","gopls.run_tests","gopls.start_debugging","gopls.test","gopls.tidy","gopls.toggle_gc_details","gopls.update_go_sum","gopls.upgrade_dependency","gopls.vendor","gopls.workspace_metadata"]} @@ -15,6 +16,7 @@ local gopls_cmds = { "gopls.generate_gopls_mod", "gopls.go_get_package", "gopls.list_known_packages", + "gopls.list_imports", "gopls.regenerate_cgo", "gopls.remove_dependency", "gopls.run_tests", @@ -28,11 +30,17 @@ local gopls_cmds = { "gopls.workspace_metadata", } +local gopls_with_result = { + "gopls.gc_details", + "gopls.list_known_packages", + "gopls.list_imports", +} + local function check_for_error(msg) if msg ~= nil and type(msg[1]) == "table" then for k, v in pairs(msg[1]) do if k == "error" then - log.error("LSP", v.message) + log("LSP", v.message) break end end @@ -41,25 +49,48 @@ end for _, value in ipairs(gopls_cmds) do local fname = string.sub(value, #"gopls." + 1) - M[fname] = function(arg) + cmds[fname] = function(arg) log(fname) local b = vim.api.nvim_get_current_buf() local uri = vim.uri_from_bufnr(b) - local arguments = { { URI = uri, URIs = { uri } } } - arguments = vim.tbl_extend("keep", arguments, arg or {}) + local arguments = { { URI = uri } } - local resp = vim.lsp.buf_request_sync(b, "workspace/executeCommand", { - command = value, - arguments = arguments, - }) - check_for_error(resp) - log(resp) - return resp + local ft = vim.bo.filetype + if ft == "gomod" or ft == "gosum" then + arguments = { { URIs = { uri } } } + end + arguments = { vim.tbl_extend("keep", arguments[1], arg or {}) } + + if vim.tbl_contains(gopls_with_result, value) then + local resp = vim.lsp.buf_request_sync(b, "workspace/executeCommand", { + command = value, + arguments = arguments, + }, 2000) + check_for_error(resp) + log(resp) + + return resp + end + + vim.schedule(function() + local resp = vim.lsp.buf.execute_command({ + command = value, + arguments = arguments, + }) + check_for_error(resp) + log(resp) + end) end end +M.import = function(path) + cmds.add_import({ + ImportPath = path, + }) +end + M.list_pkgs = function() - local resp = M.list_known_packages() + local resp = cmds.list_known_packages() or {} local pkgs = {} for _, response in pairs(resp) do diff --git a/lua/go/gotest.lua b/lua/go/gotest.lua index db75130..48b3654 100644 --- a/lua/go/gotest.lua +++ b/lua/go/gotest.lua @@ -313,4 +313,79 @@ M.test_file = function(...) utils.log("test cmd: ", cmd, " finished") end +-- TS based run func +-- https://github.com/rentziass/dotfiles/blob/master/vim/.config/nvim/lua/rentziass/lsp/go_tests.lua +M.run_file = function() + local bufnr = vim.api.nvim_get_current_buf() + local tree = vim.treesitter.get_parser(bufnr):parse()[1] + local query = vim.treesitter.parse_query("go", require("go.ts.textobjects").query_test_func) + + local test_names = {} + for id, node, metadata in query:iter_captures(tree:root(), bufnr, 0, -1) do + local name = query.captures[id] -- name of the capture in the query + if name == "test_name" then + table.insert(test_names, vim.treesitter.get_node_text(node, bufnr)) + end + end + + vim.schedule(function() + vim.lsp.buf.execute_command({ + command = "gopls.run_tests", + arguments = { { URI = vim.uri_from_bufnr(0), Tests = test_names } }, + }) + end) +end + +M.select_tests = function() + local bufnr = vim.api.nvim_get_current_buf() + local tree = vim.treesitter.get_parser(bufnr):parse()[1] + local query = vim.treesitter.parse_query("go", require("go.ts.textobjects").query_test_func) + local test_names = {} + for id, node, metadata in query:iter_captures(tree:root(), bufnr, 0, -1) do + local name = query.captures[id] -- name of the capture in the query + if name == "test_name" then + table.insert(test_names, vim.treesitter.get_node_text(node, bufnr)) + end + end + + local guihua = utils.load_plugin("guihua.lua", "guihua.gui") + local original_select = vim.ui.select + + if guihua then + vim.ui.select = require("guihua.gui").select + end + + local title = "Possible Tests" + pickers.new({}, { + prompt_title = title, + finder = finders.new_table({ + results = test_names, + entry_maker = function(entry) + return { + value = entry, + text = entry, + display = entry, + ordinal = entry, + } + end, + }), + previewer = false, + sorter = conf.generic_sorter({}), + attach_mappings = function(_) + actions.select_default:replace(function(prompt_bufnr) + local selection = action_state.get_selected_entry() + vim.schedule(function() + vim.lsp.buf.execute_command({ + command = "gopls.run_tests", + arguments = { { URI = vim.uri_from_bufnr(0), Tests = { selection.value } } }, + }) + end) + + actions.close(prompt_bufnr) + end) + return true + end, + }):find() +end + return M diff --git a/lua/go/ts/go.lua b/lua/go/ts/go.lua index 167aa09..b06eb47 100644 --- a/lua/go/ts/go.lua +++ b/lua/go/ts/go.lua @@ -84,10 +84,25 @@ M = { parameters: (parameter_list)@method.parameter result: (type_identifier)@method.result body:(block) - )@method.declaration)]] + )@method.declaration)]], + query_test_func = [[ + ( + (function_declaration + name: (identifier) @test_name + parameters: (parameter_list + (parameter_declaration + name: (identifier) + type: (pointer_type + (qualified_type + package: (package_identifier) @_param_package + name: (type_identifier) @_param_name)))) + ) @testfunc + (#contains? @test_name "Test") + (#match? @_param_package "testing") + (#match? @_param_name "T"))]], } local function get_name_defaults() - return {["func"] = "function", ["if"] = "if", ["else"] = "else", ["for"] = "for"} + return { ["func"] = "function", ["if"] = "if", ["else"] = "else", ["for"] = "for" } end M.get_struct_node_at_pos = function(row, col, bufnr) @@ -97,7 +112,7 @@ M.get_struct_node_at_pos = function(row, col, bufnr) if ns == nil then warn("struct not found") else - log('struct node', ns) + log("struct node", ns) return ns[#ns] end end