Let embedders register built-in themes via RegisterBuiltinThemes#3182
Draft
EronWright wants to merge 2 commits into
Draft
Let embedders register built-in themes via RegisterBuiltinThemes#3182EronWright wants to merge 2 commits into
EronWright wants to merge 2 commits into
Conversation
fd2fc6f to
6c7b2f9
Compare
Add styles.RegisterBuiltinThemes(fs.FS), which adds an embedder-provided theme source (e.g. an embed.FS of themes/*.yaml) to the built-in theme set. Registered themes flow through the exact list/load/merge-onto-default pipeline cagent already uses for its bundled themes, so they are first-class: they appear in ListThemeRefs and the /theme picker, resolve via LoadTheme/ApplyThemeRef, and persist as the user's selection — with no changes to the picker or handlers. Registered sources take precedence over the bundled themes, so an embedder can override a built-in and, in particular, mask "default" with their own (still merged onto cagent's pristine DefaultTheme() base). This lets a downstream CLI/TUI ship its own default and theme set without forking, while cagent core stays domain-agnostic.
6c7b2f9 to
9a14205
Compare
- lint: use errors.New for the static nil-fs message (perfsprint) and require.Error for the error assertions (testifylint) - docs: the godoc stated the opposite of the implemented behavior. Registered sources take precedence over bundled themes and can mask "default", which is what the PR description and the tests already assert. Rewrite the godoc to match. - bug: RegisterBuiltinThemes invalidated only the refs-list cache, not the parsed-theme cache. Built-in cache entries are treated as permanently valid, so an override of a built-in (or "default") that was loaded before registration was silently ignored. Invalidate the theme cache on registration and add a regression test.
Member
|
Pushed a few fixes (
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds
styles.RegisterBuiltinThemes(fsys fs.FS) error, which lets an embeddercontribute additional built-in themes from a filesystem (typically an
embed.FSofthemes/*.yaml).Why
Themes are already partial overrides on top of
DefaultTheme()—loadBuiltinThemeand
loadThemeFrombothmergeTheme(DefaultTheme(), &override), which is why abundled theme YAML only declares the colors it changes. But the built-in set is a
single compile-time
//go:embed themes/*.yaml, which a downstream consumer can'textend.
A downstream CLI/TUI built on cagent wants its own theme(s) to be first-class
without forking.
RegisterBuiltinThemesgeneralizes the bundled-theme sourcefrom one hardcoded
embed.FSto a list, so registered themes flow through theexact list/load/merge pipeline cagent already uses. They are treated like
cagent's own built-ins with no changes to the picker or handlers:
ListThemeRefs(and the/themepicker),LoadTheme/ApplyThemeRef,IsBuiltinTheme),Registered sources take precedence over the bundled themes, so an embedder can
override a built-in and, in particular, mask
defaultwith their own. Amasked default is still a partial override merged onto cagent's pristine
DefaultTheme()base, so it only needs to specify the fields it changes.DefaultTheme()itself remains the canonical merge base.Embedder usage
themes/brand.yamlis a partial override; unset fields fall back to the defaulttheme:
To make the brand theme the launch default, ship it as
themes/default.yamlinstead (or in addition) — it masks cagent's default while inheriting everything
it doesn't set.
Notes / semantics
themes/<ref>.yaml(or.yml). An embedder thatembeds at
themes/*.yamlpasses itsembed.FSdirectly; otherwisefs.Subtore-root at the themes dir.
name is still listed once.
RegisterBuiltinThemesvalidates the source eagerly (nil / missingthemesdir) so problems surface at registration, not at picker time.
Tests
Tests live in
theme_test.go(package styles), consistent with the existingtheme tests, and exercise registration through the public functions an embedder
uses, with a small unexported reset for isolation:
TestRegisterBuiltinThemes_EmbedderFlow— registers from a realembed.FSandruns the full register → list →
IsBuiltinTheme→ApplyThemeRefloop.TestRegisterBuiltinThemes— listed, classified built-in, loads merged ontothe default (overridden field changes, unset fields inherited).
TestRegisterBuiltinThemes_MultipleSources— aggregates across more than onesource; first-registered wins a collision between two registered sources.
TestRegisterBuiltinThemes_OverridesBuiltin— a registered name overrides thebundled theme.
TestRegisterBuiltinThemes_MasksDefault— masksdefault, merged onto thepristine
DefaultTheme()base.TestRegisterBuiltinThemes_Errors— nil / missing-themes-dir rejected eagerly.Full
pkg/tui/stylessuite passes under-race;go vetandgofmtclean.