Skip to content

feat(ui): theming support with config autosave#104

Merged
yimsk merged 4 commits intodevelopfrom
feature/96-theming-support
Jan 5, 2026
Merged

feat(ui): theming support with config autosave#104
yimsk merged 4 commits intodevelopfrom
feature/96-theming-support

Conversation

@yimsk
Copy link
Copy Markdown
Contributor

@yimsk yimsk commented Jan 5, 2026

Summary

  • Add 6 preset themes (dark, light, nord, dracula, gruvbox, catppuccin)
  • Add :theme command and --theme CLI flag for theme switching
  • Add :autosave on/off command and --autosave CLI flags
  • Migrate to lipgloss/v2/table for proper cell theming
  • YAML patching preserves comments and unknown config keys

Breaking Changes ⚠️

Before After Notes
persistence.enabled autosave.enabled Config key renamed
--persist / --no-persist --autosave / --no-autosave CLI flags renamed
startup.profile: name startup.profiles: [name] Array format; old format readable

New Commands

  • :theme <name> - Switch theme (persisted if autosave enabled)
  • :autosave on/off - Toggle config autosave

New CLI Flags

  • -t, --theme <name> - Set theme for session (transient)
  • --autosave / --no-autosave - Enable/disable config persistence

Testing

  • task test passes
  • task lint passes
  • task build passes

Closes #96

Add preset themes (dark, light, nord, dracula, gruvbox, catppuccin) with
runtime switching via :theme command and --theme CLI flag.

Theme System:
- 6 preset themes with full color customization
- Config support: preset name or object with overrides
- :theme command for persistent change (when autosave enabled)
- --theme CLI flag for transient theme selection
- ThemeChangedMsg for runtime style reload across all views

Config Autosave:
- :autosave on/off command with flash feedback
- --autosave/--no-autosave CLI flags
- Multi-profile support with startup.profiles array format
- YAML patching to preserve comments and unknown keys

Table Improvements:
- Migrate to lipgloss/v2/table for proper cell theming
- Extract TableCursor and NewTableStyleFunc for code reuse
- Consistent table styling across resource browser and tag search

BREAKING CHANGE: Config key renamed from 'persistence' to 'autosave'
BREAKING CHANGE: CLI flags renamed from --persist to --autosave
BREAKING CHANGE: Config 'startup.profile' (string) replaced by 'startup.profiles' (array)
  - Old format still readable for backward compatibility
  - New saves use profiles array format
@claude

This comment was marked as resolved.

- Add RWMutex to Current()/SetTheme() for thread safety
- Show warning flash when theme save fails with autosave enabled
- Add concurrent access test with race detector
@claude

This comment was marked as resolved.

Style helpers now call Current() which acquires RLock instead of
directly accessing the module-level current variable.
@claude

This comment was marked as resolved.

Save methods now hold mutex during both in-memory update and file I/O
to prevent concurrent saves from overwriting each other's changes.

Renamed patchConfig to patchConfigLocked to indicate caller holds lock.
@claude
Copy link
Copy Markdown

claude Bot commented Jan 5, 2026

PR Review: Theming Support with Config Autosave

Great work on this comprehensive feature addition! The implementation is well-structured with good test coverage. Here are my findings:

✅ Strengths

  1. Excellent backward compatibility handling - The migration from persistence to autosave and profile to profiles is well thought out with graceful fallback
  2. Robust YAML patching - The config file preservation logic comments, unknown keys is sophisticated and avoids data loss
  3. Comprehensive test coverage - Both internal/config/file_test.go and internal/ui/theme_test.go have excellent coverage 23+ and 29+ test functions respectively
  4. Thread-safe config operations - Proper use of mutex locking in FileConfig methods
  5. Atomic file writes - Using temp files with rename prevents config corruption
  6. Well-documented breaking changes - Clear migration guide in PR description

Code Quality Observations

Strong Points:

  • Clean separation of concerns config, UI, view layers
  • Good use of functional options pattern withRLock, doWithLock
  • Proper error wrapping with fmt.Errorf
  • Consistent naming conventions

