feat(app): load xterm search addon + surface→addon registry
This commit is contained in:
Generated
+7
@@ -12,6 +12,7 @@
|
|||||||
"@fontsource/inter": "^5.2.8",
|
"@fontsource/inter": "^5.2.8",
|
||||||
"@tauri-apps/api": "^2",
|
"@tauri-apps/api": "^2",
|
||||||
"@tauri-apps/plugin-notification": "^2",
|
"@tauri-apps/plugin-notification": "^2",
|
||||||
|
"@xterm/addon-search": "^0.16.0",
|
||||||
"@xterm/addon-webgl": "^0.18.0",
|
"@xterm/addon-webgl": "^0.18.0",
|
||||||
"@xterm/xterm": "^5.5.0",
|
"@xterm/xterm": "^5.5.0",
|
||||||
"lucide-react": "^1.17.0",
|
"lucide-react": "^1.17.0",
|
||||||
@@ -1462,6 +1463,12 @@
|
|||||||
"vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0"
|
"vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@xterm/addon-search": {
|
||||||
|
"version": "0.16.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@xterm/addon-search/-/addon-search-0.16.0.tgz",
|
||||||
|
"integrity": "sha512-9OeuBFu0/uZJPu+9AHKY6g/w0Czyb/Ut0A5t79I4ULoU4IfU5BEpPFVGQxP4zTTMdfZEYkVIRYbHBX1xWwjeSA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/@xterm/addon-webgl": {
|
"node_modules/@xterm/addon-webgl": {
|
||||||
"version": "0.18.0",
|
"version": "0.18.0",
|
||||||
"resolved": "https://registry.npmjs.org/@xterm/addon-webgl/-/addon-webgl-0.18.0.tgz",
|
"resolved": "https://registry.npmjs.org/@xterm/addon-webgl/-/addon-webgl-0.18.0.tgz",
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
"@fontsource/inter": "^5.2.8",
|
"@fontsource/inter": "^5.2.8",
|
||||||
"@tauri-apps/api": "^2",
|
"@tauri-apps/api": "^2",
|
||||||
"@tauri-apps/plugin-notification": "^2",
|
"@tauri-apps/plugin-notification": "^2",
|
||||||
|
"@xterm/addon-search": "^0.16.0",
|
||||||
"@xterm/addon-webgl": "^0.18.0",
|
"@xterm/addon-webgl": "^0.18.0",
|
||||||
"@xterm/xterm": "^5.5.0",
|
"@xterm/xterm": "^5.5.0",
|
||||||
"lucide-react": "^1.17.0",
|
"lucide-react": "^1.17.0",
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
import { useEffect, useRef } from "react";
|
import { useEffect, useRef } from "react";
|
||||||
import { Terminal } from "@xterm/xterm";
|
import { Terminal } from "@xterm/xterm";
|
||||||
import { WebglAddon } from "@xterm/addon-webgl";
|
import { WebglAddon } from "@xterm/addon-webgl";
|
||||||
|
import { SearchAddon } from "@xterm/addon-search";
|
||||||
import { attachSurface, detachSurface, sendInput, resizeSurface } from "./socketBridge";
|
import { attachSurface, detachSurface, sendInput, resizeSurface } from "./socketBridge";
|
||||||
|
import { registerSearch, unregisterSearch } from "./searchRegistry";
|
||||||
|
|
||||||
const decoder = new TextDecoder();
|
const decoder = new TextDecoder();
|
||||||
const encoder = new TextEncoder();
|
const encoder = new TextEncoder();
|
||||||
@@ -11,7 +13,7 @@ export function TerminalView({ surfaceId }: { surfaceId: string }) {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!ref.current) return;
|
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 {
|
try {
|
||||||
term.loadAddon(new WebglAddon());
|
term.loadAddon(new WebglAddon());
|
||||||
} catch {
|
} catch {
|
||||||
@@ -19,6 +21,10 @@ export function TerminalView({ surfaceId }: { surfaceId: string }) {
|
|||||||
}
|
}
|
||||||
term.open(ref.current);
|
term.open(ref.current);
|
||||||
|
|
||||||
|
const search = new SearchAddon();
|
||||||
|
term.loadAddon(search);
|
||||||
|
registerSearch(surfaceId, search);
|
||||||
|
|
||||||
// Input → daemon.
|
// Input → daemon.
|
||||||
const inputDisposable = term.onData((data) => {
|
const inputDisposable = term.onData((data) => {
|
||||||
void sendInput(surfaceId, encoder.encode(data));
|
void sendInput(surfaceId, encoder.encode(data));
|
||||||
@@ -42,6 +48,7 @@ export function TerminalView({ surfaceId }: { surfaceId: string }) {
|
|||||||
disposed = true;
|
disposed = true;
|
||||||
inputDisposable.dispose();
|
inputDisposable.dispose();
|
||||||
void detachSurface(surfaceId);
|
void detachSurface(surfaceId);
|
||||||
|
unregisterSearch(surfaceId);
|
||||||
term.dispose();
|
term.dispose();
|
||||||
};
|
};
|
||||||
}, [surfaceId]);
|
}, [surfaceId]);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user