go.nvim/lua/go/utils.lua

473 lines
11 KiB
Lua
Raw Normal View History

2021-03-10 12:15:06 +00:00
local util = {}
2021-08-16 23:59:01 +00:00
2021-11-10 02:20:54 +00:00
local os_name = vim.loop.os_uname().sysname
2021-12-16 07:15:21 +00:00
local is_windows = os_name == "Windows" or os_name == "Windows_NT"
2021-08-16 23:59:01 +00:00
-- Check whether current buffer contains main function
local function has_main()
local output = vim.api.nvim_exec("grep func\\ main\\(\\) %", true)
local matchCount = vim.split(output, "\n")
return #matchCount > 3
end
2021-11-10 02:20:54 +00:00
function util.sep()
if is_windows then
2021-12-16 07:15:21 +00:00
return "\\"
2021-11-10 02:20:54 +00:00
end
2021-12-16 07:15:21 +00:00
return "/"
2021-11-10 02:20:54 +00:00
end
2021-12-22 04:01:15 +00:00
local function get_path_sep()
if is_windows then
return ";"
end
return ":"
end
local function strip_path_sep(path)
local l = path[#path]
util.log(l, util.sep(), path:sub(1, #path - 1))
if l == util.sep() then
return path:sub(1, #path - 1)
end
return path
end
function util.root_dirs()
local dirs = {}
2022-01-10 10:26:41 +00:00
local root = vim.fn.systemlist({ _GO_NVIM_CFG.go, "env", "GOROOT" })
2021-12-22 04:01:15 +00:00
table.insert(dirs, root[1])
2022-01-10 10:26:41 +00:00
local paths = vim.fn.systemlist({ _GO_NVIM_CFG.go, "env", "GOPATH" })
2021-12-22 04:01:15 +00:00
local sp = get_path_sep()
paths = vim.split(paths[1], sp)
for _, p in pairs(paths) do
p = vim.fn.substitute(p, "\\\\", "/", "g")
table.insert(dirs, p)
end
return dirs
end
function util.go_packages(dirs, arglead)
util.log(debug.traceback())
local pkgs = {}
for _, dir in pairs(dirs) do
util.log(dir)
local scr_root = vim.fn.expand(dir .. util.sep() .. "src" .. util.sep())
util.log(scr_root, arglead)
local roots = vim.fn.globpath(scr_root, arglead .. "*", 0, 1)
if roots == { "" } then
roots = {}
end
util.log(roots)
for _, pkg in pairs(roots) do
util.log(pkg)
if vim.fn.isdirectory(pkg) then
pkg = pkg .. util.sep()
table.insert(pkgs, pkg)
elseif not pkg:match([[%.a$]]) then
-- without this the result can have duplicates in form of
-- 'encoding/json' and '/encoding/json/'
pkg = strip_path_sep(pkg)
-- remove the scr root and keep the package in tact
pkg = vim.fn.substitute(pkg, scr_root, "", "")
table.insert(pkgs, pkg)
end
end
end
util.log(pkgs)
return pkgs
end
-- function! s:interface_list(pkg) abort
-- let [contents, err] = go#util#Exec(['go', 'doc', a:pkg])
-- if err
-- return []
-- endif
--
-- let contents = split(contents, "\n")
-- call filter(contents, 'v:val =~# ''^type\s\+\h\w*\s\+interface''')
-- return map(contents, 'a:pkg . "." . matchstr(v:val, ''^type\s\+\zs\h\w*\ze\s\+interface'')')
-- endfunction
function util.interface_list(pkg)
2022-01-10 10:26:41 +00:00
local p = vim.fn.systemlist({ _GO_NVIM_CFG.go, "doc", pkg })
2021-12-22 04:01:15 +00:00
util.log(p)
local ifaces = {}
if p then
contents = p -- vim.split(p[1], "\n")
for _, content in pairs(contents) do
util.log(content)
if content:find("interface") then
local iface_name = vim.fn.matchstr(content, [[^type\s\+\zs\h\w*\ze\s\+interface]])
if iface_name ~= "" then
table.insert(ifaces, pkg .. iface_name)
end
end
end
end
util.log(ifaces)
return ifaces
end
2021-08-16 23:59:01 +00:00
local function smartrun()
2022-01-10 10:26:41 +00:00
local cmd
2021-08-16 23:59:01 +00:00
if has_main() then
-- Found main function in current buffer
2022-01-10 10:26:41 +00:00
cmd = string.format("lcd %:p:h | :set makeprg=%s\\ run\\ . | :make | :lcd -", _GO_NVIM_CFG.go)
vim.cmd(cmd)
2021-08-16 23:59:01 +00:00
else
2022-01-10 10:26:41 +00:00
cmd = string.format("setl makeprg=%s\\ run\\ . | :make", _GO_NVIM_CFG.go)
vim.cmd(cmd)
2021-08-16 23:59:01 +00:00
end
end
local function smartbuild()
2022-01-10 10:26:41 +00:00
local cmd
if has_main() then
2021-08-16 23:59:01 +00:00
-- Found main function in current buffer
2022-01-10 10:26:41 +00:00
cmd = string.format("lcd %:p:h | :set makeprg=%s\\ build\\ . | :make | :lcd -", _GO_NVIM_CFG.go)
vim.cmd(cmd)
2021-08-16 23:59:01 +00:00
else
2022-01-10 10:26:41 +00:00
cmd = string.format("setl makeprg=%s\\ build\\ . | :make", _GO_NVIM_CFG.go)
vim.cmd(cmd)
2021-08-16 23:59:01 +00:00
end
end
2021-03-10 12:15:06 +00:00
util.check_same = function(tbl1, tbl2)
if #tbl1 ~= #tbl2 then
return false
2021-03-10 12:15:06 +00:00
end
for k, v in ipairs(tbl1) do
if v ~= tbl2[k] then
return false
2021-03-10 12:15:06 +00:00
end
end
return true
2021-03-10 12:15:06 +00:00
end
2021-11-13 03:29:42 +00:00
util.map = function(modes, key, result, options)
2021-12-16 07:15:21 +00:00
options = util.merge({ noremap = true, silent = false, expr = false, nowait = false }, options or {})
2021-11-13 03:29:42 +00:00
local buffer = options.buffer
options.buffer = nil
if type(modes) ~= "table" then
2021-12-16 07:15:21 +00:00
modes = { modes }
2021-11-13 03:29:42 +00:00
end
for i = 1, #modes do
if buffer then
vim.api.nvim_buf_set_keymap(0, modes[i], key, result, options)
else
vim.api.nvim_set_keymap(modes[i], key, result, options)
end
end
end
2021-03-10 12:15:06 +00:00
util.copy_array = function(from, to)
for i = 1, #from do
2021-07-08 16:16:22 +00:00
to[i] = from[i]
2021-03-10 12:15:06 +00:00
end
end
2021-07-08 16:16:22 +00:00
util.deepcopy = function(orig)
2021-07-07 05:10:06 +00:00
local orig_type = type(orig)
local copy
2021-12-16 07:15:21 +00:00
if orig_type == "table" then
2021-07-08 16:16:22 +00:00
copy = {}
for orig_key, orig_value in next, orig, nil do
copy[util.deepcopy(orig_key)] = util.deepcopy(orig_value)
end
setmetatable(copy, util.deepcopy(getmetatable(orig)))
2021-07-07 05:10:06 +00:00
else -- number, string, boolean, etc
2021-07-08 16:16:22 +00:00
copy = orig
2021-07-07 05:10:06 +00:00
end
return copy
end
util.handle_job_data = function(data)
if not data then
return nil
2021-03-10 12:15:06 +00:00
end
2021-07-07 05:10:06 +00:00
-- Because the nvim.stdout's data will have an extra empty line at end on some OS (e.g. maxOS), we should remove it.
2021-12-27 08:47:59 +00:00
for i = 1, 3, 1 do
if data[#data] == "" then
table.remove(data, #data)
end
2021-07-07 05:10:06 +00:00
end
if #data < 1 then
return nil
end
return data
end
2021-03-10 12:15:06 +00:00
util.log = function(...)
2021-08-24 04:53:37 +00:00
if not _GO_NVIM_CFG.verbose then
return
end
2021-12-16 07:15:21 +00:00
local arg = { ... }
local cache_dir = vim.fn.stdpath("cache")
local log_default = string.format("%s%sgonvim.log", cache_dir, util.sep())
local log_path = _GO_NVIM_CFG.log_path or log_default
2021-08-24 04:53:37 +00:00
local str = ""
local info = debug.getinfo(2, "Sl")
str = str .. info.short_src .. ":" .. info.currentline
2021-08-24 04:53:37 +00:00
for i, v in ipairs(arg) do
if type(v) == "table" then
str = str .. " |" .. tostring(i) .. ": " .. vim.inspect(v) .. "\n"
else
str = str .. " |" .. tostring(i) .. ": " .. tostring(v)
2021-07-08 16:16:22 +00:00
end
2021-08-24 04:53:37 +00:00
end
if #str > 2 then
if log_path ~= nil and #log_path > 3 then
local f, err = io.open(log_path, "a+")
if err then
vim.notify("failed to open log" .. log_path .. err, vim.lsp.log_levels.ERROR)
2021-08-24 04:53:37 +00:00
return
end
if not f then
2021-12-16 07:15:21 +00:00
error("open file " .. log_path, f)
2021-07-08 16:16:22 +00:00
end
2021-08-24 04:53:37 +00:00
io.output(f)
io.write(str .. "\n")
io.close(f)
else
vim.notify(str .. "\n", vim.lsp.log_levels.DEBUG)
2021-07-08 16:16:22 +00:00
end
2021-03-10 12:15:06 +00:00
end
end
2021-07-10 11:04:24 +00:00
local rhs_options = {}
function rhs_options:new()
local instance = {
2021-12-16 07:15:21 +00:00
cmd = "",
options = { noremap = false, silent = false, expr = false, nowait = false },
2021-07-10 11:04:24 +00:00
}
setmetatable(instance, self)
self.__index = self
return instance
end
function rhs_options:map_cmd(cmd_string)
self.cmd = cmd_string
return self
end
function rhs_options:map_cr(cmd_string)
self.cmd = (":%s<CR>"):format(cmd_string)
return self
end
function rhs_options:map_args(cmd_string)
self.cmd = (":%s<Space>"):format(cmd_string)
return self
end
function rhs_options:map_cu(cmd_string)
self.cmd = (":<C-u>%s<CR>"):format(cmd_string)
return self
end
function rhs_options:with_silent()
self.options.silent = true
return self
end
function rhs_options:with_noremap()
self.options.noremap = true
return self
end
function rhs_options:with_expr()
self.options.expr = true
return self
end
function rhs_options:with_nowait()
self.options.nowait = true
return self
end
function util.map_cr(cmd_string)
local ro = rhs_options:new()
return ro:map_cr(cmd_string)
end
function util.map_cmd(cmd_string)
local ro = rhs_options:new()
return ro:map_cmd(cmd_string)
end
function util.map_cu(cmd_string)
local ro = rhs_options:new()
return ro:map_cu(cmd_string)
end
function util.map_args(cmd_string)
local ro = rhs_options:new()
return ro:map_args(cmd_string)
end
function util.nvim_load_mapping(mapping)
for key, value in pairs(mapping) do
local mode, keymap = key:match("([^|]*)|?(.*)")
2021-12-16 07:15:21 +00:00
if type(value) == "table" then
2021-07-10 11:04:24 +00:00
local rhs = value.cmd
local options = value.options
vim.api.nvim_set_keymap(mode, keymap, rhs, options)
end
end
end
function util.load_plugin(name, modulename)
assert(name ~= nil, "plugin should not empty")
modulename = modulename or name
local has, plugin = pcall(require, modulename)
if has then
return plugin
end
if packer_plugins ~= nil then
-- packer installed
2021-12-16 07:15:21 +00:00
local loader = require("packer").loader
2021-07-10 11:04:24 +00:00
if not packer_plugins[name] or not packer_plugins[name].loaded then
2022-01-15 11:14:56 +00:00
util.log("packer loader " .. name)
vim.cmd("packadd " .. name) -- load with default
2021-07-10 11:04:24 +00:00
loader(name)
end
else
2022-01-15 11:14:56 +00:00
util.log("packadd " .. name)
2021-07-10 11:04:24 +00:00
vim.cmd("packadd " .. name) -- load with default
end
has, plugin = pcall(require, modulename)
if not has then
2021-11-23 23:13:40 +00:00
util.warn("plugin failed to load " .. name)
2022-01-15 11:14:56 +00:00
return nil
end
2021-07-10 11:04:24 +00:00
return plugin
end
function util.check_capabilities(feature, client_id)
local clients = vim.lsp.buf_get_clients(client_id or 0)
local supported_client = false
for _, client in pairs(clients) do
util.log(client.resolved_capabilities)
supported_client = client.resolved_capabilities[feature]
if supported_client then
2021-12-27 08:47:59 +00:00
break
end
end
if supported_client then
return true
else
if #clients == 0 then
2021-08-23 06:36:30 +00:00
util.log("LSP: no client attached")
else
2021-08-23 03:55:27 +00:00
util.log("LSP: server does not support " .. feature)
end
return false
end
end
2021-11-13 03:29:42 +00:00
function util.relative_to_cwd(name)
2021-12-16 07:15:21 +00:00
local rel = vim.fn.isdirectory(name) == 0 and vim.fn.fnamemodify(name, ":h:.") or vim.fn.fnamemodify(name, ":.")
if rel == "." then
return "."
2021-11-13 03:29:42 +00:00
else
2021-12-16 07:15:21 +00:00
return "." .. util.sep() .. rel
2021-11-13 03:29:42 +00:00
end
end
function util.all_pkgs()
2021-12-16 07:15:21 +00:00
return "." .. util.sep() .. "..."
2021-11-13 03:29:42 +00:00
end
2021-11-16 22:22:16 +00:00
-- log and messages
function util.warn(msg)
2021-12-16 07:15:21 +00:00
vim.api.nvim_echo({ { "WRN: " .. msg, "WarningMsg" } }, true, {})
2021-11-16 22:22:16 +00:00
end
function util.error(msg)
2021-12-16 07:15:21 +00:00
vim.api.nvim_echo({ { "ERR: " .. msg, "ErrorMsg" } }, true, {})
2021-11-16 22:22:16 +00:00
end
function util.info(msg)
2021-12-16 07:15:21 +00:00
vim.api.nvim_echo({ { "Info: " .. msg } }, true, {})
2021-11-16 22:22:16 +00:00
end
2021-11-23 23:13:40 +00:00
function util.rel_path()
2021-12-16 07:15:21 +00:00
local fpath = vim.fn.expand("%:p:h")
local workfolders = vim.lsp.buf.list_workspace_folders()
2021-11-23 23:13:40 +00:00
if workfolder ~= nil then
fpath = "." .. fpath:sub(#workfolder + 1)
end
return fpath
end
2021-12-02 06:44:22 +00:00
function util.rtrim(s)
local n = #s
while n > 0 and s:find("^%s", n) do
n = n - 1
end
return s:sub(1, n)
end
function util.file_exists(name)
2021-12-16 07:15:21 +00:00
local f = io.open(name, "r")
if f ~= nil then
io.close(f)
return true
else
return false
end
end
function util.work_path()
local fpath = vim.fn.expand("%:p:h")
local workfolders = vim.lsp.buf.list_workspace_folders()
if #workfolders == 1 then
return workfolders[1]
end
for _, value in pairs(workfolders) do
local mod = value .. util.sep() .. "go.mod"
2021-12-17 03:48:41 +00:00
if util.file_exists(mod) then
2021-12-16 07:15:21 +00:00
return value
end
end
return workfolders[1] or fpath
end
function util.empty(t)
if t == nil then
return true
end
return next(t) == nil
end
local open = io.open
function util.read_file(path)
local file = open(path, "rb") -- r read mode and b binary mode
if not file then
return nil
end
local content = file:read("*a") -- *a or *all reads the whole file
file:close()
return content
end
2021-03-10 12:15:06 +00:00
return util