Skip to content

diff: open_in_new_tab can strand a tab if setup errors before the diff state is registered #262

Description

@ThomasK33

Summary

In M._setup_blocking_diff (lua/claudecode/diff.lua), when diff_opts.open_in_new_tab = true, display_terminal_in_new_tab() creates a new tab early in setup. If setup then throws before M._register_diff_state runs, the post-pcall error handler does not close that tab, leaving the user with a stranded extra tab.

The state-based cleanup (if active_diffs[tab_name] then M._cleanup_diff_state(...)) can't fire because the diff was never registered, and the pre-registration else branch (added in #260 for the terminal-only fallback) only cleans up fallback_window and new_buffer. new_tab_handle is declared inside the pcall closure, so the error handler can't reach it even if it tried.

Trigger

Uncommon, but the same single-failure class accepted elsewhere: an error between tab creation and state registration — most realistically load_original_buffer's vim.cmd("edit " .. fnameescape(old_file_path)) hitting a BufReadPre/BufRead autocmd that throws, a swap-file conflict, or a filereadable-vs-:edit race.

Effect

One stranded tab per failed setup on the open_in_new_tab path (and the original tab is not refocused).

Suggested fix

Symmetric to the fallback_window / new_buffer hoists in #260: lift new_tab_handle (and the original tab id) above the pcall, and in the error handler's pre-registration branch switch back to the original tab and :tabclose the stranded one. Add a regression test that forces an error during open_in_new_tab setup and asserts no extra tab survives.

Context

Pre-existing (the open_in_new_tab path predates #260). Surfaced by a Claude review on #260 (#260) and deliberately deferred to keep that PR scoped to the #231 terminal-only fix. #260 already established the hoist-and-clean-up-on-error pattern this would follow.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions