feat: Better highlight-hover/follow-cursor procedures
Previously on each outline open, the `writer.make_outline` function might be called at least 4 times(!), after this refactor it will only be called once. And on update cursor autocmds, also called once (previously at least twice). behaviour: - Now the outline window focus and highlight can update on each cursor move (previously CursorHold, dependent on updatetime). This is now configurable as well. - During fold-all/unfold-all operations, now the cursor will remain on the same node (rather than same line in outline buffer). - The performance improvement is not significantly observable since even the old implementation can appear instant. One may even argue I am fixing a problem that did not exist, but implementation-wise it's just so much better now. config: - outline_window.auto_update_events, list of events to be passed to create_user_autocmd for updating cursor focus in outline, and updating outline items (refetching symbols), using keys cursor and items respectively. - outline_window.show_cursorline now supports 2 other string values: 'focus_in_outline'/'focus_in_code' which controls when to enable cursorline. Setting to true retains the default behaviour of always showing the cursorline. This was added because now that the cursor focus on the outline could change on each CursorMoved, the cursorline may pose to be qute attention-seeking during the outline cursor updates. Hence `focus_in_outline` is added so that when focus is in code, the cursorline for outline window is not shown. 'focus_in_code' is added so that a user who disabled highlight_hovered_item can keep track of position in outline when focus is in code, disabling cursorline when focus is in outline. At any given time, if hide cursor is enabled and show_cursorline is a string value, hiding of cursor will not be done if cursorline is not shown in the the given situation. implementation: - The reason for the improvement in performance as described in the first paragraph is due to merging of finding hover item and finding the deepest matched node to put cursor, into writer.make_outline. This done, when previously done in separate function, because after the separate function (namely _highlight_hovered_item) finishes, writer.make_outline is called *again* anyway. - Autocmds to update cursor position in outline is now done per buffer rather than global. Somehow the auto unfold and unfold depth options still work perfectly, for this we should thank simrat or which ever contributor that modularized the folding module and made it adaptable :)
This commit is contained in:
@@ -31,11 +31,16 @@ M.defaults = {
|
|||||||
auto_jump = false,
|
auto_jump = false,
|
||||||
show_numbers = false,
|
show_numbers = false,
|
||||||
show_relative_numbers = false,
|
show_relative_numbers = false,
|
||||||
|
---@type boolean?|string?
|
||||||
show_cursorline = true,
|
show_cursorline = true,
|
||||||
hide_cursor = false,
|
hide_cursor = false,
|
||||||
winhl = 'OutlineDetails:Comment,OutlineLineno:LineNr',
|
winhl = 'OutlineDetails:Comment,OutlineLineno:LineNr',
|
||||||
jump_highlight_duration = 500,
|
jump_highlight_duration = 400,
|
||||||
center_on_jump = true,
|
center_on_jump = true,
|
||||||
|
auto_update_events = {
|
||||||
|
cursor = { 'CursorMoved' },
|
||||||
|
items = { 'InsertLeave', 'WinEnter', 'BufEnter', 'BufWinEnter', 'TabEnter', 'BufWritePost' },
|
||||||
|
},
|
||||||
},
|
},
|
||||||
preview_window = {
|
preview_window = {
|
||||||
auto_preview = false,
|
auto_preview = false,
|
||||||
|
|||||||
@@ -10,27 +10,12 @@ local writer = require('outline.writer')
|
|||||||
local M = {}
|
local M = {}
|
||||||
|
|
||||||
local function setup_global_autocmd()
|
local function setup_global_autocmd()
|
||||||
if cfg.o.outline_items.highlight_hovered_item or cfg.o.symbol_folding.auto_unfold_hover then
|
if utils.table_has_content(cfg.o.outline_window.auto_update_events.items) then
|
||||||
vim.api.nvim_create_autocmd('CursorHold', {
|
vim.api.nvim_create_autocmd(cfg.o.outline_window.auto_update_events.items, {
|
||||||
pattern = '*',
|
pattern = '*',
|
||||||
callback = function()
|
callback = M._refresh,
|
||||||
M._highlight_current_item(nil)
|
|
||||||
end,
|
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
vim.api.nvim_create_autocmd({
|
|
||||||
'InsertLeave',
|
|
||||||
'WinEnter',
|
|
||||||
'BufEnter',
|
|
||||||
'BufWinEnter',
|
|
||||||
'TabEnter',
|
|
||||||
'BufWritePost',
|
|
||||||
}, {
|
|
||||||
pattern = '*',
|
|
||||||
callback = M._refresh,
|
|
||||||
})
|
|
||||||
|
|
||||||
vim.api.nvim_create_autocmd('WinEnter', {
|
vim.api.nvim_create_autocmd('WinEnter', {
|
||||||
pattern = '*',
|
pattern = '*',
|
||||||
callback = require('outline.preview').close,
|
callback = require('outline.preview').close,
|
||||||
@@ -41,11 +26,13 @@ end
|
|||||||
-- STATE
|
-- STATE
|
||||||
-------------------------
|
-------------------------
|
||||||
M.state = {
|
M.state = {
|
||||||
|
opened_first_outline = false,
|
||||||
---@type outline.SymbolNode[]
|
---@type outline.SymbolNode[]
|
||||||
outline_items = {},
|
outline_items = {},
|
||||||
---@type outline.FlatSymbolNode[]
|
---@type outline.FlatSymbolNode[]
|
||||||
flattened_outline_items = {},
|
flattened_outline_items = {},
|
||||||
code_win = 0,
|
code_win = 0,
|
||||||
|
autocmds = {},
|
||||||
-- In case unhide_cursor was called before hide_cursor for _some_ reason,
|
-- In case unhide_cursor was called before hide_cursor for _some_ reason,
|
||||||
-- this can still be used as a fallback
|
-- this can still be used as a fallback
|
||||||
original_cursor = vim.o.guicursor,
|
original_cursor = vim.o.guicursor,
|
||||||
@@ -56,13 +43,18 @@ local function wipe_state()
|
|||||||
outline_items = {},
|
outline_items = {},
|
||||||
flattened_outline_items = {},
|
flattened_outline_items = {},
|
||||||
code_win = 0,
|
code_win = 0,
|
||||||
|
autocmds = {},
|
||||||
opts = {},
|
opts = {},
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
local function _update_lines()
|
local function _update_lines(update_cursor, set_cursor_to_node)
|
||||||
M.state.flattened_outline_items =
|
local current
|
||||||
writer.make_outline(M.view.bufnr, M.state.outline_items, M.state.code_win)
|
M.state.flattened_outline_items, current =
|
||||||
|
writer.make_outline(M.view.bufnr, M.state.outline_items, M.state.code_win, set_cursor_to_node)
|
||||||
|
if update_cursor ~= false then
|
||||||
|
M.update_cursor_pos(current)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
---@param items outline.SymbolNode[]
|
---@param items outline.SymbolNode[]
|
||||||
@@ -78,7 +70,29 @@ local function __refresh()
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
M.state.code_win = vim.api.nvim_get_current_win()
|
local curwin = vim.api.nvim_get_current_win()
|
||||||
|
|
||||||
|
if M.state.codewin ~= curwin then
|
||||||
|
if M.state.autocmds[M.state.codewin] then
|
||||||
|
vim.api.nvim_del_autocmd(M.state.autocmds[M.state.codewin])
|
||||||
|
end
|
||||||
|
M.state.codewin = curwin
|
||||||
|
end
|
||||||
|
|
||||||
|
if cfg.o.outline_items.highlight_hovered_item or cfg.o.symbol_folding.auto_unfold_hover then
|
||||||
|
if M.state.autocmds[M.state.code_win] then
|
||||||
|
vim.api.nvim_del_autocmd(M.state.autocmds[M.state.code_win])
|
||||||
|
end
|
||||||
|
if utils.str_or_nonempty_table(cfg.o.outline_window.auto_update_events.cursor) then
|
||||||
|
M.state.autocmds[M.state.code_win] = vim.api.nvim_create_autocmd(
|
||||||
|
cfg.o.outline_window.auto_update_events.cursor,
|
||||||
|
{
|
||||||
|
buffer = vim.api.nvim_win_get_buf(M.state.code_win),
|
||||||
|
callback = function() M._highlight_current_item(nil) end
|
||||||
|
}
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
local items = parser.parse(response, vim.api.nvim_get_current_buf())
|
local items = parser.parse(response, vim.api.nvim_get_current_buf())
|
||||||
_merge_items(items)
|
_merge_items(items)
|
||||||
@@ -156,19 +170,37 @@ function M._toggle_fold(move_cursor, node_index)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function hide_cursor()
|
local function update_cursor_style()
|
||||||
|
local cl = cfg.o.outline_window.show_cursorline
|
||||||
|
-- XXX: Still 'hide' cursor if show_cursorline set to false, because we've
|
||||||
|
-- already warned the user during setup.
|
||||||
|
local hide_cursor = type(cl) ~= 'string'
|
||||||
|
|
||||||
|
if cl == 'focus_in_outline' or cl == 'focus_in_code' then
|
||||||
|
vim.api.nvim_win_set_option(0, "cursorline", cl == 'focus_in_outline')
|
||||||
|
hide_cursor = cl == 'focus_in_outline'
|
||||||
|
end
|
||||||
|
|
||||||
-- Set cursor color to CursorLine in normal mode
|
-- Set cursor color to CursorLine in normal mode
|
||||||
M.state.original_cursor = vim.o.guicursor
|
if hide_cursor then
|
||||||
local cur = vim.o.guicursor:match('n.-:(.-)[-,]')
|
M.state.original_cursor = vim.o.guicursor
|
||||||
vim.opt.guicursor:append('n:' .. cur .. '-Cursorline')
|
local cur = vim.o.guicursor:match('n.-:(.-)[-,]')
|
||||||
|
vim.opt.guicursor:append('n:' .. cur .. '-Cursorline')
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function unhide_cursor()
|
local function reset_cursor_style()
|
||||||
|
local cl = cfg.o.outline_window.show_cursorline
|
||||||
|
|
||||||
|
if cl == 'focus_in_outline' or cl == 'focus_in_code' then
|
||||||
|
vim.api.nvim_win_set_option(0, "cursorline", cl ~= 'focus_in_outline')
|
||||||
|
end
|
||||||
-- vim.opt doesn't seem to provide a way to remove last item, like a pop()
|
-- vim.opt doesn't seem to provide a way to remove last item, like a pop()
|
||||||
-- vim.o.guicursor = vim.o.guicursor:gsub(",n.-:.-$", "")
|
-- vim.o.guicursor = vim.o.guicursor:gsub(",n.-:.-$", "")
|
||||||
vim.o.guicursor = M.state.original_cursor
|
vim.o.guicursor = M.state.original_cursor
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---Autocmds for the (current) outline buffer
|
||||||
local function setup_buffer_autocmd()
|
local function setup_buffer_autocmd()
|
||||||
if cfg.o.preview_window.auto_preview then
|
if cfg.o.preview_window.auto_preview then
|
||||||
vim.api.nvim_create_autocmd('CursorMoved', {
|
vim.api.nvim_create_autocmd('CursorMoved', {
|
||||||
@@ -190,17 +222,17 @@ local function setup_buffer_autocmd()
|
|||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
if cfg.o.outline_window.hide_cursor then
|
if cfg.o.outline_window.hide_cursor or type(cfg.o.outline_window.show_cursorline) == 'string' then
|
||||||
-- Unfortunately guicursor is a global option, so we have to make sure to
|
-- Unfortunately guicursor is a global option, so we have to make sure to
|
||||||
-- set and unset when cursor leaves the outline window.
|
-- set and unset when cursor leaves the outline window.
|
||||||
hide_cursor()
|
update_cursor_style()
|
||||||
vim.api.nvim_create_autocmd('BufEnter', {
|
vim.api.nvim_create_autocmd('BufEnter', {
|
||||||
buffer = 0,
|
buffer = 0,
|
||||||
callback = hide_cursor,
|
callback = update_cursor_style,
|
||||||
})
|
})
|
||||||
vim.api.nvim_create_autocmd('BufLeave', {
|
vim.api.nvim_create_autocmd('BufLeave', {
|
||||||
buffer = 0,
|
buffer = 0,
|
||||||
callback = unhide_cursor,
|
callback = reset_cursor_style,
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -219,7 +251,7 @@ function M._set_folded(folded, move_cursor, node_index)
|
|||||||
vim.api.nvim_win_set_cursor(M.view.winnr, { node_index, 0 })
|
vim.api.nvim_win_set_cursor(M.view.winnr, { node_index, 0 })
|
||||||
end
|
end
|
||||||
|
|
||||||
_update_lines()
|
_update_lines(false)
|
||||||
elseif node.parent then
|
elseif node.parent then
|
||||||
local parent_node = M.state.flattened_outline_items[node.parent.line_in_outline]
|
local parent_node = M.state.flattened_outline_items[node.parent.line_in_outline]
|
||||||
|
|
||||||
@@ -248,6 +280,7 @@ end
|
|||||||
---@param nodes? outline.SymbolNode[]
|
---@param nodes? outline.SymbolNode[]
|
||||||
function M._set_all_folded(folded, nodes)
|
function M._set_all_folded(folded, nodes)
|
||||||
local stack = { nodes or M.state.outline_items }
|
local stack = { nodes or M.state.outline_items }
|
||||||
|
local current = M._current_node()
|
||||||
|
|
||||||
while #stack > 0 do
|
while #stack > 0 do
|
||||||
local current_nodes = table.remove(stack, #stack)
|
local current_nodes = table.remove(stack, #stack)
|
||||||
@@ -259,7 +292,7 @@ function M._set_all_folded(folded, nodes)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
_update_lines()
|
_update_lines(true, current)
|
||||||
end
|
end
|
||||||
|
|
||||||
---@param winnr? integer Window number of code window
|
---@param winnr? integer Window number of code window
|
||||||
@@ -290,59 +323,9 @@ function M._highlight_current_item(winnr)
|
|||||||
-- parents folded)
|
-- parents folded)
|
||||||
-- In one go
|
-- In one go
|
||||||
|
|
||||||
local win = winnr or vim.api.nvim_get_current_win()
|
-- XXX: Could current win ~= M.state.codewin here?
|
||||||
local buf = vim.api.nvim_win_get_buf(win)
|
|
||||||
|
|
||||||
local hovered_line = vim.api.nvim_win_get_cursor(win)[1] - 1
|
_update_lines(true)
|
||||||
local parent_nodes = {}
|
|
||||||
|
|
||||||
-- Must not skip folded nodes so that when user unfolds a parent, they can see the leaf
|
|
||||||
-- node highlighted.
|
|
||||||
for value in
|
|
||||||
parser.preorder_iter(M.state.outline_items, function()
|
|
||||||
return true
|
|
||||||
end)
|
|
||||||
do
|
|
||||||
value.hovered = nil
|
|
||||||
|
|
||||||
if
|
|
||||||
value.line == hovered_line
|
|
||||||
or (hovered_line >= value.range_start and hovered_line <= value.range_end)
|
|
||||||
then
|
|
||||||
value.hovered = true
|
|
||||||
table.insert(parent_nodes, value)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if #parent_nodes == 0 then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Probably can't 'just' writer.add_hover_highlights here because we might
|
|
||||||
-- want to auto_unfold_hover
|
|
||||||
_update_lines()
|
|
||||||
|
|
||||||
-- Put cursor on deepest visible match
|
|
||||||
local col = 0
|
|
||||||
if cfg.o.outline_items.show_symbol_lineno then
|
|
||||||
-- Padding area between lineno column and start of guides
|
|
||||||
col = #tostring(vim.api.nvim_buf_line_count(buf) - 1)
|
|
||||||
end
|
|
||||||
local flats = M.state.flattened_outline_items
|
|
||||||
local found = false
|
|
||||||
local find_node
|
|
||||||
|
|
||||||
while #parent_nodes > 0 and not found do
|
|
||||||
find_node = table.remove(parent_nodes, #parent_nodes)
|
|
||||||
-- TODO: Is it feasible to use binary search here?
|
|
||||||
for line, node in ipairs(flats) do
|
|
||||||
if node == find_node then
|
|
||||||
vim.api.nvim_win_set_cursor(M.view.winnr, { line, col })
|
|
||||||
found = true
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local function setup_keymaps(bufnr)
|
local function setup_keymaps(bufnr)
|
||||||
@@ -409,6 +392,19 @@ local function setup_keymaps(bufnr)
|
|||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@param current outline.FlatSymbolNode?
|
||||||
|
function M.update_cursor_pos(current)
|
||||||
|
local col = 0
|
||||||
|
local buf = vim.api.nvim_win_get_buf(M.state.code_win)
|
||||||
|
if cfg.o.outline_items.show_symbol_lineno then
|
||||||
|
-- Padding area between lineno column and start of guides
|
||||||
|
col = #tostring(vim.api.nvim_buf_line_count(buf) - 1)
|
||||||
|
end
|
||||||
|
if current then -- Don't attempt to set cursor if the matching node is not found
|
||||||
|
vim.api.nvim_win_set_cursor(M.view.winnr, { current.line_in_outline, col })
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
---@param response table?
|
---@param response table?
|
||||||
---@param opts outline.OutlineOpts?
|
---@param opts outline.OutlineOpts?
|
||||||
local function handler(response, opts)
|
local function handler(response, opts)
|
||||||
@@ -417,6 +413,7 @@ local function handler(response, opts)
|
|||||||
end
|
end
|
||||||
|
|
||||||
M.state.code_win = vim.api.nvim_get_current_win()
|
M.state.code_win = vim.api.nvim_get_current_win()
|
||||||
|
M.state.opened_first_outline = true
|
||||||
|
|
||||||
if opts and opts.on_symbols then
|
if opts and opts.on_symbols then
|
||||||
opts.on_symbols()
|
opts.on_symbols()
|
||||||
@@ -428,6 +425,21 @@ local function handler(response, opts)
|
|||||||
opts.on_outline_setup()
|
opts.on_outline_setup()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if cfg.o.outline_items.highlight_hovered_item or cfg.o.symbol_folding.auto_unfold_hover then
|
||||||
|
if M.state.autocmds[M.state.code_win] then
|
||||||
|
vim.api.nvim_del_autocmd(M.state.autocmds[M.state.code_win])
|
||||||
|
end
|
||||||
|
if utils.str_or_nonempty_table(cfg.o.outline_window.auto_update_events.cursor) then
|
||||||
|
M.state.autocmds[M.state.code_win] = vim.api.nvim_create_autocmd(
|
||||||
|
cfg.o.outline_window.auto_update_events.cursor,
|
||||||
|
{
|
||||||
|
buffer = vim.api.nvim_win_get_buf(M.state.code_win),
|
||||||
|
callback = function() M._highlight_current_item(nil) end
|
||||||
|
}
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
-- clear state when buffer is closed
|
-- clear state when buffer is closed
|
||||||
vim.api.nvim_buf_attach(M.view.bufnr, false, {
|
vim.api.nvim_buf_attach(M.view.bufnr, false, {
|
||||||
on_detach = function(_, _)
|
on_detach = function(_, _)
|
||||||
@@ -441,9 +453,10 @@ local function handler(response, opts)
|
|||||||
local items = parser.parse(response, vim.api.nvim_win_get_buf(M.state.code_win))
|
local items = parser.parse(response, vim.api.nvim_win_get_buf(M.state.code_win))
|
||||||
|
|
||||||
M.state.outline_items = items
|
M.state.outline_items = items
|
||||||
M.state.flattened_outline_items = writer.make_outline(M.view.bufnr, items, M.state.code_win)
|
local current
|
||||||
|
M.state.flattened_outline_items, current = writer.make_outline(M.view.bufnr, items, M.state.code_win)
|
||||||
|
|
||||||
M._highlight_current_item(M.state.code_win)
|
M.update_cursor_pos(current)
|
||||||
|
|
||||||
if not cfg.o.outline_window.focus_on_open or (opts and not opts.focus_outline) then
|
if not cfg.o.outline_window.focus_on_open or (opts and not opts.focus_outline) then
|
||||||
vim.fn.win_gotoid(M.state.code_win)
|
vim.fn.win_gotoid(M.state.code_win)
|
||||||
@@ -667,6 +680,10 @@ With bang, don't switch cursor focus to outline window.",
|
|||||||
nargs = 0,
|
nargs = 0,
|
||||||
bang = true,
|
bang = true,
|
||||||
})
|
})
|
||||||
|
cmd('Refresh', __refresh, {
|
||||||
|
desc = "Trigger manual outline refresh of items.",
|
||||||
|
nargs = 0,
|
||||||
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
---Set up configuration options for outline.
|
---Set up configuration options for outline.
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ local function get_width_offset()
|
|||||||
width = width + 4
|
width = width + 4
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- FIXME: use actual window position based on view rather than config
|
||||||
if cfg.o.outline_window.position == 'right' then
|
if cfg.o.outline_window.position == 'right' then
|
||||||
width = 0 - width
|
width = 0 - width
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ function M.flash_highlight(winnr, lnum, durationMs, hl_group)
|
|||||||
end
|
end
|
||||||
hl_group = hl_group or 'Visual'
|
hl_group = hl_group or 'Visual'
|
||||||
if durationMs == true or durationMs == 1 then
|
if durationMs == true or durationMs == 1 then
|
||||||
durationMs = 500
|
durationMs = 400
|
||||||
end
|
end
|
||||||
local bufnr = vim.api.nvim_win_get_buf(winnr)
|
local bufnr = vim.api.nvim_win_get_buf(winnr)
|
||||||
local ns = vim.api.nvim_buf_add_highlight(bufnr, 0, hl_group, lnum - 1, 0, -1)
|
local ns = vim.api.nvim_buf_add_highlight(bufnr, 0, hl_group, lnum - 1, 0, -1)
|
||||||
@@ -137,4 +137,14 @@ function M.echo(module, message)
|
|||||||
vim.api.nvim_echo({ prefix_chunk, { message } }, true, {})
|
vim.api.nvim_echo({ prefix_chunk, { message } }, true, {})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@param t table
|
||||||
|
function M.table_has_content(t)
|
||||||
|
return t and next(t) ~= nil
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param t table|string
|
||||||
|
function M.str_or_nonempty_table(t)
|
||||||
|
return type(t) == 'string' or M.table_has_content(t)
|
||||||
|
end
|
||||||
|
|
||||||
return M
|
return M
|
||||||
|
|||||||
@@ -52,7 +52,8 @@ function View:setup_view()
|
|||||||
vim.api.nvim_win_set_option(self.winnr, 'rnu', true)
|
vim.api.nvim_win_set_option(self.winnr, 'rnu', true)
|
||||||
end
|
end
|
||||||
|
|
||||||
if cfg.o.outline_window.show_cursorline then
|
local cl = cfg.o.outline_window.show_cursorline
|
||||||
|
if cl == true or cl == 'focus_in_outline' then
|
||||||
vim.api.nvim_win_set_option(self.winnr, 'cursorline', true)
|
vim.api.nvim_win_set_option(self.winnr, 'cursorline', true)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -66,13 +66,18 @@ end
|
|||||||
-- Handles highlights, virtual text, and of course lines of outline to write
|
-- Handles highlights, virtual text, and of course lines of outline to write
|
||||||
---@param bufnr integer Nothing is done if is_buffer_outline(bufnr) is not true
|
---@param bufnr integer Nothing is done if is_buffer_outline(bufnr) is not true
|
||||||
---@param items outline.SymbolNode[] Tree of symbols after being parsed by parser.parse_result
|
---@param items outline.SymbolNode[] Tree of symbols after being parsed by parser.parse_result
|
||||||
---@return outline.FlatSymbolNode[] flattened_items Empty table returned if bufnr is invalid
|
|
||||||
---@param codewin integer code window
|
---@param codewin integer code window
|
||||||
function M.make_outline(bufnr, items, codewin)
|
---@param find_node outline.FlatSymbolNode|outline.SymbolNode? Find a given node rather than node matching cursor position in codewin
|
||||||
|
---@return outline.FlatSymbolNode[],outline.FlatSymbolNode? flattened_items Empty table returned if bufnr is invalid
|
||||||
|
function M.make_outline(bufnr, items, codewin, find_node)
|
||||||
if not M.is_buffer_outline(bufnr) then
|
if not M.is_buffer_outline(bufnr) then
|
||||||
return {}
|
return {}, nil
|
||||||
end
|
end
|
||||||
local codebuf = vim.api.nvim_win_get_buf(codewin)
|
local codebuf = vim.api.nvim_win_get_buf(codewin)
|
||||||
|
-- 0-indexed
|
||||||
|
local hovered_line = vim.api.nvim_win_get_cursor(codewin)[1] - 1
|
||||||
|
-- Deepest matching node to put cursor on based on hovered line
|
||||||
|
local put_cursor
|
||||||
|
|
||||||
clear_virt_text(bufnr)
|
clear_virt_text(bufnr)
|
||||||
|
|
||||||
@@ -131,6 +136,22 @@ function M.make_outline(bufnr, items, codewin)
|
|||||||
local fold_markers = cfg.o.symbol_folding.markers
|
local fold_markers = cfg.o.symbol_folding.markers
|
||||||
|
|
||||||
for node in parser.preorder_iter(items) do
|
for node in parser.preorder_iter(items) do
|
||||||
|
node.hovered = false
|
||||||
|
if
|
||||||
|
node.line == hovered_line
|
||||||
|
or (hovered_line >= node.range_start and hovered_line <= node.range_end)
|
||||||
|
then
|
||||||
|
-- XXX: not setting for children, but it works because when unfold is called
|
||||||
|
-- this function is called again anyway.
|
||||||
|
node.hovered = true
|
||||||
|
if not find_node then
|
||||||
|
put_cursor = node
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if find_node and find_node == node then
|
||||||
|
put_cursor = find_node
|
||||||
|
end
|
||||||
|
|
||||||
table.insert(flattened, node)
|
table.insert(flattened, node)
|
||||||
node.line_in_outline = #flattened
|
node.line_in_outline = #flattened
|
||||||
table.insert(details, node.detail or '')
|
table.insert(details, node.detail or '')
|
||||||
@@ -249,7 +270,7 @@ function M.make_outline(bufnr, items, codewin)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return flattened
|
return flattened, put_cursor
|
||||||
end
|
end
|
||||||
-- XXX: Is the performance tradeoff of calling `nvim_buf_set_lines` on each
|
-- XXX: Is the performance tradeoff of calling `nvim_buf_set_lines` on each
|
||||||
-- iteration worth it in order to put setting of highlights, details, and
|
-- iteration worth it in order to put setting of highlights, details, and
|
||||||
|
|||||||
Reference in New Issue
Block a user