222 lines
5.9 KiB
Lua
222 lines
5.9 KiB
Lua
-- local ts_utils = require 'nvim-treesitter.ts_utils'
|
|
local utils = require('go.utils')
|
|
local log = utils.log
|
|
local vfn = vim.fn
|
|
local impl = 'impl' -- GoImpl f *Foo io.Writer
|
|
-- use ts to get name
|
|
local function get_type_name()
|
|
local name = require('go.ts.go').get_struct_node_at_pos()
|
|
if name == nil then
|
|
name = require('go.ts.go').get_type_node_at_pos()
|
|
end
|
|
utils.log(name)
|
|
if name == nil then
|
|
return ''
|
|
end
|
|
local node_name = name.name
|
|
-- let move the cursor to end of line of struct name
|
|
local dim = name.dim.e
|
|
-- let move cursor
|
|
local r, c = dim.r, dim.c
|
|
utils.log('move cusror to ', r, c)
|
|
vim.api.nvim_win_set_cursor(0, { r, c })
|
|
return node_name, name.type
|
|
end
|
|
|
|
local function get_interface_name()
|
|
local name = require('go.ts.go').get_interface_node_at_pos()
|
|
|
|
utils.log(name)
|
|
if name == nil then
|
|
return nil
|
|
end
|
|
local node_name = name.name
|
|
-- let move the cursor to end of line of struct name
|
|
local dim = name.dim.e
|
|
-- let move cursor
|
|
local r, c = dim.r, dim.c
|
|
utils.log('move cusror to ', r, c)
|
|
vim.api.nvim_win_set_cursor(0, { r, c })
|
|
|
|
local pkg = require('go.package').pkg_from_path(nil, vim.api.nvim_get_current_buf())
|
|
log(pkg[1])
|
|
if pkg then
|
|
return pkg[1] .. '.' .. node_name
|
|
end
|
|
end
|
|
|
|
local run = function(...)
|
|
require('go.install').install(impl)
|
|
local impl_cmd = 'impl'
|
|
local iface = ''
|
|
local recv_name = ''
|
|
local arg = { ... }
|
|
utils.log(#arg, arg)
|
|
|
|
local recv = get_type_name()
|
|
iface = get_interface_name()
|
|
|
|
if #arg == 0 then
|
|
if not iface then
|
|
iface = vfn.input('Impl: generating method stubs for interface: ')
|
|
end
|
|
vim.cmd('redraw!')
|
|
if iface == '' then
|
|
utils.notify(
|
|
'Impl: please input interface name e.g. io.Reader or receiver name e.g. GoImpl MyType'
|
|
)
|
|
-- print("Usage: GoImpl f *File io.Reader")
|
|
end
|
|
elseif #arg == 1 then -- at least interface or type are specified
|
|
-- " i.e: ':GoImpl io.Writer'
|
|
if iface ~= nil then
|
|
recv = select(1, ...)
|
|
recv = string.lower(recv) .. ' *' .. recv
|
|
else
|
|
recv = string.lower(recv) .. ' *' .. recv
|
|
iface = select(1, ...)
|
|
end
|
|
if recv == '' and iface == '' then
|
|
vim.notify('put cursor on struct or a interface or specify a receiver & interface')
|
|
end
|
|
utils.log(recv)
|
|
vim.cmd('redraw!')
|
|
elseif #arg == 2 then
|
|
-- utils.log(recv, iface)
|
|
if iface ~= nil then
|
|
-- " i.e: ':GoImpl s TypeName'
|
|
recv = select(1, ...)
|
|
local recv_type = select(2, ...)
|
|
recv = string.lower(recv) .. ' *' .. recv_type
|
|
else
|
|
recv_name = select(1, ...)
|
|
recv = string.format('%s *%s', string.lower(recv_name), recv_name)
|
|
local l = #arg
|
|
iface = select(l, ...)
|
|
end
|
|
elseif #arg > 2 then
|
|
local l = #arg
|
|
iface = select(l, ...)
|
|
recv = select(l - 1, ...)
|
|
recv_name = select(l - 2, ...)
|
|
recv = string.format('%s %s', recv_name, recv)
|
|
end
|
|
|
|
utils.log(#arg, recv_name, recv, iface)
|
|
local dir = vfn.fnameescape(vfn.expand('%:p:h'))
|
|
|
|
impl_cmd = { impl_cmd, '-dir', dir, recv, iface }
|
|
utils.log(impl_cmd)
|
|
-- vim.cmd("normal! $%") -- do a bracket match. changed to treesitter
|
|
local opts = {
|
|
update_buffer = true,
|
|
on_exit = function(code, signal, data)
|
|
if code ~= 0 or signal ~= 0 then
|
|
utils.warn('impl failed' .. vim.inspect(data))
|
|
return
|
|
end
|
|
data = vim.split(data, '\n')
|
|
data = utils.handle_job_data(data)
|
|
if not data then
|
|
return
|
|
end
|
|
vim.schedule(function()
|
|
local lnum = vfn.getcurpos()[2]
|
|
table.insert(data, 1, '')
|
|
vfn.append(lnum, data)
|
|
vim.cmd('w')
|
|
end)
|
|
end,
|
|
}
|
|
local runner = require('go.runner')
|
|
opts.sprite_enable = false
|
|
runner.run(impl_cmd, opts)
|
|
end
|
|
|
|
local function match_iface_name(part)
|
|
local pkg, iface = string.match(part, '^(.*)%.(.*)$')
|
|
|
|
utils.log(pkg, iface)
|
|
local cmd = string.format('go doc %s', pkg)
|
|
local doc = vfn.systemlist(cmd)
|
|
if vim.v.shell_error ~= 0 then
|
|
utils.warn('go doc failed' .. vim.inspect(doc))
|
|
return
|
|
end
|
|
|
|
local ifaces = {}
|
|
local pat = string.format('^type (%s.*) interface', iface)
|
|
for _, line in ipairs(doc) do
|
|
local m = string.match(line, pat)
|
|
if m ~= nil then
|
|
table.insert(ifaces, string.format('%s.%s', pkg, m))
|
|
end
|
|
end
|
|
return ifaces
|
|
end
|
|
|
|
-- function complete(arglead, cmdline, cursorpos)
|
|
local function complete(_, cmdline, _)
|
|
local words = vim.split(cmdline, [[%s+]])
|
|
local gopls = require('go.gopls')
|
|
local last = words[#words]
|
|
log(words)
|
|
-- by default complete with local type
|
|
|
|
local iface = get_interface_name()
|
|
local query = require('go.ts.go').query_type_declaration
|
|
local bufnr = vim.api.nvim_get_current_buf()
|
|
local all_nodes = function(except)
|
|
local nodes = require('go.ts.nodes').nodes_in_buf(query, 'go', nil, bufnr, 100000, 100000)
|
|
local ns = {}
|
|
log(nodes)
|
|
for _, node in ipairs(nodes) do
|
|
table.insert(ns, node.name)
|
|
end
|
|
if except then
|
|
log('remove', except)
|
|
for i, n in ipairs(ns) do
|
|
if n == except then
|
|
table.remove(ns, i)
|
|
break
|
|
end
|
|
end
|
|
if #words > 1 and #last > 1 then
|
|
local pkgs = vfn.uniq(vfn.sort(gopls.list_pkgs()))
|
|
-- attach ns in front of pkgs
|
|
for _, n in ipairs(ns) do
|
|
table.insert(pkgs, 1, n)
|
|
end
|
|
return pkgs
|
|
else
|
|
return ns
|
|
end
|
|
else
|
|
return vfn.uniq(ns)
|
|
end
|
|
end
|
|
if iface ~= nil then
|
|
local iname = vim.split(iface, '%.')
|
|
iname = iname[#iname]
|
|
log('iface', iface)
|
|
return all_nodes(iname)
|
|
end
|
|
|
|
local struct = get_type_name()
|
|
if struct ~= nil then
|
|
log('structs', struct)
|
|
return all_nodes(struct)
|
|
end
|
|
|
|
if string.match(last, '^.+%..*') ~= nil then
|
|
local part = match_iface_name(last)
|
|
if part ~= nil then
|
|
return part
|
|
end
|
|
end
|
|
|
|
return vfn.uniq(vfn.sort(gopls.list_pkgs()))
|
|
end
|
|
|
|
return { run = run, complete = complete }
|