feat(android): font, contentInsets, lineNumbers (closes #37, refs #32)#38
Merged
Conversation
This was referenced May 14, 2026
#32) Replace the three style/layout no-op stubs in SourceEditorViewManager with real wiring through SourceEditorView setters. Demo app gains a matching `#` toggle in the status bar to flip the gutter at runtime. Library - SourceEditorView.kt: - setFont: maps `{family,size}` → `editor.typefaceText` + `editor.setTextSize`. Defaults to MONOSPACE at 14pt to match Apple's `monospacedSystemFont(ofSize: 14)` when family/size are absent. - setContentInsets: maps `{top,bottom,left,right}` (RN dp) → raw px via display-metrics, then `View.setPadding(left,top,right,bottom)`. Mirrors UIEdgeInsets semantics — applied to the editor's text container. - setLineNumbers: `editor.isLineNumberEnabled = value`. Sora ships the gutter ON by default; this lets the prop turn it off. - SourceEditorViewManager.kt: forward each of the three props to the view setters. Only `setTheme` remains a no-op; that's the next sub-PR. Demo - App.android.tsx: pass `lineNumbers`, `font={size:13}`, and `contentInsets={top:12,bottom:12,left:8,right:8}` to SourceEditor — matches the iOS App.tsx defaults. Status bar gains a `#` toggle that flips lineNumbers state, mirroring iOS's Toggle(systemImage="number"). Verified - ./gradlew :app:assembleDebug → BUILD SUCCESSFUL - npm run typecheck clean Stacked on top of feat/android-highlighting (PR #36); merge that first to get a clean diff against develop here.
9f2e81a to
558a0d0
Compare
LeslieOA
added a commit
that referenced
this pull request
May 29, 2026
#44) After this lands, every code-side and docs-side sub-task on #32 is done; the tracking issue closes. README.md - Platform table: Android → "Shipping (Fabric / New Architecture)" at API 24. Drop "Stub only" row. - Status section: name all three platforms. - Quick start: clarify cocoapods-spm is iOS-only; macOS uses RN's first-party SPM, Android pulls Sora-Editor from Maven Central. - Plugin snippet: add expo-build-properties android entries (minSdkVersion + newArchEnabled). - Roadmap: drop "Android (TextKit alternative)" — it's done. - Repo layout: describe android/ proper + the Expo CNG-shared example/expo-app/ (was example/ios-app/). - Add "Running the Android example" section mirroring iOS scripts. - License section: add Sora-Editor + LGPL boundary note. docs/installation.md - Add Android row to deployment-targets table (API 24). - New "Backing libraries" subsection summarising STTextView vs Sora. - Scope the SPM bridging section explicitly to iOS / macOS. - New "Android (Expo CNG)" section: documents the autolinking-from- Maven flow + the coreLibraryDesugaring requirement that our config plugin auto-injects. - New "Bare React Native — Android" section with the manual build.gradle snippet for non-Expo consumers. - New "License note for Android" calling out the LGPL inheritance. - Working examples block: ios-app → expo-app, add Android. docs/usage.md - `language` prop note: spell out the Android grammar source (VS Code TextMate via Sora) and the HTML caveat (no nested CSS/JS recursion on Android, unlike STTextView's attributed text). - `lineNumbers` note: now applies to all platforms. - `contentInsets` note: spell out the Android dp→px mapping. docs/examples.md - Add Android row to platform table — same expo-app/ project as iOS. - Refresh layout/toolchain narrative for the Expo-shared model. - Add android:run script line. CHANGELOG.md - Unreleased entry covering #34, #36, #38, #40, #42 plus the ios-app→expo-app rename. Stacked on feat/ci-android (#42); merge order: #36 → #38 → #40 → #42 → this.
LeslieOA
added a commit
that referenced
this pull request
May 29, 2026
Wire the `theme` prop on Android. Bundles a light TextMate theme (quietlight.json from Sora's sample app) alongside the existing darcula.json. SoraTextMate now loads both at setup and exposes applyTheme() that flips ThemeRegistry's active scheme + re-applies TextMateColorScheme on the editor. - 'light' / 'dark' map to the bundled themes by name. - 'auto' (and any unknown value) reads Configuration.UI_MODE_NIGHT_MASK to pick between them — same semantics as the iOS overrideUserInterfaceStyle = .unspecified path. Refactor: SoraTextMate.apply → applyLanguage / applyTheme, since the two prop concerns now diverge. Caller code in SourceEditorView updated accordingly. Demo: App.android.tsx gains a tiny A/L/D segmented picker in the status bar to exercise the prop. Initial state is 'auto'. Verified: ./gradlew :app:assembleDebug → BUILD SUCCESSFUL, npm run typecheck clean. Stacked on feat/android-style-props (#38). Merge order: #36 → #38 → this.
LeslieOA
added a commit
that referenced
this pull request
May 29, 2026
#40) Wire the `theme` prop on Android. Bundles a light TextMate theme (quietlight.json from Sora's sample app) alongside the existing darcula.json. SoraTextMate now loads both at setup and exposes applyTheme() that flips ThemeRegistry's active scheme + re-applies TextMateColorScheme on the editor. - 'light' / 'dark' map to the bundled themes by name. - 'auto' (and any unknown value) reads Configuration.UI_MODE_NIGHT_MASK to pick between them — same semantics as the iOS overrideUserInterfaceStyle = .unspecified path. Refactor: SoraTextMate.apply → applyLanguage / applyTheme, since the two prop concerns now diverge. Caller code in SourceEditorView updated accordingly. Demo: App.android.tsx gains a tiny A/L/D segmented picker in the status bar to exercise the prop. Initial state is 'auto'. Verified: ./gradlew :app:assembleDebug → BUILD SUCCESSFUL, npm run typecheck clean. Stacked on feat/android-style-props (#38). Merge order: #36 → #38 → this.
LeslieOA
added a commit
that referenced
this pull request
May 29, 2026
…42) * feat(android): TextMate syntax highlighting (closes #35, refs #32) Wire Sora-Editor's TextMate language module so the cross-platform \`language\` prop (markdown / json / javascript / typescript / html) actually highlights on Android. Plaintext stays unhighlighted, matching iOS/macOS behaviour. Library - android/build.gradle: add language-textmate dep + core library desugaring (joni regex engine needs java.time on minSdk 24). - android/src/.../SoraTextMate.kt: NEW. Lazy one-shot setup of Sora's GrammarRegistry + ThemeRegistry, with a string→scope map and an apply() that wires editor.colorScheme + editor.setEditorLanguage. Color-scheme-before-language ordering matters — Sora silently no-ops if a TextMateLanguage is set against a non-TextMateColorScheme. - android/src/.../SourceEditorViewManager.kt: setLanguage now delegates to SoraTextMate.apply (was no-op). - android/src/.../SourceEditorView.kt: forward setLanguage from manager. Assets - android/src/main/assets/textmate/{markdown,json,javascript,typescript, html}/*.tmLanguage.json: grammars from VS Code 1.94.0 (microsoft/vscode/extensions/<lang>-basics/syntaxes/), MIT-licensed. - android/src/main/assets/textmate/themes/dark_modern.json: VS Code's Dark Modern theme — closest off-the-shelf TextMate theme to the iOS/macOS Highlighter palette. - android/src/main/assets/textmate/languages.json: manifest mapping language names to scope + grammar paths, consumed by Sora's GrammarRegistry.loadGrammars(). Asset payload: ~625KB grammars + 5KB theme. Joni regex engine adds ~1.2MB AAR-uncompressed via the language-textmate dep. Justified for a source editor. Expo config plugin - app.plugin.js: extend with withAppBuildGradle modifier that injects coreLibraryDesugaringEnabled + the desugar_jdk_libs dep into android/app/build.gradle. Sora's language-textmate AAR declares the desugaring requirement; without it consumer build fails at checkDebugAarMetadata. Runs alongside the existing iOS Podfile cocoapods-spm injection. Verified - ./gradlew :app:assembleDebug → BUILD SUCCESSFUL. - expo prebuild --platform android applies the desugar injection cleanly. Not yet verified (needs your machine): - Highlighting actually renders correctly per language. Test plan: cycle through the language chips in App.android.tsx and confirm token colours change. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(android): swap dark_modern (JSONC) → darcula (strict JSON) VS Code's `dark_modern.json` uses JSONC (trailing commas). Sora's `TMParserJSON` is strict Gson and rejects it at runtime with: com.google.gson.stream.MalformedJsonException: Expected name at line 129 column 3 path $..widget.border Swap to `darcula.json` (taken verbatim from sora-editor's sample app — guaranteed to parse under their parser). Theme is a one-line constant swap; can revisit when we wire the `theme` prop sub-task in #32. * fix(android-demo): per-language sample text The single-sample demo masked TextMate highlighting on tab switch — a JS-flavored blob viewed under e.g. the markdown grammar tokenises as plain paragraph text, which looks like "lost highlighting" but is correct grammar behaviour. Mirror App.tsx's per-language SAMPLES record so each tab loads syntax-appropriate content. JS-side change only; library code unchanged. * refactor(example): share preview helpers, mirror iOS UI on Android Bring App.android.tsx to functional parity with App.tsx (modulo the iOS-only @expo/ui glass aesthetic): - Extract `stripTSTypes`, `wrapJSConsoleHTML`, `wrapMarkdownHTML` into `previewHelpers.ts`. Both apps import from there. Pure string-builders, no React/RN deps — safe to share. - App.android.tsx now matches iOS in functionality: - Per-language sample text (already landed in the previous commit). - Source/Preview segmented toggle in the status bar, gated on previewable languages (markdown / html / js / ts). - WebView-rendered preview using the shared helpers (markdown via marked, HTML rendered as-is, JS executed in-browser, TS stripped then executed). - Auto-blur the editor when switching to preview. - Drop back to source view automatically when switching to a non-previewable language. Skipped intentionally on Android (props are still ViewManager no-ops on Android until their respective PRs against #32 land): - lineNumbers toggle UI - font / theme / contentInsets toolbar pieces - @expo/ui glass-effect aesthetic — `@expo/ui/jetpack-compose` exposes a different component vocabulary (Switch / SegmentedButton / Chip vs Toggle / Picker / GlassEffectContainer), so true UI sharing isn't possible without a thicker abstraction layer than this PR warrants. * feat(android): font, contentInsets, lineNumbers props (closes #37, refs #32) Replace the three style/layout no-op stubs in SourceEditorViewManager with real wiring through SourceEditorView setters. Demo app gains a matching `#` toggle in the status bar to flip the gutter at runtime. Library - SourceEditorView.kt: - setFont: maps `{family,size}` → `editor.typefaceText` + `editor.setTextSize`. Defaults to MONOSPACE at 14pt to match Apple's `monospacedSystemFont(ofSize: 14)` when family/size are absent. - setContentInsets: maps `{top,bottom,left,right}` (RN dp) → raw px via display-metrics, then `View.setPadding(left,top,right,bottom)`. Mirrors UIEdgeInsets semantics — applied to the editor's text container. - setLineNumbers: `editor.isLineNumberEnabled = value`. Sora ships the gutter ON by default; this lets the prop turn it off. - SourceEditorViewManager.kt: forward each of the three props to the view setters. Only `setTheme` remains a no-op; that's the next sub-PR. Demo - App.android.tsx: pass `lineNumbers`, `font={size:13}`, and `contentInsets={top:12,bottom:12,left:8,right:8}` to SourceEditor — matches the iOS App.tsx defaults. Status bar gains a `#` toggle that flips lineNumbers state, mirroring iOS's Toggle(systemImage="number"). Verified - ./gradlew :app:assembleDebug → BUILD SUCCESSFUL - npm run typecheck clean Stacked on top of feat/android-highlighting (PR #36); merge that first to get a clean diff against develop here. * feat(android): theme prop — light / dark / auto (closes #39, refs #32) Wire the `theme` prop on Android. Bundles a light TextMate theme (quietlight.json from Sora's sample app) alongside the existing darcula.json. SoraTextMate now loads both at setup and exposes applyTheme() that flips ThemeRegistry's active scheme + re-applies TextMateColorScheme on the editor. - 'light' / 'dark' map to the bundled themes by name. - 'auto' (and any unknown value) reads Configuration.UI_MODE_NIGHT_MASK to pick between them — same semantics as the iOS overrideUserInterfaceStyle = .unspecified path. Refactor: SoraTextMate.apply → applyLanguage / applyTheme, since the two prop concerns now diverge. Caller code in SourceEditorView updated accordingly. Demo: App.android.tsx gains a tiny A/L/D segmented picker in the status bar to exercise the prop. Initial state is 'auto'. Verified: ./gradlew :app:assembleDebug → BUILD SUCCESSFUL, npm run typecheck clean. Stacked on feat/android-style-props (#38). Merge order: #36 → #38 → this. * ci: add android + macos build jobs, fix iOS paths (closes #41, refs #32) CI hadn't run since the ios-app → expo-app rename (PR #34) and the slug change (SourceEditorExampleiOS → SourceEditorExample). Latent breakage; this catches it up plus adds the two missing platforms. build-android (NEW) - ubuntu-latest, JDK 17 (Sora's language-textmate AAR + the gradle plugin chain require it). - android-actions/setup-android@v3 with platforms;android-35 + build-tools;35.0.0 to match android/build.gradle's compileSdkVersion 35. - expo prebuild --platform android — runs our app.plugin.js withAppBuildGradle modifier, injects coreLibraryDesugaring into android/app/build.gradle. - ./gradlew :app:assembleDebug. build-macos (NEW — replaces the placeholder comment) - macos-15, latest-stable Xcode (matches build-ios). - gem install cocoapods only — macos-app uses RN's first-party spm_dependency helper, no cocoapods-spm needed. - pod install + xcodebuild -workspace MacosApp.xcworkspace. build-ios (FIX) - example/ios-app → example/expo-app paths. - xcworkspace + scheme renamed: SourceEditorExampleiOS → SourceEditorExample (driven by app.json name change in PR #34). typecheck (FIX) - example/ios-app → example/expo-app path for the example typecheck. * docs: Android shipping across README + docs/* + CHANGELOG (closes #43) (#44) After this lands, every code-side and docs-side sub-task on #32 is done; the tracking issue closes. README.md - Platform table: Android → "Shipping (Fabric / New Architecture)" at API 24. Drop "Stub only" row. - Status section: name all three platforms. - Quick start: clarify cocoapods-spm is iOS-only; macOS uses RN's first-party SPM, Android pulls Sora-Editor from Maven Central. - Plugin snippet: add expo-build-properties android entries (minSdkVersion + newArchEnabled). - Roadmap: drop "Android (TextKit alternative)" — it's done. - Repo layout: describe android/ proper + the Expo CNG-shared example/expo-app/ (was example/ios-app/). - Add "Running the Android example" section mirroring iOS scripts. - License section: add Sora-Editor + LGPL boundary note. docs/installation.md - Add Android row to deployment-targets table (API 24). - New "Backing libraries" subsection summarising STTextView vs Sora. - Scope the SPM bridging section explicitly to iOS / macOS. - New "Android (Expo CNG)" section: documents the autolinking-from- Maven flow + the coreLibraryDesugaring requirement that our config plugin auto-injects. - New "Bare React Native — Android" section with the manual build.gradle snippet for non-Expo consumers. - New "License note for Android" calling out the LGPL inheritance. - Working examples block: ios-app → expo-app, add Android. docs/usage.md - `language` prop note: spell out the Android grammar source (VS Code TextMate via Sora) and the HTML caveat (no nested CSS/JS recursion on Android, unlike STTextView's attributed text). - `lineNumbers` note: now applies to all platforms. - `contentInsets` note: spell out the Android dp→px mapping. docs/examples.md - Add Android row to platform table — same expo-app/ project as iOS. - Refresh layout/toolchain narrative for the Expo-shared model. - Add android:run script line. CHANGELOG.md - Unreleased entry covering #34, #36, #38, #40, #42 plus the ios-app→expo-app rename. Stacked on feat/ci-android (#42); merge order: #36 → #38 → #40 → #42 → this. --------- Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
font,contentInsets,lineNumbersprops #37. Replaces the three style/layout no-op stubs in `SourceEditorViewManager` with real wiring.Library wiring
Demo
`App.android.tsx` now passes `lineNumbers`/`font`/`contentInsets` to SourceEditor with iOS-matching defaults. Status bar gains a `#` toggle for lineNumbers, mirroring iOS's `Toggle(systemImage="number")`.
Test plan
🤖 Generated with Claude Code