| Commit message (Collapse) | Author | Age |
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The bumpy one, again. Every `.py` outside `vendor/` plus the three `contrib/`
scripts that are Python with no extension: 60 files, 6,714 lines rewritten, no
behaviour changed. Nothing here is worth reading -- the next commit adds it to
`.git-blame-ignore-revs` so `git blame` walks past it.
It is a bigger reformat than the C was, 60% of the lines against 17%, and for a
reason worth writing down rather than tuning away: ruff and black break a call that
does not fit onto one argument per line, where this code aligned the continuation
under the opening paren. The test suite is thousands of `check("some prose", cond,
detail)` calls, so nearly every one of them changed shape and the suite grew 3,308
lines. Line length was the one lever that moved it -- 120 columns would have been a
40% reformat and no growth at all -- and it was left at 88, because picking an
unusual width to dodge a one-time diff is paying forever to avoid paying once.
Import sorting came with it. Two files had `import os, pty, uuid, select, struct,
sys, termios, time, fcntl, signal` on one line and now have ten.
Verified after, not before, because a formatter that alters behaviour would be
worse than none:
- `make retest`, 1801 checks green -- and this reformats the suite that does the
checking, including `harness.py`, which every one of those files imports.
- `make test-live`, the tty tests the fast suite skips. They matter here more than
usual: `live_input.py` and `live_m0.py` are two of the files whose comma-imports
were split, and nothing in the fast suite would have noticed if that broke them.
- All 60 files still compile, `make fmt` twice in a row changes nothing the second
time, and `ruff check --select I` has nothing left to say.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
chrome> include "contrib/chrome/heartbeat.kdl"
heartbeat.kdl: 1 chrome, 0 content
chrome> shaders {
...> tint where="chrome" color="#ff5fd7" amount="abs(sin(t / 5))"
...> dim where="content" amount=80
...> }
1 chrome, 1 content
Both of those were errors an hour ago, and the second one was my fault twice
over: `:paste` printed `include "..."` and printing something you cannot type
back is a prompt lying about its own output. Pasting it answered `unexpected
argument for include`, and `load "..."` answered the same about `load`.
So the grammar is now the config's, all of it: an entry, several with `;`, an
entry with its own `where=`, a whole `shaders { }` block over as many lines as it
takes, `include "f.kdl"`, `load f`. There is a test that reads `:paste`'s block
off the screen, clears the pane, types it back line by line and compares the
cells -- round-tripping is the property, not a nice-to-have.
**The text is a document.** What it says replaces both chains, exactly as naming
`shaders { }` in a config replaces the block rather than adding to it, and an
entry's `where=` decides which rect it lands on. That drops a rule I invented last
week -- "one chain, one rect", which refused an entry that named the other one --
because it made the prompt's mode a law rather than a default and made a two-rect
block, the thing `:paste` prints, impossible to paste back. The prompt now keeps
the document and sends all of it, so a line aimed at the frame leaves the contents
alone, and the reply says `1 chrome, 1 content` rather than `ok`: with routing
visible, the counts are the answer worth reading.
`route_entries` is the one place routing is decided now -- config file, preset
file, typed line, same function. `config_parse_chain_doc` takes the wrapper or the
bare entries, because both are things a config contains and therefore both are
things somebody will paste.
Still nothing in the prompt parses KDL. A file goes by path; a pasted block goes
via a temporary file, since an OSC payload cannot carry a newline -- a control byte
ends the sequence, by the spec -- and joining lines with `;` would need exactly the
comment-and-quote scanner I refused to write. The only syntax the script looks at
is counting braces to know whether you have finished typing, and an empty line
gives up on that.
One hint, for the mistake that started this: when the session says `unknown
shader`, the prompt adds `(a file? :load <path>, or include "<path>")`. After the
fact rather than before, so a plugin's shader name is never second-guessed.
Verified: `tests/test_shader_repl.py` is 41 checks -- every input shape, the
multi-line paste and giving up on one, the round trip, the hint -- and
`tests/test_inband_shaders.py` gained the document rule in both directions,
including that a document naming only the frame takes the contents pass off. Full
clean suite green.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
printf '\033]5577;1;shader;\033\\' # from the program
sl0ppty cmd '{"cmd":"clear-shaders","id":0}' # from outside it
bind "z" "clear-shaders" # from the keyboard
`app_clear_pane_shaders` empties both of a pane's chains and says whether
there was anything there, which is what lets a key answer "shaders cleared"
or "no shaders on this pane" instead of maybe having done something.
In-band it is not a new verb: naming no rect means all of them. `shader;`
sits under `shader;chrome;` and `shader;content;` as the degenerate case of
"which rect", so a program puts a pane back in one exchange and cannot leave
it half done. `contrib/shader-repl`'s `:both` now uses that rather than two.
**None of the three is gated on `in_band_shaders`.** A chain outlives the
setting that allowed it -- paint a pane, then turn the setting off, and the
paint is still there, because a chain belongs to the pane and not to the file
(there is a test that reloads with it off and clears anyway). A way out that
the setting can take away is not a way out. The operator path matters for the
same reason: the program that made a pane unreadable is not always in a state
to put it back.
They clear what the *pane* set. The config's chains and the session's own
dimming are not this pane's doing and are derived every frame anyway.
The action is bound to nothing, like `scroll-up`: it is in the palette, which
is what the palette is for, and the docs say to bind it if you leave the
setting on. Which is where a second bug turned up -- the palette truncates a
label at 26 characters, so "undo this pane's own shaders" read as "undo this
pane's own shade" on screen. Renamed to fit, and `tests/test_palette.py` now
checks every label against the column, since nothing failed for that: it just
looked like a typo in front of someone.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
`contrib/shader-repl` imports readline, which is most of it: editing,
up/down, ctrl-r, and history kept between runs in
`$XDG_DATA_HOME/sl0ppty/shader-repl.history`. Chains only -- a `:` command
is taken back out of the history it would otherwise fill, because pressing
up four times past `:quit` and `:paste` to reach the line you were working
on is the annoyance history exists to remove.
Tab completes the commands, the nine shader names, the property keys, the
two rects, the three channels, and the expression language's own variables
and functions. `:help` prints the lot at once, which is the same list from
the same place.
That list is a claim about what exists, so `tests/test_shader_repl.py`
checks it against `src/shader.c` and `src/expr.c` and fails if either grows
a name it does not have -- verified by removing `spotlight` and watching it
fail. Then it types every name it offers at a real prompt and requires `ok`
from a real session, because a name that completes and does not parse is a
lie with a keystroke attached. History across two runs, a tab completion,
and `:help` are driven the same way, through a pty.
Two things that cost me time and are now written down where they bite:
keys go into a pane escaped (`\r`, `\t`, `\e[A`) because `raw` takes the rest
of one command line and a literal newline ends the command instead of
arriving; and Enter is CR, which is what a terminal sends and what readline
waits for.
Also: **a bare argument on a shader entry is now a complaint.** Every
parameter is a property, so `tint color="#000000" spotlight` is not a pass
with a spare word, it is a missing `;` -- KDL reads one node, the second
name does nothing, and the session used to answer `ok`. It now says
`unexpected argument for tint: spotlight (separate entries with ';')`. Found
by watching the prompt get used.
|
|
|
printf '\033]5577;1;shader;chrome;tint color="#ff5fd7" amount="abs(t / 8 % 510 - 255)"\033\\'
The field after `shader` is which rect -- `content` or `chrome` -- and the
rest of the payload is a chain in exactly the syntax a `shaders { }` block
uses, taken verbatim so that `;` can go on separating entries. Empty text
clears that chain. The session answers on the program's stdin, `shader-reply;ok`
or `shader-reply;error;bad amount for tint: ...`, because a prototyping loop
that gets no answer cannot tell a typo from a build without the feature.
`contrib/shader-repl` is the prompt this exists for: type a chain, watch the
pane, and `:paste` prints what you have as a config block. Both ends are the
same parser, so what you arrive at is what you can keep -- verified by
pasting `:paste`'s output into a file, linting it, and checking the frame
comes out the same colour.
**D13 said this was impossible on purpose, and the reasoning stands**: a
program that can restyle the session it happens to be running in is a hazard,
and `cat hostile.txt` should not dim your panes. But *impossible* was the
wrong shape for it -- editing a file, saving, looking and guessing again is
slow enough that shaders go unwritten. So it takes `in_band_shaders true`,
one line of consent, and it is scoped to the pane that asked: its own two
chains, never its neighbour's, never what the config said about anyone else.
There is a test for the neighbour.
Each chain owns the programs its expressions compiled to, and is swapped in
whole, so a chain that turns out not to read leaves the pane looking like it
did rather than half-restyled. Measured: 1,800 replacements of an animated
chain, resident size flat after the first pass.
Also here, because it is the same paint order: the chrome chain now sits
between the config's and policy's, exactly where the content chain does.
Dead code out -- `app_shade_add`/`app_shade_clear`/`app_shade_count` had no
callers and their comment claimed the opposite of what this commit does.
|