chore: add .jerboa/security.json profile and plan-android.md
ober
53ba85130a4fcecdd8968d16016b66b5f41fb295
new file mode 100644 --- /dev/null +++ b/.jerboa/security.json @@ -0,0 +1,22 @@ +{ + "version": 1, + "repo": "jerboa-emacs", + "extends": ["jerboa:cli", "jerboa:gui", "jerboa:ffi"], + "paths": { + "production": ["*.ss", "*.sls", "lib/**/*.ss", "lib/**/*.sls", "src/**/*.{ss,sls,c,h,cpp,hpp}", "tools/**", "Makefile"], + "tests": ["test/**", "tests/**", "**/*-test.ss"], + "generated": ["build/**", "dist/**", "target/**", "*.so", "*.dylib", "*.wpo"], + "vendor": ["vendor/**", "third_party/**"], + "docs": ["README.md", "docs/**", "*.md"] + }, + "policy": { + "failOn": ["critical", "high"], + "imports": { "directChezscheme": "allow-in-ffi-boundaries" }, + "ffi": { "allowed": true, "requireOwnershipComments": true, "requireDynamicWindCleanup": true }, + "process": { "shellInterpolation": "deny", "promptForExternalCommands": true }, + "network": { "requireTimeouts": true }, + "eval": { "stringEval": "deny", "bareRead": "deny", "allowReadEval": false }, + "gui": { "requireCallbackLifetimeGuards": true } + }, + "suppressions": [] +} new file mode 100644 --- /dev/null +++ b/plan-android.md @@ -0,0 +1,138 @@ +# Android Build Plan for jerboa-emacs + +## Can You Build a Qt-Based Android App for jerboa-emacs? + +**Short answer: Yes, but it requires significant work — and you're actually closer than you might think** because you're already running in Termux on Android. + +## What Works in Your Favor + +1. **You're already on Android.** The repo lives at `/data/data/com.termux/files/home/`, meaning Chez Scheme already runs on your device's architecture (likely aarch64). + +2. **Qt6 Widgets DO work on Android.** Despite common advice to use QML, Qt6Widgets has an `android` QPA plugin and can render on Android. It won't look native, but for an Emacs-like editor, that's fine — nobody expects Material Design. + +3. **The static binary approach is well-proven.** The existing Docker pipeline already produces a fully self-contained ELF binary with embedded boot files and memfd loading. The same approach could target Android's NDK toolchain. + +4. **The FFI architecture is clean.** The three-layer design (C++ shim → C callback bridge → Scheme FFI) has no fundamental desktop-only assumptions. The SPSC ring buffer for GC-safe callbacks is platform-agnostic. + +## The Real Obstacles + +| Issue | Difficulty | Notes | +|---|---|---| +| **Qt6 for Android cross-compilation** | Medium | Qt6 supports Android as a target. You'd need to build Qt6 static libs with the Android NDK toolchain instead of Alpine musl. Qt's cmake supports `-DQT_HOST_PATH` for cross builds. | +| **Chez Scheme on Android** | Low | You already have it running in Termux. For a standalone APK, you'd need to compile Chez with the NDK — Chez supports `--machine=ta6le` and `--machine=arm64le` and has been built on Android before. | +| **APK packaging** | Medium | An Android app needs a Java/Kotlin `Activity` that hosts a `QtActivity` (Qt provides this). The static binary would become an `.so` loaded by Qt's Android bootstrapper. | +| **`/proc/self/exe` and `memfd_create`** | Low | Both work on Android's Linux kernel. `memfd_create` is available since Android 8.0 (API 26). | +| **Touch input** | Medium | Qt Widgets receive touch events as mouse events by default. Basic editing would work. You'd want to add a virtual keyboard trigger and possibly gesture support for scrolling. | +| **QScintilla on Android** | Unknown | QScintilla hasn't been widely tested on Android. May need patches for touch scrolling and DPI scaling. | +| **File access** | Low | Android's scoped storage adds friction, but Termux-style apps can request broad file access. | + +## Two Realistic Paths + +### Path A: Termux + X11 (Easiest — works today) + +Run `jemacs-qt` inside Termux with an X11 server app (like Termux:X11). You'd just need to: + +1. Build Qt6 and QScintilla as shared libs in Termux (`pkg install qt6-qtbase`) +2. Compile chez-qt and jerboa-emacs natively +3. Launch with `DISPLAY=:0` against Termux:X11 + +This gives you a working Qt app on Android with zero APK packaging. + +**Pros:** +- Works with minimal changes to existing code +- Native aarch64 compilation, no cross-compile needed +- Full filesystem access via Termux +- Can iterate quickly + +**Cons:** +- Requires Termux:X11 app running alongside +- Not a standalone APK you can distribute +- X11 adds a layer of indirection for input/display + +### Path B: Standalone APK (Proper Android app) + +This is the "real" solution but requires: + +1. **Cross-compile Qt6 static + QScintilla with Android NDK** + - Qt6 has official Android support via cmake + - Use `-DQT_HOST_PATH=/usr/local/Qt` to point at a host Qt for tools (moc, rcc, uic) + - Target: `android-arm64` with NDK r26+ + - Build QScintilla against the Android Qt6 sysroot + +2. **Cross-compile Chez Scheme with NDK** + - Chez supports `--machine=arm64le` (or `tarm64le` for threaded) + - Configure with NDK's clang as CC + - Produces `libkernel.a` for Android + +3. **Adapt `jemacs-qt-main.c` to be a JNI-loadable library** + - Replace `main()` with a JNI entry point or use Qt's `qtmain` Android bootstrapper + - Qt provides `QAndroidApplication` and `androiddeployqt` tooling + - The `Sscheme_init` / `Sbuild_heap` / `Sscheme_script` sequence stays the same + +4. **Create a minimal Android project with Qt's `QtActivity`** + - Qt ships a `QtActivity.java` that hosts the native Qt event loop + - Gradle project wraps the native `.so` into an APK + - `androiddeployqt` automates most of this + +5. **Adapt the Dockerfile/build pipeline for Android targets** + - New Dockerfile (or Makefile target) using Android NDK instead of Alpine musl + - Same WPO + boot-file embedding strategy + - Output: `libjemacs-qt.so` instead of `jemacs-qt` ELF binary + +6. **Handle Android lifecycle events** + - `onPause` / `onResume` → save/restore editor state (persist.ss already does this) + - Back button → could map to `C-g` or buffer switching + - App suspension → flush buffers + +7. **Touch input adaptations** + - Virtual keyboard: `QInputMethod::show()` on tap in editor area + - Long-press for context menu (copy/paste/select) + - Pinch-to-zoom for font size + - Swipe gestures for scrolling (Qt Widgets handles basic scrolling) + +**Pros:** +- Standalone installable APK +- Proper Android app lifecycle integration +- Can be distributed via sideloading or F-Droid +- No dependency on Termux + +**Cons:** +- Significant build infrastructure work +- Cross-compilation complexity +- Touch UX needs real design work +- QScintilla on Android is uncharted territory + +## Architecture Overview (for Path B) + +``` +Android APK +├── lib/arm64-v8a/ +│ └── libjemacs-qt.so # The entire app as a shared library +│ ├── Embedded boot files (petite, scheme, jemacs-qt) +│ ├── Embedded program (.so) +│ ├── Qt6 static libs (Core, Gui, Widgets) +│ ├── QScintilla static +│ ├── libvterm static +│ ├── tree-sitter + grammars +│ ├── Chez libkernel.a +│ └── C shims (qt_shim, qt_chez_shim, pcre2, pty, etc.) +├── classes.dex # Minimal Java: QtActivity bootstrap +├── AndroidManifest.xml +└── res/ # Icons, splash screen +``` + +## Recommendation + +**Start with Path A.** Install Termux:X11, build Qt6 in Termux, and run the existing code. You'll have a working Emacs on Android in hours, not weeks. If that proves the concept is worth investing in, Path B gives you a distributable APK later. + +The fundamental architecture of jerboa-emacs (embedded Chez + static Qt + C FFI bridge) is actually well-suited to Android — the main work is build-system plumbing, not architectural changes. + +## Key Files to Modify for Android Support + +- `jemacs-qt-main.c` — Entry point adaptation (JNI or Qt Android main) +- `Makefile` — New `android-qt` target +- `Dockerfile` — New Android NDK variant (or separate `Dockerfile.android`) +- `build-binary-qt.ss` — Target machine type (`tarm64le` instead of `ta6le`) +- `vendor/qt_shim.cpp` — Minor `#ifdef __ANDROID__` guards if needed +- `src/jerboa-emacs/qt/app.ss` — Android lifecycle hooks +- `src/jerboa-emacs/qt/sci-shim.ss` — Touch/DPI adaptations