@xzzpig/pi-starline 0.5.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/FORK-CHANGELOG.md +19 -0
- package/README.md +68 -181
- package/extensions/starline/config.ts +156 -326
- package/extensions/starline/context-live.ts +33 -0
- package/extensions/starline/editor-cursor.ts +3 -0
- package/extensions/starline/extension-status.ts +9 -5
- package/extensions/starline/footer.ts +331 -528
- package/extensions/starline/fork-editor-cursor.ts +14 -0
- package/extensions/starline/format.ts +151 -20
- package/extensions/starline/git-live.ts +20 -0
- package/extensions/starline/git-probe.ts +40 -0
- package/extensions/starline/git-segments.ts +175 -0
- package/extensions/starline/git.ts +71 -0
- package/extensions/starline/icons.ts +17 -0
- package/extensions/starline/index.ts +188 -91
- package/extensions/starline/live-session.ts +164 -0
- package/extensions/starline/live-tps.ts +165 -0
- package/extensions/starline/mouse/bubble-dismiss.ts +82 -0
- package/extensions/starline/mouse/cursor-marker.ts +69 -0
- package/extensions/starline/mouse/editor-hit-test.ts +6 -3
- package/extensions/starline/mouse/external-layer.ts +42 -0
- package/extensions/starline/mouse/fork-native-clipboard.ts +57 -0
- package/extensions/starline/mouse/fork-pill-mouse.ts +19 -0
- package/extensions/starline/mouse/fork-pointer-coordination.ts +10 -0
- package/extensions/starline/mouse/fork-transcript-copy.ts +54 -0
- package/extensions/starline/mouse/fork-wheel-compat.ts +22 -0
- package/extensions/starline/mouse/hint.ts +4 -4
- package/extensions/starline/mouse/index.ts +54 -24
- package/extensions/starline/mouse/pointer-events.ts +73 -0
- package/extensions/starline/mouse/pointer-shape.ts +138 -0
- package/extensions/starline/mouse/transcript-copy.ts +76 -33
- package/extensions/starline/paste-collapse.ts +52 -13
- package/extensions/starline/pill-actions.ts +590 -0
- package/extensions/starline/pill-anchors.ts +26 -0
- package/extensions/starline/pill-api.ts +80 -0
- package/extensions/starline/pill-bubble.ts +607 -0
- package/extensions/starline/pill-config.ts +67 -9
- package/extensions/starline/pill.ts +102 -20
- package/extensions/starline/project-probe.ts +79 -0
- package/extensions/starline/prototype-patch-registry.ts +6 -1
- package/extensions/starline/queue-rows.ts +43 -0
- package/extensions/starline/settings-command.ts +124 -177
- package/extensions/starline/subagent-fleet.ts +246 -0
- package/extensions/starline/turn-clock.ts +81 -0
- package/extensions/starline/ui.ts +297 -156
- package/extensions/starline/working-indicator.ts +189 -0
- package/package.json +6 -5
- package/types/pill-api.d.ts +115 -0
- package/extensions/starline/editor-metadata-format.ts +0 -259
- package/extensions/starline/footer-format.ts +0 -279
|
@@ -15,7 +15,6 @@ import {
|
|
|
15
15
|
type ContextStyle,
|
|
16
16
|
type ExtensionStatusColorMode,
|
|
17
17
|
type ExtensionStatusPlacement,
|
|
18
|
-
type FooterSegmentsConfig,
|
|
19
18
|
type GitBranchConfig,
|
|
20
19
|
type GitBranchMaxLength,
|
|
21
20
|
getExtensionStatusColorMode,
|
|
@@ -23,16 +22,23 @@ import {
|
|
|
23
22
|
type IconMode,
|
|
24
23
|
isExtensionStatusColorMode,
|
|
25
24
|
isExtensionStatusPlacement,
|
|
26
|
-
isSeparatorStyle,
|
|
27
25
|
type MouseConfig,
|
|
28
26
|
type PathDisplayConfig,
|
|
29
27
|
type PathDisplayMode,
|
|
30
28
|
type PolishedTuiConfig,
|
|
31
|
-
type SeparatorStyle,
|
|
32
29
|
type UiFeaturesConfig,
|
|
33
30
|
} from "./config";
|
|
34
31
|
import { sanitizeExtensionStatusText } from "./extension-status";
|
|
35
32
|
import { isIconMode } from "./icons";
|
|
33
|
+
import { pillActionFor, runPillAction } from "./pill-actions";
|
|
34
|
+
import { getPillAnchor } from "./pill-anchors";
|
|
35
|
+
import {
|
|
36
|
+
EXTENSION_STATUS_PREFIX,
|
|
37
|
+
isKnownPillSegment,
|
|
38
|
+
movePillSegment,
|
|
39
|
+
PILL_SEGMENT_NAMES,
|
|
40
|
+
pillSegmentPosition,
|
|
41
|
+
} from "./pill-config";
|
|
36
42
|
import type { SessionLifecycle } from "./session-lifecycle";
|
|
37
43
|
import { EDITOR_BORDER_STYLE, renderChromeBorder, safeThemeFg } from "./style";
|
|
38
44
|
|
|
@@ -42,11 +48,9 @@ const extensionStatusPlacementValues: ExtensionStatusPlacement[] = [
|
|
|
42
48
|
"left",
|
|
43
49
|
"middle",
|
|
44
50
|
"right",
|
|
45
|
-
"editor",
|
|
46
51
|
];
|
|
47
52
|
const extensionStatusColorModeValues: ExtensionStatusColorMode[] = ["themed", "original"];
|
|
48
53
|
const contextStyleValues: ContextStyle[] = ["text", "gauge", "text+gauge"];
|
|
49
|
-
const separatorStyleValues: SeparatorStyle[] = ["pipe", "dot", "chevron", "none"];
|
|
50
54
|
const pathDisplayModeValues: PathDisplayMode[] = ["basename", "full"];
|
|
51
55
|
const pathDepthValues = ["0", "1", "2", "3", "4", "5"] as const;
|
|
52
56
|
const branchLengthPresetValues = ["full", "10", "20", "30", "40", "50"] as const;
|
|
@@ -54,25 +58,12 @@ const iconModeValues: IconMode[] = ["auto", "nerd", "ascii"];
|
|
|
54
58
|
type FeatureState = "enabled" | "disabled";
|
|
55
59
|
|
|
56
60
|
const featureStateValues: FeatureState[] = ["enabled", "disabled"];
|
|
57
|
-
const settingsSections = [
|
|
58
|
-
"coloring",
|
|
59
|
-
"features",
|
|
60
|
-
"layout",
|
|
61
|
-
"builtinSegments",
|
|
62
|
-
"extensionSegments",
|
|
63
|
-
] as const;
|
|
61
|
+
const settingsSections = ["coloring", "features", "layout", "pills", "extensionSegments"] as const;
|
|
64
62
|
|
|
65
63
|
type ColorSettingId = "starship" | "editorMessages";
|
|
66
64
|
type FeatureSettingId = keyof UiFeaturesConfig;
|
|
67
|
-
type FooterSegmentSettingId = keyof FooterSegmentsConfig;
|
|
68
65
|
type SettingsSection = (typeof settingsSections)[number];
|
|
69
|
-
type LayoutSettingId =
|
|
70
|
-
| "contextStyle"
|
|
71
|
-
| "separator"
|
|
72
|
-
| "pathDisplay"
|
|
73
|
-
| "pathDepth"
|
|
74
|
-
| "branchLength"
|
|
75
|
-
| "iconMode";
|
|
66
|
+
type LayoutSettingId = "contextStyle" | "pathDisplay" | "pathDepth" | "branchLength" | "iconMode";
|
|
76
67
|
|
|
77
68
|
type SettingsCommandDeps = {
|
|
78
69
|
sessionLifecycle: SessionLifecycle;
|
|
@@ -82,13 +73,11 @@ type SettingsCommandDeps = {
|
|
|
82
73
|
patch: Partial<UiFeaturesConfig>,
|
|
83
74
|
ctx: ExtensionContext,
|
|
84
75
|
) => { applied: boolean; reason?: string };
|
|
85
|
-
setFooterSegments: (patch: Partial<FooterSegmentsConfig>) => void;
|
|
86
|
-
setFooterFormat: (value: string) => void;
|
|
87
76
|
setIconMode: (mode: IconMode) => void;
|
|
88
77
|
setContextStyle: (style: ContextStyle) => void;
|
|
89
|
-
setSeparator: (separator: SeparatorStyle) => void;
|
|
90
78
|
setPathDisplay: (patch: Partial<PathDisplayConfig>) => void;
|
|
91
79
|
setGitBranch: (patch: Partial<GitBranchConfig>) => void;
|
|
80
|
+
setPillSegments: (segments: readonly string[]) => void;
|
|
92
81
|
getActiveExtensionStatuses: () => ReadonlyMap<string, string>;
|
|
93
82
|
setExtensionStatusPlacement: (key: string, placement: ExtensionStatusPlacement) => void;
|
|
94
83
|
setExtensionStatusColorMode: (key: string, colorMode: ExtensionStatusColorMode) => void;
|
|
@@ -116,63 +105,74 @@ const featureSettingLabels: Record<FeatureSettingId, string> = {
|
|
|
116
105
|
};
|
|
117
106
|
|
|
118
107
|
const featureSettingDescriptions: Record<FeatureSettingId, string> = {
|
|
119
|
-
editor:
|
|
120
|
-
"Enable or disable Starline's custom editor, selector borders, and previous-message chrome.",
|
|
108
|
+
editor: "Enable or disable Starline's custom editor and selector borders.",
|
|
121
109
|
statusLine: "Enable or disable Starline's custom footer/status line.",
|
|
122
110
|
copyFriendly:
|
|
123
111
|
"Hide editor and previous-message rail glyphs for cleaner native terminal selection.",
|
|
124
112
|
};
|
|
125
113
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
114
|
+
/** Row label per bar segment. The order rows are listed in is fixed. */
|
|
115
|
+
const pillSegmentLabels: Record<string, string> = {
|
|
116
|
+
model: "Model",
|
|
117
|
+
thinking: "Thinking",
|
|
118
|
+
queue: "Queue",
|
|
119
|
+
subagents: "Subagents",
|
|
120
|
+
cwd: "Directory",
|
|
130
121
|
sessionName: "Session name",
|
|
131
|
-
|
|
132
|
-
gitStatus: "Git status",
|
|
133
|
-
gitCounts: "Git counts",
|
|
134
|
-
sessionDuration: "Session duration",
|
|
135
|
-
username: "Username@host",
|
|
136
|
-
time: "Current time",
|
|
137
|
-
os: "OS icon",
|
|
138
|
-
runtime: "Runtime",
|
|
139
|
-
context: "Context usage",
|
|
140
|
-
tokens: "Token counts",
|
|
141
|
-
cacheHit: "Cache hit rate",
|
|
142
|
-
cost: "Session cost",
|
|
143
|
-
packageVersion: "Package version",
|
|
122
|
+
git: "Git",
|
|
144
123
|
gitCommit: "Git commit",
|
|
124
|
+
gitTag: "Git tag",
|
|
145
125
|
gitMetrics: "Git line metrics",
|
|
126
|
+
runtime: "Runtime",
|
|
127
|
+
context: "Context",
|
|
128
|
+
cost: "Cost",
|
|
129
|
+
sessionDuration: "Session duration",
|
|
130
|
+
username: "user@host",
|
|
131
|
+
time: "Time",
|
|
132
|
+
os: "OS",
|
|
133
|
+
packageVersion: "Package version",
|
|
134
|
+
extensionStatus: "Other extensions",
|
|
146
135
|
};
|
|
147
136
|
|
|
148
|
-
const
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
137
|
+
const pillSegmentSettingPrefix = "pillSegment:";
|
|
138
|
+
|
|
139
|
+
function pillSegmentSettingId(name: string): string {
|
|
140
|
+
return `${pillSegmentSettingPrefix}${name}`;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function pillSegmentFromId(id: string): string | undefined {
|
|
144
|
+
if (!id.startsWith(pillSegmentSettingPrefix)) return undefined;
|
|
145
|
+
const name = id.slice(pillSegmentSettingPrefix.length);
|
|
146
|
+
// Per-status segments (`extensionStatus:<key>`) are rows too; the key is read
|
|
147
|
+
// from whatever the extension published this session, so any key is valid.
|
|
148
|
+
return isKnownPillSegment(name) ? name : undefined;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/** Row label for a segment, including the single-status rows. */
|
|
152
|
+
function pillSegmentLabel(name: string): string {
|
|
153
|
+
const builtin = pillSegmentLabels[name];
|
|
154
|
+
if (builtin) return builtin;
|
|
155
|
+
return name.startsWith(EXTENSION_STATUS_PREFIX)
|
|
156
|
+
? name.slice(EXTENSION_STATUS_PREFIX.length)
|
|
157
|
+
: name;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Values a row cycles through: `off`, then every position the bar can hold.
|
|
162
|
+
*
|
|
163
|
+
* A segment that is not on the bar gets one extra value so it can be appended to
|
|
164
|
+
* the end. A segment that is already on the bar must not get it: appending it
|
|
165
|
+
* would put it back where it already is, so the cycle would bounce between the
|
|
166
|
+
* last position and a number that renders as that same position, and `off` would
|
|
167
|
+
* become unreachable — which is exactly how a segment at the end of the bar got
|
|
168
|
+
* stuck.
|
|
169
|
+
*/
|
|
170
|
+
function pillSegmentValues(shown: number, onBar: boolean): string[] {
|
|
171
|
+
const positions = Array.from({ length: onBar ? shown : shown + 1 }, (_, index) =>
|
|
172
|
+
String(index + 1),
|
|
173
|
+
);
|
|
174
|
+
return ["off", ...positions];
|
|
175
|
+
}
|
|
176
176
|
|
|
177
177
|
const directCommandSuggestions = [
|
|
178
178
|
"editor enable",
|
|
@@ -187,21 +187,20 @@ const directCommandSuggestions = [
|
|
|
187
187
|
"mouse enable",
|
|
188
188
|
"mouse disable",
|
|
189
189
|
"mouse toggle",
|
|
190
|
-
"
|
|
191
|
-
"
|
|
192
|
-
"
|
|
190
|
+
"queue",
|
|
191
|
+
"subagents",
|
|
192
|
+
"thinking",
|
|
193
193
|
];
|
|
194
194
|
|
|
195
195
|
const sectionLabels: Record<SettingsSection, string> = {
|
|
196
196
|
coloring: "Coloring",
|
|
197
197
|
features: "Features",
|
|
198
198
|
layout: "Layout",
|
|
199
|
-
|
|
199
|
+
pills: "Pills",
|
|
200
200
|
extensionSegments: "Extension segments",
|
|
201
201
|
};
|
|
202
202
|
|
|
203
203
|
const thirdPartyStatusSettingPrefix = "thirdPartyStatus:";
|
|
204
|
-
const footerSegmentSettingPrefix = "footerSegment:";
|
|
205
204
|
type ThirdPartyStatusSettingKind = "placement" | "colorMode";
|
|
206
205
|
|
|
207
206
|
function isColorSource(value: string): value is ColorSource {
|
|
@@ -216,27 +215,6 @@ function isFeatureSettingId(value: string): value is FeatureSettingId {
|
|
|
216
215
|
return value === "editor" || value === "statusLine" || value === "copyFriendly";
|
|
217
216
|
}
|
|
218
217
|
|
|
219
|
-
function isFooterSegmentSettingId(value: string): value is FooterSegmentSettingId {
|
|
220
|
-
return (
|
|
221
|
-
value === "cwd" ||
|
|
222
|
-
value === "sessionName" ||
|
|
223
|
-
value === "gitBranch" ||
|
|
224
|
-
value === "gitStatus" ||
|
|
225
|
-
value === "gitCounts" ||
|
|
226
|
-
value === "sessionDuration" ||
|
|
227
|
-
value === "runtime" ||
|
|
228
|
-
value === "context" ||
|
|
229
|
-
value === "tokens" ||
|
|
230
|
-
value === "cost" ||
|
|
231
|
-
value === "username" ||
|
|
232
|
-
value === "time" ||
|
|
233
|
-
value === "os" ||
|
|
234
|
-
value === "packageVersion" ||
|
|
235
|
-
value === "gitCommit" ||
|
|
236
|
-
value === "gitMetrics"
|
|
237
|
-
);
|
|
238
|
-
}
|
|
239
|
-
|
|
240
218
|
function isFeatureState(value: string): value is FeatureState {
|
|
241
219
|
return value === "enabled" || value === "disabled";
|
|
242
220
|
}
|
|
@@ -269,7 +247,6 @@ function branchLengthValues(maxLength: GitBranchMaxLength): string[] {
|
|
|
269
247
|
function isLayoutSettingId(value: string): value is LayoutSettingId {
|
|
270
248
|
return (
|
|
271
249
|
value === "contextStyle" ||
|
|
272
|
-
value === "separator" ||
|
|
273
250
|
value === "pathDisplay" ||
|
|
274
251
|
value === "pathDepth" ||
|
|
275
252
|
value === "branchLength" ||
|
|
@@ -295,25 +272,8 @@ function featurePatch(id: FeatureSettingId, value: FeatureState): Partial<UiFeat
|
|
|
295
272
|
return { [id]: value === "enabled" } as Partial<UiFeaturesConfig>;
|
|
296
273
|
}
|
|
297
274
|
|
|
298
|
-
function footerSegmentSettingId(key: FooterSegmentSettingId): string {
|
|
299
|
-
return `${footerSegmentSettingPrefix}${key}`;
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
function footerSegmentSettingFromId(id: string): FooterSegmentSettingId | undefined {
|
|
303
|
-
if (!id.startsWith(footerSegmentSettingPrefix)) return undefined;
|
|
304
|
-
const key = id.slice(footerSegmentSettingPrefix.length);
|
|
305
|
-
return isFooterSegmentSettingId(key) ? key : undefined;
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
function footerSegmentPatch(
|
|
309
|
-
id: FooterSegmentSettingId,
|
|
310
|
-
value: FeatureState,
|
|
311
|
-
): Partial<FooterSegmentsConfig> {
|
|
312
|
-
return { [id]: value === "enabled" } as Partial<FooterSegmentsConfig>;
|
|
313
|
-
}
|
|
314
|
-
|
|
315
275
|
function usageText(): string {
|
|
316
|
-
return
|
|
276
|
+
return "Usage: /starline [editor|statusline|copy-friendly] [enable|disable|toggle], or /starline queue";
|
|
317
277
|
}
|
|
318
278
|
|
|
319
279
|
function featureNotification(
|
|
@@ -382,18 +342,6 @@ function parseMouseCommand(
|
|
|
382
342
|
};
|
|
383
343
|
}
|
|
384
344
|
|
|
385
|
-
function parseFormatCommand(args: string): { value: string | undefined } | undefined {
|
|
386
|
-
const trimmed = args.trim();
|
|
387
|
-
if (!trimmed.toLowerCase().startsWith("format")) return undefined;
|
|
388
|
-
|
|
389
|
-
const rest = trimmed.slice("format".length).trim();
|
|
390
|
-
if (!rest || rest.toLowerCase() === "clear") return { value: undefined };
|
|
391
|
-
|
|
392
|
-
const unquoted =
|
|
393
|
-
rest.startsWith('"') && rest.endsWith('"') && rest.length >= 2 ? rest.slice(1, -1) : rest;
|
|
394
|
-
return { value: unquoted };
|
|
395
|
-
}
|
|
396
|
-
|
|
397
345
|
function argumentCompletions(prefix: string): AutocompleteItem[] | null {
|
|
398
346
|
const trimmedPrefix = prefix.trimStart().toLowerCase();
|
|
399
347
|
const items = directCommandSuggestions.map((value) => ({ value, label: value }));
|
|
@@ -490,13 +438,6 @@ function buildItems(
|
|
|
490
438
|
currentValue: config.contextStyle,
|
|
491
439
|
values: contextStyleValues,
|
|
492
440
|
},
|
|
493
|
-
{
|
|
494
|
-
id: "separator",
|
|
495
|
-
label: "Separator",
|
|
496
|
-
description: "Choose the separator between default footer segments.",
|
|
497
|
-
currentValue: config.separator,
|
|
498
|
-
values: separatorStyleValues,
|
|
499
|
-
},
|
|
500
441
|
{
|
|
501
442
|
id: "pathDisplay",
|
|
502
443
|
label: "Path display",
|
|
@@ -516,8 +457,8 @@ function buildItems(
|
|
|
516
457
|
id: "branchLength",
|
|
517
458
|
label: "Branch length",
|
|
518
459
|
description: "Show the full branch name or truncate it to a preset visible width.",
|
|
519
|
-
currentValue: String(config.
|
|
520
|
-
values: branchLengthValues(config.
|
|
460
|
+
currentValue: String(config.git.branch.maxLength),
|
|
461
|
+
values: branchLengthValues(config.git.branch.maxLength),
|
|
521
462
|
},
|
|
522
463
|
{
|
|
523
464
|
id: "iconMode",
|
|
@@ -529,14 +470,29 @@ function buildItems(
|
|
|
529
470
|
];
|
|
530
471
|
}
|
|
531
472
|
|
|
532
|
-
if (section === "
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
473
|
+
if (section === "pills") {
|
|
474
|
+
const segments = config.pill.segments;
|
|
475
|
+
const row = (name: string, label: string): SettingItem => {
|
|
476
|
+
const position = pillSegmentPosition(segments, name);
|
|
477
|
+
const onBar = position > 0;
|
|
478
|
+
const values = pillSegmentValues(segments.length, onBar);
|
|
479
|
+
return {
|
|
480
|
+
id: pillSegmentSettingId(name),
|
|
481
|
+
label,
|
|
482
|
+
description: `Position in the bar (1 is leftmost). Space cycles off → 1…${values.length - 1}.`,
|
|
483
|
+
currentValue: onBar ? String(position) : "off",
|
|
484
|
+
values,
|
|
485
|
+
};
|
|
486
|
+
};
|
|
487
|
+
const items = PILL_SEGMENT_NAMES.map((name) => row(name, pillSegmentLabel(name)));
|
|
488
|
+
// One row per status an extension published this session, so a single
|
|
489
|
+
// status can be placed on the bar without editing starline.json. Sorted,
|
|
490
|
+
// so the rows do not move under the cursor between changes.
|
|
491
|
+
const statusKeys = [...activeStatuses.keys()].sort();
|
|
492
|
+
for (const key of statusKeys) {
|
|
493
|
+
items.push(row(`${EXTENSION_STATUS_PREFIX}${key}`, key));
|
|
494
|
+
}
|
|
495
|
+
return items;
|
|
540
496
|
}
|
|
541
497
|
|
|
542
498
|
const statuses = Array.from(activeStatuses.entries()).sort(([a], [b]) =>
|
|
@@ -621,25 +577,6 @@ export function registerStarlineSettingsCommand(pi: ExtensionAPI, deps: Settings
|
|
|
621
577
|
handler: async (_args, ctx) => {
|
|
622
578
|
const args = typeof _args === "string" ? _args : "";
|
|
623
579
|
|
|
624
|
-
const formatCommand = parseFormatCommand(args);
|
|
625
|
-
if (formatCommand) {
|
|
626
|
-
try {
|
|
627
|
-
deps.setFooterFormat(formatCommand.value ?? "");
|
|
628
|
-
deps.requestRender();
|
|
629
|
-
if (ctx.hasUI) {
|
|
630
|
-
if (formatCommand.value === undefined) {
|
|
631
|
-
ctx.ui.notify("Footer format cleared (using default layout)", "info");
|
|
632
|
-
} else {
|
|
633
|
-
ctx.ui.notify(`Footer format: ${formatCommand.value}`, "info");
|
|
634
|
-
}
|
|
635
|
-
}
|
|
636
|
-
} catch (error) {
|
|
637
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
638
|
-
if (ctx.hasUI) ctx.ui.notify(`Could not update footer format: ${message}`, "error");
|
|
639
|
-
}
|
|
640
|
-
return;
|
|
641
|
-
}
|
|
642
|
-
|
|
643
580
|
const directCommand = parseDirectFeatureCommand(args, deps.getConfig());
|
|
644
581
|
if (directCommand) {
|
|
645
582
|
try {
|
|
@@ -680,6 +617,16 @@ export function registerStarlineSettingsCommand(pi: ExtensionAPI, deps: Settings
|
|
|
680
617
|
return;
|
|
681
618
|
}
|
|
682
619
|
|
|
620
|
+
// The keyboard half of a clickable pill: same action, same bubble, pointed at
|
|
621
|
+
// the pill the footer last drew. Only segments with an action resolve, so an
|
|
622
|
+
// unknown word still falls through to the usage warning below.
|
|
623
|
+
const actionKey = args.trim().toLowerCase();
|
|
624
|
+
const action = pillActionFor(actionKey);
|
|
625
|
+
if (action) {
|
|
626
|
+
runPillAction(action, ctx, getPillAnchor(actionKey), "command");
|
|
627
|
+
return;
|
|
628
|
+
}
|
|
629
|
+
|
|
683
630
|
if (args.trim()) {
|
|
684
631
|
if (ctx.hasUI) ctx.ui.notify(usageText(), "warning");
|
|
685
632
|
return;
|
|
@@ -747,15 +694,6 @@ export function registerStarlineSettingsCommand(pi: ExtensionAPI, deps: Settings
|
|
|
747
694
|
return;
|
|
748
695
|
}
|
|
749
696
|
|
|
750
|
-
if (id === "separator" && isSeparatorStyle(newValue)) {
|
|
751
|
-
deps.setSeparator(newValue);
|
|
752
|
-
settingsList.updateValue(id, newValue);
|
|
753
|
-
deps.requestRender();
|
|
754
|
-
ctx.ui.notify(`Separator: ${newValue}`, "info");
|
|
755
|
-
tui.requestRender();
|
|
756
|
-
return;
|
|
757
|
-
}
|
|
758
|
-
|
|
759
697
|
if (id === "pathDisplay" && isPathDisplayMode(newValue)) {
|
|
760
698
|
deps.setPathDisplay({ mode: newValue });
|
|
761
699
|
settingsList.updateValue(id, newValue);
|
|
@@ -795,13 +733,22 @@ export function registerStarlineSettingsCommand(pi: ExtensionAPI, deps: Settings
|
|
|
795
733
|
return;
|
|
796
734
|
}
|
|
797
735
|
|
|
798
|
-
const
|
|
799
|
-
if (
|
|
800
|
-
|
|
801
|
-
|
|
736
|
+
const pillSegment = pillSegmentFromId(id);
|
|
737
|
+
if (pillSegment) {
|
|
738
|
+
const segments = movePillSegment(
|
|
739
|
+
deps.getConfig().pill.segments,
|
|
740
|
+
pillSegment,
|
|
741
|
+
newValue,
|
|
742
|
+
);
|
|
743
|
+
deps.setPillSegments(segments);
|
|
744
|
+
// Every row's position can change, so the list is rebuilt
|
|
745
|
+
// rather than patched — then the cursor is put back.
|
|
746
|
+
settingsList = makeSettingsList();
|
|
747
|
+
settingsList.selectItem(id);
|
|
802
748
|
deps.requestRender();
|
|
749
|
+
const label = pillSegmentLabel(pillSegment);
|
|
803
750
|
ctx.ui.notify(
|
|
804
|
-
`${
|
|
751
|
+
newValue === "off" ? `${label}: off` : `${label}: position ${newValue}`,
|
|
805
752
|
"info",
|
|
806
753
|
);
|
|
807
754
|
tui.requestRender();
|