| Commit message (Collapse) | Author | Age |
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
A native theme `lapis` (src/themes/lapis.zig) from web/theme/lapis.css:
a lapis-deep page, lapis tags with gold names, vellum text, vermilion
rubrics, gold rules and a vermilion tag rule, gold selection in lapis ink.
Its ornament is the theme's new `decor` (colors.Decor), drawn by a pixel
shell inside the chrome it already has (decision 1), all of it off every
focus indicator:
- page_dots: the site's gold dot grid (#e8c46a22, 22 px), drawn by the
cell shader on page-coloured cells alone (flag 0x10000000), so it lies
under the text and never under a selection, a tag or the cursor; fixed
to the window, a page the panes lie on.
- rail_checker: the dither frame's gold and lapis checker in the scroll
track (a decor kind, flag 0x08000000), anchored to its rail; the thumb
stays solid gold.
- tag plaques (tag_border, tag_shadow, tag_stripe): every tag a raised
plaque inside its own band, the site's trail: a 2px gold frame and a
hard 5px vermilion shadow down and right, both within the band's rows
and columns (down, what the slack under the text leaves), so no shadow
reaches a body, a grip or the next pane. The focused pane's plaque is
the code window's title bar, gold and lapis stripes of 2px, its words
on plates of the focused ground; unfocused ones are plain; column and
workspace tags take the object-label language (1px frame, 2px shadow
toward the page). Drawn as decor under the cells (a group's under
range), with blank tag cells see-through and the cells blended
premultiplied (pipeline_over) on such frames; opaque windows only.
- title_shadow: the titles' vermilion offset shadow under a file name's
letters, sampled in the cell shader inside the letters' own cells (flag
0x08000000), none on a cursor.
Chrome carries the decor (decor_*, name_ink, active_name_ink); a theme
file folds a nested decor literal field by field. Left out, with why, in
docs/effects.md: the fonts, the ornaments, a decor crossfade, and in the
tty anything but the colours (a tag row has no spare cell for a shadow).
An empty column is the page. The effect id is masked to 27 bits (ui.vert/ui.frag) for the
fifth flag.
Tests: the cell flags land only on page ground and file-name cells, never
a cursor, nothing without decor; lapis's plaques stay inside their tag's
band, clear of every grip, only the focused one striped; its checker is in
the track; no other theme draws any; the separator and focus
tests cover lapis. Goldens: theme and themesel (the ring gains lapis after
acme). Gates as G4. Feel review: .scratch/render/lapis/ (lapis.png, lapis-2x.png,
tags-focused-vs-unfocused-2x.png, a PanelSlide at 60 fps and a quarter).
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Three bundled Shadertoy passes beside Crt, each `Bloom|Vignette|Grain
0..3` (off by default, nothing drawn while off), in shaders/post/:
- Bloom: what is brighter than the page (a channel's linear peak over
0.75/0.7/0.6 and over the page's own + 0.15, so a light page does not
bloom) glows, 2/3.5/5% (§8.2's budget). The glow is a dual Kawase blur
in RGBA16F textures at half size and down, 3/4/5 steps by level
(shaders/bloom-down, bloom-up; Post.bloomChain), composited in linear
light and dithered.
- Vignette: round, from halfway to a corner, 10/18/28% at the far corners,
in linear light, dithered.
- Grain: a still, triangular-spread grain of 1.5/3/5 of 255 on
page-coloured pixels only, a logical pixel big; still, so it asks for no
frames.
Focus rule: the shell passes every bundled pass the rectangles of the tags
with their grips, the column and workspace tags, the notices and the
cursor (pardesSpare, at most 32, neighbours on one row merged), and a
bundled pass leaves them as they are; and a per-theme ceiling (pardesCap,
Post.capsOf) keeps the page's text and the selection's text at min(their
contrast, 4.5) under each pass at its strongest. User files get no
ceiling and no spared rectangles.
Fix found on the way: SDL GPU binds at most 4 KiB of a uniform block, so
every Shadertoy colour after iPalette (iBackgroundColor, iForegroundColor,
the cursor and selection colours, iPalette[>=4]) read zero. The prefix's
block is cut in three (Globals, Palette, Colors) with ghostty's names and
order, each pushed as a slice of the one struct; pardes's own block moves
to binding 3.
Tests: the caps hold over every native theme; each uniform slice fits
4 KiB; the prefix's members in ghostty's order across its blocks.
Gates: tty/gui unit-test and core-test pass; snap fails only
nested-optout; GUI goldens 01-08 byte-identical (09-18 wait on
wkzlsqvy, as in somtrmsz); web builds. Feel review material:
.scratch/render/{bloom,vignette,grain}/ (levels on forge, dusk, acme,
crops, a levels mp4).
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
separators and focus tints
Density: dp() in gui.zig draws every size given in pixels in logical
pixels (SDL's window display scale, rounded, at least one), as acme scales
Border, ButtonBorder and Scrollgap: the rules (rule_px), the tag rule, the
grip's ring, its dirty gap and mode bars, the rail's gap to the text and
its minimum, the thumb's inset, the rim, a bar cursor's minimum width,
underline and strikethrough thickness (the atlas is dropped on a scale
change), the rule-grab margin, and the Crt's scanline and mask periods
(pardesScale in the post prefix). Cell- and tagline-measured sizes stay:
the rail's width, Lift's blur and offsets, every motion; iResolution,
fragCoord and iMouse stay in the display's pixels, as ghostty's.
PARDES_TEST_SCALE forces a density in a harness (a test window is 1x
otherwise, whatever display it lands on) and sizes the test font with it.
Colours: a separator that stands off its page by less than 1.5:1 is lifted
toward the text to 1.6:1 (helix, atelier, paper; a theme with no page,
dark, is judged against #121212), and empty_col follows it. forge's own
rule already stands at 3.83:1; what hid it was density: 2 device pixels
on a 3x screen, now 6 (dp). A focused tag's tint closer than 1.5:1 to the
plain tag on a dark page (1.25:1 on a light one) is pushed further the way
it leans, as far as its text keeps its own contrast or 4.5: forge
1.23 -> 1.51 (#2d3440 -> #374253), and likewise dusk, orchard, ink,
lagoon, clay, harvest, spectrum, solarium, forge_soft; daybreak, atelier,
paper to 1.25. dark and helix gain a tint of their own (dark: #484566
under #c8c8c8, 1.54:1; helix: ramp 237 under 250, 1.65:1).
Tag caret: past a full row's end, the G3 glide box sits on the tag's right
edge, where the layer's caret and the pixel shell's are.
Tests: every native theme's separator >= 1.5 and every dark one has a
tint >= 1.25 with readable text; forge keeps its own border; the tag caret
glide box at a full row; at 2x the spine, tag rule, ring, rail start and
gap, and bar cursor double. Legacy-ThemeFile test strips helix's new pair.
Goldens: snapshot goldens change in colour rows only, the tints (orchard
#283a2f -> #314738 at boot, forge, helix and dark in theme/themesel).
GUI goldens: the harness's single Del of the renamed wide pane is refused
since ysqnkyoy (a rename counted as unsaved; fixed on the 9P line in
wkzlsqvy), so scenes 09-17 were recorded with that pane open and the file
was stale since the merge (08 and 18 also moved with ykvnltvs's full-row
tag wrap). The goldens here were recorded with that pane closed (as
wkzlsqvy will close it); against the parent's binary under the same
conditions they differ only in the tints: 01-13 forge's (#2d3440 ->
#374253, and the glyph edges on it), 14 ink's; 15-18 are byte-identical.
Until wkzlsqvy is merged, a run here fails 09-17. Each commit reproduces its own
recorded goldens on this machine (checked at kvtmqkyn). A test window is
1x unless PARDES_TEST_SCALE says otherwise, whatever display it opens on.
Prebuilt shaders refreshed from their sources.
Captures: .scratch/render/dark-borders/{before,after,compare,scale2,scale3}.
|
| |\ \ |
|
| | | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | | |
The core owns the motion, as Lift: animation.CursorGlide keeps the focused
cursor's four corners on springs (leading corners at the flavour's pace x2.4,
trailing ones x follow, so a jump smears and collapses; a long jump bows by
the flavour's arc), sampled at each frame's own time. A step of a cell or
less, insert mode, a focus change and any scroll (a file's view, a
terminal's output) land at once; a snap lands a glide under way too. The
quad is clamped to the focused pane when drawn (never its springs). Chrome
carries it on the wire (cursor_glide: bit 1 a cursor, bit 0 gliding;
cursor_alpha; cursor_quad, grid cells; cursor_idle_ms): the GUI draws the
quad as an overlay in the cursor's colour, at 85% (70% on the long
flavours) rising to solid as it lands, and hides the cells' cursors while it
does: one or the other every frame. Only the focused cursor glides.
Blink (CursorBlink, on by default in pixel shells) is the shell's: from
cursor_idle_ms and when the frame arrived, solid while typing and 500 ms
after, 530 ms halves with 80 ms eased edges, solid after 10 s idle, and
never while the window is unfocused or minimized or on a virtual clock. An
edge redraws the last frame with no core render (level B, blink_redraws);
an attached GUI blinks from the same field without a frame per edge.
Tests: snaps a cell, glides a jump with smear and bow, arrives under a pixel
by 150 ms on smooth and lands exactly, shifts with a scroll; blink holds,
eases, stops; the core glides a jump (ge) frame by frame (gliding exactly
while it moves, alpha rising, exact at rest), snaps a step (j) and a switch
to insert mid-glide; a terminal's scrolling output lands its cursor; wire
round-trip of the cursor record.
Shared files: src/animation.zig, src/pardes.zig, src/config.zig (toggle
CursorBlink), src/surface.zig, src/detached/wire.zig.
|
| | |/
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
"Unix TCP and QUIC share one listener" failed 17 of 360 runs under load
(12 parallel copies), always at p.fs.opens: the client had hung up but its
connection's task had not yet seen it, reset() then cut the connection, and
the releases the hangup owes were refused as the old editor's. The test's
replacement editor is the same editor, so those opens stayed. It now waits
(resting, with its own deadline) for the runner to empty before reset:
0 of 360 after.
fs-test -Dquic=true failed too, at two points. A session Looking at its own
tree through a QUIC mount is features.txt's documented "left as they are"
case (QUIC is answered on the editor's thread); that check is dropped with a
note. The /screen check asserted body text that the view may have scrolled
past (2 of 7 runs); it now asserts the pane's tag. 10 of 10 after.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
|
| | |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
The README's log line names newcol, delcol, ask, restored and restoredcol;
it says what $m is under 9ns --unix; and a build that embeds no sources no
longer lists src/ (derived from the build, and tested). fs.md says what the
rest of a typed line does after Kill for each shell (fish runs on, bash
abandons it), that Exec <text> in a .py pane runs a command and never the
REPL, and why appending to a tag wants printf and a leading blank.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
|
| | |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
A ctl Edit that missed answered `Edit: no match for regexp "Edit
/nomatch/d"`, quoting the whole program; it now names the address that
missed (`no match for regexp /nomatch/`) and quotes no line after. An s
on an empty dot says `no substitution: dot is empty`. A \\1 is blamed
only once its pattern has matched, as before. tags.md says & is special
in s and not in c, a or i, as in sam.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
|
| | |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
A restored text pane came back with its caret at its view's top, whatever
had been selected. The dump now keeps each text pane's dot, q0 and q1 as
acme's keeps a window's, and Restore puts it back without moving the view
it kept. Two look-walk tests that restored and walked on now start from the
match they were on.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
|
| | |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
A script could read and write a column's tag but not act on the column.
col/<serial>/ctl takes Delcol, Joincol, New and Tty, each acting on that
column as from its tag; col/<serial>/exec runs a word as a middle click in
the tag; rmdir col/<serial> closes an empty column and refuses one with
panes (ENOTEMPTY, an err record saying why). The root ctl's refusal of
Delcol and Joincol points at col/<serial>/ctl. A dump keeps each column's
serial and Restore logs restoredcol <old> <new>; the dump golden gains
them. Documented: Joincol's survivor, the column on the right, keeps its
serial and tag.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
|
| | |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
A terminal's body came back as the screen's rows, a long line cut where the
terminal wrapped it and the last line with no newline. The body (and a
terminal's Save, and the length its ctl reports) now joins wrapped rows by
ghostty's wrap flags, as pty/run's output does, and ends the last line with
a newline.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
|
| | |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
Writing a serial to /focus gave that pane the keyboard but left the active
column where it was, so pane/new under Placement acme went elsewhere, and
/layout's active named the keyboard's column rather than where a new pane
would go. A focus write now sets the active column as the user's click
there would, under either Placement, and /layout's active names the active
column, which pane/new and a look place into.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
|
| | |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
Sixteen panes was far too few for a real session. MAX_PANES is now 64 on a
desktop and stays 16 on the board; the 48 more slots cost about 3.7 KB each
in fixed tables (the core 1.33 to 1.45 MB, its surface 19 to 72 KB), and a
pane itself (84 KB and its terminal) is allocated only when it opens. At the
cap, pane/new fails with `pane/new: no pane slots: 64 max` and an err
record rather than a bare ENFILE, a 9P look or exec that would open a pane
fails its write with the same words and reads back empty, and New, Tty,
Tutor and Alt-n say it on the message row (their ctl writes fail with it).
Co-Authored-By: Claude Opus 5.5 <[email protected]>
|
| | |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
On aab, /a+ab/ matched but /(a+)ab/ and /(a*)ab/ missed, and so did
(.+)_area and ([a-z_]+)_area, in addr, Edit and look alike. mvzr's hasAlt
counts a group's own ) as an alternative, so every group with pattern after
it takes matchGroup's alternatives branch, which never tries a repeat's
shorter matches. No newer mvzr fixes it (trunk is the pinned commit), so
the build patches the fetched source as it does the step budget,
anchor-checked: when the rest fails after a group, the group's shorter
matches are tried, longest first. docs/mvzr-group-backtrack.md is a report
for upstream.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
|
| | |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
/col/<n> named a column by its index, which shifts when a column left of it
closes: exactly what scripts trip on. A column is now /col/<serial>, its
serial kept while it lives and never reused; /layout lines give serial and
index (`<serial> <index> ...`), active names the serial, /index's last
field is the column's serial, and the log says newcol and delcol with
serials. Docs, the skill and the tree's README say so.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
|
| | |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
A press on a pane's last row began a seam drag, so the row could not be
clicked or swept like the rest of the text (rsearch dragged the handle out
of the way first). Now no row of text is a handle: in the GUI a press on
the 2 px rule between two panes drags their seam, and anywhere the grip
does, as acme's button moves a window -- dragged up or down its own column
it moves the pane's top, either pane down to its tag alone (acme's
coldragwin), dragged down inside itself too. The hover hint over a last row
is gone; column edges resize as they did. Scripts that dragged a seam drag
a grip instead and match their goldens; six goldens lost the hint or moved a
cursor to the clicked text, re-recorded by name.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
|
| | |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
A script could not see where the panes sit or edit the tags a person
clicks in. /layout lists each column, its index, x and width in cells,
current or not, empty or full, and its panes' serials, then the active
column; /tag is the workspace tag and /col/<n>/tag a column's, read and
written as a pane tag is (one line: a newline written in is a space, and a
truncating write drops the one ending it); /index's lines end with the
pane's column; the log says newcol <n> and delcol <n>. acme serves no
column files, and the docs say so.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
|
| | |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
A session running with Placement pardes came back from Restore as acme: a
dump kept the layout and the theme but no setting. It now keeps every
setting line that differs from a fresh session's, as the root ctl reads it,
and a Restore applies them; the theme stays where it was kept, the font the frontend's,
and REPL bindings are still dropped. The dump golden gains the three the
snapshot harness sets.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
|
| | |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
`Lift on` over ctl on a terminal answered "unknown control message" while
Config listed Lift as unsupported, and the ctl's DumpDir line read bare while
Config showed the path in effect. A setting word this frontend lacks is now
refused as `Lift is GUI-only` (GripWidth too), and DumpDir reads back the
directory in effect, as Config does.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
|
| | |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
takes no name
`echo Del > pane/6/exec` just after pane 6 closed failed EACCES: the shell's
lookup failed, it tried to create the file, and the engine refused every
Tcreate as a permission error. pardes now takes Tcreate itself: refused as
before (acme's fsyscreate refuses it too), ENOENT in a pane that has
closed. Renaming a terminal was refused with only EPERM; it now says a
terminal is named by its shell's directory, worded so a mount still maps
it to EPERM.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
|
| | |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
A one-line send (print(1)) to Python 3.14 stopped at ... and needed another
Enter: its REPL takes a bracketed paste, and an Enter read in the same read
as the paste is part of the paste, one line or not (checked in a real pty).
Into a REPL that asked for bracketed paste, the Enters (two for an open
block) now wait for its next output, its answer to the paste, or 250 ms
with nothing. fs-test runs python3 in a real pty and checks a one-line exec
prints at once; the docs' pty/data recipe says to send the Enter apart.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
|
| | |
| |
| |
| |
| |
| |
| |
| |
| | |
`echo X > tag` stored X and a trailing newline, which drew an empty tag row.
After a truncation the newline ending each write is held back until more
text follows or the open is released, so the one ending the whole of it is
dropped and any other stays; `>>` keeps what it is given.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
|
| | |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
acme's Del asks winclean first and Delcol colclean (exec.c del, delcol):
unsaved text is warned about, and the same word again closes. pardes closed
at once. Both now refuse once through the one-warning-per-word mechanism
Exit uses, from keys, tags, exec and ctl alike. A pane dirty only by a
rename, or an empty one that never held a file, has no text to lose and is
not asked about, and a scratch or a command's output under 100 bytes is not
either, as acme's winclean passes a small unnamed window.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
|
| | |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
Their refusal named only file panes, so text typed into a +New scratch went
unasked about and was lost. A scratch with text counts as unsaved as a file
does (acme's winclean asks about an unnamed window too). The refusal a ctl
write gets now reads as the message row does, `<names>: Modified (Exit
again to discard)`, instead of a second "discard them all" wording.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
|
| | |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
A Dump into a DumpDir it could not write, or a Restore of a file that is
not a dump, answered a ctl write with rc 0 and only a message, and the
Restore warned about unsaved panes before it ever looked at the file. The
hosts' dump write now fails the waiting 9P write with EIO (the late failure
a Save uses), naming the path and the reason in the log, and Restore parses
the file before its unsaved-panes refusal, failing with `not a pardes
dump`.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
|
| | |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
Bare Placement and BootShell flip, which is pardes's convention for a word
that chooses (Crt does too), but nothing said so, and "bad value in control
message" never said what would do. A refused value now says `takes acme,
pardes` (every switch and choice setting), /commands lists each such
setting's values in a fourth field, and config.md and fs.md say that bare
steps to the next. Motion and ShaderAnimation stepped nowhere bare and now
step like the rest.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
|
| | |
| |
| |
| |
| |
| |
| |
| |
| | |
`answer z` to a question offering a and b succeeded, sent nothing and
dropped the question; so did Del's `answer x`. The ctl now takes only an
offered choice or -, refuses anything else with the choices it takes
(`answer takes k j or -`), and leaves the question asked.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
|
| |/
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Tags wrapped one cell early to keep a cell for the caret past a full row,
so a tag that exactly filled its column broke as De / l. acme's frame wraps
a box only when it is wider than what the row has left, and frptofchar
clamps the tick past a full line's end to the frame's edge. Tags now wrap
at their full width; the caret past a full row sits at the tag layer's
edge, and on the pane's last cell in a terminal grid, which has none past
it. Two tiny-screen tests collapse their tags, as the others do, and the 41
goldens that moved were re-recorded by name after the same check: rows
shift back up under the shorter tags and nothing else changes. chordcut's
file-body clicks moved back with them.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
|
| |\ \ |
|
| | | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | | |
The flavours looked alike because Lift, the only motion that read them,
moves a shadow a few pixels: overshoot and wind-up were sub-pixel. By design
now: crisp leaves at full speed and never passes its mark; smooth (the
default) eases in and out in twice crisp's time, a slide arriving in 208 ms
(inside §8.1's 220); bouncy passes its mark by ~30% and settles twice;
playful winds up, passes by ~40%, and stretches and squashes, text included
(the user's choice). Small motions are exaggerated by the flavour's gain.
Motion gains launch, gain, span and norm, and ease(u)/speed(u) for moves of
fixed length. The notice drop follows ease() over its fall (alpha never
behind its position) and stays inside its pane's body past its row. Panel
tracks carry the flavour in Track.motion (the old padding byte; macOS header
name follows); opening and moving slides, zooms and rises follow it over
span x their frames; landed, a pane is exactly its target; closing keeps
its own exit. A pane past its mark never takes a neighbour's click; a
rising one stays in its box.
Tests: each flavour's lift trajectory distinct; flavour character; exact
landing bit for bit; a stretched pane's drawn cells map back; the overshoot
hit rule; the vertical clip at peak; legacy tests pinned to crisp. GUI
golden 18-mid-transition changes (the retuned smooth slide at frame 6).
Shared files: src/animation.zig, src/Presentation.zig, src/Messages.zig,
src/macos.zig, src/config.zig, src/pardes.zig tests, src/ninep/screen.zig
test, docs/effects.md, docs/config.md.
|
| | | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | | |
rules
acme takes plan9port's own colours (acme.c iconinit, draw.h): selections
#eeee9e in the body and #9eeeee in the tag, black ink; exec and look sweeps
#aa0000 and #006600, white ink; a #99994c scrollbar under a #ffffea thumb;
black rules; a #8888cc tag/body rule and column button.
Every theme: the grip is acme's button, its tag row's full height, in one
scroll column with the scrollbar (rail_px, 12 at a 17px tagline, scaled,
times GripWidth, a percent, default 150; same x0/x1 to the pixel):
focused clean = solid box; focused dirty = box_dirty filled to a box ring
(acme's modbutton); unfocused clean = a box_border ring round the tag's
ground; unfocused dirty = box_dirty a pixel inside that ring. The grid, which
has no ring, marks dirty with a bold * on box_dirty in the grip's second cell
and fills an unfocused grip halfway to its ring. Regions carry a dirty flag.
Column buttons are the same shape, solid. 2px rules between columns and
stacked panes (inside the tag band's slack), none at the window edge; a 1px
tag/body rule halfway between tag and page.
Theme data: tag_sel_bg, sweep_bg/fg, tag_rule, rule_px, rail_px, box_border,
box_dirty. Chrome: rule_px, tag_rule, rail_px, grip_border, grip_focus_ring;
a comptime guard on Chrome's layout forces a wire bump once v8 ships.
Structural rules are exempt from the focus-indicator rule (docs/effects.md).
Tests: acme widths; stacked rule in the slack at two tagline sizes; every
grip-column pixel is band, button, ring or rule, and the button shares the
scrollbar's x0/x1 (4 metrics x top/bottom x focus x dirty); the four grip
states distinct in every native theme with a non-colour dirty cue in the
grid; wire round-trip of the new fields.
Shared files: src/colors.zig, src/surface.zig, src/body_layer.zig,
src/tagline.zig, src/detached/wire.zig, docs/themes.md, docs/config.md,
docs/effects.md, 21 snapshot goldens (the grip cells only),
test/gui-goldens.txt.
Motion flavours differ by design, and drive notice drops and pane moves
|
| | | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | | |
Rows under the first are the tag band's fill (the focused tint when the
pane is focused), for pane tags and column tags alike, on every shell,
since each draws the grid's cells. The grip region still spans every
tag row, so a press there grabs the pane, as a press anywhere in acme's
button column does (acme.c: t->scrollr is the tag's full height).
GUI goldens 12-18 change only in the grip rows under the first.
|
| | | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | | |
recedes the other panes (InactiveDim)
Motion off|crisp|smooth|bouncy|playful is one parameter set (animation.Motion)
every fx animation reads. One focus spring per pane drives both the lift and
the dim, at the flavour's pace; a grid snaps.
Lift drops glow and surface. A shadow falls on pane bodies and rails only,
capped so text and the selection keep min(contrast, 4.5); rim is a hairline
along the focused tag's top. auto is a shadow on a light page; on a dark page
the core recedes the unfocused panes' text (InactiveDim, ported from 2e4d97f,
default 30 under auto) with the same floor. Tests: focused text contrast is
never below unfocused in any style, dim or theme; the focused pane's cells and
tag are untouched by a dim.
Shared files: src/config.zig, src/builtins.zig, src/ninep/ctl.zig,
src/surface.zig, src/detached/wire.zig, docs/config.md,
test/snapshots/builtins.snap (one more wheel for the longer help).
|
| | | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | | |
The user wants Lift to read on dark themes, where a shadow has nothing to
darken. `Lift shadow|surface|rim|glow|auto` (`on` is auto, bare flips
auto and off): surface lightens the lifted part's ground about 5.5%
(Material-dark), rim is a thin soft light off its top and left edges,
glow a faint halo in the theme's accent (Chrome.accent, the focused box
colour), auto a shadow on a light page and surface with half a rim on a
dark one (by the page's luminance). Rim and glow are the soft kernel in a
light colour (no pre-warp: coloured light is laid on as is, within §8.2's
budget); each style is capped per theme so text keeps min(its contrast,
4.5) (tests: darkening and lightening over the native themes). The style
travels in the palette (Chrome.lift_style, one byte on the wire). Config
reports and ctl reads `Lift <style>`.
Shared files touched: config.zig, builtins.zig, ninep/ctl.zig,
detached/wire.zig (palette byte), gui.zig. Not touched: pardes.zig,
Messages.zig, mouse.zig.
|
| | | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | | |
Review (and the coordinator): Lift stepped with the core's 16 ms ticks, so
a 144 Hz display held each shadow for 2-3 refreshes. The lift springs are
now sampled at each frame's own time (p.now_ns), and Pardes.continuous()
reports a render-time animation in motion: while it is, the pump draws
every loop (a 1 ms wait takes only the input there is) and the present's
vsync paces it at the display's rate. They left nextWake; the stepped,
frame-indexed animations (transitions, message fades, the theme fade) and
every golden are unchanged. With PARDES_TEST_CLOCK, each loop of a moving
render-time animation moves the virtual clock by a display frame at
PARDES_TEST_HZ (default 60), so a 144 Hz series is deterministic: a focus
switch is 51 distinct frames at 144 Hz. Test: renders 6.9 ms apart give
rising lifts; settled, no frames. The tty never lifts (GUI capability).
Shared files touched: pardes.zig (continuous, pump), gui.zig.
|
| | | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | | |
`Lift` (a GUI toggle, capability lift) lifts the focused pane on a
critically damped spring (animation.Spring: closed form, about 240 ms to
settle, velocity kept across retargets, settled = no frames) and floats
notices. The core puts the lift on the regions (Region.lift, on the wire);
the GUI casts from it: a soft shadow is decor, an erf rectangle on one
quad grown by 3 sigma (decor.frag, flag 0x10000000), in the quad's own
space so a track's transform carries it; darken-only, the caster's rect
left alone, alpha pre-warped for linear light and IGN-dithered. Cast last
in its group, so a neighbour's rails and rules darken with its text; a
notice's before its rule. Strength is capped per theme so text over the
darkest shadow keeps min(its contrast, 4.5) (test over the native themes).
Opt-in until the focus lift/dim default is decided. Feel review material:
docs/effects.md. Test-mode PARDES_TEST_SERIES keeps every captured frame.
Shared files touched: pardes.zig (two fields, one nextWake line),
detached/wire.zig (lift on the region), config.zig, builtins.zig
(capability), gui.zig. Not touched: Messages.zig, mouse.zig, tty,
host_io.
|
| | | |
| | |
| | |
| | |
| | |
| | |
| | |
| | | |
The scroll margin reveals text; with none off screen there is nothing to
reveal. ensureCursorVisible and a centred look both leave such a pane at its
top. A longer file keeps helix's clamp (hxdiff and hxparity unchanged).
Co-Authored-By: Claude Opus 5.5 <[email protected]>
|
| | | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | | |
it as before
Placement and BootShell are one kind of setting now, a word from an enum,
set, flipped bare, and reported by one arm.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
|
| | | |
| | |
| | |
| | |
| | |
| | | |
acme paints it
Co-Authored-By: Claude Opus 5.5 <[email protected]>
|
| | | |
| | |
| | |
| | | |
Co-Authored-By: Claude Opus 5.5 <[email protected]>
|
| | | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | | |
makenewwindow puts them
Newcol makes an empty column; closing a column's last pane leaves it empty with
the keyboard on its tag; Delcol and Joincol alone take a column away; the
session's last pane closing quits. The +New stand-in and replaceStillborn /
stillborn_joiner are gone. Every new pane goes through exec.placeNew, which
follows acme's makenewwindow (active column, empty column whole, blank space,
halving the biggest) or, with Placement pardes, the old rules. ColumnTags is
gone: column tags are always shown. A grip drag shows acme's box cursor.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
|
| | | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | | |
With the line run under job control (the change before), the job running
has a group of its own, and Kill's SIGTERM to the tty's foreground group
stopped only that job: of `sleep 30; touch x` the touch still ran. For a
command pane the hosts now signal the shell's group as well, so the whole
line stops, as it did; a line typed at a prompt still loses only its
foreground job. The test forks a real pty for both halves: a background job
outliving its command and the pty's hangup, and a killed line not running on.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
|
| | | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | | |
A script holding serials from before a Restore could not find its panes: the
replacement numbers them afresh. The dump now keeps each pane's serial (0 in
older dumps), and the replacement's log says `restored <old> <new>` for each
after its `restore <path>`.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
|
| | | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | | |
After Restore a dogfood agent's command panes were fish shells under a stale
`(make) exit 0` tag. The dump's terminal record now keeps a command pane's
line and status, and Restore brings it back done: what it printed, its exit,
no shell and no rerun.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
|
| | | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | | |
A script could not answer the several-REPLs question, which only a key
could. Every question a pane asks on its notice band (which REPL takes an
exec, Del's side from the keyboard) is now logged as `ask <serial> <what>
<choices>`, and `answer <choice>` on the pane's ctl answers it as that key
would, `answer -` taking it back as Esc does. One function answers for a
key and for the ctl.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
|
| | | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | | |
A dogfood agent's `def` sent to python3 sat open at the continuation prompt:
a block whose last line is indented is not over at one Enter, pasted into
3.13's REPL or typed into the old one (checked against python 3.14 in a real
pty, both ways). A send to a Python REPL now adds that second Enter, and the
pty/data recipe in the docs and the 9P skill says to.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
|
| | | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | | |
A dogfood agent's `Tty bash` pane came back from Restore running fish: the
dump kept its directory but not the shell it was opened on. The dump's
terminal record now carries that shell (empty for the configured one, as
older dumps read), and Restore starts it again.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
|
| | | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | | |
A dogfood agent's background jobs died when the command that started them
finished, even under nohup. The command's shell leads its terminal's
session, and on its exit the kernel hangs up the terminal's foreground
group, which with job control off is the shell's and every job's. The line
now runs with job control on (bash, sh, dash, zsh, ksh -m; fish status
job-control full), so a job has a group of its own and lives on, printing
below exit N, and survives the pane closing. While a job holds the pty the
pane is not reused, so the directory's next command gets a second pane
(cmdexit's golden, re-recorded by name).
Co-Authored-By: Claude Opus 5.5 <[email protected]>
|
| | | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | | |
A dogfood agent ran `exit 3` through pty/run: the reader got ENOENT, and
the log went straight to del. The hosts now read a shell's exit status at
its pty's end as they do a command's; a run waiting on the line answers
`exit 3` with what it printed, the log says `exit <serial> 3` before
the pane's `del`, and an open run still stats after its pane is gone
(cat fstats its input). Pins cloud9 f35b7ed, whose stat of an open fid names
its open. Writes to a gone pane's pty/data, held open or not, fail ENOENT.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
|
| | | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | | |
A dogfood agent wrote winsize 100 30 to pty/ctl and pty/status went on
reporting the pane's grid, and the status line had no newline to end it.
The size winsize sets is kept until the pane resizes and gives the pty its
grid again; ctl's winsize read back and status both report it, and status
ends with a newline.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
|