| Commit message (Collapse) | Author | Age | Files | Lines |
| |
|
|
|
|
|
|
| |
The radio-browser lookup and the manual station creator no longer write .m3u files at pick time. Picks become url tracks in the queue, carrying the station name, uuid, and favicon as track properties, and play immediately. The display and cover-art layers read the properties first and fall back to the on-disk metadata, so existing station files keep working.
Saving is the normal playlist save, now on w. The radio feature's S=stop rebind had silently shadowed the old S=save binding. An all-stream queue saves into the MPD playlist dir, and the station name pre-fills the prompt with no -Radio suffix. A custom emitter writes the station metadata back out as .m3u comment lines, since the stock EMMS writer emits bare URLs and would lose names and cover art on reload.
I removed the write-at-pick machinery (station-m3u, write-stations, disambiguate-name, the -Radio filename suffix) and the orphaned safe-filename helper. An empty name at the save prompt now signals an error instead of writing a hidden .m3u.
|
| |
|
|
|
|
|
|
|
|
| |
Phase 3 is the fancy visual layer from the prototype. In a graphical frame with cj/music-fancy-ui on, the player draws a now-playing hero (cover image, a serif amber title, a subtitle, and a progress bar) with thumbnailed serif rows below it. A TTY frame, or the toggle off, falls back to phase 1's plain text.
The progress bar had a rendering but no data source. I added cj/music--mpv-get-property, which does an IPC round-trip that reads mpv's reply, so a file's bar fills from percent-pos. The old cj/music--mpv-command only sent commands and threw the reply away. A stream has no duration, so it shows "on air". The bar redraws on a ~1s timer that runs only across a playing span and skips when the buffer isn't visible.
I split cj/music--header-text into shared playlist and controls pieces with a text-versus-fancy dispatcher, so the two render paths build from one place and can't drift. The hero replaces the Current line when a track plays. Rows gain a cover thumbnail and a serif name. Cover art comes from phase 2's non-blocking cj/music-art--for-track. A separate idle-timer pre-warm fetches the real art off the render path, so a slow favicon host never freezes playback start.
The serif family defaults to the nov reading view's, and the amber comes from the themed warning face so the dupre theme owns it. The block-bar renderer has Normal, Boundary, and Error tests. The images, faces, and the bar advancing are a live check. The full suite is green.
|
| |
|
|
|
|
|
|
|
|
| |
Phase 2 gives each track a local cover-image path so phase 3's GUI has art to draw. A radio station uses its logo, a local file a sibling cover image, and anything without either falls back to a shipped vinyl placeholder.
I consolidated the .m3u parse into one richer cj/music--m3u-entries that reads :name, :uuid, and :favicon per station. Phase 1's cj/music--m3u-labels is now a thin projection of it, so names and art share a single cached disk read. New stations capture their favicon into a #RADIOBROWSERFAVICON line at creation, so most need no lookup later. A legacy station with only a UUID resolves its favicon through a byuuid call.
The render path never touches the network. cj/music-art--for-track reads only the cache and returns the placeholder until art exists. cj/music-art--ensure does the blocking fetch off that path. A fetched response is validated as an actual image before it's cached, so an HTML error page or an empty body becomes the placeholder, not a poisoned cache entry. Only http and https URLs are fetched, so an external favicon field can't reach a file:// resource. Art lands under data/music-art/, keyed by UUID or a file hash. cj/music-clear-art-cache empties it, with no automatic expiry.
The pure helpers carry the tests: the parser, the cache key, the favicon URL, and the image validation, each with Normal, Boundary, and Error cases. The fetch, the byuuid lookup, and the placeholder fallback are verified live against a real station. Local files use a sibling cover image for now. Embedded-tag extraction is deferred. The full suite is green.
|
| |
|
|
|
|
|
|
|
|
| |
The EMMS playlist showed the raw stream URL for every radio track, so the buffer read like a debug log. This is phase 1 of the fancy player: real names, still plain text. It ships on its own and becomes the fallback for the image and GUI phases.
I split the old cj/music--track-description into a pure, name-only cj/music--display-name that the header's Current line and the row renderer both call, so the two never drift. A url track resolves to its #EXTINF label (read once from all the playlist .m3u files into a cached map) or a tidied host. A file shows Artist - Title or its filename. The row renderer adds a dim nerd-icon glyph and the duration as right-aligned meta with an :align-to space, so it survives a window resize. The header line stays clean: just the name plus an on-air or duration suffix.
The pure helpers carry the tests: display-name, tidy-host, m3u-labels, bar-fill, format-meta, Normal/Boundary/Error each (32 tests across four files). The glyph, the aligned meta, and the disk-backed name map are the thin composition, verified live against 44 real stations.
The progress bar's visual and its live elapsed source come in phase 3. The bar-fill helper is the tested pure core it will feed. The full suite is green.
|
| | |
|
| |
|
|
|
|
|
|
|
|
| |
I reviewed the fancy music-player UI spec, then dispositioned all seven findings: five accept, two modify, none rejected. Two were blockers.
The progress bar had a chosen rendering and cadence but no data source: a stream has no duration, and for a local file the elapsed position isn't wired. The playing-time display is off and the mpv IPC helper is send-only. I narrowed it to mpv's percent-pos over the socket the seek commands already use, with streams rendering "on air" and no fill. That avoids reviving the EMMS timer I turned off on purpose.
The named row renderer, cj/music--track-description, is also the header's now-playing source and EMMS's description function, so glyph and meta would have leaked into both. I split it into a pure name-only helper the header and the row share, with the glyph, aligned meta, and image added on the row alone.
The rest tightened scope: favicon-at-creation applies to search-created stations only, fetched art is validated before caching, meta right-aligns with :align-to so it survives a resize, the placeholder is a shipped vinyl SVG with per-station tinting left to vNext, and the nerd-icons dependency gets a require and a TTY fallback. I flipped DRAFT to READY.
|
| | |
|
| |
|
|
|
|
|
|
| |
A spec for the hi-fi look Craig picked from the prototype: the EMMS playlist buffer gains names instead of stream URLs, cover art, a serif now-playing hero with a progress bar, and a warm amber palette, degrading to plain text in a terminal frame.
I verified the cover-art path is reachable (radio-browser stations carry a favicon URL, retrievable at search time or by UUID) and framed the work as three layers: a name and text base that ships value on its own and doubles as the terminal fallback, cover-art fetch and cache, then the fancy GUI render. Five design decisions are open, each with a recommended call.
The three-direction prototype (minimal, fancy, modern) lands beside the spec as its companion.
|
| |
|
|
|
|
|
|
| |
I turned the radio-browser lookup into a Radio row in the playlist buffer: n searches by station name, t searches by tag/genre, m enters a station by hand. Tag search is new (it was a vNext item), and both name and tag hit radio-browser's search endpoint with a name= or tag= field.
Freeing n and t moved two keys: single mode goes from t to s, and stop goes from s to S. The header gains a Radio row and the Mode row now reads [s] single. Created station files carry a -Radio suffix (Adroit_Jazz_Underground-Radio.m3u).
The pure pieces and the search-URL field are unit-tested (20). Name and tag searches are live-verified. The picker and playback stay a manual check.
|
| |
|
|
|
|
| |
I wired up the interactive side of the radio-browser lookup: cj/music-radio-search, bound to S in the EMMS playlist buffer (s stays emms-stop). It searches, lists the matches annotated with codec, bitrate, country, votes, and tags, and lets you pick several one at a time. Selection is a completing-read loop with a "[done]" sentinel that removes each pick from the pool, so a station name with a comma can't be mis-split. Each pick is written into the save directory (no-URL stations skipped and named, colliding filenames disambiguated by UUID), then the selection plays through mpv, interrupting whatever was on.
The dedup and write-collect logic are unit-tested. The picker and playback are left to a manual check.
|
| |
|
|
|
|
|
|
| |
I built the first phase of the radio-browser lookup: the pure pieces and the network client behind the search command, with no UI yet. It lives in modules/music-config.el, alongside the existing radio-station creator.
The client is url.el plus json-parse-string, trying a pinned host and falling back to one from /json/servers. The pure layer parses a response into station plists, and a non-JSON body signals a clear user-error rather than a stack trace. It picks a station's stream URL (url_resolved, then url), emits the .m3u in the existing radio format with the radio-browser UUID, formats the completion annotation (codec, bitrate, country, votes, tags), and disambiguates a colliding filename by UUID. Names are newline-stripped so an odd one can't inject extra m3u lines.
The pure pieces are unit-tested (14). The network client is smoke-tested against the live API.
|
| |
|
|
|
|
| |
I reviewed the spec and folded the review back in. The review found seven gaps, one blocking: completing-read-multiple splits its selection on commas, and radio-browser station names contain commas. A comma'd name would be mis-selected silently.
Resolving all seven: selection is now a loop-based single-select that never round-trips through a delimiter, the emitter skips a station with no usable stream URL, same-name picks in one search disambiguate by UUID, the server client has a defined fallback, and create-and-play interrupts current playback. The annotation format is codec, bitrate, country, votes, and tags, with no play count. Decisions read 5 of 5 and findings 7 of 7, so the spec flips to READY.
|
| |
|
|
|
|
|
|
| |
On Wayland the video start path signalled any running wf-recorder with pkill -INT and then waited a fixed 0.1s before launching a new one. Releasing the compositor capture takes longer than that, so the new wf-recorder launched into a still-held grab, died immediately, and ffmpeg finalized a ~0.5-second fragment .mkv. Seeing nothing record, I'd press the key again and burst out a pile of fragments until the capture finally freed.
I replaced the fixed wait with a poll that waits until no wf-recorder remains (capped at 2s), the same move the stop path already made when it swapped its own fixed wait for cj/recording--wait-for-exit. Two supporting changes came with it. wf-recorder stderr no longer goes to /dev/null, so a failed grab shows up in the process buffer. And the sentinel now tells a ~0.5s failed start from a real stop, saying "failed to start, try again" instead of silently clearing, so one failure doesn't snowball into a blind-retry burst.
The poll and the fail-fast timing are unit-tested. The live capture needs a manual check.
|
| |
|
|
|
|
| |
The prototype is a standalone HTML mockup of the four minibuffer screens for the radio-browser lookup: query, station list, multi-select, and created-and-playing. I drew it with real jazz-search data in the vertico and marginalia style. It shows the two candidate-annotation formats the design picks between. The spec's References section links to it.
This sets the convention for a spec's visual companion: docs/specs/<slug>.prototype.html, tracked alongside the spec.
|
| |
|
|
|
|
| |
A spec for searching radio-browser.info from Emacs and turning a selection into a playable radio .m3u, reusing the existing writer, multi-directory sourcing, and mpv path. The player can already read and play radio playlists but has no native way to discover stations, so every station is hand-entered from a browser.
I verified the API live (server discovery and station search) and matched the output to the existing radio .m3u format. All four design decisions are resolved: built-in url.el, multi-select writing one file per station, saving into the MPD playlist directory, and create-and-play. The spec has two build phases and is ready for spec-review.
|
| |
|
|
|
|
|
|
| |
The MPD radio-stream playlists moved into version control at ~/.local/share/mpd/playlists/, while the 24 local-library playlists stay at ~/music/. MPD has a single playlist_directory and its load only sees that one, so the union has to happen at the Emacs layer.
I added cj/music-m3u-roots, a precedence-ordered list of directories the reading path unions (get-m3u-files, basenames, select, load). Missing directories are skipped. On a basename collision the earlier root wins, so a local playlist shadows a same-named radio one. Saving and radio-station creation still target the single cj/music-m3u-root. Radio .m3u hold stream URLs, which the track reader and the mpv subprocess already handle, so nothing else changed to play them.
The two tests that pinned the old single-directory contract now bind the list. Their "missing directory signals an error" cases became "missing directory is skipped" to match the new behavior.
|
| |
|
|
|
|
|
|
| |
dirvish keys its media thumbnail cache on the exact preview-window pixel width (thumbnails/<width>/<md5>.jpg). Fast image thumbnails finish before the window settles, so their width is stable. Slow webm generation loses that race: the jpg is written at one width, then redisplay recomputes the width, and jitter across a floor boundary looks it up in a different bucket, so it misses, regenerates, and flashes blank.
I quantize the computed size to a 100px bucket (cj/dirvish-thumb-width-bucket) so jitter maps to one stable cache key. It's a filter-return advice on dirvish-media--img-size, added once dirvish-widgets loads. It's a local workaround for the upstream cache design. If the settle swing turns out larger than one bucket, widen the bucket or fall back to a width-independent hash.
The quantize math is unit-tested. The live preview render needs a manual check.
|
| |
|
|
|
|
|
|
| |
nov-mode's reading cycle opened on sepia and ran sepia, dark, light. I reordered it to dark, sepia, light and made a fresh EPUB open dark.
pdf-view only had a binary midnight toggle. I added a matching palette layer: a fresh PDF opens dark, and c cycles dark, sepia, light, none (C selects by name, M also cycles). Each palette is a foreground/background pair fed to pdf-view-midnight-minor-mode, so sepia and light are that same duotone with warmer and lighter colors. The pdf colors mirror the nov palettes so EPUBs and PDFs read alike.
Pure name-to-colors and cycle logic are unit-tested. The live render needs a manual check.
|
| |
|
|
|
|
| |
The spec's package-scope premise is false against the generator. It assumes the non-org bespoke packages keep their curated dupre seeds, but apply_default_face_seeds overwrites every bespoke face with the Emacs-default snapshot whenever emacs-default-faces.json is present, so org opens empty and the rest open on light-theme hexes. "Keep the curated defaults" and "the seeded page reads as a coherent dupre" then contradict, and the dupre-revised.json emitter can't be pure-Node because the non-org colors live in Python.
Phase 1 stands. I paused Phase 2 pending a spec revision that picks the direction: reseed the non-org packages from the curated dupre dicts, or keep the snapshot hexes.
|
| |
|
|
|
|
|
|
|
|
| |
I turned the coloring guide's role/seed table into an executable engine. A new pure module, seed-core.js, holds the seed model as data: a named palette whose accent shades are OKLCH-generated from the dupre anchors (reusing the colormath core), the role-to-treatment table, and a face-to-role map per owned tier, plus a pure seed() that projects the table onto syntax, UI, and org faces.
seed() owns three default sources: syntax, UI, and org among packages. It returns packages.org-mode only, so the roughly twenty non-org bespoke packages keep their curated APPS seeds untouched. The output already matches the shape the import path consumes, so phase 2 can wire it to open-seeded without a new format.
Builtins land on blue-grey and calls on a quieter gold, the two shades dupre lacked. Definitions come out gold and bold, state faces tint the background with no foreground, links underline, and the org heading ramp descends in lightness with level 1 strongest.
The module inlines into the page below the colormath core like the other pure cores, so the browser runs the code the Node tests import. #seedtest asserts the representative faces resolve correctly and that magit keeps its curated seed. test-seed-core.mjs covers the model, each tier, and seed()'s purity.
|
| |
|
|
|
|
| |
State-change log lines were written inline (org-log-into-drawer nil), where a line landing between a heading and its DEADLINE/SCHEDULED line broke org's planning-line parser and dropped the entry from agenda views. org also logged no-op "State X from X" transitions that carry no information.
Set org-log-into-drawer to t so state changes land in :LOGBOOK: drawers, and add an around-advice on org-add-log-setup that skips identical from/to transitions. The suppression decision lives in a pure predicate so it's tested without driving org-todo. This removes the cause rather than stripping the lines after they appear.
|
| | |
|
| |
|
|
|
|
|
|
| |
Migrate 29 legacy specs off the old shape (a status suffix in the filename plus a :STATUS: property drawer) onto the docs-lifecycle status heading: a top-level heading carrying the org lifecycle keyword and a dated history line, with the two #+TODO sequences in the header.
Dropping the -doing/-implemented/-superseded suffixes means a status change no longer forces a rename and link surgery. Each keyword comes from the spec's own recorded status. The four specs already on the heading form are untouched, and every inbound reference now points at the new names.
The status board is one grep: rg '^\* (DRAFT|READY|DOING|IMPLEMENTED|SUPERSEDED|CANCELLED) ' docs/specs/
|
| |
|
|
| |
Five syntax categories (rxgb, rxgc, dmark, neg, warn) rendered as editable rows but had no COLS entry, so build_syntax never gave them a SYNTAX slot. They exported nothing and re-imported nothing, so every saved theme dropped them. I added the five to COLS, where the default-face seed fills their real colors and they round-trip through save and import. A regression test now asserts every editable category has a COLS slot.
|
| |
|
|
| |
cj/markdown-preview already autostarts the httpd listener, but the docstring still described the old separate-start design that signaled a user-error. The regression test matches the whole function object, so the stale note tripped it.
|
| |
|
|
| |
The picker collected projects from ~/.emacs.d and the children of ~/code and ~/projects, so ~/.dotfiles (a single-project root in $HOME) matched neither and never appeared. I added it to cj/ai-term-project-roots alongside ~/.emacs.d.
|
| | |
|
| | |
|
| |
|
|
|
|
| |
C-z forwarded to the pty sends SIGTSTP to the foreground job; with
eat-over-tmux, fg does not reliably bring the agent back. Swallow it in
eat-semi-char-mode-map so it never reaches the pty.
|
| |
|
|
|
|
| |
The leading modeline space set its height with a display (height 1.15) property, which scales against the buffer's default face. nov-mode's reading view remaps default to 18pt, so there the padding grew to 1.15x that and the bar rendered far taller than normal. The theme's absolute mode-line height couldn't help, since the padding space drives the strip height, not the face.
The padding now uses an absolute integer height anchored to the frame's default face, so a buffer that enlarges its own default (nov, text-scale) no longer inflates the bar. Normal buffers are unchanged, and the nov bar matches them.
|
| |
|
|
|
|
| |
tab-bar, tab-line, line-number, and line-number-current-line join mode-line in the chrome height seeds (apply_modeline_height_default generalized to apply_chrome_height_defaults), each pinned at absolute 130 so no bar or gutter tracks a buffer's enlarged default face. header-line and mode-line-inactive stay unseeded on purpose: both inherit mode-line, so the pin reaches them through the chain and their own value would duplicate state. The line-number pair is seeded individually because the generated theme's explicit specs leave their :inherit unspecified at runtime.
header-line, tab-bar, and tab-line also join the UI faces table, so all chrome heights are editable through the size column; the mock-completeness gate exempts the three faces the mock deliberately doesn't draw. WIP.json reconciled and the theme regenerated; every chrome face resolves :height 130 in the live daemon, pins and inherit chains both.
|
| |
|
|
|
|
| |
heightCssValue maps a face's height to CSS from its stored kind: a relative multiplier renders as em, an absolute 1/10pt value as true pt, with legacy objects falling back to integer/fractional inference. uiCss feeds it to the mock editor, so the mode-line, mode-line-inactive, and line-number bars visibly thicken with an absolute height while the buffer text stays put; paintUI scales the UI row's sample text; the package-preview span builder swaps its em-only sizing for the same kind-aware value.
faceCss now accepts a unit-carrying string for fontSize alongside the existing em number.
|
| |
|
|
|
|
|
|
| |
A new size column in the UI and package tables carries one numeric field plus an abs/rel toggle, exposed per the editable-height spec: chrome faces (mode-line family, line-number family, and header-line/tab-bar/tab-line when they arrive) default to absolute 1/10pt entry with a computed pt hint; the seeded heading faces (org-level-*, document title/info, agenda structure/dates, shr headings, and friends) default to a relative multiplier. Any other face carrying a live height exposes the control dynamically; the long tail gets none.
Absolute entry takes a positive integer only; relative entry clamps into the 0.1-2.0 range the old field used; garbage never reaches the model. The toggle writes heightMode explicitly and clears the number on a flip, since 130 tenth-points and 1.3x mean different things. The kind-unaware height field in the row expander is retired, and a non-default height now marks the size cell instead of the expander toggle.
The seeded set is named statically in app-core.js because the per-row default comes from the captured Emacs snapshot, which carries no heights for those faces. The #preview screenshot hash now accepts @ui/@code view keys so the harness can shoot the UI table.
|
| |
|
|
|
|
| |
JSON collapses 2.0 to 2 on save, so a height's number type can't say whether it's a fixed 1/10pt value or a relative multiplier. The face model now carries an explicit heightMode field (abs/rel) through seed, save/load, and export. build-theme.el coerces :height from the kind: abs exports an integer, rel a float, so a relative 2.0 renders as 2.0, never 2.
Faces saved before the field existed infer the kind once on load (JS: integer to abs, fractional to rel; Python keeps the authored type, so a float 2.0 seed stays relative) and persist it on the next save. The mode-line seed carries abs explicitly, and WIP.json's eight seeded heights are stamped with their kinds. Regenerating the theme from the stamped WIP.json produces an identical WIP-theme.el, so the round-trip holds.
|
| |
|
|
|
| |
Phases decomposed into build tasks; Phase 1 gains a load-time kind-inference
migration for saved themes that predate the explicit height-kind field.
|
| |
|
|
|
|
|
|
|
|
|
| |
mode-line's :height was unspecified, so a buffer that remaps its default
face larger (the nov reading view) inflated its modeline with it. Seed an
absolute 130 (1/10pt) on mode-line — build_uimap gains
apply_modeline_height_default, mirroring the hover-box default — and set
it in WIP.json. Also drop the stray :height 2 from mode-line-inactive
(a JSON integral-float collapse that rendered inactive bars at 0.2pt);
inactive now inherits mode-line's height. Theme regenerated and loaded
live; the editable-height spec covers making this tunable in the studio.
|
| |
|
|
|
|
|
|
|
|
| |
Code read surfaced two findings: JSON collapses integral relative floats to
absolute ints (WIP.json's mode-line-inactive height 2 is the live casualty),
so the face model carries the kind explicitly; and the minimal seed fix the
metadata referenced never shipped. All five open decisions settled: one field
plus abs/rel toggle, exposed on chrome plus already-seeded faces, raw 1/10pt
entry with a pt hint, row-sample plus mock-editor previews, seed fix owns the
artifact cleanup.
|
| |
|
|
|
|
| |
wttrin-state-file defaults to locate-user-emacs-file, which drops the state
file at the repo root as untracked clutter. Point it at data/ alongside the
other per-machine state files; moved the existing file there.
|
| |
|
|
|
|
| |
Stubbed from the 2026-07-02 nov-reading modeline-height diagnosis: the studio
exports per-face :height but offers no editable control, and the absolute-vs-
relative distinction is what separates a scaling heading from a fixed modeline.
|
| | |
|
| |
|
|
| |
ansi-color carried a bespoke spec and a full seed palette but its renderer was never written, so it silently fell back to the generic face list. Added renderAnsiColorPreview — a compilation/shell buffer exercising all 16 SGR palette faces, the faces eat and vterm color faces inherit from — and registered it. Last generic app in the ecosystem-coverage scope.
|
| |
|
|
| |
ghostel (the terminal behind the agent buffers) gets an eat-style scene through its own 16 ANSI color faces plus the default surface and the two fake-cursor faces; all-the-icons a dired listing where each file's leading marker carries its color face across the 8 hues, their light/dark variants, and the -alt accents. Both are pinned not-loaded apps whose only visibility is the studio preview, so they carry the highest realism bar. Face names are literal, not constructed, to satisfy the coverage gate.
|
| |
|
|
|
|
| |
nerd-icons-completion
tmr shows the list view and tmr-tabulated-view with every column face; wttrin the weather buffer with staleness header, key hints, and the stale modeline lighter; alert one line per severity; org-superstar the bullet swap across levels plus list items; nerd-icons-completion folder icons in the dir face. Phase 4 of the preview run — all 13 small-scene apps now sit in the face-coverage gate.
|
| |
|
|
|
|
| |
flyspell-correct
highlight-indent-guides shows both methods (character glyphs, column bands) plus the responsive top/stack variants at a marked point; yasnippet a mid-expansion snippet with the active field and the debug overlay; prescient primary/secondary match highlights; flyspell-correct the word under correction with its menu. All four join the face-coverage gate.
|
| |
|
|
| |
emms shows its three UIs (browser tree, playlist, metaplaylist); org-roam the backlinks buffer plus the dailies calendar mark; hl-todo comment keywords and the flymake diagnostic; symbol-overlay all eight pin faces on one defun plus the at-point default. All four join the face-coverage gate.
|
| |
|
|
| |
One C-x b consult-buffer scene drawn jointly by vertico, marginalia, consult, embark, and orderless; each app's preview shows the shared session with its own faces at work, then extends it with the states only it owns (vertico multiline, marginalia's full annotation catalog, consult line/grep/async, embark act + collect, orderless component cycling). All five join the face-coverage gate, so every one of their 72 faces appears verbatim in the renderers.
|
| |
|
|
| |
The web-mode preview is one mixed document: markup with every tag/attr variant, an inline CSS part, a generic template block (engine-agnostic on purpose), and a script part carrying a JSON island, JSX depths, nested template literals, SQL-in-a-string, a PHP preprocessor island, and JSDoc annotations. The realism gate now covers it, so all 81 faces are exercised. SAMPLES gains an HTML language, which also enriches the syntax and auto-dim previews.
|
| |
|
|
| |
Five daily-driver apps leave the generic face-name list: company (a completion popup with every row variant, inline ghost preview, tooltip search, and the echo frontend), company-box (the icons variant), transient (a magit-commit-style panel exercising every key class), magit-section (status-buffer headings with child counts and the highlighted section), and rainbow-delimiters (buffer-honest nesting depths 1-9 plus the cycle past 9 and both error faces). A new test gates realism: every face of each covered app must appear verbatim in its renderer, so a scene can't silently skip faces.
|
| |
|
|
| |
PINNED_PACKAGE_FACES is the curated record of packages retired from the config (ghostel, all-the-icons). A pinned package survives inventory regeneration, shows a 'not loaded' label + hover in the app dropdown, and keeps refreshing its face list from the live inventory while that still carries it. An attempted live regen made the fragility concrete: today's daemon session was missing 142 faces from lazily-loaded packages, so regen-from-live is inherently lossy and the pin is the only durable record.
|
| | |
|