pi-zentui 0.5.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 +52 -22
- package/extensions/zentui/config.ts +142 -1
- package/extensions/zentui/footer.ts +123 -5
- package/extensions/zentui/format.ts +154 -8
- package/extensions/zentui/git.ts +142 -3
- package/extensions/zentui/icons.ts +31 -4
- package/extensions/zentui/index.ts +31 -1
- package/extensions/zentui/package-version.ts +650 -0
- package/extensions/zentui/project-state.ts +15 -0
- package/extensions/zentui/settings-command.ts +66 -3
- 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)
|
|
@@ -158,9 +158,13 @@ Default config values — copy this and change any value you want:
|
|
|
158
158
|
"warning": 70,
|
|
159
159
|
"error": 90
|
|
160
160
|
},
|
|
161
|
+
"pathDisplay": {
|
|
162
|
+
"mode": "basename",
|
|
163
|
+
"depth": 0
|
|
164
|
+
},
|
|
161
165
|
"icons": {
|
|
162
166
|
"mode": "auto",
|
|
163
|
-
"cwd": "
|
|
167
|
+
"cwd": "",
|
|
164
168
|
"git": "",
|
|
165
169
|
"ahead": "↑",
|
|
166
170
|
"behind": "↓",
|
|
@@ -193,6 +197,10 @@ Default config values — copy this and change any value you want:
|
|
|
193
197
|
"separator": "bright-black",
|
|
194
198
|
"runtimePrefix": "",
|
|
195
199
|
"sessionDuration": "yellow",
|
|
200
|
+
"packageVersion": "208",
|
|
201
|
+
"gitCommit": "bold green",
|
|
202
|
+
"gitMetricsAdded": "bold green",
|
|
203
|
+
"gitMetricsDeleted": "bold red",
|
|
196
204
|
"username": "bold yellow",
|
|
197
205
|
"time": "bold yellow",
|
|
198
206
|
"os": "bold white",
|
|
@@ -230,7 +238,19 @@ Default config values — copy this and change any value you want:
|
|
|
230
238
|
"sessionDuration": false,
|
|
231
239
|
"username": false,
|
|
232
240
|
"time": false,
|
|
233
|
-
"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
|
|
234
254
|
},
|
|
235
255
|
"extensionStatuses": {
|
|
236
256
|
"defaultPlacement": "right",
|
|
@@ -244,11 +264,14 @@ Default config values — copy this and change any value you want:
|
|
|
244
264
|
- `projectRefreshIntervalMs`: project status polling interval; `0` disables polling. Values `1..4999` clamp up to `5000` (minimum 5s); invalid/non-finite values fall back to `30000`.
|
|
245
265
|
- `contextStyle`: `text` (default), `gauge`, or `text+gauge` for the context segment.
|
|
246
266
|
- `contextThresholds`: `{ warning, error }` percentages (default `70` / `90`) that select contextNormal / contextWarning / contextError colors.
|
|
267
|
+
- `pathDisplay`: controls how the cwd/`$cwd` path is shown. `mode` is `basename` (default, last segment only) or `full` (path with home contracted to `~`). In `full` mode, `depth` keeps only the last N trailing directories (`0` = entire path after `~`, max `5`); when parents are dropped the path is prefixed with `…/` (Starship-style). The `/zentui` **Layout** tab cycles path mode and path depth (`0`–`5`; depth is ignored for basename). Example: `~/Projects/foo/bar` with `depth: 2` → `…/foo/bar`.
|
|
247
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.
|
|
248
269
|
- `colorSources`: `theme` maps styles through Pi theme tokens; `terminal` emits terminal colors. `/zentui` switches these sources; manual JSON controls specific style values.
|
|
249
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.
|
|
250
|
-
- `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`.
|
|
251
|
-
- `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 and icon mode; set or clear custom formats with `/zentui format`.
|
|
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`.
|
|
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.
|
|
252
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.
|
|
253
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`.
|
|
254
277
|
- `editorAccent` styles the active editor rail and previous user-message rail when `features.copyFriendly` is disabled.
|
|
@@ -280,22 +303,29 @@ Center the branch between directory and cost:
|
|
|
280
303
|
|
|
281
304
|
### Variables
|
|
282
305
|
|
|
283
|
-
| Token | Aliases | Renders
|
|
284
|
-
| ------------------- | ------------ |
|
|
285
|
-
| `$cwd` | `$directory` | current directory
|
|
286
|
-
| `$git_branch` | `$branch` | git branch with icon
|
|
287
|
-
| `$git_status` | `$status` | `[!?↑]` status block
|
|
288
|
-
| `$git_state` | `$state` | `REBASING` / `MERGING` / … (optional `n/m`)
|
|
289
|
-
| `$
|
|
290
|
-
| `$
|
|
291
|
-
| `$
|
|
292
|
-
| `$
|
|
293
|
-
| `$
|
|
294
|
-
| `$
|
|
295
|
-
| `$
|
|
296
|
-
| `$
|
|
297
|
-
| `$
|
|
298
|
-
| `$
|
|
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 |
|
|
299
329
|
|
|
300
330
|
### `$fill` behavior
|
|
301
331
|
|
|
@@ -23,6 +23,14 @@ export type ContextThresholds = {
|
|
|
23
23
|
error: number;
|
|
24
24
|
};
|
|
25
25
|
|
|
26
|
+
export type PathDisplayMode = "basename" | "full";
|
|
27
|
+
|
|
28
|
+
export type PathDisplayConfig = {
|
|
29
|
+
mode: PathDisplayMode;
|
|
30
|
+
/** Trailing directories to show in full mode. 0 = unlimited; clamped to 0..5. */
|
|
31
|
+
depth: number;
|
|
32
|
+
};
|
|
33
|
+
|
|
26
34
|
export type ColorSourcesConfig = {
|
|
27
35
|
starship: ColorSource;
|
|
28
36
|
editor: ColorSource;
|
|
@@ -40,6 +48,8 @@ export type FooterSegmentsConfig = {
|
|
|
40
48
|
gitBranch: boolean;
|
|
41
49
|
gitStatus: boolean;
|
|
42
50
|
gitCounts: boolean;
|
|
51
|
+
gitCommit: boolean;
|
|
52
|
+
gitMetrics: boolean;
|
|
43
53
|
runtime: boolean;
|
|
44
54
|
context: boolean;
|
|
45
55
|
tokens: boolean;
|
|
@@ -48,11 +58,31 @@ export type FooterSegmentsConfig = {
|
|
|
48
58
|
username: boolean;
|
|
49
59
|
time: boolean;
|
|
50
60
|
os: boolean;
|
|
61
|
+
packageVersion: boolean;
|
|
51
62
|
};
|
|
52
63
|
|
|
53
64
|
export type ExtensionStatusPlacement = "off" | "left" | "middle" | "right";
|
|
54
65
|
export type ExtensionStatusColorMode = "zentui" | "original";
|
|
55
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
|
+
|
|
56
86
|
const DEFAULT_EXTENSION_STATUS_COLOR_MODE: ExtensionStatusColorMode = "zentui";
|
|
57
87
|
|
|
58
88
|
export type ExtensionStatusesConfig = {
|
|
@@ -69,6 +99,7 @@ export type PolishedTuiConfig = {
|
|
|
69
99
|
footerFormat: string;
|
|
70
100
|
contextStyle: ContextStyle;
|
|
71
101
|
contextThresholds: ContextThresholds;
|
|
102
|
+
pathDisplay: PathDisplayConfig;
|
|
72
103
|
icons: ResolvedIcons;
|
|
73
104
|
colors: {
|
|
74
105
|
cwd: ColorSpec;
|
|
@@ -83,6 +114,10 @@ export type PolishedTuiConfig = {
|
|
|
83
114
|
runtimePrefix: ColorSpec;
|
|
84
115
|
extensionStatus: ColorSpec;
|
|
85
116
|
sessionDuration: ColorSpec;
|
|
117
|
+
packageVersion: ColorSpec;
|
|
118
|
+
gitCommit: ColorSpec;
|
|
119
|
+
gitMetricsAdded: ColorSpec;
|
|
120
|
+
gitMetricsDeleted: ColorSpec;
|
|
86
121
|
username: ColorSpec;
|
|
87
122
|
time: ColorSpec;
|
|
88
123
|
os: ColorSpec;
|
|
@@ -101,6 +136,8 @@ export type PolishedTuiConfig = {
|
|
|
101
136
|
colorSources: ColorSourcesConfig;
|
|
102
137
|
features: UiFeaturesConfig;
|
|
103
138
|
footerSegments: FooterSegmentsConfig;
|
|
139
|
+
gitCommit: GitCommitConfig;
|
|
140
|
+
gitMetrics: GitMetricsConfig;
|
|
104
141
|
extensionStatuses: ExtensionStatusesConfig;
|
|
105
142
|
};
|
|
106
143
|
|
|
@@ -121,6 +158,13 @@ export const FOOTER_FORMAT_VARIABLES = [
|
|
|
121
158
|
"context",
|
|
122
159
|
"tokens",
|
|
123
160
|
"cost",
|
|
161
|
+
"package",
|
|
162
|
+
"package_version",
|
|
163
|
+
"git_commit",
|
|
164
|
+
"git_tag",
|
|
165
|
+
"git_metrics",
|
|
166
|
+
"git_added",
|
|
167
|
+
"git_deleted",
|
|
124
168
|
"sep",
|
|
125
169
|
] as const;
|
|
126
170
|
|
|
@@ -133,6 +177,8 @@ export const FOOTER_FORMAT_ALIASES: Record<string, string> = {
|
|
|
133
177
|
branch: "git_branch",
|
|
134
178
|
status: "git_status",
|
|
135
179
|
state: "git_state",
|
|
180
|
+
commit: "git_commit",
|
|
181
|
+
tag: "git_tag",
|
|
136
182
|
duration: "session_duration",
|
|
137
183
|
separator: "sep",
|
|
138
184
|
};
|
|
@@ -144,6 +190,7 @@ export const defaultConfig: PolishedTuiConfig = {
|
|
|
144
190
|
footerFormat: "",
|
|
145
191
|
contextStyle: "text",
|
|
146
192
|
contextThresholds: { warning: 70, error: 90 },
|
|
193
|
+
pathDisplay: { mode: "basename", depth: 0 },
|
|
147
194
|
icons: {
|
|
148
195
|
mode: "auto",
|
|
149
196
|
...NERD_DEFAULT_ICONS,
|
|
@@ -161,6 +208,10 @@ export const defaultConfig: PolishedTuiConfig = {
|
|
|
161
208
|
runtimePrefix: "",
|
|
162
209
|
extensionStatus: "bright-black",
|
|
163
210
|
sessionDuration: "yellow",
|
|
211
|
+
packageVersion: "208",
|
|
212
|
+
gitCommit: "bold green",
|
|
213
|
+
gitMetricsAdded: "bold green",
|
|
214
|
+
gitMetricsDeleted: "bold red",
|
|
164
215
|
username: "bold yellow",
|
|
165
216
|
time: "bold yellow",
|
|
166
217
|
os: "bold white",
|
|
@@ -188,6 +239,18 @@ export const defaultConfig: PolishedTuiConfig = {
|
|
|
188
239
|
username: false,
|
|
189
240
|
time: false,
|
|
190
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,
|
|
191
254
|
},
|
|
192
255
|
extensionStatuses: {
|
|
193
256
|
defaultPlacement: "right",
|
|
@@ -244,6 +307,18 @@ function parseContextThresholds(value: unknown): ContextThresholds {
|
|
|
244
307
|
return { warning, error };
|
|
245
308
|
}
|
|
246
309
|
|
|
310
|
+
function parsePathDisplay(value: unknown): PathDisplayConfig {
|
|
311
|
+
const defaults = defaultConfig.pathDisplay;
|
|
312
|
+
if (!isRecord(value)) return { ...defaults };
|
|
313
|
+
const mode = value.mode === "full" || value.mode === "basename" ? value.mode : defaults.mode;
|
|
314
|
+
const rawDepth = value.depth;
|
|
315
|
+
const depth =
|
|
316
|
+
typeof rawDepth === "number" && Number.isFinite(rawDepth) && rawDepth >= 0
|
|
317
|
+
? Math.min(5, Math.floor(rawDepth))
|
|
318
|
+
: defaults.depth;
|
|
319
|
+
return { mode, depth };
|
|
320
|
+
}
|
|
321
|
+
|
|
247
322
|
function stringValue(record: Record<string, unknown>, key: string): string | undefined {
|
|
248
323
|
const value = record[key];
|
|
249
324
|
return typeof value === "string" ? value : undefined;
|
|
@@ -308,6 +383,10 @@ function normalizeColors(record: Record<string, unknown>): Partial<PolishedTuiCo
|
|
|
308
383
|
runtimePrefix: colorValue(record, "runtimePrefix"),
|
|
309
384
|
extensionStatus: colorValue(record, "extensionStatus"),
|
|
310
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"),
|
|
311
390
|
username: colorValue(record, "username"),
|
|
312
391
|
time: colorValue(record, "time"),
|
|
313
392
|
os: colorValue(record, "os"),
|
|
@@ -355,6 +434,41 @@ function normalizeFooterSegments(record: Record<string, unknown>): FooterSegment
|
|
|
355
434
|
username: footerSegmentValue(record, "username"),
|
|
356
435
|
time: footerSegmentValue(record, "time"),
|
|
357
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,
|
|
358
472
|
};
|
|
359
473
|
}
|
|
360
474
|
|
|
@@ -415,7 +529,10 @@ function isFooterSegmentKey(value: string): value is keyof FooterSegmentsConfig
|
|
|
415
529
|
value === "sessionDuration" ||
|
|
416
530
|
value === "username" ||
|
|
417
531
|
value === "time" ||
|
|
418
|
-
value === "os"
|
|
532
|
+
value === "os" ||
|
|
533
|
+
value === "packageVersion" ||
|
|
534
|
+
value === "gitCommit" ||
|
|
535
|
+
value === "gitMetrics"
|
|
419
536
|
);
|
|
420
537
|
}
|
|
421
538
|
|
|
@@ -483,11 +600,18 @@ export function mergeConfig(parsed: unknown): PolishedTuiConfig {
|
|
|
483
600
|
const extensionStatuses = isRecord(config.extensionStatuses)
|
|
484
601
|
? normalizeExtensionStatuses(config.extensionStatuses as Record<string, unknown>)
|
|
485
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;
|
|
486
609
|
return {
|
|
487
610
|
projectRefreshIntervalMs: parseProjectRefreshIntervalMs(config.projectRefreshIntervalMs),
|
|
488
611
|
footerFormat: stringValue(config, "footerFormat") ?? "",
|
|
489
612
|
contextStyle: parseContextStyle(config.contextStyle),
|
|
490
613
|
contextThresholds: parseContextThresholds(config.contextThresholds),
|
|
614
|
+
pathDisplay: parsePathDisplay(config.pathDisplay),
|
|
491
615
|
icons: resolveConfiguredIcons(iconMode, iconOverrides),
|
|
492
616
|
colors: {
|
|
493
617
|
...defaultConfig.colors,
|
|
@@ -496,6 +620,8 @@ export function mergeConfig(parsed: unknown): PolishedTuiConfig {
|
|
|
496
620
|
colorSources: { ...colorSources },
|
|
497
621
|
features: { ...features },
|
|
498
622
|
footerSegments: { ...footerSegments },
|
|
623
|
+
gitCommit,
|
|
624
|
+
gitMetrics,
|
|
499
625
|
extensionStatuses: {
|
|
500
626
|
defaultPlacement: extensionStatuses.defaultPlacement,
|
|
501
627
|
placements: { ...extensionStatuses.placements },
|
|
@@ -616,6 +742,21 @@ export function saveContextThresholdsPatch(
|
|
|
616
742
|
return mergeConfig(record);
|
|
617
743
|
}
|
|
618
744
|
|
|
745
|
+
export function savePathDisplayPatch(
|
|
746
|
+
patch: Partial<PathDisplayConfig>,
|
|
747
|
+
path = configPath,
|
|
748
|
+
): PolishedTuiConfig {
|
|
749
|
+
const record = readConfigRecord(path);
|
|
750
|
+
const existing = isRecord(record.pathDisplay)
|
|
751
|
+
? { ...(record.pathDisplay as Record<string, unknown>) }
|
|
752
|
+
: {};
|
|
753
|
+
if (patch.mode !== undefined) existing.mode = patch.mode;
|
|
754
|
+
if (patch.depth !== undefined) existing.depth = patch.depth;
|
|
755
|
+
record.pathDisplay = existing;
|
|
756
|
+
writeFileSync(path, `${JSON.stringify(record, null, 2)}\n`, "utf8");
|
|
757
|
+
return mergeConfig(record);
|
|
758
|
+
}
|
|
759
|
+
|
|
619
760
|
export function saveExtensionStatusPlacement(
|
|
620
761
|
key: string,
|
|
621
762
|
placement: ExtensionStatusPlacement,
|
|
@@ -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,
|
|
@@ -172,7 +175,10 @@ export function installFooter(
|
|
|
172
175
|
theme,
|
|
173
176
|
colorSource,
|
|
174
177
|
config.colors.cwd,
|
|
175
|
-
formatCwdLabel(ctx.cwd, config.icons.cwd
|
|
178
|
+
formatCwdLabel(ctx.cwd, config.icons.cwd, {
|
|
179
|
+
mode: config.pathDisplay.mode,
|
|
180
|
+
depth: config.pathDisplay.depth,
|
|
181
|
+
}),
|
|
176
182
|
);
|
|
177
183
|
const branch = state.branch;
|
|
178
184
|
const contextUsage = ctx.getContextUsage();
|
|
@@ -290,16 +296,92 @@ export function installFooter(
|
|
|
290
296
|
);
|
|
291
297
|
case "cost":
|
|
292
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
|
+
: "";
|
|
293
317
|
case "sep":
|
|
294
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
|
+
: "";
|
|
295
363
|
default:
|
|
296
364
|
return "";
|
|
297
365
|
}
|
|
298
366
|
};
|
|
299
|
-
const branchParts =
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
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
|
+
}
|
|
303
385
|
const gitStatusParts = config.footerSegments.gitStatus && statusBlock ? [statusBlock] : [];
|
|
304
386
|
const showGitState = config.footerSegments.gitBranch || config.footerSegments.gitStatus;
|
|
305
387
|
const gitStateParts = showGitState && gitStateBlock ? [gitStateBlock] : [];
|
|
@@ -315,6 +397,39 @@ export function installFooter(
|
|
|
315
397
|
iconMode,
|
|
316
398
|
)
|
|
317
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
|
+
: "";
|
|
318
433
|
|
|
319
434
|
const sessionDurationSegment = (() => {
|
|
320
435
|
if (!config.footerSegments.sessionDuration || !state.sessionStartEpoch) return "";
|
|
@@ -349,6 +464,9 @@ export function installFooter(
|
|
|
349
464
|
usernameSegment,
|
|
350
465
|
config.footerSegments.cwd ? cwdLabel : "",
|
|
351
466
|
branchLabel,
|
|
467
|
+
gitCommitLabel,
|
|
468
|
+
gitMetricsLabel,
|
|
469
|
+
packageVersionLabel,
|
|
352
470
|
runtimeLabel,
|
|
353
471
|
sessionDurationSegment,
|
|
354
472
|
]
|