import type { Terminal as XTerm } from 'xterm'; import type { FitAddon } from 'xterm-addon-fit'; /** FitAddon 适配终端并同步远端 PTY 尺寸(WebSSH resize) // Logan.Li */ export function fitTerminal(fit: FitAddon, term: XTerm, ws?: WebSocket | null) { fit.fit(); if (ws?.readyState === WebSocket.OPEN) { const { cols, rows } = term; if (cols > 0 && rows > 0) { ws.send(JSON.stringify({ status: 1, cols, rows })); } } } /** 等待容器就绪后挂载 xterm,并延迟二次 fit 消除右侧黑边 // Logan.Li */ export function mountXterm( term: XTerm, fit: FitAddon, getContainer: () => HTMLDivElement | null, ws?: WebSocket | null, ) { const applyFit = () => { try { fitTerminal(fit, term, ws); term.focus(); } catch { /* noop */ } }; const tryMount = () => { const el = getContainer(); if (!el) { requestAnimationFrame(tryMount); return; } if (!term.element) { term.open(el); } requestAnimationFrame(applyFit); setTimeout(applyFit, 100); setTimeout(applyFit, 300); }; tryMount(); } /** ResizeObserver 监听容器尺寸,持续 fit // Logan.Li */ export function attachTerminalResize( container: HTMLDivElement, fit: FitAddon, term: XTerm, ws?: WebSocket | null, ) { let timer: ReturnType; const ro = new ResizeObserver(() => { clearTimeout(timer); timer = setTimeout(() => { try { fitTerminal(fit, term, ws); } catch { /* noop */ } }, 60); }); ro.observe(container); return () => { clearTimeout(timer); ro.disconnect(); }; }