@@ -232,6 +232,56 @@ local function symbols_to_items(opts, symbols, bufnr, child_prefix)
232232 return _symbols_to_items (symbols , {}, bufnr or 0 , " " )
233233end
234234
235+ --- @param text string
236+ --- @param query string
237+ --- @param hl_func fun ( s : string ): string
238+ --- @return string
239+ local function fuzzy_highlight (text , query , hl_func )
240+ if not query or # query == 0 then
241+ return text
242+ end
243+
244+ local s , e
245+ if query :find (" %u" ) then -- exact match
246+ s , e = text :find (query , 1 , true )
247+ end
248+ if not s then -- case-insensitive match
249+ s , e = text :lower ():find (query :lower (), 1 , true )
250+ end
251+ if s and e then
252+ return text :sub (1 , s - 1 )
253+ .. hl_func (text :sub (s , e ))
254+ .. text :sub (e + 1 )
255+ end
256+
257+ -- fuzzy match: highlight only matched chars
258+ local text_lower = text :lower ()
259+ local query_lower = query :lower ()
260+ local match_indices = {}
261+ local ti , qi = 1 , 1
262+ while ti <= # text and qi <= # query do
263+ if text_lower :sub (ti , ti ) == query_lower :sub (qi , qi ) then
264+ match_indices [# match_indices + 1 ] = ti
265+ qi = qi + 1
266+ end
267+ ti = ti + 1
268+ end
269+ if # match_indices ~= # query then
270+ return text
271+ end
272+ local buf = {}
273+ local mi = 1
274+ for i = 1 , # text do
275+ if mi <= # match_indices and i == match_indices [mi ] then
276+ buf [# buf + 1 ] = hl_func (text :sub (i , i ))
277+ mi = mi + 1
278+ else
279+ buf [# buf + 1 ] = text :sub (i , i )
280+ end
281+ end
282+ return table.concat (buf )
283+ end
284+
235285local function symbol_handler (opts , cb , _ , result , ctx , _ )
236286 result = utils .tbl_islist (result ) and result or { result }
237287 local items
@@ -250,15 +300,9 @@ local function symbol_handler(opts, cb, _, result, ctx, _)
250300 (not opts ._regex_filter_fn or opts ._regex_filter_fn (entry , utils .CTX ())) then
251301 local mbicon_align = 0
252302 if opts .is_live and type (opts .query ) == " string" and # opts .query > 0 then
253- -- highlight exact matches with `live_workspace_symbols` (#1028)
303+ -- highlight exact or fuzzy matches with `live_workspace_symbols` (#1028)
254304 local sym , text = entry .text :match (" ^(.+%])(.*)$" )
255- local s , e = text :lower ():find (opts .query :lower (), 1 , true )
256- if s and e then
257- text = text :sub (1 , s - 1 )
258- .. utils .ansi_codes [opts .hls .live_sym ](text :sub (s , e ))
259- .. text :sub (e + 1 )
260- end
261- entry .text = sym .. text
305+ entry .text = sym .. fuzzy_highlight (text , opts .query , utils .ansi_codes [opts .hls .live_sym ])
262306 end
263307 if M ._sym2style then
264308 local kind = entry .text :match (" %[(.-)%]" )
0 commit comments