Skip to content

Preserve empty pane titles during save and restore - #581

Open
chirayuk wants to merge 5 commits into
tmux-plugins:masterfrom
chirayuk:fix/empty-pane-title
Open

Preserve empty pane titles during save and restore#581
chirayuk wants to merge 5 commits into
tmux-plugins:masterfrom
chirayuk:fix/empty-pane-title

Conversation

@chirayuk

Copy link
Copy Markdown

Summary

  • guard pane_title with the same leading : used for other optional
    snapshot fields;
  • remove that guard during restore, preserving a genuinely empty title;
  • add a deterministic Docker regression with one deliberately empty pane
    title and distinct non-empty titles;
  • verify both save output and save-after-restore output byte for byte.

When pane_title is empty, the current format emits adjacent tabs. Bash
treats tab as IFS whitespace and collapses that empty field, shifting every
later value left. Restore then reads pane_active as the directory and opens
the pane in $HOME instead of its saved working directory.

The colon guard makes the field non-empty on disk while still restoring the
original empty value.

Attribution

This uses the lossless approach proposed by @mtkozlowski in #570. That PR was
closed before maintainer review; its author is credited in the implementation
commit. This PR retains that idea and adds automated save/restore regression
coverage in an isolated environment.

Test environment

The Docker runner has no host mounts or network access, runs as a non-root
user with a read-only root filesystem, and verifies exact container ownership
before cleanup. The pinned environment uses Ubuntu 24.04, tmux 3.4, Bash, and
a 200-by-50 pseudo-terminal.

Verification

tests/run_tests_in_docker

Docker runner ownership tests passed
test_resurrect_restore.sh: SUCCESS
test_resurrect_save.sh: SUCCESS

KTSCode and others added 5 commits July 14, 2026 20:37
When pane_title is empty, the save file contains consecutive tab
delimiters. Bash's IFS=$'\t' read collapses these (POSIX whitespace
IFS behavior), shifting every field after pane_title one position
left. This puts pane_active into the dir field, causing panes to
restore in the wrong directory.

Use tmux conditional format #{?pane_title,#{pane_title},_} to
guarantee a non-empty field, outputting "_" for untitled panes.

Fixes tmux-plugins#437
Use the colon guard proposed in tmux-plugins#570 and retain the Docker regression coverage.

Co-authored-by: Mateusz Kozlowski <kooziu@gmail.com>
odj1001extra pushed a commit to odj1001extra/tmux-resurrect that referenced this pull request Jul 21, 2026
When pane_title is empty, the tab-delimited save format emits adjacent
tabs. Tab is an IFS-whitespace character, so the `IFS=$d read ...` loops
in dump_panes (save.sh) and restore_pane (restore.sh) collapse the empty
field and shift every later value left by one. dir is then read from the
pane_active column ("1"), remove_first_char reduces it to "", and restore
runs `tmux split-window -c ""`, which falls back to $HOME. Only panes
whose title was empty lose their working directory, which is why this
stays hidden for most users.

Give pane_title the same leading ':' guard already used for the other
optional fields (window_flags, pane_current_path, window_name,
full_command) and strip it back off during restore. The field is never
empty on disk, so it cannot collapse, and a genuinely empty title is
still restored as empty.

The awk parse sites in restore.sh are unaffected: awk with FS="\t" does
not collapse empty fields, and the field count is unchanged.

This is the lossless approach proposed by @mtkozlowski in
tmux-plugins#570 and carried forward in tmux-plugins#581.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
dainis added a commit to dainis/tmux-resurrect that referenced this pull request Jul 30, 2026
dump_panes() re-reads its own tab-delimited record with `IFS=$'\t' read`.
Tab is IFS whitespace, so an empty field collapses instead of being
preserved. Every field that can be empty is emitted with a protective ":"
prefix except pane_title, so a pane with no title shifts the record left
by one: pane_current_path lands in the title slot, pane_active ("0"/"1")
lands in the dir slot, and the full command is lost.

Effects on restore: `split-window -c ""` falls back to the session default
(panes reopen in $HOME), and restore_all_pane_processes() drops the line
via its `$11 !~ "^:$"` filter, so @resurrect-processes never matches.

Claude Code triggers this routinely -- it clears the pane title on exit.
Any program emitting OSC 2 with an empty string does the same.

Guard pane_title like the other nullable fields and strip the guard on
restore. Identical to upstream PR tmux-plugins#582 (closed as a duplicate of tmux-plugins#581);
see also tmux-plugins#520, tmux-plugins#536, tmux-plugins#564 and the closed tmux-plugins#570. Upstream has merged
nothing since 2023-03.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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