feat: terminal now resize appropriately
This commit is contained in:
parent
a0183451ad
commit
33fc082217
@ -1,12 +1,13 @@
|
||||
"use client";
|
||||
"use client"
|
||||
|
||||
import { Terminal } from "@xterm/xterm";
|
||||
import { FitAddon } from "@xterm/addon-fit";
|
||||
import "./xterm.css";
|
||||
import { Terminal } from "@xterm/xterm"
|
||||
import { FitAddon } from "@xterm/addon-fit"
|
||||
import "./xterm.css"
|
||||
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { Socket } from "socket.io-client";
|
||||
import { Loader2 } from "lucide-react";
|
||||
import { ElementRef, useEffect, useRef, useState } from "react"
|
||||
import { Socket } from "socket.io-client"
|
||||
import { Loader2 } from "lucide-react"
|
||||
import { debounce } from "@/lib/utils"
|
||||
|
||||
export default function EditorTerminal({
|
||||
socket,
|
||||
@ -15,16 +16,17 @@ export default function EditorTerminal({
|
||||
setTerm,
|
||||
visible,
|
||||
}: {
|
||||
socket: Socket;
|
||||
id: string;
|
||||
term: Terminal | null;
|
||||
setTerm: (term: Terminal) => void;
|
||||
visible: boolean;
|
||||
socket: Socket
|
||||
id: string
|
||||
term: Terminal | null
|
||||
setTerm: (term: Terminal) => void
|
||||
visible: boolean
|
||||
}) {
|
||||
const terminalRef = useRef(null);
|
||||
const terminalRef = useRef<ElementRef<"div">>(null)
|
||||
const fitAddonRef = useRef<FitAddon | null>(null)
|
||||
|
||||
useEffect(() => {
|
||||
if (!terminalRef.current) return;
|
||||
if (!terminalRef.current) return
|
||||
// console.log("new terminal", id, term ? "reusing" : "creating");
|
||||
|
||||
const terminal = new Terminal({
|
||||
@ -36,56 +38,80 @@ export default function EditorTerminal({
|
||||
fontSize: 14,
|
||||
lineHeight: 1.5,
|
||||
letterSpacing: 0,
|
||||
});
|
||||
})
|
||||
|
||||
setTerm(terminal);
|
||||
|
||||
return () => {
|
||||
if (terminal) terminal.dispose();
|
||||
};
|
||||
}, []);
|
||||
setTerm(terminal)
|
||||
const dispose = () => {
|
||||
terminal.dispose()
|
||||
}
|
||||
return dispose
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
if (!term) return;
|
||||
if (!term) return
|
||||
|
||||
if (!terminalRef.current) return;
|
||||
const fitAddon = new FitAddon();
|
||||
term.loadAddon(fitAddon);
|
||||
term.open(terminalRef.current);
|
||||
fitAddon.fit();
|
||||
if (!terminalRef.current) return
|
||||
if (!fitAddonRef.current) {
|
||||
const fitAddon = new FitAddon()
|
||||
term.loadAddon(fitAddon)
|
||||
term.open(terminalRef.current)
|
||||
fitAddon.fit()
|
||||
fitAddonRef.current = fitAddon
|
||||
}
|
||||
|
||||
const disposableOnData = term.onData((data) => {
|
||||
socket.emit("terminalData", id, data);
|
||||
});
|
||||
socket.emit("terminalData", id, data)
|
||||
})
|
||||
|
||||
const disposableOnResize = term.onResize((dimensions) => {
|
||||
// const terminal_size = {
|
||||
// width: dimensions.cols,
|
||||
// height: dimensions.rows,
|
||||
// };
|
||||
fitAddon.fit();
|
||||
socket.emit("terminalResize", dimensions);
|
||||
});
|
||||
fitAddonRef.current?.fit()
|
||||
socket.emit("terminalResize", dimensions)
|
||||
})
|
||||
const resizeObserver = new ResizeObserver(
|
||||
debounce((entries) => {
|
||||
if (!fitAddonRef.current || !terminalRef.current) return
|
||||
|
||||
const entry = entries[0]
|
||||
if (!entry) return
|
||||
|
||||
const { width, height } = entry.contentRect
|
||||
|
||||
// Only call fit if the size has actually changed
|
||||
if (
|
||||
width !== terminalRef.current.offsetWidth ||
|
||||
height !== terminalRef.current.offsetHeight
|
||||
) {
|
||||
try {
|
||||
fitAddonRef.current.fit()
|
||||
} catch (err) {
|
||||
console.error("Error during fit:", err)
|
||||
}
|
||||
}
|
||||
}, 50) // Debounce for 50ms
|
||||
)
|
||||
|
||||
// start observing for resize
|
||||
resizeObserver.observe(terminalRef.current)
|
||||
return () => {
|
||||
disposableOnData.dispose();
|
||||
disposableOnResize.dispose();
|
||||
};
|
||||
}, [term, terminalRef.current]);
|
||||
disposableOnData.dispose()
|
||||
disposableOnResize.dispose()
|
||||
resizeObserver.disconnect()
|
||||
}
|
||||
}, [term, terminalRef.current])
|
||||
|
||||
useEffect(() => {
|
||||
if (!term) return;
|
||||
if (!term) return
|
||||
const handleTerminalResponse = (response: { id: string; data: string }) => {
|
||||
if (response.id === id) {
|
||||
term.write(response.data);
|
||||
term.write(response.data)
|
||||
}
|
||||
};
|
||||
socket.on("terminalResponse", handleTerminalResponse);
|
||||
|
||||
}
|
||||
socket.on("terminalResponse", handleTerminalResponse)
|
||||
|
||||
return () => {
|
||||
socket.off("terminalResponse", handleTerminalResponse);
|
||||
};
|
||||
}, [term, id, socket]);
|
||||
socket.off("terminalResponse", handleTerminalResponse)
|
||||
}
|
||||
}, [term, id, socket])
|
||||
|
||||
return (
|
||||
<>
|
||||
@ -102,5 +128,5 @@ export default function EditorTerminal({
|
||||
) : null}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user