Skip to content

fix(previewer): allow diff/git cmd syntax#2698

Merged
phanen merged 1 commit intomainfrom
allow-diff
Apr 27, 2026
Merged

fix(previewer): allow diff/git cmd syntax#2698
phanen merged 1 commit intomainfrom
allow-diff

Conversation

@phanen
Copy link
Copy Markdown
Collaborator

@phanen phanen commented Apr 23, 2026

Related #2694 (comment)

Summary by CodeRabbit

Bug Fixes

  • Fixed syntax highlighting and treesitter context attachment in file previews—previously these were skipped for terminal buffers.
  • Improved handling of diff and git file types to ensure proper syntax highlighting and file type-specific features are correctly applied.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 23, 2026

📝 Walkthrough

Walkthrough

The change modifies preview buffer post-processing in the fzf-lua previewer, making the syntax/markdown/treesitter attachment pipeline run unconditionally during the preview_buf_post phase instead of skipping it for terminal buffers. Additionally, the do_syntax function now forces FileType autocmd execution for diff and git filetypes after filetype detection to ensure proper side effects trigger before setting internal state.

Changes

Cohort / File(s) Summary
Preview buffer post-processing
lua/fzf-lua/previewer/builtin.lua
Modified syntax/markdown/treesitter attachment pipeline to run unconditionally during preview_buf_post and forced FileType autocmd execution for diff/git filetypes with modeline=false to ensure proper file type handling.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • PR #2667: Also modifies lua/fzf-lua/previewer/builtin.lua, addressing autocmds/FileType handling and preview parsing logic with similar focus on preview behavior and file type detection.

Poem

🐰 Hop through the preview with confident stride,
FileType autocmds now run wide,
Syntax lights up, no more hiding,
Diff and git get their rightful pride,
Every buffer sees its colors shine bright! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix(previewer): allow diff/git cmd syntax' directly describes the main change—enabling syntax support for diff/git command previews in the builtin previewer.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch allow-diff

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@phanen
Copy link
Copy Markdown
Collaborator Author

phanen commented Apr 23, 2026

cc @barrettruth, with this your config can be simplified

diff --git a/config/nvim/lua/config/fzf/preview.lua b/config/nvim/lua/config/fzf/preview.lua
index c46621c..1c134a4 100644
--- a/config/nvim/lua/config/fzf/preview.lua
+++ b/config/nvim/lua/config/fzf/preview.lua
@@ -66,65 +66,8 @@ local function make_class(parse)
     end
 
     ---@param entry_str string
-    function P:populate_preview_buf(entry_str)
-        if not self.win or not self.win:validate_preview() then
-            return
-        end
-        if self.stop_job then
-            self.stop_job()
-            self.stop_job = nil
-        end
-
-        local entry = self:_parse(entry_str)
-        self._last_entry = entry_str
-        if not entry then
-            self:_render({ 'cannot preview:', entry_str })
-            return
-        end
-
-        self._job = vim.system(
-            entry.argv,
-            { text = true, cwd = self.opts.cwd or vim.uv.cwd() },
-            vim.schedule_wrap(function(res)
-                if entry_str ~= self._last_entry then
-                    return
-                end
-                if not self.win or not self.win:validate_preview() then
-                    return
-                end
-                self:_render(self:_format(res))
-            end)
-        )
-        self.stop_job = function()
-            if self._job and not self._job:is_closing() then
-                self._job:kill(9)
-            end
-        end
-    end
-
-    ---@param res vim.SystemCompleted
-    ---@return string[]
-    function P:_format(res)
-        if res.code ~= 0 then
-            local lines = { ('git exited %d'):format(res.code), '' }
-            vim.list_extend(
-                lines,
-                vim.split(res.stderr or '', '\n', { plain = true })
-            )
-            return lines
-        end
-        return vim.split(res.stdout or '', '\n', { plain = true })
-    end
-
-    ---@param lines string[]
-    function P:_render(lines)
-        local buf = self:get_tmp_buffer()
-        api.nvim_buf_set_lines(buf, 0, -1, false, lines)
-        vim.bo[buf].filetype = 'git'
-        self:set_preview_buf(buf)
-        if self.win and self.win.update_preview_scrollbar then
-            self.win:update_preview_scrollbar()
-        end
+    function P:parse_entry(entry_str)
+        return { cmd = self:_parse(entry_str), filetype = 'diff' }
     end
 
     return P
