From 24a6414d8bb1e88b9ed7e32eaa5b15ca71c3607b Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Fri, 13 Mar 2026 07:14:31 -0400 Subject: [PATCH] fix(init): guard `read_file_lines` against directory paths (#189) Problem: when a commit contains a submodule or a symlink to a directory, `read_file_lines` passes the path to `io.open` which succeeds, then `f:lines()` raises `"Is a directory"` inside the decoration provider. Solution: check `vim.fn.isdirectory(path)` before `io.open` and return nil early, which `compute_hunk_context` already handles gracefully. --- lua/diffs/init.lua | 3 +++ spec/context_spec.lua | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/lua/diffs/init.lua b/lua/diffs/init.lua index 6975af1..b986eae 100644 --- a/lua/diffs/init.lua +++ b/lua/diffs/init.lua @@ -347,6 +347,9 @@ end ---@param path string ---@return string[]? local function read_file_lines(path) + if vim.fn.isdirectory(path) == 1 then + return nil + end local f = io.open(path, 'r') if not f then return nil diff --git a/spec/context_spec.lua b/spec/context_spec.lua index 237b7f3..84243f4 100644 --- a/spec/context_spec.lua +++ b/spec/context_spec.lua @@ -165,6 +165,39 @@ describe('context', function() assert.is_nil(hunks[1].context_after) end) + it('skips when path is a directory', function() + vim.fn.mkdir(vim.fs.joinpath(tmpdir, 'subdir'), 'p') + + local hunks = { + make_hunk('subdir', { + file_new_start = 1, + file_new_count = 1, + lines = { '+x' }, + }), + } + compute_hunk_context(hunks, 25) + + assert.is_nil(hunks[1].context_before) + assert.is_nil(hunks[1].context_after) + end) + + it('skips when path is a symlink to a directory', function() + vim.fn.mkdir(vim.fs.joinpath(tmpdir, 'real_dir'), 'p') + vim.uv.fs_symlink(vim.fs.joinpath(tmpdir, 'real_dir'), vim.fs.joinpath(tmpdir, 'link_dir')) + + local hunks = { + make_hunk('link_dir', { + file_new_start = 1, + file_new_count = 1, + lines = { '+x' }, + }), + } + compute_hunk_context(hunks, 25) + + assert.is_nil(hunks[1].context_before) + assert.is_nil(hunks[1].context_after) + end) + it('skips when file does not exist on disk', function() local hunks = { make_hunk('nonexistent.lua', {