History

Handle init failure surfacing and empty XDG_CONFIG_HOME

- 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

Pixel Perfect committed 4 months ago

Commit c1caaa31 parent 7266faf2 files · +20 −5Browse files

Unified · Split

2 files
  1. apps/server/src/terminal/ghosttyStyle.ts +6 −1
  2. apps/web/src/components/ThreadTerminalDrawer.tsx +14 −4
apps/server/src/terminal/ghosttyStyle.ts+6−1
@@ -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* () {
apps/web/src/components/ThreadTerminalDrawer.tsx+14−4
@@ -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;