Skip to content

Commit 1a26436

Browse files
indacoclaude
andauthored
feat: migrate terminal output to herald typography system (#256)
* refactor: replace console package with herald typography system Introduce herald-backed printer with themed typography, replacing raw ANSI escape codes in the console package. Add theme.go with SleyTheme and ResolveTheme for named theme support. Initialize typography via printer.Init(theme) in the CLI Before hook. Co-Authored-By: claude <noreply@anthropic.com> * refactor: migrate command output to herald typography Use herald Compose, H2, H4, UL, KV, KVGroup, Table, Code, CodeBlock, Tags, and Section across discover, doctor, init, changelog, extension, hooks, workspace formatter, and extensionmgr output. Replace manual string formatting with structured typography elements for consistent visual hierarchy. Co-Authored-By: claude <noreply@anthropic.com> * style: use faint text with selective color highlights across commands Replace blanket PrintSuccess/PrintInfo with PrintFaint and Info() highlights on key values (versions, paths, names) for a cleaner visual balance. Errors and warnings remain colored. Quiet-mode summaries are unchanged. Co-Authored-By: claude <noreply@anthropic.com> * chore(deps): update herald to v0.13.0 and use Section/BR from upstream Remove local printer.Section and printer.BR implementations in favor of herald v0.13.0 Typography.Section(). Update all call sites to use ty.Section() directly. Co-Authored-By: claude <noreply@anthropic.com> --------- Co-authored-by: claude <noreply@anthropic.com>
1 parent 0f4f5d3 commit 1a26436

49 files changed

Lines changed: 689 additions & 626 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ require (
88
charm.land/lipgloss/v2 v2.0.2
99
github.com/charmbracelet/colorprofile v0.4.3
1010
github.com/goccy/go-yaml v1.19.2
11+
github.com/indaco/herald v0.13.0
1112
github.com/pelletier/go-toml/v2 v2.3.0
1213
github.com/tidwall/sjson v1.2.5
1314
github.com/urfave/cli/v3 v3.8.0

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkp
5050
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
5151
github.com/goccy/go-yaml v1.19.2 h1:PmFC1S6h8ljIz6gMRBopkjP1TVT7xuwrButHID66PoM=
5252
github.com/goccy/go-yaml v1.19.2/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
53+
github.com/indaco/herald v0.13.0 h1:+xVG9Fx5NpuWhwku/9IlRL6I009NnX4VUGKvlZHTRxU=
54+
github.com/indaco/herald v0.13.0/go.mod h1:T5g1+XLYvpjouhzAGHnAHDCKizhESkoV6+QPZ3DhgWA=
5355
github.com/lucasb-eyer/go-colorful v1.4.0 h1:UtrWVfLdarDgc44HcS7pYloGHJUjHV/4FwW4TvVgFr4=
5456
github.com/lucasb-eyer/go-colorful v1.4.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
5557
github.com/mattn/go-runewidth v0.0.21 h1:jJKAZiQH+2mIinzCJIaIG9Be1+0NR+5sz/lYEEjdM8w=

internal/cli/cli.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import (
1717
"github.com/indaco/sley/internal/commands/show"
1818
"github.com/indaco/sley/internal/commands/tag"
1919
"github.com/indaco/sley/internal/config"
20-
"github.com/indaco/sley/internal/console"
2120
"github.com/indaco/sley/internal/plugins"
2221
"github.com/indaco/sley/internal/printer"
2322
"github.com/indaco/sley/internal/tui"
@@ -64,7 +63,6 @@ func New(cfg *config.Config, registry *plugins.PluginRegistry) *urfavecli.Comman
6463
},
6564
},
6665
Before: func(ctx context.Context, cmd *urfavecli.Command) (context.Context, error) {
67-
console.SetNoColor(noColorFlag)
6866
printer.SetNoColor(noColorFlag)
6967

7068
// Theme priority: CLI flag > env var > config file > default
@@ -80,6 +78,7 @@ func New(cfg *config.Config, registry *plugins.PluginRegistry) *urfavecli.Comman
8078
}
8179

8280
tui.SetTheme(theme)
81+
printer.Init(theme)
8382
return ctx, nil
8483
},
8584
Commands: []*urfavecli.Command{

internal/clix/clix.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"github.com/indaco/sley/internal/apperrors"
1111
"github.com/indaco/sley/internal/config"
1212
"github.com/indaco/sley/internal/core"
13+
"github.com/indaco/sley/internal/printer"
1314
"github.com/indaco/sley/internal/semver"
1415
"github.com/indaco/sley/internal/tui"
1516
"github.com/indaco/sley/internal/workspace"
@@ -45,7 +46,7 @@ func getOrInitVersionFileWith(path string, strict bool, mgr *semver.VersionManag
4546
return false, err
4647
}
4748
if created {
48-
fmt.Printf("Auto-initialized %s with default version\n", path)
49+
printer.PrintFaint(fmt.Sprintf("Auto-initialized %s with default version", printer.Info(path)))
4950
}
5051
return created, nil
5152
}
@@ -322,7 +323,8 @@ func shouldShowTUIPrompt(cmd *cli.Command, options *executionOptions) bool {
322323
if !tui.IsInteractive() {
323324
return false
324325
}
325-
if cmd.Bool("yes") || cmd.Bool("non-interactive") || cmd.Bool("all") {
326+
if cmd.Bool("yes") || cmd.Bool("non-interactive") || cmd.Bool("all") ||
327+
cmd.IsSet("module") || len(cmd.StringSlice("modules")) > 0 || cmd.IsSet("pattern") {
326328
return false
327329
}
328330
return !options.defaultToAll

internal/commands/bump/auto.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ func determineBumpType(deps *bumpDeps, registry *plugins.PluginRegistry, label s
150150
}
151151

152152
if inferred != "" {
153-
printer.PrintInfo(fmt.Sprintf("Inferred bump type: %s", inferred))
153+
printer.PrintFaint(fmt.Sprintf("Inferred bump type: %s", printer.Info(inferred)))
154154
switch inferred {
155155
case "minor":
156156
return operations.BumpMinor
@@ -231,7 +231,7 @@ func runSingleModuleAuto(ctx context.Context, cmd *cli.Command, cfg *config.Conf
231231
return err
232232
}
233233

234-
printer.PrintSuccess(fmt.Sprintf("Bumped version from %s to %s", current.String(), next.String()))
234+
printer.PrintFaint(fmt.Sprintf("Bumped version from %s to %s", current.String(), printer.Info(next.String())))
235235
return nil
236236
}
237237

@@ -267,7 +267,7 @@ func getNextVersion(
267267
}
268268

269269
if inferred != "" {
270-
printer.PrintInfo(fmt.Sprintf("Inferred bump type: %s", inferred))
270+
printer.PrintFaint(fmt.Sprintf("Inferred bump type: %s", printer.Info(inferred)))
271271

272272
if current.PreRelease != "" {
273273
return promotePreRelease(current, preserveMeta), nil

internal/commands/bump/helpers.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ func commitAndTagAfterBump(registry *plugins.PluginRegistry, version semver.SemV
168168
if err := tm.CommitChanges(version, extraFiles); err != nil {
169169
return fmt.Errorf("failed to commit release changes: %w", err)
170170
}
171-
printer.PrintSuccess(fmt.Sprintf("Committed release changes for %s", version.String()))
171+
printer.PrintFaint(fmt.Sprintf("Committed release changes for %s", printer.Info(version.String())))
172172

173173
// Create tag on the new commit
174174
message := fmt.Sprintf("Release %s (%s bump)", version.String(), bumpType)
@@ -177,10 +177,10 @@ func commitAndTagAfterBump(registry *plugins.PluginRegistry, version semver.SemV
177177
}
178178

179179
tagName := tm.FormatTagName(version)
180-
printer.PrintSuccess(fmt.Sprintf("Created tag: %s", tagName))
180+
printer.PrintFaint(fmt.Sprintf("Created tag: %s", printer.Info(tagName)))
181181

182182
if tm.GetConfig().Push {
183-
printer.PrintSuccess(fmt.Sprintf("Pushed tag: %s", tagName))
183+
printer.PrintFaint(fmt.Sprintf("Pushed tag: %s", printer.Info(tagName)))
184184
}
185185

186186
return nil
@@ -280,12 +280,12 @@ func generateChangelogAfterBump(registry *plugins.PluginRegistry, version, _ sem
280280
cfg := cg.GetConfig()
281281
switch cfg.Mode {
282282
case "versioned":
283-
printer.PrintSuccess(fmt.Sprintf("Generated changelog: %s/%s.md", cfg.ChangesDir, versionStr))
283+
printer.PrintFaint(fmt.Sprintf("Generated changelog: %s", printer.Info(fmt.Sprintf("%s/%s.md", cfg.ChangesDir, versionStr))))
284284
case "unified":
285-
printer.PrintSuccess(fmt.Sprintf("Updated changelog: %s", cfg.ChangelogPath))
285+
printer.PrintFaint(fmt.Sprintf("Updated changelog: %s", printer.Info(cfg.ChangelogPath)))
286286
case "both":
287-
printer.PrintSuccess(fmt.Sprintf("Generated changelog: %s/%s.md and %s",
288-
cfg.ChangesDir, versionStr, cfg.ChangelogPath))
287+
printer.PrintFaint(fmt.Sprintf("Generated changelog: %s and %s",
288+
printer.Info(fmt.Sprintf("%s/%s.md", cfg.ChangesDir, versionStr)), printer.Info(cfg.ChangelogPath)))
289289
}
290290

291291
return nil

internal/commands/changelog/changelogcmd.go

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -62,25 +62,23 @@ Examples:
6262
// runMergeCmd executes the merge operation.
6363
func runMergeCmd(cmd *cli.Command, cfg *config.Config) error {
6464
// Check if changelog-generator plugin is enabled
65+
ty := printer.Typography()
6566
if !isChangelogGeneratorEnabled(cfg) {
66-
printer.PrintWarning("Warning: The changelog-generator plugin is not enabled.")
67-
printer.PrintInfo("To enable it, add the following to your .sley.yaml:")
68-
fmt.Println("")
69-
fmt.Println(" plugins:")
70-
fmt.Println(" changelog-generator:")
71-
fmt.Println(" enabled: true")
72-
fmt.Println(" mode: \"versioned\"")
73-
fmt.Println("")
74-
printer.PrintInfo("Proceeding with merge using default settings...")
75-
fmt.Println("")
67+
fmt.Println(ty.Compose(
68+
printer.Warning("Warning: The changelog-generator plugin is not enabled."),
69+
printer.Info("To enable it, add the following to your .sley.yaml:"),
70+
ty.CodeBlock("plugins:\n changelog-generator:\n enabled: true\n mode: \"versioned\"", "yaml"),
71+
printer.Info("Proceeding with merge using default settings..."),
72+
))
7673
} else {
7774
// Warn if merge-after is set to something other than manual
7875
mergeAfter := cfg.Plugins.ChangelogGenerator.GetMergeAfter()
7976
if mergeAfter != "manual" {
80-
printer.PrintWarning(fmt.Sprintf("Warning: 'merge-after' is set to '%s' in your configuration.", mergeAfter))
81-
printer.PrintInfo("Versioned changelog files are already being merged automatically.")
82-
printer.PrintInfo("This manual merge command may result in duplicate entries or unexpected behavior.")
83-
fmt.Println("")
77+
fmt.Println(ty.Compose(
78+
printer.Warning(fmt.Sprintf("Warning: 'merge-after' is set to '%s' in your configuration.", mergeAfter)),
79+
printer.Info("Versioned changelog files are already being merged automatically."),
80+
printer.Info("This manual merge command may result in duplicate entries or unexpected behavior."),
81+
))
8482
}
8583
}
8684

@@ -98,8 +96,8 @@ func runMergeCmd(cmd *cli.Command, cfg *config.Config) error {
9896
return fmt.Errorf("failed to merge changelog files: %w", err)
9997
}
10098

101-
printer.PrintSuccess(fmt.Sprintf("Successfully merged changelog files from %s into %s",
102-
genCfg.ChangesDir, genCfg.ChangelogPath))
99+
printer.PrintFaint(fmt.Sprintf("Merged changelog files from %s into %s",
100+
printer.Info(genCfg.ChangesDir), printer.Info(genCfg.ChangelogPath)))
103101

104102
return nil
105103
}

internal/commands/changelog/changelogcmd_test.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ func TestChangelogMergeCmd_Success(t *testing.T) {
109109
}
110110

111111
// Check success message
112-
expectedMsg := "Successfully merged changelog files"
112+
expectedMsg := "Merged changelog files"
113113
if !strings.Contains(output, expectedMsg) {
114114
t.Errorf("expected output to contain %q, got:\n%s", expectedMsg, output)
115115
}
@@ -225,7 +225,7 @@ func TestChangelogMergeCmd_NoVersionedFiles(t *testing.T) {
225225
}
226226

227227
// Should still report success (nothing to merge)
228-
expectedMsg := "Successfully merged changelog files"
228+
expectedMsg := "Merged changelog files"
229229
if !strings.Contains(output, expectedMsg) {
230230
t.Errorf("expected output to contain %q, got:\n%s", expectedMsg, output)
231231
}
@@ -424,7 +424,7 @@ func TestChangelogMergeCmd_WarningWhenPluginDisabled(t *testing.T) {
424424
}
425425

426426
// Should still succeed with merge
427-
expectedMsg := "Successfully merged changelog files"
427+
expectedMsg := "Merged changelog files"
428428
if !strings.Contains(output, expectedMsg) {
429429
t.Errorf("expected output to contain %q, got:\n%s", expectedMsg, output)
430430
}
@@ -469,7 +469,7 @@ func TestChangelogMergeCmd_WarningWhenMergeAfterImmediate(t *testing.T) {
469469
}
470470

471471
// Should still succeed with merge
472-
expectedMsg := "Successfully merged changelog files"
472+
expectedMsg := "Merged changelog files"
473473
if !strings.Contains(output, expectedMsg) {
474474
t.Errorf("expected output to contain %q, got:\n%s", expectedMsg, output)
475475
}
@@ -520,7 +520,7 @@ func TestChangelogMergeCmd_NoWarningWhenMergeAfterManual(t *testing.T) {
520520
}
521521

522522
// Should still succeed with merge
523-
expectedMsg := "Successfully merged changelog files"
523+
expectedMsg := "Merged changelog files"
524524
if !strings.Contains(output, expectedMsg) {
525525
t.Errorf("expected output to contain %q, got:\n%s", expectedMsg, output)
526526
}

internal/commands/discover/discovercmd.go

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"github.com/indaco/sley/internal/config"
99
"github.com/indaco/sley/internal/core"
1010
"github.com/indaco/sley/internal/discovery"
11+
"github.com/indaco/sley/internal/printer"
1112
"github.com/urfave/cli/v3"
1213
)
1314

@@ -102,21 +103,26 @@ func runDiscoverCmd(ctx context.Context, cmd *cli.Command, cfg *config.Config) e
102103

103104
// printQuietSummary prints a minimal summary of discovery results.
104105
func printQuietSummary(result *discovery.Result) {
106+
ty := printer.Typography()
105107
moduleCount := len(result.Modules)
106108
manifestCount := len(result.Manifests)
107109
mismatchCount := len(result.Mismatches)
108110

109-
fmt.Printf("Mode: %s | Modules: %d | Manifests: %d", result.Mode, moduleCount, manifestCount)
111+
pairs := [][2]string{
112+
{"Mode", result.Mode.String()},
113+
{"Modules", fmt.Sprintf("%d", moduleCount)},
114+
{"Manifests", fmt.Sprintf("%d", manifestCount)},
115+
}
110116

111117
if mismatchCount > 0 {
112-
fmt.Printf(" | Mismatches: %d", mismatchCount)
118+
pairs = append(pairs, [2]string{"Mismatches", fmt.Sprintf("%d", mismatchCount)})
113119
}
114120

115121
if result.PrimaryVersion() != "" {
116-
fmt.Printf(" | Version: %s", result.PrimaryVersion())
122+
pairs = append(pairs, [2]string{"Version", result.PrimaryVersion()})
117123
}
118124

119-
fmt.Println()
125+
fmt.Println(ty.KVGroup(pairs))
120126
}
121127

122128
// DiscoverAndSuggest is a helper function that performs discovery and returns

internal/commands/discover/discovercmd_test.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ func TestCLI_DiscoverCommand_QuietMode(t *testing.T) {
242242
}
243243

244244
// Verify quiet mode shows summary only
245-
if !strings.Contains(output, "Mode:") {
245+
if !strings.Contains(output, "Mode") {
246246
t.Errorf("expected 'Mode:' in quiet output, got: %q", output)
247247
}
248248
// Quiet mode should be shorter than regular output
@@ -467,7 +467,7 @@ func TestPrintQuietSummary_WithPrimaryVersion(t *testing.T) {
467467
if !strings.Contains(output, "5.0.0") {
468468
t.Errorf("expected version '5.0.0' in quiet summary, got: %q", output)
469469
}
470-
if !strings.Contains(output, "Version:") {
470+
if !strings.Contains(output, "Version") {
471471
t.Errorf("expected 'Version:' in quiet summary, got: %q", output)
472472
}
473473
}
@@ -492,8 +492,8 @@ func TestPrintQuietSummary_MultiModule(t *testing.T) {
492492
if !strings.Contains(output, "MultiModule") {
493493
t.Errorf("expected 'MultiModule' in quiet summary, got: %q", output)
494494
}
495-
if !strings.Contains(output, "Modules: 2") {
496-
t.Errorf("expected 'Modules: 2' in quiet summary, got: %q", output)
495+
if !strings.Contains(output, "Modules") {
496+
t.Errorf("expected 'Modules' in quiet summary, got: %q", output)
497497
}
498498
}
499499

@@ -519,10 +519,10 @@ func TestPrintQuietSummary_WithManifestsAndMismatches(t *testing.T) {
519519
t.Fatalf("Failed to capture stdout: %v", err)
520520
}
521521

522-
if !strings.Contains(output, "Manifests: 1") {
522+
if !strings.Contains(output, "Manifests") {
523523
t.Errorf("expected 'Manifests: 1' in quiet summary, got: %q", output)
524524
}
525-
if !strings.Contains(output, "Mismatches: 1") {
525+
if !strings.Contains(output, "Mismatches") {
526526
t.Errorf("expected 'Mismatches: 1' in quiet summary, got: %q", output)
527527
}
528528
}

0 commit comments

Comments
 (0)