Use Ghostty for native mobile terminals - #2656
Conversation
| private fun emitResize() { | ||
| if ( | ||
| width <= 0 || | ||
| height <= 0 || | ||
| terminalCanvas.width <= 0 || | ||
| terminalCanvas.height <= 0 || | ||
| isCleanedUp | ||
| ) { | ||
| return | ||
| } | ||
| val nextCols = (terminalCanvas.usableWidth() / terminalCanvas.cellWidthPx) | ||
| .toInt() | ||
| .coerceIn(2, 400) | ||
| val nextRows = (terminalCanvas.usableHeight() / terminalCanvas.cellHeightPx) | ||
| .toInt() | ||
| .coerceIn(2, 200) |
There was a problem hiding this comment.
Hardware navigation keys are dropped
When the Android Ghostty renderer receives Escape, Tab, arrow, or other terminal navigation keys from a hardware keyboard, this listener handles only Delete and Ctrl+A–Z and the native React adapter does not provide the shared onTerminalKey encoding path, causing those keys not to reach shells or terminal TUIs.
Knowledge Base Used: Paseo Mobile App (packages/app)
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
| surfaceCreationFailed = true | ||
| return |
There was a problem hiding this comment.
Surface failure disables the terminal
When Ghostty initialization or subsequent app or surface creation fails, this path permanently sets surfaceCreationFailed without reporting readiness failure or switching to the WebView renderer. The view never emits its first resize, so JavaScript keeps terminal operations queued and the terminal remains behind its loading state for the lifetime of the view.
Knowledge Base Used: Paseo Mobile App (packages/app)
|
| Filename | Overview |
|---|---|
| packages/app/src/components/terminal-emulator.native.tsx | Selects the native renderer when available, queues terminal operations until resize readiness, tracks input modes, and falls back to the extracted WebView renderer. |
| packages/app/modules/paseo-terminal/android/src/main/java/expo/modules/paseoterminal/PaseoTerminalView.kt | Implements Android terminal lifecycle, input, resize, selection, and rendering, but fails to forward common hardware terminal navigation keys. |
| packages/app/modules/paseo-terminal/android/src/main/cpp/paseo_terminal_jni.cpp | Bridges libghostty-vt terminal state, snapshots, scrolling, themes, and selection to the Android view. |
| packages/app/modules/paseo-terminal/ios/PaseoTerminalView.swift | Implements the GhosttyKit iOS surface, but a surface creation failure permanently prevents readiness and leaves terminal operations queued. |
| packages/app/src/components/terminal-emulator-webview.native.tsx | Preserves the existing xterm WebView renderer as the fallback implementation. |
| packages/app/plugins/with-fdroid-autolinking.js | Excludes the binary-backed terminal module from F-Droid native autolinking. |
| packages/app/app.config.js | Raises the generated iOS deployment target to 16.1 for the vendored GhosttyKit build. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart LR
Runtime[Terminal stream runtime] --> Detect{Native view manager available?}
Detect -->|Yes| Native[NativeTerminalEmulator]
Detect -->|No| WebView[xterm WebView fallback]
Native -->|iOS| GhosttyKit[GhosttyKit surface]
Native -->|Android| JNI[libghostty-vt JNI]
JNI --> Canvas[Android Canvas renderer]
GhosttyKit --> Resize[Input / resize / focus events]
Canvas --> Resize
Resize --> Runtime
Reviews (1): Last reviewed commit: "feat(app): use Ghostty for native termin..." | Re-trigger Greptile
Summary
GhosttyKiton iOS andlibghostty-vtplus a Canvas/JNI renderer on AndroidPackaging and compatibility
GhosttyKitbuildThe checked-in native module adds approximately 55 MB to the source tree, mostly the two iOS static-library slices.
Known follow-ups
Verification
npm run build:app-depsnpm run build:servernpm run typechecknpm run lintnpm run format:checknpx vitest run packages/app/src/terminal/runtime/terminal-snapshot.test.ts --bail=1:getpaseo-mobile-terminal-native:assembleDebugacross arm64-v8a, armeabi-v7a, x86, and x86_64readelf -lWalignment check for vendoredlibghostty-vt.soand generatedlibpaseoterminal.soacross all four ABIsiOS prebuild and autolinking were verified on Linux; an Xcode compile/runtime pass still needs macOS CI or a device build.