diff --git a/package.json b/package.json index 55b8e09da..7a88d2038 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,7 @@ "lucide-react": "^0.577.0", "node-pty": "^1.1.0", "radix-ui": "^1.4.3", - "restty": "^0.1.34", + "restty": "github:nwparker/restty#orca/desktop-word-line-selection", "shadcn": "^4.0.8", "simple-git": "^3.33.0", "tailwind-merge": "^3.5.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f9ec94af0..e27ec320a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -45,8 +45,8 @@ importers: specifier: ^1.4.3 version: 1.4.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) restty: - specifier: ^0.1.34 - version: 0.1.34(typescript@5.9.3) + specifier: github:nwparker/restty#orca/desktop-word-line-selection + version: https://codeload.github.com/nwparker/restty/tar.gz/fb8a604be99f570fb437b414790ef36fe85c8f17(typescript@5.9.3) shadcn: specifier: ^4.0.8 version: 4.0.8(@types/node@25.5.0)(typescript@5.9.3) @@ -3798,8 +3798,9 @@ packages: resolution: {integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==} engines: {node: '>=18'} - restty@0.1.34: - resolution: {integrity: sha512-466w3EXe/yLNfO8Jbha6tLLTij1QRI2MnKbm0UHCmP33Avon4YikIeIIPW1ga1A9310poAcnkoXPeV0b84Yyxw==} + restty@https://codeload.github.com/nwparker/restty/tar.gz/fb8a604be99f570fb437b414790ef36fe85c8f17: + resolution: {tarball: https://codeload.github.com/nwparker/restty/tar.gz/fb8a604be99f570fb437b414790ef36fe85c8f17} + version: 0.1.34 engines: {bun: '>=1.2.0'} retry@0.12.0: @@ -8146,7 +8147,7 @@ snapshots: onetime: 7.0.0 signal-exit: 4.1.0 - restty@0.1.34(typescript@5.9.3): + restty@https://codeload.github.com/nwparker/restty/tar.gz/fb8a604be99f570fb437b414790ef36fe85c8f17(typescript@5.9.3): dependencies: text-shaper: 0.1.18(typescript@5.9.3) transitivePeerDependencies: diff --git a/src/renderer/src/components/TerminalPane.tsx b/src/renderer/src/components/TerminalPane.tsx index 08138468b..649d952c4 100644 --- a/src/renderer/src/components/TerminalPane.tsx +++ b/src/renderer/src/components/TerminalPane.tsx @@ -88,6 +88,7 @@ function createIpcPtyTransport( onBell?: () => void ): PtyTransport { let connected = false + let destroyed = false let ptyId: string | null = null let pendingEscape = false let inOsc = false @@ -103,6 +104,13 @@ function createIpcPtyTransport( let unsubData: (() => void) | null = null let unsubExit: (() => void) | null = null + function cleanupListeners(): void { + unsubData?.() + unsubExit?.() + unsubData = null + unsubExit = null + } + return { async connect(options) { storedCallbacks = options.callbacks @@ -113,10 +121,20 @@ function createIpcPtyTransport( rows: options.rows ?? 24, cwd }) + + // If destroyed while spawn was in flight, kill the new pty and bail + if (destroyed) { + window.api.pty.kill(result.id) + return + } + ptyId = result.id connected = true onPtySpawn?.(result.id) + // Clean up any stale listeners before registering new ones + cleanupListeners() + unsubData = window.api.pty.onData((payload) => { if (payload.id === ptyId) { storedCallbacks.onData?.(payload.data) @@ -154,10 +172,7 @@ function createIpcPtyTransport( window.api.pty.kill(ptyId) connected = false ptyId = null - unsubData?.() - unsubExit?.() - unsubData = null - unsubExit = null + cleanupListeners() storedCallbacks.onDisconnect?.() } }, @@ -179,6 +194,7 @@ function createIpcPtyTransport( }, destroy() { + destroyed = true this.disconnect() } } @@ -623,7 +639,9 @@ export default function TerminalPane({ renderer: 'auto', fontSize: currentSettings?.terminalFontSize ?? 14, fontSizeMode: 'em', - alphaBlending: 'native', + fontHinting: true, + fontHintTarget: 'light', + alphaBlending: 'linear-corrected', maxScrollbackBytes: currentSettings?.terminalScrollbackBytes ?? 10_000_000, ptyTransport: createIpcPtyTransport( cwd,