pi-zentui 0.1.10 → 0.1.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +112 -119
- package/extensions/zentui/config.ts +23 -3
- package/extensions/zentui/index.ts +4 -10
- package/extensions/zentui/style.ts +34 -3
- package/extensions/zentui/ui.ts +73 -11
- package/extensions/zentui/user-message.ts +30 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -25,9 +25,9 @@ Zentui brings two popular aesthetics to Pi:
|
|
|
25
25
|
|
|
26
26
|
### Editor (Opencode-inspired)
|
|
27
27
|
|
|
28
|
-
- Bordered input box with
|
|
28
|
+
- Bordered input box with configurable accent rail and border colors
|
|
29
29
|
- Model name and provider displayed inside the editor frame
|
|
30
|
-
-
|
|
30
|
+
- Configurable model, provider, and thinking-level indicator colors
|
|
31
31
|
- Prompt-box-style user messages matching the ZentUI input chrome
|
|
32
32
|
|
|
33
33
|
### Git Status Icons
|
|
@@ -49,65 +49,65 @@ Zentui brings two popular aesthetics to Pi:
|
|
|
49
49
|
|
|
50
50
|
Detects Starship Nerd Font runtime/language modules, uses the Starship Nerd Font symbols, and keeps Starship-style defaults such as `bold green` for Node.js. By default Zentui maps those styles through your active Pi theme; switch the Starship/footer color source to `terminal` in `/zentui` if you want your terminal colorscheme to supply the exact ANSI colors.
|
|
51
51
|
|
|
52
|
-
| Runtime/language | Detection examples
|
|
53
|
-
| ---------------- |
|
|
54
|
-
| Buf | `buf.yaml`, `buf.gen.yaml`, `buf.work.yaml`
|
|
55
|
-
| Bun | `bun.lock`, `bun.lockb`
|
|
56
|
-
| C | `.c`, `.h` files
|
|
57
|
-
| C++ | `.cpp`, `.cc`, `.cxx`, `.hpp` files
|
|
58
|
-
| CMake | `CMakeLists.txt`, `CMakeCache.txt`
|
|
59
|
-
| COBOL | `.cbl`, `.cob` files
|
|
60
|
-
| Conda | `CONDA_DEFAULT_ENV` environment
|
|
61
|
-
| Crystal | `.cr` files, `shard.yml`
|
|
62
|
-
| Dart | `.dart` files, `pubspec.yaml`, `.dart_tool/`
|
|
63
|
-
| Deno | `deno.json`, `deno.jsonc`, `deno.lock`
|
|
64
|
-
| .NET | `.csproj`, `.fsproj`, `global.json`, `Directory.Build.*`
|
|
65
|
-
| Elixir | `mix.exs`
|
|
66
|
-
| Elm | `.elm` files, `elm.json`, `elm-stuff/`
|
|
67
|
-
| Erlang | `rebar.config`, `erlang.mk`
|
|
68
|
-
| Fennel | `.fnl` files
|
|
69
|
-
| Fortran | `.f`, `.f90`, `.f95`, `.f03`, `.f08`, `.f18`, `fpm.toml`
|
|
70
|
-
| Gleam | `.gleam` files, `gleam.toml`
|
|
71
|
-
| Go | `go.mod`
|
|
72
|
-
| Gradle | `build.gradle`, `build.gradle.kts`, `gradle/`
|
|
73
|
-
| Guix shell | `GUIX_ENVIRONMENT` environment
|
|
74
|
-
| Haskell | `.hs`, `.cabal`, `stack.yaml`, `cabal.project`
|
|
75
|
-
| Haxe | `.hx`, `.hxml`, `haxelib.json`, `.haxerc`
|
|
76
|
-
| Helm | `helmfile.yaml`, `Chart.yaml`
|
|
77
|
-
| Java | `.java-version`
|
|
78
|
-
| Julia | `.jl` files, `Project.toml`, `Manifest.toml`
|
|
79
|
-
| Kotlin | `.kt`, `.kts` files
|
|
80
|
-
| Lua | `.lua` files, `stylua.toml`, `.luarc.json`, `lua/` dir
|
|
81
|
-
| Maven | `pom.xml`
|
|
82
|
-
| Meson | `MESON_DEVENV=1` and `MESON_PROJECT_NAME` environment
|
|
83
|
-
| Mojo | `.mojo` files
|
|
84
|
-
| Nim | `.nim`, `.nims`, `.nimble`, `nim.cfg`
|
|
85
|
-
| Nix shell | `IN_NIX_SHELL=pure` or `IN_NIX_SHELL=impure` environment
|
|
86
|
-
| Node.js | `package.json`, `.nvmrc`, `.node-version`
|
|
87
|
-
| OCaml | `.opam`, `.ml`, `.mli`, `dune`, `_opam/`, `esy.lock/`
|
|
88
|
-
| Odin | `.odin` files
|
|
89
|
-
| OPA/Rego | `.rego` files
|
|
90
|
-
| Perl | `.pl`, `.pm`, `Makefile.PL`, `cpanfile`, `META.*`
|
|
91
|
-
| PHP | `composer.json`
|
|
52
|
+
| Runtime/language | Detection examples |
|
|
53
|
+
| ---------------- | ------------------------------------------------------------- |
|
|
54
|
+
| Buf | `buf.yaml`, `buf.gen.yaml`, `buf.work.yaml` |
|
|
55
|
+
| Bun | `bun.lock`, `bun.lockb` |
|
|
56
|
+
| C | `.c`, `.h` files |
|
|
57
|
+
| C++ | `.cpp`, `.cc`, `.cxx`, `.hpp` files |
|
|
58
|
+
| CMake | `CMakeLists.txt`, `CMakeCache.txt` |
|
|
59
|
+
| COBOL | `.cbl`, `.cob` files |
|
|
60
|
+
| Conda | `CONDA_DEFAULT_ENV` environment |
|
|
61
|
+
| Crystal | `.cr` files, `shard.yml` |
|
|
62
|
+
| Dart | `.dart` files, `pubspec.yaml`, `.dart_tool/` |
|
|
63
|
+
| Deno | `deno.json`, `deno.jsonc`, `deno.lock` |
|
|
64
|
+
| .NET | `.csproj`, `.fsproj`, `global.json`, `Directory.Build.*` |
|
|
65
|
+
| Elixir | `mix.exs` |
|
|
66
|
+
| Elm | `.elm` files, `elm.json`, `elm-stuff/` |
|
|
67
|
+
| Erlang | `rebar.config`, `erlang.mk` |
|
|
68
|
+
| Fennel | `.fnl` files |
|
|
69
|
+
| Fortran | `.f`, `.f90`, `.f95`, `.f03`, `.f08`, `.f18`, `fpm.toml` |
|
|
70
|
+
| Gleam | `.gleam` files, `gleam.toml` |
|
|
71
|
+
| Go | `go.mod` |
|
|
72
|
+
| Gradle | `build.gradle`, `build.gradle.kts`, `gradle/` |
|
|
73
|
+
| Guix shell | `GUIX_ENVIRONMENT` environment |
|
|
74
|
+
| Haskell | `.hs`, `.cabal`, `stack.yaml`, `cabal.project` |
|
|
75
|
+
| Haxe | `.hx`, `.hxml`, `haxelib.json`, `.haxerc` |
|
|
76
|
+
| Helm | `helmfile.yaml`, `Chart.yaml` |
|
|
77
|
+
| Java | `.java-version` |
|
|
78
|
+
| Julia | `.jl` files, `Project.toml`, `Manifest.toml` |
|
|
79
|
+
| Kotlin | `.kt`, `.kts` files |
|
|
80
|
+
| Lua | `.lua` files, `stylua.toml`, `.luarc.json`, `lua/` dir |
|
|
81
|
+
| Maven | `pom.xml` |
|
|
82
|
+
| Meson | `MESON_DEVENV=1` and `MESON_PROJECT_NAME` environment |
|
|
83
|
+
| Mojo | `.mojo` files |
|
|
84
|
+
| Nim | `.nim`, `.nims`, `.nimble`, `nim.cfg` |
|
|
85
|
+
| Nix shell | `IN_NIX_SHELL=pure` or `IN_NIX_SHELL=impure` environment |
|
|
86
|
+
| Node.js | `package.json`, `.nvmrc`, `.node-version` |
|
|
87
|
+
| OCaml | `.opam`, `.ml`, `.mli`, `dune`, `_opam/`, `esy.lock/` |
|
|
88
|
+
| Odin | `.odin` files |
|
|
89
|
+
| OPA/Rego | `.rego` files |
|
|
90
|
+
| Perl | `.pl`, `.pm`, `Makefile.PL`, `cpanfile`, `META.*` |
|
|
91
|
+
| PHP | `composer.json` |
|
|
92
92
|
| Pixi | `pixi.toml`, `pixi.lock`, `PIXI_ENVIRONMENT_NAME` environment |
|
|
93
|
-
| Pulumi | `Pulumi.yaml`, `Pulumi.yml`
|
|
94
|
-
| PureScript | `.purs` files, `spago.dhall`, `spago.yaml`, `spago.lock`
|
|
95
|
-
| Python | `pyproject.toml`, `requirements.txt`, `setup.py`, `Pipfile`
|
|
96
|
-
| R | `.R`, `.Rmd`, `.Rproj`, `DESCRIPTION`, `.Rproj.user/`
|
|
97
|
-
| Raku | `.raku`, `.rakumod`, `.p6`, `.pm6`, `META6.json`
|
|
98
|
-
| Red | `.red`, `.reds` files
|
|
99
|
-
| Ruby | `Gemfile`, `.ruby-version`
|
|
93
|
+
| Pulumi | `Pulumi.yaml`, `Pulumi.yml` |
|
|
94
|
+
| PureScript | `.purs` files, `spago.dhall`, `spago.yaml`, `spago.lock` |
|
|
95
|
+
| Python | `pyproject.toml`, `requirements.txt`, `setup.py`, `Pipfile` |
|
|
96
|
+
| R | `.R`, `.Rmd`, `.Rproj`, `DESCRIPTION`, `.Rproj.user/` |
|
|
97
|
+
| Raku | `.raku`, `.rakumod`, `.p6`, `.pm6`, `META6.json` |
|
|
98
|
+
| Red | `.red`, `.reds` files |
|
|
99
|
+
| Ruby | `Gemfile`, `.ruby-version` |
|
|
100
100
|
| Rust | `Cargo.toml` |
|
|
101
|
-
| Scala | `.scala`, `.sbt`, `build.sbt`, `.metals/`
|
|
102
|
-
| Solidity | `.sol` files
|
|
103
|
-
| Spack | `SPACK_ENV` environment
|
|
104
|
-
| Swift | `.swift` files, `Package.swift`
|
|
105
|
-
| Terraform | `.tf`, `.tfplan`, `.tfstate`, `.terraform/`
|
|
106
|
-
| Typst | `.typ` files, `template.typ`
|
|
107
|
-
| Vagrant | `Vagrantfile`
|
|
108
|
-
| V | `.v` files, `v.mod`, `vpkg.json`
|
|
109
|
-
| Xmake | `xmake.lua`
|
|
110
|
-
| Zig | `.zig` files, `build.zig`
|
|
101
|
+
| Scala | `.scala`, `.sbt`, `build.sbt`, `.metals/` |
|
|
102
|
+
| Solidity | `.sol` files |
|
|
103
|
+
| Spack | `SPACK_ENV` environment |
|
|
104
|
+
| Swift | `.swift` files, `Package.swift` |
|
|
105
|
+
| Terraform | `.tf`, `.tfplan`, `.tfstate`, `.terraform/` |
|
|
106
|
+
| Typst | `.typ` files, `template.typ` |
|
|
107
|
+
| Vagrant | `Vagrantfile` |
|
|
108
|
+
| V | `.v` files, `v.mod`, `vpkg.json` |
|
|
109
|
+
| Xmake | `xmake.lua` |
|
|
110
|
+
| Zig | `.zig` files, `build.zig` |
|
|
111
111
|
|
|
112
112
|
## Install
|
|
113
113
|
|
|
@@ -121,73 +121,66 @@ pi install git:github.com/lmilojevicc/pi-zentui
|
|
|
121
121
|
|
|
122
122
|
## Config
|
|
123
123
|
|
|
124
|
-
|
|
124
|
+
User config lives at `~/.pi/agent/zentui.json`. The file is optional: missing or invalid known values fall back to Zentui defaults, unknown keys are ignored at runtime, and `/zentui` currently patches only color-source settings.
|
|
125
125
|
|
|
126
|
-
|
|
127
|
-
~/.pi/agent/zentui.json
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
Zentui treats this file as user-owned and compatibility-sensitive: invalid known values fall back to runtime defaults, unknown keys are ignored at runtime, and `/zentui` patches only the settings it changes instead of rewriting the whole file.
|
|
131
|
-
|
|
132
|
-
### Runtime defaults
|
|
126
|
+
Default config values — copy this and change any value you want:
|
|
133
127
|
|
|
134
128
|
```json
|
|
135
129
|
{
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
130
|
+
"projectRefreshIntervalMs": 30000,
|
|
131
|
+
"icons": {
|
|
132
|
+
"cwd": "",
|
|
133
|
+
"git": "",
|
|
134
|
+
"ahead": "↑",
|
|
135
|
+
"behind": "↓",
|
|
136
|
+
"diverged": "⇕",
|
|
137
|
+
"conflicted": "=",
|
|
138
|
+
"untracked": "?",
|
|
139
|
+
"stashed": "$",
|
|
140
|
+
"modified": "!",
|
|
141
|
+
"staged": "+",
|
|
142
|
+
"renamed": "»",
|
|
143
|
+
"deleted": "✘",
|
|
144
|
+
"typechanged": "T"
|
|
145
|
+
},
|
|
146
|
+
"colors": {
|
|
147
|
+
"cwd": "bold cyan",
|
|
148
|
+
"gitBranch": "bold purple",
|
|
149
|
+
"gitStatus": "bold red",
|
|
150
|
+
"contextNormal": "bright-black",
|
|
151
|
+
"contextWarning": "bold yellow",
|
|
152
|
+
"contextError": "bold red",
|
|
153
|
+
"tokens": "bright-black",
|
|
154
|
+
"cost": "bold green",
|
|
155
|
+
"separator": "bright-black",
|
|
156
|
+
"runtimePrefix": "",
|
|
157
|
+
"editorAccent": "accent",
|
|
158
|
+
"editorBorder": "borderMuted",
|
|
159
|
+
"editorModel": "accent",
|
|
160
|
+
"editorProvider": "text",
|
|
161
|
+
"editorThinking": "muted",
|
|
162
|
+
"editorThinkingMinimal": "thinkingMinimal",
|
|
163
|
+
"editorThinkingLow": "thinkingLow",
|
|
164
|
+
"editorThinkingMedium": "thinkingMedium",
|
|
165
|
+
"editorThinkingHigh": "thinkingHigh",
|
|
166
|
+
"editorThinkingXhigh": "thinkingXhigh"
|
|
167
|
+
},
|
|
168
|
+
"colorSources": {
|
|
169
|
+
"starship": "theme",
|
|
170
|
+
"editor": "theme",
|
|
171
|
+
"userMessages": "theme"
|
|
172
|
+
}
|
|
169
173
|
}
|
|
170
174
|
```
|
|
171
175
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
- `
|
|
179
|
-
- `
|
|
180
|
-
|
|
181
|
-
Both settings default to `theme`. The config still stores editor and previous user-message sources separately as `editor` and `userMessages`, but `/zentui` changes them together so the prompt chrome stays consistent.
|
|
182
|
-
|
|
183
|
-
Color values can use terminal-palette style strings, hex colors, or Pi theme color tokens:
|
|
184
|
-
|
|
185
|
-
- Named terminal colors: `bold purple`, `yellow`, `bright-cyan`
|
|
186
|
-
- 256-color / hex: `bold 149`, `fg:202`, `#89b4fa`
|
|
187
|
-
- Backgrounds and modifiers: `bg:blue fg:bright-green`, `underline bg:#bf5700`
|
|
188
|
-
- Pi theme tokens: `accent`, `borderMuted`, `syntaxKeyword`
|
|
189
|
-
|
|
190
|
-
Use the `colors` config key for these values.
|
|
176
|
+
- Style values can be Starship/terminal strings (`bold purple`, `fg:202`, `#89b4fa`, `bg:blue fg:bright-green`) or Pi theme tokens (`accent`, `borderMuted`, `thinkingHigh`).
|
|
177
|
+
- `projectRefreshIntervalMs`: project status polling interval; `0` disables polling.
|
|
178
|
+
- `icons`: every shown icon key is configurable; omit any key to use the Zentui default.
|
|
179
|
+
- `colorSources`: `theme` maps styles through Pi theme tokens; `terminal` emits terminal colors. `/zentui` switches these sources; manual JSON controls specific style values.
|
|
180
|
+
- The shown `editor*` values match the default `theme` source. Omit those keys to keep Zentui's source-aware defaults when switching between `theme` and `terminal`.
|
|
181
|
+
- `editorAccent` styles the active editor rail and previous user-message rail.
|
|
182
|
+
- `editorBorder` styles the active editor and previous user-message top/bottom border color only; the border glyph stays `─`.
|
|
183
|
+
- `editorModel`, `editorProvider`, and `editorThinking*` style the editor metadata. `editorThinking` applies to every non-`off` thinking level unless a level-specific key is set.
|
|
191
184
|
|
|
192
185
|
## Requirements
|
|
193
186
|
|
|
@@ -43,6 +43,16 @@ export type PolishedTuiConfig = {
|
|
|
43
43
|
cost: ColorSpec;
|
|
44
44
|
separator: ColorSpec;
|
|
45
45
|
runtimePrefix: ColorSpec;
|
|
46
|
+
editorAccent?: ColorSpec;
|
|
47
|
+
editorBorder?: ColorSpec;
|
|
48
|
+
editorModel?: ColorSpec;
|
|
49
|
+
editorProvider?: ColorSpec;
|
|
50
|
+
editorThinking?: ColorSpec;
|
|
51
|
+
editorThinkingMinimal?: ColorSpec;
|
|
52
|
+
editorThinkingLow?: ColorSpec;
|
|
53
|
+
editorThinkingMedium?: ColorSpec;
|
|
54
|
+
editorThinkingHigh?: ColorSpec;
|
|
55
|
+
editorThinkingXhigh?: ColorSpec;
|
|
46
56
|
};
|
|
47
57
|
colorSources: ColorSourcesConfig;
|
|
48
58
|
};
|
|
@@ -70,12 +80,12 @@ export const defaultConfig: PolishedTuiConfig = {
|
|
|
70
80
|
cwd: "bold cyan",
|
|
71
81
|
gitBranch: "bold purple",
|
|
72
82
|
gitStatus: "bold red",
|
|
73
|
-
contextNormal: "
|
|
83
|
+
contextNormal: "bright-black",
|
|
74
84
|
contextWarning: "bold yellow",
|
|
75
85
|
contextError: "bold red",
|
|
76
|
-
tokens: "
|
|
86
|
+
tokens: "bright-black",
|
|
77
87
|
cost: "bold green",
|
|
78
|
-
separator: "
|
|
88
|
+
separator: "bright-black",
|
|
79
89
|
runtimePrefix: "",
|
|
80
90
|
},
|
|
81
91
|
colorSources: {
|
|
@@ -168,6 +178,16 @@ function normalizeColors(record: Record<string, unknown>): Partial<PolishedTuiCo
|
|
|
168
178
|
cost: colorValue(record, "cost"),
|
|
169
179
|
separator: colorValue(record, "separator"),
|
|
170
180
|
runtimePrefix: colorValue(record, "runtimePrefix"),
|
|
181
|
+
editorAccent: colorValue(record, "editorAccent"),
|
|
182
|
+
editorBorder: colorValue(record, "editorBorder"),
|
|
183
|
+
editorModel: colorValue(record, "editorModel"),
|
|
184
|
+
editorProvider: colorValue(record, "editorProvider"),
|
|
185
|
+
editorThinking: colorValue(record, "editorThinking"),
|
|
186
|
+
editorThinkingMinimal: colorValue(record, "editorThinkingMinimal"),
|
|
187
|
+
editorThinkingLow: colorValue(record, "editorThinkingLow"),
|
|
188
|
+
editorThinkingMedium: colorValue(record, "editorThinkingMedium"),
|
|
189
|
+
editorThinkingHigh: colorValue(record, "editorThinkingHigh"),
|
|
190
|
+
editorThinkingXhigh: colorValue(record, "editorThinkingXhigh"),
|
|
171
191
|
});
|
|
172
192
|
}
|
|
173
193
|
|
|
@@ -19,7 +19,6 @@ import { readRuntimeInfo } from "./runtime";
|
|
|
19
19
|
import { installSelectorBorderStyle } from "./selector-border";
|
|
20
20
|
import { registerZentuiSettingsCommand } from "./settings-command";
|
|
21
21
|
import { type FooterState, createInitialState, syncState } from "./state";
|
|
22
|
-
import { renderAccentLine, safeThemeFg } from "./style";
|
|
23
22
|
import { PolishedEditor } from "./ui";
|
|
24
23
|
import { installUserMessageStyle } from "./user-message";
|
|
25
24
|
|
|
@@ -81,15 +80,10 @@ export default function (pi: ExtensionAPI) {
|
|
|
81
80
|
keybindings,
|
|
82
81
|
ctx.ui.theme,
|
|
83
82
|
getCurrentConfig,
|
|
84
|
-
() =>
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
getCurrentConfig().colorSources.editor,
|
|
89
|
-
state.modelLabel,
|
|
90
|
-
),
|
|
91
|
-
safeThemeFg(ctx.ui.theme, "text", state.providerLabel),
|
|
92
|
-
].join(safeThemeFg(ctx.ui.theme, "borderMuted", " ")),
|
|
83
|
+
() => ({
|
|
84
|
+
modelLabel: state.modelLabel,
|
|
85
|
+
providerLabel: state.providerLabel,
|
|
86
|
+
}),
|
|
93
87
|
getThinkingLevel,
|
|
94
88
|
),
|
|
95
89
|
);
|
|
@@ -13,6 +13,21 @@ export type { ThemeLike };
|
|
|
13
13
|
export const EDITOR_ACCENT_STYLE = "blue";
|
|
14
14
|
export const EDITOR_BORDER_STYLE = "bright-black";
|
|
15
15
|
|
|
16
|
+
export type SourceStyleFallback = {
|
|
17
|
+
theme: ColorSpec;
|
|
18
|
+
terminal: ColorSpec;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export const EDITOR_ACCENT_FALLBACK: SourceStyleFallback = {
|
|
22
|
+
theme: "accent",
|
|
23
|
+
terminal: EDITOR_ACCENT_STYLE,
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export const EDITOR_BORDER_FALLBACK: SourceStyleFallback = {
|
|
27
|
+
theme: "borderMuted",
|
|
28
|
+
terminal: EDITOR_BORDER_STYLE,
|
|
29
|
+
};
|
|
30
|
+
|
|
16
31
|
function isHexColor(value: string): boolean {
|
|
17
32
|
return /^#(?:[0-9a-fA-F]{6})$/.test(value);
|
|
18
33
|
}
|
|
@@ -267,6 +282,17 @@ export function renderStyleForSource(
|
|
|
267
282
|
: renderThemeStyle(theme, style, text);
|
|
268
283
|
}
|
|
269
284
|
|
|
285
|
+
export function renderStyleForSourceOrFallback(
|
|
286
|
+
theme: ThemeLike,
|
|
287
|
+
source: ColorSource,
|
|
288
|
+
style: ColorSpec | undefined,
|
|
289
|
+
fallback: ColorSpec | SourceStyleFallback,
|
|
290
|
+
text: string,
|
|
291
|
+
): string {
|
|
292
|
+
const fallbackStyle = typeof fallback === "string" ? fallback : fallback[source];
|
|
293
|
+
return renderStyleForSource(theme, source, style ?? fallbackStyle, text);
|
|
294
|
+
}
|
|
295
|
+
|
|
270
296
|
export function renderEditorAccent(text: string): string {
|
|
271
297
|
return renderTerminalStyle(EDITOR_ACCENT_STYLE, text);
|
|
272
298
|
}
|
|
@@ -276,7 +302,7 @@ export function renderEditorBorder(text: string): string {
|
|
|
276
302
|
}
|
|
277
303
|
|
|
278
304
|
export function renderAccentLine(theme: ThemeLike, source: ColorSource, text: string): string {
|
|
279
|
-
return
|
|
305
|
+
return renderStyleForSourceOrFallback(theme, source, undefined, EDITOR_ACCENT_FALLBACK, text);
|
|
280
306
|
}
|
|
281
307
|
|
|
282
308
|
export function renderChromeBorder(
|
|
@@ -285,6 +311,11 @@ export function renderChromeBorder(
|
|
|
285
311
|
terminalFallbackStyle: ColorSpec,
|
|
286
312
|
text: string,
|
|
287
313
|
): string {
|
|
288
|
-
|
|
289
|
-
|
|
314
|
+
return renderStyleForSourceOrFallback(
|
|
315
|
+
theme,
|
|
316
|
+
source,
|
|
317
|
+
undefined,
|
|
318
|
+
{ theme: "borderMuted", terminal: terminalFallbackStyle },
|
|
319
|
+
text,
|
|
320
|
+
);
|
|
290
321
|
}
|
package/extensions/zentui/ui.ts
CHANGED
|
@@ -7,20 +7,30 @@ import {
|
|
|
7
7
|
visibleWidth,
|
|
8
8
|
} from "@earendil-works/pi-tui";
|
|
9
9
|
import type { PolishedTuiConfig } from "./config";
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
EDITOR_ACCENT_FALLBACK,
|
|
12
|
+
EDITOR_BORDER_FALLBACK,
|
|
13
|
+
renderStyleForSourceOrFallback,
|
|
14
|
+
safeThemeFg,
|
|
15
|
+
} from "./style";
|
|
11
16
|
|
|
12
17
|
type AutocompleteEditorInternals = {
|
|
13
18
|
autocompleteList?: Pick<Component, "render">;
|
|
14
19
|
isShowingAutocomplete?: () => boolean;
|
|
15
20
|
};
|
|
16
21
|
|
|
22
|
+
type EditorMeta = {
|
|
23
|
+
modelLabel: string;
|
|
24
|
+
providerLabel: string;
|
|
25
|
+
};
|
|
26
|
+
|
|
17
27
|
function clampRenderedLines(lines: string[], width: number): string[] {
|
|
18
28
|
const maxWidth = Math.max(0, width);
|
|
19
29
|
return lines.map((line) => truncateToWidth(line, maxWidth, ""));
|
|
20
30
|
}
|
|
21
31
|
|
|
22
32
|
export class PolishedEditor extends CustomEditor {
|
|
23
|
-
private readonly getModelMeta: () =>
|
|
33
|
+
private readonly getModelMeta: () => EditorMeta;
|
|
24
34
|
private readonly getThinkingLevel: () => string | undefined;
|
|
25
35
|
private readonly getConfig: () => PolishedTuiConfig;
|
|
26
36
|
private readonly uiTheme: Theme;
|
|
@@ -32,7 +42,7 @@ export class PolishedEditor extends CustomEditor {
|
|
|
32
42
|
keybindings: KeybindingsManager,
|
|
33
43
|
uiTheme: Theme,
|
|
34
44
|
getConfig: () => PolishedTuiConfig,
|
|
35
|
-
getModelMeta: () =>
|
|
45
|
+
getModelMeta: () => EditorMeta,
|
|
36
46
|
getThinkingLevel: () => string | undefined,
|
|
37
47
|
) {
|
|
38
48
|
super(tui, theme, keybindings, { paddingX: 0 });
|
|
@@ -49,6 +59,23 @@ export class PolishedEditor extends CustomEditor {
|
|
|
49
59
|
return `${truncated}${pad}`;
|
|
50
60
|
}
|
|
51
61
|
|
|
62
|
+
private editorThinkingStyle(config: PolishedTuiConfig, level: string): string | undefined {
|
|
63
|
+
switch (level.toLowerCase()) {
|
|
64
|
+
case "minimal":
|
|
65
|
+
return config.colors.editorThinkingMinimal ?? config.colors.editorThinking;
|
|
66
|
+
case "low":
|
|
67
|
+
return config.colors.editorThinkingLow ?? config.colors.editorThinking;
|
|
68
|
+
case "medium":
|
|
69
|
+
return config.colors.editorThinkingMedium ?? config.colors.editorThinking;
|
|
70
|
+
case "high":
|
|
71
|
+
return config.colors.editorThinkingHigh ?? config.colors.editorThinking;
|
|
72
|
+
case "xhigh":
|
|
73
|
+
return config.colors.editorThinkingXhigh ?? config.colors.editorThinking;
|
|
74
|
+
default:
|
|
75
|
+
return config.colors.editorThinking;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
52
79
|
render(width: number): string[] {
|
|
53
80
|
if (width <= 2) {
|
|
54
81
|
return clampRenderedLines(super.render(width), width);
|
|
@@ -84,26 +111,61 @@ export class PolishedEditor extends CustomEditor {
|
|
|
84
111
|
return clampRenderedLines(rendered, width);
|
|
85
112
|
}
|
|
86
113
|
|
|
114
|
+
const config = this.getConfig();
|
|
115
|
+
const colorSource = config.colorSources.editor;
|
|
87
116
|
const editorLines = editorFrame.slice(1, -1);
|
|
88
|
-
const
|
|
117
|
+
const { modelLabel, providerLabel } = this.getModelMeta();
|
|
118
|
+
const model = renderStyleForSourceOrFallback(
|
|
119
|
+
this.uiTheme,
|
|
120
|
+
colorSource,
|
|
121
|
+
config.colors.editorModel,
|
|
122
|
+
EDITOR_ACCENT_FALLBACK,
|
|
123
|
+
modelLabel,
|
|
124
|
+
);
|
|
125
|
+
const provider = renderStyleForSourceOrFallback(
|
|
126
|
+
this.uiTheme,
|
|
127
|
+
colorSource,
|
|
128
|
+
config.colors.editorProvider,
|
|
129
|
+
"text",
|
|
130
|
+
providerLabel,
|
|
131
|
+
);
|
|
132
|
+
const modelMeta = [model, provider]
|
|
133
|
+
.filter(Boolean)
|
|
134
|
+
.join(safeThemeFg(this.uiTheme, "borderMuted", " "));
|
|
135
|
+
const metaParts = [modelMeta];
|
|
89
136
|
const thinkingLevel = this.getThinkingLevel();
|
|
90
137
|
if (thinkingLevel && thinkingLevel !== "off") {
|
|
91
|
-
metaParts.push(
|
|
138
|
+
metaParts.push(
|
|
139
|
+
renderStyleForSourceOrFallback(
|
|
140
|
+
this.uiTheme,
|
|
141
|
+
colorSource,
|
|
142
|
+
this.editorThinkingStyle(config, thinkingLevel),
|
|
143
|
+
"muted",
|
|
144
|
+
thinkingLevel,
|
|
145
|
+
),
|
|
146
|
+
);
|
|
92
147
|
}
|
|
93
148
|
const meta = metaParts.filter(Boolean).join(safeThemeFg(this.uiTheme, "border", " "));
|
|
94
149
|
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
|
|
150
|
+
const rail = `${renderStyleForSourceOrFallback(
|
|
151
|
+
this.uiTheme,
|
|
152
|
+
colorSource,
|
|
153
|
+
config.colors.editorAccent,
|
|
154
|
+
EDITOR_ACCENT_FALLBACK,
|
|
155
|
+
"│",
|
|
156
|
+
)}${this.reset} `;
|
|
157
|
+
const top = renderStyleForSourceOrFallback(
|
|
98
158
|
this.uiTheme,
|
|
99
159
|
colorSource,
|
|
100
|
-
|
|
160
|
+
config.colors.editorBorder,
|
|
161
|
+
EDITOR_BORDER_FALLBACK,
|
|
101
162
|
"─".repeat(width),
|
|
102
163
|
);
|
|
103
|
-
const bottom =
|
|
164
|
+
const bottom = renderStyleForSourceOrFallback(
|
|
104
165
|
this.uiTheme,
|
|
105
166
|
colorSource,
|
|
106
|
-
|
|
167
|
+
config.colors.editorBorder,
|
|
168
|
+
EDITOR_BORDER_FALLBACK,
|
|
107
169
|
"─".repeat(width),
|
|
108
170
|
);
|
|
109
171
|
const lines = ["", ...editorLines, "", meta];
|
|
@@ -6,7 +6,11 @@ import {
|
|
|
6
6
|
visibleWidth,
|
|
7
7
|
} from "@earendil-works/pi-tui";
|
|
8
8
|
import type { PolishedTuiConfig } from "./config";
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
EDITOR_ACCENT_FALLBACK,
|
|
11
|
+
EDITOR_BORDER_FALLBACK,
|
|
12
|
+
renderStyleForSourceOrFallback,
|
|
13
|
+
} from "./style";
|
|
10
14
|
|
|
11
15
|
const OSC133_ZONE_START = "\x1b]133;A\x07";
|
|
12
16
|
const OSC133_ZONE_END = "\x1b]133;B\x07";
|
|
@@ -92,7 +96,17 @@ function renderPromptBoxLine(
|
|
|
92
96
|
config: PolishedTuiConfig,
|
|
93
97
|
): string {
|
|
94
98
|
if (width <= 0) return "";
|
|
95
|
-
const rail = `${
|
|
99
|
+
const rail = `${
|
|
100
|
+
theme
|
|
101
|
+
? renderStyleForSourceOrFallback(
|
|
102
|
+
theme,
|
|
103
|
+
config.colorSources.userMessages,
|
|
104
|
+
config.colors.editorAccent,
|
|
105
|
+
EDITOR_ACCENT_FALLBACK,
|
|
106
|
+
"│",
|
|
107
|
+
)
|
|
108
|
+
: "│"
|
|
109
|
+
} `;
|
|
96
110
|
const contentWidth = Math.max(0, width - visibleWidth(rail));
|
|
97
111
|
return truncateToWidth(`${rail}${fillLine(line, contentWidth)}`, width, "");
|
|
98
112
|
}
|
|
@@ -108,7 +122,17 @@ function renderZentuiUserMessage(
|
|
|
108
122
|
if (width <= 0) return [""];
|
|
109
123
|
|
|
110
124
|
const railWidth = visibleWidth(
|
|
111
|
-
`${
|
|
125
|
+
`${
|
|
126
|
+
theme
|
|
127
|
+
? renderStyleForSourceOrFallback(
|
|
128
|
+
theme,
|
|
129
|
+
config.colorSources.userMessages,
|
|
130
|
+
config.colors.editorAccent,
|
|
131
|
+
EDITOR_ACCENT_FALLBACK,
|
|
132
|
+
"│",
|
|
133
|
+
)
|
|
134
|
+
: "│"
|
|
135
|
+
} `,
|
|
112
136
|
);
|
|
113
137
|
const contentWidth = Math.max(1, width - railWidth);
|
|
114
138
|
const renderer = new Markdown(text, 0, 0, makeMarkdownTheme(theme), {
|
|
@@ -117,10 +141,11 @@ function renderZentuiUserMessage(
|
|
|
117
141
|
const body = renderer.render(contentWidth);
|
|
118
142
|
const contentLines = body.length > 0 ? body : [""];
|
|
119
143
|
const border = theme
|
|
120
|
-
?
|
|
144
|
+
? renderStyleForSourceOrFallback(
|
|
121
145
|
theme,
|
|
122
146
|
config.colorSources.userMessages,
|
|
123
|
-
|
|
147
|
+
config.colors.editorBorder,
|
|
148
|
+
EDITOR_BORDER_FALLBACK,
|
|
124
149
|
"─".repeat(width),
|
|
125
150
|
)
|
|
126
151
|
: "─".repeat(width);
|