| Commit message (Collapse) | Author | Age | Files | Lines |
| |
|
|
|
|
| |
arrayify-python
Extract cj/--ordering-validate-region (the start>end guard copy-pasted across all seven pure helpers) and cj/--ordering-replace-region (the delete-region + insert tail repeated in every interactive command). Alias cj/arrayify-python to cj/arrayify-json, which it duplicated verbatim, leaving both keybindable. Behavior unchanged; adds direct Normal/Boundary/Error coverage for the two new helpers.
|
| |
|
|
| |
prog-json and prog-yaml each carried a byte-identical cj/--<lang>-format-region that runs a formatter over the buffer via call-process-region and replaces it on exit 0. Hoist it to system-lib as cj/format-region-with-program with a generic output buffer, and point both formatters at it. Adds the first direct unit coverage of the helper (Normal, Boundary, Error).
|
| |
|
|
| |
Drop cj/apply-browser-choice (browser-config) and cj/load-fallback-theme (ui-theme), orphaned wrappers with no caller that just duplicated logic the live paths already inline, plus their tests. Delete commented-out blocks: a duplicate contact capture template (org-contacts-config), a disabled personal-info-dir :init (help-config), a stale TODO setq (org-config), and an old commented regex (test-runner).
|
| | |
|
| |
|
|
| |
minimize-window floors at window-min-height (4 lines), leaving roughly a 10% reveal. Bind window-min-height to 1 around it so the reveal opens at the ~2-line floor and the current window keeps almost the whole frame before the windsize arrows take over.
|
| | |
|
| |
|
|
| |
The sole-window pull split toward the arrow at 50/50, so a fullscreen terminal jumped above the revealed buffer at half height. Now the reveal opens on the opposite side and is minimized to a sliver, so the current window keeps the arrow's edge near-full and the sticky windsize arrows shrink it step by step, matching the feel of resizing an existing split.
|
| | |
|
| |
|
|
| |
When the selected window fills the frame there is no divider to resize, so the arrow now splits toward its direction with the previous buffer and the original window shrinks from that edge. Multi-window resize is unchanged.
|
| |
|
|
| |
Drop delete-to-trash. d now duplicates the file at point. D force-deletes the marked files via sudo rm -rf behind a yes-or-no-p that names the targets, and reports success only when rm exits 0.
|
| | |
|
| | |
|
| | |
|
| |
|
|
| |
Record the second studio batch as dated entries: expander hovers, view-dropdown lock indicator, expand/collapse-all, expander-stays-open-on-rebuild, 18 language previews, and the box column move.
|
| |
|
|
| |
Box now sits at column 5 in all three tables, after style and before contrast, instead of last. The contrast and example/preview columns shift right by one, and the position-based gates follow.
|
| |
|
|
| |
Add tokenized code samples for Racket, Scheme, Haskell, OCaml, Scala, Kotlin, Swift, Lua, Ruby, Perl, R, Erlang, SQL, PHP, Ada, Fortran, MATLAB, and Assembly, wired into the language dropdown. Each is an idiomatic snippet tagged by syntax category so the studio renders it in the assignment colors. A guard test checks every added language is registered and renders a non-trivial sample.
|
| |
|
|
| |
A package edit rebuilds the whole table, which collapsed any open expander under the user mid-edit. Track open rows in a module-level EXPANDED set, keyed by element/face, and reopen them on rebuild. Editing a value inside an open expander now leaves the row open. The expand-all/collapse-all and per-row toggles keep the set in sync.
|
| |
|
|
| |
Each row's expander toggle now shows a disclosure triangle that tracks its state: a right triangle when collapsed, a down triangle when expanded (it was a static ellipsis). A header-level expand-all / collapse-all button per table opens or closes every row's detail at once and follows the aggregate state. The per-row triangles and the header button stay in sync across a table rebuild.
|
| |
|
|
| |
Each label in the expander detail row now carries an explanatory hover (DETAIL_HOVERS), matching the table-header labels. The view dropdown prefixes a lock glyph on any view whose elements are all locked, recomputed on every lock change through updateLockToggles.
|
| |
|
|
| |
The Signal task linked to a todo file in the old signel checkout, which no longer exists. I repointed it to the smoke project's todo (smoke is the evolved Signal package). I also reworded the bug-capture task's prose so its quoted TODO-heading strings stop tripping the misplaced-heading checker. A full org-lint pass now reports zero, so the follow-up task is closed.
|
| |
|
|
| |
Mark the reduce-width, custom weight/slant dropdown, language-dropdown, and lock-to-leftmost tasks done as dated log entries. Refresh the org-lint follow-up list (current line numbers, plus the broken signel-todo link).
|
| |
|
|
| |
Put the lock cell first in all three assignment tables, ahead of the element/face name. The lock and name columns swap, and every column from fg onward is unchanged. The element-name sort moves to column 1, and the sort and index gates follow it.
|
| |
|
|
|
|
| |
Replace the native weight and slant selects with a custom dropdown themed like the color dropdown. The values are spelled out (semibold instead of "semi", and an unset control reads "weight"/"slant" rather than "wt"/"sl"), and each popup option renders in its own weight or slant so the choice previews itself. The trigger shows the current value in that style too.
mkEnumDropdown mirrors the color dropdown's popup, lock, and outside-click handling, so the new control opens, locks, and closes the same way. The style-cluster gates drive the popup instead of a native select and check the spelled-out range plus the per-option preview.
|
| |
|
|
| |
Reduce the per-cell horizontal padding from 12px to 8px across the assignment tables, so more of each row fits without horizontal scroll on a narrow screen. Also shorten the mode-line-highlight label to "(hover)", since the face name already carries the "mode-line" part.
|
| |
|
|
| |
Sort the language list alphabetically and pin Elisp as the default selection. Add the ‹ › arrows flanking the dropdown that step the selection (clamped, no wrap), reusing the view-dropdown's stepViewIndex so you can walk languages without reopening the menu.
|
| |
|
|
|
|
|
|
|
|
|
|
| |
The color/code, UI, and package tables now share one per-row widget set, so the editing surface reads the same whatever view is selected.
Column order is the same in all three: element, lock, fg, bg, style, contrast, example, box. Box moves to last in the color/code table, and the package table's inline inherit and size columns fold into the row expander, matching how UI and color/code already carry them.
The UI overlay faces drop the inline PASS/FAIL word and the red FAIL badge on the preview swatch. They show a bare colored worst-case number with the WCAG verdict in the hover, like the other two tables. The orphaned .crerr style goes with it.
The height picker now clamps a typed value into [0.1, 2.0]. A number input only enforces min/max on its stepper arrows, so a typed or pasted value reached the model unchecked. 0.1 is Emacs's own floor (a smaller height errors out), and 2.0 is the studio ceiling. Clearing the field still unsets to the inherited default.
Tests: clampHeight unit tests plus a #heighttest browser gate. The column and contrast gates move to the new positions and the bare-number readout.
|
| | |
|
| | |
|
| |
|
|
|
|
| |
theme-studio could theme ghostel-color-* but not the base ansi-color-* faces. build-inventory.el skips built-in faces, and ansi-color is part of Emacs core, so the 16 base ANSI faces never reached the dropdown. That left vterm, eshell, and compilation buffers on stock ANSI colors no matter the theme.
I added ansi-color as a bespoke app (the same path shr already uses for a built-in library), with the 16 palette faces seeded to match the ghostel colors. Theming ansi-color-* now sets the 16 colors for every ANSI consumer at once. ghostel-color-* inherit these, so clearing a ghostel-color face lets it follow ansi-color rather than holding its own value.
|
| |
|
|
|
|
| |
Re-exporting a theme used to land a "name (1).json" duplicate. The export built a blob and clicked a download link, which routes through the browser's downloads folder, and the browser uniquifies a re-save rather than replacing the file.
I switched export to the File System Access API (showSaveFilePicker): it writes straight to the file you pick, so re-exporting the same WIP.json overwrites it. Where the API is absent the old blob download still runs, mirroring importTheme's picker-with-fallback shape. A new #savetest browser gate stubs the picker and checks the written content and the close.
|
| | |
|
| |
|
|
| |
I added ERT tests for face-docs-dump.el: the pure first-line extractor across Normal/Boundary/Error inputs (multi-line, leading blanks, whitespace collapse, empty, whitespace-only, nil/non-string), and the syntax-category resolution (kw to the keyword-face doc, bg and p to default, the faceless dec absent). run-tests.sh loads the new file alongside the build-theme tests in the same batch.
|
| |
|
|
|
|
| |
Each table row's category cell now shows the face's Emacs docstring on hover, on top of whatever the cell showed before. The package cell keeps the face name underneath. The syntax and UI cells had no prior tooltip, so they show just the docstring. The label-span hints are left alone.
I added face-docs-dump.el, which emits face-docs.json from a live Emacs: a face-name to first-doc-line map for the UI and package tables, and a category to doc map for the syntax table. The category to font-lock-face mapping is read from build-theme.el's own map, so it isn't copied a third time. generate.py inlines both maps. A pure composeHoverTitle helper composes the tooltip, covered by Node, Python, and a new browser gate.
|
| |
|
|
|
|
| |
The F9 agent always docked as a right-side column on a landscape frame. On this 138-column frame that left ~68-column panes, too cramped to read code and the agent side by side. The F12 terminal and F10 playlist hardcoded a bottom split with no width-aware path.
I added cj/preferred-dock-direction and the cj/window-dock-min-columns defcustom (default 80) to the window-geometry lib: dock side-by-side only when the narrower pane keeps at least the minimum width, otherwise stack below. All three toggles now route through it. F9 drops its pixel-aspect rule. F12 and F10 gain a right-column width default and become adaptive. F10 keeps width and height size memory in separate vars so a resize on one axis doesn't leak to the other.
|
| | |
|
| |
|
|
| |
Added the uncovered fallback branches in app-core (migrateLegacyFace null input, normalizePkgFace's source fallback chain, mergePackagesInto's null/new-app guards, boxCss shading a relief from the bg when no box color is set) and in colormath (apca's equal-luminance return-0 and low-contrast clamp, isPureEndpointHex). New test-palette-generator-core.mjs drives planPaletteGenerator across every scheme, vibe, source mode, and the fill-gaps intents, since those internals are only reachable through the public planner. colormath branch 96 -> 99%, palette-generator-core funcs 97 -> 100%, node suite 237 tests. The remaining gaps are the deep palette-column edge branches, deferred as diminishing returns on already line-covered code.
|
| |
|
|
| |
cssWeight, faceDecoration, boxCss, and faceCss moved into app-core in the CSS-builder refactor but had no node tests, leaving app-core at 96% line / 95% funcs. Added Normal/Boundary/Error cases for all four: every weight name plus the fallbacks, underline/strike/both/neither decoration, line/released/pressed boxes with and without color and width plus the no-color fallback, and faceCss's background/noBg/fontSize/box-order assembly. app-core is now 100% line; the node suite is 217 tests.
|
| |
|
|
| |
The UI and package tier builders repeated the same "for each (face . obj) entry, build attrs, emit a non-empty spec" loop. Both now call one build-theme/--specs-from-entries helper; the package builder concatenates each app's specs in order. The syntax builder keeps its own form since it fans one category out to several font-lock faces. The 41 ERT tests stay green and the emitted themes are unchanged.
|
| |
|
|
|
|
| |
generate.py's add_default_palette_colors repeated the same fg/bg/box-color harvest three times (syntax, ui, package faces); it now calls one _harvest_spec_colors helper, preserving the add order so the palette and generated page are byte-identical. default_faces' _build_color_hex and _build_color_names each walked the same faces -> chosen/effective -> foreground/background/distantForeground nesting; both now consume one _iter_color_pairs generator and only differ in their key choice and filter. The rebuilt color maps match the originals exactly.
I left the lower-value generate.py items (a build() wrapper, dict-driven fill_data) and the capture/face-coverage script dedups for later: they touch import-time behavior or scripts the suite doesn't run, so they want their own verification rather than riding this change.
|
| |
|
|
| |
The bespoke apps were listed twice: generate.py's _BESPOKE_APPS (key, label, preview, faces, prefix, seed) and app_inventory's BESPOKE_APPS set of keys, which had drifted (it carried both "org" and "org-mode"). The spec list now lives in face_data.py as BESPOKE_APP_SPECS, beside the FACES/SEED constants it references. generate.py builds APPS from it, and app_inventory derives its exclusion set from the same keys plus an explicit "org" alias of the "org-mode" app. Adding a bespoke app is now one row. APPS order and the generated page are unchanged.
|
| |
|
|
| |
The single-spec seed now emits package-face keys in the spec's order rather than the old hand-written order, so the embedded package JSON reorders some keys. Values are identical (the APPS data parses equal; the page normalizes face key order on import), and check-generated requires the committed page to match the generator output.
|
| |
|
|
| |
STYLE_DEFAULTS, default_faces.seed, and capture-default-faces' ATTRS each hand-listed the face attributes, so adding one meant editing three places in step. face_specs.FACE_ATTRS is now one row per attribute carrying the model key, default, capture keyword, snapshot field, and seed transform kind. STYLE_DEFAULTS derives from it (same keys, order, and values), seed iterates it applying the per-kind extraction, and the capture probe map derives its emacs-attr to snapshot-field pairs from it. The snapshot-to-model translation stays genuinely per-attribute (colors prefer the Hex variant, flags become objects, weight/slant are value-narrowed), but the attribute list itself is now single-sourced. Verified byte-identical: STYLE_DEFAULTS and ATTRS match the old literals, the generated page is unchanged, and the suite is green. app-core.js mirrors this list by hand since the page is a separate runtime.
|
| |
|
|
|
|
| |
vibeChroma was a ten-branch if-ladder of magic chroma constants; it's now a [base, range] lookup table, so a vibe is one row to read or tune. resolveSyntaxFg and resolveUiAttr each hand-rolled the same cycle-guarded inherit walk; both now call one walkInheritChain helper that takes the parent and value functions. effResolve keeps its own recursive form since it double-indexes through the package map.
I left the palette-actions splice helpers (replacePaletteEntries, withCfg) and the paletteGroups dedup for a later pass: they mutate the live palette and are only browser-gate covered, so they want their own careful change rather than riding this one.
|
| |
|
|
| |
mkBoxControl duplicated the whole cluster/dropdown/paint/syncLocked machinery that mkLineStyleControl already provides for underline/strike/overline; it differed only in that its state object carries a width. I gave mkLineStyleControl an optional toState builder and reduced mkBoxControl to a wrapper that supplies it. The clear/reset tier functions already delegate their shared loop to clearUnlockedRows, so they were left as is. The buildTable/buildUITable/buildPkgTable skeleton merge is deferred: their shared control/expander/detail-editor/CSS machinery is now all extracted, and what remains is genuine per-tier column divergence that the browser gates pin by exact cell position.
|
| |
|
|
| |
The ~28 renderXxxPreview functions plus ofs/os/previewLines were ~460 lines of bespoke sample content sitting in the middle of the controller. I moved them to a new previews.js, spliced into the page through a PREVIEWS_J token the same way the other inlined libs are, and left the PACKAGE_PREVIEWS registry and dispatcher in app.js. app.js drops from 1233 to 759 lines, and the sample data now lives apart from the table/control machinery.
|
| |
|
|
| |
syntaxStyle, uiCss, and ofs each assembled the same color/background/weight/style/text-decoration/box-shadow string by hand, differing only in how they resolved fg/bg and whether they added a font-size. I promoted one faceCss(face, fg, bg, opts) plus cssWeight, boxCss, and a faceDecoration helper into app-core (all pure, no DOM), and reduced the three builders to thin wrappers that resolve fg/bg and call it. styleEx and paintUI now use the promoted cssWeight/boxCss too. udeco keeps its own untrimmed decoration form, so it stays in app.js.
|
| |
|
|
| |
oklchOf and isPureEndpointHex were each defined identically in app-core.js and palette-generator-core.js, and hueOfHex inlined oklchOf's body a third time. I moved both helpers into colormath.js, which already owns the primitives they call, and had the two consumers import them. hueOfHex now calls oklchOf instead of re-deriving it.
|
| |
|
|
|
|
| |
I replaced the two hand-kept attribute lists in normalizePkgFace and packagesForExport with a single faceAttrs() table. Each row carries the default, whether the value resolves through the palette, and the export rule, so adding a face attribute is one row instead of an edit in two places kept in step by hand.
faceAttrs is a hoisted function, not a const. The inlined page calls normalizePkgFace at top level (seedPkgmap) before the table's source position, where a const would sit in its temporal dead zone.
|
| |
|
|
|
|
| |
hl-line inherits highlight, mode-line-inactive inherits mode-line, and the
dashboard title gains :height 1.15. WIP.json is reserialized under the
expanded face model added this session.
|
| |
|
|
|
|
|
|
| |
I ran make coverage and worked the report function by function, separating real gaps from interactive/IO wrappers that aren't unit-test targets. These tests fill the genuine pure-logic holes: predicates, parsers, formatters, transforms, and three modules that had no test file at all.
New files cover car-member (local-repository), show-kill-insert-item (show-kill-ring), the oauth2-auto plstore cache fix (auth-config), the coverage-core project-root fallback, reconcile--dirty-p, and the recurrence-frequency dispatch in calendar-sync. Extended files add the missing branches: coverage-core's merge-base and diff /dev/null handling plus the staged and branch-vs-main scopes, the detect-system-timezone symlink path, user-constants no-op and optional-failure branches, the elfeed playlist branch with HTML-entity decoding, the duplicate-line no-comment-syntax guard, and several calendar-sync edges (exception field overrides, timestamp seconds and TZID fallback, property-line position advancement, parse-ics nil and out-of-range inputs).
Mocks sit at the real boundaries (plstore, url-retrieve, process-file, git) so each function's own logic runs. Dates come from relative helpers. About 65 tests added across 15 files, and the full suite stays green.
|