Skip to content

Rich text + code editor API; dogfood CodeEditor in Playground#5272

Open
shai-almog wants to merge 7 commits into
masterfrom
rich-text-and-code-editor-api
Open

Rich text + code editor API; dogfood CodeEditor in Playground#5272
shai-almog wants to merge 7 commits into
masterfrom
rich-text-and-code-editor-api

Conversation

@shai-almog

@shai-almog shai-almog commented Jun 23, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds two cross-platform native visual editors to Codename One.

  • RichTextArea — a WYSIWYG rich text / HTML editor: bold/italic/underline, lists, links, fore/highlight colors, headings, get/setHtml, change events, placeholder.
  • CodeEditor — an IDE-style editor: syntax highlighting (java/kotlin/js/python/css/xml/json/c), line-number gutter, light/dark themes, bracket/quote auto-close, async code completion (CodeCompletionProvider/CodeCompletion), and diagnostics (CodeDiagnostic → squiggly underlines + gutter markers + tooltips).

Both sit on AbstractEditorComponent, which speaks a semantic command/query/event channel with two interchangeable backends:

  1. A 100% cross-platform BrowserComponent engine (self-contained HTML/JS in the core jar) — iOS (WKWebView), Android (WebView), desktop (CEF), web (iframe), with native virtual-keyboard + physical-keyboard handling for free.
  2. An optional native backend a port may supply (CodenameOneImplementation#createNativeEditorPeer / editorPeerCommand / editorPeerQuery). CodeEditor#setEngineURL(...) also lets an app back the editor with a richer engine.

Conditional CodeMirror bundling

The Android/iOS builders detect com.codename1.ui.CodeEditor usage and gate optional CodeMirror bundling only when the API is used (CN1_USE_CODEMIRROR). The out-of-repo BuildDaemon copies are tracked separately.

Tests & docs

  • 33 deterministic unit tests (RichTextAreaTest, CodeEditorTest) via a new editor SPI backing in TestCodenameOneImplementation — green.
  • New RichTextArea + CodeEditor developer-guide sections with authentic screenshots.

Verification

  • Core compiles clean (JDK 25) and Java-5 clean (-source 1.5); maven-plugin builds; SpotBugs clean.
  • Unit tests pass (33/33). The built-in CodeEditor engine renders correctly (verified by rendering the exact engine HTML: syntax highlighting, a red wavy diagnostic squiggle + gutter marker, and the completion popup).

Notes / deferred

  • iOS black background fix: the native web widget is created transparent (WKWebView opaque=NO); the editor page now paints an opaque background and pins color-scheme so the dark peer no longer shows through.
  • Playground dogfood was proven locally against the in-repo core but is not in this PR — the Playground smoke test intentionally builds against the released CN1 (which lacks CodeEditor), so it can't compile there until the API ships in a release. Follow-up.
  • Screenshot-test screens were removed: the BrowserComponent-backed editors hang the screenshot suite on tvOS/watchOS (no reliable web view there, and those sub-platforms aren't distinguishable from iOS at runtime). The unit tests + engine render cover the editors.

🤖 Generated with Claude Code

…n Playground

Introduces two cross-platform native visual editors and proves the code editor
in the Codename One Playground.

Core (com.codename1.ui):
- RichTextArea: WYSIWYG rich text / HTML editor (bold/italic/lists/links/colors/
  headings, get/set HTML, change events, placeholder).
- CodeEditor: IDE-style editor with syntax highlighting, line-number gutter,
  light/dark themes, bracket/quote auto-close, async code completion
  (CodeCompletionProvider/CodeCompletion) and diagnostics (CodeDiagnostic:
  squiggly underlines + gutter markers + tooltips).
- AbstractEditorComponent: a semantic command/query/event channel with two
  interchangeable backends - a 100% cross-platform BrowserComponent fallback
  (works on every platform, native VKB + physical keyboard for free) and an
  optional native backend a port can supply (CodenameOneImplementation
  createNativeEditorPeer / editorPeerCommand / editorPeerQuery). CodeEditor also
  exposes setEngineURL(...) so an app can back it with a richer editor engine.

Builders: detect com.codename1.ui.CodeEditor usage and gate optional CodeMirror
bundling only when the API is used (AndroidGradleBuilder/IPhoneBuilder +
CN1_USE_CODEMIRROR placeholder in the iOS header). Mirror to BuildDaemon copies
is tracked separately (out of this repo).

Tests: 33 deterministic unit tests (RichTextAreaTest, CodeEditorTest) driven by a
new editor SPI backing in TestCodenameOneImplementation; screenshot-test screens
for both editors registered in the hellocodenameone suite (JS-port-skipped like
BrowserComponent).

Docs: new RichTextArea + CodeEditor developer-guide sections with authentic
screenshots.

Playground: PlaygroundBrowserEditor now uses CodeEditor on every non-web platform
(replacing the bare TextArea), with completion fed from the same CN1 API metadata
(PlaygroundCompletion), diagnostics, theme sync and Java/CSS modes. The web port
keeps Monaco unchanged (no regression), and a TextArea fallback engages
automatically where the platform web widget cannot initialise.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Developer Guide build artifacts are available for download from this workflow run:

Developer Guide quality checks:

  • AsciiDoc linter: No issues found (report)
  • Vale: No alerts found (report)
  • Paragraph capitalization: No paragraph capitalization issues (report)
  • LanguageTool: No grammar matches (report)
  • Image references: No unused images detected (report)

@shai-almog

shai-almog commented Jun 23, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 138 screenshots: 138 matched.

Native Android coverage

  • 📊 Line coverage: 14.56% (8920/61274 lines covered) [HTML preview] (artifact android-coverage-report, jacocoAndroidReport/html/index.html)
    • Other counters: instruction 11.80% (43919/372186), branch 5.23% (1829/34997), complexity 6.25% (2095/33537), method 10.82% (1696/15675), class 17.66% (392/2220)
    • Lowest covered classes
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysKt – 0.00% (0/6327 lines covered)
      • kotlin.collections.unsigned.kotlin.collections.unsigned.UArraysKt___UArraysKt – 0.00% (0/2384 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.ClassReader – 0.00% (0/1519 lines covered)
      • kotlin.collections.kotlin.collections.CollectionsKt___CollectionsKt – 0.00% (0/1148 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.MethodWriter – 0.00% (0/923 lines covered)
      • kotlin.sequences.kotlin.sequences.SequencesKt___SequencesKt – 0.00% (0/730 lines covered)
      • kotlin.text.kotlin.text.StringsKt___StringsKt – 0.00% (0/623 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.Frame – 0.00% (0/564 lines covered)
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysJvmKt – 0.00% (0/495 lines covered)
      • kotlinx.coroutines.kotlinx.coroutines.JobSupport – 0.00% (0/423 lines covered)

✅ Native Android screenshot tests passed.

Native Android coverage

  • 📊 Line coverage: 14.56% (8920/61274 lines covered) [HTML preview] (artifact android-coverage-report, jacocoAndroidReport/html/index.html)
    • Other counters: instruction 11.80% (43919/372186), branch 5.23% (1829/34997), complexity 6.25% (2095/33537), method 10.82% (1696/15675), class 17.66% (392/2220)
    • Lowest covered classes
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysKt – 0.00% (0/6327 lines covered)
      • kotlin.collections.unsigned.kotlin.collections.unsigned.UArraysKt___UArraysKt – 0.00% (0/2384 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.ClassReader – 0.00% (0/1519 lines covered)
      • kotlin.collections.kotlin.collections.CollectionsKt___CollectionsKt – 0.00% (0/1148 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.MethodWriter – 0.00% (0/923 lines covered)
      • kotlin.sequences.kotlin.sequences.SequencesKt___SequencesKt – 0.00% (0/730 lines covered)
      • kotlin.text.kotlin.text.StringsKt___StringsKt – 0.00% (0/623 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.Frame – 0.00% (0/564 lines covered)
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysJvmKt – 0.00% (0/495 lines covered)
      • kotlinx.coroutines.kotlinx.coroutines.JobSupport – 0.00% (0/423 lines covered)

Benchmark Results

Detailed Performance Metrics

Metric Duration
SIMD kernel backend scalar fallback (no native SIMD)
SIMD int-add (64K x300) java 185ms / native 189ms = 0.9x speedup
SIMD float-mul (64K x300) java 136ms / native 66ms = 2.0x speedup
SIMD kernel correctness PASS (native result == scalar reference)
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 SIMD byte path gated to scalar (CPU autovectorizes scalar; explicit SIMD not beneficial here)
Base64 CN1 encode 163.000 ms
Base64 CN1 decode 595.000 ms
Base64 native encode 898.000 ms
Base64 encode ratio (CN1/native) 0.182x (81.8% faster)
Base64 native decode 1095.000 ms
Base64 decode ratio (CN1/native) 0.543x (45.7% faster)
Image encode benchmark status skipped (SIMD unsupported)

@github-actions

Copy link
Copy Markdown
Contributor

Cloudflare Preview

@shai-almog

shai-almog commented Jun 23, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 136 screenshots: 136 matched.
Native Linux port (x64), GTK3/Cairo/Pango, ParparVM bytecode-to-C (no JVM): the hellocodenameone screenshot suite rendered by a native ELF built + run on the GitHub x64 runner. Baseline: scripts/linux/screenshots.

@shai-almog

shai-almog commented Jun 23, 2026

Copy link
Copy Markdown
Collaborator Author

Native Linux port (arm64)

Compared 136 screenshots: 134 matched, 2 missing references.

  • CodeEditor — missing reference. Reference screenshot missing at /home/runner/work/CodenameOne/CodenameOne/scripts/linux/screenshots-arm/CodeEditor.png.

    CodeEditor
    Preview info: JPEG preview quality 70; JPEG preview quality 70.
    Full-resolution PNG saved as CodeEditor.png in workflow artifacts.

  • RichTextArea — missing reference. Reference screenshot missing at /home/runner/work/CodenameOne/CodenameOne/scripts/linux/screenshots-arm/RichTextArea.png.

    RichTextArea
    Preview info: JPEG preview quality 70; JPEG preview quality 70.
    Full-resolution PNG saved as RichTextArea.png in workflow artifacts.

@shai-almog

shai-almog commented Jun 23, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 130 screenshots: 130 matched.
✅ JavaScript-port screenshot tests passed.

@shai-almog

shai-almog commented Jun 23, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 134 screenshots: 134 matched.
Native Windows port, REAL shipping pipeline: the hellocodenameone screenshot suite rendered by a binary CROSS-COMPILED on Linux (clang-cl + xwin, WebView2 linked) and RUN on a Windows x64 runner. Compared against the in-repo baseline in scripts/windows/screenshots.

Benchmark Results

Detailed Performance Metrics

Metric Duration
SIMD kernel backend SSE2 (x64) / NEON (arm64) native kernels
SIMD int-add (64K x300) java 63ms / native 5ms = 12.6x speedup
SIMD float-mul (64K x300) java 61ms / native 4ms = 15.2x speedup
SIMD kernel correctness PASS (native result == scalar reference)
Base64 native bridge unavailable (CN1 + SIMD + image benchmarks only)
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 SIMD byte path gated to scalar (CPU autovectorizes scalar; explicit SIMD not beneficial here)
Base64 CN1 encode 482.000 ms
Base64 CN1 decode 272.000 ms
Base64 SIMD encode 130.000 ms
Base64 encode ratio (SIMD/CN1) 0.270x (73.0% faster)
Base64 SIMD decode 111.000 ms

@shai-almog

shai-almog commented Jun 23, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 136 screenshots: 136 matched.
✅ Native Mac screenshot tests passed.

Benchmark Results

  • VM Translation Time: 0 seconds
  • Compilation Time: 150 seconds

Detailed Performance Metrics

Metric Duration
SIMD kernel backend SSE2 (x64) / NEON (arm64) native kernels
SIMD int-add (64K x300) java 52ms / native 3ms = 17.3x speedup
SIMD float-mul (64K x300) java 58ms / native 2ms = 29.0x speedup
SIMD kernel correctness PASS (native result == scalar reference)
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 SIMD byte path active (NEON-accelerated)
Base64 CN1 encode 283.000 ms
Base64 CN1 decode 202.000 ms
Base64 native encode 942.000 ms
Base64 encode ratio (CN1/native) 0.300x (70.0% faster)
Base64 native decode 617.000 ms
Base64 decode ratio (CN1/native) 0.327x (67.3% faster)
Base64 SIMD encode 55.000 ms
Base64 encode ratio (SIMD/CN1) 0.194x (80.6% faster)
Base64 SIMD decode 47.000 ms
Base64 decode ratio (SIMD/CN1) 0.233x (76.7% faster)
Base64 encode ratio (SIMD/native) 0.058x (94.2% faster)
Base64 decode ratio (SIMD/native) 0.076x (92.4% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 22.000 ms
Image createMask (SIMD on) 15.000 ms
Image createMask ratio (SIMD on/off) 0.682x (31.8% faster)
Image applyMask (SIMD off) 202.000 ms
Image applyMask (SIMD on) 191.000 ms
Image applyMask ratio (SIMD on/off) 0.946x (5.4% faster)
Image modifyAlpha (SIMD off) 177.000 ms
Image modifyAlpha (SIMD on) 130.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.734x (26.6% faster)
Image modifyAlpha removeColor (SIMD off) 168.000 ms
Image modifyAlpha removeColor (SIMD on) 164.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.976x (2.4% faster)

@shai-almog

shai-almog commented Jun 23, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 213 screenshots: 213 matched.
✅ Native Apple Watch (watchOS, Core Graphics) screenshot tests passed.

@shai-almog

shai-almog commented Jun 23, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 135 screenshots: 135 matched.
✅ Native Apple TV (tvOS, Metal) screenshot tests passed.

@shai-almog

shai-almog commented Jun 23, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 133 screenshots: 133 matched.
✅ Native iOS screenshot tests passed.

Benchmark Results

  • VM Translation Time: 0 seconds
  • Compilation Time: 243 seconds

Build and Run Timing

Metric Duration
Simulator Boot 81000 ms
Simulator Boot (Run) 1000 ms
App Install 16000 ms
App Launch 2000 ms
Test Execution 386000 ms

Detailed Performance Metrics

Metric Duration
SIMD kernel backend SSE2 (x64) / NEON (arm64) native kernels
SIMD int-add (64K x300) java 376ms / native 7ms = 53.7x speedup
SIMD float-mul (64K x300) java 106ms / native 20ms = 5.3x speedup
SIMD kernel correctness PASS (native result == scalar reference)
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 SIMD byte path active (NEON-accelerated)
Base64 CN1 encode 902.000 ms
Base64 CN1 decode 464.000 ms
Base64 native encode 1572.000 ms
Base64 encode ratio (CN1/native) 0.574x (42.6% faster)
Base64 native decode 675.000 ms
Base64 decode ratio (CN1/native) 0.687x (31.3% faster)
Base64 SIMD encode 56.000 ms
Base64 encode ratio (SIMD/CN1) 0.062x (93.8% faster)
Base64 SIMD decode 56.000 ms
Base64 decode ratio (SIMD/CN1) 0.121x (87.9% faster)
Base64 encode ratio (SIMD/native) 0.036x (96.4% faster)
Base64 decode ratio (SIMD/native) 0.083x (91.7% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 19.000 ms
Image createMask (SIMD on) 2.000 ms
Image createMask ratio (SIMD on/off) 0.105x (89.5% faster)
Image applyMask (SIMD off) 162.000 ms
Image applyMask (SIMD on) 136.000 ms
Image applyMask ratio (SIMD on/off) 0.840x (16.0% faster)
Image modifyAlpha (SIMD off) 539.000 ms
Image modifyAlpha (SIMD on) 171.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.317x (68.3% faster)
Image modifyAlpha removeColor (SIMD off) 215.000 ms
Image modifyAlpha removeColor (SIMD on) 227.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 1.056x (5.6% slower)

@shai-almog

shai-almog commented Jun 23, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 137 screenshots: 137 matched.
✅ Native iOS Metal screenshot tests passed.

Benchmark Results

  • VM Translation Time: 0 seconds
  • Compilation Time: 415 seconds

Build and Run Timing

Metric Duration
Simulator Boot 71000 ms
Simulator Boot (Run) 3000 ms
App Install 13000 ms
App Launch 0 ms
Test Execution 370000 ms

Detailed Performance Metrics

Metric Duration
SIMD kernel backend SSE2 (x64) / NEON (arm64) native kernels
SIMD int-add (64K x300) java 151ms / native 3ms = 50.3x speedup
SIMD float-mul (64K x300) java 358ms / native 20ms = 17.9x speedup
SIMD kernel correctness PASS (native result == scalar reference)
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 SIMD byte path active (NEON-accelerated)
Base64 CN1 encode 452.000 ms
Base64 CN1 decode 276.000 ms
Base64 native encode 2162.000 ms
Base64 encode ratio (CN1/native) 0.209x (79.1% faster)
Base64 native decode 865.000 ms
Base64 decode ratio (CN1/native) 0.319x (68.1% faster)
Base64 SIMD encode 70.000 ms
Base64 encode ratio (SIMD/CN1) 0.155x (84.5% faster)
Base64 SIMD decode 53.000 ms
Base64 decode ratio (SIMD/CN1) 0.192x (80.8% faster)
Base64 encode ratio (SIMD/native) 0.032x (96.8% faster)
Base64 decode ratio (SIMD/native) 0.061x (93.9% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 60.000 ms
Image createMask (SIMD on) 17.000 ms
Image createMask ratio (SIMD on/off) 0.283x (71.7% faster)
Image applyMask (SIMD off) 158.000 ms
Image applyMask (SIMD on) 334.000 ms
Image applyMask ratio (SIMD on/off) 2.114x (111.4% slower)
Image modifyAlpha (SIMD off) 186.000 ms
Image modifyAlpha (SIMD on) 274.000 ms
Image modifyAlpha ratio (SIMD on/off) 1.473x (47.3% slower)
Image modifyAlpha removeColor (SIMD off) 267.000 ms
Image modifyAlpha removeColor (SIMD on) 225.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.843x (15.7% faster)

shai-almog and others added 3 commits June 23, 2026 20:17
- iOS: RichTextArea showed black because the native web widget is created
  transparent (WKWebView opaque=NO) and the editor page had no background, so the
  dark peer showed through. Give the page an opaque white background and pin
  color-scheme:light (also on CodeEditor) so device dark mode does not invert it.
- SpotBugs (build-test 8): remove the unread pendingText/pendingHtml fields, make
  CodeEditorHtml.PAGE a runtime constant (static initializer) so the ~13KB string
  is not inlined/duplicated into other classes, and convert the three flagged
  anonymous callbacks into named static nested classes.
- Vale (developer guide): fix five contraction/style alerts in the new sections.
- Screenshot tests: remove RichTextArea/CodeEditor screenshot screens. The
  BrowserComponent-backed editors hang the screenshot suite on tvOS/watchOS (no
  reliable web view there, and those sub-platforms can't be distinguished from
  iOS at runtime). The 33 unit tests + engine rendering already cover the editors.
- Playground: revert the CodeEditor dogfood from this PR. The Playground smoke
  test intentionally builds against the released CN1 (which lacks CodeEditor), so
  the integration can't compile there yet; it lands once CodeEditor ships in a
  release. Proven locally against the in-repo core.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- PMD gate (build-test): add the required @OverRide annotations, make
  CodeEditorHtml final, and convert index for-loops to foreach.
- LanguageTool gate (build): hyphenate "cross-platform" in the dev guide.
- Re-add RichTextArea/CodeEditor screenshot screens with a hard-bounded capture
  (fires shortly after the editor is ready, or after a few seconds regardless) so
  platforms that can't render/capture the web peer produce a screenshot instead of
  stalling the suite. Goldens to be recorded from CI artifacts.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Checkstyle: re-indent the CodeEditorHtml.PAGE static-initializer continuation
  to 12 spaces (the static {} block adds an indentation level).
- Record RichTextArea/CodeEditor screenshot goldens from the CI artifacts for
  every platform that runs the suite: ios, ios-metal, ios-tv, ios-watch,
  mac-native and javascript. The capture is rendered on iOS/Metal (real editor
  with syntax highlighting + gutter), and a deterministic blank/black peer on
  platforms that don't capture peer-component pixels (tvOS/watchOS/JS) - all
  stable goldens. A small per-test .tolerance absorbs web-render AA variance.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

✅ Continuous Quality Report

Test & Coverage

Static Analysis

  • SpotBugs [Report archive]
    • ByteCodeTranslator: 0 findings (no issues)
    • android: 0 findings (no issues)
    • codenameone-maven-plugin: 0 findings (no issues)
    • core-unittests: 0 findings (no issues)
    • ios: 0 findings (no issues)
  • PMD: 0 findings (no issues) [Report archive]
  • Checkstyle: 0 findings (no issues) [Report archive]

Generated automatically by the PR CI workflow.

These suites also run the editor tests (Android/iOS native WebView renders the
editor; Linux/Windows capture a deterministic blank peer). Their gate tolerates a
missing golden so CI was green, but the screenshots showed up as new -- record
them from the CI artifacts so every platform's golden set is complete.
The CodeEditor page used color-scheme 'light dark'; on iOS the WKWebView base
background then follows the device appearance, so a capture that beats the page's
first paint shows black in dark appearance (RichTextArea already pinned 'light'
and was unaffected). Pin CodeEditor to color-scheme 'light' too, and lengthen the
screenshot settle/bound so the rendered content is reliably on screen before
capture. Goldens (rendered state) are unchanged.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant