305 lines
7.1 KiB
Lua
305 lines
7.1 KiB
Lua
local M = {}
|
|
|
|
local function printf(...) print(string.format(...)) end
|
|
local sprintf = string.format
|
|
local function cmdf(...) vim.cmd(sprintf(...)) end
|
|
local fn, api = vim.fn, vim.api
|
|
|
|
M.printf = printf
|
|
M.sprintf = sprintf
|
|
M.cmdf = cmdf
|
|
|
|
function M.get_cursor_pos() return {fn.line('.'), fn.col('.')} end
|
|
|
|
function M.debounce(func, timeout)
|
|
local timer_id
|
|
return function(...)
|
|
if timer_id ~= nil then
|
|
fn.timer_stop(timer_id)
|
|
end
|
|
local args = {...}
|
|
local function cb()
|
|
func(args)
|
|
timer_id = nil
|
|
end
|
|
timer_id = fn.timer_start(timeout, cb)
|
|
end
|
|
end
|
|
|
|
-- FIXME
|
|
function M.throttle(func, timeout)
|
|
local timer_id
|
|
local did_call = false
|
|
return function(...)
|
|
local args = {...}
|
|
if timer_id == nil then
|
|
func(unpack(args))
|
|
local function cb()
|
|
timer_id = nil
|
|
if did_call then
|
|
func(unpack(args))
|
|
did_call = false
|
|
end
|
|
end
|
|
timer_id = fn.timer_start(timeout, cb)
|
|
else
|
|
did_call = true
|
|
end
|
|
end
|
|
end
|
|
|
|
function M.run_colorscheme(colorscheme,callback)
|
|
local ok,err = pcall(function()
|
|
vim.cmd("colorscheme " .. colorscheme)
|
|
callback()
|
|
end)
|
|
|
|
if (not ok) then
|
|
vim.notify(err)
|
|
end
|
|
end
|
|
|
|
|
|
-- Convert UTF-8 hex code to character
|
|
function M.u(code)
|
|
if type(code) == 'string' then
|
|
code = tonumber('0x' .. code)
|
|
end
|
|
local c = string.char
|
|
if code <= 0x7f then
|
|
return c(code)
|
|
end
|
|
local t = {}
|
|
if code <= 0x07ff then
|
|
t[1] = c(bit.bor(0xc0, bit.rshift(code, 6)))
|
|
t[2] = c(bit.bor(0x80, bit.band(code, 0x3f)))
|
|
elseif code <= 0xffff then
|
|
t[1] = c(bit.bor(0xe0, bit.rshift(code, 12)))
|
|
t[2] = c(bit.bor(0x80, bit.band(bit.rshift(code, 6), 0x3f)))
|
|
t[3] = c(bit.bor(0x80, bit.band(code, 0x3f)))
|
|
else
|
|
t[1] = c(bit.bor(0xf0, bit.rshift(code, 18)))
|
|
t[2] = c(bit.bor(0x80, bit.band(bit.rshift(code, 12), 0x3f)))
|
|
t[3] = c(bit.bor(0x80, bit.band(bit.rshift(code, 6), 0x3f)))
|
|
t[4] = c(bit.bor(0x80, bit.band(code, 0x3f)))
|
|
end
|
|
return table.concat(t)
|
|
end
|
|
|
|
function _G.dump(...)
|
|
local args = {...}
|
|
if #args == 1 then
|
|
print(vim.inspect(args[1]))
|
|
else
|
|
print(vim.inspect(args))
|
|
end
|
|
end
|
|
|
|
function M.load(path)
|
|
local ok, mod = pcall(require, path)
|
|
if not ok then
|
|
printf('Error loading module `%s`', path)
|
|
print(mod)
|
|
else
|
|
local loadfunc
|
|
if mod == true then
|
|
-- Module doesn't export anything
|
|
return
|
|
elseif type(mod) == "table" and mod.setup ~= nil then
|
|
loadfunc = mod.setup
|
|
elseif type(mod) == "function" then
|
|
loadfunc = mod
|
|
end
|
|
local ok, err = pcall(loadfunc)
|
|
if not ok then
|
|
printf("Error loading module `%s`", path)
|
|
print(err)
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Get information about highlight group
|
|
function M.hl_by_name(hl_group)
|
|
local hl = api.nvim_get_hl_by_name(hl_group, true)
|
|
if hl.foreground ~= nil then
|
|
hl.fg = sprintf('#%x', hl.foreground)
|
|
end
|
|
if hl.background ~= nil then
|
|
hl.bg = sprintf('#%x', hl.background)
|
|
end
|
|
return hl
|
|
end
|
|
|
|
function M.isempty(s)
|
|
return s == nil or s == ""
|
|
end
|
|
|
|
function M.get_buf_option(opt)
|
|
local status_ok, buf_option = pcall(vim.api.nvim_buf_get_option, 0, opt)
|
|
if not status_ok then
|
|
return nil
|
|
else
|
|
return buf_option
|
|
end
|
|
end
|
|
|
|
-- Define a new highlight group
|
|
-- TODO: rewrite to `nvim_set_hl()` when API will be stable
|
|
function M.highlight(cfg)
|
|
local command = "highlight"
|
|
if cfg.bang == true then
|
|
command = command .. '!'
|
|
end
|
|
|
|
if #cfg == 2 and type(cfg[1]) == 'string' and type(cfg[2]) == 'string' then
|
|
-- :highlight link
|
|
vim.cmd(command.." link "..cfg[1].." "..cfg[2])
|
|
return
|
|
end
|
|
local guifg = cfg.fg or cfg.guifg
|
|
local guibg = cfg.bg or cfg.guibg
|
|
local gui = cfg.gui
|
|
local guisp = cfg.guisp
|
|
if type(cfg.override) == 'string' then
|
|
local existing = api.nvim_get_hl_by_name(cfg.override, true)
|
|
if existing.foreground ~= nil then
|
|
guifg = sprintf('#%x', existing.foreground)
|
|
end
|
|
if existing.background ~= nil then
|
|
guibg = sprintf('#%x', existing.background)
|
|
end
|
|
if existing.special ~= nil then
|
|
guibg = sprintf('#%x', existing.background)
|
|
end
|
|
if existing.undercurl == true then
|
|
gui = "undercurl"
|
|
elseif existing.underline == true then
|
|
gui = "underline"
|
|
end
|
|
end
|
|
command = command .. ' ' .. cfg[1]
|
|
if guifg ~= nil then
|
|
command = command .. ' guifg=' .. guifg
|
|
end
|
|
if guibg ~= nil then
|
|
command = command .. ' guibg=' .. guibg
|
|
end
|
|
if gui ~= nil then
|
|
command = command .. ' gui=' .. gui
|
|
end
|
|
if guisp ~= nil then
|
|
command = command .. ' guisp=' .. guisp
|
|
end
|
|
vim.cmd(command)
|
|
end
|
|
|
|
local autocmd_fn_index = 0
|
|
|
|
-- WIP:
|
|
function M.autocmd(event_name, pattern, callback)
|
|
local fn_name = 'lua_autocmd' .. autocmd_fn_index
|
|
autocmd_fn_index = autocmd_fn_index + 1
|
|
_G[fn_name] = callback
|
|
cmdf('autocmd %s %s call v:lua.%s()', event_name, pattern, fn_name)
|
|
end
|
|
|
|
function M.glob_exists(path) return fn.empty(fn.glob(path)) == 0 end
|
|
|
|
do
|
|
local show_diagnostics = vim.lsp.diagnostic.show_line_diagnostics
|
|
local cursor_pos = M.get_cursor_pos()
|
|
local debounced = M.debounce(show_diagnostics, 300)
|
|
M.show_lsp_diagnostics = function()
|
|
local cursor_pos2 = M.get_cursor_pos()
|
|
-- TODO: doesn't work when both diagnostics and popup is shown
|
|
if cursor_pos[1] ~= cursor_pos2[1] and cursor_pos[2] ~= cursor_pos2[2] then
|
|
cursor_pos = cursor_pos2
|
|
debounced()
|
|
end
|
|
end
|
|
end
|
|
|
|
function M.id_generator(start)
|
|
local cnt = start or 0
|
|
return function()
|
|
local result = cnt
|
|
cnt = cnt + 1
|
|
return result
|
|
end
|
|
end
|
|
|
|
do
|
|
local map_func_counter = 0
|
|
function M.map(mode, lhs, fn, opts)
|
|
local name = 'map_func_' .. map_func_counter
|
|
_G[name] = fn
|
|
local rhs = ':call v:lua.' .. name .. '()<CR>'
|
|
api.nvim_set_keymap(mode, lhs, rhs, opts)
|
|
map_func_counter = map_func_counter + 1
|
|
end
|
|
end
|
|
|
|
for _, mode in ipairs {'', 'n', 'i', 'c', 'x'} do
|
|
M[mode .. 'noremap'] = function(lhs, fn, opts)
|
|
local mapopts = opts or {}
|
|
mapopts.noremap = true
|
|
return M.map(mode, lhs, fn, mapopts)
|
|
end
|
|
end
|
|
|
|
function M.log_time(fn, label)
|
|
return function(...)
|
|
local now = os.clock()
|
|
fn(...)
|
|
print(
|
|
((label and (label .. ' ')) or '') ..
|
|
(math.floor((os.clock() - now) * 1e6) / 1000) ..
|
|
"ms."
|
|
)
|
|
end
|
|
end
|
|
|
|
-- TODO: fix function
|
|
function M.require_mod(modname)
|
|
local ok,mod = pcall(require,modname)
|
|
local notify_ok,notify = pcall(require,"notify")
|
|
if (not ok) then
|
|
local errmsg = "Failed to load " .. modname
|
|
if (notify_ok) then
|
|
notify(
|
|
errmsg,
|
|
"error",
|
|
{
|
|
title = "require"
|
|
}
|
|
)
|
|
else
|
|
vim.notify(errmsg)
|
|
end
|
|
|
|
return
|
|
end
|
|
|
|
return mod
|
|
end
|
|
|
|
function M.index_of(t, v, eqfn)
|
|
eqfn = eqfn or (function(el) return el == v end)
|
|
for i, value in ipairs(t) do
|
|
if eqfn(value, v) then
|
|
return i
|
|
end
|
|
end
|
|
return -1
|
|
end
|
|
|
|
local globalfn_counter = 0
|
|
function M.defglobalfn(func)
|
|
assert(type(func) == "function")
|
|
local name = "_lua_fn_" .. globalfn_counter
|
|
_G[name] = func
|
|
globalfn_counter = globalfn_counter + 1
|
|
return name
|
|
end
|
|
return M
|