mirror of
https://github.com/badlogic/pi-mono.git
synced 2026-11-05 23:37:25 +00:00
fix(coding-agent): preserve dialogs during editor updates
This commit is contained in:
parent
6f6f5683e1
commit
cacfef4886
2 changed files with 142 additions and 6 deletions
|
|
@ -2380,10 +2380,10 @@ export class InteractiveMode {
|
|||
private setCustomEditorComponent(factory: EditorFactory | undefined): void {
|
||||
this.editorComponentFactory = factory;
|
||||
|
||||
// Save text from current editor before switching
|
||||
const currentText = this.editor.getText();
|
||||
|
||||
this.editorContainer.clear();
|
||||
const previousEditor = this.editor;
|
||||
const editorIsDisplayed =
|
||||
this.editorContainer.children.length === 1 && this.editorContainer.children[0] === previousEditor;
|
||||
const currentText = previousEditor.getText();
|
||||
|
||||
if (factory) {
|
||||
// Create the custom editor with tui, theme, and keybindings
|
||||
|
|
@ -2438,8 +2438,11 @@ export class InteractiveMode {
|
|||
this.editor = this.defaultEditor;
|
||||
}
|
||||
|
||||
this.editorContainer.addChild(this.editor as Component);
|
||||
this.ui.setFocus(this.editor as Component);
|
||||
if (editorIsDisplayed) {
|
||||
this.editorContainer.clear();
|
||||
this.editorContainer.addChild(this.editor as Component);
|
||||
this.ui.setFocus(this.editor as Component);
|
||||
}
|
||||
this.ui.requestRender();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,133 @@
|
|||
import type { Component, EditorComponent } from "@earendil-works/pi-tui";
|
||||
import { Container } from "@earendil-works/pi-tui";
|
||||
import { beforeAll, describe, expect, it, vi } from "vitest";
|
||||
import type { EditorFactory } from "../src/core/extensions/types.ts";
|
||||
import { InteractiveMode } from "../src/modes/interactive/interactive-mode.ts";
|
||||
import { initTheme } from "../src/modes/interactive/theme/theme.ts";
|
||||
|
||||
class TestEditor implements EditorComponent {
|
||||
onSubmit?: (text: string) => void;
|
||||
onChange?: (text: string) => void;
|
||||
borderColor?: (text: string) => string;
|
||||
private text = "";
|
||||
readonly label: string;
|
||||
|
||||
constructor(label: string) {
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
getText(): string {
|
||||
return this.text;
|
||||
}
|
||||
|
||||
setText(text: string): void {
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
handleInput(): void {}
|
||||
|
||||
invalidate(): void {}
|
||||
|
||||
render(): string[] {
|
||||
return [this.label];
|
||||
}
|
||||
}
|
||||
|
||||
class TestDefaultEditor extends TestEditor {
|
||||
getPaddingX(): number {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
class TestDialog implements Component {
|
||||
readonly dispose = vi.fn();
|
||||
|
||||
invalidate(): void {}
|
||||
|
||||
render(): string[] {
|
||||
return ["dialog"];
|
||||
}
|
||||
}
|
||||
|
||||
type EditorContext = {
|
||||
editorComponentFactory: EditorFactory | undefined;
|
||||
defaultEditor: TestDefaultEditor;
|
||||
editor: EditorComponent;
|
||||
editorContainer: Container;
|
||||
ui: {
|
||||
setFocus: (component: Component) => void;
|
||||
requestRender: () => void;
|
||||
};
|
||||
keybindings: object;
|
||||
autocompleteProvider: undefined;
|
||||
extensionSelector?: TestDialog;
|
||||
};
|
||||
|
||||
type InteractiveModePrivate = {
|
||||
setCustomEditorComponent(this: EditorContext, factory: EditorFactory | undefined): void;
|
||||
hideExtensionSelector(this: EditorContext): void;
|
||||
};
|
||||
|
||||
const interactiveModePrototype = InteractiveMode.prototype as unknown as InteractiveModePrivate;
|
||||
|
||||
function createContext(editorContainer: Container, defaultEditor: TestDefaultEditor): EditorContext {
|
||||
return {
|
||||
editorComponentFactory: undefined,
|
||||
defaultEditor,
|
||||
editor: defaultEditor,
|
||||
editorContainer,
|
||||
ui: {
|
||||
setFocus: vi.fn(),
|
||||
requestRender: vi.fn(),
|
||||
},
|
||||
keybindings: {},
|
||||
autocompleteProvider: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
describe("InteractiveMode custom editor replacement", () => {
|
||||
beforeAll(() => {
|
||||
initTheme("dark");
|
||||
});
|
||||
|
||||
it("keeps an active selector visible and restores the delayed custom editor when it closes", () => {
|
||||
const defaultEditor = new TestDefaultEditor("default editor");
|
||||
defaultEditor.setText("draft");
|
||||
const selector = new TestDialog();
|
||||
const editorContainer = new Container();
|
||||
editorContainer.addChild(selector);
|
||||
const context = createContext(editorContainer, defaultEditor);
|
||||
context.extensionSelector = selector;
|
||||
const customEditor = new TestEditor("custom editor");
|
||||
const factory: EditorFactory = () => customEditor;
|
||||
|
||||
interactiveModePrototype.setCustomEditorComponent.call(context, factory);
|
||||
|
||||
expect(context.editor).toBe(customEditor);
|
||||
expect(customEditor.getText()).toBe("draft");
|
||||
expect(editorContainer.children).toEqual([selector]);
|
||||
expect(context.ui.setFocus).not.toHaveBeenCalled();
|
||||
|
||||
interactiveModePrototype.hideExtensionSelector.call(context);
|
||||
|
||||
expect(selector.dispose).toHaveBeenCalledOnce();
|
||||
expect(editorContainer.children).toEqual([customEditor]);
|
||||
expect(context.ui.setFocus).toHaveBeenCalledWith(customEditor);
|
||||
});
|
||||
|
||||
it("replaces and focuses the editor immediately when the old editor is displayed", () => {
|
||||
const defaultEditor = new TestDefaultEditor("default editor");
|
||||
defaultEditor.setText("draft");
|
||||
const editorContainer = new Container();
|
||||
editorContainer.addChild(defaultEditor);
|
||||
const context = createContext(editorContainer, defaultEditor);
|
||||
const customEditor = new TestEditor("custom editor");
|
||||
|
||||
interactiveModePrototype.setCustomEditorComponent.call(context, () => customEditor);
|
||||
|
||||
expect(context.editor).toBe(customEditor);
|
||||
expect(customEditor.getText()).toBe("draft");
|
||||
expect(editorContainer.children).toEqual([customEditor]);
|
||||
expect(context.ui.setFocus).toHaveBeenCalledWith(customEditor);
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue