From a19884541bde8e29e28f2b69e3e4d311adc86b7b Mon Sep 17 00:00:00 2001 From: engigu Date: Mon, 16 Mar 2026 09:08:36 +0800 Subject: [PATCH] fix: terminal wrap error --- internal/controllers/terminal_controller.go | 25 +++++++++++++++++++++ web/src/components/XTerminal.vue | 12 ++++++++++ 2 files changed, 37 insertions(+) diff --git a/internal/controllers/terminal_controller.go b/internal/controllers/terminal_controller.go index 45651c6..f961237 100644 --- a/internal/controllers/terminal_controller.go +++ b/internal/controllers/terminal_controller.go @@ -1,6 +1,7 @@ package controllers import ( + "encoding/json" "bufio" "io" "net/http" @@ -158,6 +159,20 @@ func (tc *TerminalController) handlePtyMode(conn *websocket.Conn, userID string) if err != nil { break } + + // 处理调整窗口大小的消息 + if len(message) > 0 && message[0] == '{' { + var resizeMsg struct { + Type string `json:"type"` + Rows uint16 `json:"rows"` + Cols uint16 `json:"cols"` + } + if err := json.Unmarshal(message, &resizeMsg); err == nil && resizeMsg.Type == "resize" { + pty.Setsize(ptmx, &pty.Winsize{Rows: resizeMsg.Rows, Cols: resizeMsg.Cols}) + continue + } + } + if _, err := ptmx.Write(message); err != nil { break } @@ -249,6 +264,16 @@ func (tc *TerminalController) handlePipeMode(conn *websocket.Conn, userID string if err != nil { break } + // 过滤调整窗口大小的消息(Windows Pipe 模式不支持调整尺寸,需过滤掉避免写入 stdin) + if len(message) > 0 && message[0] == '{' { + var resizeMsg struct { + Type string `json:"type"` + } + if err := json.Unmarshal(message, &resizeMsg); err == nil && resizeMsg.Type == "resize" { + continue + } + } + if _, err := stdin.Write(message); err != nil { break } diff --git a/web/src/components/XTerminal.vue b/web/src/components/XTerminal.vue index c735d35..0891c17 100644 --- a/web/src/components/XTerminal.vue +++ b/web/src/components/XTerminal.vue @@ -177,15 +177,19 @@ function connectWebSocket() { }, 100) } terminal?.focus() + // 连接成功后立即触发一次尺寸同步 + handleResize() } ws.onmessage = (event) => { if (event.data === '__PTY_MODE__') { isPtyMode = true + handleResize() // 关键:模式确认后立即同步一次尺寸 return } if (event.data === '__PIPE_MODE__') { isPtyMode = false + handleResize() return } terminal?.write(event.data) @@ -239,6 +243,14 @@ function dispose() { function handleResize() { try { fitAddon?.fit() + // 通知后端调整 PTY 尺寸 + if (isPtyMode && terminal && ws && ws.readyState === WebSocket.OPEN) { + ws.send(JSON.stringify({ + type: 'resize', + cols: terminal.cols, + rows: terminal.rows + })) + } } catch (e) { console.warn('Terminal resize failed:', e) }