@@ -181,6 +181,11 @@ M.config = {
181
181
mode = " icon" ,
182
182
padding = 1 ,
183
183
},
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
+ },
184
189
offset = 0 ,
185
190
debug = false ,
186
191
preserve_order = false , -- Default to false unless the other module handle it
229
234
M .clear_log = logger .clear_log
230
235
231
236
local ns_id = vim .api .nvim_create_namespace (" selecta_highlights" )
237
+ local current_selection_ns = vim .api .nvim_create_namespace (" selecta_current_selection" )
232
238
233
239
--- Thanks to folke and mini.nvim for this utlity of hiding the cursor
234
240
--- Hide the cursor by setting guicursor and caching the original value
@@ -259,22 +265,21 @@ local function restore_cursor()
259
265
end
260
266
end
261
267
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
-
273
268
--- Set up the highlight groups
274
269
--- @return nil
275
270
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
+ }
276
282
M .log (" Setting up highlights..." )
277
- M .log (" Current highlights table: " .. vim .inspect (highlights ))
278
283
for name , attrs in pairs (highlights ) do
279
284
vim .api .nvim_set_hl (0 , name , attrs )
280
285
end
584
589
local function apply_highlights (buf , line_nr , item , opts , query , line_length , state )
585
590
local display_str = opts .formatter (item )
586
591
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
587
596
-- First, check if this is a symbol filter query
588
597
-- local filter = query:match("^%%%w%w(.*)$")
589
598
-- 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
614
623
-- Get the formatted display string
615
624
if opts .display .mode == " raw" then
616
625
local offset = opts .offset and opts .offset (item ) or 0
626
+ offset = offset + padding_width -- Add the padding width to the offset
617
627
if query ~= " " then
618
628
local match = matcher .get_match_positions (item .text , query )
619
629
if match then
@@ -637,17 +647,18 @@ local function apply_highlights(buf, line_nr, item, opts, query, line_length, st
637
647
end
638
648
else
639
649
-- 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+")
641
652
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
643
654
end
644
655
645
656
-- Allow modules to customize prefix highlighting
646
657
if opts .prefix_highlighter then
647
658
opts .prefix_highlighter (buf , line_nr , item , icon_end , ns_id )
648
659
else
649
660
-- 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 , {
651
662
end_col = icon_end ,
652
663
hl_group = get_prefix_info (item , opts .display .prefix_width ).hl_group ,
653
664
priority = 100 ,
@@ -716,6 +727,43 @@ local function apply_highlights(buf, line_nr, item, opts, query, line_length, st
716
727
end
717
728
end
718
729
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
+
719
767
--- @param state SelectaState
720
768
--- @param opts SelectaOptions
721
769
local function update_cursor_position (state , opts )
@@ -737,6 +785,7 @@ local function update_cursor_position(state, opts)
737
785
end
738
786
end
739
787
vim .api .nvim_win_set_cursor (state .win , new_pos )
788
+ update_current_highlight (state , opts , new_pos [1 ] - 1 ) -- 0-indexed for extmarks
740
789
741
790
-- Only trigger on_move if not in initial state
742
791
if opts .on_move and not state .initial_open then
@@ -889,8 +938,11 @@ local function update_display(state, opts)
889
938
if opts .hooks and opts .hooks .on_render then
890
939
opts .hooks .on_render (state .buf , state .filtered_items , opts )
891
940
end
941
+ -- M.add_padding_to_all_items(state, opts)
892
942
893
943
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 )
894
946
end
895
947
else
896
948
if vim .api .nvim_buf_is_valid (state .buf ) then
@@ -1265,6 +1317,7 @@ local function handle_movement(state, direction, opts)
1265
1317
end
1266
1318
1267
1319
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
1268
1321
1269
1322
if opts .on_move then
1270
1323
opts .on_move (state .filtered_items [new_pos ])
@@ -1303,6 +1356,7 @@ local function handle_toggle(state, opts, direction)
1303
1356
1304
1357
-- Set new cursor position
1305
1358
pcall (vim .api .nvim_win_set_cursor , state .win , { next_pos , 0 })
1359
+ update_current_highlight (state , opts , next_pos - 1 )
1306
1360
1307
1361
-- Trigger move callback if exists
1308
1362
if opts .on_move then
@@ -1371,6 +1425,7 @@ local function handle_untoggle(state, opts)
1371
1425
1372
1426
-- Ensure cursor stays at the correct position
1373
1427
pcall (vim .api .nvim_win_set_cursor , state .win , { prev_selected_pos , 0 })
1428
+ update_current_highlight (state , opts , prev_selected_pos - 1 )
1374
1429
1375
1430
-- Trigger move callback if exists
1376
1431
if opts .on_move then
@@ -1553,6 +1608,7 @@ function M.pick(items, opts)
1553
1608
offnet = 0 ,
1554
1609
custom_keymaps = vim .tbl_deep_extend (" force" , M .config .custom_keymaps , {}),
1555
1610
movement = vim .tbl_deep_extend (" force" , M .config .movement , {}),
1611
+ current_highlight = vim .tbl_deep_extend (" force" , M .config .current_highlight , {}),
1556
1612
auto_select = M .config .auto_select ,
1557
1613
window = vim .tbl_deep_extend (" force" , M .config .window , {}),
1558
1614
pre_filter = nil ,
@@ -1567,15 +1623,19 @@ function M.pick(items, opts)
1567
1623
-- Set up formatter
1568
1624
opts .formatter = opts .formatter
1569
1625
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
1570
1630
if opts .display .mode == " raw" then
1571
- return item .text
1631
+ return prefix_padding .. item .text
1572
1632
elseif opts .display .mode == " icon" then
1573
1633
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
1575
1635
else
1576
1636
local prefix_info = get_prefix_info (item , opts .display .prefix_width )
1577
1637
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
1579
1639
end
1580
1640
end
1581
1641
@@ -1588,6 +1648,7 @@ function M.pick(items, opts)
1588
1648
local target_pos = math.min (opts .initial_index , # state .filtered_items )
1589
1649
if target_pos > 0 then
1590
1650
vim .api .nvim_win_set_cursor (state .win , { target_pos , 0 })
1651
+ update_current_highlight (state , opts , target_pos - 1 )
1591
1652
if opts .on_move then
1592
1653
opts .on_move (state .filtered_items [target_pos ])
1593
1654
end
@@ -1668,6 +1729,11 @@ function M.setup(opts)
1668
1729
setup_highlights ()
1669
1730
end )
1670
1731
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
1671
1737
-- Create autocmd for ColorScheme event
1672
1738
M .log (" Creating ColorScheme autocmd" )
1673
1739
vim .api .nvim_create_autocmd (" ColorScheme" , {
0 commit comments