Skip to content

Move input delimiter completion into the shared C++ core #1014

Open

Description

@eszlamczyk

Summary

EnrichedMarkdownTextInput completes unclosed delimiters before parsing (**bold → **bold**) with three separate copies of the same loop: InputRemend.ts (web), InputRemend.kt (Android), ENRMInputRemend.mm (iOS). They have already drifted (web never got the #798 flanking check), and they share bugs that have to be fixed three times. All three parsers already reach the C++ core, so the completion step can live there once.

Bugs in today's loop

Input Android / iOS (with #798 flanking) Web (no flanking)
**a *b*** (toolbar: bold a b, italic b) **a *b****** **a *b*********
***a* b** ***a* b***** ***a* b********
`a*b` c (delimiter inside a code span) `a*b` c`*` same
snake_case is fine, 2 * 3 ok …fine_, 2 * 3*

Where the display is rebuilt from the completed string (Android, web), these extra characters show up as literal text: the toolbar case re-imports as a b****** on web. iOS rebuilds the display from the original string and drops them (see #799).

Causes:

  • A *** closer that does not match the * on top of the stack is pushed (or ignored) instead of closing * and then **. The output is also not idempotent: completing **rebase *interactive*** again appends more asterisks.
  • Delimiters inside a code span are counted.

Proposal

One small function in packages/core/cpp, roughly today's algorithm plus:

  • the md4c-style opener check from fix: input default values serialization #798 (isEmphasisOpener, intraword _ never opens) for *, _, ~~;
  • * / _ runs close by length, popping several stack entries (*** closes * then **), so completion is idempotent;
  • a backtick run skips to the matching equal-length run; an unmatched run is still closed.

Wiring:

  • Android and web: a Md4cFlags field that makes MD4CParser.cpp complete the input before parsing (no new JNI method or wasm export, no second string copy into wasm).
  • iOS: ENRMInputParser.mm calls the C++ function directly (it already compiles the core).
  • Delete InputRemend.ts, InputRemend.kt, ENRMInputRemend.mm; move their tests to core ctest cases plus one parse-level test per platform.

This also removes a web import hot spot: completeMarkdown is the largest JS import cost today (3.7–4.8 ms per 63 KB); in C++ it runs inside the wasm parse call.

Related

Out of scope

Escaping plain text in the serializer (5 * 2, a || b round trips).

Activity

  1. added
    enhancementNew feature or request
    domain: inputEnrichedMarkdownTextInput component
    library: react-nativeTasks that are specifically for react-native-enriched-markdown
    on Oct 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    domain: inputEnrichedMarkdownTextInput componentdomain: parserMarkdown parsing (md4c)enhancementNew feature or requestlibrary: react-nativeTasks that are specifically for react-native-enriched-markdown

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions