From ff20efca71581009b4487a6ab56c82ff380d48c8 Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Sun, 21 Sep 2025 17:18:22 -0400 Subject: [PATCH 1/3] feat(diff): third, regular diff mode --- doc/cp.txt | 10 ++++---- lua/cp/config.lua | 8 +++--- lua/cp/init.lua | 60 +++++++++++++++++++++++++++++++++++++++++++- lua/cp/ui/diff.lua | 15 +++++++++++ spec/config_spec.lua | 22 ++++++++++++++++ spec/diff_spec.lua | 23 +++++++++++++++-- 6 files changed, 126 insertions(+), 12 deletions(-) diff --git a/doc/cp.txt b/doc/cp.txt index 67493f8..3bbf716 100644 --- a/doc/cp.txt +++ b/doc/cp.txt @@ -211,12 +211,12 @@ Here's an example configuration with lazy.nvim: >lua ANSI escape codes are stripped for plain text display. Requires vim.g.terminal_color_* to be configured for proper color display. - {diff_mode} (string, default: "vim") Diff backend: "vim" or "git". - Git provides character-level precision, vim uses - built-in diff. + {diff_mode} (string, default: "git") Diff backend: "none", "vim", or "git". + "none" displays plain buffers without highlighting, + "vim" uses built-in diff, "git" provides character-level precision. {next_test_key} (string, default: "") Key to navigate to next test case. {prev_test_key} (string, default: "") Key to navigate to previous test case. - {toggle_diff_key} (string, default: "t") Key to toggle diff mode. + {toggle_diff_key} (string, default: "t") Key to cycle through diff modes. {max_output_lines} (number, default: 50) Maximum lines of test output. *cp.DiffConfig* @@ -545,7 +545,7 @@ RUN PANEL KEYMAPS *cp-test-keys* run_panel.next_test_key) Navigate to previous test case (configurable via run_panel.prev_test_key) -t Toggle diff mode between vim and git (configurable +t Cycle through diff modes: none → vim → git (configurable via run_panel.toggle_diff_key) q Exit test panel and restore layout diff --git a/lua/cp/config.lua b/lua/cp/config.lua index 9386b75..a1fb62f 100644 --- a/lua/cp/config.lua +++ b/lua/cp/config.lua @@ -31,10 +31,10 @@ ---@class RunPanelConfig ---@field ansi boolean Enable ANSI color parsing and highlighting ----@field diff_mode "vim"|"git" Diff backend to use +---@field diff_mode "none"|"vim"|"git" Diff backend to use ---@field next_test_key string Key to navigate to next test case ---@field prev_test_key string Key to navigate to previous test case ----@field toggle_diff_key string Key to toggle diff mode +---@field toggle_diff_key string Key to cycle through diff modes ---@field max_output_lines number Maximum lines of test output to display ---@class DiffGitConfig @@ -205,9 +205,9 @@ function M.setup(user_config) diff_mode = { config.run_panel.diff_mode, function(value) - return vim.tbl_contains({ 'vim', 'git' }, value) + return vim.tbl_contains({ 'none', 'vim', 'git' }, value) end, - "diff_mode must be 'vim' or 'git'", + "diff_mode must be 'none', 'vim', or 'git'", }, next_test_key = { config.run_panel.next_test_key, diff --git a/lua/cp/init.lua b/lua/cp/init.lua index c50316e..4aaaf13 100644 --- a/lua/cp/init.lua +++ b/lua/cp/init.lua @@ -288,6 +288,43 @@ local function toggle_run_panel(is_debug) highlight.apply_highlights(bufnr, highlights, namespace or test_list_namespace) end + local function create_none_diff_layout(parent_win, expected_content, actual_content) + local expected_buf = create_buffer_with_options() + local actual_buf = create_buffer_with_options() + + vim.api.nvim_set_current_win(parent_win) + vim.cmd.split() + vim.cmd('resize ' .. math.floor(vim.o.lines * 0.35)) + local actual_win = vim.api.nvim_get_current_win() + vim.api.nvim_win_set_buf(actual_win, actual_buf) + + vim.cmd.vsplit() + local expected_win = vim.api.nvim_get_current_win() + vim.api.nvim_win_set_buf(expected_win, expected_buf) + + vim.api.nvim_set_option_value('filetype', 'cptest', { buf = expected_buf }) + vim.api.nvim_set_option_value('filetype', 'cptest', { buf = actual_buf }) + vim.api.nvim_set_option_value('winbar', 'Expected', { win = expected_win }) + vim.api.nvim_set_option_value('winbar', 'Actual', { win = actual_win }) + + local expected_lines = vim.split(expected_content, '\n', { plain = true, trimempty = true }) + local actual_lines = vim.split(actual_content, '\n', { plain = true, trimempty = true }) + + update_buffer_content(expected_buf, expected_lines, {}) + update_buffer_content(actual_buf, actual_lines, {}) + + return { + buffers = { expected_buf, actual_buf }, + windows = { expected_win, actual_win }, + cleanup = function() + pcall(vim.api.nvim_win_close, expected_win, true) + pcall(vim.api.nvim_win_close, actual_win, true) + pcall(vim.api.nvim_buf_delete, expected_buf, { force = true }) + pcall(vim.api.nvim_buf_delete, actual_buf, { force = true }) + end, + } + end + local function create_vim_diff_layout(parent_win, expected_content, actual_content) local expected_buf = create_buffer_with_options() local actual_buf = create_buffer_with_options() @@ -395,6 +432,8 @@ local function toggle_run_panel(is_debug) local function create_diff_layout(mode, parent_win, expected_content, actual_content) if mode == 'single' then return create_single_layout(parent_win, actual_content) + elseif mode == 'none' then + return create_none_diff_layout(parent_win, expected_content, actual_content) elseif mode == 'git' then return create_git_diff_layout(parent_win, expected_content, actual_content) else @@ -481,6 +520,16 @@ local function toggle_run_panel(is_debug) ansi_namespace ) end + elseif desired_mode == 'none' then + local expected_lines = vim.split(expected_content, '\n', { plain = true, trimempty = true }) + local actual_lines = vim.split(actual_content, '\n', { plain = true, trimempty = true }) + update_buffer_content(current_diff_layout.buffers[1], expected_lines, {}) + update_buffer_content( + current_diff_layout.buffers[2], + actual_lines, + actual_highlights, + ansi_namespace + ) else local expected_lines = vim.split(expected_content, '\n', { plain = true, trimempty = true }) local actual_lines = vim.split(actual_content, '\n', { plain = true, trimempty = true }) @@ -548,7 +597,16 @@ local function toggle_run_panel(is_debug) toggle_run_panel() end, { buffer = buf, silent = true }) vim.keymap.set('n', config.run_panel.toggle_diff_key, function() - config.run_panel.diff_mode = config.run_panel.diff_mode == 'vim' and 'git' or 'vim' + local modes = { 'none', 'vim', 'git' } + local current_idx = nil + for i, mode in ipairs(modes) do + if config.run_panel.diff_mode == mode then + current_idx = i + break + end + end + current_idx = current_idx or 1 + config.run_panel.diff_mode = modes[(current_idx % #modes) + 1] refresh_run_panel() end, { buffer = buf, silent = true }) vim.keymap.set('n', config.run_panel.next_test_key, function() diff --git a/lua/cp/ui/diff.lua b/lua/cp/ui/diff.lua index 9295c63..16dff5a 100644 --- a/lua/cp/ui/diff.lua +++ b/lua/cp/ui/diff.lua @@ -22,6 +22,20 @@ local vim_backend = { end, } +---@type DiffBackend +local none_backend = { + name = 'none', + render = function(expected, actual) + local expected_lines = vim.split(expected, '\n', { plain = true, trimempty = true }) + local actual_lines = vim.split(actual, '\n', { plain = true, trimempty = true }) + + return { + content = { expected = expected_lines, actual = actual_lines }, + highlights = {}, + } + end, +} + ---@type DiffBackend local git_backend = { name = 'git', @@ -143,6 +157,7 @@ local git_backend = { ---@type table local backends = { + none = none_backend, vim = vim_backend, git = git_backend, } diff --git a/spec/config_spec.lua b/spec/config_spec.lua index 9724832..21723b1 100644 --- a/spec/config_spec.lua +++ b/spec/config_spec.lua @@ -70,6 +70,28 @@ describe('cp.config', function() end) end) + it('validates diff_mode values', function() + local valid_config = { + run_panel = { + diff_mode = 'none', + }, + } + + assert.has_no.errors(function() + config.setup(valid_config) + end) + + local invalid_config = { + run_panel = { + diff_mode = 'invalid_mode', + }, + } + + assert.has_error(function() + config.setup(invalid_config) + end) + end) + it('validates hook functions', function() local invalid_config = { hooks = { before_run = 'not_a_function' }, diff --git a/spec/diff_spec.lua b/spec/diff_spec.lua index b50d05e..49bd120 100644 --- a/spec/diff_spec.lua +++ b/spec/diff_spec.lua @@ -12,10 +12,10 @@ describe('cp.diff', function() end) describe('get_available_backends', function() - it('returns vim and git backends', function() + it('returns none, vim and git backends', function() local backends = diff.get_available_backends() table.sort(backends) - assert.same({ 'git', 'vim' }, backends) + assert.same({ 'git', 'none', 'vim' }, backends) end) end) @@ -32,6 +32,12 @@ describe('cp.diff', function() assert.equals('git', backend.name) end) + it('returns none backend by name', function() + local backend = diff.get_backend('none') + assert.is_not_nil(backend) + assert.equals('none', backend.name) + end) + it('returns nil for invalid name', function() local backend = diff.get_backend('invalid') assert.is_nil(backend) @@ -95,6 +101,19 @@ describe('cp.diff', function() end) end) + describe('none backend', function() + it('returns both expected and actual content', function() + local backend = diff.get_backend('none') + local result = backend.render('expected\nline2', 'actual\nline2') + + assert.same({ + expected = { 'expected', 'line2' }, + actual = { 'actual', 'line2' }, + }, result.content) + assert.same({}, result.highlights) + end) + end) + describe('vim backend', function() it('returns content as-is', function() local backend = diff.get_backend('vim') From 0851339e6361d20abe347816557c62808f534096 Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Sun, 21 Sep 2025 17:19:34 -0400 Subject: [PATCH 2/3] fix(diff): default to boring view --- doc/cp.txt | 2 +- lua/cp/config.lua | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/cp.txt b/doc/cp.txt index 3bbf716..2a5a1ae 100644 --- a/doc/cp.txt +++ b/doc/cp.txt @@ -211,7 +211,7 @@ Here's an example configuration with lazy.nvim: >lua ANSI escape codes are stripped for plain text display. Requires vim.g.terminal_color_* to be configured for proper color display. - {diff_mode} (string, default: "git") Diff backend: "none", "vim", or "git". + {diff_mode} (string, default: "none") Diff backend: "none", "vim", or "git". "none" displays plain buffers without highlighting, "vim" uses built-in diff, "git" provides character-level precision. {next_test_key} (string, default: "") Key to navigate to next test case. diff --git a/lua/cp/config.lua b/lua/cp/config.lua index a1fb62f..8bafd35 100644 --- a/lua/cp/config.lua +++ b/lua/cp/config.lua @@ -101,7 +101,7 @@ M.defaults = { filename = nil, run_panel = { ansi = true, - diff_mode = 'git', + diff_mode = 'none', next_test_key = '', prev_test_key = '', toggle_diff_key = 't', From 355cb5df82d426cc654aa0a0b1f2c1f4f3f5f297 Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Sun, 21 Sep 2025 17:21:46 -0400 Subject: [PATCH 3/3] fix(diff): make git the second diff choice, not vim --- lua/cp/init.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/cp/init.lua b/lua/cp/init.lua index 4aaaf13..589265f 100644 --- a/lua/cp/init.lua +++ b/lua/cp/init.lua @@ -597,7 +597,7 @@ local function toggle_run_panel(is_debug) toggle_run_panel() end, { buffer = buf, silent = true }) vim.keymap.set('n', config.run_panel.toggle_diff_key, function() - local modes = { 'none', 'vim', 'git' } + local modes = { 'none', 'git', 'vim' } local current_idx = nil for i, mode in ipairs(modes) do if config.run_panel.diff_mode == mode then