Skip to content

fix racy light/dark rendering - #776

Open
MichaelMure wants to merge 4 commits into
charmbracelet:mainfrom
MichaelMure:fix-theme-bg
Open

fix racy light/dark rendering#776
MichaelMure wants to merge 4 commits into
charmbracelet:mainfrom
MichaelMure:fix-theme-bg

Conversation

@MichaelMure

@MichaelMure MichaelMure commented Apr 28, 2026

Copy link
Copy Markdown

Forms were racingly rendered with light-theme colors regardless of the terminal background, due to three related bugs:

  • fix(theme): fix swapped light/dark colors in ThemeCharm. This is a regression that happened in commit 47e59e9
  • fix(form): explicitely request the background color. Before, this was relying on a side effect of compat.HasDarkBackground in lipgloss (package level var) triggering the terminal request, which would eventually flow back to the form. This makes it explicit and execute in all cases. Arguably, compat.HasDarkBackground can cause problems as it queries (os.Stdin, os.Stdout) instead of the real input/output of the form.
  • fix(form): propagate background color message to un-selected groups too

Additionally:

  • fix(group): don't propagate events twice. Previously, message other than tea.KeyPressMsg, tea.PasteMsg were propagated twice. This also makes the code more obvious.

  • I have read CONTRIBUTING.md.

  • I have created a discussion that was approved by a maintainer (for new features).

Before fix:
image

After fix:
image

@MichaelMure

MichaelMure commented Apr 28, 2026

Copy link
Copy Markdown
Author

After more debugging I realize that this might not be the right fix.

But there is a bug: from what I'm seeing, there is a race, at least in Form where the tea.BackgroundColorMsg get received before or after rendering the form. The ordering is not deterministic between runs of my test program, and the form render with bad colors if tea.BackgroundColorMsg get received before rendering (??). This would suggest that the light/dark colors are indeed swapped?

This is a regression that happened in commit 47e59e9
Before, this was relying on a side effect of compat.HasDarkBackground in lipgloss (package level var) triggering the terminal request, which would eventually flow back to the form.

This makes it explicit and execute in all cases. Arguably, compat.HasDarkBackground could cause problems as it queries (os.Stdin, os.Stdout) instead of the real input/output of the form.
Previously, message other than tea.KeyPressMsg, tea.PasteMsg were propagated twice. This also makes the code more obvious.
@MichaelMure

Copy link
Copy Markdown
Author

I found the real root causes, see my root message.

@MichaelMure MichaelMure changed the title fix(theme): fix swapped light/dark background colors in ThemeCharm fix racy light/dark rendering Apr 29, 2026
Aharonee added a commit to pearl-research-labs/pearl that referenced this pull request Jul 16, 2026
…rst internals

Provisioned configs no longer pin rpclisten: oyster's own default is
loopback-only listeners on the active network's port, so one conf now
serves mainnet and testnet side by side, and an explicit rpclisten in
an existing conf becomes the address oystercli dials (the daemon
listens exactly there, whatever the network default is). Non-loopback
connect targets are treated as remote: no local auto-provisioning, no
local wallet-creation or daemon-start offers in triage, and the
not-running advice speaks about the remote's listener, firewall,
credentials, and certificate instead.

Internals now lean on libraries instead of hand-rolled logic:
oyster.conf is parsed with go-flags' ini parser (the daemon's own
format machinery) rather than regexes, required-field validation uses
huh.ValidateNotEmpty, and first-non-empty selection uses cmp.Or.
Theming drops the custom hex palette entirely — printed output uses
only basic ANSI colors and the Faint attribute, which terminal themes
keep readable on any background, and forms use huh's stock ThemeCharm
with one workaround (option foregrounds unset to the terminal default)
for the unreleased upstream fix charmbracelet/huh#776, whose v2.0.3
light palette rendered menu options near-white on light terminals.
Aharonee added a commit to pearl-research-labs/pearl that referenced this pull request Jul 16, 2026
…pport (#249)

- Restore from seed: an omitted wallet birthday now sends the chain's
  genesis time instead of falling through to oyster's time.Now()
  default, which skipped all history and left restored wallets with no
  addresses and no balance (the desktop wallet works because it
  hardcodes a pre-genesis birthday). The wizard now describes the
  birthday as narrowing the recovery scan, not as an optimization.
- One conf, every network: auto-provisioned configs no longer pin
  rpclisten — oyster's own default is loopback-only listeners on the
  active network's port — so the same oyster.conf serves mainnet and
  testnet daemons side by side and `oystercli --testnet` works end to
  end. An explicit rpclisten in an existing conf (e.g. the release
  installer's) is where the daemon actually listens, so oystercli now
  dials it, mapping wildcard hosts to loopback and reporting the
  provenance as "oyster.conf (rpclisten)".
- Remote daemons: non-loopback connect targets skip local
  bootstrapping — no auto-provisioning, no wallet-creation or
  daemon-start offers in triage — and the not-running advice covers
  the remote's listener, firewall, credentials, and certificate.
  Supported patterns (flags + copied rpc.cert, SSH tunnel, dedicated
  client appdata dir) are documented in the README.
- Terminal-theme readability: the custom hex palette is gone. Printed
  output uses only basic ANSI colors and the Faint attribute, which
  terminal themes keep readable on light and dark backgrounds. Forms
  use huh's stock ThemeCharm with one workaround — option foregrounds
  unset to the terminal default — because huh v2.0.3 always renders
  its light palette, whose near-white option color is invisible on
  light terminals; drop when charmbracelet/huh#776 ships.
- Library-first internals: oyster.conf is parsed with go-flags' ini
  parser (the daemon's own format machinery) instead of regexes,
  required-field validation uses huh.ValidateNotEmpty, and
  first-non-empty selection uses cmp.Or. The log sanitizer stays
  custom on purpose: x/ansi.Strip passes bare C0 controls through,
  which would defeat the escape-injection defense.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant