diff --git a/lua/plugins/finder.lua b/lua/plugins/finder.lua index 29ea847..6faf7ba 100644 --- a/lua/plugins/finder.lua +++ b/lua/plugins/finder.lua @@ -16,6 +16,7 @@ M.config = { max_items = 5000, -- safety cap for massive outputs debug = false, follow_symlinks = true, -- pass -L to fd + grep_path_width = 30, -- Exclusion patterns (used by fd/rg in addition to their gitignore handling) exclude_patterns = { 'node_modules', 'dist', 'build', '.git' }, @@ -241,6 +242,60 @@ local function render() end end + -- For grep mode, reformat lines with fixed-width path column + local offset_map = {} -- maps display line -> character offset for highlighting + if S.mode == 'grep' and total > 0 then + local path_width = M.config.grep_path_width or 40 + + for i = 1, #view do + local line = view[i] + if line then + -- Parse original vimgrep format: file:line:col:content + local file, lnum, col = line:match('^(.-):(%d+):(%d+):') + if file and lnum and col then + -- Pad line number to 3 chars with underscores + local padded_lnum = lnum + while #padded_lnum < 3 do + padded_lnum = ' ' .. padded_lnum + end + + local lineinfo = ':' .. padded_lnum .. '|' + local content_start = #file + 1 + #lnum + 1 + #col + 2 -- file + :lnum: + col: + local content_part = line:sub(content_start) + + -- Calculate how much space we need for file + lineinfo + local prefix_len = #file + #lineinfo + local formatted_line + + if prefix_len > path_width then + -- Need to truncate the filepath part only + local available_for_file = path_width - #lineinfo + if available_for_file > 1 then + local truncated_file = '…' .. file:sub(-(available_for_file - 1)) + formatted_line = truncated_file .. lineinfo .. content_part + -- Offset is: original_file_length - truncated_file_length + offset_map[i] = #file - #truncated_file + else + -- Extreme case: line info itself is too long, just show what we can + formatted_line = ('…' .. file):sub(1, path_width) .. lineinfo .. content_part + offset_map[i] = #file - (path_width - #lineinfo) + end + elseif prefix_len < path_width then + -- Right-align by padding before the filepath + local padding = string.rep(' ', path_width - prefix_len) + formatted_line = padding .. file .. lineinfo .. content_part + offset_map[i] = -(path_width - prefix_len) -- negative for padding added + else + formatted_line = file .. lineinfo .. content_part + offset_map[i] = 0 + end + + view[i] = formatted_line + end + end + end + end + vim.bo[S.buf_res].modifiable = true vim.api.nvim_buf_set_lines(S.buf_res, 0, -1, false, view) vim.api.nvim_buf_clear_namespace(S.buf_res, S.ns, 0, -1) @@ -253,17 +308,15 @@ local function render() local idx = S.scroll + i local line = view[i] - -- In grep mode, highlight the "file:line:col:" prefix in gray + -- In grep mode, highlight the entire "file:line|" prefix in gray if S.mode == 'grep' and line then - local prefix_end = line:find('^.-:%d+:%d+:') + -- Find the end of the full prefix including the pipe + local _, prefix_end = line:find(':[ 0-9]+|') if prefix_end then - local _, epos = line:find('^.-:%d+:%d+:') - if epos then - pcall(vim.api.nvim_buf_set_extmark, S.buf_res, S.ns, i - 1, 0, { - end_col = epos, - hl_group = 'FinderPath', - }) - end + pcall(vim.api.nvim_buf_set_extmark, S.buf_res, S.ns, i - 1, 0, { + end_col = prefix_end, + hl_group = 'FinderPath', + }) end end @@ -272,7 +325,14 @@ local function render() if spans then for _, se in ipairs(spans) do local scol, ecol = se[1], se[2] - if ecol > scol then + + -- Adjust positions for grep mode formatting + if S.mode == 'grep' and offset_map[i] then + scol = scol - offset_map[i] + ecol = ecol - offset_map[i] + end + + if ecol > scol and scol >= 0 then pcall(vim.api.nvim_buf_set_extmark, S.buf_res, S.ns, i - 1, scol, { end_col = ecol, hl_group = 'FinderMatch',