pi-zentui 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +46 -21
- package/extensions/zentui/config.ts +104 -1
- package/extensions/zentui/footer.ts +119 -4
- package/extensions/zentui/format.ts +80 -1
- package/extensions/zentui/git.ts +142 -3
- package/extensions/zentui/icons.ts +31 -4
- package/extensions/zentui/index.ts +26 -1
- package/extensions/zentui/package-version.ts +650 -0
- package/extensions/zentui/project-state.ts +15 -0
- package/extensions/zentui/settings-command.ts +13 -1
- package/extensions/zentui/state.ts +3 -0
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -17,11 +17,11 @@ Zentui brings two popular aesthetics to Pi:
|
|
|
17
17
|
|
|
18
18
|
### Footer (Starship-inspired)
|
|
19
19
|
|
|
20
|
-
-
|
|
20
|
+
- `dirname` — current directory (`basename` by default; optional `full` path with directory depth via `pathDisplay`)
|
|
21
21
|
- `on branch` — git branch with icon
|
|
22
22
|
- `[!?↑]` — git status indicators (modified, untracked, ahead/behind, stashed, etc.)
|
|
23
23
|
- `via v5.5.0` — runtime detection with version and Starship-style Nerd Font runtime/language modules
|
|
24
|
-
- Optional segments (off by default): `user@host`, current time, OS icon, and
|
|
24
|
+
- Optional segments (off by default): `user@host`, current time, OS icon, session duration, and the **project package version** (e.g. `package.json` → `0.6.0`) — distinct from the runtime segment, which shows the installed toolchain
|
|
25
25
|
- Right side shows context usage, token counts, and cost
|
|
26
26
|
- Built-in footer segments can be shown or hidden individually from `/zentui`
|
|
27
27
|
- Fully custom Starship-style layout via a `footerFormat` template string — see [Footer Format Template](#footer-format-template)
|
|
@@ -164,7 +164,7 @@ Default config values — copy this and change any value you want:
|
|
|
164
164
|
},
|
|
165
165
|
"icons": {
|
|
166
166
|
"mode": "auto",
|
|
167
|
-
"cwd": "
|
|
167
|
+
"cwd": "",
|
|
168
168
|
"git": "",
|
|
169
169
|
"ahead": "↑",
|
|
170
170
|
"behind": "↓",
|
|
@@ -197,6 +197,10 @@ Default config values — copy this and change any value you want:
|
|
|
197
197
|
"separator": "bright-black",
|
|
198
198
|
"runtimePrefix": "",
|
|
199
199
|
"sessionDuration": "yellow",
|
|
200
|
+
"packageVersion": "208",
|
|
201
|
+
"gitCommit": "bold green",
|
|
202
|
+
"gitMetricsAdded": "bold green",
|
|
203
|
+
"gitMetricsDeleted": "bold red",
|
|
200
204
|
"username": "bold yellow",
|
|
201
205
|
"time": "bold yellow",
|
|
202
206
|
"os": "bold white",
|
|
@@ -234,7 +238,19 @@ Default config values — copy this and change any value you want:
|
|
|
234
238
|
"sessionDuration": false,
|
|
235
239
|
"username": false,
|
|
236
240
|
"time": false,
|
|
237
|
-
"os": false
|
|
241
|
+
"os": false,
|
|
242
|
+
"packageVersion": false,
|
|
243
|
+
"gitCommit": false,
|
|
244
|
+
"gitMetrics": false
|
|
245
|
+
},
|
|
246
|
+
"gitCommit": {
|
|
247
|
+
"hashLength": 7,
|
|
248
|
+
"onlyDetached": true,
|
|
249
|
+
"showTag": true
|
|
250
|
+
},
|
|
251
|
+
"gitMetrics": {
|
|
252
|
+
"onlyNonzero": true,
|
|
253
|
+
"ignoreSubmodules": false
|
|
238
254
|
},
|
|
239
255
|
"extensionStatuses": {
|
|
240
256
|
"defaultPlacement": "right",
|
|
@@ -252,8 +268,10 @@ Default config values — copy this and change any value you want:
|
|
|
252
268
|
- `icons`: every shown icon key is configurable; omit any key to use the Zentui default. `icons.mode` is `auto` | `nerd` | `ascii` (default `auto`, same glyphs as nerd). ASCII mode swaps in plain fallbacks for statusline icons and runtime symbols — useful without a Nerd Font. Custom per-icon strings always win over mode defaults. Custom `icons.os` always wins; when left at the mode default, Zentui maps the OS icon by platform. `rail` sets the vertical glyph drawn as the left rail of the active editor frame and previous user messages when `copyFriendly` is disabled (default `│`; any single Unicode vertical or block glyph). `editorPrompt` controls an optional copy-friendly editor prompt glyph; the default is `""` so copy-friendly mode stays rail-free.
|
|
253
269
|
- `colorSources`: `theme` maps styles through Pi theme tokens; `terminal` emits terminal colors. `/zentui` switches these sources; manual JSON controls specific style values.
|
|
254
270
|
- `features`: `editor` enables Zentui's custom editor, selector borders, and previous-message chrome. `statusLine` enables Zentui's custom footer/status line. `copyFriendly` hides editor and previous-message rail glyphs so native terminal selection copies less chrome. All three can be changed from `/zentui` or direct slash-command arguments.
|
|
255
|
-
- `footerSegments`: show or hide individual built-in footer segments (`cwd`, `gitBranch`, `gitStatus`, `gitCounts`, `runtime`, `sessionDuration`, `username`, `time`, `os`, `context`, `tokens`, `cost`). Toggle them from the `Built-in segments` tab in `/zentui`.
|
|
271
|
+
- `footerSegments`: show or hide individual built-in footer segments (`cwd`, `gitBranch`, `gitStatus`, `gitCounts`, `gitCommit`, `gitMetrics`, `runtime`, `packageVersion`, `sessionDuration`, `username`, `time`, `os`, `context`, `tokens`, `cost`). Toggle them from the `Built-in segments` tab in `/zentui`.
|
|
256
272
|
- `footerFormat`: optional Starship-style template string that fully controls the footer layout. When set, it overrides `footerSegments`. See [Footer Format Template](#footer-format-template) below. The `/zentui` **Layout** tab configures context style, path display mode/depth, and icon mode; set or clear custom formats with `/zentui format`.
|
|
273
|
+
- `gitCommit`: Starship [`git_commit`](https://starship.rs/config/#git-commit)-style options for the `gitCommit` footer segment. `hashLength` (default `7`, clamped to `4`–`40`) controls the short-hash display length. `onlyDetached` (default `true`) shows the hash mainly on detached HEAD. `showTag` (default `true`) appends an exact-match tag (`git describe --tags --exact-match HEAD`). The tag probe piggybacks on the existing git refresh — it only runs when both the segment and `showTag` are on, and misses/failures degrade silently.
|
|
274
|
+
- `gitMetrics`: Starship [`git_metrics`](https://starship.rs/config/#git-metrics)-style options for the `gitMetrics` footer segment. Uses `git diff HEAD --numstat` (staged + unstaged combined — the Starship “total dirty” view) to show aggregate `+added −deleted` line counts. `onlyNonzero` (default `true`) omits each zero component independently and hides the segment entirely at `0/0`. `ignoreSubmodules` (default `false`) adds `--ignore-submodules=all`. The numstat diff piggybacks on the existing git refresh and uses a hard 2s timeout; a metrics-only failure degrades silently without discarding fresh branch/status data. On very large monorepos the diff may lag or be omitted on timeout.
|
|
257
275
|
- `extensionStatuses`: controls third-party statuses published by other Pi extensions through `ctx.ui.setStatus()`. `defaultPlacement` and each `placements` value can be `off`, `left`, `middle`, or `right`. The `Extension segments` tab in `/zentui` lists only statuses that are currently active.
|
|
258
276
|
- The shown `editor*` values match the default `theme` source. Omit those keys to keep Zentui's source-aware defaults when switching between `theme` and `terminal`.
|
|
259
277
|
- `editorAccent` styles the active editor rail and previous user-message rail when `features.copyFriendly` is disabled.
|
|
@@ -285,22 +303,29 @@ Center the branch between directory and cost:
|
|
|
285
303
|
|
|
286
304
|
### Variables
|
|
287
305
|
|
|
288
|
-
| Token | Aliases | Renders
|
|
289
|
-
| ------------------- | ------------ |
|
|
290
|
-
| `$cwd` | `$directory` | current directory
|
|
291
|
-
| `$git_branch` | `$branch` | git branch with icon
|
|
292
|
-
| `$git_status` | `$status` | `[!?↑]` status block
|
|
293
|
-
| `$git_state` | `$state` | `REBASING` / `MERGING` / … (optional `n/m`)
|
|
294
|
-
| `$
|
|
295
|
-
| `$
|
|
296
|
-
| `$
|
|
297
|
-
| `$
|
|
298
|
-
| `$
|
|
299
|
-
| `$
|
|
300
|
-
| `$
|
|
301
|
-
| `$
|
|
302
|
-
| `$
|
|
303
|
-
| `$
|
|
306
|
+
| Token | Aliases | Renders |
|
|
307
|
+
| ------------------- | ------------ | ------------------------------------------------------------------- |
|
|
308
|
+
| `$cwd` | `$directory` | current directory |
|
|
309
|
+
| `$git_branch` | `$branch` | git branch with icon |
|
|
310
|
+
| `$git_status` | `$status` | `[!?↑]` status block |
|
|
311
|
+
| `$git_state` | `$state` | `REBASING` / `MERGING` / … (optional `n/m`) |
|
|
312
|
+
| `$git_commit` | `$commit` | short commit hash (+ exact-match tag when present) |
|
|
313
|
+
| `$git_tag` | `$tag` | exact-match tag at HEAD |
|
|
314
|
+
| `$git_metrics` | | aggregate line changes `+added −deleted` |
|
|
315
|
+
| `$git_added` | | added line count (`+N`) |
|
|
316
|
+
| `$git_deleted` | | deleted line count (`−N`) |
|
|
317
|
+
| `$runtime` | | runtime icon + version |
|
|
318
|
+
| `$package` | | project package version, `is <glyph> <version>` (manifest-derived) |
|
|
319
|
+
| `$package_version` | | raw project package version (no icon) |
|
|
320
|
+
| `$session_duration` | `$duration` | session running time |
|
|
321
|
+
| `$username` | | `user@host` |
|
|
322
|
+
| `$os` | | operating-system icon |
|
|
323
|
+
| `$time` | | current time `HH:MM` |
|
|
324
|
+
| `$context` | | context usage (text and/or gauge via config) |
|
|
325
|
+
| `$tokens` | | input/output token counts |
|
|
326
|
+
| `$cost` | | session cost |
|
|
327
|
+
| `$sep` | `$separator` | themed `\|` using `colors.separator` |
|
|
328
|
+
| `$fill` | — | special: splits zones |
|
|
304
329
|
|
|
305
330
|
### `$fill` behavior
|
|
306
331
|
|
|
@@ -48,6 +48,8 @@ export type FooterSegmentsConfig = {
|
|
|
48
48
|
gitBranch: boolean;
|
|
49
49
|
gitStatus: boolean;
|
|
50
50
|
gitCounts: boolean;
|
|
51
|
+
gitCommit: boolean;
|
|
52
|
+
gitMetrics: boolean;
|
|
51
53
|
runtime: boolean;
|
|
52
54
|
context: boolean;
|
|
53
55
|
tokens: boolean;
|
|
@@ -56,11 +58,31 @@ export type FooterSegmentsConfig = {
|
|
|
56
58
|
username: boolean;
|
|
57
59
|
time: boolean;
|
|
58
60
|
os: boolean;
|
|
61
|
+
packageVersion: boolean;
|
|
59
62
|
};
|
|
60
63
|
|
|
61
64
|
export type ExtensionStatusPlacement = "off" | "left" | "middle" | "right";
|
|
62
65
|
export type ExtensionStatusColorMode = "zentui" | "original";
|
|
63
66
|
|
|
67
|
+
/**
|
|
68
|
+
* Starship `git_commit`-style options.
|
|
69
|
+
* See https://starship.rs/config/#git-commit
|
|
70
|
+
*/
|
|
71
|
+
export type GitCommitConfig = {
|
|
72
|
+
hashLength: number;
|
|
73
|
+
onlyDetached: boolean;
|
|
74
|
+
showTag: boolean;
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Starship `git_metrics`-style options.
|
|
79
|
+
* See https://starship.rs/config/#git-metrics
|
|
80
|
+
*/
|
|
81
|
+
export type GitMetricsConfig = {
|
|
82
|
+
onlyNonzero: boolean;
|
|
83
|
+
ignoreSubmodules: boolean;
|
|
84
|
+
};
|
|
85
|
+
|
|
64
86
|
const DEFAULT_EXTENSION_STATUS_COLOR_MODE: ExtensionStatusColorMode = "zentui";
|
|
65
87
|
|
|
66
88
|
export type ExtensionStatusesConfig = {
|
|
@@ -92,6 +114,10 @@ export type PolishedTuiConfig = {
|
|
|
92
114
|
runtimePrefix: ColorSpec;
|
|
93
115
|
extensionStatus: ColorSpec;
|
|
94
116
|
sessionDuration: ColorSpec;
|
|
117
|
+
packageVersion: ColorSpec;
|
|
118
|
+
gitCommit: ColorSpec;
|
|
119
|
+
gitMetricsAdded: ColorSpec;
|
|
120
|
+
gitMetricsDeleted: ColorSpec;
|
|
95
121
|
username: ColorSpec;
|
|
96
122
|
time: ColorSpec;
|
|
97
123
|
os: ColorSpec;
|
|
@@ -110,6 +136,8 @@ export type PolishedTuiConfig = {
|
|
|
110
136
|
colorSources: ColorSourcesConfig;
|
|
111
137
|
features: UiFeaturesConfig;
|
|
112
138
|
footerSegments: FooterSegmentsConfig;
|
|
139
|
+
gitCommit: GitCommitConfig;
|
|
140
|
+
gitMetrics: GitMetricsConfig;
|
|
113
141
|
extensionStatuses: ExtensionStatusesConfig;
|
|
114
142
|
};
|
|
115
143
|
|
|
@@ -130,6 +158,13 @@ export const FOOTER_FORMAT_VARIABLES = [
|
|
|
130
158
|
"context",
|
|
131
159
|
"tokens",
|
|
132
160
|
"cost",
|
|
161
|
+
"package",
|
|
162
|
+
"package_version",
|
|
163
|
+
"git_commit",
|
|
164
|
+
"git_tag",
|
|
165
|
+
"git_metrics",
|
|
166
|
+
"git_added",
|
|
167
|
+
"git_deleted",
|
|
133
168
|
"sep",
|
|
134
169
|
] as const;
|
|
135
170
|
|
|
@@ -142,6 +177,8 @@ export const FOOTER_FORMAT_ALIASES: Record<string, string> = {
|
|
|
142
177
|
branch: "git_branch",
|
|
143
178
|
status: "git_status",
|
|
144
179
|
state: "git_state",
|
|
180
|
+
commit: "git_commit",
|
|
181
|
+
tag: "git_tag",
|
|
145
182
|
duration: "session_duration",
|
|
146
183
|
separator: "sep",
|
|
147
184
|
};
|
|
@@ -171,6 +208,10 @@ export const defaultConfig: PolishedTuiConfig = {
|
|
|
171
208
|
runtimePrefix: "",
|
|
172
209
|
extensionStatus: "bright-black",
|
|
173
210
|
sessionDuration: "yellow",
|
|
211
|
+
packageVersion: "208",
|
|
212
|
+
gitCommit: "bold green",
|
|
213
|
+
gitMetricsAdded: "bold green",
|
|
214
|
+
gitMetricsDeleted: "bold red",
|
|
174
215
|
username: "bold yellow",
|
|
175
216
|
time: "bold yellow",
|
|
176
217
|
os: "bold white",
|
|
@@ -198,6 +239,18 @@ export const defaultConfig: PolishedTuiConfig = {
|
|
|
198
239
|
username: false,
|
|
199
240
|
time: false,
|
|
200
241
|
os: false,
|
|
242
|
+
packageVersion: false,
|
|
243
|
+
gitCommit: false,
|
|
244
|
+
gitMetrics: false,
|
|
245
|
+
},
|
|
246
|
+
gitCommit: {
|
|
247
|
+
hashLength: 7,
|
|
248
|
+
onlyDetached: true,
|
|
249
|
+
showTag: true,
|
|
250
|
+
},
|
|
251
|
+
gitMetrics: {
|
|
252
|
+
onlyNonzero: true,
|
|
253
|
+
ignoreSubmodules: false,
|
|
201
254
|
},
|
|
202
255
|
extensionStatuses: {
|
|
203
256
|
defaultPlacement: "right",
|
|
@@ -330,6 +383,10 @@ function normalizeColors(record: Record<string, unknown>): Partial<PolishedTuiCo
|
|
|
330
383
|
runtimePrefix: colorValue(record, "runtimePrefix"),
|
|
331
384
|
extensionStatus: colorValue(record, "extensionStatus"),
|
|
332
385
|
sessionDuration: colorValue(record, "sessionDuration"),
|
|
386
|
+
packageVersion: colorValue(record, "packageVersion"),
|
|
387
|
+
gitCommit: colorValue(record, "gitCommit"),
|
|
388
|
+
gitMetricsAdded: colorValue(record, "gitMetricsAdded"),
|
|
389
|
+
gitMetricsDeleted: colorValue(record, "gitMetricsDeleted"),
|
|
333
390
|
username: colorValue(record, "username"),
|
|
334
391
|
time: colorValue(record, "time"),
|
|
335
392
|
os: colorValue(record, "os"),
|
|
@@ -377,6 +434,41 @@ function normalizeFooterSegments(record: Record<string, unknown>): FooterSegment
|
|
|
377
434
|
username: footerSegmentValue(record, "username"),
|
|
378
435
|
time: footerSegmentValue(record, "time"),
|
|
379
436
|
os: footerSegmentValue(record, "os"),
|
|
437
|
+
packageVersion: footerSegmentValue(record, "packageVersion"),
|
|
438
|
+
gitCommit: footerSegmentValue(record, "gitCommit"),
|
|
439
|
+
gitMetrics: footerSegmentValue(record, "gitMetrics"),
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
/** Clamp hashLength to Git's valid abbreviation range [4, 40]. */
|
|
444
|
+
function normalizeGitHashLength(value: unknown): number {
|
|
445
|
+
const parsed = typeof value === "number" ? value : Number(value);
|
|
446
|
+
if (!Number.isFinite(parsed)) return defaultConfig.gitCommit.hashLength;
|
|
447
|
+
const rounded = Math.round(parsed);
|
|
448
|
+
return Math.min(40, Math.max(4, rounded));
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
function normalizeGitCommitConfig(record: Record<string, unknown>): GitCommitConfig {
|
|
452
|
+
return {
|
|
453
|
+
hashLength: normalizeGitHashLength(record.hashLength),
|
|
454
|
+
onlyDetached:
|
|
455
|
+
typeof record.onlyDetached === "boolean"
|
|
456
|
+
? record.onlyDetached
|
|
457
|
+
: defaultConfig.gitCommit.onlyDetached,
|
|
458
|
+
showTag: typeof record.showTag === "boolean" ? record.showTag : defaultConfig.gitCommit.showTag,
|
|
459
|
+
};
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
function normalizeGitMetricsConfig(record: Record<string, unknown>): GitMetricsConfig {
|
|
463
|
+
return {
|
|
464
|
+
onlyNonzero:
|
|
465
|
+
typeof record.onlyNonzero === "boolean"
|
|
466
|
+
? record.onlyNonzero
|
|
467
|
+
: defaultConfig.gitMetrics.onlyNonzero,
|
|
468
|
+
ignoreSubmodules:
|
|
469
|
+
typeof record.ignoreSubmodules === "boolean"
|
|
470
|
+
? record.ignoreSubmodules
|
|
471
|
+
: defaultConfig.gitMetrics.ignoreSubmodules,
|
|
380
472
|
};
|
|
381
473
|
}
|
|
382
474
|
|
|
@@ -437,7 +529,10 @@ function isFooterSegmentKey(value: string): value is keyof FooterSegmentsConfig
|
|
|
437
529
|
value === "sessionDuration" ||
|
|
438
530
|
value === "username" ||
|
|
439
531
|
value === "time" ||
|
|
440
|
-
value === "os"
|
|
532
|
+
value === "os" ||
|
|
533
|
+
value === "packageVersion" ||
|
|
534
|
+
value === "gitCommit" ||
|
|
535
|
+
value === "gitMetrics"
|
|
441
536
|
);
|
|
442
537
|
}
|
|
443
538
|
|
|
@@ -505,6 +600,12 @@ export function mergeConfig(parsed: unknown): PolishedTuiConfig {
|
|
|
505
600
|
const extensionStatuses = isRecord(config.extensionStatuses)
|
|
506
601
|
? normalizeExtensionStatuses(config.extensionStatuses as Record<string, unknown>)
|
|
507
602
|
: defaultConfig.extensionStatuses;
|
|
603
|
+
const gitCommit = isRecord(config.gitCommit)
|
|
604
|
+
? normalizeGitCommitConfig(config.gitCommit as Record<string, unknown>)
|
|
605
|
+
: defaultConfig.gitCommit;
|
|
606
|
+
const gitMetrics = isRecord(config.gitMetrics)
|
|
607
|
+
? normalizeGitMetricsConfig(config.gitMetrics as Record<string, unknown>)
|
|
608
|
+
: defaultConfig.gitMetrics;
|
|
508
609
|
return {
|
|
509
610
|
projectRefreshIntervalMs: parseProjectRefreshIntervalMs(config.projectRefreshIntervalMs),
|
|
510
611
|
footerFormat: stringValue(config, "footerFormat") ?? "",
|
|
@@ -519,6 +620,8 @@ export function mergeConfig(parsed: unknown): PolishedTuiConfig {
|
|
|
519
620
|
colorSources: { ...colorSources },
|
|
520
621
|
features: { ...features },
|
|
521
622
|
footerSegments: { ...footerSegments },
|
|
623
|
+
gitCommit,
|
|
624
|
+
gitMetrics,
|
|
522
625
|
extensionStatuses: {
|
|
523
626
|
defaultPlacement: extensionStatuses.defaultPlacement,
|
|
524
627
|
placements: { ...extensionStatuses.placements },
|
|
@@ -9,7 +9,10 @@ import {
|
|
|
9
9
|
buildSessionDurationLabel,
|
|
10
10
|
contextColorTier,
|
|
11
11
|
formatCwdLabel,
|
|
12
|
+
formatGitCommitSegment,
|
|
13
|
+
formatGitMetricsSegment,
|
|
12
14
|
formatOsLabel,
|
|
15
|
+
formatPackageVersionSegment,
|
|
13
16
|
formatRuntimeSegment,
|
|
14
17
|
formatTimeLabel,
|
|
15
18
|
formatUsernameHostLabel,
|
|
@@ -293,16 +296,92 @@ export function installFooter(
|
|
|
293
296
|
);
|
|
294
297
|
case "cost":
|
|
295
298
|
return renderStyleForSource(theme, colorSource, config.colors.cost, state.costLabel);
|
|
299
|
+
case "package":
|
|
300
|
+
return formatPackageVersionSegment(
|
|
301
|
+
theme,
|
|
302
|
+
state.packageVersion,
|
|
303
|
+
colorSource,
|
|
304
|
+
iconMode,
|
|
305
|
+
config.icons.package,
|
|
306
|
+
config.colors.packageVersion,
|
|
307
|
+
);
|
|
308
|
+
case "package_version":
|
|
309
|
+
return state.packageVersion?.version
|
|
310
|
+
? renderStyleForSource(
|
|
311
|
+
theme,
|
|
312
|
+
colorSource,
|
|
313
|
+
config.colors.packageVersion,
|
|
314
|
+
state.packageVersion.version,
|
|
315
|
+
)
|
|
316
|
+
: "";
|
|
296
317
|
case "sep":
|
|
297
318
|
return renderStyleForSource(theme, colorSource, config.colors.separator, " | ");
|
|
319
|
+
case "git_commit":
|
|
320
|
+
return formatGitCommitSegment(
|
|
321
|
+
theme,
|
|
322
|
+
state.commit,
|
|
323
|
+
config.gitCommit,
|
|
324
|
+
colorSource,
|
|
325
|
+
config.colors.gitCommit,
|
|
326
|
+
);
|
|
327
|
+
case "git_tag":
|
|
328
|
+
return config.gitCommit.showTag && state.commit?.tag
|
|
329
|
+
? renderStyleForSource(
|
|
330
|
+
theme,
|
|
331
|
+
colorSource,
|
|
332
|
+
config.colors.gitCommit,
|
|
333
|
+
state.commit.tag,
|
|
334
|
+
)
|
|
335
|
+
: "";
|
|
336
|
+
case "git_metrics":
|
|
337
|
+
return formatGitMetricsSegment(
|
|
338
|
+
theme,
|
|
339
|
+
state.metrics,
|
|
340
|
+
config.gitMetrics,
|
|
341
|
+
colorSource,
|
|
342
|
+
config.colors.gitMetricsAdded,
|
|
343
|
+
config.colors.gitMetricsDeleted,
|
|
344
|
+
);
|
|
345
|
+
case "git_added":
|
|
346
|
+
return state.metrics
|
|
347
|
+
? renderStyleForSource(
|
|
348
|
+
theme,
|
|
349
|
+
colorSource,
|
|
350
|
+
config.colors.gitMetricsAdded,
|
|
351
|
+
`+${state.metrics.added}`,
|
|
352
|
+
)
|
|
353
|
+
: "";
|
|
354
|
+
case "git_deleted":
|
|
355
|
+
return state.metrics
|
|
356
|
+
? renderStyleForSource(
|
|
357
|
+
theme,
|
|
358
|
+
colorSource,
|
|
359
|
+
config.colors.gitMetricsDeleted,
|
|
360
|
+
`−${state.metrics.deleted}`,
|
|
361
|
+
)
|
|
362
|
+
: "";
|
|
298
363
|
default:
|
|
299
364
|
return "";
|
|
300
365
|
}
|
|
301
366
|
};
|
|
302
|
-
const branchParts =
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
367
|
+
const branchParts: string[] = [];
|
|
368
|
+
if (config.footerSegments.gitBranch) {
|
|
369
|
+
if (branch) {
|
|
370
|
+
branchParts.push("on", gitIcon, gitColor(branch));
|
|
371
|
+
} else if (state.commit?.detached) {
|
|
372
|
+
// `HEAD` uses git-branch style; `(hash)` uses git-commit style
|
|
373
|
+
// (bold green) per Starship `git_commit` format.
|
|
374
|
+
branchParts.push("on", gitIcon, gitColor("HEAD"));
|
|
375
|
+
if (config.footerSegments.gitCommit && state.commit.oid) {
|
|
376
|
+
const shortHash = state.commit.oid.slice(0, config.gitCommit.hashLength);
|
|
377
|
+
const tag = config.gitCommit.showTag && state.commit.tag ? state.commit.tag : "";
|
|
378
|
+
const inner = [shortHash, tag].filter(Boolean).join(" ");
|
|
379
|
+
branchParts.push(
|
|
380
|
+
renderStyleForSource(theme, colorSource, config.colors.gitCommit, `(${inner})`),
|
|
381
|
+
);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
}
|
|
306
385
|
const gitStatusParts = config.footerSegments.gitStatus && statusBlock ? [statusBlock] : [];
|
|
307
386
|
const showGitState = config.footerSegments.gitBranch || config.footerSegments.gitStatus;
|
|
308
387
|
const gitStateParts = showGitState && gitStateBlock ? [gitStateBlock] : [];
|
|
@@ -318,6 +397,39 @@ export function installFooter(
|
|
|
318
397
|
iconMode,
|
|
319
398
|
)
|
|
320
399
|
: "";
|
|
400
|
+
const packageVersionLabel = config.footerSegments.packageVersion
|
|
401
|
+
? formatPackageVersionSegment(
|
|
402
|
+
theme,
|
|
403
|
+
state.packageVersion,
|
|
404
|
+
colorSource,
|
|
405
|
+
iconMode,
|
|
406
|
+
config.icons.package,
|
|
407
|
+
config.colors.packageVersion,
|
|
408
|
+
)
|
|
409
|
+
: "";
|
|
410
|
+
// Skip standalone gitCommit when hash is already folded into the
|
|
411
|
+
// branch display on detached HEAD.
|
|
412
|
+
const hashFoldedIntoBranch = state.commit?.detached && config.footerSegments.gitBranch;
|
|
413
|
+
const gitCommitLabel =
|
|
414
|
+
config.footerSegments.gitCommit && !hashFoldedIntoBranch
|
|
415
|
+
? formatGitCommitSegment(
|
|
416
|
+
theme,
|
|
417
|
+
state.commit,
|
|
418
|
+
config.gitCommit,
|
|
419
|
+
colorSource,
|
|
420
|
+
config.colors.gitCommit,
|
|
421
|
+
)
|
|
422
|
+
: "";
|
|
423
|
+
const gitMetricsLabel = config.footerSegments.gitMetrics
|
|
424
|
+
? formatGitMetricsSegment(
|
|
425
|
+
theme,
|
|
426
|
+
state.metrics,
|
|
427
|
+
config.gitMetrics,
|
|
428
|
+
colorSource,
|
|
429
|
+
config.colors.gitMetricsAdded,
|
|
430
|
+
config.colors.gitMetricsDeleted,
|
|
431
|
+
)
|
|
432
|
+
: "";
|
|
321
433
|
|
|
322
434
|
const sessionDurationSegment = (() => {
|
|
323
435
|
if (!config.footerSegments.sessionDuration || !state.sessionStartEpoch) return "";
|
|
@@ -352,6 +464,9 @@ export function installFooter(
|
|
|
352
464
|
usernameSegment,
|
|
353
465
|
config.footerSegments.cwd ? cwdLabel : "",
|
|
354
466
|
branchLabel,
|
|
467
|
+
gitCommitLabel,
|
|
468
|
+
gitMetricsLabel,
|
|
469
|
+
packageVersionLabel,
|
|
355
470
|
runtimeLabel,
|
|
356
471
|
sessionDurationSegment,
|
|
357
472
|
]
|
|
@@ -8,11 +8,66 @@ import type {
|
|
|
8
8
|
ContextThresholds,
|
|
9
9
|
PathDisplayMode,
|
|
10
10
|
} from "./config";
|
|
11
|
+
import type { GitCommitInfo, GitMetricsInfo } from "./git";
|
|
11
12
|
import type { IconMode } from "./icons";
|
|
12
|
-
import { resolveOsIcon, resolveRuntimeSymbol } from "./icons";
|
|
13
|
+
import { resolveOsIcon, resolvePackageIcon, resolveRuntimeSymbol } from "./icons";
|
|
14
|
+
import type { PackageVersionResult } from "./package-version";
|
|
13
15
|
import type { RuntimeInfo } from "./runtime";
|
|
14
16
|
import { renderStyleForSource } from "./style";
|
|
15
17
|
|
|
18
|
+
/**
|
|
19
|
+
* Starship `git_commit` style — render a short hash, optionally with an
|
|
20
|
+
* exact-match tag. See https://starship.rs/config/#git-commit
|
|
21
|
+
*
|
|
22
|
+
* Visibility is decided by the caller; this helper only formats the data.
|
|
23
|
+
* `hashLength` is clamped to [4, 40] upstream.
|
|
24
|
+
*/
|
|
25
|
+
export function formatGitCommitSegment(
|
|
26
|
+
theme: Pick<Theme, "fg">,
|
|
27
|
+
commit: GitCommitInfo | undefined,
|
|
28
|
+
config: { hashLength: number; onlyDetached: boolean; showTag: boolean },
|
|
29
|
+
colorSource: ColorSource,
|
|
30
|
+
style: ColorSpec,
|
|
31
|
+
): string {
|
|
32
|
+
if (!commit?.oid) return "";
|
|
33
|
+
// Starship's only_detached hides the whole module when attached.
|
|
34
|
+
if (config.onlyDetached && !commit.detached) return "";
|
|
35
|
+
const hash = commit.oid.slice(0, config.hashLength);
|
|
36
|
+
const tag = config.showTag && commit.tag ? commit.tag : "";
|
|
37
|
+
if (!hash && !tag) return "";
|
|
38
|
+
const label = [hash, tag].filter(Boolean).join(" ");
|
|
39
|
+
return renderStyleForSource(theme, colorSource, style, label);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Starship `git_metrics` style — render `+added −deleted` line counts.
|
|
44
|
+
* See https://starship.rs/config/#git-metrics
|
|
45
|
+
*
|
|
46
|
+
* When `onlyNonzero` is true, each zero component is omitted independently
|
|
47
|
+
* and the whole segment hides at 0/0.
|
|
48
|
+
*/
|
|
49
|
+
export function formatGitMetricsSegment(
|
|
50
|
+
theme: Pick<Theme, "fg">,
|
|
51
|
+
metrics: GitMetricsInfo | null | undefined,
|
|
52
|
+
config: { onlyNonzero: boolean },
|
|
53
|
+
colorSource: ColorSource,
|
|
54
|
+
addedStyle: ColorSpec,
|
|
55
|
+
deletedStyle: ColorSpec,
|
|
56
|
+
): string {
|
|
57
|
+
if (!metrics) return "";
|
|
58
|
+
const showAdded = !config.onlyNonzero || metrics.added > 0;
|
|
59
|
+
const showDeleted = !config.onlyNonzero || metrics.deleted > 0;
|
|
60
|
+
if (!showAdded && !showDeleted) return "";
|
|
61
|
+
const parts: string[] = [];
|
|
62
|
+
if (showAdded) {
|
|
63
|
+
parts.push(renderStyleForSource(theme, colorSource, addedStyle, `+${metrics.added}`));
|
|
64
|
+
}
|
|
65
|
+
if (showDeleted) {
|
|
66
|
+
parts.push(renderStyleForSource(theme, colorSource, deletedStyle, `−${metrics.deleted}`));
|
|
67
|
+
}
|
|
68
|
+
return parts.join(" ");
|
|
69
|
+
}
|
|
70
|
+
|
|
16
71
|
export type UsageTotals = {
|
|
17
72
|
input: number;
|
|
18
73
|
output: number;
|
|
@@ -244,6 +299,30 @@ export function formatRuntimeSegment(
|
|
|
244
299
|
return `${renderStyleForSource(theme, colorSource, prefixStyle, "via")} ${renderStyleForSource(theme, colorSource, runtime.style, label)}`;
|
|
245
300
|
}
|
|
246
301
|
|
|
302
|
+
/**
|
|
303
|
+
* Render the package-version segment in Starship `is <glyph> <version>` shape.
|
|
304
|
+
*
|
|
305
|
+
* Distinct from the runtime segment: this surfaces the project's own
|
|
306
|
+
* manifest version (e.g. `package.json#version`), not the installed
|
|
307
|
+
* toolchain version. Glyph comes from the Starship Nerd Font preset
|
|
308
|
+
* (https://starship.rs/presets/nerd-font); default color `208` matches
|
|
309
|
+
* the Starship `package` module default
|
|
310
|
+
* (https://starship.rs/config/#package-version).
|
|
311
|
+
*/
|
|
312
|
+
export function formatPackageVersionSegment(
|
|
313
|
+
theme: Pick<Theme, "fg">,
|
|
314
|
+
pkg: PackageVersionResult | undefined,
|
|
315
|
+
colorSource: ColorSource,
|
|
316
|
+
mode: IconMode = "auto",
|
|
317
|
+
configuredIcon: string = "",
|
|
318
|
+
versionStyle: ColorSpec = "208",
|
|
319
|
+
): string {
|
|
320
|
+
if (!pkg) return "";
|
|
321
|
+
const icon = resolvePackageIcon(configuredIcon, mode);
|
|
322
|
+
const label = `${icon} ${pkg.version}`;
|
|
323
|
+
return `${renderStyleForSource(theme, colorSource, "", "is")} ${renderStyleForSource(theme, colorSource, versionStyle, label)}`;
|
|
324
|
+
}
|
|
325
|
+
|
|
247
326
|
export type FormatCwdOptions = {
|
|
248
327
|
mode?: PathDisplayMode;
|
|
249
328
|
/** Trailing directory components to keep in full mode. 0 = unlimited. */
|