Files
hop.nvim/lua/hop/hint.lua
mohsen 31e0e42e62 refactor!: fix lint errors (#17)
* refactor!: fix lint errors
update deprecated api calls

* refactor!: update minimum nvim version to 9.0
2023-06-22 10:27:28 +00:00

169 lines
3.9 KiB
Lua

local perm = require('hop.perm')
local prio = require('hop.priority')
---@class Hint
---@field label? string
---@field jump_target JumpTarget
---@class HintState
---@field buf_list number[]
---@field all_ctxs Context
---@field hints Hint[]
---@field hl_ns number
---@field dim_ns number
---@field diag_ns table
---@field cursorline boolean
local M = {}
---@enum HintDirection
M.HintDirection = {
BEFORE_CURSOR = 1,
AFTER_CURSOR = 2,
}
---@enum HintPosition
M.HintPosition = {
BEGIN = 1,
MIDDLE = 2,
END = 3,
}
---@enum HintType
M.HintType = {
OVERLAY = 'overlay',
INLINE = 'inline',
}
---@param label table
---@return string
local function tbl_to_str(label)
local s = ''
for i = 1, #label do
s = s .. label[i]
end
return s
end
-- Reduce a hint.
-- This function will remove hints not starting with the input key and will reduce the other ones
-- with one level.
---@param label string
---@param key string
---@return string?
local function reduce_label(label, key)
local snd_idx = vim.fn.byteidx(label, 1)
if label:sub(1, snd_idx) == key then
label = label:sub(snd_idx + 1)
end
if label == '' then
return nil
end
return label
end
-- Reduce all hints and return the one fully reduced, if any.
---@param hints Hint[]
---@param key string
---@return Hint?,Hint[]
function M.reduce_hints(hints, key)
local next_hints = {}
for _, h in pairs(hints) do
local prev_label = h.label
h.label = reduce_label(h.label, key)
if h.label == nil then
return h, {}
elseif h.label ~= prev_label then
next_hints[#next_hints + 1] = h
end
end
return nil, next_hints
end
-- Create hints from jump targets.
--
-- This function associates jump targets with permutations, creating hints. A hint is then a jump target along with a
-- label.
--
-- If `indirect_jump_targets` is `nil`, `jump_targets` is assumed already ordered with all jump target with the same
-- score (0)
---@param jump_targets JumpTarget[]
---@param indirect_jump_targets IndirectJumpTarget[]
---@param opts Options
---@return Hint[]
function M.create_hints(jump_targets, indirect_jump_targets, opts)
---@type Hint[]
local hints = {}
local perms = perm.permutations(opts.keys, #jump_targets, opts)
-- get or generate indirect_jump_targets
if indirect_jump_targets == nil then
indirect_jump_targets = {}
for i = 1, #jump_targets do
indirect_jump_targets[i] = { index = i, score = 0 }
end
end
for i, indirect in pairs(indirect_jump_targets) do
hints[indirect.index] = {
label = tbl_to_str(perms[i]),
jump_target = jump_targets[indirect.index],
}
end
return hints
end
-- Create the extmarks for per-line hints.
---@param hl_ns number
---@param hints Hint[]
---@param opts Options
function M.set_hint_extmarks(hl_ns, hints, opts)
for _, hint in pairs(hints) do
local label = hint.label
if opts.uppercase_labels and label ~= nil then
label = label:upper()
end
local col = hint.jump_target.column - 1
local virt_text = { { label, 'HopNextKey' } }
-- get the byte index of the second hint so that we can slice it correctly
if label ~= nil and vim.fn.strdisplaywidth(label) ~= 1 then
local snd_idx = vim.fn.byteidx(label, 1)
virt_text = { { label:sub(1, snd_idx), 'HopNextKey1' }, { label:sub(snd_idx + 1), 'HopNextKey2' } }
end
vim.api.nvim_buf_set_extmark(hint.jump_target.buffer or 0, hl_ns, hint.jump_target.line, col, {
virt_text = virt_text,
virt_text_pos = opts.hint_type,
hl_mode = 'combine',
priority = prio.HINT_PRIO,
})
end
end
---@param hl_ns number
---@param jump_targets JumpTarget[]
function M.set_hint_preview(hl_ns, jump_targets)
for _, jt in ipairs(jump_targets) do
vim.api.nvim_buf_set_extmark(jt.buffer, hl_ns, jt.line, jt.column - 1, {
end_row = jt.line,
end_col = jt.column - 1 + jt.length,
hl_group = 'HopPreview',
hl_eol = true,
priority = prio.HINT_PRIO,
})
end
end
return M