diff --git a/README.md b/README.md index 3580749..7767ee4 100644 --- a/README.md +++ b/README.md @@ -88,6 +88,7 @@ https://github.com/user-attachments/assets/64c41f01-dffe-4318-bce4-16eec8de356e diff = { disable_inlay_hints = true, -- Disable inlay hints in diff windows for cleaner view max_computation_time_ms = 5000, -- Maximum time for diff computation (VSCode default) + ignore_trim_whitespace = false, -- Ignore leading/trailing whitespace changes (like diffopt+=iwhite) hide_merge_artifacts = false, -- Hide merge tool temp files (*.orig, *.BACKUP.*, *.BASE.*, *.LOCAL.*, *.REMOTE.*) original_position = "left", -- Position of original (old) content: "left" or "right" conflict_ours_position = "right", -- Position of ours (:2) in conflict view: "left" or "right" diff --git a/VERSION b/VERSION index ef0f38a..7329e21 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.19.0 +2.20.0 diff --git a/lua/codediff/config.lua b/lua/codediff/config.lua index 45b9ec0..aec7df6 100644 --- a/lua/codediff/config.lua +++ b/lua/codediff/config.lua @@ -31,6 +31,7 @@ M.defaults = { diff = { disable_inlay_hints = true, -- Disable inlay hints in diff windows for cleaner view max_computation_time_ms = 5000, -- Maximum time for diff computation (5 seconds, VSCode default) + ignore_trim_whitespace = false, -- Ignore leading/trailing whitespace changes (like diffopt+=iwhite) hide_merge_artifacts = false, -- Hide merge tool temp files (*.orig, *.BACKUP.*, *.BASE.*, *.LOCAL.*, *.REMOTE.*) original_position = "left", -- Position of original (old) content: "left" or "right" conflict_ours_position = "right", -- Position of ours (:2) in conflict view: "left" or "right" (independent of original_position) diff --git a/lua/codediff/ui/auto_refresh.lua b/lua/codediff/ui/auto_refresh.lua index fe81e83..c017de5 100644 --- a/lua/codediff/ui/auto_refresh.lua +++ b/lua/codediff/ui/auto_refresh.lua @@ -89,6 +89,7 @@ local function do_diff_update(bufnr, skip_watcher_check) local config = require("codediff.config") local diff_options = { max_computation_time_ms = config.options.diff.max_computation_time_ms, + ignore_trim_whitespace = config.options.diff.ignore_trim_whitespace, } local lines_diff = diff.compute_diff(original_lines, modified_lines, diff_options) if not lines_diff then @@ -270,6 +271,7 @@ local function do_result_diff_update(bufnr) local config = require("codediff.config") local diff_options = { max_computation_time_ms = config.options.diff.max_computation_time_ms, + ignore_trim_whitespace = config.options.diff.ignore_trim_whitespace, } local lines_diff = diff.compute_diff(base_lines, result_lines, diff_options) if not lines_diff then diff --git a/lua/codediff/ui/lifecycle/state.lua b/lua/codediff/ui/lifecycle/state.lua index facf9c0..6eca61a 100644 --- a/lua/codediff/ui/lifecycle/state.lua +++ b/lua/codediff/ui/lifecycle/state.lua @@ -156,7 +156,11 @@ local function resume_diff(tabpage) if need_recompute or not diff.stored_diff_result then -- Buffer or file changed, recompute diff local diff_module = require("codediff.core.diff") - lines_diff = diff_module.compute_diff(original_lines, modified_lines) + local config = require("codediff.config") + lines_diff = diff_module.compute_diff(original_lines, modified_lines, { + max_computation_time_ms = config.options.diff.max_computation_time_ms, + ignore_trim_whitespace = config.options.diff.ignore_trim_whitespace, + }) diff_was_recomputed = true if lines_diff then diff --git a/lua/codediff/ui/view/render.lua b/lua/codediff/ui/view/render.lua index c80fe29..be992e8 100644 --- a/lua/codediff/ui/view/render.lua +++ b/lua/codediff/ui/view/render.lua @@ -22,6 +22,7 @@ function M.compute_and_render( -- Compute diff local diff_options = { max_computation_time_ms = config.options.diff.max_computation_time_ms, + ignore_trim_whitespace = config.options.diff.ignore_trim_whitespace, } local lines_diff = diff_module.compute_diff(original_lines, modified_lines, diff_options) if not lines_diff then @@ -102,6 +103,7 @@ end function M.compute_and_render_conflict(original_buf, modified_buf, base_lines, original_lines, modified_lines, original_win, modified_win, auto_scroll_to_first_hunk) local diff_options = { max_computation_time_ms = config.options.diff.max_computation_time_ms, + ignore_trim_whitespace = config.options.diff.ignore_trim_whitespace, } -- Compute base -> original (incoming) diff diff --git a/tests/ignore_whitespace_spec.lua b/tests/ignore_whitespace_spec.lua new file mode 100644 index 0000000..2edc57a --- /dev/null +++ b/tests/ignore_whitespace_spec.lua @@ -0,0 +1,65 @@ +-- Test: ignore_trim_whitespace option +-- Validates that the ignore_trim_whitespace DiffOption works correctly via FFI + +local diff = require('codediff.core.diff') + +describe("ignore_trim_whitespace", function() + it("detects whitespace-only changes when disabled", function() + local result = diff.compute_diff( + {" hello", "world"}, + {" hello", "world"}, + { ignore_trim_whitespace = false } + ) + assert.is_true(#result.changes > 0, "Should detect leading whitespace change") + end) + + it("ignores leading whitespace changes when enabled", function() + local result = diff.compute_diff( + {" hello", "world"}, + {" hello", "world"}, + { ignore_trim_whitespace = true } + ) + assert.equal(0, #result.changes, "Should ignore leading whitespace difference") + end) + + it("ignores trailing whitespace changes when enabled", function() + local result = diff.compute_diff( + {"hello ", "world"}, + {"hello ", "world"}, + { ignore_trim_whitespace = true } + ) + assert.equal(0, #result.changes, "Should ignore trailing whitespace difference") + end) + + it("still detects content changes when whitespace is ignored", function() + local result = diff.compute_diff( + {" hello", "world"}, + {" goodbye", "world"}, + { ignore_trim_whitespace = true } + ) + assert.is_true(#result.changes > 0, "Should still detect non-whitespace changes") + end) + + it("ignores indentation-only changes across multiple lines", function() + local result = diff.compute_diff( + {"function foo()", " return 1", "end"}, + {"function foo()", " return 1", "end"}, + { ignore_trim_whitespace = true } + ) + assert.equal(0, #result.changes, "Should ignore indentation-only differences") + end) + + it("defaults to false when not specified", function() + local with_default = diff.compute_diff( + {" hello"}, + {" hello"} + ) + local with_false = diff.compute_diff( + {" hello"}, + {" hello"}, + { ignore_trim_whitespace = false } + ) + assert.equal(#with_default.changes, #with_false.changes, + "Default behavior should match ignore_trim_whitespace=false") + end) +end)