@@ -157,29 +100,23 @@ local function parse_status(self, entry_str)
     if is_untracked then
         local stat = vim.uv.fs_stat(entry.path)
         if stat and stat.type == 'directory' then
-            return { argv = { 'ls', '-la', entry.path } }
+            return { 'ls', '-la', entry.path }
         end
         return {
-            argv = {
-                'git',
-                'diff',
-                '--no-color',
-                '--no-index',
-                '/dev/null',
-                entry.path,
-            },
+            'git',
+            'diff',
+            '--no-color',
+            '--no-index',
+            '/dev/null',
+            entry.path,
         }
     end
 
     if is_deleted or is_modified then
-        return {
-            argv = { 'git', 'diff', '--no-color', 'HEAD', '--', entry.path },
-        }
+        return { 'git', 'diff', '--no-color', 'HEAD', '--', entry.path }
     end
 
-    return {
-        argv = { 'git', 'diff', '--no-color', 'HEAD', '--', entry.path },
-    }
+    return { 'git', 'diff', '--no-color', 'HEAD', '--', entry.path }
 end
 
 ---@param _ fzf.preview.Previewer
@@ -190,7 +127,7 @@ local function parse_commits(_, entry_str)
     if not sha then
         return nil
     end
-    return { argv = { 'git', 'show', '--no-color', sha } }
+    return { 'git', 'show', '--no-color', sha }
 end
 
 ---@param self fzf.preview.Previewer
@@ -201,9 +138,7 @@ local function parse_bcommits(self, entry_str)
     if not sha or not self._file then
         return nil
     end
-    return {
-        argv = { 'git', 'show', '--no-color', sha, '--', self._file },
-    }
+    return { 'git', 'show', '--no-color', sha, '--', self._file }
 end
 
 ---@param self fzf.preview.Previewer
@@ -228,7 +163,7 @@ local function parse_diff(self, entry_str)
     end
     table.insert(argv, '--')
     table.insert(argv, entry.path)
-    return { argv = argv }
+    return argv
 end
 
 ---@param _ fzf.preview.Previewer
@@ -239,9 +174,7 @@ local function parse_stash(_, entry_str)
     if not ref then
         return nil
     end
-    return {
-        argv = { 'git', 'stash', 'show', '--patch', '--no-color', ref },
-    }
+    return { 'git', 'stash', 'show', '--patch', '--no-color', ref }
 end
 
 ---@param self fzf.preview.Previewer
@@ -252,9 +185,7 @@ local function parse_blame(self, entry_str)
     if not sha or not self._file then
         return nil
     end
-    return {
-        argv = { 'git', 'show', '--no-color', sha, '--', self._file },
-    }
+    return { 'git', 'show', '--no-color', sha, '--', self._file }
 end
 
 local M = {}

@phanen phanen marked this pull request as draft April 23, 2026 02:35
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
lua/fzf-lua/previewer/builtin.lua (1)

1187-1191: Narrow allow-list for FileType re-dispatch — double-check edge cases.

The special case is deliberately scoped to diff/git to work around filetype_detect's eventignore("FileType"). Two minor things worth confirming:

  1. When entry.filetype == "diff" or "git" (e.g. from _populate_loaded_buffer_preview where entry.filetype = vim.bo[entry.bufnr].filetype), filetype_detect is never called, so vim.bo[bufnr].filetype is still "" at the moment this autocmd fires. Any FileType autocmd consumer that reads &filetype (rather than the dispatched pattern) would see an empty value. Core ftplugins generally don't, but plugin-registered ones (fugitive, gitsigns helpers, etc.) might. Consider setting vim.bo[bufnr].filetype = ft immediately before the dispatch to keep buffer state consistent.
  2. Are there other filetypes that need the same treatment (e.g. fugitive, gitcommit, diff-adjacent), or is diff/git the complete set from the linked issue? A brief comment documenting why only these two would help future readers.
