Skip to content

feat(tui): close several windows at once with /close 2,3-5 - #38

Merged
t0d0r merged 4 commits into
masterfrom
feature/close-ranges
Nov 4, 2026
Merged

t0d0r merged 4 commits into
masterfrom
feature/close-ranges

Conversation

@t0d0r

@t0d0r t0d0r commented Nov 4, 2026

Copy link
Copy Markdown
Owner

What

/close (also /wc, /part) now takes a list and ranges as well as one number: /close 2,3-5, /close 1-4, /close 1,2,3. Commas and/or spaces separate the items. /close alone still closes the current window.

  • Numbering: every number is the window as numbered before the command, as the window bar showed it.
  • All or nothing: a malformed item, a reversed range (5-3), window 0 or a missing window (no window N) closes none of them and changes nothing.
  • Repeats: a window listed twice, or covered by overlapping ranges, closes once.
  • Notices: each closed window gets its window closed: notice in window 0, and one status line names them all (cut after four as +N more).
  • Focus: the current window stays current, or, if it closed, the nearest open window before it becomes current. Closing sends no read receipts and changes no unread counts.
  • Changed error texts: a non-number gets the list error; a number past the end is no window N (it was the server-window error); +2 is now malformed.

specs/ui.md (with Decision lines), docs/usage.md and /help (/close [N,M-K]) describe it.

Review

  • One implementing agent built it, then two reviews (correctness and test strength; spec conformance), with each finding verified by a second agent.
  • 2 confirmed and fixed: notices sent from a chat window were untested; a reversed range whose ends overflow an int was not caught as reversed.
  • 5 refuted.
  • 25 mutants of the new code were all caught by the tests.
  • Checked in the demo.

make check and the race tests pass.

t0d0r added 4 commits November 4, 2026 03:43
/close now takes a list of window numbers and ranges as well as one
number: /close 1,2,3, /close 1-4, /close 2,3-5, /close 2, 3-5 and
/close 2 3 5. Items are separated by commas and/or spaces; an item is N
or A-B with A <= B, ASCII digits, no sign. /close alone still closes
the current window.

Every number is the window's number before the command, as the window
bar shows it, so /close 2,3 closes the windows that were 2 and 3. A
window named twice closes once. The whole argument is checked first and
nothing closes on an error: a malformed item or reversed range is
"/close takes window numbers: N, a list or ranges (as 2,3-5)", then
window 0 anywhere is the server window's error, then the first number
past the last window as written is "no window N" (which replaces the
server window's error for /close 9). Signs (-1, +2) are now malformed.

Each closed window gets its "window closed: <name>" notice in window 0
in window order; the status says "closed <name>" for one window and
"closed N windows: 2:#dev, ..." cut after four as "+N more" for
several; the layout is saved once. The current window stays current
when it stays open, else the nearest open window before it becomes
current. Closing focuses nothing, so no read receipt goes and no unread
count changes; the last window is dropped when it closes, as before.

The logic moves to internal/tui/close.go (closeSpec, closeWins);
closeWin, used by the /win list [close] button, now goes through
closeWins. specs/ui.md (Windows, the commands table), docs/usage.md and
/help describe the forms, with the decisions: numbers as shown before
the command, and all or nothing so a typo closes nothing.
TestCloseNoticesAndStatus runs every case with window 0 current, so it
could not tell window 0 from the current window: notices sent to the
current window instead would have passed it.

TestCloseNoticesGoToWindowZero runs /close from a chat window, once one
that stays open (window 6, /close 1,3) and once one that closes (window
3, /close 3-4, after which #dev is current). Window 0 gets exactly the
"window closed: <name>" notices in window order, and no chat window that
stays, the current one before or after included, gets any notice.
A number too large for an int reads as the largest int, so a range
whose ends both overflowed, as 99999999999999999999-10000000000000000000,
compared as equal and passed the reversed-range check: it was "no window
99999999999999999999", and with ",0" added the server window's error,
instead of the /close form error that specs/ui.md gives a reversed range
before the window-0 and past-the-end checks. Nothing closed either way;
only the error text was wrong.

The order of a range's ends now compares the digit text without leading
zeros (its length, then digit by digit), which is exact for whole
numbers of any length. The int value still serves the window-0 and
past-the-end checks, where any overflowing number is past every window.

specs/ui.md says the ends are compared as whole numbers of any length,
with a decision: the error never depends on the machine's int size.
TestCloseSpec gains overflowing ranges, reversed and not, and
TestCloseIsAllOrNothing a reversed overflowing range that closes nothing.
Mark the item done in todo/todo.md and add session/2026-11-04-close-ranges.md: the forms, the all-or-nothing rule, the changed error texts, the review results and how to check it.
@t0d0r
t0d0r merged commit cedec74 into master Nov 4, 2026
4 checks passed
@t0d0r
t0d0r deleted the feature/close-ranges branch November 4, 2026 01:46
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.

1 participant