| Commit message (Collapse) | Author | Age |
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The out-of-the-box look, rethought as one piece:
- the compiled-in palette calms down: muted blue #7aa2f7 on the same
neutral darks, with the colours that mean something kept semantic --
amber bell, red-orange dead. sl0p stays one include away as the house
style, and contrib/themes/default.kdl is the starting point written
down (theme-tour shows it).
- derived state defaults now actually follow the theme: the scrolled
wash is rebuilt from scroll_bg after the theme block (it used to bake
the compiled accent), and declaring a state -- in any file of an
include chain -- still wins. The dump writes derived states as
comments so C-a e cannot pin what is meant to keep following.
- a bell you can see: the frame blinks three times in theme's bell
colour then breathes until answered, and a soft diagonal shimmer --
the bell colour halved towards default_fg, width breathing on a sine
-- crosses the body for the same 900ms. bell_indicator false silences
all of it; states { bell { } } replaces it like any state. since
carries the clock dependency, so an idle session pays nothing.
- scrollback says where it continues: while scrolled, the viewport's
top and bottom rows melt towards an edge with content past it and
turn solid at the buffer's end. New expression variables above/below
(lines hidden past each edge, own dependency bit, cached per scroll
position), carried in shade_ctx_t -- SLOSH_SHADER_ABI 3 -> 4.
- expressions survive the dump: a program keeps its source and cb_chain
writes it back, so amount="(y % 2) * 40" no longer dumps as a number.
- headers move to include/, -Iinclude everywhere; the plugin Makefile's
SLOSH var becomes SLOSH_DIR because slosh exports SLOSH=1 into every
pane it runs, and building from inside a session read that as a path.
- comment drift culled where features outran the prose, and the
derivation boilerplate folded into derived_pass()/ctx_scroll().
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
|
|
Five things, in one commit because they land in the same few files --
the action table, the shader pass, config.kdl -- and splitting them by
hunk would buy a tidier log at the price of commits that do not build.
Each is verified end to end; the suite is 46 files green.
Chrome shaders. `where="chrome"` on any entry in `shaders` or in a
`states` block runs that pass over a pane's frame -- border, padding,
title, buttons -- instead of its contents. Nothing else changes: same
registry, same `amount`, same expressions, same chain order, one new
word, because a frame is another rect and so it is another pass. It runs
over the frame's whole rect with the contents punched out as a hole,
rather than four passes over four sides: an effect has to be able to
travel round a border, and four passes would each count x/y from zero
and restart at every corner. The hole keeps the two honest -- a skipped
cell is never visited, so a full-strength chrome tint cannot reach your
text. It is also the only kind of pass that can colour a pane a small
window has collapsed to a single row (D6), which is the state where a
colour is worth the most.
`channel="fg"|"bg"|"both"` came out of looking at the first border
flash: `tint` mixes both of a cell's colours, and a frame's background
is the terminal's own default, so the pass materialised it to our guess
at that default and mixed towards the colour -- a dark rectangle behind
the glyphs, left there until the pane changed state. The mask is
enforced by the pass, not the shader: the other colour is snapshotted
before materialising and put back after, so an unset colour goes back to
unset, it works for a built-in and a plugin alike, and no shader grows
an fg-only twin of itself.
A `bell` pane state and a `since` variable, because "flash the border
when a pane rings" needed both and neither existed. `since` is
milliseconds since the pane entered its current state, stamped in the
one function that decides the state -- a transition is the one thing a
frame cannot tell you, so it is remembered where it cannot disagree with
the state it dates. `bell` ranks above the ambient states and below
`dead`: a pane that rang while you were elsewhere is news, and a pane
that rang and then exited is a pane that exited. It ends when you look
at the pane, because that is what answering a bell is.
Animation needed a clock and did not have one: a shader reading `t` only
advanced when something else caused a frame, so a pulse froze the moment
you stopped typing. `app_next_deadline_ms` now reports `anim_ms` while a
chain that reads the clock ran over the last frame -- derived from what
was applied, so a pulse hung off `dead` costs a clock while a pane is
dead and nothing for the rest of the session. A `deadline` verb makes
that observable; the server's poll loop already lived on the number.
contrib/chrome has seven presets and the perimeter trick they are built
on: on a frame the coordinate you want is distance along the ring, which
the language can work out, and `min(d, P - d)` is what makes an effect
cross the corner it started from. Hand-written, unlike contrib/shaders,
because the toy previews contents and a frame has no preview to give --
so tests/test_chrome_presets.py checks each one the only way left: load
it into a real session, assert the frame moves and the contents do not.
`equalize` (C-a =) puts every share back to even: each split's children
weighted by how many visible panes are behind them, so one pane beside a
stack of three is a quarter of the width and "even" means the same thing
at every depth. Exactly equal cell counts are not something a tree can
always express, so the action promises the even division it can.
`rotate-layout` (C-a Space) turns the whole tab a quarter turn
clockwise. Every split changes axis and a row split's children reverse,
because the pane on top of a stack is the pane on the right once you
turn it; get that asymmetry wrong and you have a mirror image, which
looks almost right until four turns fail to come back. They do come
back, exactly, which is why the inverse is three more turns rather than
a second mirrored routine with its own chance of being wrong -- and why
a key as easy as space is the right one rather than a hazard. A turn is
refused when it would not fit: a share of the height is not always a
share the width can afford, and a node that cannot give its children
their floor takes the whole tab down to a list. So the turn is tried,
the layout is asked what it made of it, and one that flattened the tab
is put back with a word. Same rule `split_fits` applies to splitting.
Keys: the palette moves from `shift+p` to `p`, and cycling tabs from
`n`/`p` to tab/shift+tab. `p` is pressed far more often than "the tab
before this one" and was the only shifted letter in the defaults; tab is
what every other tabbed thing cycles with, and `\e[Z` decodes as
shift+tab on a plain terminal, so this costs nothing on a client without
the kitty protocol. `n` is free again. The actions are untouched: two
lines of config put the old binds back.
The shader ABI goes to 3: `shade_ctx_t` gained `state_ms` and struct
shader gained `channels`, both the pass's business rather than a
shader's. Plugins need a rebuild, which is what the version is for.
|