Program status (OSC 7501)
A program can tell the terminal what it is doing: whether it is working, finished, failed, or waiting for the user to approve something or answer a question. The terminal keeps the latest report of every program running in it, and shows it where the user will see it even when the tab is in the background.
Contour implements the program-status protocol, revision 0.4.
Syntax
Pairs are separated by :. A value uses letters, digits and _ . , + / = -; a pair holding
anything else, a pair without =, and unknown keys are skipped, and a repeated key keeps its last
value.
| Key | Value | Meaning |
|---|---|---|
state |
idle, working, done, blocked, error, clear |
Required. clear removes records. |
id |
segment(/segment)* |
Which record; absent for the root. build/test lies beneath build. |
kind |
permission, question, auth |
Why it is blocked; only with blocked. |
progress |
0..100 |
Percent done; only with working or blocked. |
app |
[A-Za-z0-9_.+-]{1,32} |
The program; inherited from the nearest ancestor when absent. |
title |
base64 UTF-8 | A short label. |
msg |
base64 UTF-8 | One line describing the status. |
A report replaces its record whole: a key it leaves out is cleared.
Limits
A report that breaks one of these is discarded whole, and the records stay as they were:
- the whole sequence is at most 4096 bytes, a key at most 16;
idis at most 128 bytes, 32 per segment and 8 segments deep;msgis at most 2732 bytes encoded and 2048 decoded,title256 and 192;- base64 must be valid (padding is optional);
- decoded text must be UTF-8 without control characters (C0, DEL or C1).
Contour keeps at most 64 records per terminal, the minimum the protocol requires. A 65th evicts the record that was updated least recently, so a loop reporting fresh ids cannot grow the terminal.
Lifetime
Records belong to the terminal, not to a screen: switching to the alternate screen and back keeps them, and so does a soft reset (DECSTR). A full reset (RIS) removes all of them.
| State | Ends when |
|---|---|
working, blocked |
Replaced, cleared, the process exits, or a new shell prompt starts (OSC 133 A) |
idle |
Replaced or cleared; Contour keeps it across a prompt |
done, error |
Replaced or cleared |
A close the user or a script asks for ends the terminal, and its records with it.
Feature detection
Contour answers
before the primary device attributes reply. A terminal that does not support the protocol answers only the device attributes.
Where it shows
- The tab strip. A tab shows the most urgent record of all its panes: blocked, then error, then working, then done. Working (with its progress, when given) and blocked show always; done and error only while the tab is in the background. The badge's tooltip is the record's title, else its message, else its app, with invisible formatting characters (bidi overrides, zero-width characters) removed.
- The control API.
contour ls --jsonlists each pane's records, andcontour events --kind pane.programStatusChangedfollows their changes. - Daemon mode. The daemon keeps the records and mirrors them to every attached client.
Contour does not derive program status from the progress indicator (OSC 9;4), nor the other way round: they are separate sequences with separate meanings.
Examples
# A build: working at 40%, then finished.
printf '\033]7501;state=working:app=cargo:progress=40\033\\'
printf '\033]7501;state=done:app=cargo\033\\'
# Waiting for an approval, with a message.
printf '\033]7501;state=blocked:kind=permission:app=terraform:msg=%s\033\\' \
"$(printf 'Apply 3 changes?' | base64 -w0)"
# Two regions of a deployment, then clearing both.
printf '\033]7501;state=working:id=deploy/eu:app=deploy\033\\'
printf '\033]7501;state=error:id=deploy/us\033\\'
printf '\033]7501;state=clear:id=deploy\033\\'