diff --git a/README.md b/README.md index 22e607a..ffc1c09 100644 --- a/README.md +++ b/README.md @@ -388,6 +388,7 @@ require('go').setup({ fillstruct = 'gopls', -- can be nil (use fillstruct, slower) and gopls lsp_diag_hdlr = true, -- hook lsp diag handler dap_debug = true, -- set to false to disable dap + textobjects = true, -- enable default text jobects through treesittter-text-objects test_runner = 'go', -- richgo, go test, richgo, dlv, ginkgo run_in_floaterm = false, -- set to true to run in float window. --float term recommand if you use richgo/ginkgo with terminal color diff --git a/lua/go.lua b/lua/go.lua index 2ce5ee5..d5b8c67 100644 --- a/lua/go.lua +++ b/lua/go.lua @@ -20,6 +20,7 @@ _GO_NVIM_CFG = { gocoverage_sign = "█", gocoverage_sign_priority = 5, dap_debug = true, + textobjects = true, dap_debug_gui = true, dap_vt = true, -- false, true and 'all frames' gopls_cmd = nil, --- you can provide gopls path and cmd if it not in PATH, e.g. cmd = { "/home/ray/.local/nvim/data/lspinstall/go/gopls" } @@ -78,7 +79,9 @@ function go.setup(cfg) ) -- vim.cmd([[command! GoTestCompile :setl makeprg=go\ build | :GoMake]]) --print-issued-lines=false - vim.cmd([[command! GoLint :setl makeprg=golangci-lint\ run\ --print-issued-lines=false\ --exclude-use-default=false | :GoMake]]) + vim.cmd( + [[command! GoLint :setl makeprg=golangci-lint\ run\ --print-issued-lines=false\ --exclude-use-default=false | :GoMake]] + ) -- e.g. GoTestFunc unit vim.cmd([[command! -nargs=* GoTestFunc lua require('go.gotest').test_fun()]]) @@ -157,6 +160,9 @@ function go.setup(cfg) require("go.codelens").setup() end + if _GO_NVIM_CFG.textobjects then + require('go.ts.textobjects').setup() + end -- TODO remove in future vim.cmd([[command! Gofmt echo 'use GoFmt']]) vim.cmd([[command! -nargs=* Goimport echo 'use GoImport']]) diff --git a/lua/go/asyncmake.lua b/lua/go/asyncmake.lua index 7993d9f..b545e11 100644 --- a/lua/go/asyncmake.lua +++ b/lua/go/asyncmake.lua @@ -1,6 +1,7 @@ -- https://phelipetls.github.io/posts/async-make-in-nvim-with-lua/ local M = {} -local log = require("go.utils").log +local util = require("go.utils") +local log = util.log function M.make(...) local args = { ... } local lines = {} @@ -28,6 +29,14 @@ function M.make(...) -- lint vim.cmd([[setl errorformat=%A%\\%%(%[%^:]%\\+:\ %\\)%\\?%f:%l:%c:\ %m]]) vim.cmd([[setl errorformat+=%A%\\%%(%[%^:]%\\+:\ %\\)%\\?%f:%l:\ %m]]) + + local pwd = vim.lsp.buf.list_workspace_folders()[1] + 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 end if makeprg == "go run" and #args == 0 then vim.cmd([[setl makeprg=go\ run\ \.]]) diff --git a/lua/go/doc.lua b/lua/go/doc.lua new file mode 100644 index 0000000..9b841b9 --- /dev/null +++ b/lua/go/doc.lua @@ -0,0 +1,109 @@ +local M = {} +local utils = require('go.utils') +local log = utils.log +local gopls = require('go.gopls') +local help_items = {} +function M.help_complete(arglead, cmdline, cursorPos) + if #help_items < 1 then + local doc = vim.fn.systemlist('go help') + if vim.v.shell_error ~= 0 then + return + end + + for _, line in ipairs(doc) do + local m = string.match(line, '^%s+([%w%p]+)') + if m ~= nil and m ~= 'go' then + table.insert(help_items, m) + end + end + table.sort(help_items) + end + return table.concat(help_items, '\n') +end + +local function match_partial_item_name(pkg, pattern) + local cmd = string.format('go doc %s', pkg) + local doc = vim.fn.systemlist(cmd) + if vim.v.shell_error ~= 0 then + return + end + + local items = {} + for _, _type in ipairs {'var', 'const', 'func', 'type'} do + local patterns = { + string.format('^%%s*%s (%s%%w+)', _type, pattern), + string.format('^%%s*%s %%(.-%%) (%s%%w+)', _type, pattern) + } + log(patterns) + for _, line in ipairs(doc) do + local m + for _, pat in ipairs(patterns) do + m = string.match(line, pat) + if m then + log(m) + table.insert(items, m) + break + end + end + end + end + table.sort(items) + log(items) + return items +end + +function M.doc_complete(arglead, cmdline, cursorPos) + log(arglead, cmdline) + local words = vim.split(cmdline, '%s+') + if #words > 2 and string.match(words[#words - 1], '^-') == nil then + local pkg = words[#words - 1] + local item = words[#words] + return table.concat(match_partial_item_name(pkg, item), '\n') + elseif #words > 1 and string.match(words[#words], '^[^-].+%..*') ~= nil then + local pkg, item, method = unpack(vim.split(words[#words], '%.')) + if method then + pkg = string.format('%s.%s', pkg, item) + item = method + end + local comps = match_partial_item_name(pkg, item) + for i, comp in ipairs(comps or {}) do + comps[i] = string.format('%s.%s', pkg, comp) + end + return table.concat(comps or {}, '\n') + elseif #words > 1 and string.match(words[#words], '^-') == nil then + local result = gopls.list_known_packages() + if result and result.result and result.result.Packages then + local pkgs = result.result.Packages + return table.concat(pkgs or {}, '\n') + end + end + return '' +end + +-- +M.run = function(type, args) + + -- local offset = string.format("%s:#%i", fname, byte_offset) + + local setup = {'go', type} + + vim.list_extend(setup, args) + local j = vim.fn.jobstart(setup, { + on_stdout = function(jobid, data, event) + data = utils.handle_job_data(data) + if not data then + return + end + -- log(data) + local close_events = {"CursorMoved", "CursorMovedI", "BufHidden", "InsertCharPre"} + local config = {close_events = close_events, focusable = true, border = 'single'} + vim.lsp.util.open_floating_preview(data, 'go', config) + -- local result = vim.fn.json_decode(data) + -- if result.errors ~= nil or result.lines == nil or result["start"] == nil or result["start"] == 0 then + -- print("failed to get doc" .. vim.inspect(result)) + -- end + end + }) +end + +return M diff --git a/lua/go/ts/textobjects.lua b/lua/go/ts/textobjects.lua new file mode 100644 index 0000000..57bc41d --- /dev/null +++ b/lua/go/ts/textobjects.lua @@ -0,0 +1,37 @@ +local util = require 'go.utils' +local plugins = util.load_plugin + +local M = {} + +function M.setup() + if not plugins('treesitter') then + return + end + + local ts = require 'nvim-treesitter.configs' + ts.setup { + textobjects = { + select = { + enable = true, + lookahead = true, + keymaps = { + ['af'] = { go = '@function.outer' }, + ['if'] = { go = '@function.inner' }, + ['ac'] = { go = '@comment.outer' }, + }, + }, + move = { + enable = true, + set_jumps = true, + goto_next_start = { + [']]'] = { go = '@function.outer' }, + }, + goto_previous_start = { + ['[['] = { go = '@function.outer' }, + }, + }, + }, + } +end + +return M diff --git a/lua/go/utils.lua b/lua/go/utils.lua index 34b32fa..5986adf 100644 --- a/lua/go/utils.lua +++ b/lua/go/utils.lua @@ -313,4 +313,9 @@ function util.rtrim(s) return s:sub(1, n) end +function util.file_exists(name) + local f=io.open(name,"r") + if f~=nil then io.close(f) return true else return false end +end + return util