Skip to content

A window is the default, in the shell and out of it - #180

Open
torstei wants to merge 2 commits into
mainfrom
feature/graph-window-clause
Open

A window is the default, in the shell and out of it#180
torstei wants to merge 2 commits into
mainfrom
feature/graph-window-clause

Conversation

@torstei

@torstei torstei commented Sep 7, 2026

Copy link
Copy Markdown
Owner

graph could only write a file, so seeing a plot meant leaving the shell for timbergraph — whose --window timbersh never exposed. Adds window and ascii clauses, with a window as the default.

graph http_requests from [class=tally] by status;          window at a desk, ASCII over ssh
graph http_requests from [class=tally] window;             force one (refuses if impossible)
graph http_requests from [class=tally] ascii;              force text
graph http_requests from [class=tally] png '/tmp/r.png';   a file, as before

Three conditions, and none implies the others

A window needs a display, and a gnuplot built with an interactive terminal (gnuplot-nox has none), and — for the default only — a terminal to be watching it.

That third one isn't fussiness. timbersh -q < script.tsh > out.txt at a desk would otherwise open a window and write an empty file, turning a working non-interactive run into nothing. Naming window overrides it, since a window isn't stdout. It follows the rule view and into view already use.

Where a window can't be drawn the default is ASCII, so ssh sessions behave exactly as before. A named window that can't be drawn is refused rather than downgraded — the point of saying it is to get one — and the message names both missing pieces.

Two smaller decisions

The probe reads gnuplot's terminal list, not its exit code. set terminal nosuchterm exits 0 and only warns on stderr, so a probe trusting the status would call every terminal available. One gnuplot at ~10 ms, cached, since it's a fact about the machine.

Two destinations is now refused instead of resolved in silence: window png 'f' wrote the file and no window, window ascii was ASCII, and png beside svg quietly preferred the png.

timbergraph's own CLI keeps ASCII as its default — deliberately asymmetric. It's a pipe tool that gets scripted and redirected; timbersh is a console with somebody in front of it. Its --window now names what's missing rather than relaying gnuplot's complaint.

Tests

Six new, and the suite can now say what the machine can do — a fake-gnuplot reporting a chosen terminal list, plus a per-session env override. Without that a suite would inherit the developer's DISPLAY and assert one thing at a desk and the opposite in CI.

Two things I got wrong on the way and fixed, because they're the failure modes worth knowing about:

  • My first four tests all ran with no display, so none of them exercised the auto-window default at all — the actual feature. Confirmed by disabling the default and watching them all still pass. The default test now runs on a PTY, since the default is gated on one.
  • Two tests asserted only the absence of the window marker, which would also pass if nothing ran. The fake now prints a marker for both paths, so every case asserts what was actually asked for.

a_graph_draws_a_window_by_default_where_one_can_be_drawn fails with the default disabled (verified). 67/67 timbersh tests pass, as do the timbergraph, timberview and timberfs-client suites.

⚠ Not shipped by the timberfs package — timbersh/timbergraph live in timberfs-sh, so this needs a timbersh-v* tag to reach anyone.

🤖 Generated with Claude Code

`graph` could only write a file — `png 'f'`/`svg 'f'` — so seeing a plot
meant leaving the shell for timbergraph, whose `--window` timbersh never
exposed. Both now default to a WINDOW, and both take `window`/`ascii`
(`--window`/`--ascii`) to say which outright.

ASCII IS THE REASON. It cannot carry the detail: five series an order of
magnitude apart collapse into two rows of characters and one of them
disappears from the plot entirely, legend and all. A picture is the point
of a graph.

ONE RULE, in `choose_terminal`, called by both. Two copies would drift
and the drift would be silent — the same words meaning different
pictures depending which of the two you typed them in. A window wants
three things and none implies another: a display, a gnuplot built with an
interactive terminal (`gnuplot-nox` has none), and a TTY to be watching
it. The tty binds the DEFAULT only, and it is not fussiness:
`timbersh -q < script > out.txt` at a desk would otherwise open a window
and write an empty file, turning a working non-interactive run into
nothing. Naming `window` overrides it, a window not being stdout. A
NAMED window that cannot be drawn is refused rather than downgraded,
because the point of saying it is to get one.

The probe reads gnuplot's TERMINAL LIST rather than its exit code: `set
terminal nosuchterm` exits 0 and only warns, so a probe trusting the
status would call every terminal available. One gnuplot at ~10 ms,
cached, this being a fact about the machine.

Two destinations is refused rather than resolved in silence — `window
png 'f'` wrote the file and no window, `window ascii` was ASCII, `png`
beside `svg` quietly preferred the png. In timbersh it is decided BEFORE
the read, so such a statement costs no fleet query; and `Bad` is
translated, since only ValueError reaches the loop's handler and a
refusal left untranslated arrives as a traceback out of the shell.

The tests can say what the machine can do — a `fake-gnuplot` reporting a
chosen terminal list, and a per-session env override — because a suite
inheriting the developer's DISPLAY would assert one thing at a desk and
the opposite in CI. timbersh's default-window test runs on a PTY, the
default being gated on one; each destination is asserted by what the
fake was ASKED for rather than by the absence of the other, which would
also pass if nothing ran.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@torstei
torstei force-pushed the feature/graph-window-clause branch from 9f98404 to e1ed46d Compare September 7, 2026 19:29
@torstei torstei changed the title graph draws a window where one can be drawn A window is the default, in the shell and out of it Sep 7, 2026
`graph ... window` refused on a machine with gnuplot-qt installed and
WAYLAND_DISPLAY set. `gnuplot -e CMD` runs CMD and then goes on READING
STDIN, and `capture_output=True` does not touch stdin — so inside an
interactive shell the probe inherited the user's terminal, waited there
for the full timeout, and the fallback reported "no interactive terminal"
about a machine that has one. It also ate whatever was typed at it
meanwhile. `stdin=subprocess.DEVNULL` is the whole fix; measured on a
real pty, 10 s and None becomes 0.02 s and `qt`.

⚠ NO TEST COULD HAVE SEEN THIS. Every suite pipes stdin, where gnuplot
reaches EOF at once and the probe is correct. So `fake-gnuplot` now reads
stdin to EOF after answering `set term`, which is what the real one does
in the respect that matters — and the default-window test, which already
ran on a PTY, fails without the fix.

The bare `except Exception` around the probe is narrowed to OSError and
SubprocessError. Falling back to ASCII is the safe direction, but
swallowing every exception is what turned a hang into a confident wrong
answer about the machine.

Co-Authored-By: Claude Opus 5 (1M context) <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.

1 participant