From bcba5932d50bffb4ec8be9fbae65d6bd5b048a7f Mon Sep 17 00:00:00 2001 From: Augustin Date: Wed, 22 Apr 2026 18:46:29 +0200 Subject: [PATCH] fix(terminal): restore terminal input and cursor visibility - Fix shell execution to avoid --login flag causing issues on some shells - Improve terminal initialization timing with requestAnimationFrame - Force display visibility on xterm instances via CSS - Ensure container has proper min-height and overflow handling Assisted-by: MiniMax-M2.7 via Crush --- internal/api/terminal.go | 11 ++++++++--- web/src/components/Shell.jsx | 24 +++++++++++++++++------- web/src/styles/global.css | 3 ++- 3 files changed, 27 insertions(+), 11 deletions(-) diff --git a/internal/api/terminal.go b/internal/api/terminal.go index fe0dc37..2d56ea6 100644 --- a/internal/api/terminal.go +++ b/internal/api/terminal.go @@ -7,6 +7,7 @@ import ( "net/http" "os" "os/exec" + "path/filepath" "runtime" "strings" "sync" @@ -109,12 +110,16 @@ func (s *Server) handleTerminalWS(w http.ResponseWriter, r *http.Request) { return } - if strings.Contains(shell, "wsl") { + shellName := filepath.Base(shell) + switch shellName { + case "wsl": cmd = exec.Command(shell, "--shell-type", "login") - } else if strings.Contains(shell, "powershell") || strings.Contains(shell, "pwsh") { + case "powershell", "pwsh": cmd = exec.Command(shell, "-NoLogo", "-NoProfile") - } else { + case "fish": cmd = exec.Command(shell, "--login") + default: + cmd = exec.Command(shell) } } diff --git a/web/src/components/Shell.jsx b/web/src/components/Shell.jsx index d4af5bd..87b9868 100644 --- a/web/src/components/Shell.jsx +++ b/web/src/components/Shell.jsx @@ -239,15 +239,25 @@ export default function Shell({ api }) { useEffect(() => { const tab = tabs.find(t => t.id === activeTab) - if (tab && !tabsRef.current[tab.id]) { - const timer = setTimeout(() => initTerminal(tab.id, tab), 50) - return () => clearTimeout(timer) - } else if (tab && tabsRef.current[tab.id]) { + if (!tab) return + + const container = document.getElementById(`terminal-${tab.id}`) + if (!container) return + + if (!tabsRef.current[tab.id]) { const timer = setTimeout(() => { - const { fitAddon } = tabsRef.current[tab.id] - fitAddon.fit() - }, 50) + initTerminal(tab.id, tab) + requestAnimationFrame(() => { + const entry = tabsRef.current[tab.id] + if (entry) entry.fitAddon.fit() + }) + }, 100) return () => clearTimeout(timer) + } else { + requestAnimationFrame(() => { + const entry = tabsRef.current[tab.id] + if (entry) entry.fitAddon.fit() + }) } }, [activeTab, tabs, initTerminal]) diff --git a/web/src/styles/global.css b/web/src/styles/global.css index 728f01e..ea7fd40 100644 --- a/web/src/styles/global.css +++ b/web/src/styles/global.css @@ -269,7 +269,7 @@ input::placeholder { color: var(--text-disabled); } .sidebar-tab.active { background: var(--accent); color: #fff; font-weight: 600; } .shell-layout { display: flex; height: 100%; } -.shell-terminal-col { flex: 1; display: flex; flex-direction: column; min-width: 0; } +.shell-terminal-col { flex: 1; display: flex; flex-direction: column; min-width: 0; min-height: 0; overflow: hidden; } .shell-tabs-bar { display: flex; align-items: center; background: var(--bg-surface); @@ -377,6 +377,7 @@ input::placeholder { color: var(--text-disabled); } .shell-xterm-wrapper { flex: 1; background: var(--bg); overflow: hidden; position: relative; } .shell-xterm-instance { position: absolute; inset: 0; padding: 4px; + display: block !important; } .shell-xterm-instance .xterm { height: 100%; padding: 4px; }