refactor(writer): Move make_outline to sidebar
Was passing self fields a lot, decided to just do all that in Sidebar in the first place. Also resolved guides.enabled=false early to setting markers to ' '. Everything should work the same.
This commit is contained in:
@@ -284,6 +284,12 @@ function M.resolve_config()
|
|||||||
M.o.guides.enabled = false
|
M.o.guides.enabled = false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
if not M.o.guides.enabled then
|
||||||
|
M.o.guides = {
|
||||||
|
enabled = true,
|
||||||
|
markers = { middle = ' ', vertical = ' ', bottom = ' ' }
|
||||||
|
}
|
||||||
|
end
|
||||||
----- SPLIT COMMAND -----
|
----- SPLIT COMMAND -----
|
||||||
local sc = M.o.outline_window.split_command
|
local sc = M.o.outline_window.split_command
|
||||||
if sc then
|
if sc then
|
||||||
|
|||||||
@@ -5,6 +5,10 @@ local parser = require('outline.parser')
|
|||||||
local providers = require('outline.providers.init')
|
local providers = require('outline.providers.init')
|
||||||
local utils = require('outline.utils.init')
|
local utils = require('outline.utils.init')
|
||||||
local writer = require('outline.writer')
|
local writer = require('outline.writer')
|
||||||
|
local symbols = require('outline.symbols')
|
||||||
|
local t_utils = require('outline.utils.table')
|
||||||
|
|
||||||
|
local strlen = vim.fn.strlen
|
||||||
|
|
||||||
---@class outline.Sidebar
|
---@class outline.Sidebar
|
||||||
local Sidebar = {}
|
local Sidebar = {}
|
||||||
@@ -95,10 +99,7 @@ function Sidebar:initial_handler(response, opts)
|
|||||||
local items = parser.parse(response, self.code.buf)
|
local items = parser.parse(response, self.code.buf)
|
||||||
self.items = items
|
self.items = items
|
||||||
|
|
||||||
local current
|
self:_update_lines(true)
|
||||||
self.flats, current, self.hovered = writer.make_outline(self.view.bufnr, items, self.code.win)
|
|
||||||
|
|
||||||
self:update_cursor_pos(current)
|
|
||||||
|
|
||||||
if not cfg.o.outline_window.focus_on_open or not opts.focus_outline then
|
if not cfg.o.outline_window.focus_on_open or not opts.focus_outline then
|
||||||
vim.fn.win_gotoid(self.code.win)
|
vim.fn.win_gotoid(self.code.win)
|
||||||
@@ -262,9 +263,7 @@ end
|
|||||||
---@param update_cursor boolean?
|
---@param update_cursor boolean?
|
||||||
---@param set_cursor_to_node outline.SymbolNode|outline.FlatSymbolNode?
|
---@param set_cursor_to_node outline.SymbolNode|outline.FlatSymbolNode?
|
||||||
function Sidebar:_update_lines(update_cursor, set_cursor_to_node)
|
function Sidebar:_update_lines(update_cursor, set_cursor_to_node)
|
||||||
local current
|
local current = self:write_outline(set_cursor_to_node)
|
||||||
self.flats, current, self.hovered =
|
|
||||||
writer.make_outline(self.view.bufnr, self.items, self.code.win, set_cursor_to_node)
|
|
||||||
if update_cursor ~= false then
|
if update_cursor ~= false then
|
||||||
self:update_cursor_pos(current)
|
self:update_cursor_pos(current)
|
||||||
end
|
end
|
||||||
@@ -601,4 +600,187 @@ function Sidebar:_highlight_current_item(winnr, update_cursor)
|
|||||||
self:_update_lines(update_cursor)
|
self:_update_lines(update_cursor)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---The quintessential function of this entire plugin. Clears virtual text,
|
||||||
|
-- parses each node and replaces old lines with new lines to be written for the
|
||||||
|
-- outline buffer.
|
||||||
|
--
|
||||||
|
-- Handles highlights, virtual text, and of course lines of outline to write.
|
||||||
|
---@note Ensure new outlines are already set to `self.items` before calling this function. `self.flats` will be overwritten and current line is obtained from `win_get_cursor` using `self.code.win`.
|
||||||
|
---@param find_node outline.FlatSymbolNode|outline.SymbolNode? Find a given node rather than node matching cursor position in codewin
|
||||||
|
---@return outline.FlatSymbolNode? set_cursor_to_this_node
|
||||||
|
function Sidebar:write_outline(find_node)
|
||||||
|
-- 0-indexed
|
||||||
|
local hovered_line = vim.api.nvim_win_get_cursor(self.code.win)[1] - 1
|
||||||
|
-- Deepest matching node to put cursor on based on hovered line
|
||||||
|
local put_cursor ---@type outline.FlatSymbolNode
|
||||||
|
|
||||||
|
self.flats = {}
|
||||||
|
local line_count = 0
|
||||||
|
|
||||||
|
local lines = {} ---@type string[]
|
||||||
|
local details = {} ---@type string[]
|
||||||
|
local linenos = {} ---@type string[]
|
||||||
|
local hl = {}
|
||||||
|
|
||||||
|
-- Find the prefix for each line needed for the lineno space
|
||||||
|
local lineno_offset = 0
|
||||||
|
local lineno_prefix = ''
|
||||||
|
local lineno_max_width = #tostring(vim.api.nvim_buf_line_count(self.code.buf) - 1)
|
||||||
|
if cfg.o.outline_items.show_symbol_lineno then
|
||||||
|
-- Use max width-1 plus 1 space padding.
|
||||||
|
-- -1 because if max_width is a power of ten, don't shift the entire lineno
|
||||||
|
-- column by the right just because the last line number requires an extra
|
||||||
|
-- digit. If max_width is 1000, the lineno column will take up 3 columns to
|
||||||
|
-- fill the digits, and 1 padding on the right. The 1000 can fit perfectly
|
||||||
|
-- there.
|
||||||
|
lineno_offset = math.max(2, lineno_max_width) + 1
|
||||||
|
lineno_prefix = string.rep(' ', lineno_offset)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Closures for convenience
|
||||||
|
local function add_guide_hl(from, to)
|
||||||
|
table.insert(hl, {
|
||||||
|
line_count,
|
||||||
|
from,
|
||||||
|
to,
|
||||||
|
'OutlineGuides',
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
local function add_fold_hl(from, to)
|
||||||
|
table.insert(hl, {
|
||||||
|
line_count,
|
||||||
|
from,
|
||||||
|
to,
|
||||||
|
'OutlineFoldMarker',
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
local guide_markers = cfg.o.guides.markers
|
||||||
|
local fold_markers = cfg.o.symbol_folding.markers
|
||||||
|
|
||||||
|
for node in parser.preorder_iter(self.items) do
|
||||||
|
line_count = line_count + 1
|
||||||
|
node.line_in_outline = line_count
|
||||||
|
table.insert(self.flats, node)
|
||||||
|
|
||||||
|
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
|
||||||
|
table.insert(self.hovered, node)
|
||||||
|
if not find_node then
|
||||||
|
put_cursor = node
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if find_node and find_node == node then
|
||||||
|
---@diagnostic disable-next-line: cast-local-type
|
||||||
|
put_cursor = find_node
|
||||||
|
end
|
||||||
|
|
||||||
|
table.insert(details, node.detail or '')
|
||||||
|
local lineno = tostring(node.range_start + 1)
|
||||||
|
local leftpad = string.rep(' ', lineno_max_width - #lineno)
|
||||||
|
table.insert(linenos, leftpad .. lineno)
|
||||||
|
|
||||||
|
-- Make the guides for the line prefix
|
||||||
|
local pref = t_utils.str_to_table(string.rep(' ', node.depth))
|
||||||
|
local fold_marker_width = 0
|
||||||
|
|
||||||
|
if folding.is_foldable(node) then
|
||||||
|
-- Add fold marker
|
||||||
|
local marker = fold_markers[2]
|
||||||
|
if folding.is_folded(node) then
|
||||||
|
marker = fold_markers[1]
|
||||||
|
end
|
||||||
|
pref[#pref] = marker
|
||||||
|
fold_marker_width = strlen(marker)
|
||||||
|
else
|
||||||
|
-- Rightmost guide for the direct parent, only added if fold marker is
|
||||||
|
-- not added
|
||||||
|
if node.depth > 1 then
|
||||||
|
local marker = guide_markers.middle
|
||||||
|
if node.isLast then
|
||||||
|
marker = guide_markers.bottom
|
||||||
|
end
|
||||||
|
pref[#pref] = marker
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Add vertical guides to the left, for all parents that isn't the last
|
||||||
|
-- sibling. Iter from first grandparent until second last ancestor (last
|
||||||
|
-- ancestor is the entire outline itself, it should not have a vertical
|
||||||
|
-- guide).
|
||||||
|
local iternode = node
|
||||||
|
for i = node.depth - 1, 2, -1 do
|
||||||
|
iternode = iternode.parent_node
|
||||||
|
if not iternode.isLast then
|
||||||
|
pref[i] = guide_markers.vertical
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Finished with guide prefix
|
||||||
|
-- Join all prefix chars by a space
|
||||||
|
local pref_str = table.concat(pref, ' ')
|
||||||
|
local total_pref_len = lineno_offset + #pref_str
|
||||||
|
|
||||||
|
-- Guide hl goes from start of prefix till before the fold marker, if any.
|
||||||
|
-- Fold hl goes from start of fold marker until before the icon.
|
||||||
|
add_guide_hl(lineno_offset, total_pref_len - fold_marker_width)
|
||||||
|
if fold_marker_width > 0 then
|
||||||
|
add_fold_hl(total_pref_len - fold_marker_width, total_pref_len + 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
local line = lineno_prefix .. pref_str
|
||||||
|
local icon_pref = 0
|
||||||
|
if node.icon ~= '' then
|
||||||
|
line = line .. ' ' .. node.icon
|
||||||
|
icon_pref = 1
|
||||||
|
end
|
||||||
|
line = line .. ' ' .. node.name
|
||||||
|
|
||||||
|
-- Highlight for the icon ✨
|
||||||
|
-- Start from icon col
|
||||||
|
local hl_start = #pref_str + #lineno_prefix + icon_pref
|
||||||
|
local hl_end = hl_start + #node.icon -- until after icon
|
||||||
|
local hl_type = cfg.o.symbols.icons[symbols.kinds[node.kind]].hl
|
||||||
|
table.insert(hl, { line_count, hl_start, hl_end, hl_type })
|
||||||
|
|
||||||
|
-- Prefix length is from start until the beginning of the node.name, used
|
||||||
|
-- for hover highlights.
|
||||||
|
node.prefix_length = hl_end + 1
|
||||||
|
|
||||||
|
-- lines passed to nvim_buf_set_lines cannot contain newlines in each line
|
||||||
|
line = line:gsub('\n', ' ')
|
||||||
|
table.insert(lines, line)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Render
|
||||||
|
|
||||||
|
writer.clear_virt_text(self.view.bufnr)
|
||||||
|
writer.clear_icon_hl(self.view.bufnr)
|
||||||
|
|
||||||
|
vim.api.nvim_buf_set_option(self.view.bufnr, 'modifiable', true)
|
||||||
|
vim.api.nvim_buf_set_lines(self.view.bufnr, 0, -1, false, lines)
|
||||||
|
vim.api.nvim_buf_set_option(self.view.bufnr, 'modifiable', false)
|
||||||
|
|
||||||
|
-- Unfortunately highlights and extmarks cannot be added to lines that do not
|
||||||
|
-- yet exist. Hence these require another O(n) of iteration.
|
||||||
|
writer.add_highlights(self.view.bufnr, hl, self.flats)
|
||||||
|
|
||||||
|
if cfg.o.outline_items.show_symbol_details then
|
||||||
|
writer.add_details(self.view.bufnr, details)
|
||||||
|
end
|
||||||
|
|
||||||
|
if cfg.o.outline_items.show_symbol_lineno then
|
||||||
|
writer.add_linenos(self.view.bufnr, linenos)
|
||||||
|
end
|
||||||
|
|
||||||
|
return put_cursor
|
||||||
|
end
|
||||||
|
|
||||||
return Sidebar
|
return Sidebar
|
||||||
|
|||||||
@@ -1,11 +1,5 @@
|
|||||||
local cfg = require('outline.config')
|
local cfg = require('outline.config')
|
||||||
local folding = require('outline.folding')
|
|
||||||
local highlight = require('outline.highlight')
|
local highlight = require('outline.highlight')
|
||||||
local parser = require('outline.parser')
|
|
||||||
local symbols = require('outline.symbols')
|
|
||||||
local t_utils = require('outline.utils.table')
|
|
||||||
|
|
||||||
local strlen = vim.fn.strlen
|
|
||||||
|
|
||||||
local M = {}
|
local M = {}
|
||||||
|
|
||||||
@@ -34,13 +28,18 @@ function M.add_highlights(bufnr, hl_info, nodes)
|
|||||||
M.add_hover_highlights(bufnr, nodes)
|
M.add_hover_highlights(bufnr, nodes)
|
||||||
end
|
end
|
||||||
|
|
||||||
---@param bufnr integer
|
---@param bufnr integer Outline buffer
|
||||||
local function clear_virt_text(bufnr)
|
function M.clear_icon_hl(bufnr)
|
||||||
|
vim.api.nvim_buf_clear_namespace(bufnr, hlns, 0, -1)
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param bufnr integer Outline buffer
|
||||||
|
function M.clear_virt_text(bufnr)
|
||||||
vim.api.nvim_buf_clear_namespace(bufnr, vtns, 0, -1)
|
vim.api.nvim_buf_clear_namespace(bufnr, vtns, 0, -1)
|
||||||
end
|
end
|
||||||
|
|
||||||
---@param bufnr integer
|
---@param bufnr integer Outline buffer
|
||||||
---@param nodes outline.FlatSymbolNode[] flattened nodes
|
---@param nodes outline.FlatSymbolNode[]
|
||||||
function M.add_hover_highlights(bufnr, nodes)
|
function M.add_hover_highlights(bufnr, nodes)
|
||||||
if not cfg.o.outline_items.highlight_hovered_item then
|
if not cfg.o.outline_items.highlight_hovered_item then
|
||||||
return
|
return
|
||||||
@@ -49,243 +48,42 @@ function M.add_hover_highlights(bufnr, nodes)
|
|||||||
-- clear old highlight
|
-- clear old highlight
|
||||||
highlight.clear_hover_highlight(bufnr)
|
highlight.clear_hover_highlight(bufnr)
|
||||||
for _, node in ipairs(nodes) do
|
for _, node in ipairs(nodes) do
|
||||||
if not node.hovered then
|
if node.hovered then
|
||||||
goto continue
|
|
||||||
end
|
|
||||||
|
|
||||||
if node.prefix_length then
|
|
||||||
highlight.add_hover_highlight(bufnr, node.line_in_outline - 1, node.prefix_length)
|
highlight.add_hover_highlight(bufnr, node.line_in_outline - 1, node.prefix_length)
|
||||||
end
|
end
|
||||||
::continue::
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
---The quintessential function of this entire plugin. Clears virtual text,
|
---@param bufnr integer Outline buffer
|
||||||
-- parses each node and replaces old lines with new lines to be written for the
|
---@param details string[]
|
||||||
-- outline buffer.
|
function M.add_details(bufnr, details)
|
||||||
-- Handles highlights, virtual text, and of course lines of outline to write
|
for index, value in ipairs(details) do
|
||||||
---@param bufnr integer Nothing is done if is_buffer_outline(bufnr) is not true
|
vim.api.nvim_buf_set_extmark(bufnr, vtns, index - 1, -1, {
|
||||||
---@param items outline.SymbolNode[] Tree of symbols after being parsed by parser.parse_result
|
virt_text = { { value, 'OutlineDetails' } },
|
||||||
---@param codewin integer code window
|
virt_text_pos = 'eol',
|
||||||
---@param find_node outline.FlatSymbolNode|outline.SymbolNode? Find a given node rather than node matching cursor position in codewin
|
hl_mode = 'combine',
|
||||||
---@return outline.FlatSymbolNode[],outline.FlatSymbolNode?,outline.FlatSymbolNode[]? flattened_items Empty table returned if bufnr is invalid
|
})
|
||||||
function M.make_outline(bufnr, items, codewin, find_node)
|
end
|
||||||
if not M.is_buffer_outline(bufnr) then
|
end
|
||||||
return {}, nil, {}
|
|
||||||
end
|
---@param bufnr integer Outline buffer
|
||||||
local codebuf = vim.api.nvim_win_get_buf(codewin)
|
---@param linenos string[] Must already be padded
|
||||||
-- 0-indexed
|
function M.add_linenos(bufnr, linenos)
|
||||||
local hovered_line = vim.api.nvim_win_get_cursor(codewin)[1] - 1
|
-- TODO: Fix lineno not appearing if text in line is truncated on the right
|
||||||
-- Deepest matching node to put cursor on based on hovered line
|
-- due to narrow window, after nvim fixes virt_text_hide.
|
||||||
local put_cursor
|
for index, value in ipairs(linenos) do
|
||||||
local hover_list = {}
|
vim.api.nvim_buf_set_extmark(bufnr, vtns, index - 1, -1, {
|
||||||
|
virt_text = { { value, 'OutlineLineno' } },
|
||||||
clear_virt_text(bufnr)
|
virt_text_pos = 'overlay',
|
||||||
|
virt_text_win_col = 0,
|
||||||
---@type string[]
|
-- When hide_cursor + cursorline enabled, we want the lineno to also
|
||||||
local lines = {}
|
-- take on the cursorline background so wherever the cursor is, it
|
||||||
---@type string[]
|
-- appears blended. We want 'replace' even for `hide_cursor=false
|
||||||
local details = {}
|
-- cursorline=true` because vim's native line numbers do not get
|
||||||
---@type string[]
|
-- highlighted by cursorline.
|
||||||
local linenos = {}
|
hl_mode = (cfg.o.outline_window.hide_cursor and 'combine') or 'replace',
|
||||||
---@type outline.FlatSymbolNode[]
|
|
||||||
local flattened = {}
|
|
||||||
local hl = {}
|
|
||||||
|
|
||||||
-- Find the prefix for each line needed for the lineno space
|
|
||||||
local lineno_offset = 0
|
|
||||||
local lineno_prefix = ''
|
|
||||||
local lineno_max_width = #tostring(vim.api.nvim_buf_line_count(codebuf) - 1)
|
|
||||||
if cfg.o.outline_items.show_symbol_lineno then
|
|
||||||
-- Use max width-1 plus 1 space padding.
|
|
||||||
-- -1 because if max_width is a power of ten, don't shift the entire lineno
|
|
||||||
-- column by the right just because the last line number requires an extra
|
|
||||||
-- digit. If max_width is 1000, the lineno column will take up 3 columns to
|
|
||||||
-- fill the digits, and 1 padding on the right. The 1000 can fit perfectly
|
|
||||||
-- there.
|
|
||||||
lineno_offset = math.max(2, lineno_max_width) + 1
|
|
||||||
lineno_prefix = string.rep(' ', lineno_offset)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Closures for convenience
|
|
||||||
local function add_guide_hl(from, to)
|
|
||||||
table.insert(hl, {
|
|
||||||
#flattened,
|
|
||||||
from,
|
|
||||||
to,
|
|
||||||
'OutlineGuides',
|
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
local function add_fold_hl(from, to)
|
|
||||||
table.insert(hl, {
|
|
||||||
#flattened,
|
|
||||||
from,
|
|
||||||
to,
|
|
||||||
'OutlineFoldMarker',
|
|
||||||
})
|
|
||||||
end
|
|
||||||
|
|
||||||
local guide_markers = cfg.o.guides.markers
|
|
||||||
if not cfg.o.guides.enabled then
|
|
||||||
guide_markers = {
|
|
||||||
middle = ' ',
|
|
||||||
vertical = ' ',
|
|
||||||
bottom = ' ',
|
|
||||||
}
|
|
||||||
end
|
|
||||||
local fold_markers = cfg.o.symbol_folding.markers
|
|
||||||
|
|
||||||
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
|
|
||||||
table.insert(hover_list, node)
|
|
||||||
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)
|
|
||||||
node.line_in_outline = #flattened
|
|
||||||
table.insert(details, node.detail or '')
|
|
||||||
local lineno = tostring(node.range_start + 1)
|
|
||||||
local leftpad = string.rep(' ', lineno_max_width - #lineno)
|
|
||||||
table.insert(linenos, leftpad .. lineno)
|
|
||||||
|
|
||||||
-- Make the guides for the line prefix
|
|
||||||
local pref = t_utils.str_to_table(string.rep(' ', node.depth))
|
|
||||||
local fold_marker_width = 0
|
|
||||||
|
|
||||||
if folding.is_foldable(node) then
|
|
||||||
-- Add fold marker
|
|
||||||
local marker = fold_markers[2]
|
|
||||||
if folding.is_folded(node) then
|
|
||||||
marker = fold_markers[1]
|
|
||||||
end
|
|
||||||
pref[#pref] = marker
|
|
||||||
fold_marker_width = strlen(marker)
|
|
||||||
else
|
|
||||||
-- Rightmost guide for the immediate parent, only added if fold marker is
|
|
||||||
-- not added
|
|
||||||
if node.depth > 1 then
|
|
||||||
local marker = guide_markers.middle
|
|
||||||
if node.isLast then
|
|
||||||
marker = guide_markers.bottom
|
|
||||||
end
|
|
||||||
pref[#pref] = marker
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Add vertical guides to the left, for all parents that isn't the last
|
|
||||||
-- sibling. Iter from first grandparent until second last ancestor (last
|
|
||||||
-- ancestor is the entire outline itself, it should not have a vertical
|
|
||||||
-- guide).
|
|
||||||
local iternode = node
|
|
||||||
for i = node.depth - 1, 2, -1 do
|
|
||||||
iternode = iternode.parent_node
|
|
||||||
if not iternode.isLast then
|
|
||||||
pref[i] = guide_markers.vertical
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Finished with guide prefix
|
|
||||||
-- Join all prefix chars by a space
|
|
||||||
local pref_str = table.concat(pref, ' ')
|
|
||||||
local total_pref_len = lineno_offset + #pref_str
|
|
||||||
|
|
||||||
-- Guide hl goes from start of prefix till before the fold marker, if any.
|
|
||||||
-- Fold hl goes from start of fold marker until before the icon.
|
|
||||||
add_guide_hl(lineno_offset, total_pref_len - fold_marker_width)
|
|
||||||
if fold_marker_width > 0 then
|
|
||||||
add_fold_hl(total_pref_len - fold_marker_width, total_pref_len + 1)
|
|
||||||
end
|
|
||||||
|
|
||||||
local line = lineno_prefix .. pref_str
|
|
||||||
local icon_pref = 0
|
|
||||||
if node.icon ~= '' then
|
|
||||||
line = line .. ' ' .. node.icon
|
|
||||||
icon_pref = 1
|
|
||||||
end
|
|
||||||
line = line .. ' ' .. node.name
|
|
||||||
|
|
||||||
-- Highlight for the icon ✨
|
|
||||||
-- Start from icon col
|
|
||||||
local hl_start = #pref_str + #lineno_prefix + icon_pref
|
|
||||||
local hl_end = hl_start + #node.icon -- until after icon
|
|
||||||
local hl_type = cfg.o.symbols.icons[symbols.kinds[node.kind]].hl
|
|
||||||
table.insert(hl, { #flattened, hl_start, hl_end, hl_type })
|
|
||||||
|
|
||||||
-- Prefix length is from start until the beginning of the node.name, used
|
|
||||||
-- for hover highlights.
|
|
||||||
node.prefix_length = hl_end + 1
|
|
||||||
|
|
||||||
-- lines passed to nvim_buf_set_lines cannot contain newlines in each line
|
|
||||||
line = line:gsub('\n', ' ')
|
|
||||||
table.insert(lines, line)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Write the lines 🎉
|
|
||||||
vim.api.nvim_buf_set_option(bufnr, 'modifiable', true)
|
|
||||||
vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, lines)
|
|
||||||
vim.api.nvim_buf_set_option(bufnr, 'modifiable', false)
|
|
||||||
|
|
||||||
-- Unfortunately highlights and extmarks cannot be added to lines that do not
|
|
||||||
-- yet exist. Hence this requires another O(n) of iteration.
|
|
||||||
M.add_highlights(bufnr, hl, flattened)
|
|
||||||
|
|
||||||
-- Add details and lineno virtual text.
|
|
||||||
if cfg.o.outline_items.show_symbol_details then
|
|
||||||
for index, value in ipairs(details) do
|
|
||||||
vim.api.nvim_buf_set_extmark(bufnr, vtns, index - 1, -1, {
|
|
||||||
virt_text = { { value, 'OutlineDetails' } },
|
|
||||||
virt_text_pos = 'eol',
|
|
||||||
hl_mode = 'combine',
|
|
||||||
})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if cfg.o.outline_items.show_symbol_lineno then
|
|
||||||
-- Line numbers are left padded, right aligned, positioned at the leftmost
|
|
||||||
-- column
|
|
||||||
-- TODO: Fix lineno not appearing if text in line is truncated on the right
|
|
||||||
-- due to narrow window, after nvim fixes virt_text_hide.
|
|
||||||
for index, value in ipairs(linenos) do
|
|
||||||
vim.api.nvim_buf_set_extmark(bufnr, vtns, index - 1, -1, {
|
|
||||||
virt_text = { { value, 'OutlineLineno' } },
|
|
||||||
virt_text_pos = 'overlay',
|
|
||||||
virt_text_win_col = 0,
|
|
||||||
-- When hide_cursor + cursorline enabled, we want the lineno to also
|
|
||||||
-- take on the cursorline background so wherever the cursor is, it
|
|
||||||
-- appears blended. We want 'replace' even for `hide_cursor=false
|
|
||||||
-- cursorline=true` because vim's native line numbers do not get
|
|
||||||
-- highlighted by cursorline.
|
|
||||||
hl_mode = (cfg.o.outline_window.hide_cursor and 'combine') or 'replace',
|
|
||||||
})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return flattened, put_cursor, hover_list
|
|
||||||
end
|
end
|
||||||
-- 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
|
|
||||||
-- linenos together with each line?
|
|
||||||
-- That is,
|
|
||||||
-- 1. { call nvim_buf_set_lines once for all lines }
|
|
||||||
-- + { O(n) for each of highlights, details, and linenos }
|
|
||||||
--OR
|
|
||||||
-- 2. { call nvim_buf_set_lines for each line }
|
|
||||||
-- + { O(1) for each of highlight/detail/lineno the same iteration }
|
|
||||||
-- It appears that for highlight/detail/lineno, the number of calls to nvim API
|
|
||||||
-- is the same, only 3 extra tables in memory for (1). Where as for (2) you
|
|
||||||
-- have to call nvim_buf_set_lines n times (each line) rather than add lines
|
|
||||||
-- all at once, saving only the need of 1 extra table (lines table) in memory.
|
|
||||||
|
|
||||||
return M
|
return M
|
||||||
|
|||||||
Reference in New Issue
Block a user