go.nvim/lua/go/guru.lua

124 lines
3.4 KiB
Lua

-- 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
log(data)
local res = data
if format == "json" then
local re = vim.json.decode(data)
if re.errors ~= nil or re.lines == nil or re["start"] == nil or re["start"] == 0 then
vim.notify("failed to run guru" .. vim.inspect(re), vim.log.levels.ERROR)
end
end
if #res > 0 then
vim.fn.setqflist({}, " ", {
title = cmd,
lines = res,
efm = [[%f:%l.%c-%[%^:]%#:\ %m,%f:%l:%c:\ %m]],
})
end
vim.notify("guru " .. mode, vim.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 }