- Attach a rejection handler to the terminal WASM init so a load failure logs, shows a message in the viewport, and clears on retry instead of leaving a blank pane and an unhandled rejection - Treat an empty XDG_CONFIG_HOME as unset per the XDG spec instead of resolving the Ghostty config relative to the server cwd
Unified · Split
| @@ -187,7 +187,12 @@ export const loadGhosttyTerminalStyle: Effect.Effect< · 186 unmodified lines | |||
| 187 | const fs = yield* FileSystem.FileSystem; | 187 | const fs = yield* FileSystem.FileSystem; |
| 188 | const path = yield* Path.Path; | 188 | const path = yield* Path.Path; |
| 189 | const home = NodeOS.homedir(); | 189 | const home = NodeOS.homedir(); |
| 190 | const xdgConfigHome = process.env["XDG_CONFIG_HOME"] ?? path.join(home, ".config"); | 190 | // Per the XDG spec an empty XDG_CONFIG_HOME must be treated as unset. |
| 191 | const xdgConfigHomeEnv = process.env["XDG_CONFIG_HOME"]; | ||
| 192 | const xdgConfigHome = | ||
| 193 | xdgConfigHomeEnv !== undefined && xdgConfigHomeEnv.length > 0 | ||
| 194 | ? xdgConfigHomeEnv | ||
| 195 | : path.join(home, ".config"); | ||
| 191 | 196 | ||
| 192 | const readFirstExisting = (candidates: ReadonlyArray<string>) => | 197 | const readFirstExisting = (candidates: ReadonlyArray<string>) => |
| 193 | Effect.gen(function* () { | 198 | Effect.gen(function* () { |
| @@ -500,6 +500,8 @@ export function TerminalViewport({ · 499 unmodified lines | |||
| 500 | let teardown: (() => void) | undefined; | 500 | let teardown: (() => void) | undefined; |
| 501 | 501 | ||
| 502 | const setUpTerminal = (mount: HTMLDivElement): (() => void) => { | 502 | const setUpTerminal = (mount: HTMLDivElement): (() => void) => { |
| 503 | // Clear any failure message left by an earlier init attempt. | ||
| 504 | mount.textContent = ""; | ||
| 503 | const localApi = readLocalApi(); | 505 | const localApi = readLocalApi(); |
| 504 | 506 | ||
| 505 | const style = readTerminalStyle(); | 507 | const style = readTerminalStyle(); |
| @@ -887,10 +889,18 @@ export function TerminalViewport({ · 381 unmodified lines | |||
| 887 | }; | 889 | }; |
| 888 | }; | 890 | }; |
| 889 | 891 | ||
| 890 | void ensureGhosttyReady().then(() => { | 892 | void ensureGhosttyReady().then( |
| 891 | if (effectDisposed || containerRef.current !== mountElement) return; | 893 | () => { |
| 892 | teardown = setUpTerminal(mountElement); | 894 | if (effectDisposed || containerRef.current !== mountElement) return; |
| 893 | }); | 895 | teardown = setUpTerminal(mountElement); |
| 896 | }, | ||
| 897 | (error: unknown) => { | ||
| 898 | if (effectDisposed || containerRef.current !== mountElement) return; | ||
| 899 | console.error("ghostty-web terminal failed to initialize", error); | ||
| 900 | mountElement.textContent = | ||
| 901 | "Terminal failed to initialize. Close and reopen the terminal to retry."; | ||
| 902 | }, | ||
| 903 | ); | ||
| 894 | 904 | ||
| 895 | return () => { | 905 | return () => { |
| 896 | effectDisposed = true; | 906 | effectDisposed = true; |