@agi-fans/dsh-tui 0.20.0 → 0.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/CHANGELOG.md +249 -3
- package/lib/chrome/box.d.ts +47 -16
- package/lib/chrome/box.js +172 -130
- package/lib/chrome/box.js.map +1 -1
- package/lib/chrome/code-highlight.d.ts +15 -0
- package/lib/chrome/code-highlight.js +60 -4
- package/lib/chrome/code-highlight.js.map +1 -1
- package/lib/chrome/command-output.d.ts +29 -2
- package/lib/chrome/command-output.js +100 -4
- package/lib/chrome/command-output.js.map +1 -1
- package/lib/chrome/main-screen-renderer.d.ts +18 -0
- package/lib/chrome/main-screen-renderer.js +58 -5
- package/lib/chrome/main-screen-renderer.js.map +1 -1
- package/lib/chrome/markdown.js +30 -10
- package/lib/chrome/markdown.js.map +1 -1
- package/lib/chrome/relative-time.d.ts +17 -0
- package/lib/chrome/relative-time.js +36 -0
- package/lib/chrome/relative-time.js.map +1 -1
- package/lib/chrome/renderer.d.ts +9 -0
- package/lib/chrome/renderer.js +1 -1
- package/lib/chrome/renderer.js.map +1 -1
- package/lib/chrome/secret-mask.d.ts +35 -0
- package/lib/chrome/secret-mask.js +180 -0
- package/lib/chrome/secret-mask.js.map +1 -0
- package/lib/chrome/status-config.d.ts +161 -51
- package/lib/chrome/status-config.js +237 -126
- package/lib/chrome/status-config.js.map +1 -1
- package/lib/chrome/status-line.d.ts +3 -2
- package/lib/chrome/status-line.js +105 -63
- package/lib/chrome/status-line.js.map +1 -1
- package/lib/chrome/terminal-colors.d.ts +85 -0
- package/lib/chrome/terminal-colors.js +230 -0
- package/lib/chrome/terminal-colors.js.map +1 -0
- package/lib/chrome/terminal-images.d.ts +9 -1
- package/lib/chrome/terminal-images.js +27 -4
- package/lib/chrome/terminal-images.js.map +1 -1
- package/lib/chrome/theme.d.ts +32 -9
- package/lib/chrome/theme.js +616 -520
- package/lib/chrome/theme.js.map +1 -1
- package/lib/chrome/tool-args.d.ts +1 -1
- package/lib/chrome/tool-args.js +3 -1
- package/lib/chrome/tool-args.js.map +1 -1
- package/lib/chrome/tool-renderers.d.ts +2 -0
- package/lib/chrome/tool-renderers.js +69 -3
- package/lib/chrome/tool-renderers.js.map +1 -1
- package/lib/chrome/tools-list.d.ts +1 -4
- package/lib/chrome/tools-list.js +1 -41
- package/lib/chrome/tools-list.js.map +1 -1
- package/lib/chrome/welcome-tips.d.ts +20 -7
- package/lib/chrome/welcome-tips.js +22 -41
- package/lib/chrome/welcome-tips.js.map +1 -1
- package/lib/commands/auth-ids.d.ts +25 -0
- package/lib/commands/auth-ids.js +27 -0
- package/lib/commands/auth-ids.js.map +1 -0
- package/lib/commands/auth-input.d.ts +34 -0
- package/lib/commands/auth-input.js +96 -0
- package/lib/commands/auth-input.js.map +1 -0
- package/lib/commands/auth-providers.d.ts +39 -0
- package/lib/commands/auth-providers.js +125 -0
- package/lib/commands/auth-providers.js.map +1 -0
- package/lib/commands/auth.d.ts +16 -22
- package/lib/commands/auth.js +346 -299
- package/lib/commands/auth.js.map +1 -1
- package/lib/commands/btw.d.ts +27 -0
- package/lib/commands/btw.js +59 -0
- package/lib/commands/btw.js.map +1 -0
- package/lib/commands/diff.js +30 -5
- package/lib/commands/diff.js.map +1 -1
- package/lib/commands/export.d.ts +1 -1
- package/lib/commands/export.js +5 -3
- package/lib/commands/export.js.map +1 -1
- package/lib/commands/files.d.ts +17 -1
- package/lib/commands/files.js +69 -61
- package/lib/commands/files.js.map +1 -1
- package/lib/commands/integrations.js +18 -6
- package/lib/commands/integrations.js.map +1 -1
- package/lib/commands/jobs.d.ts +19 -4
- package/lib/commands/jobs.js +50 -7
- package/lib/commands/jobs.js.map +1 -1
- package/lib/commands/model.js +109 -76
- package/lib/commands/model.js.map +1 -1
- package/lib/commands/permission.js +46 -13
- package/lib/commands/permission.js.map +1 -1
- package/lib/commands/plugins.js +196 -42
- package/lib/commands/plugins.js.map +1 -1
- package/lib/commands/schedule.d.ts +29 -0
- package/lib/commands/schedule.js +228 -0
- package/lib/commands/schedule.js.map +1 -0
- package/lib/commands/session-configuration.d.ts +1 -1
- package/lib/commands/session-configuration.js +29 -28
- package/lib/commands/session-configuration.js.map +1 -1
- package/lib/commands/session.js +75 -80
- package/lib/commands/session.js.map +1 -1
- package/lib/commands/terminal.d.ts +24 -4
- package/lib/commands/terminal.js +38 -94
- package/lib/commands/terminal.js.map +1 -1
- package/lib/commands/trajectory.js +4 -1
- package/lib/commands/trajectory.js.map +1 -1
- package/lib/definition.d.ts +150 -11
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/index.js.map +1 -1
- package/lib/input/actions.d.ts +51 -0
- package/lib/input/actions.js +120 -0
- package/lib/input/actions.js.map +1 -0
- package/lib/input/editor-discovery.js +2 -2
- package/lib/input/editor-discovery.js.map +1 -1
- package/lib/input/editor.d.ts +0 -10
- package/lib/input/editor.js +11 -9
- package/lib/input/editor.js.map +1 -1
- package/lib/input/image-paste.d.ts +19 -1
- package/lib/input/image-paste.js +82 -1
- package/lib/input/image-paste.js.map +1 -1
- package/lib/input/keybindings-config.d.ts +15 -4
- package/lib/input/keybindings-config.js +57 -35
- package/lib/input/keybindings-config.js.map +1 -1
- package/lib/input/keys.d.ts +18 -0
- package/lib/input/keys.js +48 -3
- package/lib/input/keys.js.map +1 -1
- package/lib/input/wheel-scroll.d.ts +46 -0
- package/lib/input/wheel-scroll.js +69 -0
- package/lib/input/wheel-scroll.js.map +1 -0
- package/lib/prompt-intents.d.ts +182 -0
- package/lib/prompt-intents.js +127 -0
- package/lib/prompt-intents.js.map +1 -0
- package/lib/runtime/agent-profile.d.ts +5 -0
- package/lib/runtime/agent-profile.js +12 -0
- package/lib/runtime/agent-profile.js.map +1 -1
- package/lib/runtime/approval-rules.d.ts +59 -0
- package/lib/runtime/approval-rules.js +179 -0
- package/lib/runtime/approval-rules.js.map +1 -0
- package/lib/runtime/btw-policy.d.ts +7 -0
- package/lib/runtime/btw-policy.js +18 -0
- package/lib/runtime/btw-policy.js.map +1 -0
- package/lib/runtime/btw.d.ts +47 -0
- package/lib/runtime/btw.js +200 -0
- package/lib/runtime/btw.js.map +1 -0
- package/lib/runtime/cancellable.d.ts +75 -0
- package/lib/runtime/cancellable.js +76 -0
- package/lib/runtime/cancellable.js.map +1 -0
- package/lib/runtime/composer-images.js +5 -4
- package/lib/runtime/composer-images.js.map +1 -1
- package/lib/runtime/composer-shell.d.ts +30 -0
- package/lib/runtime/composer-shell.js +150 -0
- package/lib/runtime/composer-shell.js.map +1 -0
- package/lib/runtime/file-recovery-local.d.ts +73 -0
- package/lib/runtime/file-recovery-local.js +351 -0
- package/lib/runtime/file-recovery-local.js.map +1 -0
- package/lib/runtime/file-recovery-recording.d.ts +23 -0
- package/lib/runtime/file-recovery-recording.js +131 -0
- package/lib/runtime/file-recovery-recording.js.map +1 -0
- package/lib/runtime/file-recovery-review.d.ts +3 -0
- package/lib/runtime/file-recovery-review.js +130 -0
- package/lib/runtime/file-recovery-review.js.map +1 -0
- package/lib/runtime/file-recovery-store.d.ts +83 -0
- package/lib/runtime/file-recovery-store.js +329 -0
- package/lib/runtime/file-recovery-store.js.map +1 -0
- package/lib/runtime/file-recovery-worker.d.ts +22 -0
- package/lib/runtime/file-recovery-worker.js +153 -0
- package/lib/runtime/file-recovery-worker.js.map +1 -0
- package/lib/runtime/file-review.d.ts +6 -3
- package/lib/runtime/file-review.js +44 -7
- package/lib/runtime/file-review.js.map +1 -1
- package/lib/runtime/herdr-agent.d.ts +4 -13
- package/lib/runtime/herdr-agent.js +19 -63
- package/lib/runtime/herdr-agent.js.map +1 -1
- package/lib/runtime/plain-tui.d.ts +2 -0
- package/lib/runtime/plain-tui.js +7 -1
- package/lib/runtime/plain-tui.js.map +1 -1
- package/lib/runtime/plugin-settings.d.ts +25 -2
- package/lib/runtime/plugin-settings.js +329 -31
- package/lib/runtime/plugin-settings.js.map +1 -1
- package/lib/runtime/provider-local.d.ts +81 -24
- package/lib/runtime/provider-local.js +1807 -608
- package/lib/runtime/provider-local.js.map +1 -1
- package/lib/runtime/runner.js +52 -12
- package/lib/runtime/runner.js.map +1 -1
- package/lib/runtime/session-archive.d.ts +6 -0
- package/lib/runtime/session-archive.js +129 -3
- package/lib/runtime/session-archive.js.map +1 -1
- package/lib/runtime/session-runtime.js +1 -1
- package/lib/runtime/session-runtime.js.map +1 -1
- package/lib/runtime/settings-preferences.d.ts +5 -0
- package/lib/runtime/settings-preferences.js +34 -0
- package/lib/runtime/settings-preferences.js.map +1 -0
- package/lib/runtime/startup-notices.js +2 -0
- package/lib/runtime/startup-notices.js.map +1 -1
- package/lib/runtime/terminal-modes.d.ts +47 -0
- package/lib/runtime/terminal-modes.js +86 -0
- package/lib/runtime/terminal-modes.js.map +1 -0
- package/lib/runtime/terminal-notifications.d.ts +3 -5
- package/lib/runtime/terminal-notifications.js +4 -8
- package/lib/runtime/terminal-notifications.js.map +1 -1
- package/lib/runtime/terminal-probe.d.ts +36 -0
- package/lib/runtime/terminal-probe.js +37 -0
- package/lib/runtime/terminal-probe.js.map +1 -0
- package/lib/runtime/terminal-session.d.ts +57 -0
- package/lib/runtime/terminal-session.js +164 -0
- package/lib/runtime/terminal-session.js.map +1 -0
- package/lib/runtime/terminal-state.d.ts +29 -0
- package/lib/runtime/terminal-state.js +62 -0
- package/lib/runtime/terminal-state.js.map +1 -0
- package/lib/runtime/tool-presentation.js +50 -14
- package/lib/runtime/tool-presentation.js.map +1 -1
- package/lib/session/external-agents.d.ts +5 -0
- package/lib/session/external-agents.js +27 -0
- package/lib/session/external-agents.js.map +1 -0
- package/lib/session/feature-toggles.d.ts +1 -1
- package/lib/session/feature-toggles.js +1 -1
- package/lib/session/interaction-adapter.d.ts +1 -6
- package/lib/session/interaction-adapter.js +95 -18
- package/lib/session/interaction-adapter.js.map +1 -1
- package/lib/session/message-queue.js +1 -1
- package/lib/session/message-queue.js.map +1 -1
- package/lib/session/model-readiness.d.ts +16 -0
- package/lib/session/model-readiness.js +43 -0
- package/lib/session/model-readiness.js.map +1 -0
- package/lib/session/package-metadata.d.ts +8 -0
- package/lib/session/package-metadata.js +8 -0
- package/lib/session/package-metadata.js.map +1 -1
- package/lib/session/project-context.d.ts +5 -0
- package/lib/session/project-context.js +36 -0
- package/lib/session/project-context.js.map +1 -1
- package/lib/session/session-controller.d.ts +10 -13
- package/lib/session/session-controller.js +183 -98
- package/lib/session/session-controller.js.map +1 -1
- package/lib/session/session-library.js +2 -0
- package/lib/session/session-library.js.map +1 -1
- package/lib/session/session-tree.d.ts +3 -0
- package/lib/session/session-tree.js +3 -1
- package/lib/session/session-tree.js.map +1 -1
- package/lib/session/subagent-roster.d.ts +2 -1
- package/lib/session/subagent-roster.js +24 -3
- package/lib/session/subagent-roster.js.map +1 -1
- package/lib/session/subagent-tracker.d.ts +6 -2
- package/lib/session/subagent-tracker.js +49 -2
- package/lib/session/subagent-tracker.js.map +1 -1
- package/lib/session/tui-settings.d.ts +47 -13
- package/lib/session/tui-settings.js +76 -34
- package/lib/session/tui-settings.js.map +1 -1
- package/lib/session/working-directory.d.ts +4 -0
- package/lib/session/working-directory.js +4 -0
- package/lib/session/working-directory.js.map +1 -0
- package/lib/session/worktrees.d.ts +13 -0
- package/lib/session/worktrees.js +49 -0
- package/lib/session/worktrees.js.map +1 -0
- package/lib/views/approval-rule.d.ts +3 -0
- package/lib/views/approval-rule.js +4 -0
- package/lib/views/approval-rule.js.map +1 -0
- package/lib/views/at-complete.d.ts +8 -0
- package/lib/views/at-complete.js +64 -2
- package/lib/views/at-complete.js.map +1 -1
- package/lib/views/autocomplete.d.ts +22 -2
- package/lib/views/autocomplete.js +70 -40
- package/lib/views/autocomplete.js.map +1 -1
- package/lib/views/copy-targets.d.ts +13 -14
- package/lib/views/copy-targets.js +42 -54
- package/lib/views/copy-targets.js.map +1 -1
- package/lib/views/document-reader.js +18 -5
- package/lib/views/document-reader.js.map +1 -1
- package/lib/views/event-views.d.ts +1 -1
- package/lib/views/event-views.js +60 -6
- package/lib/views/event-views.js.map +1 -1
- package/lib/views/file-actions.d.ts +12 -0
- package/lib/views/file-actions.js +72 -0
- package/lib/views/file-actions.js.map +1 -0
- package/lib/views/history-search.js +15 -21
- package/lib/views/history-search.js.map +1 -1
- package/lib/views/hotkeys.d.ts +8 -1
- package/lib/views/hotkeys.js +53 -26
- package/lib/views/hotkeys.js.map +1 -1
- package/lib/views/list-navigation.d.ts +62 -0
- package/lib/views/list-navigation.js +73 -0
- package/lib/views/list-navigation.js.map +1 -0
- package/lib/views/list-view.d.ts +99 -0
- package/lib/views/list-view.js +165 -0
- package/lib/views/list-view.js.map +1 -0
- package/lib/views/prompt-selector.d.ts +34 -4
- package/lib/views/prompt-selector.js +270 -134
- package/lib/views/prompt-selector.js.map +1 -1
- package/lib/views/session-files.d.ts +1 -2
- package/lib/views/session-files.js +1 -11
- package/lib/views/session-files.js.map +1 -1
- package/lib/views/settings-list.d.ts +51 -10
- package/lib/views/settings-list.js +267 -315
- package/lib/views/settings-list.js.map +1 -1
- package/lib/views/trajectory-timeline.d.ts +72 -0
- package/lib/views/trajectory-timeline.js +133 -0
- package/lib/views/trajectory-timeline.js.map +1 -0
- package/lib/views/trajectory.d.ts +15 -4
- package/lib/views/trajectory.js +557 -123
- package/lib/views/trajectory.js.map +1 -1
- package/lib/views/transcript-export.js +9 -0
- package/lib/views/transcript-export.js.map +1 -1
- package/lib/views/transcript-render.d.ts +97 -25
- package/lib/views/transcript-render.js +542 -170
- package/lib/views/transcript-render.js.map +1 -1
- package/lib/views/transcript-search.d.ts +39 -6
- package/lib/views/transcript-search.js +46 -11
- package/lib/views/transcript-search.js.map +1 -1
- package/lib/views/transcript-types.d.ts +63 -5
- package/lib/views/transcript-types.js +23 -11
- package/lib/views/transcript-types.js.map +1 -1
- package/package.json +95 -65
- package/lib/commands/loop.d.ts +0 -52
- package/lib/commands/loop.js +0 -307
- package/lib/commands/loop.js.map +0 -1
- package/lib/commands/steer.d.ts +0 -5
- package/lib/commands/steer.js +0 -24
- package/lib/commands/steer.js.map +0 -1
- package/lib/runtime/terminal-reader.d.ts +0 -11
- package/lib/runtime/terminal-reader.js +0 -87
- package/lib/runtime/terminal-reader.js.map +0 -1
- package/lib/views/agent-hub.d.ts +0 -32
- package/lib/views/agent-hub.js +0 -206
- package/lib/views/agent-hub.js.map +0 -1
- package/lib/views/copy-selector.d.ts +0 -51
- package/lib/views/copy-selector.js +0 -139
- package/lib/views/copy-selector.js.map +0 -1
|
@@ -3,16 +3,20 @@
|
|
|
3
3
|
* Pure — the provider owns live application of the selected values.
|
|
4
4
|
* @module @agi-fans/dsh-tui
|
|
5
5
|
*/
|
|
6
|
+
import { TERMINAL_TITLE_MODES, TERMINAL_STATE_MODES } from "../runtime/terminal-state.js";
|
|
6
7
|
import { STARTUP_CHANGELOG_MODES } from "../session/release-notes.js";
|
|
7
|
-
import {
|
|
8
|
+
import { STATUS_DENSITIES, STATUS_ITEM_IDS, isStatusItemId, resolveStatusBarConfig, statusBarDocument, statusItemVisible, toggleStatusItem, } from "../chrome/status-config.js";
|
|
8
9
|
import { renderStatusFooter } from "../chrome/status-line.js";
|
|
9
|
-
import { BOX,
|
|
10
|
-
import { padToWidth, truncateToWidth, visibleWidth,
|
|
11
|
-
import { MOTION_MODES } from "../session/tui-settings.js";
|
|
10
|
+
import { BOX, THEME_NAMES, isThemeName } from "../chrome/theme.js";
|
|
11
|
+
import { padToWidth, truncateToWidth, visibleWidth, wrapTextStable } from "../chrome/width.js";
|
|
12
|
+
import { MOTION_MODES, NOTIFICATION_MODES, resolveNotificationMode, } from "../session/tui-settings.js";
|
|
12
13
|
import { MATH_MODES } from "../chrome/math.js";
|
|
13
14
|
import { MERMAID_MODES } from "../chrome/mermaid.js";
|
|
14
|
-
import {
|
|
15
|
+
import { listNavigation } from "./list-navigation.js";
|
|
16
|
+
import { LIST_CURSOR_CELLS, renderListRowWithValue } from "./list-view.js";
|
|
15
17
|
import { FEATURE_TOGGLES } from "../session/feature-toggles.js";
|
|
18
|
+
import { rankSearchResults } from "../input/fuzzy-search.js";
|
|
19
|
+
import { moveGraphemeLeft } from "../chrome/grapheme.js";
|
|
16
20
|
const COLOR_VALUES = ['on', 'off'];
|
|
17
21
|
const STARTUP_CHANGELOG_VALUES = [...STARTUP_CHANGELOG_MODES];
|
|
18
22
|
const AGENT_LANGUAGE_VALUES = ['Auto', 'Simplified Chinese', 'English'];
|
|
@@ -22,46 +26,30 @@ const AGENT_LANGUAGE_LABELS = {
|
|
|
22
26
|
en: 'English',
|
|
23
27
|
};
|
|
24
28
|
const AGENT_LANGUAGE_IDS = Object.fromEntries(Object.entries(AGENT_LANGUAGE_LABELS).map(([id, label]) => [label, id]));
|
|
25
|
-
const STATUS_ITEM_CONTROLS = '
|
|
29
|
+
const STATUS_ITEM_CONTROLS = 'Space shows or hides it.';
|
|
26
30
|
const STATUS_ITEM_COPY = {
|
|
27
|
-
model: { label: 'Model', description: `Model name on the
|
|
31
|
+
model: { label: 'Model', description: `Model name on the first footer line. ${STATUS_ITEM_CONTROLS}`, sample: 'deepseek' },
|
|
28
32
|
effort: { label: 'Effort', description: `Reasoning effort on the first footer line. ${STATUS_ITEM_CONTROLS}`, sample: 'max' },
|
|
29
33
|
path: { label: 'Path', description: `Workspace path on the right of the first footer line. ${STATUS_ITEM_CONTROLS}`, sample: '~/project' },
|
|
30
|
-
git: { label: 'Git', description: `Git branch on the
|
|
31
|
-
session: { label: 'Session', description: `Folded session title on the first footer line. Off
|
|
32
|
-
context: { label: 'Context', description: `Context occupancy
|
|
33
|
-
cache: { label: 'Cache', description: `Prompt-cache hit rate. Cache-hit percentages stay on the success color. ${STATUS_ITEM_CONTROLS}`, sample: 'Cache 99%' },
|
|
34
|
-
tokens: { label: 'Tokens', description: `Input and output token counts. ${STATUS_ITEM_CONTROLS}`, sample: '5.9M in' },
|
|
35
|
-
speed: { label: 'Latency', description: `First-token latency and decode rate. ${STATUS_ITEM_CONTROLS}`, sample: 'TTFT 1.2s' },
|
|
36
|
-
durations: { label: 'Time', description: `LLM and tool duration. ${STATUS_ITEM_CONTROLS}`, sample: 'LLM 16m51s' },
|
|
37
|
-
counts: { label: 'Activity', description: `Turn and step counts. ${STATUS_ITEM_CONTROLS}`, sample: '3 turns' },
|
|
34
|
+
git: { label: 'Git', description: `Git branch on the first footer line. A dirty worktree stays warning. ${STATUS_ITEM_CONTROLS}`, sample: 'main *1' },
|
|
35
|
+
session: { label: 'Session', description: `Folded session title on the first footer line. Off at Standard and Minimal; the terminal window title shows it regardless. ${STATUS_ITEM_CONTROLS}`, sample: 'Fix the parser' },
|
|
36
|
+
context: { label: 'Context', description: `Context occupancy, on the left of the second line. Its representation follows the density. ${STATUS_ITEM_CONTROLS}`, sample: 'Ctx 1.6%' },
|
|
37
|
+
cache: { label: 'Cache', description: `Prompt-cache hit rate, beside occupancy on the left. Cache-hit percentages stay on the success color. ${STATUS_ITEM_CONTROLS}`, sample: 'Cache 99%' },
|
|
38
|
+
tokens: { label: 'Tokens', description: `Input and output token counts, on the right with the other cost figures. ${STATUS_ITEM_CONTROLS}`, sample: '5.9M in' },
|
|
39
|
+
speed: { label: 'Latency', description: `First-token latency and decode rate, on the right. ${STATUS_ITEM_CONTROLS}`, sample: 'TTFT 1.2s' },
|
|
40
|
+
durations: { label: 'Time', description: `LLM and tool duration, on the right. ${STATUS_ITEM_CONTROLS}`, sample: 'LLM 16m51s' },
|
|
41
|
+
counts: { label: 'Activity', description: `Turn and step counts, on the right. ${STATUS_ITEM_CONTROLS}`, sample: '3 turns' },
|
|
38
42
|
};
|
|
39
|
-
function itemSwatch(id, token) {
|
|
40
|
-
if (token !== 'default')
|
|
41
|
-
return token === 'label' ? 'customMessageLabel' : token;
|
|
42
|
-
if (id === 'effort')
|
|
43
|
-
return 'customMessageLabel';
|
|
44
|
-
if (id === 'git')
|
|
45
|
-
return 'warning';
|
|
46
|
-
if (id === 'path')
|
|
47
|
-
return 'muted';
|
|
48
|
-
return 'text';
|
|
49
|
-
}
|
|
50
|
-
function statusItemVisible(config, id) {
|
|
51
|
-
return isStatusMetaId(id) ? (config.meta ?? STATUS_META_IDS).includes(id) : config.groups.includes(id);
|
|
52
|
-
}
|
|
53
43
|
function statusItemRow(config, id) {
|
|
54
44
|
const visible = statusItemVisible(config, id);
|
|
55
|
-
const color = config.colors?.[id] ?? 'default';
|
|
56
45
|
const copy = STATUS_ITEM_COPY[id];
|
|
57
46
|
return {
|
|
58
47
|
id: `statusItem:${id}`,
|
|
59
|
-
label:
|
|
48
|
+
label: copy.label,
|
|
60
49
|
description: copy.description,
|
|
61
50
|
sample: visible ? copy.sample : 'hidden',
|
|
62
|
-
value:
|
|
63
|
-
values:
|
|
64
|
-
swatch: itemSwatch(id, color),
|
|
51
|
+
value: visible ? 'shown' : 'hidden',
|
|
52
|
+
values: ['shown', 'hidden'],
|
|
65
53
|
hidden: !visible,
|
|
66
54
|
};
|
|
67
55
|
}
|
|
@@ -102,6 +90,13 @@ function generalSettingItems(prefs, editors = [{ id: 'auto', label: 'Auto' }]) {
|
|
|
102
90
|
value: prefs.mermaidMode ?? 'auto',
|
|
103
91
|
values: MERMAID_MODES,
|
|
104
92
|
},
|
|
93
|
+
{
|
|
94
|
+
id: 'hideThinking',
|
|
95
|
+
label: 'Thinking in turns',
|
|
96
|
+
description: 'Shown keeps reasoning visible while a turn runs; Hidden collapses it to one line. Ctrl+T flips this for the session.',
|
|
97
|
+
value: prefs.hideThinking === true ? 'hidden' : 'shown',
|
|
98
|
+
values: ['shown', 'hidden'],
|
|
99
|
+
},
|
|
105
100
|
{
|
|
106
101
|
id: 'editor',
|
|
107
102
|
label: 'Editor',
|
|
@@ -131,11 +126,10 @@ function generalSettingItems(prefs, editors = [{ id: 'auto', label: 'Auto' }]) {
|
|
|
131
126
|
values: COLOR_VALUES,
|
|
132
127
|
},
|
|
133
128
|
{
|
|
134
|
-
id: '
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
values: COLOR_VALUES,
|
|
129
|
+
id: 'terminalTitle', label: 'Terminal title', description: 'Status and session, session only, status and workspace, or Off. Changes the terminal tab title.', value: prefs.terminalTitle ?? 'status', values: TERMINAL_TITLE_MODES,
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
id: 'terminalState', label: 'Terminal status', description: 'Auto reports the root Agent lifecycle once the terminal answers an OSC 7501 capability query; On reports regardless; Off clears reports.', value: prefs.terminalState ?? 'auto', values: TERMINAL_STATE_MODES,
|
|
139
133
|
},
|
|
140
134
|
{
|
|
141
135
|
id: 'checkUpdates',
|
|
@@ -154,23 +148,9 @@ function generalSettingItems(prefs, editors = [{ id: 'auto', label: 'Auto' }]) {
|
|
|
154
148
|
{
|
|
155
149
|
id: 'notifications',
|
|
156
150
|
label: 'Notifications',
|
|
157
|
-
description: 'Notify when a turn finishes or input is required',
|
|
158
|
-
value: prefs.notifications
|
|
159
|
-
values:
|
|
160
|
-
},
|
|
161
|
-
{
|
|
162
|
-
id: 'notificationFocus',
|
|
163
|
-
label: 'Notify when',
|
|
164
|
-
description: 'Only notify while away from the terminal, or regardless of focus. Terminals without focus reports use the existing notification policy.',
|
|
165
|
-
value: prefs.notificationFocus ?? 'unfocused',
|
|
166
|
-
values: ['unfocused', 'always'],
|
|
167
|
-
},
|
|
168
|
-
{
|
|
169
|
-
id: 'notificationThreshold',
|
|
170
|
-
label: 'Long turn',
|
|
171
|
-
description: 'Minimum duration for long-running notifications',
|
|
172
|
-
value: prefs.notificationThreshold ?? '30s',
|
|
173
|
-
values: ['15s', '30s', '1m', '2m'],
|
|
151
|
+
description: 'Notify when a long turn finishes or input is required. Away also waits until the terminal loses focus; Always reports regardless of focus.',
|
|
152
|
+
value: resolveNotificationMode(prefs.notifications, prefs.notificationFocus),
|
|
153
|
+
values: NOTIFICATION_MODES,
|
|
174
154
|
},
|
|
175
155
|
];
|
|
176
156
|
}
|
|
@@ -191,28 +171,21 @@ function statusSettingItems(prefs) {
|
|
|
191
171
|
{
|
|
192
172
|
id: 'statusEnabled',
|
|
193
173
|
label: 'Telemetry',
|
|
194
|
-
description: 'Show session metrics
|
|
174
|
+
description: 'Show session metrics below the first footer line',
|
|
195
175
|
value: statusBar.enabled ? 'on' : 'off',
|
|
196
176
|
values: COLOR_VALUES,
|
|
197
177
|
},
|
|
198
178
|
{
|
|
199
|
-
id: '
|
|
200
|
-
label: '
|
|
201
|
-
description: '
|
|
202
|
-
value: statusBar.
|
|
203
|
-
values:
|
|
204
|
-
},
|
|
205
|
-
{
|
|
206
|
-
id: 'statusContextStyle',
|
|
207
|
-
label: 'Context style',
|
|
208
|
-
description: 'Percentage, a ten-cell bar, used/window tokens, or percentage with tokens',
|
|
209
|
-
value: statusBar.contextStyle,
|
|
210
|
-
values: STATUS_CONTEXT_STYLES,
|
|
179
|
+
id: 'statusDensity',
|
|
180
|
+
label: 'Density',
|
|
181
|
+
description: 'Minimal shows occupancy and cache; Standard adds latency; Verbose adds tokens on the same line and gives durations and activity a third, with long labels and the detailed context form',
|
|
182
|
+
value: statusBar.density,
|
|
183
|
+
values: STATUS_DENSITIES,
|
|
211
184
|
},
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
...
|
|
185
|
+
// Each part has one fixed place, so the rows below are a list of what
|
|
186
|
+
// appears rather than a layout to assemble: Space shows or hides, and
|
|
187
|
+
// nothing has to be dragged into a column.
|
|
188
|
+
...STATUS_ITEM_IDS.map(id => statusItemRow(statusBar, id)),
|
|
216
189
|
];
|
|
217
190
|
}
|
|
218
191
|
/**
|
|
@@ -230,68 +203,10 @@ function featureSettingItems(features) {
|
|
|
230
203
|
}));
|
|
231
204
|
}
|
|
232
205
|
/** Product-owned rows shown in `/settings` (OMP settings-list cycle widgets). */
|
|
233
|
-
export function tuiSettingItems(prefs, agent, features, plugins, editors) {
|
|
234
|
-
return
|
|
235
|
-
...
|
|
236
|
-
...
|
|
237
|
-
...(features === undefined ? [] : featureSettingItems(features)),
|
|
238
|
-
...statusSettingItems(prefs),
|
|
239
|
-
...(plugins ?? []).map(plugin => ({ ...plugin, id: `plugin:${plugin.id}`, value: 'Edit', values: [] })),
|
|
240
|
-
];
|
|
241
|
-
}
|
|
242
|
-
function showInOrder(visible, order, id) {
|
|
243
|
-
const next = visible.filter(item => item !== id);
|
|
244
|
-
const position = order.indexOf(id);
|
|
245
|
-
const insert = next.findIndex(item => order.indexOf(item) > position);
|
|
246
|
-
next.splice(insert < 0 ? next.length : insert, 0, id);
|
|
247
|
-
return next;
|
|
248
|
-
}
|
|
249
|
-
function updateStatusGroup(config, id, value) {
|
|
250
|
-
const groups = config.groups.filter(group => group !== id);
|
|
251
|
-
if (value === 'hidden' || value === 'off')
|
|
252
|
-
return { ...config, groups };
|
|
253
|
-
if (value === 'shown')
|
|
254
|
-
return { ...config, groups: showInOrder(groups, config.order ?? STATUS_GROUP_IDS, id) };
|
|
255
|
-
const position = Number.parseInt(value, 10);
|
|
256
|
-
if (!Number.isInteger(position) || position < 1 || position > STATUS_GROUP_IDS.length)
|
|
257
|
-
return config;
|
|
258
|
-
groups.splice(Math.min(position - 1, groups.length), 0, id);
|
|
259
|
-
return { ...config, groups };
|
|
260
|
-
}
|
|
261
|
-
function toggleStatusItem(config, id) {
|
|
262
|
-
if (isStatusMetaId(id)) {
|
|
263
|
-
const meta = config.meta ?? [...STATUS_META_IDS];
|
|
264
|
-
const hidden = !meta.includes(id);
|
|
265
|
-
return {
|
|
266
|
-
...config,
|
|
267
|
-
meta: hidden ? showInOrder(meta.filter(item => item !== id), config.metaOrder ?? STATUS_META_IDS, id) : meta.filter(item => item !== id),
|
|
268
|
-
};
|
|
269
|
-
}
|
|
270
|
-
return updateStatusGroup(config, id, statusItemVisible(config, id) ? 'hidden' : 'shown');
|
|
271
|
-
}
|
|
272
|
-
function reorderVisible(visible, order, moving, direction) {
|
|
273
|
-
const from = visible.indexOf(moving);
|
|
274
|
-
if (from < 0)
|
|
275
|
-
return { visible: [...visible], order: [...order] };
|
|
276
|
-
const to = Math.max(0, Math.min(visible.length - 1, from + direction));
|
|
277
|
-
const nextVisible = [...visible];
|
|
278
|
-
if (to !== from) {
|
|
279
|
-
nextVisible.splice(from, 1);
|
|
280
|
-
nextVisible.splice(to, 0, moving);
|
|
281
|
-
}
|
|
282
|
-
const visibleSet = new Set(nextVisible);
|
|
283
|
-
const nextOrder = [];
|
|
284
|
-
let visibleIndex = 0;
|
|
285
|
-
for (const item of order) {
|
|
286
|
-
if (visibleSet.has(item))
|
|
287
|
-
nextOrder.push(nextVisible[visibleIndex++]);
|
|
288
|
-
else
|
|
289
|
-
nextOrder.push(item);
|
|
290
|
-
}
|
|
291
|
-
for (const item of nextVisible)
|
|
292
|
-
if (!nextOrder.includes(item))
|
|
293
|
-
nextOrder.push(item);
|
|
294
|
-
return { visible: nextVisible, order: nextOrder };
|
|
206
|
+
export function tuiSettingItems(prefs, agent, features, plugins, editors, actions) {
|
|
207
|
+
return settingGroups({ prefs, ...(agent === undefined ? {} : { agent }), ...(features === undefined ? {} : { features }),
|
|
208
|
+
...(plugins === undefined ? {} : { plugins }), ...(editors === undefined ? {} : { editors }),
|
|
209
|
+
...(actions === undefined ? {} : { actions }) }).flatMap(group => group.items);
|
|
295
210
|
}
|
|
296
211
|
/** Apply one cycled value back onto the prefs record. */
|
|
297
212
|
export function applySettingValue(prefs, id, value) {
|
|
@@ -305,6 +220,8 @@ export function applySettingValue(prefs, id, value) {
|
|
|
305
220
|
return { ...prefs, mathMode: value };
|
|
306
221
|
if (id === 'mermaidMode' && MERMAID_MODES.includes(value))
|
|
307
222
|
return { ...prefs, mermaidMode: value };
|
|
223
|
+
if (id === 'hideThinking')
|
|
224
|
+
return { ...prefs, hideThinking: value === 'hidden' };
|
|
308
225
|
if (id === 'pasteProtection')
|
|
309
226
|
return { ...prefs, pasteProtection: value === 'on' };
|
|
310
227
|
if (id === 'copyOnSelect')
|
|
@@ -312,54 +229,60 @@ export function applySettingValue(prefs, id, value) {
|
|
|
312
229
|
if (id === 'mouseInteraction' && ['auto', 'tui', 'native'].includes(value)) {
|
|
313
230
|
return { ...prefs, mouseInteraction: value };
|
|
314
231
|
}
|
|
315
|
-
if (id === '
|
|
316
|
-
return { ...prefs,
|
|
232
|
+
if (id === 'terminalTitle' && TERMINAL_TITLE_MODES.includes(value))
|
|
233
|
+
return { ...prefs, terminalTitle: value };
|
|
234
|
+
if (id === 'terminalState' && TERMINAL_STATE_MODES.includes(value))
|
|
235
|
+
return { ...prefs, terminalState: value };
|
|
317
236
|
if (id === 'checkUpdates')
|
|
318
237
|
return { ...prefs, checkUpdates: value === 'on' };
|
|
319
238
|
if (id === 'startupChangelog' && STARTUP_CHANGELOG_MODES.includes(value)) {
|
|
320
239
|
return { ...prefs, startupChangelog: value };
|
|
321
240
|
}
|
|
322
|
-
if (id === 'notifications' &&
|
|
241
|
+
if (id === 'notifications' && NOTIFICATION_MODES.includes(value)) {
|
|
323
242
|
return { ...prefs, notifications: value };
|
|
324
243
|
}
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
244
|
+
/**
|
|
245
|
+
* The status line is one document: a density, plus the parts hidden on top of
|
|
246
|
+
* it. Row identity decides which field moves — there is no per-item colour or
|
|
247
|
+
* column left to write, and `enabled` survives only as "telemetry off".
|
|
248
|
+
*/
|
|
249
|
+
const statusBar = storedStatusBar(prefs);
|
|
250
|
+
if (id === 'statusDensity' && STATUS_DENSITIES.includes(value)) {
|
|
251
|
+
return { ...prefs, statusBar: { ...statusBar, density: value } };
|
|
329
252
|
}
|
|
330
|
-
const statusBar = resolveStatusBarConfig(prefs.statusBar, prefs.statusPreset);
|
|
331
253
|
if (id === 'statusEnabled')
|
|
332
254
|
return { ...prefs, statusBar: { ...statusBar, enabled: value === 'on' } };
|
|
333
|
-
if (id === 'statusLabels' && STATUS_LABEL_STYLES.includes(value)) {
|
|
334
|
-
return { ...prefs, statusBar: { ...statusBar, labels: value } };
|
|
335
|
-
}
|
|
336
|
-
if (id === 'statusContextStyle' && STATUS_CONTEXT_STYLES.includes(value)) {
|
|
337
|
-
return { ...prefs, statusBar: { ...statusBar, contextStyle: value } };
|
|
338
|
-
}
|
|
339
255
|
if (id.startsWith('statusItem:')) {
|
|
340
256
|
const item = id.slice('statusItem:'.length);
|
|
341
|
-
if (isStatusItemId(item)
|
|
342
|
-
return
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
}
|
|
350
|
-
if (STATUS_GROUP_IDS.includes(item)) {
|
|
351
|
-
return { ...prefs, statusBar: updateStatusGroup(statusBar, item, value) };
|
|
352
|
-
}
|
|
257
|
+
if (!isStatusItemId(item))
|
|
258
|
+
return prefs;
|
|
259
|
+
if (value !== 'shown' && value !== 'hidden' && value !== 'off')
|
|
260
|
+
return prefs;
|
|
261
|
+
const resolved = resolveStatusBarConfig(statusBar);
|
|
262
|
+
if (statusItemVisible(resolved, item) === (value === 'shown'))
|
|
263
|
+
return prefs;
|
|
264
|
+
return { ...prefs, statusBar: toggleStatusItem(statusBar, item) };
|
|
353
265
|
}
|
|
354
266
|
return prefs;
|
|
355
267
|
}
|
|
268
|
+
/**
|
|
269
|
+
* The document as it stands, ready for one edit.
|
|
270
|
+
*
|
|
271
|
+
* The narrowing is read from the *stored* document, not reconstructed from what
|
|
272
|
+
* the footer is showing. Reconstructing it turned every part the density happens
|
|
273
|
+
* to omit into an explicit hiding: pressing Space on one row then silently made
|
|
274
|
+
* a different density show less, which is the drift this replaced.
|
|
275
|
+
*/
|
|
276
|
+
function storedStatusBar(prefs) {
|
|
277
|
+
return statusBarDocument(resolveStatusBarConfig(prefs.statusBar, prefs.statusPreset));
|
|
278
|
+
}
|
|
356
279
|
function adjacentValue(current, values, direction) {
|
|
357
280
|
const index = values.indexOf(current);
|
|
358
281
|
return values[(index + direction + values.length) % values.length] ?? values[0] ?? current;
|
|
359
282
|
}
|
|
360
283
|
/** Open the overlay on the current prefs, optionally focused on one row. */
|
|
361
|
-
export function createSettings(prefs, focusId, agent, features, plugins, editors) {
|
|
362
|
-
const items = tuiSettingItems(prefs, agent, features, plugins, editors);
|
|
284
|
+
export function createSettings(prefs, focusId, agent, features, plugins, editors, actions) {
|
|
285
|
+
const items = tuiSettingItems(prefs, agent, features, plugins, editors, actions);
|
|
363
286
|
const focused = focusId === undefined ? 0 : items.findIndex((item) => item.id === focusId);
|
|
364
287
|
return {
|
|
365
288
|
prefs,
|
|
@@ -368,93 +291,73 @@ export function createSettings(prefs, focusId, agent, features, plugins, editors
|
|
|
368
291
|
...(features === undefined ? {} : { features }),
|
|
369
292
|
...(plugins === undefined ? {} : { plugins }),
|
|
370
293
|
...(editors === undefined ? {} : { editors }),
|
|
294
|
+
...(actions === undefined ? {} : { actions }),
|
|
371
295
|
};
|
|
372
296
|
}
|
|
373
297
|
function selectedStatusItem(state) {
|
|
374
|
-
const id = tuiSettingItems(state.prefs, state.agent, state.features, state.plugins, state.editors)[state.selected]?.id;
|
|
298
|
+
const id = tuiSettingItems(state.prefs, state.agent, state.features, state.plugins, state.editors, state.actions)[state.selected]?.id;
|
|
375
299
|
if (id?.startsWith('statusItem:') !== true)
|
|
376
300
|
return undefined;
|
|
377
301
|
const item = id.slice('statusItem:'.length);
|
|
378
302
|
return isStatusItemId(item) ? item : undefined;
|
|
379
303
|
}
|
|
380
|
-
function
|
|
381
|
-
const
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
:
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
order.splice(last + 1, 0, id);
|
|
400
|
-
return { ...next, metaOrder: order };
|
|
401
|
-
}
|
|
402
|
-
const order = (next.order ?? STATUS_GROUP_IDS).filter(item => item !== id);
|
|
403
|
-
let last = -1;
|
|
404
|
-
for (let index = 0; index < order.length; index += 1) {
|
|
405
|
-
if (itemSide(next, order[index]) === side)
|
|
406
|
-
last = index;
|
|
407
|
-
}
|
|
408
|
-
order.splice(last + 1, 0, id);
|
|
409
|
-
return { ...next, order };
|
|
410
|
-
}
|
|
411
|
-
function moveStatusItem(state, direction) {
|
|
412
|
-
const moving = state.moving;
|
|
413
|
-
if (moving === undefined)
|
|
414
|
-
return state;
|
|
415
|
-
const config = resolveStatusBarConfig(state.prefs.statusBar, state.prefs.statusPreset);
|
|
416
|
-
const side = itemSide(config, moving);
|
|
417
|
-
if (isStatusMetaId(moving)) {
|
|
418
|
-
const reordered = reorderVisible(config.meta.filter(id => itemSide(config, id) === side), config.metaOrder, moving, direction);
|
|
419
|
-
const prefs = { ...state.prefs, statusBar: { ...config, meta: reordered.visible.concat(config.meta.filter(id => itemSide(config, id) !== side)), metaOrder: reordered.order } };
|
|
420
|
-
const selected = tuiSettingItems(prefs, state.agent, state.features, state.plugins, state.editors).findIndex(row => row.id === `statusItem:${moving}`);
|
|
421
|
-
return { ...state, prefs, selected, moving };
|
|
422
|
-
}
|
|
423
|
-
const reordered = reorderVisible(config.groups.filter(id => itemSide(config, id) === side), config.order, moving, direction);
|
|
424
|
-
const prefs = { ...state.prefs, statusBar: { ...config, groups: reordered.visible.concat(config.groups.filter(id => itemSide(config, id) !== side)), order: reordered.order } };
|
|
425
|
-
const selected = tuiSettingItems(prefs, state.agent, state.features, state.plugins, state.editors).findIndex(row => row.id === `statusItem:${moving}`);
|
|
426
|
-
return { ...state, prefs, selected, moving };
|
|
427
|
-
}
|
|
428
|
-
function moveStatusItemSide(state, side) {
|
|
429
|
-
const moving = state.moving;
|
|
430
|
-
if (moving === undefined)
|
|
431
|
-
return state;
|
|
432
|
-
const config = resolveStatusBarConfig(state.prefs.statusBar, state.prefs.statusPreset);
|
|
433
|
-
const prefs = { ...state.prefs, statusBar: assignItemSide(config, moving, side) };
|
|
434
|
-
const selected = tuiSettingItems(prefs, state.agent, state.features, state.plugins, state.editors).findIndex(row => row.id === `statusItem:${moving}`);
|
|
435
|
-
return { ...state, prefs, selected, moving };
|
|
304
|
+
function settingGroups(state) {
|
|
305
|
+
const owned = (section) => (state.plugins ?? [])
|
|
306
|
+
.filter(entry => (entry.section ?? 'advanced') === section)
|
|
307
|
+
.map(entry => ({ ...entry, id: `plugin:${entry.id}`, value: entry.inline?.value ?? entry.summary ?? 'Configure',
|
|
308
|
+
values: entry.inline?.choices.map(choice => choice.label) ?? [], resettable: (entry.fields?.length ?? 0) > 0 }));
|
|
309
|
+
return [
|
|
310
|
+
{ id: 'general', label: 'Interface', items: [...generalSettingItems(state.prefs, state.editors).map(item => ({ ...item,
|
|
311
|
+
resettable: true, group: ['theme', 'colors', 'motion', 'mathMode', 'mermaidMode', 'hideThinking', 'terminalTitle', 'terminalState'].includes(item.id) ? 'Appearance'
|
|
312
|
+
: ['editor', 'mouseInteraction', 'pasteProtection', 'copyOnSelect'].includes(item.id) ? 'Input'
|
|
313
|
+
: ['checkUpdates', 'startupChangelog'].includes(item.id) ? 'Startup' : 'Notifications',
|
|
314
|
+
description: item.description,
|
|
315
|
+
})), ...(state.actions ?? []).filter(item => item.group === 'Input')].sort((a, b) => ['Appearance', 'Input', 'Notifications', 'Startup'].indexOf(a.group ?? '') - ['Appearance', 'Input', 'Notifications', 'Startup'].indexOf(b.group ?? '')) },
|
|
316
|
+
{ id: 'agent', label: 'Agent', items: [...(state.actions ?? []).filter(item => item.group !== 'Input'), ...agentSettingItems(state.agent).map(item => ({ ...item, resettable: true, description: `${item.description}. Saved in this profile; applies from the next turn.` })), ...owned('agent')] },
|
|
317
|
+
{ id: 'tools', label: 'Tools', items: [...(state.features === undefined ? [] : featureSettingItems(state.features)), ...owned('tools')] },
|
|
318
|
+
{ id: 'status', label: 'Status line', items: [...statusSettingItems(state.prefs).map(item => ({ ...item, resettable: true })),
|
|
319
|
+
{ id: 'statusReset', label: 'Restore layout', value: 'Restore', values: [], resettable: true, description: 'Restore the inherited status-line layout, colors and visibility. Confirmation shows what will be restored.' }] },
|
|
320
|
+
{ id: 'integrations', label: 'Integrations', items: owned('integrations') },
|
|
321
|
+
{ id: 'advanced', label: 'Advanced', items: owned('advanced') },
|
|
322
|
+
].filter(group => group.items.length > 0);
|
|
436
323
|
}
|
|
437
324
|
function settingSections(state) {
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
...(agentEnd === generalEnd ? [] : [{ id: 'agent', label: 'Agent', start: generalEnd, end: agentEnd }]),
|
|
445
|
-
...(featuresEnd === agentEnd
|
|
446
|
-
? []
|
|
447
|
-
: [{ id: 'features', label: 'Features', start: agentEnd, end: featuresEnd }]),
|
|
448
|
-
{ id: 'status', label: 'Status line', start: featuresEnd, end: statusEnd },
|
|
449
|
-
...(!state.plugins?.length ? [] : [{ id: 'plugins', label: 'Plugins', start: statusEnd, end: statusEnd + state.plugins.length }]),
|
|
450
|
-
];
|
|
325
|
+
let start = 0;
|
|
326
|
+
return settingGroups(state).map(group => {
|
|
327
|
+
const section = { id: group.id, label: group.label, start, end: start + group.items.length };
|
|
328
|
+
start = section.end;
|
|
329
|
+
return section;
|
|
330
|
+
});
|
|
451
331
|
}
|
|
452
332
|
function selectedSection(state) {
|
|
453
333
|
const sections = settingSections(state);
|
|
454
334
|
return sections.find(section => state.selected >= section.start && state.selected < section.end)
|
|
455
335
|
?? sections[0];
|
|
456
336
|
}
|
|
337
|
+
function settingsMatches(state) {
|
|
338
|
+
let index = 0;
|
|
339
|
+
const rows = settingGroups(state).flatMap(group => group.items.map(item => ({ item, index: index++, section: group.label })));
|
|
340
|
+
return rankSearchResults(rows, state.search ?? '', row => [row.item.label, row.item.description, row.section, row.item.group ?? '', ...row.item.keywords ?? []]);
|
|
341
|
+
}
|
|
342
|
+
function searchSettings(state, query) {
|
|
343
|
+
const next = { ...state, search: query };
|
|
344
|
+
const rows = settingsMatches(next);
|
|
345
|
+
return { ...next, selected: rows.find(row => row.index === state.selected)?.index ?? rows[0]?.index ?? state.selected };
|
|
346
|
+
}
|
|
347
|
+
/** Preserve selection and a cross-category search when live configuration refreshes. */
|
|
348
|
+
export function refreshSettings(state, next) {
|
|
349
|
+
const id = tuiSettingItems(state.prefs, state.agent, state.features, state.plugins, state.editors, state.actions)[state.selected]?.id;
|
|
350
|
+
const selected = tuiSettingItems(next.prefs, next.agent, next.features, next.plugins, next.editors, next.actions).findIndex(item => item.id === id);
|
|
351
|
+
const updated = { ...next, selected: selected < 0 ? next.selected : selected,
|
|
352
|
+
...(state.searchOrigin === undefined ? {} : { searchOrigin: state.searchOrigin }) };
|
|
353
|
+
return state.search === undefined ? updated : searchSettings(updated, state.search);
|
|
354
|
+
}
|
|
457
355
|
function moveSelected(state, next) {
|
|
356
|
+
if (state.search !== undefined) {
|
|
357
|
+
const rows = settingsMatches(state), current = rows.findIndex(row => row.index === state.selected);
|
|
358
|
+
const index = rows[Math.max(0, Math.min(rows.length - 1, current + next - state.selected))]?.index;
|
|
359
|
+
return index === undefined ? state : { ...state, selected: index };
|
|
360
|
+
}
|
|
458
361
|
const section = selectedSection(state);
|
|
459
362
|
const selected = Math.max(section.start, Math.min(next, section.end - 1));
|
|
460
363
|
if (selected === state.selected)
|
|
@@ -466,15 +369,25 @@ function moveSection(state, direction) {
|
|
|
466
369
|
const active = selectedSection(state);
|
|
467
370
|
const current = sections.findIndex(section => section.id === active.id);
|
|
468
371
|
const next = (current + direction + sections.length) % sections.length;
|
|
469
|
-
|
|
372
|
+
const { search: _, searchOrigin: __, ...browse } = state;
|
|
373
|
+
return { ...browse, selected: sections[next]?.start ?? 0 };
|
|
470
374
|
}
|
|
471
375
|
function cycleSelected(state, direction = 1) {
|
|
472
|
-
const items = tuiSettingItems(state.prefs, state.agent, state.features, state.plugins, state.editors);
|
|
376
|
+
const items = tuiSettingItems(state.prefs, state.agent, state.features, state.plugins, state.editors, state.actions);
|
|
473
377
|
const item = items[state.selected];
|
|
474
378
|
if (item === undefined)
|
|
475
379
|
return { kind: 'ignore' };
|
|
476
|
-
if (item.
|
|
380
|
+
if (item.action !== undefined)
|
|
477
381
|
return { kind: 'ignore' };
|
|
382
|
+
if (item.id.startsWith('plugin:')) {
|
|
383
|
+
const entry = state.plugins?.find(entry => `plugin:${entry.id}` === item.id);
|
|
384
|
+
const choices = entry?.inline?.choices;
|
|
385
|
+
if (entry === undefined || choices === undefined || choices.length === 0)
|
|
386
|
+
return { kind: 'ignore' };
|
|
387
|
+
const current = choices.findIndex(choice => choice.label === item.value);
|
|
388
|
+
const next = current < 0 ? direction === 1 ? 0 : choices.length - 1 : (current + direction + choices.length) % choices.length;
|
|
389
|
+
return { kind: 'set-plugin', entry, value: choices[next].value };
|
|
390
|
+
}
|
|
478
391
|
const value = adjacentValue(item.value, item.values, direction);
|
|
479
392
|
if (item.id === 'editor') {
|
|
480
393
|
const editor = state.editors?.find(choice => choice.label === value)?.id ?? 'auto';
|
|
@@ -502,25 +415,43 @@ function cycleSelected(state, direction = 1) {
|
|
|
502
415
|
}
|
|
503
416
|
/** Apply one decoded event to the overlay. */
|
|
504
417
|
export function applySettingsEvent(state, event) {
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
if (state.moving !== undefined) {
|
|
511
|
-
if (event.type !== 'key')
|
|
512
|
-
return { kind: 'ignore' };
|
|
513
|
-
if (event.id === 'up' || event.id === 'down') {
|
|
514
|
-
return { kind: 'apply', domain: 'tui', state: moveStatusItem(state, event.id === 'up' ? -1 : 1) };
|
|
418
|
+
{
|
|
419
|
+
if (event.type === 'text' && (state.search !== undefined || event.value !== ' ')) {
|
|
420
|
+
const origin = tuiSettingItems(state.prefs, state.agent, state.features, state.plugins, state.editors, state.actions)[state.selected]?.id;
|
|
421
|
+
const searching = state.search === undefined ? { ...state, search: '', ...(origin === undefined ? {} : { searchOrigin: origin }) } : state;
|
|
422
|
+
return { kind: 'update', state: searchSettings(searching, (searching.search ?? '') + (event.value === '/' && state.search === undefined ? '' : event.value.replace(/[\r\n]/gu, ' '))) };
|
|
515
423
|
}
|
|
516
|
-
if (
|
|
517
|
-
|
|
424
|
+
if (state.search !== undefined && event.type === 'key') {
|
|
425
|
+
if (event.id === 'escape' || event.id === 'ctrl+c') {
|
|
426
|
+
if (state.search !== '')
|
|
427
|
+
return { kind: 'update', state: searchSettings(state, '') };
|
|
428
|
+
const { search: _, searchOrigin, ...browse } = state;
|
|
429
|
+
const index = tuiSettingItems(state.prefs, state.agent, state.features, state.plugins, state.editors, state.actions).findIndex(item => item.id === searchOrigin);
|
|
430
|
+
return { kind: 'update', state: { ...browse, selected: index < 0 ? state.selected : index } };
|
|
431
|
+
}
|
|
432
|
+
if (event.id === 'backspace' || event.id === 'ctrl+u')
|
|
433
|
+
return { kind: 'update', state: searchSettings(state, event.id === 'ctrl+u' ? '' : state.search.slice(0, moveGraphemeLeft(state.search, state.search.length))) };
|
|
434
|
+
if (event.id === 'home' || event.id === 'end') {
|
|
435
|
+
const rows = settingsMatches(state);
|
|
436
|
+
return { kind: 'update', state: { ...state, selected: (event.id === 'home' ? rows[0] : rows.at(-1))?.index ?? state.selected } };
|
|
437
|
+
}
|
|
438
|
+
if (settingsMatches(state).length === 0 && ['enter', 'left', 'right', 'ctrl+r'].includes(event.id))
|
|
439
|
+
return { kind: 'ignore' };
|
|
518
440
|
}
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
441
|
+
const selected = tuiSettingItems(state.prefs, state.agent, state.features, state.plugins, state.editors, state.actions)[state.selected];
|
|
442
|
+
if (event.type === 'key' && event.id === 'ctrl+r' && selected?.resettable) {
|
|
443
|
+
const entry = state.plugins?.find(entry => `plugin:${entry.id}` === selected.id);
|
|
444
|
+
return { kind: 'reset', id: selected.id, label: selected.label, ...(entry === undefined ? {} : { entry }) };
|
|
522
445
|
}
|
|
523
|
-
|
|
446
|
+
if (event.type === 'key' && event.id === 'enter' && selected?.id === 'statusReset')
|
|
447
|
+
return { kind: 'reset', id: selected.id, label: selected.label };
|
|
448
|
+
if (selected?.action !== undefined && event.type === 'key' && event.id === 'enter')
|
|
449
|
+
return { kind: 'open-command', name: selected.action };
|
|
450
|
+
}
|
|
451
|
+
if ((event.type === 'key' && event.id === 'enter') || (event.type === 'text' && event.value === ' ')) {
|
|
452
|
+
const selected = tuiSettingItems(state.prefs, state.agent, state.features, state.plugins, state.editors, state.actions)[state.selected];
|
|
453
|
+
if (selected?.id.startsWith('plugin:') && (event.type === 'key' || selected.values.length === 0))
|
|
454
|
+
return { kind: 'open-plugin', id: selected.id.slice('plugin:'.length) };
|
|
524
455
|
}
|
|
525
456
|
if (event.type === 'text' && event.value === ' ') {
|
|
526
457
|
const item = selectedStatusItem(state);
|
|
@@ -531,10 +462,7 @@ export function applySettingsEvent(state, event) {
|
|
|
531
462
|
domain: 'tui',
|
|
532
463
|
state: {
|
|
533
464
|
...state,
|
|
534
|
-
prefs: {
|
|
535
|
-
...state.prefs,
|
|
536
|
-
statusBar: toggleStatusItem(resolveStatusBarConfig(state.prefs.statusBar, state.prefs.statusPreset), item),
|
|
537
|
-
},
|
|
465
|
+
prefs: { ...state.prefs, statusBar: toggleStatusItem(storedStatusBar(state.prefs), item) },
|
|
538
466
|
},
|
|
539
467
|
};
|
|
540
468
|
}
|
|
@@ -542,33 +470,31 @@ export function applySettingsEvent(state, event) {
|
|
|
542
470
|
return { kind: 'ignore' };
|
|
543
471
|
switch (event.id) {
|
|
544
472
|
case 'enter':
|
|
545
|
-
{
|
|
546
|
-
const item = selectedStatusItem(state);
|
|
547
|
-
if (item !== undefined)
|
|
548
|
-
return { kind: 'apply', domain: 'tui', state: startMoving(state, item) };
|
|
549
|
-
}
|
|
550
473
|
return cycleSelected(state);
|
|
551
474
|
case 'right':
|
|
552
475
|
return cycleSelected(state);
|
|
553
476
|
case 'left':
|
|
554
477
|
return cycleSelected(state, -1);
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
return { kind: 'update', state: moveSelected(state, state.selected - 1) };
|
|
560
|
-
case 'down':
|
|
561
|
-
return { kind: 'update', state: moveSelected(state, state.selected + 1) };
|
|
478
|
+
// This overlay keeps three keys that a plain list would spend on movement:
|
|
479
|
+
// `tab` switches section, and `home`/`end` jump to the edge of the current
|
|
480
|
+
// section rather than of the whole list, which is the only reading that makes
|
|
481
|
+
// sense when the rows above belong to another category.
|
|
562
482
|
case 'tab':
|
|
563
483
|
return { kind: 'update', state: moveSection(state, 1) };
|
|
564
484
|
case 'shift+tab':
|
|
565
485
|
return { kind: 'update', state: moveSection(state, -1) };
|
|
566
486
|
case 'home':
|
|
567
|
-
return { kind: 'update', state: moveSelected(state,
|
|
487
|
+
return { kind: 'update', state: moveSelected(state, selectedSection(state).start) };
|
|
568
488
|
case 'end':
|
|
569
489
|
return { kind: 'update', state: moveSelected(state, selectedSection(state).end - 1) };
|
|
570
|
-
default:
|
|
490
|
+
default: {
|
|
491
|
+
const navigation = listNavigation(event);
|
|
492
|
+
if (navigation.kind === 'close')
|
|
493
|
+
return { kind: 'close' };
|
|
494
|
+
if (navigation.kind === 'move')
|
|
495
|
+
return { kind: 'update', state: moveSelected(state, state.selected + navigation.delta) };
|
|
571
496
|
return { kind: 'ignore' };
|
|
497
|
+
}
|
|
572
498
|
}
|
|
573
499
|
}
|
|
574
500
|
/** First overlay-local row that paints a setting item. */
|
|
@@ -578,14 +504,11 @@ export const SETTINGS_ITEM_ROW = 3;
|
|
|
578
504
|
const HOTKEY_NAVIGATE = { keys: '↑↓', action: 'Navigate rows' };
|
|
579
505
|
const HOTKEY_CHANGE = { keys: '←→', action: 'Change the selected value' };
|
|
580
506
|
const HOTKEY_TOGGLE = { keys: 'Space', action: 'Toggle — show or hide a status item, or cycle other rows' };
|
|
581
|
-
const HOTKEY_MOVE = { keys: 'Enter', action: 'Change —
|
|
507
|
+
const HOTKEY_MOVE = { keys: 'Enter', action: 'Change — open configuration, or cycle other rows' };
|
|
582
508
|
const HOTKEY_SECTION = { keys: 'Tab / Shift+Tab', action: 'Switch section' };
|
|
583
509
|
const HOTKEY_EDGE = { keys: 'Home / End', action: 'Jump to the section edges' };
|
|
584
|
-
const HOTKEY_CLOSE = { keys: 'Esc', action: '
|
|
585
|
-
const HOTKEY_CANCEL = { keys: 'Ctrl+C', action: 'Close the overlay
|
|
586
|
-
const HOTKEY_ORDER = { keys: '↑↓', action: 'Order the grabbed item while moving' };
|
|
587
|
-
const HOTKEY_COLUMN = { keys: '←→', action: 'Column — choose the footer side while moving' };
|
|
588
|
-
const HOTKEY_PLACE = { keys: 'Enter / Esc', action: 'Place the grabbed item and stop moving' };
|
|
510
|
+
const HOTKEY_CLOSE = { keys: 'Esc', action: 'Clear search, return to browsing, or close the overlay' };
|
|
511
|
+
const HOTKEY_CANCEL = { keys: 'Ctrl+C', action: 'Close the overlay' };
|
|
589
512
|
/** Keys the settings overlay accepts; `/help` and its bottom hint read this list. */
|
|
590
513
|
export const SETTINGS_HOTKEYS = [
|
|
591
514
|
HOTKEY_NAVIGATE,
|
|
@@ -594,17 +517,15 @@ export const SETTINGS_HOTKEYS = [
|
|
|
594
517
|
HOTKEY_MOVE,
|
|
595
518
|
HOTKEY_SECTION,
|
|
596
519
|
HOTKEY_EDGE,
|
|
520
|
+
{ keys: '/ or Text', action: 'Search across all categories' },
|
|
521
|
+
{ keys: 'Backspace / Ctrl+U', action: 'Edit or clear the settings search' },
|
|
522
|
+
{ keys: 'Ctrl+R', action: 'Restore inheritance for the selected setting' },
|
|
597
523
|
HOTKEY_CLOSE,
|
|
598
524
|
HOTKEY_CANCEL,
|
|
599
|
-
HOTKEY_ORDER,
|
|
600
|
-
HOTKEY_COLUMN,
|
|
601
|
-
HOTKEY_PLACE,
|
|
602
525
|
];
|
|
603
526
|
/** Bottom hint for the overlay; the grabbed-row state swaps in its own gestures. */
|
|
604
|
-
function settingsHints(
|
|
605
|
-
return
|
|
606
|
-
? formatOverlayHint([HOTKEY_ORDER, HOTKEY_COLUMN, HOTKEY_PLACE])
|
|
607
|
-
: formatOverlayHint([HOTKEY_NAVIGATE, HOTKEY_CHANGE, HOTKEY_TOGGLE, HOTKEY_MOVE, HOTKEY_CLOSE]);
|
|
527
|
+
function settingsHints() {
|
|
528
|
+
return '↑↓ select · ←→ change · Tab sections · / search · Ctrl+R reset · Esc back';
|
|
608
529
|
}
|
|
609
530
|
function fit(text, width) {
|
|
610
531
|
if (width <= 0)
|
|
@@ -616,7 +537,7 @@ function border(theme, text) {
|
|
|
616
537
|
}
|
|
617
538
|
function topBorder(theme, width) {
|
|
618
539
|
const inner = Math.max(0, width - 2);
|
|
619
|
-
const title = truncateToWidth(' Settings ', Math.max(0, inner - 2));
|
|
540
|
+
const title = truncateToWidth(' Settings · Profile ', Math.max(0, inner - 2));
|
|
620
541
|
const fill = Math.max(0, inner - 1 - visibleWidth(title));
|
|
621
542
|
return border(theme, BOX.topLeft + BOX.horizontal)
|
|
622
543
|
+ theme.bold(theme.fg('accent', title))
|
|
@@ -637,7 +558,9 @@ function renderSectionTabs(active, sections, theme, width) {
|
|
|
637
558
|
? theme.bold(theme.fg('accent', `● ${label}`))
|
|
638
559
|
: theme.fg('muted', `○ ${label}`);
|
|
639
560
|
const all = ' ' + sections.map(section => tab(section.id, section.label)).join(' ');
|
|
640
|
-
|
|
561
|
+
const current = sections.findIndex(section => section.id === active);
|
|
562
|
+
return framedRow(theme, visibleWidth(all) <= width - 4 ? all
|
|
563
|
+
: ` ‹ ${tab(active, sections[current]?.label ?? active)} · ${current + 1}/${sections.length} ›`, width);
|
|
641
564
|
}
|
|
642
565
|
const STATUS_PREVIEW_STATS = {
|
|
643
566
|
turns: 3,
|
|
@@ -680,7 +603,7 @@ function renderStatusPreview(state, theme, width, rows) {
|
|
|
680
603
|
}
|
|
681
604
|
/** Fullscreen OMP-style settings frame with stable chrome and section tabs. */
|
|
682
605
|
export function renderSettings(state, theme, width, height = 24) {
|
|
683
|
-
const items = tuiSettingItems(state.prefs, state.agent, state.features, state.plugins, state.editors);
|
|
606
|
+
const items = tuiSettingItems(state.prefs, state.agent, state.features, state.plugins, state.editors, state.actions);
|
|
684
607
|
const index = Math.max(0, Math.min(state.selected, Math.max(0, items.length - 1)));
|
|
685
608
|
const viewState = index === state.selected ? state : { ...state, selected: index };
|
|
686
609
|
const sections = settingSections(viewState);
|
|
@@ -697,39 +620,61 @@ export function renderSettings(state, theme, width, height = 24) {
|
|
|
697
620
|
? renderStatusPreview(state, theme, width, maxPreviewContent)
|
|
698
621
|
: [];
|
|
699
622
|
const previewRows = previewLines.length === 0 ? 0 : previewLines.length + 1;
|
|
700
|
-
const
|
|
701
|
-
|
|
702
|
-
const
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
623
|
+
const matches = state.search === undefined ? undefined : settingsMatches(state);
|
|
624
|
+
let previousGroup;
|
|
625
|
+
const rows = matches ?? sectionItems.flatMap((item, offset) => {
|
|
626
|
+
const heading = item.group !== undefined && item.group !== previousGroup ? [{ group: item.group }] : [];
|
|
627
|
+
previousGroup = item.group;
|
|
628
|
+
return [...heading, { item, index: sectionStart + offset }];
|
|
629
|
+
});
|
|
630
|
+
const viewportHeight = Math.max(1, height - 6 - descriptionRows - previewRows - (matches === undefined ? 0 : 1));
|
|
631
|
+
const localSelection = rows.findIndex(row => 'item' in row && row.index === index);
|
|
632
|
+
const visibleCount = Math.min(viewportHeight, rows.length);
|
|
633
|
+
const start = Math.max(0, Math.min(localSelection - Math.floor(visibleCount / 2), rows.length - visibleCount));
|
|
634
|
+
const visibleItems = rows.slice(start, start + visibleCount);
|
|
635
|
+
const selected = matches?.length === 0 ? undefined : items[index];
|
|
636
|
+
const lines = [topBorder(theme, width), renderSectionTabs(active, sections, theme, width)];
|
|
637
|
+
if (matches !== undefined)
|
|
638
|
+
lines.push(framedRow(theme, `Search: ${state.search || 'type to filter'} · ${matches.length} matches`, width));
|
|
639
|
+
lines.push(divider(theme, width));
|
|
707
640
|
if (previewLines.length > 0) {
|
|
708
641
|
lines.push(...previewLines, divider(theme, width));
|
|
709
642
|
}
|
|
710
643
|
let cursorRow = SETTINGS_ITEM_ROW;
|
|
711
644
|
for (let row = 0; row < viewportHeight; row += 1) {
|
|
712
|
-
const
|
|
713
|
-
if (
|
|
714
|
-
lines.push(framedRow(theme, '', width));
|
|
645
|
+
const entry = visibleItems[row];
|
|
646
|
+
if (entry === undefined) {
|
|
647
|
+
lines.push(framedRow(theme, row === 0 && matches?.length === 0 ? theme.fg('muted', 'No matching settings') : '', width));
|
|
648
|
+
continue;
|
|
649
|
+
}
|
|
650
|
+
if ('group' in entry) {
|
|
651
|
+
lines.push(framedRow(theme, theme.fg('dim', ` ${entry.group}`), width));
|
|
715
652
|
continue;
|
|
716
653
|
}
|
|
717
|
-
const
|
|
718
|
-
const selectedRow =
|
|
654
|
+
const item = entry.item;
|
|
655
|
+
const selectedRow = entry.index === index;
|
|
719
656
|
if (selectedRow)
|
|
720
657
|
cursorRow = lines.length;
|
|
721
658
|
const above = start > 0 && row === 0 ? theme.fg('dim', '↑ ') : '';
|
|
722
|
-
const below = start + visibleCount <
|
|
723
|
-
lines.push(framedRow(theme, renderSettingRow(item, selectedRow, theme, Math.max(1, width - 4), above || below,
|
|
659
|
+
const below = start + visibleCount < rows.length && row === viewportHeight - 1 ? theme.fg('dim', '↓ ') : '';
|
|
660
|
+
lines.push(framedRow(theme, renderSettingRow(entry.section === undefined ? item : { ...item, label: `${item.label} · ${entry.section}` }, selectedRow, theme, Math.max(1, width - 4), above || below, false), width));
|
|
724
661
|
}
|
|
725
662
|
lines.push(divider(theme, width));
|
|
726
|
-
const description = selected
|
|
727
|
-
const descriptionLines =
|
|
663
|
+
const description = selected === undefined ? '' : selected.description;
|
|
664
|
+
const descriptionLines = wrapTextStable(description, Math.max(1, width - 8)).slice(0, descriptionRows);
|
|
728
665
|
for (let row = 0; row < descriptionRows; row += 1) {
|
|
729
666
|
const text = descriptionLines[row] ?? '';
|
|
730
667
|
lines.push(framedRow(theme, text === '' ? '' : ' ' + theme.fg('muted', text), width));
|
|
731
668
|
}
|
|
732
|
-
const
|
|
669
|
+
const fullHint = matches !== undefined ? 'Type filter · ↑↓ select · ←→ change · Enter edit · Tab sections · Esc clear/back'
|
|
670
|
+
: selected?.action !== undefined ? 'Enter open · Tab sections · / search · Esc back'
|
|
671
|
+
: selected?.id.startsWith('plugin:') === true ? `Enter configure${selected.values.length > 0 ? ' · ←→ change' : ''} · Tab sections · / search${selected.resettable ? ' · Ctrl+R reset' : ''} · Esc back`
|
|
672
|
+
: selected?.id.startsWith('statusItem:') === true
|
|
673
|
+
? 'Space show/hide · / search · Esc back'
|
|
674
|
+
: selected?.resettable === false ? '←→ change · Tab sections · / search · Esc back' : settingsHints();
|
|
675
|
+
const hints = theme.fg('dim', width < 60
|
|
676
|
+
? matches !== undefined ? 'Type filter · ↑↓ · Esc clear/back' : 'Tab sections · / search · Esc back'
|
|
677
|
+
: fullHint);
|
|
733
678
|
lines.push(framedRow(theme, hints, width), bottomBorder(theme, width));
|
|
734
679
|
return {
|
|
735
680
|
lines,
|
|
@@ -737,18 +682,25 @@ export function renderSettings(state, theme, width, height = 24) {
|
|
|
737
682
|
};
|
|
738
683
|
}
|
|
739
684
|
function renderSettingRow(item, selected, theme, width, edge = '', moving = false) {
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
? theme.bold(theme.fg('accent', item.label))
|
|
743
|
-
: item.hidden === true ? theme.fg('dim', item.label) : item.label;
|
|
744
|
-
const sample = item.sample === undefined
|
|
745
|
-
? ''
|
|
746
|
-
: ' ' + theme.fg(item.hidden === true ? 'dim' : 'muted', item.sample);
|
|
685
|
+
// A colour value keeps its swatch tone only when the row is not selected;
|
|
686
|
+
// selection has to win, or the reader cannot tell which row the cursor is on.
|
|
747
687
|
const rawValue = moving ? 'moving' : item.value;
|
|
748
|
-
const value = selected || item.swatch === undefined
|
|
749
|
-
|
|
750
|
-
:
|
|
751
|
-
|
|
752
|
-
|
|
688
|
+
const value = selected || item.swatch === undefined ? rawValue : theme.fg(item.swatch, rawValue);
|
|
689
|
+
const row = {
|
|
690
|
+
label: item.label,
|
|
691
|
+
...(item.sample === undefined ? {} : { description: item.sample }),
|
|
692
|
+
secondary: item.hidden === true,
|
|
693
|
+
value,
|
|
694
|
+
};
|
|
695
|
+
const rendered = renderListRowWithValue(row, theme, width, visibleWidth(item.label), {
|
|
696
|
+
selected,
|
|
697
|
+
...(moving ? { moving } : {}),
|
|
698
|
+
});
|
|
699
|
+
// An edge mark replaces the cursor cell, which the shared row already
|
|
700
|
+
// reserved, so the row cannot shift when the reader reaches either end.
|
|
701
|
+
if (edge === '')
|
|
702
|
+
return rendered;
|
|
703
|
+
const mark = theme.fg('dim', edge.trimStart() + ' ');
|
|
704
|
+
return truncateToWidth(mark + rendered.slice(LIST_CURSOR_CELLS), width);
|
|
753
705
|
}
|
|
754
706
|
//# sourceMappingURL=settings-list.js.map
|