@sayknow-cli/coding-agent 0.3.5 → 0.3.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +76 -0
- package/dist/types/capability/mcp.d.ts +2 -0
- package/dist/types/cli/local-provider-smoke.d.ts +59 -0
- package/dist/types/cli/notify-cli.d.ts +1 -1
- package/dist/types/cli/telegram-cli.d.ts +13 -0
- package/dist/types/cli/update-cli.d.ts +24 -1
- package/dist/types/commands/local-provider.d.ts +34 -0
- package/dist/types/commands/telegram.d.ts +22 -0
- package/dist/types/config/keybindings.d.ts +12 -6
- package/dist/types/config/model-registry.d.ts +5 -0
- package/dist/types/config/models-config-schema.d.ts +5 -0
- package/dist/types/config/settings-schema.d.ts +284 -4
- package/dist/types/config/settings.d.ts +7 -0
- package/dist/types/config/telegram-autostart.d.ts +14 -0
- package/dist/types/config/telegram-env-bridge.d.ts +18 -0
- package/dist/types/coordinator-mcp/server.d.ts +8 -0
- package/dist/types/defaults/skc-defaults.d.ts +7 -0
- package/dist/types/discovery/cursor.d.ts +4 -1
- package/dist/types/discovery/index.d.ts +0 -1
- package/dist/types/discovery/windsurf.d.ts +3 -1
- package/dist/types/extensibility/extensions/types.d.ts +11 -0
- package/dist/types/i18n/messages/en.d.ts +1 -0
- package/dist/types/modes/components/custom-editor.d.ts +6 -1
- package/dist/types/modes/components/custom-model-preset-wizard.d.ts +1 -1
- package/dist/types/modes/components/hook-selector.d.ts +5 -0
- package/dist/types/modes/components/model-selector.d.ts +2 -0
- package/dist/types/modes/components/settings-selector.d.ts +5 -1
- package/dist/types/modes/components/skill-message.d.ts +1 -0
- package/dist/types/modes/components/status-line/types.d.ts +5 -7
- package/dist/types/modes/components/status-line.d.ts +15 -3
- package/dist/types/modes/components/two-column-body.d.ts +9 -0
- package/dist/types/modes/components/welcome.d.ts +9 -1
- package/dist/types/modes/controllers/command-controller.d.ts +1 -0
- package/dist/types/modes/controllers/input-controller.d.ts +6 -1
- package/dist/types/modes/controllers/selector-controller.d.ts +10 -1
- package/dist/types/modes/interactive-mode.d.ts +2 -0
- package/dist/types/modes/prompt-action-autocomplete.d.ts +3 -0
- package/dist/types/modes/rpc/rpc-types.d.ts +1 -0
- package/dist/types/modes/shared/agent-wire/deep-interview-gate.d.ts +41 -7
- package/dist/types/modes/slash-command-visibility.d.ts +1 -0
- package/dist/types/modes/theme/theme.d.ts +1 -1
- package/dist/types/modes/tmux-scroll.d.ts +18 -0
- package/dist/types/modes/types.d.ts +5 -1
- package/dist/types/modes/utils/terminal-bell.d.ts +3 -0
- package/dist/types/notifications/daemon-paths.d.ts +9 -0
- package/dist/types/notifications/html-format.d.ts +2 -0
- package/dist/types/notifications/recent-activity.d.ts +5 -1
- package/dist/types/notifications/telegram-daemon-cli.d.ts +21 -4
- package/dist/types/notifications/telegram-daemon-control.d.ts +8 -0
- package/dist/types/notifications/telegram-daemon.d.ts +4 -10
- package/dist/types/notifications/telegram-reference.d.ts +4 -0
- package/dist/types/notifications/threaded-render.d.ts +1 -0
- package/dist/types/runtime-mcp/config-writer.d.ts +9 -0
- package/dist/types/runtime-mcp/config.d.ts +2 -0
- package/dist/types/runtime-mcp/loader.d.ts +2 -0
- package/dist/types/runtime-mcp/manager.d.ts +2 -0
- package/dist/types/runtime-mcp/types.d.ts +6 -0
- package/dist/types/sdk.d.ts +1 -1
- package/dist/types/skc-runtime/launch-tmux.d.ts +2 -2
- package/dist/types/skc-runtime/ralplan-runtime.d.ts +3 -2
- package/dist/types/skc-runtime/restricted-role-agent-bash.d.ts +1 -0
- package/dist/types/skc-runtime/session-state-sidecar.d.ts +5 -0
- package/dist/types/skc-runtime/state-writer.d.ts +1 -0
- package/dist/types/skc-runtime/team-runtime.d.ts +1 -1
- package/dist/types/skc-runtime/tmux-common.d.ts +12 -0
- package/dist/types/skc-runtime/ultragoal-guard.d.ts +7 -1
- package/dist/types/skc-runtime/ultragoal-runtime.d.ts +0 -4
- package/dist/types/slash-commands/types.d.ts +2 -0
- package/dist/types/system-prompt.d.ts +7 -0
- package/dist/types/tools/skill.d.ts +1 -1
- package/dist/types/utils/cmux-workspace.d.ts +52 -0
- package/dist/types/web/search/index.d.ts +4 -2
- package/dist/types/web/search/provider.d.ts +14 -0
- package/dist/types/web/search/providers/utils.d.ts +42 -13
- package/dist/types/web/search/render.d.ts +1 -0
- package/dist/types/workflow/workflow-intent-diff.d.ts +19 -0
- package/package.json +8 -8
- package/scripts/build-binary.ts +3 -0
- package/scripts/verify-insane-vendor.ts +0 -5
- package/src/capability/mcp.ts +2 -0
- package/src/cli/local-provider-smoke.ts +632 -0
- package/src/cli/notify-cli.ts +4 -2
- package/src/cli/telegram-cli.ts +156 -0
- package/src/cli/update-cli.ts +179 -13
- package/src/cli/web-search-cli.ts +5 -7
- package/src/cli.ts +20 -1
- package/src/commands/launch.ts +47 -2
- package/src/commands/local-provider.ts +62 -0
- package/src/commands/notify.ts +1 -1
- package/src/commands/ralplan.ts +1 -0
- package/src/commands/telegram.ts +47 -0
- package/src/config/keybindings.ts +15 -6
- package/src/config/mcp-schema.json +4 -0
- package/src/config/model-registry.ts +55 -1
- package/src/config/models-config-schema.ts +9 -0
- package/src/config/settings-schema.ts +256 -4
- package/src/config/settings.ts +11 -0
- package/src/config/telegram-autostart.ts +107 -0
- package/src/config/telegram-env-bridge.ts +92 -0
- package/src/coordinator-mcp/server.ts +276 -34
- package/src/defaults/skc/skills/ralplan/SKILL.md +29 -20
- package/src/defaults/skc/skills/ultragoal/SKILL.md +37 -112
- package/src/defaults/skc-defaults.ts +16 -0
- package/src/discovery/builtin.ts +12 -0
- package/src/discovery/cursor.ts +5 -84
- package/src/discovery/gemini.ts +3 -89
- package/src/discovery/index.ts +4 -1
- package/src/discovery/mcp-json.ts +11 -0
- package/src/discovery/opencode.ts +5 -122
- package/src/discovery/windsurf.ts +4 -82
- package/src/edit/read-file.ts +9 -1
- package/src/extensibility/extensions/runner.ts +2 -1
- package/src/extensibility/extensions/types.ts +11 -0
- package/src/extensibility/skills.ts +30 -2
- package/src/hooks/skill-state.ts +33 -73
- package/src/i18n/messages/de.ts +1 -0
- package/src/i18n/messages/en.ts +1 -0
- package/src/i18n/messages/es.ts +1 -0
- package/src/i18n/messages/fr.ts +1 -0
- package/src/i18n/messages/ja.settings.ts +28 -0
- package/src/i18n/messages/ja.ts +1 -0
- package/src/i18n/messages/ko.settings.ts +28 -0
- package/src/i18n/messages/ko.ts +1 -0
- package/src/i18n/messages/zh.settings.ts +28 -0
- package/src/i18n/messages/zh.ts +1 -0
- package/src/internal-urls/docs-index.generated.ts +12 -7
- package/src/main.ts +5 -2
- package/src/migrate/executor.ts +23 -6
- package/src/modes/acp/acp-agent.ts +7 -6
- package/src/modes/components/agent-dashboard.ts +3 -35
- package/src/modes/components/custom-editor.ts +26 -0
- package/src/modes/components/custom-model-preset-wizard.ts +30 -189
- package/src/modes/components/extensions/extension-dashboard.ts +2 -48
- package/src/modes/components/hook-selector.ts +21 -3
- package/src/modes/components/model-selector.ts +246 -11
- package/src/modes/components/session-observer-overlay.ts +3 -3
- package/src/modes/components/session-selector.ts +19 -9
- package/src/modes/components/settings-selector.ts +551 -11
- package/src/modes/components/skill-message.ts +18 -10
- package/src/modes/components/status-line/presets.ts +11 -0
- package/src/modes/components/status-line/segments.ts +16 -19
- package/src/modes/components/status-line/types.ts +6 -2
- package/src/modes/components/status-line.ts +281 -117
- package/src/modes/components/tree-selector.ts +28 -8
- package/src/modes/components/two-column-body.ts +36 -0
- package/src/modes/components/welcome.ts +165 -30
- package/src/modes/controllers/command-controller.ts +26 -2
- package/src/modes/controllers/event-controller.ts +102 -4
- package/src/modes/controllers/extension-ui-controller.ts +21 -2
- package/src/modes/controllers/input-controller.ts +214 -47
- package/src/modes/controllers/selector-controller.ts +35 -33
- package/src/modes/interactive-mode.ts +36 -30
- package/src/modes/prompt-action-autocomplete.ts +48 -8
- package/src/modes/rpc/rpc-types.ts +1 -0
- package/src/modes/shared/agent-wire/deep-interview-gate.ts +72 -15
- package/src/modes/shared/agent-wire/workflow-gate-schema.ts +20 -0
- package/src/modes/slash-command-visibility.ts +9 -0
- package/src/modes/theme/theme.ts +5 -1
- package/src/modes/tmux-scroll.ts +92 -0
- package/src/modes/types.ts +8 -1
- package/src/modes/utils/hotkeys-markdown.ts +5 -2
- package/src/modes/utils/terminal-bell.ts +48 -0
- package/src/modes/utils/ui-helpers.ts +76 -3
- package/src/notifications/daemon-paths.ts +22 -0
- package/src/notifications/html-format.ts +75 -1
- package/src/notifications/index.ts +32 -2
- package/src/notifications/lifecycle-control-runtime.ts +12 -3
- package/src/notifications/recent-activity.ts +32 -8
- package/src/notifications/telegram-daemon-cli.ts +125 -13
- package/src/notifications/telegram-daemon-control.ts +9 -0
- package/src/notifications/telegram-daemon.ts +88 -46
- package/src/notifications/telegram-reference.ts +36 -14
- package/src/notifications/threaded-render.ts +14 -6
- package/src/prompts/agents/architect.md +7 -4
- package/src/prompts/agents/critic.md +15 -6
- package/src/prompts/agents/planner.md +8 -3
- package/src/prompts/system/system-prompt.md +20 -2
- package/src/prompts/tools/bash.md +1 -1
- package/src/runtime-mcp/config-writer.ts +28 -0
- package/src/runtime-mcp/config.ts +7 -0
- package/src/runtime-mcp/loader.ts +3 -0
- package/src/runtime-mcp/manager.ts +3 -0
- package/src/runtime-mcp/types.ts +6 -0
- package/src/sdk.ts +10 -11
- package/src/session/agent-session.ts +103 -13
- package/src/session/session-manager.ts +58 -18
- package/src/skc-runtime/launch-tmux.ts +34 -8
- package/src/skc-runtime/launch-worktree.ts +16 -2
- package/src/skc-runtime/ralplan-runtime.ts +22 -6
- package/src/skc-runtime/restricted-role-agent-bash.ts +1 -0
- package/src/skc-runtime/session-state-sidecar.ts +167 -24
- package/src/skc-runtime/state-runtime.ts +8 -5
- package/src/skc-runtime/state-writer.ts +5 -5
- package/src/skc-runtime/team-runtime.ts +21 -6
- package/src/skc-runtime/tmux-common.ts +16 -0
- package/src/skc-runtime/tmux-sessions.ts +13 -9
- package/src/skc-runtime/ultragoal-guard.ts +150 -24
- package/src/skc-runtime/ultragoal-runtime.ts +16 -124
- package/src/skc-runtime/workflow-manifest.generated.json +0 -8
- package/src/skc-runtime/workflow-manifest.ts +0 -1
- package/src/slash-commands/builtin-registry.ts +136 -23
- package/src/slash-commands/types.ts +2 -0
- package/src/system-prompt.ts +8 -0
- package/src/task/executor.ts +5 -0
- package/src/tools/ast-grep.ts +10 -7
- package/src/tools/bash.ts +39 -14
- package/src/tools/index.ts +8 -1
- package/src/tools/skill.ts +1 -1
- package/src/utils/cmux-workspace.ts +233 -0
- package/src/utils/title-generator.ts +2 -0
- package/src/web/kagi.ts +1 -1
- package/src/web/parallel.ts +2 -2
- package/src/web/search/index.ts +137 -52
- package/src/web/search/provider.ts +80 -0
- package/src/web/search/providers/anthropic.ts +1 -1
- package/src/web/search/providers/brave.ts +1 -1
- package/src/web/search/providers/codex.ts +1 -1
- package/src/web/search/providers/duckduckgo.ts +1 -1
- package/src/web/search/providers/exa.ts +1 -1
- package/src/web/search/providers/gemini.ts +7 -3
- package/src/web/search/providers/jina.ts +1 -1
- package/src/web/search/providers/kimi.ts +6 -1
- package/src/web/search/providers/openai-compatible.ts +1 -1
- package/src/web/search/providers/parallel.ts +1 -1
- package/src/web/search/providers/perplexity.ts +2 -2
- package/src/web/search/providers/searxng.ts +1 -1
- package/src/web/search/providers/synthetic.ts +1 -1
- package/src/web/search/providers/tavily.ts +1 -1
- package/src/web/search/providers/utils.ts +67 -17
- package/src/web/search/providers/xai.ts +1 -1
- package/src/web/search/providers/zai.ts +1 -1
- package/src/web/search/render.ts +3 -0
- package/src/workflow/workflow-intent-diff.ts +199 -0
- package/vendor/insane-search/MANIFEST.json +1 -3
- package/vendor/insane-search/engine/tests/test_u1.py +0 -28
- package/vendor/insane-search/engine/transport.py +2 -3
- package/vendor/insane-search/engine/validators.py +0 -14
- package/src/defaults/skc/rules/ponytail.md +0 -68
|
@@ -28,7 +28,9 @@ import { getTabBarTheme } from "../shared";
|
|
|
28
28
|
import { DynamicBorder } from "./dynamic-border";
|
|
29
29
|
import { handleInputOrEscape, PluginSettingsComponent } from "./plugin-settings";
|
|
30
30
|
import { getSettingsForTab, type SettingDef } from "./settings-defs";
|
|
31
|
+
import type { StatusLineSegmentOptions } from "./status-line";
|
|
31
32
|
import { getPreset } from "./status-line/presets";
|
|
33
|
+
import { ALL_SEGMENT_IDS } from "./status-line/segments";
|
|
32
34
|
|
|
33
35
|
// Settings UI strings are translated by deterministic keys derived from the
|
|
34
36
|
// setting path; English (the schema value) is the fallback. Keys match those
|
|
@@ -49,7 +51,6 @@ function tSettingOptions<T extends { value: string; label?: string; description?
|
|
|
49
51
|
description: o.description ? td(`set:${path}:o:${o.value}:d`, o.description) : o.description,
|
|
50
52
|
}));
|
|
51
53
|
}
|
|
52
|
-
|
|
53
54
|
/**
|
|
54
55
|
* A submenu component for selecting from a list of options.
|
|
55
56
|
*/
|
|
@@ -79,8 +80,6 @@ class TextInputSubmenu extends Container {
|
|
|
79
80
|
this.#input = new Input();
|
|
80
81
|
if (currentValue) {
|
|
81
82
|
this.#input.setValue(currentValue);
|
|
82
|
-
// Move cursor to end of pre-filled value (ctrl+e = cursorLineEnd).
|
|
83
|
-
this.#input.handleInput("\x05");
|
|
84
83
|
}
|
|
85
84
|
this.#input.onSubmit = value => {
|
|
86
85
|
this.onSubmit(value); // empty string clears the setting
|
|
@@ -182,6 +181,471 @@ class SelectSubmenu extends Container {
|
|
|
182
181
|
this.#selectList.handleInput(data);
|
|
183
182
|
}
|
|
184
183
|
}
|
|
184
|
+
const STATUS_LINE_CUSTOM_EDITOR_ID = "statusLine.customEditor";
|
|
185
|
+
const STATUS_LINE_USAGE_MODE_ID = "statusLine.usageMode";
|
|
186
|
+
const PUBLIC_STATUS_SEGMENTS = ALL_SEGMENT_IDS.filter(id => id !== "pi");
|
|
187
|
+
|
|
188
|
+
type StatusLineDraft = Required<
|
|
189
|
+
Pick<StatusLinePreviewSettings, "preset" | "leftSegments" | "rightSegments" | "separator" | "segmentOptions">
|
|
190
|
+
>;
|
|
191
|
+
|
|
192
|
+
const BOOL_VALUES = ["true", "false"];
|
|
193
|
+
const PATH_LENGTH_OPTIONS: SelectItem[] = [16, 24, 32, 40, 50, 60, 80].map(value => ({
|
|
194
|
+
value: String(value),
|
|
195
|
+
label: String(value),
|
|
196
|
+
}));
|
|
197
|
+
const TIME_FORMAT_OPTIONS: SelectItem[] = [
|
|
198
|
+
{ value: "24h", label: "24h" },
|
|
199
|
+
{ value: "12h", label: "12h" },
|
|
200
|
+
];
|
|
201
|
+
const USAGE_MODE_VALUES = ["used", "remaining"] as const;
|
|
202
|
+
type UsageMode = (typeof USAGE_MODE_VALUES)[number];
|
|
203
|
+
|
|
204
|
+
function cloneSegmentOptions(options: StatusLineSegmentOptions | undefined): StatusLineSegmentOptions {
|
|
205
|
+
return mergeSegmentOptions(undefined, options);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function mergeSegmentOptions(
|
|
209
|
+
base: StatusLineSegmentOptions | undefined,
|
|
210
|
+
overrides: StatusLineSegmentOptions | undefined,
|
|
211
|
+
): StatusLineSegmentOptions {
|
|
212
|
+
return {
|
|
213
|
+
model: base?.model || overrides?.model ? { ...(base?.model ?? {}), ...(overrides?.model ?? {}) } : undefined,
|
|
214
|
+
path: base?.path || overrides?.path ? { ...(base?.path ?? {}), ...(overrides?.path ?? {}) } : undefined,
|
|
215
|
+
git: base?.git || overrides?.git ? { ...(base?.git ?? {}), ...(overrides?.git ?? {}) } : undefined,
|
|
216
|
+
time: base?.time || overrides?.time ? { ...(base?.time ?? {}), ...(overrides?.time ?? {}) } : undefined,
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function effectiveSegmentOptions(
|
|
221
|
+
preset: StatusLinePreset,
|
|
222
|
+
options: StatusLineSegmentOptions | undefined,
|
|
223
|
+
): StatusLineSegmentOptions {
|
|
224
|
+
return mergeSegmentOptions(getPreset(preset).segmentOptions, options);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function effectiveCustomSegments(
|
|
228
|
+
preset: StatusLinePreset,
|
|
229
|
+
leftSegments: StatusLineSegmentId[],
|
|
230
|
+
rightSegments: StatusLineSegmentId[],
|
|
231
|
+
): { leftSegments: StatusLineSegmentId[]; rightSegments: StatusLineSegmentId[] } {
|
|
232
|
+
if (preset === "custom") {
|
|
233
|
+
return { leftSegments: [...leftSegments], rightSegments: [...rightSegments] };
|
|
234
|
+
}
|
|
235
|
+
const presetDef = getPreset(preset);
|
|
236
|
+
return {
|
|
237
|
+
leftSegments: [...presetDef.leftSegments],
|
|
238
|
+
rightSegments: [...presetDef.rightSegments],
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function getSavedUsageMode(): UsageMode {
|
|
243
|
+
const segmentOptions = settings.get("statusLine.segmentOptions") as StatusLineSegmentOptions;
|
|
244
|
+
return segmentOptions.usage?.mode === "remaining" ? "remaining" : "used";
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
function setSavedUsageMode(mode: string): StatusLineSegmentOptions {
|
|
248
|
+
const normalizedMode: UsageMode = mode === "remaining" ? "remaining" : "used";
|
|
249
|
+
const segmentOptions = settings.get("statusLine.segmentOptions") as StatusLineSegmentOptions;
|
|
250
|
+
const nextOptions: StatusLineSegmentOptions = {
|
|
251
|
+
...segmentOptions,
|
|
252
|
+
usage: {
|
|
253
|
+
...(segmentOptions.usage ?? {}),
|
|
254
|
+
mode: normalizedMode,
|
|
255
|
+
},
|
|
256
|
+
};
|
|
257
|
+
settings.set("statusLine.segmentOptions", nextOptions as Record<string, unknown>);
|
|
258
|
+
return nextOptions;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function statusSegmentLabel(id: StatusLineSegmentId): string {
|
|
262
|
+
return id.replace(/_/g, " ");
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
function segmentPlacement(
|
|
266
|
+
id: StatusLineSegmentId,
|
|
267
|
+
leftSegments: StatusLineSegmentId[],
|
|
268
|
+
rightSegments: StatusLineSegmentId[],
|
|
269
|
+
): "hidden" | "left" | "right" {
|
|
270
|
+
if (leftSegments.includes(id)) return "left";
|
|
271
|
+
if (rightSegments.includes(id)) return "right";
|
|
272
|
+
return "hidden";
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
class StatusLineCustomEditor extends Container {
|
|
276
|
+
#list!: SettingsList;
|
|
277
|
+
#draft: StatusLineDraft;
|
|
278
|
+
#currentWidthPreviewText!: Text;
|
|
279
|
+
#narrowWidthPreviewText!: Text;
|
|
280
|
+
#previewHighlightSegment: StatusLineSegmentId | undefined;
|
|
281
|
+
|
|
282
|
+
constructor(
|
|
283
|
+
private readonly callbacks: SettingsCallbacks,
|
|
284
|
+
private readonly done: (value?: string) => void,
|
|
285
|
+
) {
|
|
286
|
+
super();
|
|
287
|
+
const preset = settings.get("statusLine.preset");
|
|
288
|
+
const seeded = effectiveCustomSegments(
|
|
289
|
+
preset,
|
|
290
|
+
settings.get("statusLine.leftSegments"),
|
|
291
|
+
settings.get("statusLine.rightSegments"),
|
|
292
|
+
);
|
|
293
|
+
this.#draft = {
|
|
294
|
+
preset: "custom",
|
|
295
|
+
leftSegments: seeded.leftSegments,
|
|
296
|
+
rightSegments: seeded.rightSegments,
|
|
297
|
+
separator: settings.get("statusLine.separator"),
|
|
298
|
+
segmentOptions: effectiveSegmentOptions(
|
|
299
|
+
preset,
|
|
300
|
+
settings.get("statusLine.segmentOptions") as StatusLineSegmentOptions,
|
|
301
|
+
),
|
|
302
|
+
};
|
|
303
|
+
this.#preview();
|
|
304
|
+
this.#build();
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
#build(): void {
|
|
308
|
+
this.clear();
|
|
309
|
+
this.addChild(new Text(theme.bold(theme.fg("accent", "Status Line Custom Editor")), 0, 0));
|
|
310
|
+
this.addChild(new Spacer(1));
|
|
311
|
+
this.addChild(new Text(theme.fg("muted", "Current width preview:"), 0, 0));
|
|
312
|
+
this.#currentWidthPreviewText = new Text(this.#statusLinePreview(), 0, 0);
|
|
313
|
+
this.addChild(this.#currentWidthPreviewText);
|
|
314
|
+
this.addChild(new Text(theme.fg("muted", "Narrow width preview:"), 0, 0));
|
|
315
|
+
this.#narrowWidthPreviewText = new Text(this.#statusLinePreview(40), 0, 0);
|
|
316
|
+
this.addChild(this.#narrowWidthPreviewText);
|
|
317
|
+
this.addChild(new Spacer(1));
|
|
318
|
+
this.#list = new SettingsList(
|
|
319
|
+
this.#items(),
|
|
320
|
+
14,
|
|
321
|
+
getSettingsListTheme(),
|
|
322
|
+
(id, value) => this.#handleChange(id, value),
|
|
323
|
+
() => this.#cancel(),
|
|
324
|
+
item => this.#setSelectedItem(item),
|
|
325
|
+
);
|
|
326
|
+
this.addChild(this.#list);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
#refresh(): void {
|
|
330
|
+
this.#refreshPreview();
|
|
331
|
+
this.#list.setItems(this.#items());
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
#refreshPreview(): void {
|
|
335
|
+
this.#currentWidthPreviewText.setText(this.#statusLinePreview());
|
|
336
|
+
this.#narrowWidthPreviewText.setText(this.#statusLinePreview(40));
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
#statusLinePreview(width?: number): string {
|
|
340
|
+
return this.callbacks.getStatusLinePreview?.(width) ?? theme.fg("dim", "(preview not available)");
|
|
341
|
+
}
|
|
342
|
+
#setSelectedItem(item: SettingItem | undefined): void {
|
|
343
|
+
this.#previewHighlightSegment = this.#highlightSegmentForItem(item);
|
|
344
|
+
this.#preview();
|
|
345
|
+
this.#refreshPreview();
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
#highlightSegmentForItem(item: SettingItem | undefined): StatusLineSegmentId | undefined {
|
|
349
|
+
if (!item) return undefined;
|
|
350
|
+
if (item.id.startsWith("segment.")) {
|
|
351
|
+
return item.id.slice("segment.".length) as StatusLineSegmentId;
|
|
352
|
+
}
|
|
353
|
+
if (item.id.startsWith("moveup.")) {
|
|
354
|
+
return item.id.slice("moveup.".length) as StatusLineSegmentId;
|
|
355
|
+
}
|
|
356
|
+
if (item.id.startsWith("movedown.")) {
|
|
357
|
+
return item.id.slice("movedown.".length) as StatusLineSegmentId;
|
|
358
|
+
}
|
|
359
|
+
if (item.id.startsWith("option.")) {
|
|
360
|
+
const [segment] = item.id.slice("option.".length).split(".");
|
|
361
|
+
return segment as StatusLineSegmentId;
|
|
362
|
+
}
|
|
363
|
+
return undefined;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
#items(): SettingItem[] {
|
|
367
|
+
const items: SettingItem[] = [
|
|
368
|
+
{
|
|
369
|
+
id: "action.save",
|
|
370
|
+
label: "Save custom status line",
|
|
371
|
+
description: "Persist the previewed custom status line to user config.",
|
|
372
|
+
currentValue: "approve",
|
|
373
|
+
values: ["approve"],
|
|
374
|
+
},
|
|
375
|
+
{
|
|
376
|
+
id: "action.cancel",
|
|
377
|
+
label: "Cancel and restore",
|
|
378
|
+
description: "Close without persisting draft settings and restore the previous preview.",
|
|
379
|
+
currentValue: "restore",
|
|
380
|
+
values: ["restore"],
|
|
381
|
+
},
|
|
382
|
+
{
|
|
383
|
+
id: "separator",
|
|
384
|
+
label: "Separator",
|
|
385
|
+
description: "Separator style between status line segments.",
|
|
386
|
+
currentValue: this.#draft.separator,
|
|
387
|
+
submenu: (currentValue, done) =>
|
|
388
|
+
new SelectSubmenu(
|
|
389
|
+
"Status Line Separator",
|
|
390
|
+
"Style of separators between segments.",
|
|
391
|
+
[
|
|
392
|
+
{ value: "powerline", label: "Powerline" },
|
|
393
|
+
{ value: "powerline-thin", label: "Thin chevron" },
|
|
394
|
+
{ value: "slash", label: "Slash" },
|
|
395
|
+
{ value: "pipe", label: "Pipe" },
|
|
396
|
+
{ value: "block", label: "Block" },
|
|
397
|
+
{ value: "none", label: "None" },
|
|
398
|
+
{ value: "ascii", label: "ASCII" },
|
|
399
|
+
],
|
|
400
|
+
currentValue,
|
|
401
|
+
done,
|
|
402
|
+
() => done(),
|
|
403
|
+
),
|
|
404
|
+
},
|
|
405
|
+
];
|
|
406
|
+
|
|
407
|
+
for (const id of PUBLIC_STATUS_SEGMENTS) {
|
|
408
|
+
items.push({
|
|
409
|
+
id: `segment.${id}`,
|
|
410
|
+
label: `Segment: ${statusSegmentLabel(id)}`,
|
|
411
|
+
description: "Cycle placement: hidden → left → right. Use move actions below to reorder visible segments.",
|
|
412
|
+
currentValue: segmentPlacement(id, this.#draft.leftSegments, this.#draft.rightSegments),
|
|
413
|
+
values: ["hidden", "left", "right"],
|
|
414
|
+
});
|
|
415
|
+
if (segmentPlacement(id, this.#draft.leftSegments, this.#draft.rightSegments) !== "hidden") {
|
|
416
|
+
items.push(
|
|
417
|
+
{
|
|
418
|
+
id: `moveup.${id}`,
|
|
419
|
+
label: `Move left: ${statusSegmentLabel(id)}`,
|
|
420
|
+
currentValue: "←",
|
|
421
|
+
values: ["←"],
|
|
422
|
+
},
|
|
423
|
+
{
|
|
424
|
+
id: `movedown.${id}`,
|
|
425
|
+
label: `Move right: ${statusSegmentLabel(id)}`,
|
|
426
|
+
currentValue: "→",
|
|
427
|
+
values: ["→"],
|
|
428
|
+
},
|
|
429
|
+
);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
items.push(
|
|
434
|
+
{
|
|
435
|
+
id: "option.model.showThinkingLevel",
|
|
436
|
+
label: "Model: show thinking level",
|
|
437
|
+
currentValue: String(this.#draft.segmentOptions.model?.showThinkingLevel !== false),
|
|
438
|
+
values: BOOL_VALUES,
|
|
439
|
+
},
|
|
440
|
+
{
|
|
441
|
+
id: "option.path.abbreviate",
|
|
442
|
+
label: "Path: abbreviate",
|
|
443
|
+
currentValue: String(this.#draft.segmentOptions.path?.abbreviate !== false),
|
|
444
|
+
values: BOOL_VALUES,
|
|
445
|
+
},
|
|
446
|
+
{
|
|
447
|
+
id: "option.path.maxLength",
|
|
448
|
+
label: "Path: max length",
|
|
449
|
+
currentValue: String(this.#draft.segmentOptions.path?.maxLength ?? 32),
|
|
450
|
+
submenu: (currentValue, done) =>
|
|
451
|
+
new SelectSubmenu(
|
|
452
|
+
"Path max length",
|
|
453
|
+
"Maximum displayed path length.",
|
|
454
|
+
PATH_LENGTH_OPTIONS,
|
|
455
|
+
currentValue,
|
|
456
|
+
done,
|
|
457
|
+
() => done(),
|
|
458
|
+
),
|
|
459
|
+
},
|
|
460
|
+
{
|
|
461
|
+
id: "option.path.stripWorkPrefix",
|
|
462
|
+
label: "Path: strip work prefix",
|
|
463
|
+
currentValue: String(this.#draft.segmentOptions.path?.stripWorkPrefix === true),
|
|
464
|
+
values: BOOL_VALUES,
|
|
465
|
+
},
|
|
466
|
+
{
|
|
467
|
+
id: "option.git.showBranch",
|
|
468
|
+
label: "Git: show branch",
|
|
469
|
+
currentValue: String(this.#draft.segmentOptions.git?.showBranch !== false),
|
|
470
|
+
values: BOOL_VALUES,
|
|
471
|
+
},
|
|
472
|
+
{
|
|
473
|
+
id: "option.git.showStaged",
|
|
474
|
+
label: "Git: show staged",
|
|
475
|
+
currentValue: String(this.#draft.segmentOptions.git?.showStaged !== false),
|
|
476
|
+
values: BOOL_VALUES,
|
|
477
|
+
},
|
|
478
|
+
{
|
|
479
|
+
id: "option.git.showUnstaged",
|
|
480
|
+
label: "Git: show unstaged",
|
|
481
|
+
currentValue: String(this.#draft.segmentOptions.git?.showUnstaged !== false),
|
|
482
|
+
values: BOOL_VALUES,
|
|
483
|
+
},
|
|
484
|
+
{
|
|
485
|
+
id: "option.git.showUntracked",
|
|
486
|
+
label: "Git: show untracked",
|
|
487
|
+
currentValue: String(this.#draft.segmentOptions.git?.showUntracked !== false),
|
|
488
|
+
values: BOOL_VALUES,
|
|
489
|
+
},
|
|
490
|
+
{
|
|
491
|
+
id: "option.time.format",
|
|
492
|
+
label: "Time: format",
|
|
493
|
+
currentValue: this.#draft.segmentOptions.time?.format ?? "24h",
|
|
494
|
+
submenu: (currentValue, done) =>
|
|
495
|
+
new SelectSubmenu(
|
|
496
|
+
"Time format",
|
|
497
|
+
"Clock format for the time segment.",
|
|
498
|
+
TIME_FORMAT_OPTIONS,
|
|
499
|
+
currentValue,
|
|
500
|
+
done,
|
|
501
|
+
() => done(),
|
|
502
|
+
),
|
|
503
|
+
},
|
|
504
|
+
{
|
|
505
|
+
id: "option.time.showSeconds",
|
|
506
|
+
label: "Time: show seconds",
|
|
507
|
+
currentValue: String(this.#draft.segmentOptions.time?.showSeconds === true),
|
|
508
|
+
values: BOOL_VALUES,
|
|
509
|
+
},
|
|
510
|
+
);
|
|
511
|
+
|
|
512
|
+
return items;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
#handleChange(id: string, value: string): void {
|
|
516
|
+
if (id === "action.save") {
|
|
517
|
+
this.#save();
|
|
518
|
+
return;
|
|
519
|
+
}
|
|
520
|
+
if (id === "action.cancel") {
|
|
521
|
+
this.#cancel();
|
|
522
|
+
return;
|
|
523
|
+
}
|
|
524
|
+
if (id === "separator") {
|
|
525
|
+
this.#draft.separator = value as StatusLineSeparatorStyle;
|
|
526
|
+
} else if (id.startsWith("segment.")) {
|
|
527
|
+
this.#setSegmentPlacement(
|
|
528
|
+
id.slice("segment.".length) as StatusLineSegmentId,
|
|
529
|
+
value as "hidden" | "left" | "right",
|
|
530
|
+
);
|
|
531
|
+
} else if (id.startsWith("moveup.")) {
|
|
532
|
+
this.#moveSegment(id.slice("moveup.".length) as StatusLineSegmentId, -1);
|
|
533
|
+
} else if (id.startsWith("movedown.")) {
|
|
534
|
+
this.#moveSegment(id.slice("movedown.".length) as StatusLineSegmentId, 1);
|
|
535
|
+
} else if (id.startsWith("option.")) {
|
|
536
|
+
this.#setOption(id.slice("option.".length), value);
|
|
537
|
+
}
|
|
538
|
+
this.#preview();
|
|
539
|
+
this.#refresh();
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
#setSegmentPlacement(id: StatusLineSegmentId, placement: "hidden" | "left" | "right"): void {
|
|
543
|
+
this.#draft.leftSegments = this.#draft.leftSegments.filter(segment => segment !== id);
|
|
544
|
+
this.#draft.rightSegments = this.#draft.rightSegments.filter(segment => segment !== id);
|
|
545
|
+
if (placement === "left") this.#draft.leftSegments.push(id);
|
|
546
|
+
if (placement === "right") this.#draft.rightSegments.push(id);
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
#moveSegment(id: StatusLineSegmentId, delta: -1 | 1): void {
|
|
550
|
+
const group = this.#draft.leftSegments.includes(id) ? this.#draft.leftSegments : this.#draft.rightSegments;
|
|
551
|
+
const index = group.indexOf(id);
|
|
552
|
+
if (index < 0) return;
|
|
553
|
+
const nextIndex = Math.max(0, Math.min(group.length - 1, index + delta));
|
|
554
|
+
if (nextIndex === index) return;
|
|
555
|
+
const [segment] = group.splice(index, 1);
|
|
556
|
+
if (segment) group.splice(nextIndex, 0, segment);
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
#setOption(path: string, value: string): void {
|
|
560
|
+
const bool = value === "true";
|
|
561
|
+
switch (path) {
|
|
562
|
+
case "model.showThinkingLevel":
|
|
563
|
+
this.#draft.segmentOptions.model = { ...(this.#draft.segmentOptions.model ?? {}), showThinkingLevel: bool };
|
|
564
|
+
break;
|
|
565
|
+
case "path.abbreviate":
|
|
566
|
+
this.#draft.segmentOptions.path = { ...(this.#draft.segmentOptions.path ?? {}), abbreviate: bool };
|
|
567
|
+
break;
|
|
568
|
+
case "path.maxLength":
|
|
569
|
+
this.#draft.segmentOptions.path = { ...(this.#draft.segmentOptions.path ?? {}), maxLength: Number(value) };
|
|
570
|
+
break;
|
|
571
|
+
case "path.stripWorkPrefix":
|
|
572
|
+
this.#draft.segmentOptions.path = { ...(this.#draft.segmentOptions.path ?? {}), stripWorkPrefix: bool };
|
|
573
|
+
break;
|
|
574
|
+
case "git.showBranch":
|
|
575
|
+
this.#draft.segmentOptions.git = { ...(this.#draft.segmentOptions.git ?? {}), showBranch: bool };
|
|
576
|
+
break;
|
|
577
|
+
case "git.showStaged":
|
|
578
|
+
this.#draft.segmentOptions.git = { ...(this.#draft.segmentOptions.git ?? {}), showStaged: bool };
|
|
579
|
+
break;
|
|
580
|
+
case "git.showUnstaged":
|
|
581
|
+
this.#draft.segmentOptions.git = { ...(this.#draft.segmentOptions.git ?? {}), showUnstaged: bool };
|
|
582
|
+
break;
|
|
583
|
+
case "git.showUntracked":
|
|
584
|
+
this.#draft.segmentOptions.git = { ...(this.#draft.segmentOptions.git ?? {}), showUntracked: bool };
|
|
585
|
+
break;
|
|
586
|
+
case "time.format":
|
|
587
|
+
this.#draft.segmentOptions.time = {
|
|
588
|
+
...(this.#draft.segmentOptions.time ?? {}),
|
|
589
|
+
format: value as "12h" | "24h",
|
|
590
|
+
};
|
|
591
|
+
break;
|
|
592
|
+
case "time.showSeconds":
|
|
593
|
+
this.#draft.segmentOptions.time = { ...(this.#draft.segmentOptions.time ?? {}), showSeconds: bool };
|
|
594
|
+
break;
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
#preview(): void {
|
|
599
|
+
this.callbacks.onStatusLinePreview?.({
|
|
600
|
+
preset: "custom",
|
|
601
|
+
leftSegments: [...this.#draft.leftSegments],
|
|
602
|
+
rightSegments: [...this.#draft.rightSegments],
|
|
603
|
+
separator: this.#draft.separator,
|
|
604
|
+
segmentOptions: cloneSegmentOptions(this.#draft.segmentOptions),
|
|
605
|
+
previewHighlightSegment: this.#previewHighlightSegment,
|
|
606
|
+
});
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
#restorePreview(): void {
|
|
610
|
+
this.callbacks.onStatusLinePreview?.({
|
|
611
|
+
preset: settings.get("statusLine.preset"),
|
|
612
|
+
leftSegments: settings.get("statusLine.leftSegments"),
|
|
613
|
+
rightSegments: settings.get("statusLine.rightSegments"),
|
|
614
|
+
separator: settings.get("statusLine.separator"),
|
|
615
|
+
segmentOptions: cloneSegmentOptions(settings.get("statusLine.segmentOptions") as StatusLineSegmentOptions),
|
|
616
|
+
sessionAccent: settings.get("statusLine.sessionAccent"),
|
|
617
|
+
previewHighlightSegment: undefined,
|
|
618
|
+
});
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
#save(): void {
|
|
622
|
+
settings.set("statusLine.preset", "custom");
|
|
623
|
+
settings.set("statusLine.leftSegments", [...this.#draft.leftSegments]);
|
|
624
|
+
settings.set("statusLine.rightSegments", [...this.#draft.rightSegments]);
|
|
625
|
+
settings.set("statusLine.separator", this.#draft.separator);
|
|
626
|
+
settings.set(
|
|
627
|
+
"statusLine.segmentOptions",
|
|
628
|
+
cloneSegmentOptions(this.#draft.segmentOptions) as Record<string, unknown>,
|
|
629
|
+
);
|
|
630
|
+
this.callbacks.onChange("statusLine.preset", "custom");
|
|
631
|
+
this.callbacks.onChange("statusLine.leftSegments", [...this.#draft.leftSegments]);
|
|
632
|
+
this.callbacks.onChange("statusLine.rightSegments", [...this.#draft.rightSegments]);
|
|
633
|
+
this.callbacks.onChange("statusLine.separator", this.#draft.separator);
|
|
634
|
+
this.callbacks.onChange("statusLine.segmentOptions", cloneSegmentOptions(this.#draft.segmentOptions));
|
|
635
|
+
this.#previewHighlightSegment = undefined;
|
|
636
|
+
this.#preview();
|
|
637
|
+
this.done("saved");
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
#cancel(): void {
|
|
641
|
+
this.#restorePreview();
|
|
642
|
+
this.done();
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
handleInput(data: string): void {
|
|
646
|
+
this.#list.handleInput(data);
|
|
647
|
+
}
|
|
648
|
+
}
|
|
185
649
|
|
|
186
650
|
function getSettingsTabs(): Tab[] {
|
|
187
651
|
return [
|
|
@@ -215,7 +679,10 @@ export interface StatusLinePreviewSettings {
|
|
|
215
679
|
leftSegments?: StatusLineSegmentId[];
|
|
216
680
|
rightSegments?: StatusLineSegmentId[];
|
|
217
681
|
separator?: StatusLineSeparatorStyle;
|
|
682
|
+
segmentOptions?: StatusLineSegmentOptions;
|
|
683
|
+
previewHighlightSegment?: StatusLineSegmentId;
|
|
218
684
|
sessionAccent?: boolean;
|
|
685
|
+
maxRows?: number;
|
|
219
686
|
}
|
|
220
687
|
|
|
221
688
|
export interface SettingsCallbacks {
|
|
@@ -228,7 +695,7 @@ export interface SettingsCallbacks {
|
|
|
228
695
|
/** Called for status line preview while configuring */
|
|
229
696
|
onStatusLinePreview?: (settings: StatusLinePreviewSettings) => void;
|
|
230
697
|
/** Get current rendered status line for inline preview */
|
|
231
|
-
getStatusLinePreview?: () => string;
|
|
698
|
+
getStatusLinePreview?: (width?: number) => string;
|
|
232
699
|
/** Called when plugins change */
|
|
233
700
|
onPluginsChanged?: () => void;
|
|
234
701
|
/** Called when settings panel is closed */
|
|
@@ -395,7 +862,9 @@ export class SettingsSelectorComponent extends Container {
|
|
|
395
862
|
} else if (def.path === "theme.dark" || def.path === "theme.light") {
|
|
396
863
|
options = this.context.availableThemes.map(t => ({ value: t, label: t }));
|
|
397
864
|
}
|
|
398
|
-
|
|
865
|
+
if (def.path === "statusLine.preset") {
|
|
866
|
+
options = options.filter(option => option.value !== "custom");
|
|
867
|
+
}
|
|
399
868
|
// Preview handlers
|
|
400
869
|
let onPreview: ((value: string) => void | Promise<void>) | undefined;
|
|
401
870
|
let onPreviewCancel: (() => void) | undefined;
|
|
@@ -410,25 +879,37 @@ export class SettingsSelectorComponent extends Container {
|
|
|
410
879
|
};
|
|
411
880
|
} else if (def.path === "statusLine.preset") {
|
|
412
881
|
onPreview = value => {
|
|
413
|
-
const presetDef = getPreset(
|
|
414
|
-
value as "default" | "minimal" | "compact" | "full" | "nerd" | "ascii" | "custom",
|
|
415
|
-
);
|
|
882
|
+
const presetDef = getPreset(value as StatusLinePreset);
|
|
416
883
|
this.callbacks.onStatusLinePreview?.({
|
|
417
884
|
preset: value as StatusLinePreset,
|
|
418
885
|
leftSegments: presetDef.leftSegments,
|
|
419
886
|
rightSegments: presetDef.rightSegments,
|
|
420
887
|
separator: presetDef.separator,
|
|
888
|
+
previewHighlightSegment: undefined,
|
|
421
889
|
});
|
|
422
890
|
this.#updateStatusPreview();
|
|
423
891
|
};
|
|
424
892
|
onPreviewCancel = () => {
|
|
425
893
|
const currentPreset = settings.get("statusLine.preset");
|
|
426
894
|
const presetDef = getPreset(currentPreset);
|
|
895
|
+
const savedCustomSettings =
|
|
896
|
+
currentPreset === "custom"
|
|
897
|
+
? {
|
|
898
|
+
leftSegments: settings.get("statusLine.leftSegments"),
|
|
899
|
+
rightSegments: settings.get("statusLine.rightSegments"),
|
|
900
|
+
separator: settings.get("statusLine.separator"),
|
|
901
|
+
segmentOptions: cloneSegmentOptions(
|
|
902
|
+
settings.get("statusLine.segmentOptions") as StatusLineSegmentOptions,
|
|
903
|
+
),
|
|
904
|
+
}
|
|
905
|
+
: {};
|
|
427
906
|
this.callbacks.onStatusLinePreview?.({
|
|
428
907
|
preset: currentPreset,
|
|
429
908
|
leftSegments: presetDef.leftSegments,
|
|
430
909
|
rightSegments: presetDef.rightSegments,
|
|
431
910
|
separator: presetDef.separator,
|
|
911
|
+
...savedCustomSettings,
|
|
912
|
+
previewHighlightSegment: undefined,
|
|
432
913
|
});
|
|
433
914
|
this.#updateStatusPreview();
|
|
434
915
|
};
|
|
@@ -439,7 +920,19 @@ export class SettingsSelectorComponent extends Container {
|
|
|
439
920
|
};
|
|
440
921
|
onPreviewCancel = () => {
|
|
441
922
|
const separator = settings.get("statusLine.separator");
|
|
442
|
-
this.callbacks.onStatusLinePreview?.({ separator });
|
|
923
|
+
this.callbacks.onStatusLinePreview?.({ separator, previewHighlightSegment: undefined });
|
|
924
|
+
this.#updateStatusPreview();
|
|
925
|
+
};
|
|
926
|
+
} else if (def.path === "statusLine.maxRows") {
|
|
927
|
+
onPreview = value => {
|
|
928
|
+
this.callbacks.onStatusLinePreview?.({ maxRows: Number(value) });
|
|
929
|
+
this.#updateStatusPreview();
|
|
930
|
+
};
|
|
931
|
+
onPreviewCancel = () => {
|
|
932
|
+
this.callbacks.onStatusLinePreview?.({
|
|
933
|
+
maxRows: settings.get("statusLine.maxRows"),
|
|
934
|
+
previewHighlightSegment: undefined,
|
|
935
|
+
});
|
|
443
936
|
this.#updateStatusPreview();
|
|
444
937
|
};
|
|
445
938
|
}
|
|
@@ -532,10 +1025,20 @@ export class SettingsSelectorComponent extends Container {
|
|
|
532
1025
|
}
|
|
533
1026
|
|
|
534
1027
|
this.#currentList = new SettingsList(
|
|
535
|
-
this.#
|
|
1028
|
+
this.#buildItemsForTab(defs, tabId),
|
|
536
1029
|
10,
|
|
537
1030
|
getSettingsListTheme(),
|
|
538
1031
|
(id, newValue) => {
|
|
1032
|
+
if (id === STATUS_LINE_USAGE_MODE_ID) {
|
|
1033
|
+
const segmentOptions = setSavedUsageMode(newValue);
|
|
1034
|
+
this.callbacks.onChange("statusLine.segmentOptions", segmentOptions);
|
|
1035
|
+
if (tabId === "appearance") {
|
|
1036
|
+
this.#triggerStatusLinePreview();
|
|
1037
|
+
}
|
|
1038
|
+
this.#refreshCurrentTabItems(defs);
|
|
1039
|
+
return;
|
|
1040
|
+
}
|
|
1041
|
+
|
|
539
1042
|
const def = defs.find(d => d.path === id);
|
|
540
1043
|
if (!def) return;
|
|
541
1044
|
|
|
@@ -576,10 +1079,45 @@ export class SettingsSelectorComponent extends Container {
|
|
|
576
1079
|
return items;
|
|
577
1080
|
}
|
|
578
1081
|
|
|
1082
|
+
#buildItemsForTab(defs: SettingDef[], tabId: SettingTab): SettingItem[] {
|
|
1083
|
+
const items = this.#buildItemsForDefs(defs);
|
|
1084
|
+
if (tabId === "appearance") {
|
|
1085
|
+
const customEditorItem: SettingItem = {
|
|
1086
|
+
id: STATUS_LINE_CUSTOM_EDITOR_ID,
|
|
1087
|
+
label: "Status Line Custom Editor",
|
|
1088
|
+
description:
|
|
1089
|
+
"Edit custom status line segments, placement, separator, and typed segment options with live previews.",
|
|
1090
|
+
currentValue: "open",
|
|
1091
|
+
submenu: (_currentValue, done) => new StatusLineCustomEditor(this.callbacks, done),
|
|
1092
|
+
};
|
|
1093
|
+
const presetIndex = items.findIndex(item => item.id === "statusLine.preset");
|
|
1094
|
+
if (presetIndex >= 0) {
|
|
1095
|
+
items.splice(presetIndex + 1, 0, customEditorItem);
|
|
1096
|
+
} else {
|
|
1097
|
+
items.push(customEditorItem);
|
|
1098
|
+
}
|
|
1099
|
+
{
|
|
1100
|
+
const usageModeItem: SettingItem = {
|
|
1101
|
+
id: STATUS_LINE_USAGE_MODE_ID,
|
|
1102
|
+
label: "Status Line Usage Mode",
|
|
1103
|
+
description: "Show provider quota in the status line as used or remaining.",
|
|
1104
|
+
currentValue: getSavedUsageMode(),
|
|
1105
|
+
values: [...USAGE_MODE_VALUES],
|
|
1106
|
+
};
|
|
1107
|
+
if (presetIndex >= 0) {
|
|
1108
|
+
items.splice(presetIndex + 2, 0, usageModeItem);
|
|
1109
|
+
} else {
|
|
1110
|
+
items.push(usageModeItem);
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
}
|
|
1114
|
+
return items;
|
|
1115
|
+
}
|
|
1116
|
+
|
|
579
1117
|
/** Re-evaluate condition gates against the current settings and refresh the active list. */
|
|
580
1118
|
#refreshCurrentTabItems(defs: SettingDef[]): void {
|
|
581
1119
|
if (this.#currentTabId === "plugins" || !this.#currentList) return;
|
|
582
|
-
this.#currentList.setItems(this.#
|
|
1120
|
+
this.#currentList.setItems(this.#buildItemsForTab(defs, this.#currentTabId));
|
|
583
1121
|
}
|
|
584
1122
|
|
|
585
1123
|
/**
|
|
@@ -601,7 +1139,9 @@ export class SettingsSelectorComponent extends Container {
|
|
|
601
1139
|
leftSegments: settings.get("statusLine.leftSegments"),
|
|
602
1140
|
rightSegments: settings.get("statusLine.rightSegments"),
|
|
603
1141
|
separator: settings.get("statusLine.separator"),
|
|
1142
|
+
segmentOptions: cloneSegmentOptions(settings.get("statusLine.segmentOptions") as StatusLineSegmentOptions),
|
|
604
1143
|
sessionAccent: settings.get("statusLine.sessionAccent"),
|
|
1144
|
+
previewHighlightSegment: undefined,
|
|
605
1145
|
};
|
|
606
1146
|
this.callbacks.onStatusLinePreview?.(statusLineSettings);
|
|
607
1147
|
this.#updateStatusPreview();
|