Commit bd8ee0395c16
Changed files (1)
dots
pi
agent
extensions
dots/pi/agent/extensions/prompt-editor.ts
@@ -343,28 +343,39 @@ function hexToAnsi(hex: string): string {
return `\x1b[38;2;${r};${g};${b}m`;
}
-function getModeBorderColor(ctx: ExtensionContext, pi: ExtensionAPI, mode: string): (text: string) => string {
- const theme = ctx.ui.theme;
- const spec = runtime.data.modes[mode];
+/**
+ * Patch Editor.prototype.render so that every editor instance (file-picker,
+ * shell-completions, default, etc.) picks up the current mode's border color
+ * at render time. This avoids fighting with setEditorComponent ordering and
+ * pi's updateEditorBorderColor which we can't trigger from the extension API.
+ *
+ * On each render call, if the current mode has a custom color, we temporarily
+ * swap the editor's borderColor, call the original render, then restore it.
+ */
+let editorPatchInstalled = false;
+function installEditorBorderPatch(): void {
+ if (editorPatchInstalled) return;
- // Hex color from modes.json
- if (spec?.color && /^#[0-9a-fA-F]{6}$/.test(spec.color)) {
- const ansi = hexToAnsi(spec.color);
- return (text: string) => `${ansi}${text}\x1b[39m`;
- }
+ // Get Editor.prototype via the CustomEditor import
+ const EditorProto = Object.getPrototypeOf(CustomEditor.prototype);
+ if (!EditorProto || typeof EditorProto.render !== "function") return;
- // Theme token fallback
- if (spec?.color) {
- try {
- theme.getFgAnsi(spec.color as any);
- return (text: string) => theme.fg(spec.color as any, text);
- } catch {
- // fall through to thinking-based colors
+ const originalRender = EditorProto.render as (this: { borderColor: (text: string) => string }, width: number) => string[];
+
+ EditorProto.render = function patchedRender(this: { borderColor: (text: string) => string }, width: number): string[] {
+ const spec = runtime.data.modes[runtime.currentMode];
+ if (spec?.color && /^#[0-9a-fA-F]{6}$/.test(spec.color)) {
+ const ansi = hexToAnsi(spec.color);
+ const saved = this.borderColor;
+ this.borderColor = (text: string) => `${ansi}${text}\x1b[39m`;
+ const result = originalRender.call(this, width);
+ this.borderColor = saved;
+ return result;
}
- }
+ return originalRender.call(this, width);
+ };
- // Default: derive from the current thinking level.
- return theme.getThinkingBorderColor(pi.getThinkingLevel());
+ editorPatchInstalled = true;
}
async function resolveModesPath(cwd: string): Promise<string> {
@@ -958,31 +969,6 @@ interface PromptEntry {
}
class PromptEditor extends CustomEditor {
- private lockedBorder = false;
- private _borderColor?: (text: string) => string;
-
- constructor(
- tui: ConstructorParameters<typeof CustomEditor>[0],
- theme: ConstructorParameters<typeof CustomEditor>[1],
- keybindings: ConstructorParameters<typeof CustomEditor>[2],
- ) {
- super(tui, theme, keybindings);
- delete (this as { borderColor?: (text: string) => string }).borderColor;
- Object.defineProperty(this, "borderColor", {
- get: () => this._borderColor ?? ((text: string) => text),
- set: (value: (text: string) => string) => {
- if (this.lockedBorder) return;
- this._borderColor = value;
- },
- configurable: true,
- enumerable: true,
- });
- }
-
- lockBorderColor() {
- this.lockedBorder = true;
- }
-
public requestRenderNow(): void {
this.tui.requestRender();
}
@@ -1136,16 +1122,6 @@ function setEditor(pi: ExtensionAPI, ctx: ExtensionContext, history: PromptEntry
ctx.ui.setEditorComponent((tui, theme, keybindings) => {
const editor = new PromptEditor(tui, theme, keybindings);
requestEditorRender = () => editor.requestRenderNow();
- const borderColor = (text: string) => {
- const isBashMode = editor.getText().trimStart().startsWith("!");
- if (isBashMode) {
- return ctx.ui.theme.getBashModeBorderColor()(text);
- }
- return getModeBorderColor(ctx, pi, runtime.currentMode)(text);
- };
-
- editor.borderColor = borderColor;
- editor.lockBorderColor();
for (const prompt of history) {
editor.addToHistory?.(prompt.text);
}
@@ -1240,6 +1216,7 @@ export default function (pi: ExtensionAPI) {
lastObservedModel = { provider: ctx.model?.provider, modelId: ctx.model?.id };
await ensureRuntime(pi, ctx);
customOverlay = null;
+ installEditorBorderPatch();
const inferred = inferModeFromSelection(ctx, pi, runtime.data);
if (inferred) {