feat(app): load xterm search addon + surface→addon registry

This commit is contained in:
2026-06-10 12:35:41 +07:00
parent daf87d3c09
commit 52a502c38b
4 changed files with 33 additions and 1 deletions
+8 -1
View File
@@ -1,7 +1,9 @@
import { useEffect, useRef } from "react";
import { Terminal } from "@xterm/xterm";
import { WebglAddon } from "@xterm/addon-webgl";
import { SearchAddon } from "@xterm/addon-search";
import { attachSurface, detachSurface, sendInput, resizeSurface } from "./socketBridge";
import { registerSearch, unregisterSearch } from "./searchRegistry";
const decoder = new TextDecoder();
const encoder = new TextEncoder();
@@ -11,7 +13,7 @@ export function TerminalView({ surfaceId }: { surfaceId: string }) {
useEffect(() => {
if (!ref.current) return;
const term = new Terminal({ fontFamily: "'JetBrains Mono Variable', 'JetBrains Mono', monospace", fontSize: 13, convertEol: false });
const term = new Terminal({ fontFamily: "'JetBrains Mono Variable', 'JetBrains Mono', monospace", fontSize: 13, convertEol: false, scrollback: 10000 });
try {
term.loadAddon(new WebglAddon());
} catch {
@@ -19,6 +21,10 @@ export function TerminalView({ surfaceId }: { surfaceId: string }) {
}
term.open(ref.current);
const search = new SearchAddon();
term.loadAddon(search);
registerSearch(surfaceId, search);
// Input → daemon.
const inputDisposable = term.onData((data) => {
void sendInput(surfaceId, encoder.encode(data));
@@ -42,6 +48,7 @@ export function TerminalView({ surfaceId }: { surfaceId: string }) {
disposed = true;
inputDisposable.dispose();
void detachSurface(surfaceId);
unregisterSearch(surfaceId);
term.dispose();
};
}, [surfaceId]);
+17
View File
@@ -0,0 +1,17 @@
import type { SearchAddon } from "@xterm/addon-search";
/** Maps a surfaceId to its terminal's SearchAddon so the search bar can reach
* the focused panel without prop-drilling through the layout tree. */
const registry = new Map<string, SearchAddon>();
export function registerSearch(surfaceId: string, addon: SearchAddon): void {
registry.set(surfaceId, addon);
}
export function unregisterSearch(surfaceId: string): void {
registry.delete(surfaceId);
}
export function getSearch(surfaceId: string): SearchAddon | undefined {
return registry.get(surfaceId);
}