Meh I'll figure out submodules later
This commit is contained in:
parent
4ca9d44a90
commit
8cb281f436
352 changed files with 66107 additions and 0 deletions
478
.config/nvim/pack/tree/start/nui.nvim/lua/nui/utils/autocmd.lua
Normal file
478
.config/nvim/pack/tree/start/nui.nvim/lua/nui/utils/autocmd.lua
Normal file
|
|
@ -0,0 +1,478 @@
|
|||
local buf_storage = require("nui.utils.buf_storage")
|
||||
local is_type = require("nui.utils").is_type
|
||||
local feature = require("nui.utils")._.feature
|
||||
|
||||
local autocmd = {
|
||||
event = {
|
||||
-- after adding a buffer to the buffer list
|
||||
BufAdd = "BufAdd",
|
||||
-- deleting a buffer from the buffer list
|
||||
BufDelete = "BufDelete",
|
||||
-- after entering a buffer
|
||||
BufEnter = "BufEnter",
|
||||
-- after renaming a buffer
|
||||
BufFilePost = "BufFilePost",
|
||||
-- before renaming a buffer
|
||||
BufFilePre = "BufFilePre",
|
||||
-- just after buffer becomes hidden
|
||||
BufHidden = "BufHidden",
|
||||
-- before leaving a buffer
|
||||
BufLeave = "BufLeave",
|
||||
-- after the 'modified' state of a buffer changes
|
||||
BufModifiedSet = "BufModifiedSet",
|
||||
-- after creating any buffer
|
||||
BufNew = "BufNew",
|
||||
-- when creating a buffer for a new file
|
||||
BufNewFile = "BufNewFile",
|
||||
-- read buffer using command
|
||||
BufReadCmd = "BufReadCmd",
|
||||
-- after reading a buffer
|
||||
BufReadPost = "BufReadPost",
|
||||
-- before reading a buffer
|
||||
BufReadPre = "BufReadPre",
|
||||
-- just before unloading a buffer
|
||||
BufUnload = "BufUnload",
|
||||
-- after showing a buffer in a window
|
||||
BufWinEnter = "BufWinEnter",
|
||||
-- just after buffer removed from window
|
||||
BufWinLeave = "BufWinLeave",
|
||||
-- just before really deleting a buffer
|
||||
BufWipeout = "BufWipeout",
|
||||
-- write buffer using command
|
||||
BufWriteCmd = "BufWriteCmd",
|
||||
-- after writing a buffer
|
||||
BufWritePost = "BufWritePost",
|
||||
-- before writing a buffer
|
||||
BufWritePre = "BufWritePre",
|
||||
-- info was received about channel
|
||||
ChanInfo = "ChanInfo",
|
||||
-- channel was opened
|
||||
ChanOpen = "ChanOpen",
|
||||
-- command undefined
|
||||
CmdUndefined = "CmdUndefined",
|
||||
-- command line was modified
|
||||
CmdlineChanged = "CmdlineChanged",
|
||||
-- after entering cmdline mode
|
||||
CmdlineEnter = "CmdlineEnter",
|
||||
-- before leaving cmdline mode
|
||||
CmdlineLeave = "CmdlineLeave",
|
||||
-- after entering the cmdline window
|
||||
CmdWinEnter = "CmdwinEnter",
|
||||
-- before leaving the cmdline window
|
||||
CmdWinLeave = "CmdwinLeave",
|
||||
-- after loading a colorscheme
|
||||
ColorScheme = "ColorScheme",
|
||||
-- before loading a colorscheme
|
||||
ColorSchemePre = "ColorSchemePre",
|
||||
-- after popup menu changed
|
||||
CompleteChanged = "CompleteChanged",
|
||||
-- after finishing insert complete
|
||||
CompleteDone = "CompleteDone",
|
||||
-- idem, before clearing info
|
||||
CompleteDonePre = "CompleteDonePre",
|
||||
-- cursor in same position for a while
|
||||
CursorHold = "CursorHold",
|
||||
-- idem, in Insert mode
|
||||
CursorHoldI = "CursorHoldI",
|
||||
-- cursor was moved
|
||||
CursorMoved = "CursorMoved",
|
||||
-- cursor was moved in Insert mode
|
||||
CursorMovedI = "CursorMovedI",
|
||||
-- diffs have been updated
|
||||
DiffUpdated = "DiffUpdated",
|
||||
-- directory changed
|
||||
DirChanged = "DirChanged",
|
||||
-- after changing the 'encoding' option
|
||||
EncodingChanged = "EncodingChanged",
|
||||
-- before exiting
|
||||
ExitPre = "ExitPre",
|
||||
-- append to a file using command
|
||||
FileAppendCmd = "FileAppendCmd",
|
||||
-- after appending to a file
|
||||
FileAppendPost = "FileAppendPost",
|
||||
-- before appending to a file
|
||||
FileAppendPre = "FileAppendPre",
|
||||
-- before first change to read-only file
|
||||
FileChangedRO = "FileChangedRO",
|
||||
-- after shell command that changed file
|
||||
FileChangedShell = "FileChangedShell",
|
||||
-- after (not) reloading changed file
|
||||
FileChangedShellPost = "FileChangedShellPost",
|
||||
-- read from a file using command
|
||||
FileReadCmd = "FileReadCmd",
|
||||
-- after reading a file
|
||||
FileReadPost = "FileReadPost",
|
||||
-- before reading a file
|
||||
FileReadPre = "FileReadPre",
|
||||
-- new file type detected (user defined)
|
||||
FileType = "FileType",
|
||||
-- write to a file using command
|
||||
FileWriteCmd = "FileWriteCmd",
|
||||
-- after writing a file
|
||||
FileWritePost = "FileWritePost",
|
||||
-- before writing a file
|
||||
FileWritePre = "FileWritePre",
|
||||
-- after reading from a filter
|
||||
FilterReadPost = "FilterReadPost",
|
||||
-- before reading from a filter
|
||||
FilterReadPre = "FilterReadPre",
|
||||
-- after writing to a filter
|
||||
FilterWritePost = "FilterWritePost",
|
||||
-- before writing to a filter
|
||||
FilterWritePre = "FilterWritePre",
|
||||
-- got the focus
|
||||
FocusGained = "FocusGained",
|
||||
-- lost the focus to another app
|
||||
FocusLost = "FocusLost",
|
||||
-- if calling a function which doesn't exist
|
||||
FuncUndefined = "FuncUndefined",
|
||||
-- after starting the GUI
|
||||
GUIEnter = "GUIEnter",
|
||||
-- after starting the GUI failed
|
||||
GUIFailed = "GUIFailed",
|
||||
-- when changing Insert/Replace mode
|
||||
InsertChange = "InsertChange",
|
||||
-- before inserting a char
|
||||
InsertCharPre = "InsertCharPre",
|
||||
-- when entering Insert mode
|
||||
InsertEnter = "InsertEnter",
|
||||
-- just after leaving Insert mode
|
||||
InsertLeave = "InsertLeave",
|
||||
-- just before leaving Insert mode
|
||||
InsertLeavePre = "InsertLeavePre",
|
||||
-- just before popup menu is displayed
|
||||
MenuPopup = "MenuPopup",
|
||||
-- after changing the mode
|
||||
ModeChanged = "ModeChanged",
|
||||
-- after setting any option
|
||||
OptionSet = "OptionSet",
|
||||
-- after :make, :grep etc.
|
||||
QuickFixCmdPost = "QuickFixCmdPost",
|
||||
-- before :make, :grep etc.
|
||||
QuickFixCmdPre = "QuickFixCmdPre",
|
||||
-- before :quit
|
||||
QuitPre = "QuitPre",
|
||||
-- upon string reception from a remote vim
|
||||
RemoteReply = "RemoteReply",
|
||||
-- when the search wraps around the document
|
||||
SearchWrapped = "SearchWrapped",
|
||||
-- after loading a session file
|
||||
SessionLoadPost = "SessionLoadPost",
|
||||
-- after ":!cmd"
|
||||
ShellCmdPost = "ShellCmdPost",
|
||||
-- after ":1,2!cmd", ":w !cmd", ":r !cmd".
|
||||
ShellFilterPost = "ShellFilterPost",
|
||||
-- after nvim process received a signal
|
||||
Signal = "Signal",
|
||||
-- sourcing a Vim script using command
|
||||
SourceCmd = "SourceCmd",
|
||||
-- after sourcing a Vim script
|
||||
SourcePost = "SourcePost",
|
||||
-- before sourcing a Vim script
|
||||
SourcePre = "SourcePre",
|
||||
-- spell file missing
|
||||
SpellFileMissing = "SpellFileMissing",
|
||||
-- after reading from stdin
|
||||
StdinReadPost = "StdinReadPost",
|
||||
-- before reading from stdin
|
||||
StdinReadPre = "StdinReadPre",
|
||||
-- found existing swap file
|
||||
SwapExists = "SwapExists",
|
||||
-- syntax selected
|
||||
Syntax = "Syntax",
|
||||
-- a tab has closed
|
||||
TabClosed = "TabClosed",
|
||||
-- after entering a tab page
|
||||
TabEnter = "TabEnter",
|
||||
-- before leaving a tab page
|
||||
TabLeave = "TabLeave",
|
||||
-- when creating a new tab
|
||||
TabNew = "TabNew",
|
||||
-- after entering a new tab
|
||||
TabNewEntered = "TabNewEntered",
|
||||
-- after changing 'term'
|
||||
TermChanged = "TermChanged",
|
||||
-- after the process exits
|
||||
TermClose = "TermClose",
|
||||
-- after entering Terminal mode
|
||||
TermEnter = "TermEnter",
|
||||
-- after leaving Terminal mode
|
||||
TermLeave = "TermLeave",
|
||||
-- after opening a terminal buffer
|
||||
TermOpen = "TermOpen",
|
||||
-- after setting "v:termresponse"
|
||||
TermResponse = "TermResponse",
|
||||
-- text was modified
|
||||
TextChanged = "TextChanged",
|
||||
-- text was modified in Insert mode(no popup)
|
||||
TextChangedI = "TextChangedI",
|
||||
-- text was modified in Insert mode(popup)
|
||||
TextChangedP = "TextChangedP",
|
||||
-- after a yank or delete was done (y, d, c)
|
||||
TextYankPost = "TextYankPost",
|
||||
-- after UI attaches
|
||||
UIEnter = "UIEnter",
|
||||
-- after UI detaches
|
||||
UILeave = "UILeave",
|
||||
-- user defined autocommand
|
||||
User = "User",
|
||||
-- whenthe user presses the same key 42 times
|
||||
UserGettingBored = "UserGettingBored",
|
||||
-- after starting Vim
|
||||
VimEnter = "VimEnter",
|
||||
-- before exiting Vim
|
||||
VimLeave = "VimLeave",
|
||||
-- before exiting Vim and writing ShaDa file
|
||||
VimLeavePre = "VimLeavePre",
|
||||
-- after Vim window was resized
|
||||
VimResized = "VimResized",
|
||||
-- after Nvim is resumed
|
||||
VimResume = "VimResume",
|
||||
-- before Nvim is suspended
|
||||
VimSuspend = "VimSuspend",
|
||||
-- after closing a window
|
||||
WinClosed = "WinClosed",
|
||||
-- after entering a window
|
||||
WinEnter = "WinEnter",
|
||||
-- before leaving a window
|
||||
WinLeave = "WinLeave",
|
||||
-- when entering a new window
|
||||
WinNew = "WinNew",
|
||||
-- after scrolling a window
|
||||
WinScrolled = "WinScrolled",
|
||||
|
||||
-- alias for `BufAdd`
|
||||
BufCreate = "BufAdd",
|
||||
-- alias for `BufReadPost`
|
||||
BufRead = "BufReadPost",
|
||||
-- alias for `BufWritePre`
|
||||
BufWrite = "BufWritePre",
|
||||
-- alias for `EncodingChanged`
|
||||
FileEncoding = "EncodingChanged",
|
||||
},
|
||||
buf = {
|
||||
storage = buf_storage.create("nui.utils.autocmd", { _next_handler_id = 1 }),
|
||||
},
|
||||
}
|
||||
|
||||
---@param callback fun(event: table): nil
|
||||
---@param bufnr integer
|
||||
local function to_stored_handler(callback, bufnr)
|
||||
local handler_id = autocmd.buf.storage[bufnr]._next_handler_id
|
||||
autocmd.buf.storage[bufnr]._next_handler_id = handler_id + 1
|
||||
|
||||
autocmd.buf.storage[bufnr][handler_id] = callback
|
||||
|
||||
local command = string.format(":lua require('nui.utils.autocmd').execute_stored_handler(%s, %s)", bufnr, handler_id)
|
||||
|
||||
return command
|
||||
end
|
||||
|
||||
---@param bufnr integer
|
||||
---@param handler_id number
|
||||
function autocmd.execute_stored_handler(bufnr, handler_id)
|
||||
local handler = autocmd.buf.storage[bufnr][handler_id]
|
||||
if is_type("function", handler) then
|
||||
handler()
|
||||
end
|
||||
end
|
||||
|
||||
---@param name string
|
||||
---@param opts { clear?: boolean }
|
||||
function autocmd.create_group(name, opts)
|
||||
if feature.lua_autocmd then
|
||||
return vim.api.nvim_create_augroup(name, opts)
|
||||
end
|
||||
|
||||
vim.cmd(string.format(
|
||||
[[
|
||||
augroup %s
|
||||
%s
|
||||
augroup end
|
||||
]],
|
||||
name,
|
||||
opts.clear and "autocmd!" or ""
|
||||
))
|
||||
end
|
||||
|
||||
---@param name string
|
||||
function autocmd.delete_group(name)
|
||||
if feature.lua_autocmd then
|
||||
return vim.api.nvim_del_augroup_by_name(name)
|
||||
end
|
||||
|
||||
vim.cmd(string.format(
|
||||
[[
|
||||
autocmd! %s
|
||||
augroup! %s
|
||||
]],
|
||||
name,
|
||||
name
|
||||
))
|
||||
end
|
||||
|
||||
---@param event string|string[]
|
||||
---@param opts table
|
||||
---@param bufnr? integer # to store callback if lua autocmd is not available
|
||||
function autocmd.create(event, opts, bufnr)
|
||||
if feature.lua_autocmd then
|
||||
return vim.api.nvim_create_autocmd(event, opts)
|
||||
end
|
||||
|
||||
event = type(event) == "table" and table.concat(event, ",") or event --[[@as string]]
|
||||
local pattern = is_type("table", opts.pattern) and table.concat(opts.pattern, ",") or opts.pattern
|
||||
if opts.buffer then
|
||||
pattern = string.format("<buffer=%s>", opts.buffer)
|
||||
end
|
||||
|
||||
if opts.callback then
|
||||
local buffer = opts.buffer or bufnr
|
||||
if not buffer then
|
||||
error("[nui.utils.autocmd] missing param: bufnr")
|
||||
end
|
||||
opts.command = to_stored_handler(opts.callback, buffer)
|
||||
end
|
||||
|
||||
vim.cmd(
|
||||
string.format(
|
||||
"autocmd %s %s %s %s %s %s",
|
||||
opts.group or "",
|
||||
event,
|
||||
pattern,
|
||||
opts.once and "++once" or "",
|
||||
opts.nested and "++nested" or "",
|
||||
opts.command
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
---@param opts table
|
||||
function autocmd.delete(opts)
|
||||
if feature.lua_autocmd then
|
||||
for _, item in ipairs(vim.api.nvim_get_autocmds(opts)) do
|
||||
if item.id then
|
||||
vim.api.nvim_del_autocmd(item.id)
|
||||
end
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
local event = is_type("table", opts.event) and table.concat(opts.event, ",") or opts.event
|
||||
local pattern = is_type("table", opts.pattern) and table.concat(opts.pattern, ",") or opts.pattern
|
||||
if opts.buffer then
|
||||
pattern = string.format("<buffer=%s>", opts.buffer)
|
||||
end
|
||||
|
||||
vim.cmd(string.format("autocmd! %s %s %s", opts.group or "", event or "*", pattern or ""))
|
||||
end
|
||||
|
||||
---@param event string|string[]
|
||||
---@param opts table
|
||||
function autocmd.exec(event, opts)
|
||||
local events = type(event) == "table" and event or { event } --[=[@as string[]]=]
|
||||
|
||||
if feature.lua_autocmd then
|
||||
vim.api.nvim_exec_autocmds(events, {
|
||||
group = opts.group,
|
||||
pattern = opts.pattern,
|
||||
buffer = opts.buffer,
|
||||
modeline = opts.modeline,
|
||||
data = opts.data,
|
||||
})
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
for _, event_name in ipairs(events) do
|
||||
local command = string.format(
|
||||
[[doautocmd %s %s %s %s]],
|
||||
opts.modeline == false and "<nomodeline>" or "",
|
||||
opts.group or "",
|
||||
event_name,
|
||||
opts.pattern or ""
|
||||
)
|
||||
|
||||
if opts.buffer then
|
||||
vim.api.nvim_buf_call(opts.buffer, function()
|
||||
vim.cmd(command)
|
||||
end)
|
||||
else
|
||||
vim.cmd(command)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- @deprecated
|
||||
---@deprecated
|
||||
---@param event string | string[]
|
||||
---@param pattern string | string[]
|
||||
---@param cmd string
|
||||
---@param options nil | table<"'once'" | "'nested'", boolean>
|
||||
function autocmd.define(event, pattern, cmd, options)
|
||||
local opts = options or {}
|
||||
opts.pattern = pattern
|
||||
opts.command = cmd
|
||||
autocmd.create(event, opts)
|
||||
end
|
||||
|
||||
-- @deprecated
|
||||
---@deprecated
|
||||
---@param group_name string
|
||||
---@param auto_clear boolean
|
||||
---@param definitions table<"'event'" | "'pattern'" | "'cmd'" | "'options'", any>
|
||||
function autocmd.define_grouped(group_name, auto_clear, definitions)
|
||||
if not is_type("boolean", auto_clear) then
|
||||
error("invalid param type: auto_clear, expected boolean")
|
||||
end
|
||||
|
||||
autocmd.create_group(group_name, { clear = auto_clear })
|
||||
|
||||
for _, definition in ipairs(definitions) do
|
||||
autocmd.define(definition.event, definition.pattern, definition.cmd, definition.options)
|
||||
end
|
||||
end
|
||||
|
||||
-- @deprecated
|
||||
---@deprecated
|
||||
---@param group_name nil | string
|
||||
---@param event nil | string | string[]
|
||||
---@param pattern nil | string | string[]
|
||||
function autocmd.remove(group_name, event, pattern)
|
||||
autocmd.delete({
|
||||
event = event,
|
||||
group = group_name,
|
||||
pattern = pattern,
|
||||
})
|
||||
end
|
||||
|
||||
---@param bufnr number
|
||||
---@param event string | string[]
|
||||
---@param handler string | function
|
||||
---@param options nil | table<"'once'" | "'nested'", boolean>
|
||||
function autocmd.buf.define(bufnr, event, handler, options)
|
||||
local opts = options or {}
|
||||
|
||||
opts.buffer = bufnr
|
||||
|
||||
if is_type("function", handler) then
|
||||
opts.callback = handler
|
||||
else
|
||||
opts.command = handler
|
||||
end
|
||||
|
||||
autocmd.create(event, opts, bufnr)
|
||||
end
|
||||
|
||||
---@param bufnr number
|
||||
---@param group_name nil | string
|
||||
---@param event nil | string | string[]
|
||||
function autocmd.buf.remove(bufnr, group_name, event)
|
||||
autocmd.delete({
|
||||
buffer = bufnr,
|
||||
event = event,
|
||||
group = group_name,
|
||||
})
|
||||
end
|
||||
|
||||
return autocmd
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
local defaults = require("nui.utils").defaults
|
||||
|
||||
local buf_storage = {
|
||||
_registry = {},
|
||||
}
|
||||
|
||||
---@param storage_name string
|
||||
---@param default_value any
|
||||
---@return table<number, any>
|
||||
function buf_storage.create(storage_name, default_value)
|
||||
local storage = setmetatable({}, {
|
||||
__index = function(tbl, bufnr)
|
||||
rawset(tbl, bufnr, vim.deepcopy(defaults(default_value, {})))
|
||||
|
||||
-- TODO: can `buf_storage.cleanup` be automatically (and reliably) triggered on `BufWipeout`?
|
||||
|
||||
return tbl[bufnr]
|
||||
end,
|
||||
})
|
||||
|
||||
buf_storage._registry[storage_name] = storage
|
||||
|
||||
return storage
|
||||
end
|
||||
|
||||
---@param bufnr number
|
||||
function buf_storage.cleanup(bufnr)
|
||||
for _, storage in pairs(buf_storage._registry) do
|
||||
rawset(storage, bufnr, nil)
|
||||
end
|
||||
end
|
||||
|
||||
return buf_storage
|
||||
387
.config/nvim/pack/tree/start/nui.nvim/lua/nui/utils/init.lua
Normal file
387
.config/nvim/pack/tree/start/nui.nvim/lua/nui/utils/init.lua
Normal file
|
|
@ -0,0 +1,387 @@
|
|||
local ok_nvim_version, nvim_version = pcall(vim.version)
|
||||
if not ok_nvim_version then
|
||||
nvim_version = {}
|
||||
end
|
||||
|
||||
-- internal utils
|
||||
local _ = {
|
||||
feature = {
|
||||
lua_keymap = type(vim.keymap) ~= "nil",
|
||||
lua_autocmd = type(vim.api.nvim_create_autocmd) ~= "nil",
|
||||
v0_10 = nvim_version.minor >= 10,
|
||||
v0_11 = nvim_version.minor >= 11,
|
||||
},
|
||||
}
|
||||
|
||||
local utils = {
|
||||
_ = _,
|
||||
}
|
||||
|
||||
function utils.get_editor_size()
|
||||
return {
|
||||
width = vim.o.columns,
|
||||
height = vim.o.lines,
|
||||
}
|
||||
end
|
||||
|
||||
function utils.get_window_size(winid)
|
||||
winid = winid or 0
|
||||
return {
|
||||
width = vim.api.nvim_win_get_width(winid),
|
||||
height = vim.api.nvim_win_get_height(winid),
|
||||
}
|
||||
end
|
||||
|
||||
function utils.defaults(v, default_value)
|
||||
return type(v) == "nil" and default_value or v
|
||||
end
|
||||
|
||||
-- luacheck: push no max comment line length
|
||||
---@param type_name "'nil'" | "'number'" | "'string'" | "'boolean'" | "'table'" | "'function'" | "'thread'" | "'userdata'" | "'list'" | '"map"'
|
||||
---@return boolean
|
||||
function utils.is_type(type_name, v)
|
||||
-- `vim.tbl_islist` will be removed in the future
|
||||
local islist = vim.islist or vim.tbl_islist
|
||||
if type_name == "list" then
|
||||
return islist(v)
|
||||
end
|
||||
|
||||
if type_name == "map" then
|
||||
return type(v) == "table" and not islist(v)
|
||||
end
|
||||
|
||||
return type(v) == type_name
|
||||
end
|
||||
-- luacheck: pop
|
||||
|
||||
---@param v string | number
|
||||
function utils.parse_number_input(v)
|
||||
local parsed = {}
|
||||
|
||||
parsed.is_percentage = type(v) == "string" and string.sub(v, -1) == "%"
|
||||
|
||||
if parsed.is_percentage then
|
||||
parsed.value = tonumber(string.sub(v, 1, #v - 1)) / 100
|
||||
else
|
||||
parsed.value = tonumber(v)
|
||||
parsed.is_percentage = parsed.value and 0 < parsed.value and parsed.value < 1
|
||||
end
|
||||
|
||||
return parsed
|
||||
end
|
||||
|
||||
---@param prefix? string
|
||||
---@return (fun(): string) get_next_id
|
||||
local function get_id_generator(prefix)
|
||||
prefix = prefix or ""
|
||||
local id = 0
|
||||
return function()
|
||||
id = id + 1
|
||||
return prefix .. id
|
||||
end
|
||||
end
|
||||
|
||||
_.get_next_id = get_id_generator("nui_")
|
||||
|
||||
---@private
|
||||
---@param bufnr number
|
||||
---@param linenr number line number (1-indexed)
|
||||
---@param char_start number start character position (0-indexed)
|
||||
---@param char_end number end character position (0-indexed)
|
||||
---@return number[] byte_range
|
||||
function _.char_to_byte_range(bufnr, linenr, char_start, char_end)
|
||||
local line = vim.api.nvim_buf_get_lines(bufnr, linenr - 1, linenr, false)[1]
|
||||
local skipped_part = vim.fn.strcharpart(line, 0, char_start)
|
||||
local target_part = vim.fn.strcharpart(line, char_start, char_end - char_start)
|
||||
|
||||
local byte_start = vim.fn.strlen(skipped_part)
|
||||
local byte_end = math.min(byte_start + vim.fn.strlen(target_part), vim.fn.strlen(line))
|
||||
return { byte_start, byte_end }
|
||||
end
|
||||
|
||||
---@type integer
|
||||
local fallback_namespace_id = vim.api.nvim_create_namespace("nui.nvim")
|
||||
|
||||
---@private
|
||||
---@param ns_id integer
|
||||
---@return integer
|
||||
function _.ensure_namespace_id(ns_id)
|
||||
return ns_id == -1 and fallback_namespace_id or ns_id
|
||||
end
|
||||
|
||||
---@private
|
||||
---@param ns_id? integer|string
|
||||
---@return integer ns_id namespace id
|
||||
function _.normalize_namespace_id(ns_id)
|
||||
if utils.is_type("string", ns_id) then
|
||||
---@cast ns_id string
|
||||
return vim.api.nvim_create_namespace(ns_id)
|
||||
end
|
||||
---@cast ns_id integer
|
||||
return ns_id or fallback_namespace_id
|
||||
end
|
||||
|
||||
---@private
|
||||
---@param bufnr integer
|
||||
---@param ns_id integer
|
||||
---@param linenr_start? integer (1-indexed)
|
||||
---@param linenr_end? integer (1-indexed,inclusive)
|
||||
function _.clear_namespace(bufnr, ns_id, linenr_start, linenr_end)
|
||||
linenr_start = linenr_start or 1
|
||||
linenr_end = linenr_end and linenr_end + 1 or 0
|
||||
vim.api.nvim_buf_clear_namespace(bufnr, ns_id, linenr_start - 1, linenr_end - 1)
|
||||
end
|
||||
|
||||
-- luacov: disable
|
||||
local nvim_buf_set_option = vim.api.nvim_buf_set_option
|
||||
---@param bufnr integer
|
||||
---@param name string
|
||||
---@param value any
|
||||
local function set_buf_option(bufnr, name, value)
|
||||
nvim_buf_set_option(bufnr, name, value)
|
||||
end
|
||||
|
||||
local nvim_win_set_option = vim.api.nvim_win_set_option
|
||||
---@param winid integer
|
||||
---@param name string
|
||||
---@param value any
|
||||
local function set_win_option(winid, name, value)
|
||||
nvim_win_set_option(winid, name, value)
|
||||
end
|
||||
-- luacov: enable
|
||||
|
||||
if _.feature.v0_10 then
|
||||
function set_buf_option(bufnr, name, value)
|
||||
vim.api.nvim_set_option_value(name, value, { buf = bufnr })
|
||||
end
|
||||
|
||||
function set_win_option(winid, name, value)
|
||||
vim.api.nvim_set_option_value(name, value, { win = winid, scope = "local" })
|
||||
end
|
||||
end
|
||||
|
||||
_.set_buf_option = set_buf_option
|
||||
_.set_win_option = set_win_option
|
||||
|
||||
---@private
|
||||
---@param bufnr number
|
||||
---@param buf_options table<string, any>
|
||||
function _.set_buf_options(bufnr, buf_options)
|
||||
for name, value in pairs(buf_options) do
|
||||
set_buf_option(bufnr, name, value)
|
||||
end
|
||||
end
|
||||
|
||||
---@private
|
||||
---@param winid number
|
||||
---@param win_options table<string, any>
|
||||
function _.set_win_options(winid, win_options)
|
||||
for name, value in pairs(win_options) do
|
||||
set_win_option(winid, name, value)
|
||||
end
|
||||
end
|
||||
|
||||
---@private
|
||||
---@param dimension number | string
|
||||
---@param container_dimension number
|
||||
---@return nil | number
|
||||
function _.normalize_dimension(dimension, container_dimension)
|
||||
local number = utils.parse_number_input(dimension)
|
||||
|
||||
if not number.value then
|
||||
return nil
|
||||
end
|
||||
|
||||
if number.is_percentage then
|
||||
return math.floor(container_dimension * number.value)
|
||||
end
|
||||
|
||||
return number.value
|
||||
end
|
||||
|
||||
local strchars, strcharpart, strdisplaywidth = vim.fn.strchars, vim.fn.strcharpart, vim.fn.strdisplaywidth
|
||||
|
||||
---@param text string
|
||||
---@param max_length number
|
||||
---@return string
|
||||
function _.truncate_text(text, max_length)
|
||||
if strdisplaywidth(text) <= max_length then
|
||||
return text
|
||||
end
|
||||
|
||||
local low, high = 0, strchars(text)
|
||||
local mid
|
||||
|
||||
while low < high do
|
||||
mid = math.floor((low + high + 1) / 2)
|
||||
if strdisplaywidth(strcharpart(text, 0, mid)) < max_length then
|
||||
low = mid
|
||||
else
|
||||
high = mid - 1
|
||||
end
|
||||
end
|
||||
|
||||
return strcharpart(text, 0, low) .. "…"
|
||||
end
|
||||
|
||||
---@param text NuiText
|
||||
---@param max_width number
|
||||
function _.truncate_nui_text(text, max_width)
|
||||
text:set(_.truncate_text(text:content(), max_width))
|
||||
end
|
||||
|
||||
---@param line NuiLine
|
||||
---@param max_width number
|
||||
function _.truncate_nui_line(line, max_width)
|
||||
local width = line:width()
|
||||
local last_part_idx = #line._texts
|
||||
|
||||
while width > max_width do
|
||||
local extra_width = width - max_width
|
||||
local last_part = line._texts[last_part_idx]
|
||||
|
||||
if last_part:width() <= extra_width then
|
||||
width = width - last_part:width()
|
||||
line._texts[last_part_idx] = nil
|
||||
last_part_idx = last_part_idx - 1
|
||||
|
||||
-- need to add truncate indicator in previous part
|
||||
if last_part:width() == extra_width then
|
||||
last_part = line._texts[last_part_idx]
|
||||
last_part:set(_.truncate_text(last_part:content() .. " ", last_part:width()))
|
||||
end
|
||||
else
|
||||
last_part:set(_.truncate_text(last_part:content(), last_part:width() - extra_width))
|
||||
width = width - extra_width
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---@param align "'left'" | "'center'" | "'right'"
|
||||
---@param total_width number
|
||||
---@param text_width number
|
||||
---@return number left_gap_width, number right_gap_width
|
||||
function _.calculate_gap_width(align, total_width, text_width)
|
||||
local gap_width = total_width - text_width
|
||||
if align == "left" then
|
||||
return 0, gap_width
|
||||
elseif align == "center" then
|
||||
return math.floor(gap_width / 2), math.ceil(gap_width / 2)
|
||||
elseif align == "right" then
|
||||
return gap_width, 0
|
||||
end
|
||||
|
||||
error("invalid value align=" .. align)
|
||||
end
|
||||
|
||||
---@param lines (string|NuiLine)[]
|
||||
---@param bufnr number
|
||||
---@param ns_id number
|
||||
---@param linenr_start integer (1-indexed)
|
||||
---@param linenr_end? integer (1-indexed,inclusive)
|
||||
---@param byte_start? integer (0-indexed)
|
||||
---@param byte_end? integer (0-indexed,exclusive)
|
||||
function _.render_lines(lines, bufnr, ns_id, linenr_start, linenr_end, byte_start, byte_end)
|
||||
local row_start = linenr_start - 1
|
||||
local row_end = linenr_end or row_start + 1
|
||||
|
||||
local content = vim.tbl_map(function(line)
|
||||
if type(line) == "string" then
|
||||
return line
|
||||
end
|
||||
return line:content()
|
||||
end, lines)
|
||||
|
||||
if byte_start then
|
||||
local col_start = byte_start
|
||||
local col_end = byte_end or #vim.api.nvim_buf_get_lines(bufnr, row_start, row_end, false)[1]
|
||||
vim.api.nvim_buf_set_text(bufnr, row_start, col_start, row_end - 1, col_end, content)
|
||||
else
|
||||
vim.api.nvim_buf_set_lines(bufnr, row_start, row_end, false, content)
|
||||
end
|
||||
|
||||
for linenr, line in ipairs(lines) do
|
||||
if type(line) ~= "string" then
|
||||
line:highlight(bufnr, ns_id, linenr + row_start, byte_start)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---@param bufnr integer
|
||||
---@param linenr_start integer (1-indexed)
|
||||
---@param linenr_end integer (1-indexed,inclusive)
|
||||
function _.clear_lines(bufnr, linenr_start, linenr_end)
|
||||
local count = linenr_end - linenr_start + 1
|
||||
if count < 1 then
|
||||
return
|
||||
end
|
||||
|
||||
local lines = {}
|
||||
for i = 1, count do
|
||||
lines[i] = ""
|
||||
end
|
||||
|
||||
vim.api.nvim_buf_set_lines(bufnr, linenr_start - 1, linenr_end, false, lines)
|
||||
end
|
||||
|
||||
function _.normalize_layout_options(options)
|
||||
if utils.is_type("string", options.relative) then
|
||||
options.relative = {
|
||||
type = options.relative,
|
||||
}
|
||||
end
|
||||
|
||||
if options.position and not utils.is_type("table", options.position) then
|
||||
options.position = {
|
||||
row = options.position,
|
||||
col = options.position,
|
||||
}
|
||||
end
|
||||
|
||||
if options.size and not utils.is_type("table", options.size) then
|
||||
options.size = {
|
||||
width = options.size,
|
||||
height = options.size,
|
||||
}
|
||||
end
|
||||
|
||||
return options
|
||||
end
|
||||
|
||||
---@param winhighlight string
|
||||
---@return table<string, string> highlight_map
|
||||
function _.parse_winhighlight(winhighlight)
|
||||
local highlight = {}
|
||||
local parts = vim.split(winhighlight, ",", { plain = true, trimempty = true })
|
||||
for _, part in ipairs(parts) do
|
||||
local key, value = part:match("(.+):(.+)")
|
||||
highlight[key] = value
|
||||
end
|
||||
return highlight
|
||||
end
|
||||
|
||||
---@param highlight_map table<string, string>
|
||||
---@return string winhighlight
|
||||
function _.serialize_winhighlight(highlight_map)
|
||||
local parts = vim.tbl_map(function(key)
|
||||
return key .. ":" .. highlight_map[key]
|
||||
end, vim.tbl_keys(highlight_map))
|
||||
table.sort(parts)
|
||||
return table.concat(parts, ",")
|
||||
end
|
||||
|
||||
function _.get_default_winborder()
|
||||
return "none"
|
||||
end
|
||||
|
||||
if _.feature.v0_11 then
|
||||
function _.get_default_winborder()
|
||||
local style = vim.api.nvim_get_option_value("winborder", {})
|
||||
if style == "" then
|
||||
return "none"
|
||||
end
|
||||
return style
|
||||
end
|
||||
end
|
||||
|
||||
return utils
|
||||
154
.config/nvim/pack/tree/start/nui.nvim/lua/nui/utils/keymap.lua
Normal file
154
.config/nvim/pack/tree/start/nui.nvim/lua/nui/utils/keymap.lua
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
local buf_storage = require("nui.utils.buf_storage")
|
||||
local is_type = require("nui.utils").is_type
|
||||
local feature = require("nui.utils")._.feature
|
||||
|
||||
local keymap = {
|
||||
storage = buf_storage.create("nui.utils.keymap", { _next_handler_id = 1, keys = {}, handlers = {} }),
|
||||
}
|
||||
|
||||
---@param mode string
|
||||
---@param key string
|
||||
---@return string key_id
|
||||
local function get_key_id(mode, key)
|
||||
return string.format("%s---%s", mode, vim.api.nvim_replace_termcodes(key, true, true, true))
|
||||
end
|
||||
|
||||
---@param bufnr number
|
||||
---@param key_id string
|
||||
---@return integer|nil handler_id
|
||||
local function get_handler_id(bufnr, key_id)
|
||||
return keymap.storage[bufnr].keys[key_id]
|
||||
end
|
||||
|
||||
---@param bufnr number
|
||||
---@param key_id string
|
||||
---@return integer handler_id
|
||||
local function next_handler_id(bufnr, key_id)
|
||||
local handler_id = keymap.storage[bufnr]._next_handler_id
|
||||
keymap.storage[bufnr].keys[key_id] = handler_id
|
||||
keymap.storage[bufnr]._next_handler_id = handler_id + 1
|
||||
return handler_id
|
||||
end
|
||||
|
||||
---@param bufnr number
|
||||
---@param mode string
|
||||
---@param key string
|
||||
---@param handler string|fun(): nil
|
||||
---@return { rhs: string, callback?: fun(): nil }|nil
|
||||
local function get_keymap_info(bufnr, mode, key, handler, overwrite)
|
||||
local key_id = get_key_id(mode, key)
|
||||
|
||||
-- luacov: disable
|
||||
if get_handler_id(bufnr, key_id) and not overwrite then
|
||||
return nil
|
||||
end
|
||||
-- luacov: enable
|
||||
|
||||
local handler_id = next_handler_id(bufnr, key_id)
|
||||
|
||||
local rhs, callback = "", nil
|
||||
|
||||
if type(handler) == "function" then
|
||||
if feature.lua_keymap then
|
||||
callback = handler
|
||||
else
|
||||
keymap.storage[bufnr].handlers[handler_id] = handler
|
||||
rhs = string.format("<cmd>lua require('nui.utils.keymap').execute(%s, %s)<CR>", bufnr, handler_id)
|
||||
end
|
||||
else
|
||||
rhs = handler
|
||||
end
|
||||
|
||||
return {
|
||||
rhs = rhs,
|
||||
callback = callback,
|
||||
}
|
||||
end
|
||||
|
||||
---@param bufnr number
|
||||
---@param handler_id number
|
||||
function keymap.execute(bufnr, handler_id)
|
||||
local handler = keymap.storage[bufnr].handlers[handler_id]
|
||||
if is_type("function", handler) then
|
||||
handler(bufnr)
|
||||
end
|
||||
end
|
||||
|
||||
---@param bufnr number
|
||||
---@param mode string
|
||||
---@param lhs string|string[]
|
||||
---@param handler string|fun(): nil
|
||||
---@param opts? table<"'expr'"|"'noremap'"|"'nowait'"|"'remap'"|"'script'"|"'silent'"|"'unique'", boolean>
|
||||
---@return nil
|
||||
function keymap.set(bufnr, mode, lhs, handler, opts, force)
|
||||
if feature.lua_keymap and not is_type("boolean", force) then
|
||||
force = true
|
||||
end
|
||||
|
||||
local keys = lhs
|
||||
if type(lhs) ~= "table" then
|
||||
keys = { lhs }
|
||||
end
|
||||
---@cast keys -string
|
||||
|
||||
opts = opts or {}
|
||||
|
||||
if not is_type("nil", opts.remap) then
|
||||
opts.noremap = not opts.remap
|
||||
opts.remap = nil
|
||||
end
|
||||
|
||||
for _, key in ipairs(keys) do
|
||||
local keymap_info = get_keymap_info(bufnr, mode, key, handler, force)
|
||||
-- luacov: disable
|
||||
if not keymap_info then
|
||||
return false
|
||||
end
|
||||
-- luacov: enable
|
||||
|
||||
local options = vim.deepcopy(opts)
|
||||
options.callback = keymap_info.callback
|
||||
|
||||
vim.api.nvim_buf_set_keymap(bufnr, mode, key, keymap_info.rhs, options)
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
---@param bufnr number
|
||||
---@param mode string
|
||||
---@param lhs string|string[]
|
||||
---@return nil
|
||||
function keymap._del(bufnr, mode, lhs, force)
|
||||
if feature.lua_keymap and not is_type("boolean", force) then
|
||||
force = true
|
||||
end
|
||||
|
||||
local keys = lhs
|
||||
if type(lhs) ~= "table" then
|
||||
keys = { lhs }
|
||||
end
|
||||
---@cast keys -string
|
||||
|
||||
for _, key in ipairs(keys) do
|
||||
local key_id = get_key_id(mode, key)
|
||||
|
||||
local handler_id = get_handler_id(bufnr, key_id)
|
||||
|
||||
-- luacov: disable
|
||||
if not handler_id and not force then
|
||||
return false
|
||||
---@cast handler_id -nil
|
||||
end
|
||||
-- luacov: enable
|
||||
|
||||
keymap.storage[bufnr].keys[key_id] = nil
|
||||
keymap.storage[bufnr].handlers[handler_id] = nil
|
||||
|
||||
vim.api.nvim_buf_del_keymap(bufnr, mode, key)
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
return keymap
|
||||
Loading…
Add table
Add a link
Reference in a new issue