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