go.nvim/lua/go/utils.lua

930 lines
22 KiB
Lua
Raw Normal View History

2021-03-10 12:15:06 +00:00
local util = {}
local fn = vim.fn
2021-08-16 23:59:01 +00:00
2021-11-10 02:20:54 +00:00
local os_name = vim.loop.os_uname().sysname
2022-07-30 13:05:27 +00:00
local is_windows = os_name == 'Windows' or os_name == 'Windows_NT'
2023-04-04 11:55:20 +00:00
local HASNVIM0_9 = vim.fn.has('nvim-0.9') == 1
util.get_node_text = vim.treesitter.get_node_text
if not HASNVIM0_9 or util.get_node_text == nil then
util.get_node_text = vim.treesitter.query.get_node_text
end
local nvim_exec = vim.api.nvim_exec2
if nvim_exec == nil then
nvim_exec = vim.api.nvim_exec
end
2021-08-16 23:59:01 +00:00
-- Check whether current buffer contains main function
2022-06-01 11:29:13 +00:00
function util.has_main()
2023-04-04 11:55:20 +00:00
local output = nvim_exec('grep func\\ main\\(\\) %', true)
2022-07-30 13:05:27 +00:00
local matchCount = vim.split(output, '\n')
2021-08-16 23:59:01 +00:00
return #matchCount > 3
end
2021-11-10 02:20:54 +00:00
function util.sep()
if is_windows then
2022-07-30 13:05:27 +00:00
return '\\'
2021-11-10 02:20:54 +00:00
end
2022-07-30 13:05:27 +00:00
return '/'
2021-11-10 02:20:54 +00:00
end
2022-07-27 04:50:39 +00:00
function util.sep2()
if is_windows then
2022-07-30 13:05:27 +00:00
return ';'
2022-07-27 04:50:39 +00:00
end
2022-07-30 13:05:27 +00:00
return ':'
2022-07-27 04:50:39 +00:00
end
function util.is_windows()
return is_windows
end
2022-07-27 16:19:42 +00:00
function util.ext()
if is_windows then
2022-07-30 13:05:27 +00:00
return '.exe'
2022-07-27 16:19:42 +00:00
end
2022-07-30 13:05:27 +00:00
return ''
2022-07-27 16:19:42 +00:00
end
2021-12-22 04:01:15 +00:00
local function get_path_sep()
if is_windows then
2022-07-30 13:05:27 +00:00
return ';'
2021-12-22 04:01:15 +00:00
end
2022-07-30 13:05:27 +00:00
return ':'
2021-12-22 04:01:15 +00:00
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-07-30 13:05:27 +00:00
local root = fn.systemlist({ _GO_NVIM_CFG.go, 'env', 'GOROOT' })
2021-12-22 04:01:15 +00:00
table.insert(dirs, root[1])
2022-07-30 13:05:27 +00:00
local paths = 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
2022-07-30 13:05:27 +00:00
p = fn.substitute(p, '\\\\', '/', 'g')
2021-12-22 04:01:15 +00:00
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)
2022-07-30 13:05:27 +00:00
local scr_root = fn.expand(dir .. util.sep() .. 'src' .. util.sep())
2021-12-22 04:01:15 +00:00
util.log(scr_root, arglead)
2022-07-30 13:05:27 +00:00
local roots = fn.globpath(scr_root, arglead .. '*', 0, 1)
if roots == { '' } then
2021-12-22 04:01:15 +00:00
roots = {}
end
util.log(roots)
for _, pkg in pairs(roots) do
util.log(pkg)
if fn.isdirectory(pkg) then
2021-12-22 04:01:15 +00:00
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
2022-07-30 13:05:27 +00:00
pkg = fn.substitute(pkg, scr_root, '', '')
2021-12-22 04:01:15 +00:00
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-07-30 13:05:27 +00:00
local p = fn.systemlist({ _GO_NVIM_CFG.go, 'doc', pkg })
2021-12-22 04:01:15 +00:00
util.log(p)
local ifaces = {}
if p then
2022-06-01 11:29:13 +00:00
local contents = p -- vim.split(p[1], "\n")
2021-12-22 04:01:15 +00:00
for _, content in pairs(contents) do
util.log(content)
2022-07-30 13:05:27 +00:00
if content:find('interface') then
local iface_name = fn.matchstr(content, [[^type\s\+\zs\h\w*\ze\s\+interface]])
2022-07-30 13:05:27 +00:00
if iface_name ~= '' then
2021-12-22 04:01:15 +00:00
table.insert(ifaces, pkg .. iface_name)
end
end
end
end
util.log(ifaces)
return ifaces
end
2022-10-01 04:53:27 +00:00
-- https://alpha2phi.medium.com/neovim-101-regular-expression-f15a6d782add
function util.get_fname_num(line)
line = util.trim(line)
local reg = [[\(.\+\.go\)\:\(\d\+\):]]
local f = fn.matchlist(line, reg)
if f[1] and f[1] ~= '' then
return f[2], tonumber(f[3])
end
end
2022-06-01 11:29:13 +00:00
function util.smartrun()
2022-01-10 10:26:41 +00:00
local cmd
2022-06-01 11:29:13 +00:00
if util.has_main() then
2022-07-30 13:05:27 +00:00
cmd = string.format('lcd %:p:h | :set makeprg=%s\\ run\\ . | :make | :lcd -', _GO_NVIM_CFG.go)
2022-01-10 10:26:41 +00:00
vim.cmd(cmd)
2021-08-16 23:59:01 +00:00
else
2022-07-30 13:05:27 +00:00
cmd = string.format('setl makeprg=%s\\ run\\ . | :make', _GO_NVIM_CFG.go)
2022-01-10 10:26:41 +00:00
vim.cmd(cmd)
2021-08-16 23:59:01 +00:00
end
end
2022-06-01 11:29:13 +00:00
function util.smartbuild()
2022-01-10 10:26:41 +00:00
local cmd
2022-06-01 11:29:13 +00:00
if util.has_main() then
2022-07-30 13:05:27 +00:00
cmd = string.format('lcd %:p:h | :set makeprg=%s\\ build\\ . | :make | :lcd -', _GO_NVIM_CFG.go)
2022-01-10 10:26:41 +00:00
vim.cmd(cmd)
2021-08-16 23:59:01 +00:00
else
2022-07-30 13:05:27 +00:00
cmd = string.format('setl makeprg=%s\\ build\\ . | :make', _GO_NVIM_CFG.go)
2022-01-10 10:26:41 +00:00
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)
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
2022-07-30 13:05:27 +00:00
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
2022-07-30 13:05:27 +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.
2022-06-01 11:29:13 +00:00
for _ = 1, 3, 1 do
2022-07-30 13:05:27 +00:00
if data[#data] == '' then
2021-12-27 08:47:59 +00:00
table.remove(data, #data)
end
2021-07-07 05:10:06 +00:00
end
if #data < 1 then
return nil
end
-- remove ansi escape code
for i, v in ipairs(data) do
data[i] = util.remove_ansi_escape(data[i])
end
2021-07-07 05:10:06 +00:00
return data
end
2021-03-10 12:15:06 +00:00
2022-07-30 13:05:27 +00:00
local cache_dir = fn.stdpath('cache')
2021-03-10 12:15:06 +00:00
util.log = function(...)
2023-01-19 01:26:14 +00:00
if not _GO_NVIM_CFG or not _GO_NVIM_CFG.verbose then
2021-08-24 04:53:37 +00:00
return
end
2021-12-16 07:15:21 +00:00
local arg = { ... }
2022-07-30 13:05:27 +00:00
local log_default = string.format('%s%sgonvim.log', cache_dir, util.sep())
local log_path = _GO_NVIM_CFG.log_path or log_default
2022-07-30 13:05:27 +00:00
local str = ''
2022-07-30 13:05:27 +00:00
local info = debug.getinfo(2, 'Sl')
str = str .. info.short_src .. ':' .. info.currentline
local _, ms = vim.loop.gettimeofday()
str = string.format('[%s %d] %s', os.date(), ms, str)
2021-08-24 04:53:37 +00:00
for i, v in ipairs(arg) do
2022-07-30 13:05:27 +00:00
if type(v) == 'table' then
str = str .. ' |' .. tostring(i) .. ': ' .. vim.inspect(v or 'nil') .. '\n'
2021-08-24 04:53:37 +00:00
else
str = str .. ' |' .. tostring(i) .. ': ' .. tostring(v or 'nil')
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
2022-07-30 13:05:27 +00:00
local f, err = io.open(log_path, 'a+')
2021-08-24 04:53:37 +00:00
if err then
vim.notify('failed to open log' .. log_path .. err, vim.log.levels.ERROR)
2021-08-24 04:53:37 +00:00
return
end
if not f then
2022-07-30 13:05:27 +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)
2022-07-30 13:05:27 +00:00
io.write(str .. '\n')
2021-08-24 04:53:37 +00:00
io.close(f)
else
vim.notify(str .. '\n', vim.log.levels.DEBUG)
2021-07-08 16:16:22 +00:00
end
2021-03-10 12:15:06 +00:00
end
end
util.trace = function(...)
end
2021-07-10 11:04:24 +00:00
local rhs_options = {}
function rhs_options:new()
local instance = {
2022-07-30 13:05:27 +00:00
cmd = '',
2021-12-16 07:15:21 +00:00
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)
2022-07-30 13:05:27 +00:00
self.cmd = (':%s<CR>'):format(cmd_string)
2021-07-10 11:04:24 +00:00
return self
end
function rhs_options:map_args(cmd_string)
2022-07-30 13:05:27 +00:00
self.cmd = (':%s<Space>'):format(cmd_string)
2021-07-10 11:04:24 +00:00
return self
end
function rhs_options:map_cu(cmd_string)
2022-07-30 13:05:27 +00:00
self.cmd = (':<C-u>%s<CR>'):format(cmd_string)
2021-07-10 11:04:24 +00:00
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
2022-07-30 13:05:27 +00:00
local mode, keymap = key:match('([^|]*)|?(.*)')
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)
2022-07-30 13:05:27 +00:00
assert(name ~= nil, 'plugin should not empty')
2021-07-10 11:04:24 +00:00
modulename = modulename or name
local has, plugin = pcall(require, modulename)
if has then
return plugin
end
2023-02-08 09:56:26 +00:00
local pkg = packer_plugins
local has_packer = pcall(require, 'packer')
local has_lazy = pcall(require, 'lazy')
if has_packer or has_lazy then
2021-07-10 11:04:24 +00:00
-- packer installed
2023-02-08 09:56:26 +00:00
if has_packer then
local loader = require('packer').loader
if not pkg[name] or not pkg[name].loaded then
util.log('packer loader ' .. name)
vim.cmd('packadd ' .. name) -- load with default
if pkg[name] ~= nil then
loader(name)
end
end
2023-02-08 09:56:26 +00:00
else
require('lazy').load({ plugins = name })
2023-02-08 09:56:26 +00:00
end
2021-07-10 11:04:24 +00:00
else
2022-07-30 13:05:27 +00:00
util.log('packadd ' .. name)
2022-05-24 11:14:40 +00:00
local paths = vim.o.runtimepath
2022-05-24 11:17:55 +00:00
if paths:find(name) then
2022-07-30 13:05:27 +00:00
vim.cmd('packadd ' .. name)
2022-05-24 10:58:54 +00:00
end
2021-07-10 11:04:24 +00:00
end
has, plugin = pcall(require, modulename)
if not has then
2022-07-30 13:05:27 +00:00
util.info('plugin ' .. name .. ' module ' .. modulename .. ' not loaded ')
2022-01-15 11:14:56 +00:00
return nil
end
2021-07-10 11:04:24 +00:00
return plugin
end
2022-04-24 11:03:38 +00:00
-- deprecated
-- 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)
-- util.log(client.server_capabilities)
-- supported_client = client.resolved_capabilities[feature]
-- supported_client = client.resolved_capabilities[feature]
-- if supported_client then
-- break
-- end
-- end
--
-- if supported_client then
-- return true
-- else
-- if #clients == 0 then
-- util.log("LSP: no client attached")
-- else
-- 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)
local rel = fn.isdirectory(name) == 0 and fn.fnamemodify(name, ':h:.')
or fn.fnamemodify(name, ':.')
2022-07-30 13:05:27 +00:00
if rel == '.' then
return '.'
2021-11-13 03:29:42 +00:00
else
2022-07-30 13:05:27 +00:00
return '.' .. util.sep() .. rel
2021-11-13 03:29:42 +00:00
end
end
2022-06-18 05:43:07 +00:00
function util.chdir(dir)
2022-07-30 13:05:27 +00:00
if fn.exists('*chdir') then
2022-06-18 05:43:07 +00:00
return fn.chdir(dir)
end
local oldir = fn.getcwd()
2022-07-30 13:05:27 +00:00
local cd = 'cd'
if fn.exists('*haslocaldir') and fn.haslocaldir() then
cd = 'lcd'
vim.cmd(cd .. ' ' .. fn.fnameescape(dir))
2022-06-18 05:43:07 +00:00
return oldir
end
end
2021-11-13 03:29:42 +00:00
function util.all_pkgs()
2022-07-30 13:05:27 +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)
2023-04-01 03:04:03 +00:00
vim.schedule(function()
vim.notify('WARN: ' .. msg, vim.log.levels.WARN)
end)
2021-11-16 22:22:16 +00:00
end
function util.error(msg)
2023-04-01 03:04:03 +00:00
vim.schedule(function()
vim.notify('ERR: ' .. msg, vim.log.levels.ERROR)
end)
2021-11-16 22:22:16 +00:00
end
function util.info(msg)
2023-04-01 03:04:03 +00:00
vim.schedule(function()
vim.notify('INFO: ' .. msg, vim.log.levels.INFO)
end)
2021-11-16 22:22:16 +00:00
end
function util.debug(msg)
2023-04-01 03:04:03 +00:00
vim.schedule(function()
vim.notify('DEBUG: ' .. msg, vim.log.levels.DEBUG)
end)
end
function util.rel_path(folder)
2022-07-05 22:28:29 +00:00
-- maybe expand('%:p:h:t')
2022-07-30 13:05:27 +00:00
local mod = '%:p'
if folder then
2022-07-30 13:05:27 +00:00
mod = '%:p:h'
end
local fpath = fn.expand(mod)
2021-12-16 07:15:21 +00:00
local workfolders = vim.lsp.buf.list_workspace_folders()
2022-07-05 22:28:29 +00:00
if fn.empty(workfolders) == 0 then
2022-07-30 13:05:27 +00:00
fpath = '.' .. fpath:sub(#workfolders[1] + 1)
2022-07-05 22:28:29 +00:00
else
2022-07-30 13:05:27 +00:00
fpath = fn.fnamemodify(fn.expand(mod), ':p:.')
2022-07-05 22:28:29 +00:00
end
util.log(fpath:sub(#fpath), fpath, util.sep())
if fpath:sub(#fpath) == util.sep() then
fpath = fpath:sub(1, #fpath - 1)
util.log(fpath)
2021-11-23 23:13:40 +00:00
end
2022-07-05 22:28:29 +00:00
return fpath
2021-11-23 23:13:40 +00:00
end
function util.trim(s)
if s then
s = util.ltrim(s)
return util.rtrim(s)
end
end
2021-12-02 06:44:22 +00:00
function util.rtrim(s)
local n = #s
2022-07-30 13:05:27 +00:00
while n > 0 and s:find('^%s', n) do
2021-12-02 06:44:22 +00:00
n = n - 1
end
return s:sub(1, n)
end
function util.ltrim(s)
2022-07-30 13:05:27 +00:00
return (s:gsub('^%s*', ''))
end
2021-12-16 07:15:21 +00:00
function util.work_path()
2022-07-30 13:05:27 +00:00
local fpath = fn.expand('%:p:h')
2021-12-16 07:15:21 +00:00
local workfolders = vim.lsp.buf.list_workspace_folders()
if #workfolders == 1 then
return workfolders[1]
end
for _, value in pairs(workfolders) do
2022-07-30 13:05:27 +00:00
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
2022-07-30 13:05:27 +00:00
if type(t) ~= 'table' then
return false
end
return next(t) == nil
end
local open = io.open
function util.read_file(path)
2022-07-30 13:05:27 +00:00
local file = open(path, 'rb') -- r read mode and b binary mode
if not file then
return nil
end
2022-07-30 13:05:27 +00:00
local content = file:read('*a') -- *a or *all reads the whole file
file:close()
return content
end
2022-02-21 22:46:59 +00:00
function util.restart(cmd_args)
local old_lsp_clients = vim.lsp.get_active_clients()
2022-07-30 13:05:27 +00:00
local configs = require('lspconfig.configs')
for _, client in pairs(old_lsp_clients) do
2022-10-01 04:53:27 +00:00
if client.name == 'gopls' then
vim.lsp.stop_client(client.id)
end
end
2022-10-01 04:53:27 +00:00
if configs['gopls'] ~= nil then
vim.defer_fn(function()
2022-10-01 04:53:27 +00:00
configs['gopls'].launch()
end, 500)
2022-02-21 22:46:59 +00:00
end
end
2022-05-10 07:59:48 +00:00
util.deletedir = function(dir)
2022-07-30 13:05:27 +00:00
local lfs = require('lfs')
2022-05-10 07:59:48 +00:00
for file in lfs.dir(dir) do
2022-07-30 13:05:27 +00:00
local file_path = dir .. '/' .. file
if file ~= '.' and file ~= '..' then
if lfs.attributes(file_path, 'mode') == 'file' then
2022-05-10 07:59:48 +00:00
os.remove(file_path)
2022-07-30 13:05:27 +00:00
print('remove file', file_path)
elseif lfs.attributes(file_path, 'mode') == 'directory' then
print('dir', file_path)
2022-05-10 07:59:48 +00:00
util.deletedir(file_path)
end
end
end
lfs.rmdir(dir)
2022-07-30 13:05:27 +00:00
util.log('remove dir', dir)
2022-05-10 07:59:48 +00:00
end
2022-06-01 11:29:13 +00:00
function util.file_exists(name)
2022-07-30 13:05:27 +00:00
local f = io.open(name, 'r')
2022-06-01 11:29:13 +00:00
if f ~= nil then
io.close(f)
return true
end
2022-06-01 11:29:13 +00:00
return false
2022-05-13 09:27:02 +00:00
end
-- get all lines from a file, returns an empty
-- list/table if the file does not exist
function util.lines_from(file)
if not util.file_exists(file) then
return {}
end
2022-05-13 09:27:02 +00:00
local lines = {}
for line in io.lines(file) do
lines[#lines + 1] = line
end
return lines
end
function util.list_directory()
2022-07-30 13:05:27 +00:00
return fn.map(fn.glob(fn.fnameescape('./') .. '/{,.}*/', 1, 1), 'fnamemodify(v:val, ":h:t")')
2022-05-13 09:27:02 +00:00
end
function util.get_active_buf()
local lb = fn.getbufinfo({ buflisted = 1 })
util.log(lb)
local result = {}
for _, item in ipairs(lb) do
if fn.empty(item.name) == 0 and item.hidden == 0 then
2022-07-30 13:05:27 +00:00
util.log('buf loaded', item.name)
table.insert(result, { name = fn.shellescape(item.name), bufnr = item.bufnr })
end
end
return result
2022-05-13 09:27:02 +00:00
end
-- for l:item in l:blist
-- "skip unnamed buffers; also skip hidden buffers?
-- if empty(l:item.name) || l:item.hidden
-- continue
-- endif
-- call add(l:result, shellescape(l:item.name))
-- return l:result
2022-05-13 09:27:02 +00:00
function util.set_nulls()
if _GO_NVIM_CFG.null_ls_document_formatting_disable then
local query = {}
2022-07-30 13:05:27 +00:00
if type(_GO_NVIM_CFG.null_ls_document_formatting_disable) ~= 'boolean' then
2022-05-13 09:27:02 +00:00
query = _GO_NVIM_CFG.null_ls_document_formatting_disable
end
2022-07-30 13:05:27 +00:00
local ok, nulls = pcall(require, 'null-ls')
2022-05-13 09:27:02 +00:00
if ok then
nulls.disable(query)
end
end
end
2022-06-18 05:43:07 +00:00
-- run in current source code path
function util.exec_in_path(cmd, bufnr, ...)
bufnr = bufnr or vim.api.nvim_get_current_buf()
2023-03-14 12:01:56 +00:00
local path
if type(bufnr) == 'string' then
path = bufnr
else
path = fn.fnamemodify(fn.bufname(bufnr), ':p:h')
end
2022-06-18 05:43:07 +00:00
local dir = util.chdir(path)
local result
2022-07-30 13:05:27 +00:00
if type(cmd) == 'function' then
result = cmd(bufnr, ...)
2022-06-18 05:43:07 +00:00
else
result = fn.systemlist(cmd, ...)
end
util.log(result)
util.chdir(dir)
return result
end
function util.line_ending()
2022-07-30 13:05:27 +00:00
if vim.o.fileformat == 'dos' then
return '\r\n'
elseif vim.o.fileformat == 'mac' then
return '\r'
2022-06-18 05:43:07 +00:00
end
2022-07-30 13:05:27 +00:00
return '\n'
2022-06-18 05:43:07 +00:00
end
function util.offset(line, col)
util.log(line, col)
2022-07-30 13:05:27 +00:00
if vim.o.encoding ~= 'utf-8' then
print('only utf-8 encoding is supported current encoding: ', vim.o.encoding)
2022-06-18 05:43:07 +00:00
end
return fn.line2byte(line) + col - 2
end
-- parse //+build integration unit
2022-08-06 11:11:12 +00:00
-- //go:build ci
function util.get_build_tags(buf)
local tags = {}
2022-07-30 13:05:27 +00:00
buf = buf or '%'
local pattern = [[^//\s*[+|(go:)]*build\s\+\(.\+\)]]
2022-07-30 13:05:27 +00:00
local cnt = vim.fn.getbufinfo(buf)[1]['linecount']
cnt = math.min(cnt, 10)
for i = 1, cnt do
local line = vim.fn.trim(vim.fn.getbufline(buf, i)[1])
2022-07-30 13:05:27 +00:00
if string.find(line, 'package') then
break
end
2022-07-30 13:05:27 +00:00
local t = vim.fn.substitute(line, pattern, [[\1]], '')
if t ~= line then -- tag found
2022-07-30 13:05:27 +00:00
t = vim.fn.substitute(t, [[ \+]], ',', 'g')
table.insert(tags, t)
end
end
if #tags > 0 then
return tags
end
end
-- a uuid
function util.uuid()
2022-07-30 13:05:27 +00:00
math.randomseed(tonumber(tostring(os.time()):reverse():sub(1, 9)))
local random = math.random
local template = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'
return string.gsub(template, '[xy]', function(c)
local v = (c == 'x') and random(0, 0xf) or random(8, 0xb)
return string.format('%x', v)
end)
end
2022-07-30 13:05:27 +00:00
local lorem =
'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum'
function util.lorem()
return lorem
end
function util.random_words(len)
local str = util.lorem()
2022-07-30 13:05:27 +00:00
local words = fn.split(str, ' ')
str = ''
for i = 1, len do
2022-07-30 13:05:27 +00:00
str = str .. ' ' .. words[math.random(#words)]
end
return str
end
function util.random_line()
2022-07-30 13:05:27 +00:00
local lines = vim.split(lorem, ', ')
return lines[math.random(#lines)] .. ','
end
function util.run_command(cmd, ...)
local result = fn.systemlist(cmd, ...)
return result
end
2022-07-30 13:05:27 +00:00
function util.quickfix(cmd)
if _GO_NVIM_CFG.trouble == true then
local ok, trouble = pcall(require, 'trouble')
if ok then
if cmd:find('copen') then
trouble.open('quickfix')
else
trouble.open('loclist')
end
else
vim.notify('trouble not found')
end
else
vim.cmd(cmd)
end
end
2022-07-26 16:21:58 +00:00
util.debounce = function(func, duration)
local timer = vim.loop.new_timer()
local function inner(args)
timer:stop()
timer:start(
duration,
0,
vim.schedule_wrap(function()
2022-07-26 16:21:58 +00:00
func(args)
end)
)
end
2022-07-30 13:05:27 +00:00
local group = vim.api.nvim_create_augroup('gonvim__CleanupLuvTimers', {})
vim.api.nvim_create_autocmd('VimLeavePre', {
group = group,
2022-07-30 13:05:27 +00:00
pattern = '*',
callback = function()
if timer then
if timer:has_ref() then
timer:stop()
if not timer:is_closing() then
timer:close()
end
end
timer = nil
end
end,
})
return timer, inner
end
local namepath = {}
util.extract_filepath = function(msg, pkg_path)
msg = msg or ''
-- util.log(msg)
--[[ or [[ findAllSubStr_test.go:234: Error inserting caseResult1: operation error DynamoDB: PutItem, exceeded maximum number of attempts]]
-- or 'path/path2/filename.go:50:11: Error invaild
-- or /home/ray/go/src/github/sample/app/driver.go:342 +0x19e5
local ma = fn.matchlist(msg, [[\v\s*(\w+.+\.go):(\d+):]])
ma = ma or fn.matchlist(msg, [[\v\s*(\w+.+\.go):(\d+)]])
local filename, lnum
if ma[2] then
util.log(ma)
filename = ma[2]
lnum = ma[3]
else
return
end
util.log('fname : ' .. (filename or 'nil') .. ':' .. (lnum or '-1'))
if namepath[filename] then
-- if name is same, no need to update path
return (namepath[filename] ~= filename), namepath[filename], lnum
end
if vim.fn.filereadable(filename) == 1 then
util.log('filename', filename)
-- no need to extract path, already quickfix format
namepath[filename] = filename
return false, filename, lnum
end
if pkg_path then
local pn = pkg_path:gsub('%.%.%.', '')
local fname = pn .. util.sep() .. filename
if vim.fn.filereadable(fname) == 1 then
namepath[filename] = fname
util.log('fname with pkg_name', fname)
return true, fname, lnum
end
end
local fname = fn.fnamemodify(fn.expand('%:h'), ':~:.') .. util.sep() .. ma[2]
util.log(fname, namepath[fname])
2023-02-01 21:53:54 +00:00
if vim.fn.filereadable(fname) == 1 then
namepath[filename] = fname
return true, fname, lnum
end
if namepath[filename] ~= nil then
util.log(namepath[filename])
return namepath[filename], lnum
end
if vim.fn.executable('find') == 0 then
return false, fname, lnum
end
-- note: slow operations
local cmd = 'find ./ -type f -name ' .. filename
local path = vim.fn.systemlist(cmd)
if vim.v.shell_error ~= 0 then
util.warn('find failed ' .. cmd .. vim.inspect(path))
end
for _, value in pairs(path) do
local st, _ = value:find(filename)
if st then
-- find cmd returns `./path/path2/filename.go`, the leading './' is not needed for quickfix
local p = value:sub(1, st - 1)
util.log(value, st, p)
namepath[filename] = p
return true, p, lnum
end
end
-- nothing... we will not check this file again
namepath[filename] = filename
end
util.remove_ansi_escape = function(str)
local ansi_escape_pattern = '\27%[%d+;%d*;%d*m'
-- Replace all occurrences of the pattern with an empty string
str = str:gsub(ansi_escape_pattern, '')
str = str:gsub('\27%[[%d;]*%a', '')
return str
end
-- Keeps track of tools that are already installed.
-- The keys are the names of tools and the values are booleans
-- indicating whether the tools is available or not.
util.installed_tools = {}
-- Check if host has goenv in path.
util.goenv_mode = function()
if is_windows then
-- always return false for Windows because goenv doesn't seem to be supported there.
return false
end
local cmd = "command -v goenv > /dev/null 2>&1"
local status = os.execute(cmd)
return status == 0
end
2021-03-10 12:15:06 +00:00
return util