pi-one-ui 0.4.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +34 -1
- package/README.en.md +5 -4
- package/README.md +7 -5
- package/extensions/app/commands/settings-previews.ts +23 -44
- package/extensions/app/config/shell.ts +19 -58
- package/extensions/app/panel.ts +42 -19
- package/extensions/app/presets.ts +2 -2
- package/extensions/layouts/context/renderer/index.ts +15 -0
- package/extensions/layouts/context/renderer/tool/toggle-render-cache.ts +333 -0
- package/extensions/layouts/editor/controller.ts +16 -8
- package/extensions/layouts/editor/minimalist-editor.ts +10 -5
- package/extensions/layouts/editor/ui.ts +52 -365
- package/extensions/layouts/footer/footer.ts +7 -3
- package/extensions/shared/style.ts +48 -0
- package/extensions/tools/patch-keys.ts +5 -0
- package/package.json +1 -1
- package/themes/cc-dark.json +7 -4
- package/themes/cc-light.json +4 -1
- package/extensions/layouts/editor/completion-menu.ts +0 -183
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,37 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.5.1] - 2026-09-05
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
|
|
13
|
+
- Refined the `cc-dark` theme: `thinkingLow` uses cyan, `thinkingXhigh` yellow, and `thinkingMax` orange for a clearer effort-level hierarchy; `cwd` and `editorModel` labels switch from blue to the muted token for calmer status text.
|
|
14
|
+
|
|
15
|
+
## [0.5.0] - 2026-09-05
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
|
|
19
|
+
- Reduced the Editor to the single `minimalist` style with an `on`/`off` switch: `off` restores Pi's native editor, and the retired `opencode` style is removed (`enabled` merges into `style`, legacy values migrate automatically).
|
|
20
|
+
- Added `/oneui` panel settings for the Editor component: style (`on`/`off`), color source (`theme`/`terminal`), and border color mode (`static`/`adaptive`), each with an inline description.
|
|
21
|
+
- In `off` mode, an explicitly configured `colors.editorBorder` is applied to the native editor border through `colorSource` (theme tokens or fixed terminal colors); without it the native effort/theme coloring is preserved.
|
|
22
|
+
|
|
23
|
+
### Performance
|
|
24
|
+
|
|
25
|
+
- Cached `ToolExecutionComponent` render widgets across expand/collapse toggles: repeated Ctrl+O toggles and identical result updates now skip the full native rebuild, cutting batch expansion of many tools (e.g. 30 × 1000-line outputs) from ~130ms to under 0.2ms while keeping expanded and collapsed render slots independent.
|
|
26
|
+
|
|
27
|
+
### Removed
|
|
28
|
+
|
|
29
|
+
- Removed the `opencode` Editor style along with its polished renderer, completion-menu module, and `styles.opencode` configuration; the `enabled` field is gone.
|
|
30
|
+
|
|
31
|
+
### Migration
|
|
32
|
+
|
|
33
|
+
- `components.editor.enabled: false` becomes `components.editor.style: "off"`; `style: "opencode"`/`"minimalist"` become `"on"`. The `styles.opencode` block and `opencode-copy-friendly`/`accent-rail` selections are ignored.
|
|
34
|
+
|
|
35
|
+
### Fixed
|
|
36
|
+
|
|
37
|
+
- Toggling the Editor style between `on`/`off` no longer replaces the editor factory: the existing instance (and Pi's overlay focus target) stays valid, so the `/oneui` panel restores keyboard focus to the input editor after closing.
|
|
38
|
+
- Unconfigured `cwd`, model-label, and static border colors now prefer the theme's `cwd`/`editorModel`/`editorBorder` tokens (which may reference `vars` variables or hex), falling back to Pi's native defaults when the theme does not define them.
|
|
39
|
+
|
|
9
40
|
## [0.4.0] - 2026-09-03
|
|
10
41
|
|
|
11
42
|
### Changed
|
|
@@ -62,7 +93,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
|
62
93
|
|
|
63
94
|
- Reduced rendering lag when expanding settled tool groups by reusing cached child output.
|
|
64
95
|
|
|
65
|
-
[Unreleased]: https://github.com/kerolt/pi-one-ui/compare/v0.
|
|
96
|
+
[Unreleased]: https://github.com/kerolt/pi-one-ui/compare/v0.5.1...HEAD
|
|
97
|
+
[0.5.1]: https://github.com/kerolt/pi-one-ui/compare/v0.5.0...v0.5.1
|
|
98
|
+
[0.5.0]: https://github.com/kerolt/pi-one-ui/compare/v0.4.0...v0.5.0
|
|
66
99
|
[0.4.0]: https://github.com/kerolt/pi-one-ui/compare/v0.3.1...v0.4.0
|
|
67
100
|
[0.3.1]: https://github.com/kerolt/pi-one-ui/compare/v0.3.0...v0.3.1
|
|
68
101
|
[0.3.0]: https://github.com/kerolt/pi-one-ui/compare/v0.2.2...v0.3.0
|
package/README.en.md
CHANGED
|
@@ -26,7 +26,7 @@ Header → Context → WorkingLine → Editor → Footer
|
|
|
26
26
|
- **Header**: startup information, logo, and shortcut hints.
|
|
27
27
|
- **Context**: the conversation area, including user messages, assistant messages, thinking, tools, diffs, Markdown, and summaries.
|
|
28
28
|
- **WorkingLine**: working state, spinner, token/thought/elapsed information, live output rate, and turn summaries.
|
|
29
|
-
- **Editor**: input editor, completion, metadata, and the
|
|
29
|
+
- **Editor**: input editor, completion, metadata, and the Minimalist style (Pi native is one toggle away).
|
|
30
30
|
- **Footer**: current directory, Git, runtime, token, cost, and extension status information.
|
|
31
31
|
- **Overlay**: temporary interfaces such as the settings panel and Context Inspector, managed by a shared OverlayManager.
|
|
32
32
|
|
|
@@ -90,8 +90,9 @@ Using the `/oneui` settings panel is recommended. The panel uses a top-centered
|
|
|
90
90
|
"version": 1,
|
|
91
91
|
"components": {
|
|
92
92
|
"editor": {
|
|
93
|
-
"
|
|
94
|
-
"
|
|
93
|
+
"style": "on",
|
|
94
|
+
"colorSource": "theme",
|
|
95
|
+
"borderColorMode": "static"
|
|
95
96
|
},
|
|
96
97
|
"userMessages": {
|
|
97
98
|
"enabled": true,
|
|
@@ -111,7 +112,7 @@ Using the `/oneui` settings panel is recommended. The panel uses a top-centered
|
|
|
111
112
|
}
|
|
112
113
|
```
|
|
113
114
|
|
|
114
|
-
The Editor
|
|
115
|
+
The Editor keeps a single `minimalist` decoration style controlled by `style`: `on` enables the Minimalist decoration, `off` restores Pi's native editor (the border follows the theme and effort coloring by default; when `colors.editorBorder` is explicitly configured, the off mode applies that color through `colorSource`, overriding the native effort coloring). Legacy configurations migrate automatically: `enabled: false` becomes `style: "off"`, and `opencode`/`minimalist` become `style: "on"`; the `styles.opencode` block and the retired `opencode-copy-friendly`/`accent-rail` styles are ignored. `borderColorMode` supports `static` (fixed `colors.editorBorder`) and `adaptive` (border shifts with the effort level); `colorSource` supports `theme` (colors resolved through the active Pi theme tokens) and `terminal` (fixed terminal colors). When `cwd`, the model label, or the static border are not explicitly configured, the theme's `cwd`/`editorModel`/`editorBorder` tokens are used first (they may point to `vars` variables or hex values), falling back to Pi's native defaults when the theme does not define them; the terminal source falls back to Pi's native colors as well when unconfigured (only an explicit terminal color name or hex is rendered fixed). Context-usage information is presented by Footer.
|
|
115
116
|
|
|
116
117
|
The WorkingLine token segment appends live output throughput, such as `⚡12 tok/s`, after a model response has run for at least 500ms. Throughput is calculated independently for the current response and resets on the next `turn_start`; disabling the token segment hides it as well.
|
|
117
118
|
|
package/README.md
CHANGED
|
@@ -26,7 +26,7 @@ Header → Context → WorkingLine → Editor → Footer
|
|
|
26
26
|
- **Header**:启动信息、Logo 和快捷键提示。
|
|
27
27
|
- **Context**:对话内容区,包含用户消息、Assistant 消息、Thinking、Tool、Diff、Markdown 和 Summary。
|
|
28
28
|
- **WorkingLine**:工作状态、spinner、token/thought/elapsed、实时输出速率和回合摘要。
|
|
29
|
-
- **Editor**:输入编辑器、completion、metadata,以及
|
|
29
|
+
- **Editor**:输入编辑器、completion、metadata,以及 Minimalist 样式(可切换 Pi 原生)。
|
|
30
30
|
- **Footer**:目录、Git、runtime、token、cost 和扩展状态等信息。
|
|
31
31
|
- **Overlay**:设置面板、Context Inspector 等临时浮层由统一的 OverlayManager 管理。
|
|
32
32
|
|
|
@@ -83,15 +83,17 @@ pi install git:github.com/kerolt/pi-one-ui
|
|
|
83
83
|
~/.pi/agent/pi-one-ui.json
|
|
84
84
|
```
|
|
85
85
|
|
|
86
|
-
|
|
86
|
+
|
|
87
|
+
推荐通过 `/oneui` 设置面板修改配置。面板采用更靠近顶部的居中布局;切换 Editor 开关、颜色源或边框模式时会保持打开并在 Editor 替换后恢复焦点,持久化失败时则恢复列表中的有效旧值。当前配置仍使用 v1 结构,例如:
|
|
87
88
|
|
|
88
89
|
```json
|
|
89
90
|
{
|
|
90
91
|
"version": 1,
|
|
91
92
|
"components": {
|
|
92
93
|
"editor": {
|
|
93
|
-
"
|
|
94
|
-
"
|
|
94
|
+
"style": "on",
|
|
95
|
+
"colorSource": "theme",
|
|
96
|
+
"borderColorMode": "static"
|
|
95
97
|
},
|
|
96
98
|
"userMessages": {
|
|
97
99
|
"enabled": true,
|
|
@@ -111,7 +113,7 @@ pi install git:github.com/kerolt/pi-one-ui
|
|
|
111
113
|
}
|
|
112
114
|
```
|
|
113
115
|
|
|
114
|
-
Editor
|
|
116
|
+
Editor 只保留 `minimalist` 一种装饰样式,通过 `style` 开关控制:`on` 启用 Minimalist 装饰,`off` 恢复 Pi 原生编辑器(边框默认跟随主题与 effort 变色;若显式配置了 `colors.editorBorder`,off 模式下也会按 `colorSource` 应用该颜色,覆盖原生 effort 变色)。旧配置的 `enabled: false` 会迁移为 `style: "off"`,`opencode`/`minimalist` 会迁移为 `style: "on"`,`styles.opencode` 嵌套配置与 `opencode-copy-friendly`、`accent-rail` 一并失效。`borderColorMode` 支持 `static`(固定 `colors.editorBorder`)与 `adaptive`(边框随 effort 档位变化);`colorSource` 支持 `theme`(颜色取当前主题 token)与 `terminal`(固定终端色)。cwd、模型名与边框(static)未显式配置时优先使用主题的 `cwd`/`editorModel`/`editorBorder` token(可指向 vars 变量或 hex),主题未定义则回落 Pi 原生默认;terminal 源未配置时同样回落 Pi 原生颜色(配置了终端色名/hex 才固定渲染)。上下文占用相关信息由 Footer 统一展示。
|
|
115
117
|
|
|
116
118
|
WorkingLine 的 token segment 会在一次模型响应持续至少 500ms 后追加实时输出速率,例如 `⚡12 tok/s`。速率按当前响应独立计算,在下一次 `turn_start` 时重置;关闭 token segment 时也会一并隐藏。
|
|
117
119
|
|
|
@@ -3,7 +3,6 @@ import { truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
|
|
|
3
3
|
import { renderUserMessageStyle } from "../../layouts/context/message/user-message-styles.ts";
|
|
4
4
|
import { sanitizeEditorMetadataText } from "../../layouts/editor/editor-metadata-format.ts";
|
|
5
5
|
import { renderMinimalistFrame } from "../../layouts/editor/minimalist-editor.ts";
|
|
6
|
-
import { renderPolishedEditorFrame } from "../../layouts/editor/ui.ts";
|
|
7
6
|
import { safeThemeFg } from "../../shared/style.ts";
|
|
8
7
|
import type { PolishedTuiConfig } from "../config/shell.ts";
|
|
9
8
|
|
|
@@ -59,50 +58,30 @@ export function renderEditorSettingsPreview(
|
|
|
59
58
|
const viewport = editor.viewportIndicators
|
|
60
59
|
? { above: "2", below: "3" }
|
|
61
60
|
: undefined;
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
modelLabel,
|
|
78
|
-
thinkingLevel: "high",
|
|
79
|
-
sessionName: "Preview",
|
|
80
|
-
agentDurationMs: 12_000,
|
|
81
|
-
agentActive: true,
|
|
82
|
-
},
|
|
83
|
-
uiTheme: theme,
|
|
84
|
-
config: safeConfig,
|
|
85
|
-
borderColor,
|
|
86
|
-
});
|
|
87
|
-
} else {
|
|
88
|
-
frame = renderPolishedEditorFrame({
|
|
89
|
-
width: previewWidth,
|
|
90
|
-
editorLines,
|
|
91
|
-
autocompleteLines,
|
|
92
|
-
viewport,
|
|
93
|
-
uiTheme: theme,
|
|
94
|
-
config: safeConfig,
|
|
95
|
-
modelMeta: {
|
|
96
|
-
modelLabel,
|
|
97
|
-
modelId: "sonnet-4",
|
|
98
|
-
modelName: "Sonnet 4",
|
|
99
|
-
providerLabel: "Anthropic",
|
|
100
|
-
sessionName: "Preview",
|
|
101
|
-
},
|
|
61
|
+
const frame = renderMinimalistFrame({
|
|
62
|
+
width: previewWidth,
|
|
63
|
+
editorLines,
|
|
64
|
+
autocompleteLines,
|
|
65
|
+
viewport,
|
|
66
|
+
inputText: EDITOR_PREVIEW_INPUT,
|
|
67
|
+
metadata: {
|
|
68
|
+
cwd: "/workspace/zentui/src",
|
|
69
|
+
projectRoot: "/workspace/zentui",
|
|
70
|
+
branch: "feat/settings-previews",
|
|
71
|
+
dirty: true,
|
|
72
|
+
ahead: 2,
|
|
73
|
+
behind: 1,
|
|
74
|
+
costLabel: "$.12",
|
|
75
|
+
modelLabel,
|
|
102
76
|
thinkingLevel: "high",
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
77
|
+
sessionName: "Preview",
|
|
78
|
+
agentDurationMs: 12_000,
|
|
79
|
+
agentActive: true,
|
|
80
|
+
},
|
|
81
|
+
uiTheme: theme,
|
|
82
|
+
config: safeConfig,
|
|
83
|
+
borderColor,
|
|
84
|
+
});
|
|
106
85
|
return boundedRows(frame, previewWidth);
|
|
107
86
|
}
|
|
108
87
|
|
|
@@ -24,7 +24,7 @@ export type { IconMode } from "../../shared/icons.ts";
|
|
|
24
24
|
export type ContextStyle = "text" | "gauge" | "text+gauge";
|
|
25
25
|
export type SeparatorStyle = "pipe" | "dot" | "chevron" | "none";
|
|
26
26
|
export type ModelLabelSource = "id" | "name";
|
|
27
|
-
export type EditorStyle = "
|
|
27
|
+
export type EditorStyle = "on" | "off";
|
|
28
28
|
export type UserMessageStyle =
|
|
29
29
|
| "framed"
|
|
30
30
|
| "framed-copy-friendly"
|
|
@@ -46,7 +46,6 @@ export type ComponentStyleOwner =
|
|
|
46
46
|
| "footer";
|
|
47
47
|
export type MinimalistPathDisplayMode = "compact" | "project" | "full";
|
|
48
48
|
export type EditorBorderColorMode = "static" | "adaptive";
|
|
49
|
-
export type CompletionMenuStyle = "native" | "palette";
|
|
50
49
|
export type CompactFooterMaxLines = 1 | 2 | 3 | "unlimited";
|
|
51
50
|
|
|
52
51
|
export const DEFAULT_COMPACT_FOOTER_FORMAT =
|
|
@@ -103,11 +102,6 @@ export type FooterSegmentsConfig = {
|
|
|
103
102
|
packageVersion: boolean;
|
|
104
103
|
};
|
|
105
104
|
|
|
106
|
-
export type PolishedEditorStyleConfig = {
|
|
107
|
-
metadataFormat: string;
|
|
108
|
-
completionMenu: CompletionMenuStyle;
|
|
109
|
-
};
|
|
110
|
-
|
|
111
105
|
export type MinimalistEditorStyleConfig = {
|
|
112
106
|
pathDisplay: MinimalistPathDisplayMode;
|
|
113
107
|
showSessionName: boolean;
|
|
@@ -124,14 +118,12 @@ export type EditorStylesConfig = {
|
|
|
124
118
|
};
|
|
125
119
|
|
|
126
120
|
export type EditorComponentConfig = {
|
|
127
|
-
enabled: boolean;
|
|
128
121
|
style: EditorStyle;
|
|
129
122
|
colorSource: ColorSource;
|
|
130
123
|
borderColorMode: EditorBorderColorMode;
|
|
131
124
|
modelLabel: ModelLabelSource;
|
|
132
125
|
viewportIndicators: boolean;
|
|
133
126
|
styles: {
|
|
134
|
-
opencode: PolishedEditorStyleConfig;
|
|
135
127
|
minimalist: MinimalistEditorStyleConfig;
|
|
136
128
|
};
|
|
137
129
|
};
|
|
@@ -281,7 +273,7 @@ export type ZentuiConfig = {
|
|
|
281
273
|
};
|
|
282
274
|
|
|
283
275
|
export type PolishedTuiColors = {
|
|
284
|
-
cwd
|
|
276
|
+
cwd?: ColorSpec;
|
|
285
277
|
sessionName: ColorSpec;
|
|
286
278
|
gitBranch: ColorSpec;
|
|
287
279
|
gitStatus: ColorSpec;
|
|
@@ -414,8 +406,6 @@ const defaultFooterSegments: FooterSegmentsConfig = {
|
|
|
414
406
|
packageVersion: false,
|
|
415
407
|
};
|
|
416
408
|
|
|
417
|
-
const DEFAULT_COMPLETION_MENU: CompletionMenuStyle = "palette";
|
|
418
|
-
|
|
419
409
|
const defaultMinimalistStyle: MinimalistEditorStyleConfig = {
|
|
420
410
|
pathDisplay: "compact",
|
|
421
411
|
showSessionName: true,
|
|
@@ -446,17 +436,12 @@ const defaultStarshipStyle: StarshipFooterStyleConfig = {
|
|
|
446
436
|
|
|
447
437
|
const defaultComponents: ComponentsConfig = {
|
|
448
438
|
editor: {
|
|
449
|
-
|
|
450
|
-
style: "opencode",
|
|
439
|
+
style: "on",
|
|
451
440
|
colorSource: "theme",
|
|
452
441
|
borderColorMode: "static",
|
|
453
442
|
modelLabel: "id",
|
|
454
443
|
viewportIndicators: true,
|
|
455
444
|
styles: {
|
|
456
|
-
opencode: {
|
|
457
|
-
metadataFormat: DEFAULT_EDITOR_METADATA_FORMAT,
|
|
458
|
-
completionMenu: DEFAULT_COMPLETION_MENU,
|
|
459
|
-
},
|
|
460
445
|
minimalist: defaultMinimalistStyle,
|
|
461
446
|
},
|
|
462
447
|
},
|
|
@@ -496,7 +481,6 @@ export const defaultConfig: PolishedTuiConfig = {
|
|
|
496
481
|
projectRefreshIntervalMs: DEFAULT_PROJECT_REFRESH_INTERVAL_MS,
|
|
497
482
|
icons: { mode: "auto", ...NERD_DEFAULT_ICONS },
|
|
498
483
|
colors: {
|
|
499
|
-
cwd: "bold cyan",
|
|
500
484
|
sessionName: "bold green",
|
|
501
485
|
gitBranch: "bold purple",
|
|
502
486
|
gitStatus: "bold red",
|
|
@@ -578,7 +562,9 @@ function parseEditorModelLabel(
|
|
|
578
562
|
}
|
|
579
563
|
|
|
580
564
|
function parseEditorStyle(value: unknown): EditorStyle {
|
|
581
|
-
if (value === "
|
|
565
|
+
if (value === "on" || value === "off") return value;
|
|
566
|
+
// 迁移:旧 opencode / minimalist 样式统一收敛为 on(minimalist)。
|
|
567
|
+
if (value === "opencode" || value === "minimalist") return "on";
|
|
582
568
|
return defaultComponents.editor.style;
|
|
583
569
|
}
|
|
584
570
|
|
|
@@ -587,12 +573,6 @@ function parseEditorBorderColorMode(value: unknown): EditorBorderColorMode {
|
|
|
587
573
|
return defaultConfig.editorBorderColorMode;
|
|
588
574
|
}
|
|
589
575
|
|
|
590
|
-
function parseCompletionMenuStyle(value: unknown): CompletionMenuStyle {
|
|
591
|
-
return value === "native" || value === "palette"
|
|
592
|
-
? value
|
|
593
|
-
: DEFAULT_COMPLETION_MENU;
|
|
594
|
-
}
|
|
595
|
-
|
|
596
576
|
export function isSeparatorStyle(value: unknown): value is SeparatorStyle {
|
|
597
577
|
return (
|
|
598
578
|
value === "pipe" ||
|
|
@@ -1027,7 +1007,6 @@ function resolveComponents(config: ConfigRecord): ComponentsConfig {
|
|
|
1027
1007
|
const components = recordValue(config.components);
|
|
1028
1008
|
const editor = recordValue(components.editor);
|
|
1029
1009
|
const editorStyles = recordValue(editor.styles);
|
|
1030
|
-
const opencode = recordValue(editorStyles.opencode);
|
|
1031
1010
|
const minimalist = recordValue(editorStyles.minimalist);
|
|
1032
1011
|
const userMessages = recordValue(components.userMessages);
|
|
1033
1012
|
const workingLine = recordValue(components.workingLine);
|
|
@@ -1040,8 +1019,12 @@ function resolveComponents(config: ConfigRecord): ComponentsConfig {
|
|
|
1040
1019
|
|
|
1041
1020
|
return {
|
|
1042
1021
|
editor: {
|
|
1043
|
-
enabled:
|
|
1044
|
-
style:
|
|
1022
|
+
// 迁移:旧 enabled:false 收敛为 style:"off"(enabled 字段已移除)。
|
|
1023
|
+
style:
|
|
1024
|
+
hasOwn(editor, "enabled") &&
|
|
1025
|
+
parseBoolean(editor.enabled, true) === false
|
|
1026
|
+
? "off"
|
|
1027
|
+
: parseEditorStyle(editor.style),
|
|
1045
1028
|
colorSource: parseColorSource(
|
|
1046
1029
|
editor.colorSource,
|
|
1047
1030
|
defaultComponents.editor.colorSource,
|
|
@@ -1056,13 +1039,6 @@ function resolveComponents(config: ConfigRecord): ComponentsConfig {
|
|
|
1056
1039
|
defaultComponents.editor.viewportIndicators,
|
|
1057
1040
|
),
|
|
1058
1041
|
styles: {
|
|
1059
|
-
opencode: {
|
|
1060
|
-
metadataFormat: parseNonEmptyString(
|
|
1061
|
-
opencode.metadataFormat,
|
|
1062
|
-
DEFAULT_EDITOR_METADATA_FORMAT,
|
|
1063
|
-
),
|
|
1064
|
-
completionMenu: parseCompletionMenuStyle(opencode.completionMenu),
|
|
1065
|
-
},
|
|
1066
1042
|
minimalist: {
|
|
1067
1043
|
pathDisplay:
|
|
1068
1044
|
minimalist.pathDisplay === "compact" ||
|
|
@@ -1241,8 +1217,7 @@ function derivedRuntimeView(config: ZentuiConfig): PolishedTuiConfig {
|
|
|
1241
1217
|
extensionStatuses: starship.extensionStatuses,
|
|
1242
1218
|
editorStyle: config.components.editor.style,
|
|
1243
1219
|
editorStyles: { minimalist },
|
|
1244
|
-
editorMetadataFormat:
|
|
1245
|
-
config.components.editor.styles.opencode.metadataFormat,
|
|
1220
|
+
editorMetadataFormat: DEFAULT_EDITOR_METADATA_FORMAT,
|
|
1246
1221
|
editorBorderColorMode: config.components.editor.borderColorMode,
|
|
1247
1222
|
editorModelLabel: config.components.editor.modelLabel,
|
|
1248
1223
|
colorSources: {
|
|
@@ -1251,7 +1226,7 @@ function derivedRuntimeView(config: ZentuiConfig): PolishedTuiConfig {
|
|
|
1251
1226
|
userMessages: config.components.userMessages.colorSource,
|
|
1252
1227
|
},
|
|
1253
1228
|
features: {
|
|
1254
|
-
editor: config.components.editor.
|
|
1229
|
+
editor: config.components.editor.style === "on",
|
|
1255
1230
|
statusLine: config.components.footer.style === "starship",
|
|
1256
1231
|
viewportIndicators: config.components.editor.viewportIndicators,
|
|
1257
1232
|
},
|
|
@@ -1263,8 +1238,10 @@ const unsupportedComponentStyles = new WeakMap<
|
|
|
1263
1238
|
ReadonlySet<ComponentStyleOwner>
|
|
1264
1239
|
>();
|
|
1265
1240
|
|
|
1266
|
-
// Retired selections migrate to
|
|
1241
|
+
// Retired selections migrate to the sole "on" (minimalist) style instead of
|
|
1242
|
+
// disabling the custom Editor. opencode itself is retired along with its variants.
|
|
1267
1243
|
const retiredEditorStyleIds: ReadonlySet<string> = new Set([
|
|
1244
|
+
"opencode",
|
|
1268
1245
|
"opencode-copy-friendly",
|
|
1269
1246
|
"accent-rail",
|
|
1270
1247
|
]);
|
|
@@ -1273,7 +1250,7 @@ const knownComponentStyleIds: Record<
|
|
|
1273
1250
|
ComponentStyleOwner,
|
|
1274
1251
|
ReadonlySet<string>
|
|
1275
1252
|
> = {
|
|
1276
|
-
editor: new Set(["
|
|
1253
|
+
editor: new Set(["on", "off"]),
|
|
1277
1254
|
userMessages: new Set([
|
|
1278
1255
|
"framed",
|
|
1279
1256
|
"framed-copy-friendly",
|
|
@@ -1441,7 +1418,6 @@ function applyEditorComponentPatch(
|
|
|
1441
1418
|
patch: Partial<
|
|
1442
1419
|
Pick<
|
|
1443
1420
|
EditorComponentConfig,
|
|
1444
|
-
| "enabled"
|
|
1445
1421
|
| "style"
|
|
1446
1422
|
| "colorSource"
|
|
1447
1423
|
| "borderColorMode"
|
|
@@ -1450,7 +1426,6 @@ function applyEditorComponentPatch(
|
|
|
1450
1426
|
>
|
|
1451
1427
|
>,
|
|
1452
1428
|
): void {
|
|
1453
|
-
if (patch.enabled !== undefined) component.enabled = patch.enabled;
|
|
1454
1429
|
if (patch.style !== undefined) component.style = patch.style;
|
|
1455
1430
|
if (patch.colorSource !== undefined)
|
|
1456
1431
|
component.colorSource = patch.colorSource;
|
|
@@ -1466,7 +1441,6 @@ export function saveEditorComponentPatch(
|
|
|
1466
1441
|
patch: Partial<
|
|
1467
1442
|
Pick<
|
|
1468
1443
|
EditorComponentConfig,
|
|
1469
|
-
| "enabled"
|
|
1470
1444
|
| "style"
|
|
1471
1445
|
| "colorSource"
|
|
1472
1446
|
| "borderColorMode"
|
|
@@ -1483,19 +1457,6 @@ export function saveEditorComponentPatch(
|
|
|
1483
1457
|
);
|
|
1484
1458
|
}
|
|
1485
1459
|
|
|
1486
|
-
export function savePolishedEditorStylePatch(
|
|
1487
|
-
patch: Partial<PolishedEditorStyleConfig>,
|
|
1488
|
-
path = configPath,
|
|
1489
|
-
): PolishedTuiConfig {
|
|
1490
|
-
return saveComponentsMutation((components) => {
|
|
1491
|
-
const style = components.editor.styles.opencode;
|
|
1492
|
-
if (patch.metadataFormat !== undefined)
|
|
1493
|
-
style.metadataFormat = patch.metadataFormat;
|
|
1494
|
-
if (patch.completionMenu !== undefined)
|
|
1495
|
-
style.completionMenu = patch.completionMenu;
|
|
1496
|
-
}, path);
|
|
1497
|
-
}
|
|
1498
|
-
|
|
1499
1460
|
function applyMinimalistStylePatch(
|
|
1500
1461
|
style: MinimalistEditorStyleConfig,
|
|
1501
1462
|
patch: Partial<MinimalistEditorStyleConfig>,
|
|
@@ -1695,7 +1656,7 @@ export function saveUiFeaturesPatch(
|
|
|
1695
1656
|
return saveComponentsMutation(
|
|
1696
1657
|
(components) => {
|
|
1697
1658
|
if (valid.editor !== undefined) {
|
|
1698
|
-
components.editor.
|
|
1659
|
+
components.editor.style = valid.editor ? "on" : "off";
|
|
1699
1660
|
components.userMessages.enabled = valid.editor;
|
|
1700
1661
|
components.selectorBorders.enabled = valid.editor;
|
|
1701
1662
|
}
|
package/extensions/app/panel.ts
CHANGED
|
@@ -23,10 +23,11 @@ import {
|
|
|
23
23
|
} from "./config/renderer.ts";
|
|
24
24
|
import {
|
|
25
25
|
type EditorComponentConfig,
|
|
26
|
-
type EditorStyle,
|
|
27
26
|
type FooterComponentConfig,
|
|
28
27
|
type FooterStyle,
|
|
29
28
|
loadConfig as loadShellConfig,
|
|
29
|
+
saveColorSourcesPatch,
|
|
30
|
+
saveEditorBorderColorMode,
|
|
30
31
|
saveEditorComponentPatch,
|
|
31
32
|
saveFooterComponentPatch,
|
|
32
33
|
saveUserMessagesComponentPatch,
|
|
@@ -40,7 +41,6 @@ import { overlayManager } from "./overlay/overlay-manager.ts";
|
|
|
40
41
|
import { ownerFor } from "./ownership.ts";
|
|
41
42
|
import { applyPreset, PRESET_VALUES, type Preset } from "./presets.ts";
|
|
42
43
|
|
|
43
|
-
const EDITOR_STYLES: EditorStyle[] = ["opencode", "minimalist"];
|
|
44
44
|
const MESSAGE_STYLES: UserMessageStyle[] = [
|
|
45
45
|
"framed",
|
|
46
46
|
"framed-copy-friendly",
|
|
@@ -126,18 +126,28 @@ function editorItems(): SettingItem[] {
|
|
|
126
126
|
const config = loadShellConfig();
|
|
127
127
|
return [
|
|
128
128
|
{
|
|
129
|
-
id: "
|
|
129
|
+
id: "editorStyle",
|
|
130
130
|
label: "Editor",
|
|
131
|
-
description:
|
|
132
|
-
|
|
131
|
+
description:
|
|
132
|
+
"on applies the Minimalist decoration; off restores Pi's native editor.",
|
|
133
|
+
currentValue: config.components.editor.style,
|
|
133
134
|
values: ["on", "off"],
|
|
134
135
|
},
|
|
135
136
|
{
|
|
136
|
-
id: "
|
|
137
|
-
label: "
|
|
138
|
-
description:
|
|
139
|
-
|
|
140
|
-
|
|
137
|
+
id: "editorColorSource",
|
|
138
|
+
label: "Color source",
|
|
139
|
+
description:
|
|
140
|
+
"theme resolves colors through the active Pi theme; terminal uses fixed terminal colors.",
|
|
141
|
+
currentValue: config.components.editor.colorSource,
|
|
142
|
+
values: ["theme", "terminal"],
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
id: "editorBorderColorMode",
|
|
146
|
+
label: "Border color",
|
|
147
|
+
description:
|
|
148
|
+
"static keeps one border color; adaptive shifts the border with the effort level.",
|
|
149
|
+
currentValue: config.components.editor.borderColorMode,
|
|
150
|
+
values: ["static", "adaptive"],
|
|
141
151
|
},
|
|
142
152
|
];
|
|
143
153
|
}
|
|
@@ -429,18 +439,31 @@ function updateSetting(
|
|
|
429
439
|
ctx: any,
|
|
430
440
|
deps: UnifiedPanelDeps,
|
|
431
441
|
): void {
|
|
432
|
-
if (id === "
|
|
433
|
-
if (deps.runtime)
|
|
434
|
-
|
|
435
|
-
else saveEditorComponentPatch({ enabled: isOn(value) });
|
|
442
|
+
if (id === "editorStyle" && (value === "on" || value === "off")) {
|
|
443
|
+
if (deps.runtime) deps.runtime.setEditorComponent({ style: value }, ctx);
|
|
444
|
+
else saveEditorComponentPatch({ style: value });
|
|
436
445
|
saveNotice(ctx, "Editor", value);
|
|
437
446
|
return;
|
|
438
447
|
}
|
|
439
|
-
if (
|
|
448
|
+
if (
|
|
449
|
+
id === "editorColorSource" &&
|
|
450
|
+
(value === "theme" || value === "terminal")
|
|
451
|
+
) {
|
|
440
452
|
if (deps.runtime)
|
|
441
|
-
deps.runtime.setEditorComponent({
|
|
442
|
-
else
|
|
443
|
-
saveNotice(ctx, "
|
|
453
|
+
deps.runtime.setEditorComponent({ colorSource: value }, ctx);
|
|
454
|
+
else saveColorSourcesPatch({ editor: value });
|
|
455
|
+
saveNotice(ctx, "Color source", value);
|
|
456
|
+
return;
|
|
457
|
+
}
|
|
458
|
+
if (id === "editorBorderColorMode") {
|
|
459
|
+
const valid =
|
|
460
|
+
value === "static" || value === "adaptive" ? value : undefined;
|
|
461
|
+
if (valid) {
|
|
462
|
+
if (deps.runtime)
|
|
463
|
+
deps.runtime.setEditorComponent({ borderColorMode: valid }, ctx);
|
|
464
|
+
else saveEditorBorderColorMode(valid);
|
|
465
|
+
saveNotice(ctx, "Border color", value);
|
|
466
|
+
}
|
|
444
467
|
return;
|
|
445
468
|
}
|
|
446
469
|
if (id === "userMessagesEnabled") {
|
|
@@ -615,7 +638,7 @@ export async function showOneUiPanel(
|
|
|
615
638
|
createList();
|
|
616
639
|
list.selectItem(id);
|
|
617
640
|
} finally {
|
|
618
|
-
if (id === "
|
|
641
|
+
if (id === "editorStyle") {
|
|
619
642
|
panelHandle?.focus();
|
|
620
643
|
}
|
|
621
644
|
tui.requestRender();
|
|
@@ -17,7 +17,7 @@ export function isPreset(value: string): value is Preset {
|
|
|
17
17
|
/** Apply only ownership-related values; detailed options remain user-editable. */
|
|
18
18
|
export function applyPreset(preset: Preset): void {
|
|
19
19
|
if (preset === "native") {
|
|
20
|
-
saveEditorComponentPatch({
|
|
20
|
+
saveEditorComponentPatch({ style: "off" });
|
|
21
21
|
saveUserMessagesComponentPatch({ enabled: false });
|
|
22
22
|
saveWorkingLineComponentPatch({ enabled: false });
|
|
23
23
|
saveFooterComponentPatch({ style: "native" });
|
|
@@ -25,7 +25,7 @@ export function applyPreset(preset: Preset): void {
|
|
|
25
25
|
return;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
saveEditorComponentPatch({
|
|
28
|
+
saveEditorComponentPatch({ style: "on" });
|
|
29
29
|
saveUserMessagesComponentPatch({ enabled: true });
|
|
30
30
|
saveWorkingLineComponentPatch({ enabled: true });
|
|
31
31
|
saveFooterComponentPatch({ style: "starship" });
|
|
@@ -47,6 +47,10 @@ import {
|
|
|
47
47
|
setMessageDisplayTheme,
|
|
48
48
|
} from "./tool/message-display.ts";
|
|
49
49
|
import { clearAllAnimations } from "./tool/result.ts";
|
|
50
|
+
import {
|
|
51
|
+
installToggleRenderCache,
|
|
52
|
+
type ToggleRenderCacheHooks,
|
|
53
|
+
} from "./tool/toggle-render-cache.ts";
|
|
50
54
|
|
|
51
55
|
/**
|
|
52
56
|
* Claude Code Style for pi — 装配入口。
|
|
@@ -143,6 +147,7 @@ export default function (
|
|
|
143
147
|
| {
|
|
144
148
|
defaultMode: DefaultModeHooks;
|
|
145
149
|
toolGrouping: ToolGroupingHooks;
|
|
150
|
+
toggleRenderCache: ToggleRenderCacheHooks;
|
|
146
151
|
compactMode: CompactModeHooks;
|
|
147
152
|
disposeMessageDisplay: () => void;
|
|
148
153
|
disposeToolExpandedBackground: () => void;
|
|
@@ -162,12 +167,15 @@ export default function (
|
|
|
162
167
|
});
|
|
163
168
|
compactModeHooks = compactMode;
|
|
164
169
|
const disposeMessageDisplay = installMessageDisplayRendering();
|
|
170
|
+
// 跨 toggle 重建缓存必须在展开背景 patch 之下(背景后装外层,shutdown 先拆)。
|
|
171
|
+
const toggleRenderCache = installToggleRenderCache();
|
|
165
172
|
// 展开背景必须在 compact-mode 之后装,shutdown 时先于 compact 释放。
|
|
166
173
|
const disposeToolExpandedBackground = installToolExpandedBackground();
|
|
167
174
|
deactivateLegacyCompactionRendering();
|
|
168
175
|
installation = {
|
|
169
176
|
defaultMode,
|
|
170
177
|
toolGrouping,
|
|
178
|
+
toggleRenderCache,
|
|
171
179
|
compactMode,
|
|
172
180
|
disposeMessageDisplay,
|
|
173
181
|
disposeToolExpandedBackground,
|
|
@@ -180,6 +188,9 @@ export default function (
|
|
|
180
188
|
applyStyleMode(mode, ctx, installation?.toolGrouping),
|
|
181
189
|
updateConfig: (partial, ctx) => {
|
|
182
190
|
updateConfig(partial);
|
|
191
|
+
// 配置(如 expandedPreviewMaxLines / excludeRenderers)变化可能改变
|
|
192
|
+
// 渲染结果:丢弃工具卡跨 toggle 缓存,下次 updateDisplay 重建。
|
|
193
|
+
installation?.toggleRenderCache.clear();
|
|
183
194
|
refreshCurrentContext(ctx, installation?.toolGrouping);
|
|
184
195
|
},
|
|
185
196
|
});
|
|
@@ -213,6 +224,7 @@ export default function (
|
|
|
213
224
|
installToolMouseInteraction(ctx, mouseOwner);
|
|
214
225
|
if (!hooks) return;
|
|
215
226
|
hooks.toolGrouping.setTheme(ctx.ui.theme);
|
|
227
|
+
hooks.toggleRenderCache.setTheme(ctx.ui.theme);
|
|
216
228
|
setMessageDisplayTheme(ctx.ui.theme);
|
|
217
229
|
ctx.ui.setStatus("ccstyle", undefined);
|
|
218
230
|
// Collect the resumed context before syncing compact patches and expansion state.
|
|
@@ -231,6 +243,7 @@ export default function (
|
|
|
231
243
|
installToolMouseInteraction(ctx, mouseOwner);
|
|
232
244
|
if (!hooks) return;
|
|
233
245
|
hooks.toolGrouping.setTheme(ctx.ui.theme);
|
|
246
|
+
hooks.toggleRenderCache.setTheme(ctx.ui.theme);
|
|
234
247
|
setMessageDisplayTheme(ctx.ui.theme);
|
|
235
248
|
syncCompactMode(ctx);
|
|
236
249
|
scheduleSessionRender(() => {
|
|
@@ -248,6 +261,7 @@ export default function (
|
|
|
248
261
|
|
|
249
262
|
pi.on("tool_execution_start", async (_event, ctx) => {
|
|
250
263
|
installation?.toolGrouping.setTheme(ctx.ui.theme);
|
|
264
|
+
installation?.toggleRenderCache.setTheme(ctx.ui.theme);
|
|
251
265
|
});
|
|
252
266
|
|
|
253
267
|
pi.on("session_shutdown", async () => {
|
|
@@ -260,6 +274,7 @@ export default function (
|
|
|
260
274
|
current.defaultMode.shutdown();
|
|
261
275
|
current.toolGrouping.shutdown();
|
|
262
276
|
current.disposeToolExpandedBackground();
|
|
277
|
+
current.toggleRenderCache.shutdown();
|
|
263
278
|
current.compactMode.shutdown();
|
|
264
279
|
compactModeHooks = undefined;
|
|
265
280
|
current.disposeMessageDisplay();
|