Minor Issues:

  1. Potential nil panic in theme application internal/config/file.go:331 - If c.Theme has color fields that are nil/zero, callers need to handle this. Consider documenting this or providing a safe getter.

  2. Magic number in command_input.go:72 - ti.CharLimit = 50 should be extracted to a named constant like maxCommandLength

  3. Empty region check could be more explicit internal/config/file.go:335-337 - The early return on empty regions silently succeeds. Consider documenting why empty regions are a no-op.

@claude
Copy link
Copy Markdown

claude Bot commented Jan 5, 2026

Potential Issues

  1. Race condition in config save medium severity

    In internal/config/file.go:391-449, patchConfigLocked reads the file, patches it, and writes it back. If another process writes to the config between read and write, those changes will be lost.

    Recommendation: Consider using file locking flock or document that concurrent writes from multiple claws instances are not supported.

  2. Unclear error handling in SaveRegions/SaveProfiles low severity - SaveRegions returns early on empty input, but SaveProfiles does not have similar validation. This inconsistency could be confusing.

  3. Command mode UI state minor - In internal/app/app.go:487-517, the command mode changes the entire status line format. Users might not notice the completion hints appear/disappear.

Security

No major security concerns identified. Good practices observed:

  • Atomic file writes prevent corruption
  • No user input directly concatenated into shell commands
  • Proper file permissions 0755 for dirs
  • YAML parsing uses safe unmarshaling

Minor consideration: Config files may contain profile names which could leak info if shared.

Performance

  1. Style recreation on theme change - When theme changes, all views recreate their styles internal/app/app.go:214-222. For large view stacks this could cause a brief lag. However, this is likely acceptable given theme changes are infrequent.

  2. File I/O on every save operation - Each SaveRegions, SaveProfiles, SaveTheme reads and writes the entire config file. For rapid changes this could be slow. Consider debouncing rapid saves.

@claude
Copy link
Copy Markdown

claude Bot commented Jan 5, 2026

Test Coverage

Excellent coverage overall:

  • Config file operations: 23+ tests
  • Theme system: 29+ tests
  • YAML patching: covered
  • Backward compatibility: covered
  • Concurrent saves: covered

Missing test scenarios:

  1. Theme change with autosave disabled verify it does not persist
  2. Invalid theme names in config file ensure graceful fallback
  3. Corrupted YAML during patch operation
  4. Theme override behavior when CLI flag conflicts with config file

Documentation

Strong documentation:

  • README updated with clear theme table
  • Breaking changes clearly marked
  • CLI help text updated

Suggestions:

  1. Add example of theme overrides in README the object format with preset + custom colors
  2. Document thread-safety guarantees of FileConfig
  3. Add godoc comments to exported functions in internal/config/file.go

Specific Code Suggestions

internal/config/file.go:366-375 - Consider adding theme validation before saving to prevent invalid theme names from being persisted.

internal/app/app.go:219 - Consider logging failed theme persistence at debug level instead of warn, as this is not critical.

@claude
Copy link
Copy Markdown

claude Bot commented Jan 5, 2026

Migration Guide Validation

The breaking changes section is excellent. Verified:

  • Old config format is still readable
  • New format is written on save operations
  • CLI flags match the new naming

Summary

This is a high-quality PR with solid architecture, good testing, and thoughtful backward compatibility. The concerns raised are mostly minor and do not block merging.

Recommendation: APPROVE with optional improvements

The race condition in config saves is the only notable issue, but given this is a single-user CLI tool, it is acceptable to document as a known limitation rather than block the PR.

Priority fixes optional:

  1. Add validation to SaveTheme
  2. Document concurrent access limitations
  3. Add missing test scenarios for edge cases

Nice-to-have improvements:

  1. Extract magic numbers to constants
  2. Add godoc comments
  3. Document theme override format in README

Great work overall!

@yimsk yimsk merged commit d9ae652 into develop Jan 5, 2026
5 checks passed
@yimsk yimsk deleted the feature/96-theming-support branch January 5, 2026 08:25
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