pi-one-ui 0.7.0 → 0.7.1
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/CHANGELOG.md +25 -1
- package/README.en.md +19 -6
- package/README.md +19 -6
- package/extensions/app/config/context.ts +42 -0
- package/extensions/app/config/editor.ts +80 -0
- package/extensions/app/config/footer.ts +291 -0
- package/extensions/app/config/panel.ts +1 -5
- package/extensions/app/config/renderer.ts +1 -6
- package/extensions/app/config/shell.ts +358 -1435
- package/extensions/app/config/store.ts +22 -1
- package/extensions/app/config/values.ts +33 -0
- package/extensions/app/config/working-line.ts +100 -0
- package/extensions/app/overlay/input-router.ts +56 -32
- package/extensions/app/overlay/overlay-manager.ts +183 -21
- package/extensions/app/runtime/event-coordinator.ts +90 -42
- package/extensions/{features → app/runtime}/flush-docked-bash.ts +12 -2
- package/extensions/app/runtime/render-scheduler.ts +35 -31
- package/extensions/app/runtime/tui-runtime.ts +315 -312
- package/extensions/app/settings/controller.ts +202 -0
- package/extensions/app/settings/panel.ts +81 -0
- package/extensions/app/settings/presets.ts +43 -0
- package/extensions/features/context-inspector/index.ts +83 -662
- package/extensions/layouts/context/index.ts +58 -161
- package/extensions/layouts/context/message/user-message.ts +1 -1
- package/extensions/layouts/context/renderer/index.ts +31 -13
- package/extensions/layouts/context/renderer/mouse/interaction.ts +29 -14
- package/extensions/layouts/editor/controller.ts +9 -18
- package/extensions/layouts/editor/factory.ts +3 -3
- package/extensions/layouts/footer/controller.ts +30 -19
- package/extensions/layouts/footer/footer.ts +2 -2
- package/extensions/layouts/overlay/context-inspector.ts +497 -0
- package/extensions/{app → layouts}/overlay/selector-border.ts +5 -5
- package/extensions/{app → layouts}/overlay/selector-controller.ts +1 -1
- package/extensions/layouts/overlay/settings-panel.ts +359 -0
- package/extensions/{app/commands → layouts/overlay}/settings-previews.ts +4 -4
- package/extensions/layouts/working-line/controller.ts +3 -29
- package/extensions/layouts/working-line/working-line.ts +17 -114
- package/extensions/shared/working-line-text.ts +108 -0
- package/package.json +1 -1
- package/extensions/app/host/pi-extension-port.ts +0 -25
- package/extensions/app/host/pi-ui-port.ts +0 -52
- package/extensions/app/host/tui-capabilities.ts +0 -27
- package/extensions/app/ownership/layout-registry.ts +0 -65
- package/extensions/app/ownership.ts +0 -32
- package/extensions/app/panel.ts +0 -770
- package/extensions/app/presets.ts +0 -35
- package/extensions/app/runtime/runtime-state.ts +0 -83
- /package/extensions/{layouts/working-line → app/config}/working-line-messages.ts +0 -0
- /package/extensions/app/{ownership → runtime}/prototype-patch-registry.ts +0 -0
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { normalizeWorkingLineMessages } from "../../layouts/working-line/working-line.ts";
|
|
2
|
-
import { PI_WORKING_LINE_MESSAGES } from "../../layouts/working-line/working-line-messages.ts";
|
|
3
1
|
import {
|
|
4
2
|
ICON_GLYPH_KEYS,
|
|
5
3
|
type IconGlyphs,
|
|
@@ -10,208 +8,81 @@ import {
|
|
|
10
8
|
resolveConfiguredIcons,
|
|
11
9
|
} from "../../shared/icons.ts";
|
|
12
10
|
import { isSupportedColorSpec } from "../../shared/style.ts";
|
|
11
|
+
import {
|
|
12
|
+
normalizeUserMessages,
|
|
13
|
+
type UserMessagesComponentConfig,
|
|
14
|
+
} from "./context.ts";
|
|
15
|
+
import {
|
|
16
|
+
defaultEditor,
|
|
17
|
+
type EditorBorderColorMode,
|
|
18
|
+
type EditorComponentConfig,
|
|
19
|
+
type EditorStyle,
|
|
20
|
+
type MinimalistConfig,
|
|
21
|
+
type MinimalistEditorStyleConfig,
|
|
22
|
+
type ModelLabelSource,
|
|
23
|
+
normalizeEditor,
|
|
24
|
+
parseEditorBorderColorMode,
|
|
25
|
+
parseEditorModelLabel,
|
|
26
|
+
parseEditorStyle,
|
|
27
|
+
} from "./editor.ts";
|
|
28
|
+
import {
|
|
29
|
+
type CompactFooterMaxLines,
|
|
30
|
+
type ContextStyle,
|
|
31
|
+
type ContextThresholds,
|
|
32
|
+
defaultFooter,
|
|
33
|
+
defaultFooterSegments,
|
|
34
|
+
type ExtensionStatusColorMode,
|
|
35
|
+
type ExtensionStatusPlacement,
|
|
36
|
+
type FooterComponentConfig,
|
|
37
|
+
type FooterSegmentsConfig,
|
|
38
|
+
type GitBranchConfig,
|
|
39
|
+
type GitCommitConfig,
|
|
40
|
+
type GitMetricsConfig,
|
|
41
|
+
isExtensionStatusColorMode,
|
|
42
|
+
isExtensionStatusPlacement,
|
|
43
|
+
normalizeFooter,
|
|
44
|
+
type PathDisplayConfig,
|
|
45
|
+
parseCompactFooterMaxLines,
|
|
46
|
+
parseContextStyle,
|
|
47
|
+
parseSeparatorStyle,
|
|
48
|
+
type SeparatorStyle,
|
|
49
|
+
type StarshipFooterStyleConfig,
|
|
50
|
+
} from "./footer.ts";
|
|
13
51
|
import {
|
|
14
52
|
type ConfigRecord,
|
|
15
53
|
configStore,
|
|
16
54
|
configPath as defaultConfigPath,
|
|
17
55
|
mutateConfigFile,
|
|
18
56
|
} from "./store.ts";
|
|
57
|
+
import { booleanValue, overlayKnown, recordValue } from "./values.ts";
|
|
58
|
+
import {
|
|
59
|
+
defaultWorkingLine,
|
|
60
|
+
normalizeWorkingLine,
|
|
61
|
+
type WorkingLineComponentConfig,
|
|
62
|
+
type WorkingLineComponentPatch,
|
|
63
|
+
} from "./working-line.ts";
|
|
19
64
|
|
|
20
|
-
export type ColorSpec = string;
|
|
21
65
|
export type { IconMode } from "../../shared/icons.ts";
|
|
22
|
-
|
|
23
|
-
export
|
|
24
|
-
export
|
|
25
|
-
export
|
|
26
|
-
export type
|
|
27
|
-
export type UserMessageStyle =
|
|
28
|
-
| "framed"
|
|
29
|
-
| "framed-copy-friendly"
|
|
30
|
-
| "compact"
|
|
31
|
-
| "labeled";
|
|
66
|
+
export * from "./context.ts";
|
|
67
|
+
export * from "./editor.ts";
|
|
68
|
+
export * from "./footer.ts";
|
|
69
|
+
export * from "./working-line.ts";
|
|
70
|
+
export type ColorSpec = string;
|
|
32
71
|
export type SelectorBorderStyle = "zentui";
|
|
33
|
-
export type
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
| "pinwheel"
|
|
38
|
-
| "claude-inspired"
|
|
39
|
-
| "pulse";
|
|
40
|
-
export type WorkingLineTextAnimation = "classic" | "kitt" | "disabled";
|
|
72
|
+
export type SelectorBordersComponentConfig = {
|
|
73
|
+
enabled: boolean;
|
|
74
|
+
style: SelectorBorderStyle;
|
|
75
|
+
};
|
|
41
76
|
export type ComponentStyleOwner =
|
|
42
77
|
| "editor"
|
|
43
78
|
| "userMessages"
|
|
44
79
|
| "selectorBorders"
|
|
45
80
|
| "footer";
|
|
46
|
-
export type MinimalistPathDisplayMode = "compact" | "project" | "full";
|
|
47
|
-
export type EditorBorderColorMode = "static" | "adaptive";
|
|
48
|
-
export type CompactFooterMaxLines = 1 | 2 | 3 | "unlimited";
|
|
49
|
-
|
|
50
|
-
export const DEFAULT_COMPACT_FOOTER_FORMAT =
|
|
51
|
-
"$cwd$wrap(in $session_name)$wrap(on $git_branch) $git_status$wrap$context$wrap_sep$tokens";
|
|
52
|
-
|
|
53
|
-
export type ContextThresholds = {
|
|
54
|
-
warning: number;
|
|
55
|
-
error: number;
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
export type PathDisplayMode = "basename" | "full";
|
|
59
|
-
|
|
60
|
-
export type PathDisplayConfig = {
|
|
61
|
-
mode: PathDisplayMode;
|
|
62
|
-
/** Trailing directories to show in full mode. 0 = unlimited; clamped to 0..5. */
|
|
63
|
-
depth: number;
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
export type GitBranchMaxLength = "full" | number;
|
|
67
|
-
|
|
68
|
-
export type GitBranchConfig = {
|
|
69
|
-
maxLength: GitBranchMaxLength;
|
|
70
|
-
};
|
|
71
|
-
|
|
72
81
|
export type UiFeaturesConfig = {
|
|
73
82
|
editor: boolean;
|
|
74
83
|
statusLine: boolean;
|
|
75
84
|
viewportIndicators: boolean;
|
|
76
85
|
};
|
|
77
|
-
|
|
78
|
-
export type FooterSegmentsConfig = {
|
|
79
|
-
cwd: boolean;
|
|
80
|
-
sessionName: boolean;
|
|
81
|
-
gitBranch: boolean;
|
|
82
|
-
gitStatus: boolean;
|
|
83
|
-
gitCounts: boolean;
|
|
84
|
-
gitCommit: boolean;
|
|
85
|
-
gitMetrics: boolean;
|
|
86
|
-
runtime: boolean;
|
|
87
|
-
modelInfo: boolean;
|
|
88
|
-
context: boolean;
|
|
89
|
-
tokens: boolean;
|
|
90
|
-
cost: boolean;
|
|
91
|
-
sessionDuration: boolean;
|
|
92
|
-
username: boolean;
|
|
93
|
-
time: boolean;
|
|
94
|
-
os: boolean;
|
|
95
|
-
packageVersion: boolean;
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
export type MinimalistEditorStyleConfig = {
|
|
99
|
-
pathDisplay: MinimalistPathDisplayMode;
|
|
100
|
-
/** Controls the Editor directory label independently of its format and the Footer. */
|
|
101
|
-
showCwd: boolean;
|
|
102
|
-
showSessionName: boolean;
|
|
103
|
-
showTimer: boolean;
|
|
104
|
-
showCost: boolean;
|
|
105
|
-
showGit: boolean;
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
/** Temporary name retained for existing settings consumers. */
|
|
109
|
-
export type MinimalistConfig = MinimalistEditorStyleConfig;
|
|
110
|
-
|
|
111
|
-
export type EditorStylesConfig = {
|
|
112
|
-
minimalist: MinimalistEditorStyleConfig;
|
|
113
|
-
};
|
|
114
|
-
|
|
115
|
-
export type EditorComponentConfig = {
|
|
116
|
-
style: EditorStyle;
|
|
117
|
-
borderColorMode: EditorBorderColorMode;
|
|
118
|
-
modelLabel: ModelLabelSource;
|
|
119
|
-
viewportIndicators: boolean;
|
|
120
|
-
styles: {
|
|
121
|
-
minimalist: MinimalistEditorStyleConfig;
|
|
122
|
-
};
|
|
123
|
-
};
|
|
124
|
-
|
|
125
|
-
export type FramedUserMessageStyleConfig = Record<string, never>;
|
|
126
|
-
export type FramedCopyFriendlyUserMessageStyleConfig = Record<string, never>;
|
|
127
|
-
export type CompactUserMessageStyleConfig = Record<string, never>;
|
|
128
|
-
export type LabeledUserMessageStyleConfig = Record<string, never>;
|
|
129
|
-
|
|
130
|
-
export type UserMessagesComponentConfig = {
|
|
131
|
-
enabled: boolean;
|
|
132
|
-
style: UserMessageStyle;
|
|
133
|
-
styles: {
|
|
134
|
-
framed: FramedUserMessageStyleConfig;
|
|
135
|
-
"framed-copy-friendly": FramedCopyFriendlyUserMessageStyleConfig;
|
|
136
|
-
compact: CompactUserMessageStyleConfig;
|
|
137
|
-
labeled: LabeledUserMessageStyleConfig;
|
|
138
|
-
};
|
|
139
|
-
};
|
|
140
|
-
|
|
141
|
-
export type SelectorBordersComponentConfig = {
|
|
142
|
-
enabled: boolean;
|
|
143
|
-
style: SelectorBorderStyle;
|
|
144
|
-
};
|
|
145
|
-
|
|
146
|
-
export type StarshipFooterStyleConfig = {
|
|
147
|
-
format: string;
|
|
148
|
-
responsive: boolean;
|
|
149
|
-
compactFormat: string;
|
|
150
|
-
compactMaxLines: CompactFooterMaxLines;
|
|
151
|
-
separator: SeparatorStyle;
|
|
152
|
-
contextStyle: ContextStyle;
|
|
153
|
-
contextThresholds: ContextThresholds;
|
|
154
|
-
pathDisplay: PathDisplayConfig;
|
|
155
|
-
segments: FooterSegmentsConfig;
|
|
156
|
-
gitBranch: GitBranchConfig;
|
|
157
|
-
gitCommit: GitCommitConfig;
|
|
158
|
-
gitMetrics: GitMetricsConfig;
|
|
159
|
-
extensionStatuses: ExtensionStatusesConfig;
|
|
160
|
-
};
|
|
161
|
-
|
|
162
|
-
export type FooterComponentConfig = {
|
|
163
|
-
style: FooterStyle;
|
|
164
|
-
modelLabel: ModelLabelSource;
|
|
165
|
-
styles: {
|
|
166
|
-
starship: StarshipFooterStyleConfig;
|
|
167
|
-
};
|
|
168
|
-
};
|
|
169
|
-
|
|
170
|
-
export type WorkingLineMessagesConfig = {
|
|
171
|
-
custom: boolean;
|
|
172
|
-
values: string[];
|
|
173
|
-
};
|
|
174
|
-
|
|
175
|
-
export type WorkingLineSegmentsConfig = {
|
|
176
|
-
tool: boolean;
|
|
177
|
-
elapsed: boolean;
|
|
178
|
-
thought: boolean;
|
|
179
|
-
tokens: boolean;
|
|
180
|
-
};
|
|
181
|
-
|
|
182
|
-
export const DEFAULT_WORKING_LINE_SPINNER_INTERVAL_MS = 100;
|
|
183
|
-
export const DEFAULT_WORKING_LINE_TEXT_INTERVAL_MS = 60;
|
|
184
|
-
export const MIN_WORKING_LINE_INTERVAL_MS = 30;
|
|
185
|
-
export const MAX_WORKING_LINE_INTERVAL_MS = 1000;
|
|
186
|
-
|
|
187
|
-
export function isValidWorkingLineIntervalMs(value: unknown): value is number {
|
|
188
|
-
return (
|
|
189
|
-
typeof value === "number" &&
|
|
190
|
-
Number.isSafeInteger(value) &&
|
|
191
|
-
value >= MIN_WORKING_LINE_INTERVAL_MS &&
|
|
192
|
-
value <= MAX_WORKING_LINE_INTERVAL_MS
|
|
193
|
-
);
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
export type WorkingLineComponentConfig = {
|
|
197
|
-
enabled: boolean;
|
|
198
|
-
turnSummary: boolean;
|
|
199
|
-
spinner: WorkingLineSpinner;
|
|
200
|
-
spinnerIntervalMs: number;
|
|
201
|
-
animateSpinnerColor: boolean;
|
|
202
|
-
textIntervalMs: number;
|
|
203
|
-
textAnimation: WorkingLineTextAnimation;
|
|
204
|
-
messages: WorkingLineMessagesConfig;
|
|
205
|
-
segments: WorkingLineSegmentsConfig;
|
|
206
|
-
};
|
|
207
|
-
|
|
208
|
-
export type WorkingLineComponentPatch = Partial<
|
|
209
|
-
Omit<WorkingLineComponentConfig, "messages" | "segments">
|
|
210
|
-
> & {
|
|
211
|
-
messages?: Partial<WorkingLineMessagesConfig>;
|
|
212
|
-
segments?: Partial<WorkingLineSegmentsConfig>;
|
|
213
|
-
};
|
|
214
|
-
|
|
215
86
|
export type ComponentsConfig = {
|
|
216
87
|
editor: EditorComponentConfig;
|
|
217
88
|
userMessages: UserMessagesComponentConfig;
|
|
@@ -219,49 +90,6 @@ export type ComponentsConfig = {
|
|
|
219
90
|
selectorBorders: SelectorBordersComponentConfig;
|
|
220
91
|
footer: FooterComponentConfig;
|
|
221
92
|
};
|
|
222
|
-
|
|
223
|
-
export type ExtensionStatusPlacement = "off" | "left" | "middle" | "right";
|
|
224
|
-
export type ExtensionStatusColorMode = "zentui" | "original";
|
|
225
|
-
|
|
226
|
-
/**
|
|
227
|
-
* Starship `git_commit`-style options.
|
|
228
|
-
* See https://starship.rs/config/#git-commit
|
|
229
|
-
*/
|
|
230
|
-
export type GitCommitConfig = {
|
|
231
|
-
hashLength: number;
|
|
232
|
-
onlyDetached: boolean;
|
|
233
|
-
showTag: boolean;
|
|
234
|
-
};
|
|
235
|
-
|
|
236
|
-
/**
|
|
237
|
-
* Starship `git_metrics`-style options.
|
|
238
|
-
* See https://starship.rs/config/#git-metrics
|
|
239
|
-
*/
|
|
240
|
-
export type GitMetricsConfig = {
|
|
241
|
-
onlyNonzero: boolean;
|
|
242
|
-
ignoreSubmodules: boolean;
|
|
243
|
-
};
|
|
244
|
-
|
|
245
|
-
const DEFAULT_EXTENSION_STATUS_PLACEMENT: ExtensionStatusPlacement = "right";
|
|
246
|
-
const DEFAULT_EXTENSION_STATUS_COLOR_MODE: ExtensionStatusColorMode = "zentui";
|
|
247
|
-
|
|
248
|
-
export type ExtensionStatusesConfig = {
|
|
249
|
-
defaultPlacement: ExtensionStatusPlacement;
|
|
250
|
-
placements: Record<string, ExtensionStatusPlacement>;
|
|
251
|
-
colorModes: Record<string, ExtensionStatusColorMode>;
|
|
252
|
-
};
|
|
253
|
-
|
|
254
|
-
const DEFAULT_PROJECT_REFRESH_INTERVAL_MS = 30_000;
|
|
255
|
-
const MIN_PROJECT_REFRESH_INTERVAL_MS = 5_000;
|
|
256
|
-
export const DEFAULT_EDITOR_METADATA_FORMAT = "$model $provider( $thinking)";
|
|
257
|
-
|
|
258
|
-
export type ZentuiConfig = {
|
|
259
|
-
projectRefreshIntervalMs: number;
|
|
260
|
-
icons: ResolvedIcons;
|
|
261
|
-
colors: PolishedTuiColors;
|
|
262
|
-
components: ComponentsConfig;
|
|
263
|
-
};
|
|
264
|
-
|
|
265
93
|
export type PolishedTuiColors = {
|
|
266
94
|
cwd?: ColorSpec;
|
|
267
95
|
sessionName: ColorSpec;
|
|
@@ -299,172 +127,17 @@ export type PolishedTuiColors = {
|
|
|
299
127
|
workingLineMid?: ColorSpec;
|
|
300
128
|
workingLineHigh?: ColorSpec;
|
|
301
129
|
};
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
compactFooterFormat: string;
|
|
308
|
-
compactFooterMaxLines: CompactFooterMaxLines;
|
|
309
|
-
editorMetadataFormat: string;
|
|
310
|
-
separator: SeparatorStyle;
|
|
311
|
-
contextStyle: ContextStyle;
|
|
312
|
-
editorModelLabel: ModelLabelSource;
|
|
313
|
-
editorStyle: EditorStyle;
|
|
314
|
-
editorStyles: EditorStylesConfig;
|
|
315
|
-
editorBorderColorMode: EditorBorderColorMode;
|
|
316
|
-
contextThresholds: ContextThresholds;
|
|
317
|
-
pathDisplay: PathDisplayConfig;
|
|
318
|
-
gitBranch: GitBranchConfig;
|
|
319
|
-
features: UiFeaturesConfig;
|
|
320
|
-
footerSegments: FooterSegmentsConfig;
|
|
321
|
-
gitCommit: GitCommitConfig;
|
|
322
|
-
gitMetrics: GitMetricsConfig;
|
|
323
|
-
extensionStatuses: ExtensionStatusesConfig;
|
|
324
|
-
};
|
|
325
|
-
|
|
326
|
-
/**
|
|
327
|
-
* Canonical footer format variable names. In a `footerFormat` string these
|
|
328
|
-
* are written as `$name` or `${name}`.
|
|
329
|
-
*/
|
|
330
|
-
export const FOOTER_FORMAT_VARIABLES = [
|
|
331
|
-
"cwd",
|
|
332
|
-
"session_name",
|
|
333
|
-
"git_branch",
|
|
334
|
-
"git_status",
|
|
335
|
-
"git_state",
|
|
336
|
-
"runtime",
|
|
337
|
-
"model",
|
|
338
|
-
"provider",
|
|
339
|
-
"session_duration",
|
|
340
|
-
"username",
|
|
341
|
-
"os",
|
|
342
|
-
"time",
|
|
343
|
-
"context",
|
|
344
|
-
"tokens",
|
|
345
|
-
"cache_read",
|
|
346
|
-
"cache_write",
|
|
347
|
-
"cost",
|
|
348
|
-
"subscription",
|
|
349
|
-
"auto_compaction",
|
|
350
|
-
"package",
|
|
351
|
-
"package_version",
|
|
352
|
-
"git_commit",
|
|
353
|
-
"git_tag",
|
|
354
|
-
"git_metrics",
|
|
355
|
-
"git_added",
|
|
356
|
-
"git_deleted",
|
|
357
|
-
"sep",
|
|
358
|
-
] as const;
|
|
359
|
-
|
|
360
|
-
/**
|
|
361
|
-
* Alias → canonical variable name mapping for `footerFormat`.
|
|
362
|
-
* `$fill` is special (not a variable) and handled by the parser.
|
|
363
|
-
*/
|
|
364
|
-
export const FOOTER_FORMAT_ALIASES: Record<string, string> = {
|
|
365
|
-
directory: "cwd",
|
|
366
|
-
branch: "git_branch",
|
|
367
|
-
status: "git_status",
|
|
368
|
-
state: "git_state",
|
|
369
|
-
commit: "git_commit",
|
|
370
|
-
tag: "git_tag",
|
|
371
|
-
duration: "session_duration",
|
|
372
|
-
separator: "sep",
|
|
130
|
+
export type ZentuiConfig = {
|
|
131
|
+
projectRefreshIntervalMs: number;
|
|
132
|
+
icons: ResolvedIcons;
|
|
133
|
+
colors: PolishedTuiColors;
|
|
134
|
+
components: ComponentsConfig;
|
|
373
135
|
};
|
|
374
|
-
|
|
375
|
-
/** Shared configuration file used by the pi-one-ui package. */
|
|
136
|
+
export type PolishedTuiConfig = ZentuiConfig;
|
|
376
137
|
export const configPath = defaultConfigPath;
|
|
377
138
|
|
|
378
|
-
const
|
|
379
|
-
|
|
380
|
-
sessionName: true,
|
|
381
|
-
gitBranch: true,
|
|
382
|
-
gitStatus: true,
|
|
383
|
-
gitCounts: false,
|
|
384
|
-
gitCommit: false,
|
|
385
|
-
gitMetrics: false,
|
|
386
|
-
runtime: true,
|
|
387
|
-
modelInfo: false,
|
|
388
|
-
context: true,
|
|
389
|
-
tokens: true,
|
|
390
|
-
cost: true,
|
|
391
|
-
sessionDuration: false,
|
|
392
|
-
username: false,
|
|
393
|
-
time: false,
|
|
394
|
-
os: false,
|
|
395
|
-
packageVersion: false,
|
|
396
|
-
};
|
|
397
|
-
|
|
398
|
-
const defaultMinimalistStyle: MinimalistEditorStyleConfig = {
|
|
399
|
-
pathDisplay: "compact",
|
|
400
|
-
showCwd: true,
|
|
401
|
-
showSessionName: true,
|
|
402
|
-
showTimer: true,
|
|
403
|
-
showCost: true,
|
|
404
|
-
showGit: true,
|
|
405
|
-
};
|
|
406
|
-
|
|
407
|
-
const defaultStarshipStyle: StarshipFooterStyleConfig = {
|
|
408
|
-
format: "",
|
|
409
|
-
responsive: true,
|
|
410
|
-
compactFormat: DEFAULT_COMPACT_FOOTER_FORMAT,
|
|
411
|
-
compactMaxLines: 2,
|
|
412
|
-
separator: "pipe",
|
|
413
|
-
contextStyle: "text",
|
|
414
|
-
contextThresholds: { warning: 70, error: 90 },
|
|
415
|
-
pathDisplay: { mode: "basename", depth: 0 },
|
|
416
|
-
segments: defaultFooterSegments,
|
|
417
|
-
gitBranch: { maxLength: "full" },
|
|
418
|
-
gitCommit: { hashLength: 7, onlyDetached: true, showTag: true },
|
|
419
|
-
gitMetrics: { onlyNonzero: true, ignoreSubmodules: false },
|
|
420
|
-
extensionStatuses: {
|
|
421
|
-
defaultPlacement: "right",
|
|
422
|
-
placements: {},
|
|
423
|
-
colorModes: {},
|
|
424
|
-
},
|
|
425
|
-
};
|
|
426
|
-
|
|
427
|
-
const defaultComponents: ComponentsConfig = {
|
|
428
|
-
editor: {
|
|
429
|
-
style: "on",
|
|
430
|
-
borderColorMode: "static",
|
|
431
|
-
modelLabel: "id",
|
|
432
|
-
viewportIndicators: true,
|
|
433
|
-
styles: {
|
|
434
|
-
minimalist: defaultMinimalistStyle,
|
|
435
|
-
},
|
|
436
|
-
},
|
|
437
|
-
userMessages: {
|
|
438
|
-
enabled: true,
|
|
439
|
-
style: "framed",
|
|
440
|
-
styles: {
|
|
441
|
-
framed: {},
|
|
442
|
-
"framed-copy-friendly": {},
|
|
443
|
-
compact: {},
|
|
444
|
-
labeled: {},
|
|
445
|
-
},
|
|
446
|
-
},
|
|
447
|
-
workingLine: {
|
|
448
|
-
enabled: false,
|
|
449
|
-
turnSummary: true,
|
|
450
|
-
spinner: "star-bloom",
|
|
451
|
-
spinnerIntervalMs: DEFAULT_WORKING_LINE_SPINNER_INTERVAL_MS,
|
|
452
|
-
animateSpinnerColor: false,
|
|
453
|
-
textIntervalMs: DEFAULT_WORKING_LINE_TEXT_INTERVAL_MS,
|
|
454
|
-
textAnimation: "classic",
|
|
455
|
-
messages: { custom: true, values: [...PI_WORKING_LINE_MESSAGES] },
|
|
456
|
-
segments: { tool: true, elapsed: true, thought: true, tokens: true },
|
|
457
|
-
},
|
|
458
|
-
selectorBorders: { enabled: true, style: "zentui" },
|
|
459
|
-
footer: {
|
|
460
|
-
style: "starship",
|
|
461
|
-
modelLabel: "id",
|
|
462
|
-
styles: { starship: defaultStarshipStyle },
|
|
463
|
-
},
|
|
464
|
-
};
|
|
465
|
-
|
|
466
|
-
export const defaultConfig: PolishedTuiConfig = {
|
|
467
|
-
projectRefreshIntervalMs: DEFAULT_PROJECT_REFRESH_INTERVAL_MS,
|
|
139
|
+
export const defaultConfig: ZentuiConfig = {
|
|
140
|
+
projectRefreshIntervalMs: 30_000,
|
|
468
141
|
icons: { mode: "auto", ...NERD_DEFAULT_ICONS },
|
|
469
142
|
colors: {
|
|
470
143
|
sessionName: "bold green",
|
|
@@ -487,706 +160,52 @@ export const defaultConfig: PolishedTuiConfig = {
|
|
|
487
160
|
time: "bold yellow",
|
|
488
161
|
os: "bold white",
|
|
489
162
|
},
|
|
490
|
-
components:
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
separator: defaultStarshipStyle.separator,
|
|
497
|
-
contextStyle: defaultStarshipStyle.contextStyle,
|
|
498
|
-
editorModelLabel: defaultComponents.editor.modelLabel,
|
|
499
|
-
editorStyle: defaultComponents.editor.style,
|
|
500
|
-
editorStyles: { minimalist: defaultMinimalistStyle },
|
|
501
|
-
editorBorderColorMode: defaultComponents.editor.borderColorMode,
|
|
502
|
-
contextThresholds: defaultStarshipStyle.contextThresholds,
|
|
503
|
-
pathDisplay: defaultStarshipStyle.pathDisplay,
|
|
504
|
-
gitBranch: defaultStarshipStyle.gitBranch,
|
|
505
|
-
features: {
|
|
506
|
-
editor: true,
|
|
507
|
-
statusLine: true,
|
|
508
|
-
viewportIndicators: true,
|
|
163
|
+
components: {
|
|
164
|
+
editor: defaultEditor,
|
|
165
|
+
userMessages: normalizeUserMessages(undefined),
|
|
166
|
+
workingLine: defaultWorkingLine,
|
|
167
|
+
selectorBorders: { enabled: true, style: "zentui" },
|
|
168
|
+
footer: defaultFooter,
|
|
509
169
|
},
|
|
510
|
-
footerSegments: defaultFooterSegments,
|
|
511
|
-
gitCommit: defaultStarshipStyle.gitCommit,
|
|
512
|
-
gitMetrics: defaultStarshipStyle.gitMetrics,
|
|
513
|
-
extensionStatuses: defaultStarshipStyle.extensionStatuses,
|
|
514
170
|
};
|
|
515
171
|
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
return defaultComponents.editor.style;
|
|
554
|
-
}
|
|
555
|
-
|
|
556
|
-
function parseEditorBorderColorMode(value: unknown): EditorBorderColorMode {
|
|
557
|
-
if (value === "static" || value === "adaptive") return value;
|
|
558
|
-
return defaultConfig.editorBorderColorMode;
|
|
559
|
-
}
|
|
560
|
-
|
|
561
|
-
export function isSeparatorStyle(value: unknown): value is SeparatorStyle {
|
|
562
|
-
return (
|
|
563
|
-
value === "pipe" ||
|
|
564
|
-
value === "dot" ||
|
|
565
|
-
value === "chevron" ||
|
|
566
|
-
value === "none"
|
|
567
|
-
);
|
|
568
|
-
}
|
|
569
|
-
|
|
570
|
-
function parseSeparatorStyle(value: unknown): SeparatorStyle {
|
|
571
|
-
return isSeparatorStyle(value) ? value : defaultConfig.separator;
|
|
572
|
-
}
|
|
573
|
-
|
|
574
|
-
function parseContextThresholds(
|
|
575
|
-
value: unknown,
|
|
576
|
-
defaults: ContextThresholds = defaultStarshipStyle.contextThresholds,
|
|
577
|
-
): ContextThresholds {
|
|
578
|
-
if (!isRecord(value)) return { ...defaults };
|
|
579
|
-
|
|
580
|
-
const warningRaw = value.warning;
|
|
581
|
-
const errorRaw = value.error;
|
|
582
|
-
let warning =
|
|
583
|
-
typeof warningRaw === "number" && Number.isFinite(warningRaw)
|
|
584
|
-
? clampPercent(Math.round(warningRaw))
|
|
585
|
-
: defaults.warning;
|
|
586
|
-
let error =
|
|
587
|
-
typeof errorRaw === "number" && Number.isFinite(errorRaw)
|
|
588
|
-
? clampPercent(Math.round(errorRaw))
|
|
589
|
-
: defaults.error;
|
|
590
|
-
if (error < warning) {
|
|
591
|
-
const swapped = warning;
|
|
592
|
-
warning = error;
|
|
593
|
-
error = swapped;
|
|
594
|
-
}
|
|
595
|
-
return { warning, error };
|
|
596
|
-
}
|
|
597
|
-
|
|
598
|
-
function parsePathDisplay(value: unknown): PathDisplayConfig {
|
|
599
|
-
const defaults = defaultConfig.pathDisplay;
|
|
600
|
-
if (!isRecord(value)) return { ...defaults };
|
|
601
|
-
const mode =
|
|
602
|
-
value.mode === "full" || value.mode === "basename"
|
|
603
|
-
? value.mode
|
|
604
|
-
: defaults.mode;
|
|
605
|
-
const rawDepth = value.depth;
|
|
606
|
-
const depth =
|
|
607
|
-
typeof rawDepth === "number" && Number.isFinite(rawDepth) && rawDepth >= 0
|
|
608
|
-
? Math.min(5, Math.floor(rawDepth))
|
|
609
|
-
: defaults.depth;
|
|
610
|
-
return { mode, depth };
|
|
611
|
-
}
|
|
612
|
-
|
|
613
|
-
function normalizeGitBranchMaxLength(value: unknown): GitBranchMaxLength {
|
|
614
|
-
if (value === "full") return value;
|
|
615
|
-
if (typeof value === "number" && Number.isInteger(value) && value > 0)
|
|
616
|
-
return value;
|
|
617
|
-
return defaultConfig.gitBranch.maxLength;
|
|
618
|
-
}
|
|
619
|
-
|
|
620
|
-
function parseGitBranchConfig(value: unknown): GitBranchConfig {
|
|
621
|
-
const defaults = defaultConfig.gitBranch;
|
|
622
|
-
if (!isRecord(value)) return { ...defaults };
|
|
623
|
-
return {
|
|
624
|
-
maxLength: normalizeGitBranchMaxLength(value.maxLength),
|
|
625
|
-
};
|
|
626
|
-
}
|
|
627
|
-
|
|
628
|
-
function stringValue(
|
|
629
|
-
record: Record<string, unknown>,
|
|
630
|
-
key: string,
|
|
631
|
-
): string | undefined {
|
|
632
|
-
const value = record[key];
|
|
633
|
-
return typeof value === "string" ? value : undefined;
|
|
634
|
-
}
|
|
635
|
-
|
|
636
|
-
function parseCompactFooterMaxLines(value: unknown): CompactFooterMaxLines {
|
|
637
|
-
return value === 1 || value === 2 || value === 3 || value === "unlimited"
|
|
638
|
-
? value
|
|
639
|
-
: 2;
|
|
640
|
-
}
|
|
641
|
-
|
|
642
|
-
function colorValue(
|
|
643
|
-
record: Record<string, unknown>,
|
|
644
|
-
key: string,
|
|
645
|
-
): string | undefined {
|
|
646
|
-
const value = stringValue(record, key);
|
|
647
|
-
return value !== undefined && isSupportedColorSpec(value) ? value : undefined;
|
|
648
|
-
}
|
|
649
|
-
|
|
650
|
-
function definedColors(
|
|
651
|
-
colors: Partial<
|
|
652
|
-
Record<keyof PolishedTuiConfig["colors"], string | undefined>
|
|
653
|
-
>,
|
|
654
|
-
): Partial<PolishedTuiConfig["colors"]> {
|
|
655
|
-
return Object.fromEntries(
|
|
656
|
-
Object.entries(colors).filter(
|
|
657
|
-
(entry): entry is [keyof PolishedTuiConfig["colors"], string] =>
|
|
658
|
-
typeof entry[1] === "string",
|
|
659
|
-
),
|
|
660
|
-
) as Partial<PolishedTuiConfig["colors"]>;
|
|
661
|
-
}
|
|
662
|
-
|
|
663
|
-
function normalizeIconOverrides(
|
|
664
|
-
record: Record<string, unknown>,
|
|
665
|
-
): Partial<IconGlyphs> {
|
|
666
|
-
return Object.fromEntries(
|
|
667
|
-
ICON_GLYPH_KEYS.flatMap((key) => {
|
|
668
|
-
const value = stringValue(record, key);
|
|
669
|
-
return value === undefined ? [] : [[key, value]];
|
|
670
|
-
}),
|
|
671
|
-
) as Partial<IconGlyphs>;
|
|
672
|
-
}
|
|
673
|
-
|
|
674
|
-
function normalizeColors(
|
|
675
|
-
record: Record<string, unknown>,
|
|
676
|
-
): Partial<PolishedTuiConfig["colors"]> {
|
|
677
|
-
return definedColors({
|
|
678
|
-
cwd: colorValue(record, "cwd"),
|
|
679
|
-
sessionName: colorValue(record, "sessionName"),
|
|
680
|
-
gitBranch: colorValue(record, "gitBranch"),
|
|
681
|
-
gitStatus: colorValue(record, "gitStatus"),
|
|
682
|
-
contextNormal: colorValue(record, "contextNormal"),
|
|
683
|
-
contextWarning: colorValue(record, "contextWarning"),
|
|
684
|
-
contextError: colorValue(record, "contextError"),
|
|
685
|
-
tokens: colorValue(record, "tokens"),
|
|
686
|
-
cost: colorValue(record, "cost"),
|
|
687
|
-
separator: colorValue(record, "separator"),
|
|
688
|
-
runtimePrefix: colorValue(record, "runtimePrefix"),
|
|
689
|
-
extensionStatus: colorValue(record, "extensionStatus"),
|
|
690
|
-
sessionDuration: colorValue(record, "sessionDuration"),
|
|
691
|
-
packageVersion: colorValue(record, "packageVersion"),
|
|
692
|
-
gitCommit: colorValue(record, "gitCommit"),
|
|
693
|
-
gitMetricsAdded: colorValue(record, "gitMetricsAdded"),
|
|
694
|
-
gitMetricsDeleted: colorValue(record, "gitMetricsDeleted"),
|
|
695
|
-
username: colorValue(record, "username"),
|
|
696
|
-
time: colorValue(record, "time"),
|
|
697
|
-
os: colorValue(record, "os"),
|
|
698
|
-
editorAccent: colorValue(record, "editorAccent"),
|
|
699
|
-
editorBorder: colorValue(record, "editorBorder"),
|
|
700
|
-
editorGitBranch: colorValue(record, "editorGitBranch"),
|
|
701
|
-
editorModel: colorValue(record, "editorModel"),
|
|
702
|
-
editorProvider: colorValue(record, "editorProvider"),
|
|
703
|
-
editorThinking: colorValue(record, "editorThinking"),
|
|
704
|
-
editorThinkingMinimal: colorValue(record, "editorThinkingMinimal"),
|
|
705
|
-
editorThinkingLow: colorValue(record, "editorThinkingLow"),
|
|
706
|
-
editorThinkingMedium: colorValue(record, "editorThinkingMedium"),
|
|
707
|
-
editorThinkingHigh: colorValue(record, "editorThinkingHigh"),
|
|
708
|
-
editorThinkingXhigh: colorValue(record, "editorThinkingXhigh"),
|
|
709
|
-
editorThinkingMax: colorValue(record, "editorThinkingMax"),
|
|
710
|
-
workingLineLow: colorValue(record, "workingLineLow"),
|
|
711
|
-
workingLineMid: colorValue(record, "workingLineMid"),
|
|
712
|
-
workingLineHigh: colorValue(record, "workingLineHigh"),
|
|
713
|
-
});
|
|
714
|
-
}
|
|
715
|
-
|
|
716
|
-
/** Clamp hashLength to Git's valid abbreviation range [4, 40]. */
|
|
717
|
-
function normalizeGitHashLength(value: unknown): number {
|
|
718
|
-
const parsed = typeof value === "number" ? value : Number(value);
|
|
719
|
-
if (!Number.isFinite(parsed)) return defaultConfig.gitCommit.hashLength;
|
|
720
|
-
const rounded = Math.round(parsed);
|
|
721
|
-
return Math.min(40, Math.max(4, rounded));
|
|
722
|
-
}
|
|
723
|
-
|
|
724
|
-
function normalizeGitCommitConfig(
|
|
725
|
-
record: Record<string, unknown>,
|
|
726
|
-
): GitCommitConfig {
|
|
727
|
-
return {
|
|
728
|
-
hashLength: normalizeGitHashLength(record.hashLength),
|
|
729
|
-
onlyDetached:
|
|
730
|
-
typeof record.onlyDetached === "boolean"
|
|
731
|
-
? record.onlyDetached
|
|
732
|
-
: defaultConfig.gitCommit.onlyDetached,
|
|
733
|
-
showTag:
|
|
734
|
-
typeof record.showTag === "boolean"
|
|
735
|
-
? record.showTag
|
|
736
|
-
: defaultConfig.gitCommit.showTag,
|
|
737
|
-
};
|
|
738
|
-
}
|
|
739
|
-
|
|
740
|
-
function normalizeGitMetricsConfig(
|
|
741
|
-
record: Record<string, unknown>,
|
|
742
|
-
): GitMetricsConfig {
|
|
743
|
-
return {
|
|
744
|
-
onlyNonzero:
|
|
745
|
-
typeof record.onlyNonzero === "boolean"
|
|
746
|
-
? record.onlyNonzero
|
|
747
|
-
: defaultConfig.gitMetrics.onlyNonzero,
|
|
748
|
-
ignoreSubmodules:
|
|
749
|
-
typeof record.ignoreSubmodules === "boolean"
|
|
750
|
-
? record.ignoreSubmodules
|
|
751
|
-
: defaultConfig.gitMetrics.ignoreSubmodules,
|
|
752
|
-
};
|
|
753
|
-
}
|
|
754
|
-
|
|
755
|
-
export function isExtensionStatusPlacement(
|
|
756
|
-
value: unknown,
|
|
757
|
-
): value is ExtensionStatusPlacement {
|
|
758
|
-
return (
|
|
759
|
-
value === "off" ||
|
|
760
|
-
value === "left" ||
|
|
761
|
-
value === "middle" ||
|
|
762
|
-
value === "right"
|
|
763
|
-
);
|
|
764
|
-
}
|
|
765
|
-
|
|
766
|
-
export function isExtensionStatusColorMode(
|
|
767
|
-
value: unknown,
|
|
768
|
-
): value is ExtensionStatusColorMode {
|
|
769
|
-
return value === "zentui" || value === "original";
|
|
770
|
-
}
|
|
771
|
-
|
|
772
|
-
function normalizeExtensionStatuses(
|
|
773
|
-
record: Record<string, unknown>,
|
|
774
|
-
): ExtensionStatusesConfig {
|
|
775
|
-
const defaultPlacement = isExtensionStatusPlacement(record.defaultPlacement)
|
|
776
|
-
? record.defaultPlacement
|
|
777
|
-
: defaultConfig.extensionStatuses.defaultPlacement;
|
|
778
|
-
const placements = isRecord(record.placements)
|
|
779
|
-
? Object.fromEntries(
|
|
780
|
-
Object.entries(record.placements).filter(
|
|
781
|
-
(entry): entry is [string, ExtensionStatusPlacement] =>
|
|
782
|
-
isExtensionStatusPlacement(entry[1]),
|
|
783
|
-
),
|
|
784
|
-
)
|
|
785
|
-
: {};
|
|
786
|
-
const colorModes = isRecord(record.colorModes)
|
|
787
|
-
? Object.fromEntries(
|
|
788
|
-
Object.entries(record.colorModes).filter(
|
|
789
|
-
(entry): entry is [string, ExtensionStatusColorMode] =>
|
|
790
|
-
isExtensionStatusColorMode(entry[1]),
|
|
791
|
-
),
|
|
792
|
-
)
|
|
793
|
-
: {};
|
|
794
|
-
|
|
795
|
-
return {
|
|
796
|
-
defaultPlacement,
|
|
797
|
-
placements,
|
|
798
|
-
colorModes,
|
|
799
|
-
};
|
|
800
|
-
}
|
|
801
|
-
|
|
802
|
-
function isUiFeatureKey(value: string): value is keyof UiFeaturesConfig {
|
|
803
|
-
return (
|
|
804
|
-
value === "editor" ||
|
|
805
|
-
value === "statusLine" ||
|
|
806
|
-
value === "viewportIndicators"
|
|
807
|
-
);
|
|
808
|
-
}
|
|
809
|
-
|
|
810
|
-
function isFooterSegmentKey(
|
|
811
|
-
value: string,
|
|
812
|
-
): value is keyof FooterSegmentsConfig {
|
|
813
|
-
return (
|
|
814
|
-
value === "cwd" ||
|
|
815
|
-
value === "sessionName" ||
|
|
816
|
-
value === "gitBranch" ||
|
|
817
|
-
value === "gitStatus" ||
|
|
818
|
-
value === "gitCounts" ||
|
|
819
|
-
value === "runtime" ||
|
|
820
|
-
value === "modelInfo" ||
|
|
821
|
-
value === "context" ||
|
|
822
|
-
value === "tokens" ||
|
|
823
|
-
value === "cost" ||
|
|
824
|
-
value === "sessionDuration" ||
|
|
825
|
-
value === "username" ||
|
|
826
|
-
value === "time" ||
|
|
827
|
-
value === "os" ||
|
|
828
|
-
value === "packageVersion" ||
|
|
829
|
-
value === "gitCommit" ||
|
|
830
|
-
value === "gitMetrics"
|
|
831
|
-
);
|
|
832
|
-
}
|
|
833
|
-
|
|
834
|
-
function validUiFeatureEntries(
|
|
835
|
-
record: Record<string, unknown>,
|
|
836
|
-
): Partial<UiFeaturesConfig> {
|
|
837
|
-
return Object.fromEntries(
|
|
838
|
-
Object.entries(record).filter(
|
|
839
|
-
(entry): entry is [keyof UiFeaturesConfig, boolean] => {
|
|
840
|
-
const [key, value] = entry;
|
|
841
|
-
return isUiFeatureKey(key) && typeof value === "boolean";
|
|
842
|
-
},
|
|
843
|
-
),
|
|
844
|
-
) as Partial<UiFeaturesConfig>;
|
|
845
|
-
}
|
|
846
|
-
|
|
847
|
-
function validFooterSegmentEntries(
|
|
848
|
-
record: Record<string, unknown>,
|
|
849
|
-
): Partial<FooterSegmentsConfig> {
|
|
850
|
-
return Object.fromEntries(
|
|
851
|
-
Object.entries(record).filter(
|
|
852
|
-
(entry): entry is [keyof FooterSegmentsConfig, boolean] => {
|
|
853
|
-
const [key, value] = entry;
|
|
854
|
-
return isFooterSegmentKey(key) && typeof value === "boolean";
|
|
855
|
-
},
|
|
856
|
-
),
|
|
857
|
-
) as Partial<FooterSegmentsConfig>;
|
|
858
|
-
}
|
|
859
|
-
|
|
860
|
-
/** Applies one canonical mutation through the shared config writer. */
|
|
861
|
-
function mutateConfig(
|
|
862
|
-
path: string,
|
|
863
|
-
mutate: (record: ConfigRecord) => void,
|
|
864
|
-
): PolishedTuiConfig {
|
|
865
|
-
const update = (record: ConfigRecord): void => {
|
|
866
|
-
record.version = 1;
|
|
867
|
-
mutate(record);
|
|
868
|
-
};
|
|
869
|
-
const record =
|
|
870
|
-
path === configPath
|
|
871
|
-
? configStore.update(update)
|
|
872
|
-
: mutateConfigFile(path, update);
|
|
873
|
-
return mergeConfig(record);
|
|
874
|
-
}
|
|
875
|
-
|
|
876
|
-
export function ensureConfigExists(_path = configPath): void {
|
|
877
|
-
// Intentionally left as a no-op. Runtime defaults come from `mergeConfig({})`;
|
|
878
|
-
// persist the canonical file only after the user changes a setting.
|
|
879
|
-
}
|
|
880
|
-
|
|
881
|
-
function hasOwn(record: ConfigRecord, key: string): boolean {
|
|
882
|
-
return Object.hasOwn(record, key);
|
|
883
|
-
}
|
|
884
|
-
|
|
885
|
-
function recordValue(value: unknown): ConfigRecord {
|
|
886
|
-
return isRecord(value) ? value : {};
|
|
887
|
-
}
|
|
888
|
-
|
|
889
|
-
function parseBoolean(value: unknown, fallback: boolean): boolean {
|
|
890
|
-
return typeof value === "boolean" ? value : fallback;
|
|
891
|
-
}
|
|
892
|
-
|
|
893
|
-
function parseSelectorBorderStyle(value: unknown): SelectorBorderStyle {
|
|
894
|
-
return value === "zentui" ? value : "zentui";
|
|
895
|
-
}
|
|
896
|
-
|
|
897
|
-
function parseFooterStyle(value: unknown): FooterStyle {
|
|
898
|
-
return value === "native" || value === "starship" || value === "hidden"
|
|
899
|
-
? value
|
|
900
|
-
: defaultComponents.footer.style;
|
|
901
|
-
}
|
|
902
|
-
|
|
903
|
-
function parseUserMessageStyle(value: unknown): UserMessageStyle {
|
|
904
|
-
return value === "framed" ||
|
|
905
|
-
value === "framed-copy-friendly" ||
|
|
906
|
-
value === "compact" ||
|
|
907
|
-
value === "labeled"
|
|
908
|
-
? value
|
|
909
|
-
: defaultComponents.userMessages.style;
|
|
910
|
-
}
|
|
911
|
-
|
|
912
|
-
function parseNonEmptyString(value: unknown, fallback: string): string {
|
|
913
|
-
return typeof value === "string" && value.length > 0 ? value : fallback;
|
|
914
|
-
}
|
|
915
|
-
|
|
916
|
-
function resolveContextThresholds(
|
|
917
|
-
value: unknown,
|
|
918
|
-
defaults: ContextThresholds,
|
|
919
|
-
): ContextThresholds {
|
|
920
|
-
return parseContextThresholds(value, defaults);
|
|
921
|
-
}
|
|
922
|
-
|
|
923
|
-
function resolvePathDisplay(value: unknown): PathDisplayConfig {
|
|
924
|
-
return parsePathDisplay(value);
|
|
925
|
-
}
|
|
926
|
-
|
|
927
|
-
function resolveGitBranch(value: unknown): GitBranchConfig {
|
|
928
|
-
return parseGitBranchConfig(value);
|
|
929
|
-
}
|
|
930
|
-
|
|
931
|
-
function resolveGitCommit(value: unknown): GitCommitConfig {
|
|
932
|
-
return normalizeGitCommitConfig(recordValue(value));
|
|
933
|
-
}
|
|
934
|
-
|
|
935
|
-
function resolveGitMetrics(value: unknown): GitMetricsConfig {
|
|
936
|
-
return normalizeGitMetricsConfig(recordValue(value));
|
|
937
|
-
}
|
|
938
|
-
|
|
939
|
-
function resolveExtensionStatuses(value: unknown): ExtensionStatusesConfig {
|
|
940
|
-
return normalizeExtensionStatuses(recordValue(value));
|
|
941
|
-
}
|
|
942
|
-
|
|
943
|
-
const FOOTER_SEGMENT_KEYS = Object.keys(defaultFooterSegments) as Array<
|
|
944
|
-
keyof FooterSegmentsConfig
|
|
945
|
-
>;
|
|
946
|
-
|
|
947
|
-
function resolveFooterSegments(value: unknown): FooterSegmentsConfig {
|
|
948
|
-
const record = recordValue(value);
|
|
949
|
-
return Object.fromEntries(
|
|
950
|
-
FOOTER_SEGMENT_KEYS.map((key) => [
|
|
951
|
-
key,
|
|
952
|
-
parseBoolean(record[key], defaultFooterSegments[key]),
|
|
953
|
-
]),
|
|
954
|
-
) as FooterSegmentsConfig;
|
|
955
|
-
}
|
|
956
|
-
|
|
957
|
-
function resolveWorkingLineMessages(
|
|
958
|
-
messages: ConfigRecord,
|
|
959
|
-
): WorkingLineMessagesConfig {
|
|
960
|
-
return {
|
|
961
|
-
custom: parseBoolean(messages.custom, true),
|
|
962
|
-
values: hasOwn(messages, "values")
|
|
963
|
-
? normalizeWorkingLineMessages(messages.values)
|
|
964
|
-
: [...PI_WORKING_LINE_MESSAGES],
|
|
965
|
-
};
|
|
966
|
-
}
|
|
967
|
-
|
|
968
|
-
function resolveComponents(config: ConfigRecord): ComponentsConfig {
|
|
969
|
-
const components = recordValue(config.components);
|
|
970
|
-
const editor = recordValue(components.editor);
|
|
971
|
-
const editorStyles = recordValue(editor.styles);
|
|
972
|
-
const minimalist = recordValue(editorStyles.minimalist);
|
|
973
|
-
const userMessages = recordValue(components.userMessages);
|
|
974
|
-
const workingLine = recordValue(components.workingLine);
|
|
975
|
-
const workingLineMessages = recordValue(workingLine.messages);
|
|
976
|
-
const workingLineSegments = recordValue(workingLine.segments);
|
|
977
|
-
const selectorBorders = recordValue(components.selectorBorders);
|
|
978
|
-
const footer = recordValue(components.footer);
|
|
979
|
-
const footerStyles = recordValue(footer.styles);
|
|
980
|
-
const starship = recordValue(footerStyles.starship);
|
|
981
|
-
|
|
982
|
-
return {
|
|
983
|
-
editor: {
|
|
984
|
-
// 迁移:旧 enabled:false 收敛为 style:"off"(enabled 字段已移除)。
|
|
985
|
-
style:
|
|
986
|
-
hasOwn(editor, "enabled") &&
|
|
987
|
-
parseBoolean(editor.enabled, true) === false
|
|
988
|
-
? "off"
|
|
989
|
-
: parseEditorStyle(editor.style),
|
|
990
|
-
borderColorMode: parseEditorBorderColorMode(editor.borderColorMode),
|
|
991
|
-
modelLabel: parseEditorModelLabel(
|
|
992
|
-
editor.modelLabel,
|
|
993
|
-
defaultComponents.editor.modelLabel,
|
|
994
|
-
),
|
|
995
|
-
viewportIndicators: parseBoolean(
|
|
996
|
-
editor.viewportIndicators,
|
|
997
|
-
defaultComponents.editor.viewportIndicators,
|
|
998
|
-
),
|
|
999
|
-
styles: {
|
|
1000
|
-
minimalist: {
|
|
1001
|
-
pathDisplay:
|
|
1002
|
-
minimalist.pathDisplay === "compact" ||
|
|
1003
|
-
minimalist.pathDisplay === "project" ||
|
|
1004
|
-
minimalist.pathDisplay === "full"
|
|
1005
|
-
? minimalist.pathDisplay
|
|
1006
|
-
: defaultMinimalistStyle.pathDisplay,
|
|
1007
|
-
showCwd: parseBoolean(
|
|
1008
|
-
minimalist.showCwd,
|
|
1009
|
-
defaultMinimalistStyle.showCwd,
|
|
1010
|
-
),
|
|
1011
|
-
showSessionName: parseBoolean(
|
|
1012
|
-
minimalist.showSessionName,
|
|
1013
|
-
defaultMinimalistStyle.showSessionName,
|
|
1014
|
-
),
|
|
1015
|
-
showTimer: parseBoolean(
|
|
1016
|
-
minimalist.showTimer,
|
|
1017
|
-
defaultMinimalistStyle.showTimer,
|
|
1018
|
-
),
|
|
1019
|
-
showCost: parseBoolean(
|
|
1020
|
-
minimalist.showCost,
|
|
1021
|
-
defaultMinimalistStyle.showCost,
|
|
1022
|
-
),
|
|
1023
|
-
showGit: parseBoolean(
|
|
1024
|
-
minimalist.showGit,
|
|
1025
|
-
defaultMinimalistStyle.showGit,
|
|
1026
|
-
),
|
|
1027
|
-
},
|
|
1028
|
-
},
|
|
1029
|
-
},
|
|
1030
|
-
userMessages: {
|
|
1031
|
-
enabled: parseBoolean(
|
|
1032
|
-
userMessages.enabled,
|
|
1033
|
-
defaultComponents.userMessages.enabled,
|
|
1034
|
-
),
|
|
1035
|
-
style: parseUserMessageStyle(userMessages.style),
|
|
1036
|
-
styles: {
|
|
1037
|
-
framed: {},
|
|
1038
|
-
"framed-copy-friendly": {},
|
|
1039
|
-
compact: {},
|
|
1040
|
-
labeled: {},
|
|
1041
|
-
},
|
|
1042
|
-
},
|
|
1043
|
-
workingLine: {
|
|
1044
|
-
enabled: parseBoolean(
|
|
1045
|
-
workingLine.enabled,
|
|
1046
|
-
defaultComponents.workingLine.enabled,
|
|
1047
|
-
),
|
|
1048
|
-
turnSummary: parseBoolean(
|
|
1049
|
-
workingLine.turnSummary,
|
|
1050
|
-
defaultComponents.workingLine.turnSummary,
|
|
1051
|
-
),
|
|
1052
|
-
spinner:
|
|
1053
|
-
workingLine.spinner === "braille" ||
|
|
1054
|
-
workingLine.spinner === "star-bloom" ||
|
|
1055
|
-
workingLine.spinner === "pinwheel" ||
|
|
1056
|
-
workingLine.spinner === "claude-inspired" ||
|
|
1057
|
-
workingLine.spinner === "pulse"
|
|
1058
|
-
? workingLine.spinner
|
|
1059
|
-
: defaultComponents.workingLine.spinner,
|
|
1060
|
-
spinnerIntervalMs: isValidWorkingLineIntervalMs(
|
|
1061
|
-
workingLine.spinnerIntervalMs,
|
|
1062
|
-
)
|
|
1063
|
-
? workingLine.spinnerIntervalMs
|
|
1064
|
-
: defaultComponents.workingLine.spinnerIntervalMs,
|
|
1065
|
-
animateSpinnerColor: parseBoolean(
|
|
1066
|
-
workingLine.animateSpinnerColor,
|
|
1067
|
-
defaultComponents.workingLine.animateSpinnerColor,
|
|
1068
|
-
),
|
|
1069
|
-
textIntervalMs: isValidWorkingLineIntervalMs(workingLine.textIntervalMs)
|
|
1070
|
-
? workingLine.textIntervalMs
|
|
1071
|
-
: defaultComponents.workingLine.textIntervalMs,
|
|
1072
|
-
textAnimation:
|
|
1073
|
-
workingLine.textAnimation === "classic" ||
|
|
1074
|
-
workingLine.textAnimation === "kitt" ||
|
|
1075
|
-
workingLine.textAnimation === "disabled"
|
|
1076
|
-
? workingLine.textAnimation
|
|
1077
|
-
: defaultComponents.workingLine.textAnimation,
|
|
1078
|
-
messages: resolveWorkingLineMessages(workingLineMessages),
|
|
1079
|
-
segments: {
|
|
1080
|
-
tool: parseBoolean(
|
|
1081
|
-
workingLineSegments.tool,
|
|
1082
|
-
defaultComponents.workingLine.segments.tool,
|
|
1083
|
-
),
|
|
1084
|
-
elapsed: parseBoolean(
|
|
1085
|
-
workingLineSegments.elapsed,
|
|
1086
|
-
defaultComponents.workingLine.segments.elapsed,
|
|
1087
|
-
),
|
|
1088
|
-
thought: parseBoolean(
|
|
1089
|
-
workingLineSegments.thought,
|
|
1090
|
-
defaultComponents.workingLine.segments.thought,
|
|
1091
|
-
),
|
|
1092
|
-
tokens: parseBoolean(
|
|
1093
|
-
workingLineSegments.tokens,
|
|
1094
|
-
defaultComponents.workingLine.segments.tokens,
|
|
1095
|
-
),
|
|
1096
|
-
},
|
|
1097
|
-
},
|
|
1098
|
-
selectorBorders: {
|
|
1099
|
-
enabled: parseBoolean(
|
|
1100
|
-
selectorBorders.enabled,
|
|
1101
|
-
defaultComponents.selectorBorders.enabled,
|
|
1102
|
-
),
|
|
1103
|
-
style: parseSelectorBorderStyle(selectorBorders.style),
|
|
1104
|
-
},
|
|
1105
|
-
footer: {
|
|
1106
|
-
style: parseFooterStyle(footer.style),
|
|
1107
|
-
modelLabel: parseEditorModelLabel(
|
|
1108
|
-
footer.modelLabel,
|
|
1109
|
-
defaultComponents.footer.modelLabel,
|
|
1110
|
-
),
|
|
1111
|
-
styles: {
|
|
1112
|
-
starship: {
|
|
1113
|
-
format:
|
|
1114
|
-
typeof starship.format === "string"
|
|
1115
|
-
? starship.format
|
|
1116
|
-
: defaultStarshipStyle.format,
|
|
1117
|
-
responsive: parseBoolean(
|
|
1118
|
-
starship.responsive,
|
|
1119
|
-
defaultStarshipStyle.responsive,
|
|
1120
|
-
),
|
|
1121
|
-
compactFormat: parseNonEmptyString(
|
|
1122
|
-
starship.compactFormat,
|
|
1123
|
-
defaultStarshipStyle.compactFormat,
|
|
1124
|
-
),
|
|
1125
|
-
compactMaxLines: parseCompactFooterMaxLines(starship.compactMaxLines),
|
|
1126
|
-
separator: parseSeparatorStyle(starship.separator),
|
|
1127
|
-
contextStyle: parseContextStyle(starship.contextStyle),
|
|
1128
|
-
contextThresholds: resolveContextThresholds(
|
|
1129
|
-
starship.contextThresholds,
|
|
1130
|
-
defaultStarshipStyle.contextThresholds,
|
|
1131
|
-
),
|
|
1132
|
-
pathDisplay: resolvePathDisplay(starship.pathDisplay),
|
|
1133
|
-
segments: resolveFooterSegments(starship.segments),
|
|
1134
|
-
gitBranch: resolveGitBranch(starship.gitBranch),
|
|
1135
|
-
gitCommit: resolveGitCommit(starship.gitCommit),
|
|
1136
|
-
gitMetrics: resolveGitMetrics(starship.gitMetrics),
|
|
1137
|
-
extensionStatuses: resolveExtensionStatuses(
|
|
1138
|
-
starship.extensionStatuses,
|
|
1139
|
-
),
|
|
1140
|
-
},
|
|
1141
|
-
},
|
|
1142
|
-
},
|
|
1143
|
-
};
|
|
1144
|
-
}
|
|
1145
|
-
|
|
1146
|
-
function derivedRuntimeView(config: ZentuiConfig): PolishedTuiConfig {
|
|
1147
|
-
const starship = config.components.footer.styles.starship;
|
|
1148
|
-
const minimalist = config.components.editor.styles.minimalist;
|
|
1149
|
-
return {
|
|
1150
|
-
...config,
|
|
1151
|
-
footerFormat: starship.format,
|
|
1152
|
-
responsiveFooter: starship.responsive,
|
|
1153
|
-
compactFooterFormat: starship.compactFormat,
|
|
1154
|
-
compactFooterMaxLines: starship.compactMaxLines,
|
|
1155
|
-
separator: starship.separator,
|
|
1156
|
-
contextStyle: starship.contextStyle,
|
|
1157
|
-
contextThresholds: starship.contextThresholds,
|
|
1158
|
-
pathDisplay: starship.pathDisplay,
|
|
1159
|
-
gitBranch: starship.gitBranch,
|
|
1160
|
-
footerSegments: starship.segments,
|
|
1161
|
-
gitCommit: starship.gitCommit,
|
|
1162
|
-
gitMetrics: starship.gitMetrics,
|
|
1163
|
-
extensionStatuses: starship.extensionStatuses,
|
|
1164
|
-
editorStyle: config.components.editor.style,
|
|
1165
|
-
editorStyles: { minimalist },
|
|
1166
|
-
editorMetadataFormat: DEFAULT_EDITOR_METADATA_FORMAT,
|
|
1167
|
-
editorBorderColorMode: config.components.editor.borderColorMode,
|
|
1168
|
-
editorModelLabel: config.components.editor.modelLabel,
|
|
1169
|
-
features: {
|
|
1170
|
-
editor: config.components.editor.style === "on",
|
|
1171
|
-
statusLine: config.components.footer.style === "starship",
|
|
1172
|
-
viewportIndicators: config.components.editor.viewportIndicators,
|
|
1173
|
-
},
|
|
1174
|
-
};
|
|
1175
|
-
}
|
|
1176
|
-
|
|
1177
|
-
const unsupportedComponentStyles = new WeakMap<
|
|
1178
|
-
ZentuiConfig,
|
|
1179
|
-
ReadonlySet<ComponentStyleOwner>
|
|
1180
|
-
>();
|
|
1181
|
-
|
|
1182
|
-
// Retired selections migrate to the sole "on" (minimalist) style instead of
|
|
1183
|
-
// disabling the custom Editor. opencode itself is retired along with its variants.
|
|
1184
|
-
const retiredEditorStyleIds: ReadonlySet<string> = new Set([
|
|
1185
|
-
"opencode",
|
|
1186
|
-
"opencode-copy-friendly",
|
|
1187
|
-
"accent-rail",
|
|
1188
|
-
]);
|
|
1189
|
-
|
|
172
|
+
const colorKeys: readonly (keyof PolishedTuiColors)[] = [
|
|
173
|
+
"cwd",
|
|
174
|
+
"sessionName",
|
|
175
|
+
"gitBranch",
|
|
176
|
+
"gitStatus",
|
|
177
|
+
"contextNormal",
|
|
178
|
+
"contextWarning",
|
|
179
|
+
"contextError",
|
|
180
|
+
"tokens",
|
|
181
|
+
"cost",
|
|
182
|
+
"separator",
|
|
183
|
+
"runtimePrefix",
|
|
184
|
+
"extensionStatus",
|
|
185
|
+
"sessionDuration",
|
|
186
|
+
"packageVersion",
|
|
187
|
+
"gitCommit",
|
|
188
|
+
"gitMetricsAdded",
|
|
189
|
+
"gitMetricsDeleted",
|
|
190
|
+
"username",
|
|
191
|
+
"time",
|
|
192
|
+
"os",
|
|
193
|
+
"editorAccent",
|
|
194
|
+
"editorBorder",
|
|
195
|
+
"editorGitBranch",
|
|
196
|
+
"editorModel",
|
|
197
|
+
"editorProvider",
|
|
198
|
+
"editorThinking",
|
|
199
|
+
"editorThinkingMinimal",
|
|
200
|
+
"editorThinkingLow",
|
|
201
|
+
"editorThinkingMedium",
|
|
202
|
+
"editorThinkingHigh",
|
|
203
|
+
"editorThinkingXhigh",
|
|
204
|
+
"editorThinkingMax",
|
|
205
|
+
"workingLineLow",
|
|
206
|
+
"workingLineMid",
|
|
207
|
+
"workingLineHigh",
|
|
208
|
+
];
|
|
1190
209
|
const knownComponentStyleIds: Record<
|
|
1191
210
|
ComponentStyleOwner,
|
|
1192
211
|
ReadonlySet<string>
|
|
@@ -1201,14 +220,24 @@ const knownComponentStyleIds: Record<
|
|
|
1201
220
|
selectorBorders: new Set(["zentui"]),
|
|
1202
221
|
footer: new Set(["native", "starship", "hidden"]),
|
|
1203
222
|
};
|
|
223
|
+
const retiredEditorStyleIds = new Set([
|
|
224
|
+
"opencode",
|
|
225
|
+
"opencode-copy-friendly",
|
|
226
|
+
"accent-rail",
|
|
227
|
+
]);
|
|
228
|
+
const unsupportedComponentStyles = new WeakMap<
|
|
229
|
+
ZentuiConfig,
|
|
230
|
+
ReadonlySet<ComponentStyleOwner>
|
|
231
|
+
>();
|
|
232
|
+
const styleOwners = Object.keys(
|
|
233
|
+
knownComponentStyleIds,
|
|
234
|
+
) as ComponentStyleOwner[];
|
|
1204
235
|
|
|
1205
236
|
function unsupportedSelectedStyleId(
|
|
1206
237
|
record: ConfigRecord,
|
|
1207
238
|
owner: ComponentStyleOwner,
|
|
1208
239
|
): string | undefined {
|
|
1209
|
-
const
|
|
1210
|
-
if (!hasOwn(component, "style")) return undefined;
|
|
1211
|
-
const style = component.style;
|
|
240
|
+
const style = recordValue(recordValue(record.components)[owner]).style;
|
|
1212
241
|
return typeof style === "string" &&
|
|
1213
242
|
style.trim() &&
|
|
1214
243
|
!knownComponentStyleIds[owner].has(style) &&
|
|
@@ -1224,38 +253,69 @@ export function hasUnsupportedComponentStyle(
|
|
|
1224
253
|
return unsupportedComponentStyles.get(config)?.has(owner) ?? false;
|
|
1225
254
|
}
|
|
1226
255
|
|
|
1227
|
-
|
|
1228
|
-
const
|
|
1229
|
-
const
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
256
|
+
function resolveComponents(value: unknown): ComponentsConfig {
|
|
257
|
+
const source = recordValue(value);
|
|
258
|
+
const selector = recordValue(source.selectorBorders);
|
|
259
|
+
return {
|
|
260
|
+
editor: normalizeEditor(source.editor),
|
|
261
|
+
userMessages: normalizeUserMessages(source.userMessages),
|
|
262
|
+
workingLine: normalizeWorkingLine(source.workingLine),
|
|
263
|
+
selectorBorders: {
|
|
264
|
+
enabled: booleanValue(selector.enabled, true),
|
|
265
|
+
style: "zentui",
|
|
266
|
+
},
|
|
267
|
+
footer: normalizeFooter(source.footer),
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/** 各配置领域在此组合,运行时仅使用 canonical 结构。 */
|
|
272
|
+
export function mergeConfig(parsed: unknown): ZentuiConfig {
|
|
273
|
+
const record = recordValue(parsed);
|
|
274
|
+
const icons = recordValue(record.icons);
|
|
275
|
+
const colors = recordValue(record.colors);
|
|
276
|
+
const interval = record.projectRefreshIntervalMs;
|
|
277
|
+
const config: ZentuiConfig = {
|
|
278
|
+
projectRefreshIntervalMs:
|
|
279
|
+
typeof interval === "number" && Number.isFinite(interval)
|
|
280
|
+
? Math.round(interval) <= 0
|
|
281
|
+
? 0
|
|
282
|
+
: Math.max(5_000, Math.round(interval))
|
|
283
|
+
: 30_000,
|
|
1236
284
|
icons: resolveConfiguredIcons(
|
|
1237
|
-
normalizeIconMode(
|
|
1238
|
-
|
|
285
|
+
normalizeIconMode(icons.mode),
|
|
286
|
+
Object.fromEntries(
|
|
287
|
+
ICON_GLYPH_KEYS.filter((key) => typeof icons[key] === "string").map(
|
|
288
|
+
(key) => [key, icons[key]],
|
|
289
|
+
),
|
|
290
|
+
) as Partial<IconGlyphs>,
|
|
1239
291
|
),
|
|
1240
292
|
colors: {
|
|
1241
293
|
...defaultConfig.colors,
|
|
1242
|
-
...
|
|
294
|
+
...Object.fromEntries(
|
|
295
|
+
colorKeys
|
|
296
|
+
.filter(
|
|
297
|
+
(key) =>
|
|
298
|
+
typeof colors[key] === "string" &&
|
|
299
|
+
isSupportedColorSpec(colors[key]),
|
|
300
|
+
)
|
|
301
|
+
.map((key) => [key, colors[key]]),
|
|
302
|
+
),
|
|
1243
303
|
},
|
|
1244
|
-
components: resolveComponents(
|
|
304
|
+
components: resolveComponents(record.components),
|
|
1245
305
|
};
|
|
1246
|
-
const
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
] as const) {
|
|
1254
|
-
if (unsupportedSelectedStyleId(config, owner) !== undefined)
|
|
1255
|
-
unsupported.add(owner);
|
|
306
|
+
const unsupported = new Set(
|
|
307
|
+
styleOwners.filter(
|
|
308
|
+
(owner) => unsupportedSelectedStyleId(record, owner) !== undefined,
|
|
309
|
+
),
|
|
310
|
+
);
|
|
311
|
+
if (unsupported.size > 0) {
|
|
312
|
+
unsupportedComponentStyles.set(config, unsupported);
|
|
1256
313
|
}
|
|
1257
|
-
|
|
1258
|
-
|
|
314
|
+
return config;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
export function loadConfig(): ZentuiConfig {
|
|
318
|
+
return mergeConfig(configStore.read());
|
|
1259
319
|
}
|
|
1260
320
|
|
|
1261
321
|
export function getExtensionStatusPlacement(
|
|
@@ -1263,113 +323,78 @@ export function getExtensionStatusPlacement(
|
|
|
1263
323
|
key: string,
|
|
1264
324
|
): ExtensionStatusPlacement {
|
|
1265
325
|
const statuses = config.components.footer.styles.starship.extensionStatuses;
|
|
1266
|
-
if (
|
|
1267
|
-
|
|
1268
|
-
|
|
326
|
+
if (
|
|
327
|
+
Object.hasOwn(statuses.placements, key) &&
|
|
328
|
+
isExtensionStatusPlacement(statuses.placements[key])
|
|
329
|
+
) {
|
|
330
|
+
return statuses.placements[key];
|
|
1269
331
|
}
|
|
1270
332
|
return isExtensionStatusPlacement(statuses.defaultPlacement)
|
|
1271
333
|
? statuses.defaultPlacement
|
|
1272
|
-
:
|
|
334
|
+
: "right";
|
|
1273
335
|
}
|
|
1274
336
|
|
|
1275
337
|
export function getExtensionStatusColorMode(
|
|
1276
338
|
config: ZentuiConfig,
|
|
1277
339
|
key: string,
|
|
1278
340
|
): ExtensionStatusColorMode {
|
|
1279
|
-
const
|
|
341
|
+
const modes =
|
|
1280
342
|
config.components.footer.styles.starship.extensionStatuses.colorModes;
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
}
|
|
1285
|
-
return DEFAULT_EXTENSION_STATUS_COLOR_MODE;
|
|
343
|
+
return Object.hasOwn(modes, key) && isExtensionStatusColorMode(modes[key])
|
|
344
|
+
? modes[key]
|
|
345
|
+
: "zentui";
|
|
1286
346
|
}
|
|
1287
347
|
|
|
1288
|
-
/**
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
writable: true,
|
|
1308
|
-
});
|
|
348
|
+
/** 纯配置修改可在一次 ConfigStore.update 中组合成 Preset。 */
|
|
349
|
+
export function mutateComponentsRecord(
|
|
350
|
+
record: ConfigRecord,
|
|
351
|
+
update: (components: ComponentsConfig) => void,
|
|
352
|
+
replacedStyles: readonly ComponentStyleOwner[] = [],
|
|
353
|
+
): void {
|
|
354
|
+
const preserved = styleOwners.map(
|
|
355
|
+
(owner) => [owner, unsupportedSelectedStyleId(record, owner)] as const,
|
|
356
|
+
);
|
|
357
|
+
const components = resolveComponents(record.components);
|
|
358
|
+
update(components);
|
|
359
|
+
record.version = 1;
|
|
360
|
+
const merged = recordValue(
|
|
361
|
+
overlayKnown(record.components, resolveComponents(components)),
|
|
362
|
+
);
|
|
363
|
+
for (const [owner, style] of preserved) {
|
|
364
|
+
if (style !== undefined && !replacedStyles.includes(owner)) {
|
|
365
|
+
recordValue(merged[owner]).style = style;
|
|
366
|
+
}
|
|
1309
367
|
}
|
|
1310
|
-
|
|
368
|
+
record.components = merged;
|
|
1311
369
|
}
|
|
1312
370
|
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
footer: unsupportedSelectedStyleId(record, "footer"),
|
|
371
|
+
function mutateConfig(
|
|
372
|
+
path: string,
|
|
373
|
+
update: (record: ConfigRecord) => void,
|
|
374
|
+
): ZentuiConfig {
|
|
375
|
+
const mutate = (record: ConfigRecord) => {
|
|
376
|
+
record.version = 1;
|
|
377
|
+
update(record);
|
|
1321
378
|
};
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
replacedStyle?: ComponentStyleOwner,
|
|
1328
|
-
): void {
|
|
1329
|
-
const components = recordValue(record.components);
|
|
1330
|
-
for (const [owner, style] of Object.entries(preserved) as [
|
|
1331
|
-
ComponentStyleOwner,
|
|
1332
|
-
string,
|
|
1333
|
-
][]) {
|
|
1334
|
-
if (style === undefined || owner === replacedStyle) continue;
|
|
1335
|
-
const component = recordValue(components[owner]);
|
|
1336
|
-
component.style = style;
|
|
1337
|
-
components[owner] = component;
|
|
1338
|
-
}
|
|
1339
|
-
record.components = components;
|
|
379
|
+
return mergeConfig(
|
|
380
|
+
path === configPath
|
|
381
|
+
? configStore.update(mutate)
|
|
382
|
+
: mutateConfigFile(path, mutate),
|
|
383
|
+
);
|
|
1340
384
|
}
|
|
1341
385
|
|
|
1342
386
|
function saveComponentsMutation(
|
|
1343
387
|
update: (components: ComponentsConfig) => void,
|
|
1344
388
|
path: string,
|
|
1345
389
|
replacedStyle?: ComponentStyleOwner,
|
|
1346
|
-
):
|
|
1347
|
-
return mutateConfig(path, (record) =>
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
});
|
|
1355
|
-
}
|
|
1356
|
-
|
|
1357
|
-
function applyEditorComponentPatch(
|
|
1358
|
-
component: EditorComponentConfig,
|
|
1359
|
-
patch: Partial<
|
|
1360
|
-
Pick<
|
|
1361
|
-
EditorComponentConfig,
|
|
1362
|
-
"style" | "borderColorMode" | "modelLabel" | "viewportIndicators"
|
|
1363
|
-
>
|
|
1364
|
-
>,
|
|
1365
|
-
): void {
|
|
1366
|
-
if (patch.style !== undefined) component.style = patch.style;
|
|
1367
|
-
if (patch.borderColorMode !== undefined)
|
|
1368
|
-
component.borderColorMode = patch.borderColorMode;
|
|
1369
|
-
if (patch.modelLabel !== undefined) component.modelLabel = patch.modelLabel;
|
|
1370
|
-
if (patch.viewportIndicators !== undefined) {
|
|
1371
|
-
component.viewportIndicators = patch.viewportIndicators;
|
|
1372
|
-
}
|
|
390
|
+
): ZentuiConfig {
|
|
391
|
+
return mutateConfig(path, (record) =>
|
|
392
|
+
mutateComponentsRecord(
|
|
393
|
+
record,
|
|
394
|
+
update,
|
|
395
|
+
replacedStyle ? [replacedStyle] : [],
|
|
396
|
+
),
|
|
397
|
+
);
|
|
1373
398
|
}
|
|
1374
399
|
|
|
1375
400
|
export function saveEditorComponentPatch(
|
|
@@ -1380,236 +405,173 @@ export function saveEditorComponentPatch(
|
|
|
1380
405
|
>
|
|
1381
406
|
>,
|
|
1382
407
|
path = configPath,
|
|
1383
|
-
):
|
|
408
|
+
): ZentuiConfig {
|
|
1384
409
|
return saveComponentsMutation(
|
|
1385
|
-
(components) =>
|
|
410
|
+
(components) => {
|
|
411
|
+
components.editor = overlayKnown(
|
|
412
|
+
components.editor,
|
|
413
|
+
patch,
|
|
414
|
+
) as EditorComponentConfig;
|
|
415
|
+
},
|
|
1386
416
|
path,
|
|
1387
417
|
patch.style !== undefined ? "editor" : undefined,
|
|
1388
418
|
);
|
|
1389
419
|
}
|
|
1390
|
-
|
|
1391
|
-
function applyMinimalistStylePatch(
|
|
1392
|
-
style: MinimalistEditorStyleConfig,
|
|
1393
|
-
patch: Partial<MinimalistEditorStyleConfig>,
|
|
1394
|
-
): void {
|
|
1395
|
-
if (patch.pathDisplay !== undefined) style.pathDisplay = patch.pathDisplay;
|
|
1396
|
-
if (patch.showCwd !== undefined) {
|
|
1397
|
-
style.showCwd = patch.showCwd;
|
|
1398
|
-
}
|
|
1399
|
-
if (patch.showSessionName !== undefined)
|
|
1400
|
-
style.showSessionName = patch.showSessionName;
|
|
1401
|
-
if (patch.showTimer !== undefined) style.showTimer = patch.showTimer;
|
|
1402
|
-
if (patch.showCost !== undefined) style.showCost = patch.showCost;
|
|
1403
|
-
if (patch.showGit !== undefined) style.showGit = patch.showGit;
|
|
1404
|
-
}
|
|
1405
|
-
|
|
1406
420
|
export function saveMinimalistEditorStylePatch(
|
|
1407
421
|
patch: Partial<MinimalistEditorStyleConfig>,
|
|
1408
422
|
path = configPath,
|
|
1409
|
-
):
|
|
1410
|
-
return saveComponentsMutation(
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
423
|
+
): ZentuiConfig {
|
|
424
|
+
return saveComponentsMutation((components) => {
|
|
425
|
+
components.editor.styles.minimalist = overlayKnown(
|
|
426
|
+
components.editor.styles.minimalist,
|
|
427
|
+
patch,
|
|
428
|
+
) as MinimalistEditorStyleConfig;
|
|
429
|
+
}, path);
|
|
1415
430
|
}
|
|
1416
|
-
|
|
1417
431
|
export function saveUserMessagesComponentPatch(
|
|
1418
432
|
patch: Partial<Pick<UserMessagesComponentConfig, "enabled" | "style">>,
|
|
1419
433
|
path = configPath,
|
|
1420
|
-
):
|
|
434
|
+
): ZentuiConfig {
|
|
1421
435
|
return saveComponentsMutation(
|
|
1422
436
|
(components) => {
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
437
|
+
components.userMessages = overlayKnown(
|
|
438
|
+
components.userMessages,
|
|
439
|
+
patch,
|
|
440
|
+
) as UserMessagesComponentConfig;
|
|
1426
441
|
},
|
|
1427
442
|
path,
|
|
1428
443
|
patch.style !== undefined ? "userMessages" : undefined,
|
|
1429
444
|
);
|
|
1430
445
|
}
|
|
1431
|
-
|
|
1432
446
|
export function saveWorkingLineComponentPatch(
|
|
1433
447
|
patch: WorkingLineComponentPatch,
|
|
1434
448
|
path = configPath,
|
|
1435
|
-
):
|
|
449
|
+
): ZentuiConfig {
|
|
1436
450
|
return saveComponentsMutation((components) => {
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
if (patch.spinner !== undefined) component.spinner = patch.spinner;
|
|
1442
|
-
if (patch.spinnerIntervalMs !== undefined)
|
|
1443
|
-
component.spinnerIntervalMs = patch.spinnerIntervalMs;
|
|
1444
|
-
if (patch.animateSpinnerColor !== undefined)
|
|
1445
|
-
component.animateSpinnerColor = patch.animateSpinnerColor;
|
|
1446
|
-
if (patch.textIntervalMs !== undefined)
|
|
1447
|
-
component.textIntervalMs = patch.textIntervalMs;
|
|
1448
|
-
if (patch.textAnimation !== undefined)
|
|
1449
|
-
component.textAnimation = patch.textAnimation;
|
|
1450
|
-
if (patch.messages?.custom !== undefined)
|
|
1451
|
-
component.messages.custom = patch.messages.custom;
|
|
1452
|
-
if (patch.messages?.values !== undefined) {
|
|
1453
|
-
component.messages.values = normalizeWorkingLineMessages([
|
|
1454
|
-
...patch.messages.values,
|
|
1455
|
-
]);
|
|
1456
|
-
}
|
|
1457
|
-
if (patch.segments?.tool !== undefined)
|
|
1458
|
-
component.segments.tool = patch.segments.tool;
|
|
1459
|
-
if (patch.segments?.elapsed !== undefined)
|
|
1460
|
-
component.segments.elapsed = patch.segments.elapsed;
|
|
1461
|
-
if (patch.segments?.thought !== undefined)
|
|
1462
|
-
component.segments.thought = patch.segments.thought;
|
|
1463
|
-
if (patch.segments?.tokens !== undefined)
|
|
1464
|
-
component.segments.tokens = patch.segments.tokens;
|
|
451
|
+
components.workingLine = overlayKnown(
|
|
452
|
+
components.workingLine,
|
|
453
|
+
patch,
|
|
454
|
+
) as WorkingLineComponentConfig;
|
|
1465
455
|
}, path);
|
|
1466
456
|
}
|
|
1467
|
-
|
|
1468
457
|
export function saveSelectorBordersComponentPatch(
|
|
1469
458
|
patch: Partial<SelectorBordersComponentConfig>,
|
|
1470
459
|
path = configPath,
|
|
1471
|
-
):
|
|
460
|
+
): ZentuiConfig {
|
|
1472
461
|
return saveComponentsMutation(
|
|
1473
462
|
(components) => {
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
463
|
+
components.selectorBorders = overlayKnown(
|
|
464
|
+
components.selectorBorders,
|
|
465
|
+
patch,
|
|
466
|
+
) as SelectorBordersComponentConfig;
|
|
1477
467
|
},
|
|
1478
468
|
path,
|
|
1479
469
|
patch.style !== undefined ? "selectorBorders" : undefined,
|
|
1480
470
|
);
|
|
1481
471
|
}
|
|
1482
|
-
|
|
1483
472
|
export function saveFooterComponentPatch(
|
|
1484
473
|
patch: Partial<Pick<FooterComponentConfig, "style" | "modelLabel">>,
|
|
1485
474
|
path = configPath,
|
|
1486
|
-
):
|
|
475
|
+
): ZentuiConfig {
|
|
1487
476
|
return saveComponentsMutation(
|
|
1488
477
|
(components) => {
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
478
|
+
components.footer = overlayKnown(
|
|
479
|
+
components.footer,
|
|
480
|
+
patch,
|
|
481
|
+
) as FooterComponentConfig;
|
|
1493
482
|
},
|
|
1494
483
|
path,
|
|
1495
484
|
patch.style !== undefined ? "footer" : undefined,
|
|
1496
485
|
);
|
|
1497
486
|
}
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
}
|
|
1517
|
-
if (patch.pathDisplay !== undefined) {
|
|
1518
|
-
style.pathDisplay = { ...style.pathDisplay, ...patch.pathDisplay };
|
|
1519
|
-
}
|
|
1520
|
-
if (patch.segments !== undefined)
|
|
1521
|
-
style.segments = { ...style.segments, ...patch.segments };
|
|
1522
|
-
if (patch.gitBranch !== undefined)
|
|
1523
|
-
style.gitBranch = { ...style.gitBranch, ...patch.gitBranch };
|
|
1524
|
-
if (patch.gitCommit !== undefined)
|
|
1525
|
-
style.gitCommit = { ...style.gitCommit, ...patch.gitCommit };
|
|
1526
|
-
if (patch.gitMetrics !== undefined)
|
|
1527
|
-
style.gitMetrics = { ...style.gitMetrics, ...patch.gitMetrics };
|
|
1528
|
-
if (patch.extensionStatuses !== undefined) {
|
|
1529
|
-
style.extensionStatuses = {
|
|
1530
|
-
...style.extensionStatuses,
|
|
1531
|
-
...patch.extensionStatuses,
|
|
1532
|
-
placements: {
|
|
1533
|
-
...style.extensionStatuses.placements,
|
|
1534
|
-
...patch.extensionStatuses.placements,
|
|
1535
|
-
},
|
|
1536
|
-
colorModes: {
|
|
1537
|
-
...style.extensionStatuses.colorModes,
|
|
1538
|
-
...patch.extensionStatuses.colorModes,
|
|
1539
|
-
},
|
|
1540
|
-
};
|
|
1541
|
-
}
|
|
1542
|
-
}
|
|
487
|
+
export type StarshipFooterStylePatch = Partial<
|
|
488
|
+
Omit<
|
|
489
|
+
StarshipFooterStyleConfig,
|
|
490
|
+
| "contextThresholds"
|
|
491
|
+
| "pathDisplay"
|
|
492
|
+
| "segments"
|
|
493
|
+
| "gitBranch"
|
|
494
|
+
| "gitCommit"
|
|
495
|
+
| "gitMetrics"
|
|
496
|
+
>
|
|
497
|
+
> & {
|
|
498
|
+
contextThresholds?: Partial<ContextThresholds>;
|
|
499
|
+
pathDisplay?: Partial<PathDisplayConfig>;
|
|
500
|
+
segments?: Partial<FooterSegmentsConfig>;
|
|
501
|
+
gitBranch?: Partial<GitBranchConfig>;
|
|
502
|
+
gitCommit?: Partial<GitCommitConfig>;
|
|
503
|
+
gitMetrics?: Partial<GitMetricsConfig>;
|
|
504
|
+
};
|
|
1543
505
|
|
|
1544
506
|
export function saveStarshipFooterStylePatch(
|
|
1545
|
-
patch:
|
|
507
|
+
patch: StarshipFooterStylePatch,
|
|
1546
508
|
path = configPath,
|
|
1547
|
-
):
|
|
1548
|
-
return saveComponentsMutation(
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
509
|
+
): ZentuiConfig {
|
|
510
|
+
return saveComponentsMutation((components) => {
|
|
511
|
+
components.footer.styles.starship = overlayKnown(
|
|
512
|
+
components.footer.styles.starship,
|
|
513
|
+
patch,
|
|
514
|
+
) as StarshipFooterStyleConfig;
|
|
515
|
+
}, path);
|
|
1553
516
|
}
|
|
1554
|
-
|
|
1555
517
|
export function saveUiFeaturesPatch(
|
|
1556
518
|
patch: Partial<UiFeaturesConfig>,
|
|
1557
519
|
path = configPath,
|
|
1558
|
-
):
|
|
1559
|
-
const valid = validUiFeatureEntries(patch);
|
|
520
|
+
): ZentuiConfig {
|
|
1560
521
|
return saveComponentsMutation(
|
|
1561
522
|
(components) => {
|
|
1562
|
-
if (
|
|
1563
|
-
components.editor.style =
|
|
1564
|
-
components.userMessages.enabled =
|
|
1565
|
-
components.selectorBorders.enabled =
|
|
523
|
+
if (typeof patch.editor === "boolean") {
|
|
524
|
+
components.editor.style = patch.editor ? "on" : "off";
|
|
525
|
+
components.userMessages.enabled = patch.editor;
|
|
526
|
+
components.selectorBorders.enabled = patch.editor;
|
|
1566
527
|
}
|
|
1567
|
-
if (
|
|
1568
|
-
components.footer.style =
|
|
528
|
+
if (typeof patch.statusLine === "boolean") {
|
|
529
|
+
components.footer.style = patch.statusLine ? "starship" : "native";
|
|
1569
530
|
}
|
|
1570
|
-
if (
|
|
1571
|
-
components.editor.viewportIndicators =
|
|
531
|
+
if (typeof patch.viewportIndicators === "boolean") {
|
|
532
|
+
components.editor.viewportIndicators = patch.viewportIndicators;
|
|
1572
533
|
}
|
|
1573
534
|
},
|
|
1574
535
|
path,
|
|
1575
|
-
|
|
536
|
+
typeof patch.statusLine === "boolean" ? "footer" : undefined,
|
|
1576
537
|
);
|
|
1577
538
|
}
|
|
1578
|
-
|
|
1579
539
|
export function saveFooterSegmentsPatch(
|
|
1580
540
|
patch: Partial<FooterSegmentsConfig>,
|
|
1581
541
|
path = configPath,
|
|
1582
|
-
):
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
542
|
+
): ZentuiConfig {
|
|
543
|
+
const segments = Object.fromEntries(
|
|
544
|
+
Object.entries(patch).filter(
|
|
545
|
+
([key, value]) =>
|
|
546
|
+
Object.hasOwn(defaultFooterSegments, key) && typeof value === "boolean",
|
|
547
|
+
),
|
|
548
|
+
) as FooterSegmentsConfig;
|
|
549
|
+
return saveStarshipFooterStylePatch({ segments }, path);
|
|
1587
550
|
}
|
|
1588
|
-
|
|
1589
551
|
export function saveFooterFormatPatch(
|
|
1590
552
|
value: string,
|
|
1591
553
|
path = configPath,
|
|
1592
|
-
):
|
|
554
|
+
): ZentuiConfig {
|
|
1593
555
|
return saveStarshipFooterStylePatch(
|
|
1594
556
|
{ format: typeof value === "string" ? value : "" },
|
|
1595
557
|
path,
|
|
1596
558
|
);
|
|
1597
559
|
}
|
|
1598
|
-
|
|
1599
560
|
export function saveResponsiveFooterPatch(
|
|
1600
|
-
patch:
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
>,
|
|
561
|
+
patch: {
|
|
562
|
+
responsiveFooter?: boolean;
|
|
563
|
+
compactFooterFormat?: string;
|
|
564
|
+
compactFooterMaxLines?: CompactFooterMaxLines;
|
|
565
|
+
},
|
|
1606
566
|
path = configPath,
|
|
1607
|
-
):
|
|
567
|
+
): ZentuiConfig {
|
|
1608
568
|
const canonical: Partial<StarshipFooterStyleConfig> = {};
|
|
1609
|
-
if (typeof patch.responsiveFooter === "boolean")
|
|
569
|
+
if (typeof patch.responsiveFooter === "boolean") {
|
|
1610
570
|
canonical.responsive = patch.responsiveFooter;
|
|
1611
|
-
|
|
571
|
+
}
|
|
572
|
+
if (typeof patch.compactFooterFormat === "string") {
|
|
1612
573
|
canonical.compactFormat = patch.compactFooterFormat;
|
|
574
|
+
}
|
|
1613
575
|
if (patch.compactFooterMaxLines !== undefined) {
|
|
1614
576
|
canonical.compactMaxLines = parseCompactFooterMaxLines(
|
|
1615
577
|
patch.compactFooterMaxLines,
|
|
@@ -1617,164 +579,126 @@ export function saveResponsiveFooterPatch(
|
|
|
1617
579
|
}
|
|
1618
580
|
return saveStarshipFooterStylePatch(canonical, path);
|
|
1619
581
|
}
|
|
1620
|
-
|
|
1621
582
|
export function saveIconsModePatch(
|
|
1622
583
|
mode: IconMode,
|
|
1623
584
|
path = configPath,
|
|
1624
|
-
):
|
|
585
|
+
): ZentuiConfig {
|
|
1625
586
|
return mutateConfig(path, (record) => {
|
|
1626
|
-
|
|
1627
|
-
|
|
587
|
+
record.icons = {
|
|
588
|
+
...recordValue(record.icons),
|
|
589
|
+
mode: normalizeIconMode(mode),
|
|
590
|
+
};
|
|
1628
591
|
});
|
|
1629
592
|
}
|
|
1630
|
-
|
|
1631
593
|
export function saveContextStylePatch(
|
|
1632
594
|
style: ContextStyle,
|
|
1633
595
|
path = configPath,
|
|
1634
|
-
):
|
|
596
|
+
): ZentuiConfig {
|
|
1635
597
|
return saveStarshipFooterStylePatch(
|
|
1636
598
|
{ contextStyle: parseContextStyle(style) },
|
|
1637
599
|
path,
|
|
1638
600
|
);
|
|
1639
601
|
}
|
|
1640
|
-
|
|
1641
602
|
export function saveSeparatorPatch(
|
|
1642
603
|
separator: SeparatorStyle,
|
|
1643
604
|
path = configPath,
|
|
1644
|
-
):
|
|
605
|
+
): ZentuiConfig {
|
|
1645
606
|
return saveStarshipFooterStylePatch(
|
|
1646
607
|
{ separator: parseSeparatorStyle(separator) },
|
|
1647
608
|
path,
|
|
1648
609
|
);
|
|
1649
610
|
}
|
|
1650
|
-
|
|
1651
611
|
export function saveContextThresholdsPatch(
|
|
1652
|
-
|
|
612
|
+
patch: Partial<ContextThresholds>,
|
|
1653
613
|
path = configPath,
|
|
1654
|
-
):
|
|
1655
|
-
if (
|
|
1656
|
-
typeof thresholds.warning === "bigint" ||
|
|
1657
|
-
typeof thresholds.error === "bigint"
|
|
1658
|
-
) {
|
|
614
|
+
): ZentuiConfig {
|
|
615
|
+
if (typeof patch.warning === "bigint" || typeof patch.error === "bigint") {
|
|
1659
616
|
throw new TypeError("Context thresholds must be JSON-serializable numbers");
|
|
1660
617
|
}
|
|
1661
|
-
return
|
|
1662
|
-
components.footer.styles.starship.contextThresholds = {
|
|
1663
|
-
...components.footer.styles.starship.contextThresholds,
|
|
1664
|
-
...thresholds,
|
|
1665
|
-
};
|
|
1666
|
-
}, path);
|
|
618
|
+
return saveStarshipFooterStylePatch({ contextThresholds: patch }, path);
|
|
1667
619
|
}
|
|
1668
|
-
|
|
1669
620
|
export function savePathDisplayPatch(
|
|
1670
621
|
patch: Partial<PathDisplayConfig>,
|
|
1671
622
|
path = configPath,
|
|
1672
|
-
):
|
|
1673
|
-
return
|
|
1674
|
-
components.footer.styles.starship.pathDisplay = {
|
|
1675
|
-
...components.footer.styles.starship.pathDisplay,
|
|
1676
|
-
...patch,
|
|
1677
|
-
};
|
|
1678
|
-
}, path);
|
|
623
|
+
): ZentuiConfig {
|
|
624
|
+
return saveStarshipFooterStylePatch({ pathDisplay: patch }, path);
|
|
1679
625
|
}
|
|
1680
|
-
|
|
1681
626
|
export function saveGitBranchPatch(
|
|
1682
627
|
patch: Partial<GitBranchConfig>,
|
|
1683
628
|
path = configPath,
|
|
1684
|
-
):
|
|
1685
|
-
return
|
|
1686
|
-
components.footer.styles.starship.gitBranch = {
|
|
1687
|
-
...components.footer.styles.starship.gitBranch,
|
|
1688
|
-
...patch,
|
|
1689
|
-
};
|
|
1690
|
-
}, path);
|
|
629
|
+
): ZentuiConfig {
|
|
630
|
+
return saveStarshipFooterStylePatch({ gitBranch: patch }, path);
|
|
1691
631
|
}
|
|
1692
|
-
|
|
1693
632
|
export function saveEditorModelLabel(
|
|
1694
633
|
value: ModelLabelSource,
|
|
1695
634
|
path = configPath,
|
|
1696
|
-
):
|
|
635
|
+
): ZentuiConfig {
|
|
1697
636
|
return saveComponentsMutation((components) => {
|
|
1698
|
-
|
|
1699
|
-
components.
|
|
1700
|
-
components.footer.modelLabel = normalized;
|
|
637
|
+
components.editor.modelLabel = parseEditorModelLabel(value);
|
|
638
|
+
components.footer.modelLabel = parseEditorModelLabel(value);
|
|
1701
639
|
}, path);
|
|
1702
640
|
}
|
|
1703
|
-
|
|
1704
641
|
export function saveEditorStyle(
|
|
1705
642
|
value: EditorStyle,
|
|
1706
643
|
path = configPath,
|
|
1707
|
-
):
|
|
644
|
+
): ZentuiConfig {
|
|
1708
645
|
return saveEditorComponentPatch({ style: parseEditorStyle(value) }, path);
|
|
1709
646
|
}
|
|
1710
|
-
|
|
1711
647
|
export function saveMinimalistPatch(
|
|
1712
648
|
patch: Partial<MinimalistConfig>,
|
|
1713
649
|
path = configPath,
|
|
1714
|
-
):
|
|
650
|
+
): ZentuiConfig {
|
|
1715
651
|
return saveMinimalistEditorStylePatch(patch, path);
|
|
1716
652
|
}
|
|
1717
|
-
|
|
1718
653
|
export function saveEditorBorderColorMode(
|
|
1719
654
|
value: EditorBorderColorMode,
|
|
1720
655
|
path = configPath,
|
|
1721
|
-
):
|
|
656
|
+
): ZentuiConfig {
|
|
1722
657
|
return saveEditorComponentPatch(
|
|
1723
658
|
{ borderColorMode: parseEditorBorderColorMode(value) },
|
|
1724
659
|
path,
|
|
1725
660
|
);
|
|
1726
661
|
}
|
|
1727
|
-
|
|
1728
662
|
export function saveGitCommitPatch(
|
|
1729
663
|
patch: Partial<Pick<GitCommitConfig, "onlyDetached" | "showTag">>,
|
|
1730
664
|
path = configPath,
|
|
1731
|
-
):
|
|
1732
|
-
const valid
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
};
|
|
1741
|
-
}, path);
|
|
665
|
+
): ZentuiConfig {
|
|
666
|
+
const valid = Object.fromEntries(
|
|
667
|
+
Object.entries(patch).filter(
|
|
668
|
+
([key, value]) =>
|
|
669
|
+
(key === "onlyDetached" || key === "showTag") &&
|
|
670
|
+
typeof value === "boolean",
|
|
671
|
+
),
|
|
672
|
+
);
|
|
673
|
+
return saveStarshipFooterStylePatch({ gitCommit: valid }, path);
|
|
1742
674
|
}
|
|
1743
|
-
|
|
1744
675
|
export function saveGitMetricsPatch(
|
|
1745
676
|
patch: Partial<GitMetricsConfig>,
|
|
1746
677
|
path = configPath,
|
|
1747
|
-
):
|
|
1748
|
-
const valid
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
...valid,
|
|
1757
|
-
};
|
|
1758
|
-
}, path);
|
|
678
|
+
): ZentuiConfig {
|
|
679
|
+
const valid = Object.fromEntries(
|
|
680
|
+
Object.entries(patch).filter(
|
|
681
|
+
([key, value]) =>
|
|
682
|
+
(key === "onlyNonzero" || key === "ignoreSubmodules") &&
|
|
683
|
+
typeof value === "boolean",
|
|
684
|
+
),
|
|
685
|
+
);
|
|
686
|
+
return saveStarshipFooterStylePatch({ gitMetrics: valid }, path);
|
|
1759
687
|
}
|
|
1760
|
-
|
|
1761
688
|
export function saveExtensionStatusDefaultPlacement(
|
|
1762
689
|
placement: ExtensionStatusPlacement,
|
|
1763
690
|
path = configPath,
|
|
1764
|
-
):
|
|
691
|
+
): ZentuiConfig {
|
|
1765
692
|
return saveComponentsMutation((components) => {
|
|
1766
693
|
components.footer.styles.starship.extensionStatuses.defaultPlacement =
|
|
1767
|
-
isExtensionStatusPlacement(placement)
|
|
1768
|
-
? placement
|
|
1769
|
-
: defaultConfig.extensionStatuses.defaultPlacement;
|
|
694
|
+
isExtensionStatusPlacement(placement) ? placement : "right";
|
|
1770
695
|
}, path);
|
|
1771
696
|
}
|
|
1772
|
-
|
|
1773
697
|
export function saveExtensionStatusPlacement(
|
|
1774
698
|
key: string,
|
|
1775
699
|
placement: ExtensionStatusPlacement,
|
|
1776
700
|
path = configPath,
|
|
1777
|
-
):
|
|
701
|
+
): ZentuiConfig {
|
|
1778
702
|
return saveComponentsMutation((components) => {
|
|
1779
703
|
Object.defineProperty(
|
|
1780
704
|
components.footer.styles.starship.extensionStatuses.placements,
|
|
@@ -1788,12 +712,11 @@ export function saveExtensionStatusPlacement(
|
|
|
1788
712
|
);
|
|
1789
713
|
}, path);
|
|
1790
714
|
}
|
|
1791
|
-
|
|
1792
715
|
export function saveExtensionStatusColorMode(
|
|
1793
716
|
key: string,
|
|
1794
717
|
colorMode: ExtensionStatusColorMode,
|
|
1795
718
|
path = configPath,
|
|
1796
|
-
):
|
|
719
|
+
): ZentuiConfig {
|
|
1797
720
|
return saveComponentsMutation((components) => {
|
|
1798
721
|
Object.defineProperty(
|
|
1799
722
|
components.footer.styles.starship.extensionStatuses.colorModes,
|