fix(tui): add vertical scrolling to Editor when content exceeds terminal height
The Editor component now accepts TUI as the first constructor parameter, enabling it to query terminal dimensions. When content exceeds available height, the editor scrolls vertically keeping the cursor visible. Features: - Max editor height is 30% of terminal rows (minimum 5 lines) - Page Up/Down keys scroll by page size - Scroll indicators show lines above/below: ─── ↑ 5 more ─── Breaking change: Editor constructor signature changed from new Editor(theme) to new Editor(tui, theme) fixes #732
This commit is contained in:
35
packages/coding-agent/examples/extensions/load-file.ts
Normal file
35
packages/coding-agent/examples/extensions/load-file.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* Load file into editor - for testing editor scrolling
|
||||
*
|
||||
* Usage: pi --extension ./examples/extensions/load-file.ts
|
||||
*
|
||||
* Commands:
|
||||
* /load [path] - Load file into editor (defaults to README.md)
|
||||
*/
|
||||
|
||||
import * as fs from "node:fs";
|
||||
import * as path from "node:path";
|
||||
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
||||
|
||||
export default function (pi: ExtensionAPI) {
|
||||
pi.registerCommand("load", {
|
||||
description: "Load file into editor (defaults to README.md)",
|
||||
handler: async (args, ctx) => {
|
||||
const filePath = args.trim() || "README.md";
|
||||
const fullPath = path.resolve(filePath);
|
||||
|
||||
if (!fs.existsSync(fullPath)) {
|
||||
ctx.ui.notify(`File not found: ${fullPath}`, "error");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const content = fs.readFileSync(fullPath, "utf-8");
|
||||
ctx.ui.setEditorText(content);
|
||||
ctx.ui.notify(`Loaded ${filePath} (${content.split("\n").length} lines)`);
|
||||
} catch (err) {
|
||||
ctx.ui.notify(`Failed to read file: ${err}`, "error");
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -80,6 +80,6 @@ class ModalEditor extends CustomEditor {
|
||||
|
||||
export default function (pi: ExtensionAPI) {
|
||||
pi.on("session_start", (_event, ctx) => {
|
||||
ctx.ui.setEditorComponent((_tui, theme, kb) => new ModalEditor(theme, kb));
|
||||
ctx.ui.setEditorComponent((tui, theme, kb) => new ModalEditor(tui, theme, kb));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ export default function question(pi: ExtensionAPI) {
|
||||
noMatch: (t) => theme.fg("warning", t),
|
||||
},
|
||||
};
|
||||
const editor = new Editor(editorTheme);
|
||||
const editor = new Editor(tui, editorTheme);
|
||||
|
||||
editor.onSubmit = (value) => {
|
||||
const trimmed = value.trim();
|
||||
|
||||
@@ -119,7 +119,7 @@ export default function questionnaire(pi: ExtensionAPI) {
|
||||
noMatch: (t) => theme.fg("warning", t),
|
||||
},
|
||||
};
|
||||
const editor = new Editor(editorTheme);
|
||||
const editor = new Editor(tui, editorTheme);
|
||||
|
||||
// Helpers
|
||||
function refresh() {
|
||||
|
||||
@@ -4,8 +4,7 @@
|
||||
* Usage: pi --extension ./examples/extensions/rainbow-editor.ts
|
||||
*/
|
||||
|
||||
import { CustomEditor, type ExtensionAPI, type KeybindingsManager } from "@mariozechner/pi-coding-agent";
|
||||
import type { EditorTheme, TUI } from "@mariozechner/pi-tui";
|
||||
import { CustomEditor, type ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
||||
|
||||
// Base colors (coral → yellow → green → teal → blue → purple → pink)
|
||||
const COLORS: [number, number, number][] = [
|
||||
@@ -44,14 +43,8 @@ function colorize(text: string, shinePos: number): string {
|
||||
|
||||
class RainbowEditor extends CustomEditor {
|
||||
private animationTimer?: ReturnType<typeof setInterval>;
|
||||
private tui: TUI;
|
||||
private frame = 0;
|
||||
|
||||
constructor(tui: TUI, theme: EditorTheme, keybindings: KeybindingsManager) {
|
||||
super(theme, keybindings);
|
||||
this.tui = tui;
|
||||
}
|
||||
|
||||
private hasUltrathink(): boolean {
|
||||
return /ultrathink/i.test(this.getText());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user