返回 DeepSeek-Reasonix
TerminalView.tsx
根目录 / desktop / frontend / src / components / TerminalView.tsx
1 import { useEffect, useRef } from "react";
2 import { FitAddon } from "@xterm/addon-fit";
3 import { Terminal } from "@xterm/xterm";
4 import "@xterm/xterm/css/xterm.css";
5
6 import { useTerminalStore } from "../store/terminal";
7 import { registerTerminalSink, startTerminalEventBridge } from "../lib/terminalEvents";
8 import { observeTerminalTheme, terminalThemeForElement } from "../lib/terminalTheme";
9 import type { TerminalSessionView } from "../lib/types";
10
11 export function TerminalView({ tabId, session }: { tabId: string; session: TerminalSessionView }) {
12 const hostRef = useRef<HTMLDivElement>(null);
13 const write = useTerminalStore((state) => state.write);
14 const resize = useTerminalStore((state) => state.resize);
15
16 useEffect(() => {
17 startTerminalEventBridge();
18 const host = hostRef.current;
19 if (!host) return;
20 const terminal = new Terminal({
21 convertEol: true,
22 cursorBlink: true,
23 fontFamily: "ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace",
24 fontSize: 13,
25 theme: terminalThemeForElement(host),
26 });
27 const fit = new FitAddon();
28 terminal.loadAddon(fit);
29 terminal.open(host);
30 const updateTheme = () => {
31 terminal.options.theme = terminalThemeForElement(host);
32 };
33 const stopObservingTheme = observeTerminalTheme(host, updateTheme);
34 const unregister = registerTerminalSink(session.id, (bytes) => terminal.write(bytes));
35 const input = terminal.onData((data) => { void write(tabId, session.id, data).catch(() => {}); });
36 const outputResize = terminal.onResize(({ cols, rows }) => { void resize(tabId, session.id, cols, rows).catch(() => {}); });
37 const fitTerminal = () => {
38 fit.fit();
39 const { cols, rows } = terminal;
40 if (cols > 0 && rows > 0) void resize(tabId, session.id, cols, rows).catch(() => {});
41 };
42 const observer = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(fitTerminal);
43 observer?.observe(host);
44 fitTerminal();
45 return () => {
46 observer?.disconnect();
47 stopObservingTheme();
48 input.dispose();
49 outputResize.dispose();
50 unregister();
51 terminal.dispose();
52 };
53 }, [resize, session.id, tabId, write]);
54
55 return <div ref={hostRef} className="terminal-view" aria-label={session.title} />;
56 }
57
57 lines Plain Text