Optional nit: set `&filetype` before re-dispatch
   if ft == "diff" or ft == "git" then
     api.nvim_buf_call(bufnr, function()
+      vim.bo[bufnr].filetype = ft
       api.nvim_exec_autocmds("FileType", { pattern = ft, modeline = false })
     end)
   end
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lua/fzf-lua/previewer/builtin.lua` around lines 1187 - 1191, The FileType
re-dispatch for ft == "diff" or "git" can leave vim.bo[bufnr].filetype empty for
autocmd handlers that read &filetype; before calling api.nvim_exec_autocmds set
vim.bo[bufnr].filetype = ft to keep buffer state consistent (while still using
api.nvim_buf_call(bufnr, ...)); also add a brief comment near the ft/git
conditional explaining why only these filetypes are re-dispatched (reference the
filetype_detect/eventignore issue) and note to consider related filetypes (e.g.,
fugitive/gitcommit) if needed so future readers understand the narrow
allow-list.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@lua/fzf-lua/previewer/builtin.lua`:
- Around line 1187-1191: The FileType re-dispatch for ft == "diff" or "git" can
leave vim.bo[bufnr].filetype empty for autocmd handlers that read &filetype;
before calling api.nvim_exec_autocmds set vim.bo[bufnr].filetype = ft to keep
buffer state consistent (while still using api.nvim_buf_call(bufnr, ...)); also
add a brief comment near the ft/git conditional explaining why only these
filetypes are re-dispatched (reference the filetype_detect/eventignore issue)
and note to consider related filetypes (e.g., fugitive/gitcommit) if needed so
future readers understand the narrow allow-list.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 55c63076-eed3-4748-80db-7dd635c3922a

📥 Commits

Reviewing files that changed from the base of the PR and between 8223eb2 and b1a3799.

📒 Files selected for processing (1)
  • lua/fzf-lua/previewer/builtin.lua

@barrettruth
Copy link
Copy Markdown
Contributor

barrettruth commented Apr 23, 2026

Def better and more elegant but the highlighting is not quite as good as my overly-complex approach (lol) because of fzf-lua terminal-pty-like rendering.

See the local of highlighting on the index.. lines and +++ lines.

image

Would like this in main regardless.

@phanen
Copy link
Copy Markdown
Collaborator Author

phanen commented Apr 23, 2026

right 'git' seems always better than 'diff' in this case

index c96684c2..40599687 100644
@@ -58,7 +58,7 @@ local function make_class(parse)
   end
 
   ---@param entry_str string
-  function P:parse_entry(entry_str) return { cmd = self:_parse(entry_str), filetype = 'diff' } end
+  function P:parse_entry(entry_str) return { cmd = self:_parse(entry_str), filetype = 'git' } end
 
   return P
 end

@barrettruth
Copy link
Copy Markdown
Contributor

@phanen can this be marked as ready?

@phanen phanen marked this pull request as ready for review April 27, 2026 01:15
@phanen
Copy link
Copy Markdown
Collaborator Author

phanen commented Apr 27, 2026

we can merge it now. i forgot why i skip syntax hl on terminal buffer before, maybe for no reason

@phanen
Copy link
Copy Markdown
Collaborator Author

phanen commented Apr 27, 2026

wondering if we can emit ft event for all filetype... or is there way to kown "lsp" filetype to skip (maybe via get_autocmd or something)

not sure will nvim attach lsp on special buftype?

@phanen phanen merged commit 2e29d5f into main Apr 27, 2026
11 checks passed
@barrettruth
Copy link
Copy Markdown
Contributor

image

@phanen so clean! thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants