Skip to content

Commit 57dd360

Browse files
author
Bassam Data
committed
feat(selecta): add highlight for current line and prefix as well, see
1 parent 678a3e0 commit 57dd360

File tree

6 files changed

+101
-20
lines changed

6 files changed

+101
-20
lines changed

lua/namu/core/symbol_utils.lua

+2
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,8 @@ function M.show_picker(selectaItems, state, config, ui, selecta, title, notify_o
224224
auto_select = config.auto_select,
225225
initially_hidden = config.initially_hidden,
226226
movement = vim.tbl_deep_extend("force", config.movement, {}),
227+
current_highlight = vim.tbl_deep_extend("force", config.current_highlight, {}),
228+
-- current_highlight = vim.tbl_deep_extend("force", config.current_highlight, {}),
227229
row_position = config.row_position,
228230
debug = config.debug,
229231
pre_filter = function(items, query)

lua/namu/namu_symbols/config.lua

+7-1
Original file line numberDiff line numberDiff line change
@@ -94,9 +94,15 @@ M.defaults = {
9494
Operator = "󰆕",
9595
TypeParameter = "󰊄",
9696
},
97+
current_highlight = {
98+
enabled = false, -- Enable custom selection highlight
99+
hl_group = "CursorLine", -- Default highlight group (could also create a custom one)
100+
-- Please keep space after the icon for better viewing
101+
prefix_icon = "", --icon for current selection, some other example ▎ 󰇙 ┆
102+
},
97103
preview = {
98104
highlight_on_move = true, -- Whether to highlight symbols as you move through them
99-
-- TODO: still needs implmenting, keep it always now
105+
-- TODO: still needs implementing, keep it always now
100106
highlight_mode = "always", -- "always" | "select" (only highlight when selecting)
101107
},
102108
icon = "󱠦", -- 󱠦 -  -  -- 󰚟

lua/namu/namu_symbols/helpers.lua

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
local M = {}
2-
local request_symbols = require("namu.namu_symbols").request_symbols
2+
local request_symbols = require("namu.namu_symbols.lsp").request_symbols
33
local filter_symbol_types = require("namu.namu_symbols").config.filter_symbol_types
44

55
-- Shared constants and utilities

lua/namu/namu_symbols/types.lua

+6
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@
3535
---@field close_on_yank boolean Whether to close picker after yanking text
3636
---@field close_on_delete boolean Whether to close picker after deleting text
3737

38+
---@class CurrentHighlightConfig
39+
---@field enabled boolean Enable custom selection highlight
40+
---@field hl_group string Highlight group for the selection
41+
---@field prefix_icon string Icon to show before the selected item
42+
3843
---@class NamuConfig
3944
---@field AllowKinds table<string, string[]> Symbol kinds to include
4045
---@field display table<string, string|number> Display configuration
@@ -58,6 +63,7 @@
5863
---@field filter_symbol_types NamuSymbolTypes Configuration for symbol type filtering
5964
---@field actions NamuActionConfig Configuration for picker actions
6065
---@field max_items number|nil
66+
---@field current_highlight CurrentHighlightConfig Configuration for selection highlighting
6167

6268
---@class NamuState
6369
---@field original_win number|nil Original window

lua/namu/selecta/selecta.lua

+84-18
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,11 @@ M.config = {
181181
mode = "icon",
182182
padding = 1,
183183
},
184+
current_highlight = {
185+
enabled = false, -- Enable custom selection highlight
186+
hl_group = "CursorLine", -- Default highlight group (could also create a custom one)
187+
prefix_icon = "", --▎ ▎󰇙┆Vertical bar icon for current selection
188+
},
184189
offset = 0,
185190
debug = false,
186191
preserve_order = false, -- Default to false unless the other module handle it
@@ -229,6 +234,7 @@ end
229234
M.clear_log = logger.clear_log
230235

231236
local ns_id = vim.api.nvim_create_namespace("selecta_highlights")
237+
local current_selection_ns = vim.api.nvim_create_namespace("selecta_current_selection")
232238

233239
---Thanks to folke and mini.nvim for this utlity of hiding the cursor
234240
---Hide the cursor by setting guicursor and caching the original value
@@ -259,22 +265,21 @@ local function restore_cursor()
259265
end
260266
end
261267

262-
local highlights = {
263-
SelectaPrefix = { link = "Special" },
264-
SelectaMatch = { link = "Identifier" }, -- or maybe DiagnosticFloatingOk
265-
-- BUG: only selectafilter cleared when changing colorscheme - drive me crazy
266-
SelectaFilter = { link = "Type" },
267-
SelectaCursor = { blend = 100, nocombine = true },
268-
SelectaPrompt = { link = "FloatTitle" },
269-
SelectaSelected = { link = "Statement" },
270-
SelectaFooter = { link = "Comment" },
271-
}
272-
273268
---Set up the highlight groups
274269
---@return nil
275270
local function setup_highlights()
271+
local highlights = {
272+
SelectaPrefix = { link = "Special" },
273+
SelectaMatch = { link = "Identifier" }, -- or maybe DiagnosticFloatingOk
274+
-- BUG: only selectafilter cleared when changing colorscheme - drive me crazy
275+
SelectaFilter = { link = "Type" },
276+
SelectaCursor = { blend = 100, nocombine = true },
277+
SelectaPrompt = { link = "FloatTitle" },
278+
SelectaSelected = { link = "Statement" },
279+
SelectaFooter = { link = "Comment" },
280+
SelectaCurrentLine = { link = M.config.current_highlight.hl_group },
281+
}
276282
M.log("Setting up highlights...")
277-
M.log("Current highlights table: " .. vim.inspect(highlights))
278283
for name, attrs in pairs(highlights) do
279284
vim.api.nvim_set_hl(0, name, attrs)
280285
end
@@ -584,6 +589,10 @@ end
584589
local function apply_highlights(buf, line_nr, item, opts, query, line_length, state)
585590
local display_str = opts.formatter(item)
586591

592+
local padding_width = 0
593+
if M.config.current_highlight.enabled and #M.config.current_highlight.prefix_icon > 0 then
594+
padding_width = vim.api.nvim_strwidth(M.config.current_highlight.prefix_icon)
595+
end
587596
-- First, check if this is a symbol filter query
588597
-- local filter = query:match("^%%%w%w(.*)$")
589598
-- local actual_query = filter and query:sub(4) or query -- Use everything after %xx if filter exists
@@ -614,6 +623,7 @@ local function apply_highlights(buf, line_nr, item, opts, query, line_length, st
614623
-- Get the formatted display string
615624
if opts.display.mode == "raw" then
616625
local offset = opts.offset and opts.offset(item) or 0
626+
offset = offset + padding_width -- Add the padding width to the offset
617627
if query ~= "" then
618628
local match = matcher.get_match_positions(item.text, query)
619629
if match then
@@ -637,17 +647,18 @@ local function apply_highlights(buf, line_nr, item, opts, query, line_length, st
637647
end
638648
else
639649
-- Find the actual icon boundary by looking for the padding
640-
local _, icon_end = display_str:find("^[^%s]+%s+")
650+
local _, icon_end = display_str:find("^" .. string.rep(" ", padding_width) .. "[^%s]+%s+")
651+
-- local _, icon_end = display_str:find("^[^%s]+%s+")
641652
if not icon_end then
642-
icon_end = 2 -- fallback if pattern not found
653+
icon_end = padding_width + 2 -- fallback if pattern not found, accounting for padding
643654
end
644655

645656
-- Allow modules to customize prefix highlighting
646657
if opts.prefix_highlighter then
647658
opts.prefix_highlighter(buf, line_nr, item, icon_end, ns_id)
648659
else
649660
-- Highlight prefix/icon
650-
vim.api.nvim_buf_set_extmark(buf, ns_id, line_nr, 0, {
661+
vim.api.nvim_buf_set_extmark(buf, ns_id, line_nr, padding_width, {
651662
end_col = icon_end,
652663
hl_group = get_prefix_info(item, opts.display.prefix_width).hl_group,
653664
priority = 100,
@@ -716,6 +727,43 @@ local function apply_highlights(buf, line_nr, item, opts, query, line_length, st
716727
end
717728
end
718729

730+
---@param state SelectaState The current state of the selecta picker
731+
---@param opts SelectaOptions The options for the selecta picker
732+
---@param line_nr number The 0-based line number to highlight
733+
---@return nil
734+
local function update_current_highlight(state, opts, line_nr)
735+
if not state or not state.buf or not vim.api.nvim_buf_is_valid(state.buf) then
736+
return
737+
end
738+
739+
-- Clear previous highlights in this namespace
740+
vim.api.nvim_buf_clear_namespace(state.buf, current_selection_ns, 0, -1)
741+
742+
-- Get the line content
743+
local lines = vim.api.nvim_buf_get_lines(state.buf, line_nr, line_nr + 1, false)
744+
if #lines == 0 then
745+
return
746+
end
747+
748+
-- Apply highlight to the whole line
749+
vim.api.nvim_buf_set_extmark(state.buf, current_selection_ns, line_nr, 0, {
750+
end_row = line_nr + 1,
751+
end_col = 0,
752+
hl_eol = true,
753+
hl_group = "SelectaCurrentLine",
754+
priority = 201, -- Higher than regular highlights but lower than matches
755+
})
756+
757+
-- Add the prefix icon if enabled
758+
if M.config.current_highlight.enabled and #M.config.current_highlight.prefix_icon > 0 then
759+
vim.api.nvim_buf_set_extmark(state.buf, current_selection_ns, line_nr, 0, {
760+
virt_text = { { M.config.current_highlight.prefix_icon, "SelectaCurrentLine" } },
761+
virt_text_pos = "overlay",
762+
priority = 100, -- Higher priority than the line highlight
763+
})
764+
end
765+
end
766+
719767
---@param state SelectaState
720768
---@param opts SelectaOptions
721769
local function update_cursor_position(state, opts)
@@ -737,6 +785,7 @@ local function update_cursor_position(state, opts)
737785
end
738786
end
739787
vim.api.nvim_win_set_cursor(state.win, new_pos)
788+
update_current_highlight(state, opts, new_pos[1] - 1) -- 0-indexed for extmarks
740789

741790
-- Only trigger on_move if not in initial state
742791
if opts.on_move and not state.initial_open then
@@ -889,8 +938,11 @@ local function update_display(state, opts)
889938
if opts.hooks and opts.hooks.on_render then
890939
opts.hooks.on_render(state.buf, state.filtered_items, opts)
891940
end
941+
-- M.add_padding_to_all_items(state, opts)
892942

893943
update_cursor_position(state, opts)
944+
local cursor_pos = vim.api.nvim_win_get_cursor(state.win)
945+
update_current_highlight(state, opts, cursor_pos[1] - 1)
894946
end
895947
else
896948
if vim.api.nvim_buf_is_valid(state.buf) then
@@ -1265,6 +1317,7 @@ local function handle_movement(state, direction, opts)
12651317
end
12661318

12671319
pcall(vim.api.nvim_win_set_cursor, state.win, { new_pos, 0 })
1320+
update_current_highlight(state, opts, new_pos - 1) -- 0-indexed for extmarks
12681321

12691322
if opts.on_move then
12701323
opts.on_move(state.filtered_items[new_pos])
@@ -1303,6 +1356,7 @@ local function handle_toggle(state, opts, direction)
13031356

13041357
-- Set new cursor position
13051358
pcall(vim.api.nvim_win_set_cursor, state.win, { next_pos, 0 })
1359+
update_current_highlight(state, opts, next_pos - 1)
13061360

13071361
-- Trigger move callback if exists
13081362
if opts.on_move then
@@ -1371,6 +1425,7 @@ local function handle_untoggle(state, opts)
13711425

13721426
-- Ensure cursor stays at the correct position
13731427
pcall(vim.api.nvim_win_set_cursor, state.win, { prev_selected_pos, 0 })
1428+
update_current_highlight(state, opts, prev_selected_pos - 1)
13741429

13751430
-- Trigger move callback if exists
13761431
if opts.on_move then
@@ -1553,6 +1608,7 @@ function M.pick(items, opts)
15531608
offnet = 0,
15541609
custom_keymaps = vim.tbl_deep_extend("force", M.config.custom_keymaps, {}),
15551610
movement = vim.tbl_deep_extend("force", M.config.movement, {}),
1611+
current_highlight = vim.tbl_deep_extend("force", M.config.current_highlight, {}),
15561612
auto_select = M.config.auto_select,
15571613
window = vim.tbl_deep_extend("force", M.config.window, {}),
15581614
pre_filter = nil,
@@ -1567,15 +1623,19 @@ function M.pick(items, opts)
15671623
-- Set up formatter
15681624
opts.formatter = opts.formatter
15691625
or function(item)
1626+
local prefix_padding = ""
1627+
if M.config.current_highlight.enabled and #M.config.current_highlight.prefix_icon > 0 then
1628+
prefix_padding = string.rep(" ", vim.api.nvim_strwidth(M.config.current_highlight.prefix_icon))
1629+
end
15701630
if opts.display.mode == "raw" then
1571-
return item.text
1631+
return prefix_padding .. item.text
15721632
elseif opts.display.mode == "icon" then
15731633
local icon = item.icon or " "
1574-
return icon .. string.rep(" ", opts.display.padding or 1) .. item.text
1634+
return prefix_padding .. icon .. string.rep(" ", opts.display.padding or 1) .. item.text
15751635
else
15761636
local prefix_info = get_prefix_info(item, opts.display.prefix_width)
15771637
local padding = string.rep(" ", prefix_info.padding)
1578-
return prefix_info.text .. padding .. item.text
1638+
return prefix_padding .. prefix_info.text .. padding .. item.text
15791639
end
15801640
end
15811641

@@ -1588,6 +1648,7 @@ function M.pick(items, opts)
15881648
local target_pos = math.min(opts.initial_index, #state.filtered_items)
15891649
if target_pos > 0 then
15901650
vim.api.nvim_win_set_cursor(state.win, { target_pos, 0 })
1651+
update_current_highlight(state, opts, target_pos - 1)
15911652
if opts.on_move then
15921653
opts.on_move(state.filtered_items[target_pos])
15931654
end
@@ -1668,6 +1729,11 @@ function M.setup(opts)
16681729
setup_highlights()
16691730
end)
16701731

1732+
if M.config.current_highlight.enabled then
1733+
vim.api.nvim_set_hl(0, "SelectaCurrentLine", {
1734+
link = M.config.current_highlight.hl_group,
1735+
})
1736+
end
16711737
-- Create autocmd for ColorScheme event
16721738
M.log("Creating ColorScheme autocmd")
16731739
vim.api.nvim_create_autocmd("ColorScheme", {

plugin/namu.lua

+1
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,7 @@ local function command_complete(_, line, col)
189189
return candidates
190190
end
191191
if words[2] == "help" then
192+
-- BUG: after modulize the plugin request_symbol is not working with those.
192193
local help_types = { "symbols", "analysis" }
193194
local prefix = words[3] or ""
194195
return vim.tbl_filter(function(type)

0 commit comments

Comments
 (0)