guru support

pull/140/head
ray-x 2 years ago
parent a059a12010
commit 755e5816f0

@ -6,7 +6,7 @@ The plugin covers most features required for a gopher.
- Perproject setup. Allows you setup plugin behavior per project based on project files(launch.json, .gonvim)
- Async jobs with libuv
- Syntax highlight & Texobject: Native treesitter support is faster and more accurate. All you need is a theme support treesitter, try
[aurora](https://github.com/ray-x/aurora). Also, there are quite a few listed in [awesome-neovim](https://github.com/rockerBOO/awesome-neovim)
[aurora](https://github.com/ray-x/aurora), [starry.nvim](https://github.com/ray-x/starry.nvim). Also, there are quite a few listed in [awesome-neovim](https://github.com/rockerBOO/awesome-neovim)
- All the GoToXxx (E.g reference, implementation, definition, goto doc, peek code/doc etc) You need lspconfig setup. There are lots of posts on how to
set it up. You can also check my [navigator](https://github.com/ray-x/navigator.lua) gopls setup [lspconfig.lua](https://github.com/ray-x/navigator.lua/blob/master/lua/navigator/lspclient/clients.lua)
- Runtime lint/vet/compile: Supported by lsp (once you setup up your lsp client), GoLint with golangci-lint also supported
@ -24,7 +24,7 @@ The plugin covers most features required for a gopher.
- Go to alternative go file (between test and source)
- Test with ginkgo, richgo inside floaterm (to enable floaterm, guihua.lua has to be installed)
- Go 1.18 support, configure your go to `go1.18` in config
- Code refactor made easy: GoFixPlural, FixStruct, FixSwitch, Add comment, IfErr, ModTidy, GoGet ... Most of the tools are built on top of
- Code refactor made easy: GoFixPlural, FixStruct, FixSwitch, Add comment, IfErr, ModTidy, GoGet, extract function/block with codeactions... Most of the tools are built on top of
treesitter AST or go AST. It is fast and accurate.
- GoCheat get go cheatsheet from [cheat.sh](https://cheat.sh/).
- Smart build tag detection when debug/run tests (e.g. `//go:build integration`)

@ -201,6 +201,8 @@ function go.setup(cfg)
vim.cmd([[command! -bang GoModTidy lua require"go.gopls".tidy()]])
vim.cmd([[command! -bang GoListImports lua print(vim.inspect(require"go.gopls".list_imports()))]])
vim.cmd([[command! -bang GoCallstack lua require"go.guru".callstack(-1)]])
vim.cmd([[command! -bang GoChanel lua require"go.guru".channel_peers(-1)]])
if _GO_NVIM_CFG.dap_debug then
dap_config()
vim.cmd(

@ -52,6 +52,7 @@ end
-- return "-tags=tag1,tag2"
M.get_build_tags = function(args)
-- local tags = "-tags"
args = args or {}
local tags = {}
if _GO_NVIM_CFG.build_tags ~= "" then
tags = { _GO_NVIM_CFG.build_tags }

@ -0,0 +1,114 @@
-- local ts_utils = require 'nvim-treesitter.ts_utils'
local utils = require("go.utils")
local log = utils.log
local pkg = require("go.package")
local fn = vim.fn
local guru = "guru"
local vfn = vim.fn
-- guru_cmd returns a dict that contains the command to execute guru. args
-- is dict with following options:
-- mode : guru mode, such as 'implements'
-- format : output format, either 'plain' or 'json'
-- needs_scope : if 1, adds the current package to the scope
-- selected : if 1, means it's a range of selection, otherwise it picks up the
-- offset under the cursor
-- example output:
-- {'cmd' : ['guru', '-json', 'implements', 'demo/demo.go:#66']}
local guru_cmd = function(args)
local mode = args.mode
local format = args.format
local selected = args.selected
local postype = vim.fn.get(args, "postype", "cursor")
local need_scope = args.needs_scope
local result = {}
local build_tags = require("go.gotest").get_build_tags()
require("go.install").install(guru)
local cmd = { guru }
if build_tags then
table.insert(cmd, build_tags)
end
if vim.o.modified then
table.insert(cmd, "-modified")
end
if format == "json" then
table.insert(cmd, "-json")
end
local fname = vfn.expand("%:p") -- %:p:h ? %:p
-- local fpath = vfn.expand("%:p:h") -- %:p:h ? %:p
if need_scope then
local scope = pkg.pkg_from_path()
log(scope)
if scope then
table.insert(cmd, "-scope")
table.insert(cmd, fn.join(scope, ","))
end
end
local pos
if postype == "balloon" then
local byte_offset = utils.offset(vim.v.beval_lnum, vim.v.beval_col)
pos = string.format("#%s", byte_offset)
else
if selected ~= -1 then -- visual mode
local pos1 = utils.offset(fn.line("'<"), fn.col("'<"))
local pos2 = utils.offset(fn.line("'>"), fn.col("'>"))
pos = string.format("#%s,#%s", pos1, pos2)
else
pos = string.format("#%s", vfn.wordcount().cursor_bytes)
end
end
local filename = fn.fnamemodify(fn.expand("%"), ":p:gs?\\?/?") .. ":" .. pos
table.insert(cmd, mode)
table.insert(cmd, filename)
log(cmd)
print(vim.inspect(cmd))
vfn.jobstart(cmd, {
on_exit = function(status, data, stderr)
log(status, data)
end,
on_stderr = function(e, data)
log(e, data)
end,
on_stdout = function(_, data, _)
data = utils.handle_job_data(data)
if not data then
return
end
print(data)
log(data)
-- local result = vfn.json_decode(data)
local result = vim.json.decode(data)
if result.errors ~= nil or result.lines == nil or result["start"] == nil or result["start"] == 0 then
vim.notify("failed to run guru" .. vim.inspect(result), vim.lsp.log_levels.ERROR)
end
vim.notify("guru " .. mode, vim.lsp.log_levels.INFO)
end,
})
end
local function callstack(selected)
selected = selected or -1
guru_cmd({
mode = "callstack",
format = "plain",
needs_scope = 1,
selected = selected,
})
end
local function channel_peers(selected)
selected = selected or -1
guru_cmd({
mode = "peers",
format = "plain",
needs_scope = 1,
selected = selected,
})
end
return { guru_cmd = guru_cmd, callstack = callstack, channel_peers = channel_peers }

@ -12,6 +12,8 @@ local url = {
gopls = "golang.org/x/tools/gopls",
gotests = "github.com/cweill/gotests/...",
iferr = "github.com/koron/iferr",
callgraph = "golang.org/x/tools/cmd/callgraph",
guru = "golang.org/x/tools/cmd/guru",
impl = "github.com/josharian/impl",
fillstruct = "github.com/davidrjenni/reftools/cmd/fillstruct",
fillswitch = "github.com/davidrjenni/reftools/cmd/fillswitch",
@ -24,6 +26,7 @@ local tools = {}
for tool, _ in pairs(url) do
table.insert(tools, tool)
end
local function is_installed(bin)
local env_path = os.getenv("PATH")
local base_paths = vim.split(env_path, ":", true)

@ -1,40 +1,49 @@
local golist = require'go.list'.list
local util = require 'go.utils'
local golist = require("go.list").list
local util = require("go.utils")
local log = util.log
local vfn = vim.fn
return {
complete = function()
local ok, l = golist(false, {util.all_pkgs()})
if not ok then
log('Failed to find all packages for current module/project.')
end
local curpkgmatch = false
local curpkg = vfn.fnamemodify(vfn.expand('%'), ':h:.')
local pkgs = {}
for _, p in ipairs(l) do
local d = vfn.fnamemodify(p.Dir, ':.')
if curpkg ~= d then
if d ~= vfn.getcwd() then
table.insert(pkgs, util.relative_to_cwd(d))
end
else
curpkgmatch = true
local complete = function()
local ok, l = golist(false, { util.all_pkgs() })
if not ok then
log("Failed to find all packages for current module/project.")
end
local curpkgmatch = false
local curpkg = vfn.fnamemodify(vfn.expand("%"), ":h:.")
local pkgs = {}
for _, p in ipairs(l) do
local d = vfn.fnamemodify(p.Dir, ":.")
if curpkg ~= d then
if d ~= vfn.getcwd() then
table.insert(pkgs, util.relative_to_cwd(d))
end
else
curpkgmatch = true
end
table.sort(pkgs)
table.insert(pkgs, util.all_pkgs())
table.insert(pkgs, '.')
if curpkgmatch then
table.insert(pkgs, util.relative_to_cwd(curpkg))
end
return table.concat(pkgs, '\n')
end,
all_pkgs = function()
local ok, l = golist(false, {util.all_pkgs()})
if not ok then
log('Failed to find all packages for current module/project.')
end
return l
end
table.sort(pkgs)
table.insert(pkgs, util.all_pkgs())
table.insert(pkgs, ".")
if curpkgmatch then
table.insert(pkgs, util.relative_to_cwd(curpkg))
end
return table.concat(pkgs, "\n")
end
local all_pkgs = function()
local ok, l = golist(false, { util.all_pkgs() })
if not ok then
log("Failed to find all packages for current module/project.")
end
return l
end
local pkg_from_path = function(arg)
log(arg, path)
return util.exec_in_path({'go', 'list'})
end
return {
complete = complete,
all_pkgs = all_pkgs,
pkg_from_path = pkg_from_path,
}

@ -404,6 +404,20 @@ function util.relative_to_cwd(name)
end
end
function util.chdir(dir)
if fn.exists("*chdir") then
return fn.chdir(dir)
end
local oldir = fn.getcwd()
local cd = "cd"
if fn.exists("*haslocaldir") and fn.haslocaldir() then
cd = "lcd"
vim.cmd(cd .. " " .. fn.fnameescape(dir))
return oldir
end
end
function util.all_pkgs()
return "." .. util.sep() .. "..."
end
@ -580,6 +594,42 @@ function util.set_nulls()
end
end
-- run in current source code path
function util.exec_in_path(cmd, ...)
local arg = vim.fn.expand("%:p:h")
local path = fn.fnamemodify(arg, ":p")
if fn.isdirectory(path) then
path = fn.fnamemodify(path, ":h")
end
local dir = util.chdir(path)
local result
if type(cmd) == "function" then
result = cmd(...)
else
result = fn.systemlist(cmd, ...)
end
util.log(result)
util.chdir(dir)
return result
end
function util.line_ending()
if vim.o.fileformat == "dos" then
return "\r\n"
elseif vim.o.fileformat == "mac" then
return "\r"
end
return "\n"
end
function util.offset(line, col)
util.log(line, col)
if vim.o.encoding ~= "utf-8" then
print("only utf-8 encoding is supported current encoding: ", vim.o.encoding)
end
return fn.line2byte(line) + col - 2
end
-- parse //+build integration unit
function util.get_build_tags(buf)
local tags = {}

Loading…
Cancel
Save