@selesai/code 0.8.1 → 0.8.3
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 +15 -0
- package/README.md +4 -2
- package/dist/cli/args.d.ts +2 -0
- package/dist/cli/args.js +18 -0
- package/dist/cli/config-selector.js +2 -2
- package/dist/cli/startup-ui.d.ts +1 -1
- package/dist/cli/startup-ui.js +2 -2
- package/dist/core/keybindings.d.ts +44 -4
- package/dist/core/llama/provider.js +22 -7
- package/dist/core/model-resolver.js +2 -0
- package/dist/core/model-runtime.d.ts +4 -2
- package/dist/core/model-runtime.js +23 -2
- package/dist/core/remote-catalog-provider.js +72 -67
- package/dist/core/settings-manager.d.ts +8 -0
- package/dist/core/settings-manager.js +18 -0
- package/dist/extensions/pi-powerline-footer/CHANGELOG.md +3 -1
- package/dist/extensions/pi-powerline-footer/guide.ts +11 -3
- package/dist/extensions/pi-powerline-footer/index.ts +3 -272
- package/dist/extensions/pi-powerline-footer/package.json +4 -5
- package/dist/extensions/pi-powerline-footer/powerline-config.ts +0 -6
- package/dist/extensions/pi-powerline-footer/tests/fixed-editor-border.test.ts +2 -2
- package/dist/extensions/pi-powerline-footer/tests/guide.test.ts +24 -1
- package/dist/extensions/pi-powerline-footer/tsconfig.json +1 -1
- package/dist/extensions/pi-subagents/package-lock.json +2 -2
- package/dist/extensions/pi-subagents/package.json +1 -1
- package/dist/extensions/pi-subagents/test/unit/package-manifest.test.ts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/main.js +1 -0
- package/dist/modes/interactive/components/settings-selector.d.ts +6 -2
- package/dist/modes/interactive/components/settings-selector.js +20 -0
- package/dist/modes/interactive/interactive-mode.d.ts +28 -0
- package/dist/modes/interactive/interactive-mode.js +214 -28
- package/dist/modes/interactive/theme/dark.json +1 -0
- package/dist/modes/interactive/theme/light.json +1 -0
- package/dist/modes/interactive/theme/theme-controller.d.ts +3 -0
- package/dist/modes/interactive/theme/theme-controller.js +10 -1
- package/dist/modes/interactive/theme/theme.d.ts +2 -2
- package/dist/modes/interactive/theme/theme.js +24 -6
- package/docs/keybindings.md +35 -7
- package/docs/settings.md +16 -14
- package/docs/usage.md +5 -0
- package/package.json +5 -5
- package/dist/extensions/pi-powerline-footer/fixed-editor/cluster.ts +0 -113
- package/dist/extensions/pi-powerline-footer/fixed-editor/terminal-split.ts +0 -1080
- package/dist/extensions/pi-powerline-footer/tests/fixed-editor.test.ts +0 -1452
- package/dist/extensions/pi-powerline-footer/tests/jump-shortcuts.test.ts +0 -49
package/docs/keybindings.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Keybindings
|
|
2
2
|
|
|
3
|
-
All keyboard shortcuts can be customized via `~/.
|
|
3
|
+
All keyboard shortcuts can be customized via `~/.selesai/agent/keybindings.json`. Each action can be bound to one or more keys.
|
|
4
4
|
|
|
5
5
|
The config file uses the same namespaced keybinding ids that pi uses internally and that extension authors use in `keyHint()` and injected `keybindings` managers.
|
|
6
6
|
|
|
@@ -10,7 +10,7 @@ After editing `keybindings.json`, run `/reload` in pi to apply the changes witho
|
|
|
10
10
|
|
|
11
11
|
## Key Format
|
|
12
12
|
|
|
13
|
-
`modifier+key` where modifiers are `ctrl`, `shift`, `alt` (combinable) and keys are:
|
|
13
|
+
`modifier+key` where modifiers are `ctrl`, `shift`, `alt`, `super` (combinable) and keys are:
|
|
14
14
|
|
|
15
15
|
- **Letters:** `a-z`
|
|
16
16
|
- **Digits:** `0-9`
|
|
@@ -18,7 +18,9 @@ After editing `keybindings.json`, run `/reload` in pi to apply the changes witho
|
|
|
18
18
|
- **Function:** `f1`-`f12`
|
|
19
19
|
- **Symbols:** `` ` ``, `-`, `=`, `[`, `]`, `\`, `;`, `'`, `,`, `.`, `/`, `!`, `@`, `#`, `$`, `%`, `^`, `&`, `*`, `(`, `)`, `_`, `+`, `|`, `~`, `{`, `}`, `:`, `<`, `>`, `?`
|
|
20
20
|
|
|
21
|
-
Modifier combinations: `ctrl+shift+x`, `alt+ctrl+x`, `ctrl+shift+alt+x`, `ctrl+1`, etc.
|
|
21
|
+
Modifier combinations: `ctrl+shift+x`, `alt+ctrl+x`, `ctrl+shift+alt+x`, `super+k`, `ctrl+super+k`, `ctrl+1`, etc.
|
|
22
|
+
|
|
23
|
+
`super` bindings require a terminal that reports the modifier separately, typically through the Kitty keyboard protocol. They may not work in terminals without that support.
|
|
22
24
|
|
|
23
25
|
## All Actions
|
|
24
26
|
|
|
@@ -78,16 +80,42 @@ Modifier combinations: `ctrl+shift+x`, `alt+ctrl+x`, `ctrl+shift+alt+x`, `ctrl+1
|
|
|
78
80
|
| `tui.select.confirm` | `enter` | Confirm selection |
|
|
79
81
|
| `tui.select.cancel` | `escape`, `ctrl+c` | Cancel selection |
|
|
80
82
|
|
|
83
|
+
### TUI Fullscreen Viewport
|
|
84
|
+
|
|
85
|
+
These actions apply when interactive mode uses fullscreen TUI mode (the Selesai default; `tuiMode: "fullscreen"` in settings or `--tui-mode fullscreen`) and target the primary transcript scroll region. Two-finger trackpad and mouse-wheel input scroll the region under the pointer, falling back to the transcript over the fixed editor/status/footer dock. Clicking an OSC 8 hyperlink opens it in the default handler. Dragging with the primary mouse button selects text and copies it to the clipboard; holding at the transcript's top or bottom edge auto-scrolls into off-screen content.
|
|
86
|
+
|
|
87
|
+
Fullscreen transcript bindings take precedence over editor bindings. The default unmodified navigation keys therefore control the transcript in fullscreen mode, while their `ctrl` variants continue to control the editor. Outside fullscreen mode, both variants control the editor.
|
|
88
|
+
|
|
89
|
+
| Key | Default mode | Fullscreen mode |
|
|
90
|
+
|-----|--------------|-----------------|
|
|
91
|
+
| `home`, `end` | Editor | Transcript |
|
|
92
|
+
| `ctrl+home`, `ctrl+end` | Editor | Editor |
|
|
93
|
+
| `pageUp`, `pageDown` | Editor | Transcript |
|
|
94
|
+
| `ctrl+pageUp`, `ctrl+pageDown` | Editor | Editor |
|
|
95
|
+
|
|
96
|
+
This routing remains configurable through the ordinary action bindings. For example, `"tui.altScreen.pageUp": "ctrl+pageUp"` makes `pageUp` control the editor and `ctrl+pageUp` control the transcript in fullscreen mode. Bind `tui.altScreen.halfPageUp` and `tui.altScreen.halfPageDown` for smaller transcript steps while keeping the full-page bindings. Setting `"tui.altScreen.pageUp": []` disables that transcript shortcut entirely. User bindings replace the defaults for that action.
|
|
97
|
+
|
|
98
|
+
| Keybinding id | Default | Description |
|
|
99
|
+
|--------|---------|-------------|
|
|
100
|
+
| `tui.altScreen.pageUp` | `pageUp` | Scroll the transcript up by one page |
|
|
101
|
+
| `tui.altScreen.pageDown` | `pageDown` | Scroll the transcript down by one page |
|
|
102
|
+
| `tui.altScreen.halfPageUp` | *(none)* | Scroll the transcript up by half a page |
|
|
103
|
+
| `tui.altScreen.halfPageDown` | *(none)* | Scroll the transcript down by half a page |
|
|
104
|
+
| `tui.altScreen.previousPrompt` | `ctrl+shift+up` | Jump to the previous marked message |
|
|
105
|
+
| `tui.altScreen.nextPrompt` | `ctrl+shift+down` | Jump to the next marked message |
|
|
106
|
+
| `tui.altScreen.top` | `home` | Scroll to the beginning of the transcript |
|
|
107
|
+
| `tui.altScreen.bottom` | `end` | Scroll to the transcript end and follow new output |
|
|
108
|
+
|
|
81
109
|
### Application
|
|
82
110
|
|
|
83
111
|
| Keybinding id | Default | Description |
|
|
84
112
|
|--------|---------|-------------|
|
|
85
113
|
| `app.interrupt` | `escape` | Cancel / abort |
|
|
86
|
-
| `app.clear` | `ctrl+c` | Clear editor |
|
|
114
|
+
| `app.clear` | `ctrl+c` | Clear editor (first) / exit (second) |
|
|
87
115
|
| `app.exit` | `ctrl+d` | Exit (when editor empty) |
|
|
88
116
|
| `app.suspend` | `ctrl+z` (none on Windows) | Suspend to background |
|
|
89
117
|
| `app.editor.external` | `ctrl+g` | Open in external editor (`$VISUAL` or `$EDITOR`) |
|
|
90
|
-
| `app.clipboard.pasteImage` | `ctrl+v` (`alt+v` on Windows) | Paste image from clipboard |
|
|
118
|
+
| `app.clipboard.pasteImage` | `ctrl+v` (`alt+v` on Windows) | Paste image or text from clipboard |
|
|
91
119
|
|
|
92
120
|
### Sessions
|
|
93
121
|
|
|
@@ -153,7 +181,7 @@ Used inside the scoped models selector (opened via `/scoped-models`).
|
|
|
153
181
|
|
|
154
182
|
## Custom Configuration
|
|
155
183
|
|
|
156
|
-
Create `~/.
|
|
184
|
+
Create `~/.selesai/agent/keybindings.json`:
|
|
157
185
|
|
|
158
186
|
```json
|
|
159
187
|
{
|
|
@@ -165,7 +193,7 @@ Create `~/.pi/agent/keybindings.json`:
|
|
|
165
193
|
|
|
166
194
|
Each action can have a single key or an array of keys. User config overrides defaults.
|
|
167
195
|
|
|
168
|
-
On native Windows, `app.suspend` has no default binding because Windows terminals do not support Unix job control. If you bind it manually,
|
|
196
|
+
On native Windows, `app.suspend` has no default binding because Windows terminals do not support Unix job control. If you bind it manually, Selesai shows a status message instead of suspending. In WSL, the normal Linux `ctrl+z`/`fg` behavior still applies.
|
|
169
197
|
|
|
170
198
|
### Emacs Example
|
|
171
199
|
|
package/docs/settings.md
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
# Settings
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Selesai uses JSON settings files with project settings overriding global settings.
|
|
4
4
|
|
|
5
5
|
| Location | Scope |
|
|
6
6
|
|----------|-------|
|
|
7
|
-
| `~/.
|
|
8
|
-
| `.
|
|
7
|
+
| `~/.selesai/agent/settings.json` | Global (all projects) |
|
|
8
|
+
| `.selesai/settings.json` | Project (current directory) |
|
|
9
9
|
|
|
10
10
|
Edit directly or use `/settings` for common options.
|
|
11
11
|
|
|
12
12
|
## Project Trust
|
|
13
13
|
|
|
14
|
-
On interactive startup,
|
|
14
|
+
On interactive startup, Selesai asks before trusting a project folder that contains project-local settings, resources, or project `.agents/skills` and has no saved decision for the folder or a parent folder in `~/.selesai/agent/trust.json`. Trusting a project allows Selesai to load `.selesai/settings.json` and `.selesai` resources, install missing project packages, and execute project extensions.
|
|
15
15
|
|
|
16
16
|
Non-interactive modes (`-p`, `--mode json`, and `--mode rpc`) do not show a trust prompt. Without an applicable saved trust decision, they use `defaultProjectTrust` from global settings: `ask` (default) and `never` ignore those project resources, while `always` trusts them. Pass `--approve`/`-a` or `--no-approve`/`-na` to override project trust for one run.
|
|
17
17
|
|
|
18
|
-
If no extension or saved decision applies, `defaultProjectTrust` controls the fallback behavior. Set it to `"ask"`, `"always"`, or `"never"` in `~/.
|
|
18
|
+
If no extension or saved decision applies, `defaultProjectTrust` controls the fallback behavior. Set it to `"ask"`, `"always"`, or `"never"` in `~/.selesai/agent/settings.json`, or change it with `/settings`.
|
|
19
19
|
|
|
20
|
-
`
|
|
20
|
+
`selesai config` and package commands use the same project trust flow, except `selesai update` never prompts. Pass `--approve` to trust project-local settings for one command or `--no-approve` to ignore them.
|
|
21
21
|
|
|
22
|
-
Use `/trust` in interactive mode to save a project trust decision for future sessions, including trust for the immediate parent folder. It writes `~/.
|
|
22
|
+
Use `/trust` in interactive mode to save a project trust decision for future sessions, including trust for the immediate parent folder. It writes `~/.selesai/agent/trust.json` only; the current session is not reloaded, so restart Selesai for changes to take effect.
|
|
23
23
|
|
|
24
24
|
## All Settings
|
|
25
25
|
|
|
@@ -62,6 +62,8 @@ Use `/trust` in interactive mode to save a project trust decision for future ses
|
|
|
62
62
|
| `editorPaddingX` | number | `0` | Horizontal padding for input editor (0-3) |
|
|
63
63
|
| `autocompleteMaxVisible` | number | `5` | Max visible items in autocomplete dropdown (3-20) |
|
|
64
64
|
| `showHardwareCursor` | boolean | `false` | Show the terminal cursor while TUI positions it for IME support |
|
|
65
|
+
| `tuiMode` | string | `"fullscreen"` | TUI layout: `"fullscreen"` (default) or `"regular"`. `fullscreen` uses Pi's native alternate-screen viewport with a fixed dock for the input editor, status, and widgets; set `"regular"` to opt out |
|
|
66
|
+
| `fullscreenScrollbar` | string | `"auto"` | Fullscreen transcript scrollbar: `"auto"`, `"always"`, or `"hidden"`; configurable in `/settings`. No effect in regular TUI mode |
|
|
65
67
|
|
|
66
68
|
### Telemetry and update checks
|
|
67
69
|
|
|
@@ -184,7 +186,7 @@ Keep `retry.provider.maxRetries` at `0` unless provider-level retries are explic
|
|
|
184
186
|
}
|
|
185
187
|
```
|
|
186
188
|
|
|
187
|
-
`npmCommand` is used for all npm package-manager operations, including installs, uninstalls, and dependency installs inside git packages. User-scoped npm packages install under `~/.
|
|
189
|
+
`npmCommand` is used for all npm package-manager operations, including installs, uninstalls, and dependency installs inside git packages. User-scoped npm packages install under `~/.selesai/agent/npm/`; project-scoped npm packages install under `.selesai/npm/`. Use argv-style entries exactly as the process should be launched. When `npmCommand` is configured, git package dependency installs use plain `install` to avoid npm-specific flags in wrappers or alternate package managers.
|
|
188
190
|
|
|
189
191
|
### Sessions
|
|
190
192
|
|
|
@@ -193,10 +195,10 @@ Keep `retry.provider.maxRetries` at `0` unless provider-level retries are explic
|
|
|
193
195
|
| `sessionDir` | string | - | Directory where session files are stored. Accepts absolute or relative paths, plus `~`. |
|
|
194
196
|
|
|
195
197
|
```json
|
|
196
|
-
{ "sessionDir": ".
|
|
198
|
+
{ "sessionDir": ".selesai/sessions" }
|
|
197
199
|
```
|
|
198
200
|
|
|
199
|
-
When multiple sources specify a session directory, precedence is `--session-dir`, `
|
|
201
|
+
When multiple sources specify a session directory, precedence is `--session-dir`, `SELESAI_CODING_AGENT_SESSION_DIR`, then `sessionDir` in settings.json.
|
|
200
202
|
|
|
201
203
|
### Model Cycling
|
|
202
204
|
|
|
@@ -220,7 +222,7 @@ When multiple sources specify a session directory, precedence is `--session-dir`
|
|
|
220
222
|
|
|
221
223
|
These settings define where to load extensions, skills, prompts, and themes from.
|
|
222
224
|
|
|
223
|
-
Paths in `~/.
|
|
225
|
+
Paths in `~/.selesai/agent/settings.json` resolve relative to `~/.selesai/agent`. Paths in `.selesai/settings.json` resolve relative to `.selesai`. Absolute paths and `~` are supported.
|
|
224
226
|
|
|
225
227
|
| Setting | Type | Default | Description |
|
|
226
228
|
|---------|------|---------|-------------|
|
|
@@ -300,16 +302,16 @@ Keys are top-level entry names (dir name for packaged extensions, file name for
|
|
|
300
302
|
|
|
301
303
|
## Project Overrides
|
|
302
304
|
|
|
303
|
-
Project settings (`.
|
|
305
|
+
Project settings (`.selesai/settings.json`) override global settings. Nested objects are merged:
|
|
304
306
|
|
|
305
307
|
```json
|
|
306
|
-
// ~/.
|
|
308
|
+
// ~/.selesai/agent/settings.json (global)
|
|
307
309
|
{
|
|
308
310
|
"theme": "dark",
|
|
309
311
|
"compaction": { "enabled": true, "reserveTokens": 16384 }
|
|
310
312
|
}
|
|
311
313
|
|
|
312
|
-
// .
|
|
314
|
+
// .selesai/settings.json (project)
|
|
313
315
|
{
|
|
314
316
|
"compaction": { "reserveTokens": 8192 }
|
|
315
317
|
}
|
package/docs/usage.md
CHANGED
|
@@ -15,6 +15,10 @@ The interface has four main areas:
|
|
|
15
15
|
|
|
16
16
|
The editor can be replaced temporarily by built-in UI such as `/settings` or by custom extension UI.
|
|
17
17
|
|
|
18
|
+
### TUI Mode
|
|
19
|
+
|
|
20
|
+
Selesai runs its terminal interface in **fullscreen TUI mode** by default: the chat scrolls inside Pi's native alternate-screen viewport while the input editor, status line, and extension widgets stay fixed in a dock at the bottom. The `TUI mode` entry in `/settings` (or `tuiMode` in `settings.json`) switches between `fullscreen` and `regular` immediately and picks the default for future sessions. The `--tui-mode fullscreen|regular` flag overrides it for a single run. In regular mode, output renders inline into the terminal scrollback. See [Keybindings](keybindings.md) for the fullscreen transcript scrolling keys.
|
|
21
|
+
|
|
18
22
|
### Editor Features
|
|
19
23
|
|
|
20
24
|
| Feature | How |
|
|
@@ -236,6 +240,7 @@ pi --no-extensions -e ./my-extension.ts
|
|
|
236
240
|
|--------|-------------|
|
|
237
241
|
| `--system-prompt <text>` | Replace default prompt; context files and skills are still appended |
|
|
238
242
|
| `--append-system-prompt <text>` | Append to system prompt |
|
|
243
|
+
| `--tui-mode <mode>` | TUI mode: `fullscreen` (default) or `regular` |
|
|
239
244
|
| `--verbose` | Force verbose startup |
|
|
240
245
|
| `-a`, `--approve` | Trust project-local files for this run |
|
|
241
246
|
| `-na`, `--no-approve` | Ignore project-local files for this run |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@selesai/code",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.3",
|
|
4
4
|
"description": "Maintained, extension-first Pi coding agent with built-in workflows, subagents, web research, questions, skills, and an enhanced terminal UI.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -55,9 +55,9 @@
|
|
|
55
55
|
},
|
|
56
56
|
"dependencies": {
|
|
57
57
|
"@ast-grep/cli": "0.45.0",
|
|
58
|
-
"@earendil-works/pi-agent-core": "0.
|
|
59
|
-
"@earendil-works/pi-ai": "0.
|
|
60
|
-
"@earendil-works/pi-tui": "0.
|
|
58
|
+
"@earendil-works/pi-agent-core": "0.84.1",
|
|
59
|
+
"@earendil-works/pi-ai": "0.84.1",
|
|
60
|
+
"@earendil-works/pi-tui": "0.84.1",
|
|
61
61
|
"@mozilla/readability": "^0.6.0",
|
|
62
62
|
"@silvia-odwyer/photon-node": "0.3.4",
|
|
63
63
|
"chalk": "5.6.2",
|
|
@@ -76,7 +76,7 @@
|
|
|
76
76
|
"semver": "7.8.0",
|
|
77
77
|
"tsx": "^4.20.0",
|
|
78
78
|
"typebox": "1.3.7",
|
|
79
|
-
"undici": "8.
|
|
79
|
+
"undici": "8.9.0",
|
|
80
80
|
"yaml": "2.9.0"
|
|
81
81
|
},
|
|
82
82
|
"devDependencies": {
|
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
import { truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
|
|
2
|
-
|
|
3
|
-
export const CURSOR_MARKER = "\x1b_pi:c\x07";
|
|
4
|
-
|
|
5
|
-
export interface FixedEditorClusterInput {
|
|
6
|
-
width: number;
|
|
7
|
-
terminalRows: number;
|
|
8
|
-
statusLines?: string[];
|
|
9
|
-
topLines?: string[];
|
|
10
|
-
editorLines: string[];
|
|
11
|
-
secondaryLines?: string[];
|
|
12
|
-
transcriptLines?: string[];
|
|
13
|
-
lastPromptLines?: string[];
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export interface FixedEditorCursor {
|
|
17
|
-
row: number;
|
|
18
|
-
col: number;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export interface FixedEditorClusterRender {
|
|
22
|
-
lines: string[];
|
|
23
|
-
cursor: FixedEditorCursor | null;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function normalizeLines(lines: string[] | undefined, width: number): string[] {
|
|
27
|
-
if (!lines || width <= 0) return [];
|
|
28
|
-
|
|
29
|
-
return lines
|
|
30
|
-
.filter((line) => line !== undefined && line !== null)
|
|
31
|
-
.map((line) => visibleWidth(line) > width ? truncateToWidth(line, width, "", true) : line);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
function takeTail(lines: string[], count: number): string[] {
|
|
35
|
-
if (count <= 0) return [];
|
|
36
|
-
return lines.length <= count ? lines : lines.slice(lines.length - count);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
function capEditorLines(lines: string[], count: number): string[] {
|
|
40
|
-
if (count <= 0) return [];
|
|
41
|
-
if (lines.length <= count) return lines;
|
|
42
|
-
|
|
43
|
-
const cursorRow = lines.findIndex((line) => line.includes(CURSOR_MARKER));
|
|
44
|
-
if (cursorRow !== -1) {
|
|
45
|
-
const start = Math.max(0, Math.min(cursorRow - count + 1, lines.length - count));
|
|
46
|
-
return lines.slice(start, start + count);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const selectedRow = lines.findIndex((line) => line.replace(/\x1b\[[0-9;]*m/g, "").trimStart().startsWith("→ "));
|
|
50
|
-
if (selectedRow === -1) {
|
|
51
|
-
return lines.slice(0, count);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const start = Math.max(0, Math.min(selectedRow - Math.floor(count / 2), lines.length - count));
|
|
55
|
-
return lines.slice(start, start + count);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
function extractCursor(lines: string[]): FixedEditorClusterRender {
|
|
59
|
-
let cursor: FixedEditorCursor | null = null;
|
|
60
|
-
const cleaned = lines.map((line, row) => {
|
|
61
|
-
const markerIndex = line.indexOf(CURSOR_MARKER);
|
|
62
|
-
if (markerIndex === -1) return line;
|
|
63
|
-
|
|
64
|
-
if (!cursor) {
|
|
65
|
-
cursor = {
|
|
66
|
-
row,
|
|
67
|
-
col: visibleWidth(line.slice(0, markerIndex)),
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
return line.slice(0, markerIndex) + line.slice(markerIndex + CURSOR_MARKER.length);
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
return { lines: cleaned, cursor };
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
export function renderFixedEditorCluster(input: FixedEditorClusterInput): FixedEditorClusterRender {
|
|
78
|
-
const width = Math.max(1, input.width);
|
|
79
|
-
const maxRows = Math.max(1, input.terminalRows - 1);
|
|
80
|
-
|
|
81
|
-
const statusLines = normalizeLines(input.statusLines, width);
|
|
82
|
-
const topLines = normalizeLines(input.topLines, width);
|
|
83
|
-
const editorSource = normalizeLines(input.editorLines, width);
|
|
84
|
-
const secondaryLines = normalizeLines(input.secondaryLines, width);
|
|
85
|
-
const transcriptLines = normalizeLines(input.transcriptLines, width);
|
|
86
|
-
const lastPromptLines = normalizeLines(input.lastPromptLines, width);
|
|
87
|
-
|
|
88
|
-
const editorLines = capEditorLines(editorSource, maxRows);
|
|
89
|
-
let remaining = maxRows - editorLines.length;
|
|
90
|
-
|
|
91
|
-
const top = takeTail(topLines, remaining);
|
|
92
|
-
remaining -= top.length;
|
|
93
|
-
|
|
94
|
-
const secondary = takeTail(secondaryLines, remaining);
|
|
95
|
-
remaining -= secondary.length;
|
|
96
|
-
|
|
97
|
-
const lastPrompt = takeTail(lastPromptLines, remaining);
|
|
98
|
-
remaining -= lastPrompt.length;
|
|
99
|
-
|
|
100
|
-
const status = takeTail(statusLines, remaining);
|
|
101
|
-
remaining -= status.length;
|
|
102
|
-
|
|
103
|
-
const transcript = takeTail(transcriptLines, remaining);
|
|
104
|
-
|
|
105
|
-
return extractCursor([
|
|
106
|
-
...status,
|
|
107
|
-
...top,
|
|
108
|
-
...editorLines,
|
|
109
|
-
...secondary,
|
|
110
|
-
...transcript,
|
|
111
|
-
...lastPrompt,
|
|
112
|
-
]);
|
|
113
|
-
}
|