Skip to content

chore: harden blit for v0.1.1#3

Merged
moneycaringcoder merged 31 commits intomainfrom
chore/harden
Apr 10, 2026
Merged

chore: harden blit for v0.1.1#3
moneycaringcoder merged 31 commits intomainfrom
chore/harden

Conversation

@moneycaringcoder
Copy link
Copy Markdown
Contributor

Summary

  • Fix confirmed bugs: sess2tape version mismatch, layout dead code, Windows record fail-early, readKeys goroutine leak
  • Rename all TUIKIT_* env vars to BLIT_* post-migration
  • Encapsulate overlay stack access behind proper methods
  • Add test coverage for gradient, cli/message, btest screen/region/style
  • Expand linter config (gosimple, misspell), add Makefile targets (fmt, vet, snapshot)
  • Reset CHANGELOG.md to v0.1.0 baseline, fix CONTRIBUTING.md Go version

Test plan

  • go build ./... passes
  • go test ./... passes (all packages green)
  • CI lint + test passes on Linux
  • Manual smoke test of blit -watch with new 2s poll interval
  • Verify no remaining TUIKIT_ references in codebase

sess2tape only accepted version 1 sessions but btest.SessionRecorder
writes version 2 since the migration. Update the constant and version
check to match the pattern in btest/sess.go.
Both branches returned the same value regardless of FlexAlign. Visual
alignment is handled at render time by alignCrossHBox/alignCrossVBox,
so SetSize always needs the full cross-axis dimension. Clarify intent
with comments and drop the misleading conditional.
- makeRaw on Windows now returns an error instead of silently succeeding
  with no-op raw mode, causing runRecordSession to exit immediately
- readKeys on all platforms accepts a done channel for clean shutdown
- signal.Stop added to clean up signal handler on exit
snapshotTree walks the entire repo computing mtime hashes on every
tick. At 500ms this is unnecessarily aggressive for file change
detection. 2s with the existing 300ms debounce is responsive enough.
TUIKIT_NO_ANIM     → BLIT_NO_ANIM
TUIKIT_DEVCONSOLE  → BLIT_DEVCONSOLE
TUIKIT_UPDATE_DISABLE → BLIT_UPDATE_DISABLE
TUIKIT_THEME       → BLIT_THEME (docs only, not in Go code)
Add contains() and remove() methods to overlayStack. Replace all
direct .stack slice manipulation in app.go with method calls,
preventing out-of-bounds risks and improving readability.
- Add fmt, vet, snapshot targets to Makefile
- Enable gosimple and misspell linters in golangci-lint
- Fix CONTRIBUTING.md Go version (1.24+ → 1.25+)
Replace inherited tuikit-go version history with a single v0.1.0
entry summarizing everything blit ships with at initial release.
Cover parseHex, lerpU8, Gradient.RenderAt, Gradient.RenderText, and
RenderGradient with edge cases for invalid hex, boundary values, empty
strings, and clamped t values.
Cover all message functions (Success, Warning, Error, Info, Step,
Title, Section, Separator, Dim, KeyValue and f-variants) using
stdout capture to verify output content.
Cover Screen methods (TextAt, Contains, FindText, FindAllText, Row,
Column, RowCount, MatchesRegexp, FindRegexp, CountOccurrences, etc.),
Region methods (Contains, Row, FindText, CountOccurrences, StyleAt),
and CellStyle zero value. Includes boundary and edge case coverage.
@moneycaringcoder moneycaringcoder self-assigned this Apr 10, 2026
Cover v1/v2 session formats, all step kinds (key, type, resize,
screen), key mapping (known, unknown, empty), quote escaping,
width/height overrides, and stdin source path.
Use a future timestamp instead of sleeping 20ms, eliminating
flakiness from timing-dependent assertions.
Shorthand helpers that wrap ToastCmd with sensible default durations
(4s for info/success, 6s for warn/error). Reduces boilerplate for
the most common toast patterns.
CopyToClipboardCmd sends text to the system clipboard via OSC 52,
which works over SSH and in most modern terminals without external
tools. CopyToClipboardWithNotify additionally sends a message so
the app can show confirmation feedback.
ConfigField now accepts an optional Validate func(string) error that
runs before Set. If validation fails, the error is shown inline and
Set is never called, giving consumers a clean separation between
input validation and persistence.
When the list has no items and EmptyText is set, a centered muted
message is rendered instead of a blank viewport. When EmptyText is
not set, behavior is unchanged.
Provides plug-and-play YAML config persistence so apps don't need to
roll their own. LoadYAML silently returns nil on missing files (use
struct defaults). SaveYAML writes atomically via temp+rename.
DefaultConfigPath and EnsureConfigDir handle XDG-style path resolution.
RetryCmd wraps a func() (tea.Msg, error) with configurable retry
attempts and exponential backoff. Returns RetryErrorMsg when all
attempts are exhausted. Composable with Poller for resilient polling.
--json enables go test -json for machine-readable output.
--timeout passes through to go test -timeout for per-test limits.
--fail suppresses passing test output, showing only failures and
summary lines for cleaner CI logs.

Refactors runGoTest to accept a runOpts struct for cleaner flag
threading.
The --fail flag filters plain-text go test output, which is
incompatible with --json's JSON lines format. Fail early with
a clear error message instead of producing silent empty output.
Verify that EmptyText is displayed when the list has no items,
and that the empty state is blank when EmptyText is not set.
Drop TestCopyToClipboardMsg (tests Go struct assignment, not our
code) and remove an inaccurate comment in config_test.go.
- config.go: explicitly discard error returns on best-effort cleanup
  calls (tmp.Close, os.Remove) to satisfy errcheck
- cli/spinner.go: make Stop() synchronous with sync.WaitGroup so the
  goroutine finishes before Stop returns, preventing a data race with
  tests that reassign os.Stdout
The horizontal tab bar underline joined segments with ┼ (cross), which
rendered as a visual artifact on many terminals. Use ┴ (up-and-horizontal)
for a proper connection with the border line below.

Fixes #4
Append() is documented as goroutine-safe but View() read the viewport
and filteredLines without holding the mutex. Switch to sync.RWMutex
and add RLock in View() and renderStatusBar() so concurrent Append
calls don't race with the Bubble Tea render goroutine.
The filter-in-place idiom in overlayStack.remove kept stale interface
references in the backing array tail, preventing GC of removed overlays
until the slice was reallocated.
- templates/starter/go.mod: update dependency from tuikit-go to blit
- scripts/vhs/*.tape: rename tuikit-go to blit in comments and typed input
Table-driven tests for Truncate (fits, exact, truncated, very short,
empty, zero width), Divider (normal and zero width), and Badge (basic,
bold, empty text).
- Start cursor tween from theme.Border instead of theme.Muted so the
  cursor row is distinguishable from dim text during animation
- Apply row style foreground (TextInverse) to cell content on cursor
  rows so CellRenderer foreground colors don't create poor contrast
  against the cursor background

Fixes #6
@moneycaringcoder moneycaringcoder marked this pull request as ready for review April 10, 2026 14:04
@moneycaringcoder moneycaringcoder merged commit 7139898 into main Apr 10, 2026
2 checks passed
@moneycaringcoder moneycaringcoder deleted the chore/harden branch April 10, 2026 14:04
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.

Tabs: underline separator uses ┼ cross character instead of proper connector

1 participant