@apollohg/react-native-rich-text-editor 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (494) hide show
  1. package/LICENSE +160 -0
  2. package/README.md +259 -0
  3. package/RUST-STANDARD-LIBRARY-NOTICES.html +8266 -0
  4. package/ReactNativeProseEditor.podspec +59 -0
  5. package/THIRD_PARTY_NOTICES.md +31155 -0
  6. package/android/build.gradle +188 -0
  7. package/android/consumer-rules.pro +18 -0
  8. package/android/expo/build.gradle +17 -0
  9. package/android/src/debug/java/com/apollohg/editor/viewer/PreparedProseDrawInstrumentation.kt +7 -0
  10. package/android/src/main/assets/editor-icons/MaterialIcons.json +2236 -0
  11. package/android/src/main/assets/editor-icons/MaterialIcons.ttf +0 -0
  12. package/android/src/main/java/com/apollohg/editor/AndroidApiCompat.kt +19 -0
  13. package/android/src/main/java/com/apollohg/editor/AndroidCollaborationTransport.kt +860 -0
  14. package/android/src/main/java/com/apollohg/editor/CaretGeometry.kt +91 -0
  15. package/android/src/main/java/com/apollohg/editor/CodeHighlighting.kt +141 -0
  16. package/android/src/main/java/com/apollohg/editor/DecodedBitmapBudget.kt +250 -0
  17. package/android/src/main/java/com/apollohg/editor/EditorAddons.kt +133 -0
  18. package/android/src/main/java/com/apollohg/editor/EditorBlockSpacing.kt +51 -0
  19. package/android/src/main/java/com/apollohg/editor/EditorBoxDrawable.kt +16 -0
  20. package/android/src/main/java/com/apollohg/editor/EditorBoxDrawing.kt +234 -0
  21. package/android/src/main/java/com/apollohg/editor/EditorCheckboxSpan.kt +87 -0
  22. package/android/src/main/java/com/apollohg/editor/EditorCodeHighlighting.kt +120 -0
  23. package/android/src/main/java/com/apollohg/editor/EditorDecorationLayer.java +18 -0
  24. package/android/src/main/java/com/apollohg/editor/EditorDocumentLayout.kt +626 -0
  25. package/android/src/main/java/com/apollohg/editor/EditorEditText.kt +1042 -0
  26. package/android/src/main/java/com/apollohg/editor/EditorEditTextAnnotations.kt +191 -0
  27. package/android/src/main/java/com/apollohg/editor/EditorEditTextCaret.kt +100 -0
  28. package/android/src/main/java/com/apollohg/editor/EditorEditTextClipboard.kt +101 -0
  29. package/android/src/main/java/com/apollohg/editor/EditorEditTextComposition.kt +220 -0
  30. package/android/src/main/java/com/apollohg/editor/EditorEditTextConfiguration.kt +316 -0
  31. package/android/src/main/java/com/apollohg/editor/EditorEditTextCorrection.kt +303 -0
  32. package/android/src/main/java/com/apollohg/editor/EditorEditTextDeferredUpdates.kt +327 -0
  33. package/android/src/main/java/com/apollohg/editor/EditorEditTextDeletion.kt +258 -0
  34. package/android/src/main/java/com/apollohg/editor/EditorEditTextDiagnostics.kt +83 -0
  35. package/android/src/main/java/com/apollohg/editor/EditorEditTextDragDrop.kt +67 -0
  36. package/android/src/main/java/com/apollohg/editor/EditorEditTextExternalComposition.kt +357 -0
  37. package/android/src/main/java/com/apollohg/editor/EditorEditTextHardwareInput.kt +277 -0
  38. package/android/src/main/java/com/apollohg/editor/EditorEditTextImages.kt +280 -0
  39. package/android/src/main/java/com/apollohg/editor/EditorEditTextInputLifecycle.kt +183 -0
  40. package/android/src/main/java/com/apollohg/editor/EditorEditTextInputPreparation.kt +79 -0
  41. package/android/src/main/java/com/apollohg/editor/EditorEditTextInputTraits.kt +384 -0
  42. package/android/src/main/java/com/apollohg/editor/EditorEditTextLayout.kt +100 -0
  43. package/android/src/main/java/com/apollohg/editor/EditorEditTextNativeMutation.kt +243 -0
  44. package/android/src/main/java/com/apollohg/editor/EditorEditTextPlaceholder.kt +154 -0
  45. package/android/src/main/java/com/apollohg/editor/EditorEditTextRenderPatch.kt +347 -0
  46. package/android/src/main/java/com/apollohg/editor/EditorEditTextRendering.kt +313 -0
  47. package/android/src/main/java/com/apollohg/editor/EditorEditTextRustCommands.kt +281 -0
  48. package/android/src/main/java/com/apollohg/editor/EditorEditTextSelection.kt +352 -0
  49. package/android/src/main/java/com/apollohg/editor/EditorEditTextState.kt +113 -0
  50. package/android/src/main/java/com/apollohg/editor/EditorEditTextTaskMarkers.kt +92 -0
  51. package/android/src/main/java/com/apollohg/editor/EditorEditTextTextCommit.kt +327 -0
  52. package/android/src/main/java/com/apollohg/editor/EditorEditTextToolbar.kt +84 -0
  53. package/android/src/main/java/com/apollohg/editor/EditorEditTextUpdates.kt +245 -0
  54. package/android/src/main/java/com/apollohg/editor/EditorGlyphHeightCursorDrawable.kt +42 -0
  55. package/android/src/main/java/com/apollohg/editor/EditorHeightBehavior.kt +13 -0
  56. package/android/src/main/java/com/apollohg/editor/EditorInputConnection.kt +923 -0
  57. package/android/src/main/java/com/apollohg/editor/EditorInputCoordinates.kt +191 -0
  58. package/android/src/main/java/com/apollohg/editor/EditorInputCorrection.kt +107 -0
  59. package/android/src/main/java/com/apollohg/editor/EditorInputCursorGeometry.kt +128 -0
  60. package/android/src/main/java/com/apollohg/editor/EditorInputSnapshots.kt +134 -0
  61. package/android/src/main/java/com/apollohg/editor/EditorInputSurroundingDeletion.kt +321 -0
  62. package/android/src/main/java/com/apollohg/editor/EditorKeyboardToolbarView.kt +851 -0
  63. package/android/src/main/java/com/apollohg/editor/EditorMentionStyle.kt +192 -0
  64. package/android/src/main/java/com/apollohg/editor/EditorReconciliationWatcher.kt +46 -0
  65. package/android/src/main/java/com/apollohg/editor/EditorStyleSheet.kt +303 -0
  66. package/android/src/main/java/com/apollohg/editor/EditorStyleSheetSpans.kt +253 -0
  67. package/android/src/main/java/com/apollohg/editor/EditorSurfaceInputConnection.kt +67 -0
  68. package/android/src/main/java/com/apollohg/editor/EditorTextDecorationDrawing.kt +143 -0
  69. package/android/src/main/java/com/apollohg/editor/EditorTextSurface.kt +712 -0
  70. package/android/src/main/java/com/apollohg/editor/EditorTextSurfaceDragDrop.kt +94 -0
  71. package/android/src/main/java/com/apollohg/editor/EditorTextSurfaceInteraction.kt +708 -0
  72. package/android/src/main/java/com/apollohg/editor/EditorTheme.kt +650 -0
  73. package/android/src/main/java/com/apollohg/editor/EditorV2Adapter.kt +912 -0
  74. package/android/src/main/java/com/apollohg/editor/EditorV2AdapterMutations.kt +402 -0
  75. package/android/src/main/java/com/apollohg/editor/EditorV2AdapterRendering.kt +123 -0
  76. package/android/src/main/java/com/apollohg/editor/EditorV2AdapterSelection.kt +203 -0
  77. package/android/src/main/java/com/apollohg/editor/EditorV2Backend.kt +120 -0
  78. package/android/src/main/java/com/apollohg/editor/EditorV2Driver.kt +87 -0
  79. package/android/src/main/java/com/apollohg/editor/EditorV2Registry.kt +97 -0
  80. package/android/src/main/java/com/apollohg/editor/EditorV2RenderValidation.kt +409 -0
  81. package/android/src/main/java/com/apollohg/editor/ExpoAutoGrowStyleSizePublisher.kt +34 -0
  82. package/android/src/main/java/com/apollohg/editor/ImageResizeOverlayView.kt +266 -0
  83. package/android/src/main/java/com/apollohg/editor/ImeTextCoordinateMapper.kt +102 -0
  84. package/android/src/main/java/com/apollohg/editor/KeyboardToolbarImeAnimationController.kt +101 -0
  85. package/android/src/main/java/com/apollohg/editor/MentionSuggestionChipView.kt +234 -0
  86. package/android/src/main/java/com/apollohg/editor/NativeCollaborationTransportRegistry.kt +493 -0
  87. package/android/src/main/java/com/apollohg/editor/NativeEditorExpoView.kt +813 -0
  88. package/android/src/main/java/com/apollohg/editor/NativeEditorExpoViewAtoms.kt +68 -0
  89. package/android/src/main/java/com/apollohg/editor/NativeEditorExpoViewBinding.kt +126 -0
  90. package/android/src/main/java/com/apollohg/editor/NativeEditorExpoViewDiagnostics.kt +208 -0
  91. package/android/src/main/java/com/apollohg/editor/NativeEditorExpoViewErrors.kt +146 -0
  92. package/android/src/main/java/com/apollohg/editor/NativeEditorExpoViewEvents.kt +150 -0
  93. package/android/src/main/java/com/apollohg/editor/NativeEditorExpoViewExternalComposition.kt +39 -0
  94. package/android/src/main/java/com/apollohg/editor/NativeEditorExpoViewFocus.kt +176 -0
  95. package/android/src/main/java/com/apollohg/editor/NativeEditorExpoViewLifecycle.kt +302 -0
  96. package/android/src/main/java/com/apollohg/editor/NativeEditorExpoViewMentions.kt +259 -0
  97. package/android/src/main/java/com/apollohg/editor/NativeEditorExpoViewNativeActions.kt +179 -0
  98. package/android/src/main/java/com/apollohg/editor/NativeEditorExpoViewOutsideTap.kt +214 -0
  99. package/android/src/main/java/com/apollohg/editor/NativeEditorExpoViewPendingUpdates.kt +376 -0
  100. package/android/src/main/java/com/apollohg/editor/NativeEditorExpoViewProperties.kt +234 -0
  101. package/android/src/main/java/com/apollohg/editor/NativeEditorExpoViewPropertyRetries.kt +197 -0
  102. package/android/src/main/java/com/apollohg/editor/NativeEditorExpoViewToolbar.kt +285 -0
  103. package/android/src/main/java/com/apollohg/editor/NativeEditorExpoViewTypes.kt +28 -0
  104. package/android/src/main/java/com/apollohg/editor/NativeEditorExpoViewUpdates.kt +271 -0
  105. package/android/src/main/java/com/apollohg/editor/NativeEditorModule.kt +687 -0
  106. package/android/src/main/java/com/apollohg/editor/NativeEditorOutsideTapDispatcher.kt +380 -0
  107. package/android/src/main/java/com/apollohg/editor/NativeEditorV2Numbers.kt +45 -0
  108. package/android/src/main/java/com/apollohg/editor/NativeEditorViewRegistry.kt +372 -0
  109. package/android/src/main/java/com/apollohg/editor/NativeImagePipeline.kt +22 -0
  110. package/android/src/main/java/com/apollohg/editor/NativeToolbar.kt +193 -0
  111. package/android/src/main/java/com/apollohg/editor/NativeToolbarIcons.kt +177 -0
  112. package/android/src/main/java/com/apollohg/editor/NativeToolbarItem.kt +274 -0
  113. package/android/src/main/java/com/apollohg/editor/OkHttpCollaborationSocket.kt +102 -0
  114. package/android/src/main/java/com/apollohg/editor/OrderedListMarkerFormatter.kt +130 -0
  115. package/android/src/main/java/com/apollohg/editor/PointerTransparentView.java +18 -0
  116. package/android/src/main/java/com/apollohg/editor/PositionBridge.kt +128 -0
  117. package/android/src/main/java/com/apollohg/editor/ProseViewerView.kt +854 -0
  118. package/android/src/main/java/com/apollohg/editor/RemoteSelectionOverlayView.kt +314 -0
  119. package/android/src/main/java/com/apollohg/editor/RenderBlockSpans.kt +314 -0
  120. package/android/src/main/java/com/apollohg/editor/RenderBridge.kt +224 -0
  121. package/android/src/main/java/com/apollohg/editor/RenderBridgeBlockStyles.kt +407 -0
  122. package/android/src/main/java/com/apollohg/editor/RenderBridgeElements.kt +544 -0
  123. package/android/src/main/java/com/apollohg/editor/RenderBridgeInlineAndAtoms.kt +631 -0
  124. package/android/src/main/java/com/apollohg/editor/RenderBridgeParagraphs.kt +215 -0
  125. package/android/src/main/java/com/apollohg/editor/RenderImageDecoder.kt +748 -0
  126. package/android/src/main/java/com/apollohg/editor/RenderImageLoader.kt +900 -0
  127. package/android/src/main/java/com/apollohg/editor/RenderLayoutConstants.kt +117 -0
  128. package/android/src/main/java/com/apollohg/editor/RenderMediaSpans.kt +337 -0
  129. package/android/src/main/java/com/apollohg/editor/RenderParagraphSpans.kt +182 -0
  130. package/android/src/main/java/com/apollohg/editor/RichTextEditorView.kt +951 -0
  131. package/android/src/main/java/com/apollohg/editor/SharedNativeImagePipeline.kt +78 -0
  132. package/android/src/main/java/com/apollohg/editor/UniffiEditorV2Backend.kt +261 -0
  133. package/android/src/main/java/com/apollohg/editor/viewer/AndroidProseLayoutEngine.kt +1656 -0
  134. package/android/src/main/java/com/apollohg/editor/viewer/FabricAttachmentSidecars.kt +80 -0
  135. package/android/src/main/java/com/apollohg/editor/viewer/FabricLeaseHandleBridge.kt +59 -0
  136. package/android/src/main/java/com/apollohg/editor/viewer/FallbackSelectionGeometry.kt +450 -0
  137. package/android/src/main/java/com/apollohg/editor/viewer/PreparedProseDrawingView.kt +678 -0
  138. package/android/src/main/java/com/apollohg/editor/viewer/PreparedProseInstrumentation.kt +608 -0
  139. package/android/src/main/java/com/apollohg/editor/viewer/PreparedProseLayout.kt +186 -0
  140. package/android/src/main/java/com/apollohg/editor/viewer/PreparedProseLayoutCache.kt +393 -0
  141. package/android/src/main/java/com/apollohg/editor/viewer/PreparedProseLayoutRegistry.kt +828 -0
  142. package/android/src/main/java/com/apollohg/editor/viewer/PreparedProseTheme.kt +316 -0
  143. package/android/src/main/java/com/apollohg/editor/viewer/PreparedProseViewerManager.kt +900 -0
  144. package/android/src/main/java/com/apollohg/editor/viewer/PreparedProseViewerPackage.kt +16 -0
  145. package/android/src/main/java/com/apollohg/editor/viewer/PreparedViewerAtoms.kt +89 -0
  146. package/android/src/main/java/com/apollohg/editor/viewer/ViewerCodeHighlighting.kt +91 -0
  147. package/android/src/main/java/com/apollohg/editor/viewer/ViewerDocument.kt +453 -0
  148. package/android/src/main/java/com/apollohg/editor/viewer/ViewerFontEnvironment.kt +282 -0
  149. package/android/src/main/java/com/apollohg/editor/viewer/ViewerImagePipeline.kt +460 -0
  150. package/android/src/main/jni/CMakeLists.txt +85 -0
  151. package/android/src/main/jni/PreparedProseViewerMeasurementsManager.cpp +334 -0
  152. package/android/src/main/jni/ReactNativeProseEditorSpec.h +17 -0
  153. package/android/src/main/jni/reactnativeproseeditor.h +6 -0
  154. package/android/src/main/res/values/attrs.xml +6 -0
  155. package/android/src/release/java/com/apollohg/editor/viewer/PreparedProseDrawInstrumentation.kt +9 -0
  156. package/app.plugin.js +62 -0
  157. package/common/cpp/react/renderer/components/PreparedProseViewer/PreparedProseMeasurementsManager.h +62 -0
  158. package/common/cpp/react/renderer/components/PreparedProseViewer/PreparedProseViewerComponentDescriptor.h +30 -0
  159. package/common/cpp/react/renderer/components/PreparedProseViewer/PreparedProseViewerShadowNode.cpp +192 -0
  160. package/common/cpp/react/renderer/components/PreparedProseViewer/PreparedProseViewerShadowNode.h +46 -0
  161. package/common/cpp/react/renderer/components/PreparedProseViewer/PreparedProseViewerState.h +145 -0
  162. package/dist/AtomHost.d.ts +17 -0
  163. package/dist/AtomHost.js +135 -0
  164. package/dist/DefaultAtomChip.d.ts +2 -0
  165. package/dist/DefaultAtomChip.js +22 -0
  166. package/dist/EditorAddon.d.ts +32 -0
  167. package/dist/EditorAddon.js +29 -0
  168. package/dist/EditorAddonNormalization.d.ts +6 -0
  169. package/dist/EditorAddonNormalization.js +48 -0
  170. package/dist/EditorMentionThemeNormalization.d.ts +8 -0
  171. package/dist/EditorMentionThemeNormalization.js +22 -0
  172. package/dist/EditorMentionThemeValidation.d.ts +12 -0
  173. package/dist/EditorMentionThemeValidation.js +95 -0
  174. package/dist/EditorStyleSheet.d.ts +4 -0
  175. package/dist/EditorStyleSheet.js +10 -0
  176. package/dist/EditorStyleSheetNormalization.d.ts +3 -0
  177. package/dist/EditorStyleSheetNormalization.js +226 -0
  178. package/dist/EditorStyleSheetTypes.d.ts +151 -0
  179. package/dist/EditorStyleSheetTypes.js +2 -0
  180. package/dist/EditorTheme.d.ts +117 -0
  181. package/dist/EditorTheme.js +41 -0
  182. package/dist/EditorToolbar.d.ts +4 -0
  183. package/dist/EditorToolbar.js +17 -0
  184. package/dist/EditorToolbarComponent.d.ts +13 -0
  185. package/dist/EditorToolbarComponent.js +24 -0
  186. package/dist/EditorToolbarItems.d.ts +9 -0
  187. package/dist/EditorToolbarItems.js +58 -0
  188. package/dist/EditorToolbarRegistry.d.ts +59 -0
  189. package/dist/EditorToolbarRegistry.js +175 -0
  190. package/dist/EditorToolbarTypes.d.ts +273 -0
  191. package/dist/EditorToolbarTypes.js +2 -0
  192. package/dist/EditorToolbarVisuals.d.ts +154 -0
  193. package/dist/EditorToolbarVisuals.js +228 -0
  194. package/dist/EditorUpdateRevision.d.ts +8 -0
  195. package/dist/EditorUpdateRevision.js +22 -0
  196. package/dist/ExternalTextComposition.d.ts +45 -0
  197. package/dist/ExternalTextComposition.js +537 -0
  198. package/dist/ImageLoadingPolicy.d.ts +54 -0
  199. package/dist/ImageLoadingPolicy.js +60 -0
  200. package/dist/NativeEditorBoundaryError.d.ts +111 -0
  201. package/dist/NativeEditorBoundaryError.js +268 -0
  202. package/dist/NativeEditorBridge.d.ts +9 -0
  203. package/dist/NativeEditorBridge.js +37 -0
  204. package/dist/NativeEditorCollaborationTransport.d.ts +154 -0
  205. package/dist/NativeEditorCollaborationTransport.js +275 -0
  206. package/dist/NativeEditorCreateConfig.d.ts +16 -0
  207. package/dist/NativeEditorCreateConfig.js +249 -0
  208. package/dist/NativeEditorCreateJson.d.ts +76 -0
  209. package/dist/NativeEditorCreateJson.js +474 -0
  210. package/dist/NativeEditorCreateValidation.d.ts +32 -0
  211. package/dist/NativeEditorCreateValidation.js +150 -0
  212. package/dist/NativeEditorDocumentBridge.d.ts +72 -0
  213. package/dist/NativeEditorDocumentBridge.js +305 -0
  214. package/dist/NativeEditorDocumentHandle.d.ts +70 -0
  215. package/dist/NativeEditorDocumentHandle.js +89 -0
  216. package/dist/NativeEditorLocalAwareness.d.ts +34 -0
  217. package/dist/NativeEditorLocalAwareness.js +153 -0
  218. package/dist/NativeEditorNativeModule.d.ts +48 -0
  219. package/dist/NativeEditorNativeModule.js +34 -0
  220. package/dist/NativeEditorRenderNormalization.d.ts +22 -0
  221. package/dist/NativeEditorRenderNormalization.js +274 -0
  222. package/dist/NativeEditorResultNormalization.d.ts +108 -0
  223. package/dist/NativeEditorResultNormalization.js +400 -0
  224. package/dist/NativeEditorTypes.d.ts +318 -0
  225. package/dist/NativeEditorTypes.js +15 -0
  226. package/dist/NativeEditorV2Decimal.d.ts +5 -0
  227. package/dist/NativeEditorV2Decimal.js +18 -0
  228. package/dist/NativeProseViewer.d.ts +122 -0
  229. package/dist/NativeProseViewer.js +130 -0
  230. package/dist/NativeRichTextEditor.d.ts +3 -0
  231. package/dist/NativeRichTextEditor.js +6 -0
  232. package/dist/ResourceLimits.d.ts +100 -0
  233. package/dist/ResourceLimits.js +80 -0
  234. package/dist/RichTextEditor.d.ts +4 -0
  235. package/dist/RichTextEditor.js +25 -0
  236. package/dist/RichTextEditorNativeTypes.d.ts +122 -0
  237. package/dist/RichTextEditorNativeTypes.js +2 -0
  238. package/dist/RichTextEditorNativeView.d.ts +12 -0
  239. package/dist/RichTextEditorNativeView.js +15 -0
  240. package/dist/RichTextEditorSerialization.d.ts +53 -0
  241. package/dist/RichTextEditorSerialization.js +283 -0
  242. package/dist/RichTextEditorTypes.d.ts +281 -0
  243. package/dist/RichTextEditorTypes.js +2 -0
  244. package/dist/ViewerConfiguration.d.ts +22 -0
  245. package/dist/ViewerConfiguration.js +6 -0
  246. package/dist/YjsCollaboration.d.ts +146 -0
  247. package/dist/YjsCollaboration.js +496 -0
  248. package/dist/addons.d.ts +193 -0
  249. package/dist/addons.js +122 -0
  250. package/dist/atomConstants.d.ts +3 -0
  251. package/dist/atomConstants.js +6 -0
  252. package/dist/atomInstances.d.ts +35 -0
  253. package/dist/atomInstances.js +79 -0
  254. package/dist/atomPolicy.d.ts +4 -0
  255. package/dist/atomPolicy.js +47 -0
  256. package/dist/atomUpdates.d.ts +2 -0
  257. package/dist/atomUpdates.js +38 -0
  258. package/dist/atoms.d.ts +92 -0
  259. package/dist/atoms.js +222 -0
  260. package/dist/attributeValidation.d.ts +4 -0
  261. package/dist/attributeValidation.js +97 -0
  262. package/dist/contentExpression.d.ts +6 -0
  263. package/dist/contentExpression.js +335 -0
  264. package/dist/index.d.ts +21 -0
  265. package/dist/index.js +78 -0
  266. package/dist/listMarkers.d.ts +15 -0
  267. package/dist/listMarkers.js +21 -0
  268. package/dist/schemaDefinition.d.ts +143 -0
  269. package/dist/schemaDefinition.js +206 -0
  270. package/dist/schemaDocument.d.ts +17 -0
  271. package/dist/schemaDocument.js +69 -0
  272. package/dist/schemaDocumentConstruction.d.ts +5 -0
  273. package/dist/schemaDocumentConstruction.js +125 -0
  274. package/dist/schemaNormalization.d.ts +29 -0
  275. package/dist/schemaNormalization.js +313 -0
  276. package/dist/schemaPresets.d.ts +68 -0
  277. package/dist/schemaPresets.js +198 -0
  278. package/dist/schemaResolution.d.ts +9 -0
  279. package/dist/schemaResolution.js +211 -0
  280. package/dist/schemas.d.ts +5 -0
  281. package/dist/schemas.js +28 -0
  282. package/dist/specs/PreparedProseViewerNativeComponent.d.ts +37 -0
  283. package/dist/specs/PreparedProseViewerNativeComponent.js +6 -0
  284. package/dist/useEditorToolbarInteractions.d.ts +12 -0
  285. package/dist/useEditorToolbarInteractions.js +218 -0
  286. package/dist/useEditorToolbarItems.d.ts +8 -0
  287. package/dist/useEditorToolbarItems.js +280 -0
  288. package/dist/useEditorToolbarPresentation.d.ts +4 -0
  289. package/dist/useEditorToolbarPresentation.js +203 -0
  290. package/dist/useEditorToolbarState.d.ts +63 -0
  291. package/dist/useEditorToolbarState.js +108 -0
  292. package/dist/useFocusPreservingFrames.d.ts +17 -0
  293. package/dist/useFocusPreservingFrames.js +108 -0
  294. package/dist/useNativeEditor.d.ts +66 -0
  295. package/dist/useNativeEditor.js +370 -0
  296. package/dist/useRichTextEditorCommands.d.ts +21 -0
  297. package/dist/useRichTextEditorCommands.js +299 -0
  298. package/dist/useRichTextEditorEvents.d.ts +18 -0
  299. package/dist/useRichTextEditorEvents.js +216 -0
  300. package/dist/useRichTextEditorMentions.d.ts +11 -0
  301. package/dist/useRichTextEditorMentions.js +316 -0
  302. package/dist/useRichTextEditorPresentation.d.ts +5 -0
  303. package/dist/useRichTextEditorPresentation.js +178 -0
  304. package/dist/useRichTextEditorState.d.ts +180 -0
  305. package/dist/useRichTextEditorState.js +405 -0
  306. package/dist/useRichTextEditorUpdates.d.ts +10 -0
  307. package/dist/useRichTextEditorUpdates.js +308 -0
  308. package/dist/useViewerAtoms.d.ts +38 -0
  309. package/dist/useViewerAtoms.js +288 -0
  310. package/expo-module.config.json +13 -0
  311. package/ios/EditorAddons.swift +354 -0
  312. package/ios/EditorCodeHighlighting.swift +184 -0
  313. package/ios/EditorCore.xcframework/Info.plist +44 -0
  314. package/ios/EditorCore.xcframework/ios-arm64/libeditor_core.a +0 -0
  315. package/ios/EditorCore.xcframework/ios-arm64_x86_64-simulator/libeditor_core.a +0 -0
  316. package/ios/EditorInteractionOverlays.swift +697 -0
  317. package/ios/EditorLayoutManager.swift +971 -0
  318. package/ios/EditorNodeTypes.swift +37 -0
  319. package/ios/EditorStyleSheet.swift +461 -0
  320. package/ios/EditorTextView+AttributedPatch.swift +305 -0
  321. package/ios/EditorTextView+Binding.swift +61 -0
  322. package/ios/EditorTextView+Caret.swift +333 -0
  323. package/ios/EditorTextView+Commands.swift +203 -0
  324. package/ios/EditorTextView+Delegate.swift +65 -0
  325. package/ios/EditorTextView+Diagnostics.swift +225 -0
  326. package/ios/EditorTextView+DragDrop.swift +290 -0
  327. package/ios/EditorTextView+ExternalComposition.swift +364 -0
  328. package/ios/EditorTextView+Images.swift +354 -0
  329. package/ios/EditorTextView+InputTraits.swift +200 -0
  330. package/ios/EditorTextView+KeyboardInput.swift +318 -0
  331. package/ios/EditorTextView+Layout.swift +245 -0
  332. package/ios/EditorTextView+MarkedText.swift +267 -0
  333. package/ios/EditorTextView+NativeInputLifecycle.swift +372 -0
  334. package/ios/EditorTextView+NativeMutation.swift +471 -0
  335. package/ios/EditorTextView+Reconciliation.swift +97 -0
  336. package/ios/EditorTextView+RenderPatch.swift +573 -0
  337. package/ios/EditorTextView+Rendering.swift +539 -0
  338. package/ios/EditorTextView+Selection.swift +542 -0
  339. package/ios/EditorTextView.swift +953 -0
  340. package/ios/EditorTheme.swift +626 -0
  341. package/ios/EditorV2Adapter+Commands.swift +204 -0
  342. package/ios/EditorV2Adapter+Envelope.swift +238 -0
  343. package/ios/EditorV2Adapter+Mutation.swift +392 -0
  344. package/ios/EditorV2Adapter+Registry.swift +185 -0
  345. package/ios/EditorV2Adapter+RenderState.swift +360 -0
  346. package/ios/EditorV2Adapter+RenderValidation.swift +420 -0
  347. package/ios/EditorV2Adapter+Selection.swift +329 -0
  348. package/ios/EditorV2Adapter+TextCommands.swift +430 -0
  349. package/ios/EditorV2Adapter.swift +376 -0
  350. package/ios/EditorV2Shadow.swift +353 -0
  351. package/ios/Generated_editor_core.swift +2378 -0
  352. package/ios/NativeCodeHighlighting.swift +159 -0
  353. package/ios/NativeCollaborationSocket.swift +144 -0
  354. package/ios/NativeCollaborationTransport+Protocol.swift +258 -0
  355. package/ios/NativeCollaborationTransport+Socket.swift +379 -0
  356. package/ios/NativeCollaborationTransport+Validation.swift +103 -0
  357. package/ios/NativeCollaborationTransport.swift +322 -0
  358. package/ios/NativeCollaborationTransportRegistry.swift +521 -0
  359. package/ios/NativeEditorExpoView+AccessoryRetry.swift +219 -0
  360. package/ios/NativeEditorExpoView+Binding.swift +268 -0
  361. package/ios/NativeEditorExpoView+Diagnostics.swift +66 -0
  362. package/ios/NativeEditorExpoView+Events.swift +131 -0
  363. package/ios/NativeEditorExpoView+Focus.swift +169 -0
  364. package/ios/NativeEditorExpoView+MentionRetry.swift +288 -0
  365. package/ios/NativeEditorExpoView+Mentions.swift +288 -0
  366. package/ios/NativeEditorExpoView+Properties.swift +300 -0
  367. package/ios/NativeEditorExpoView+Toolbar.swift +86 -0
  368. package/ios/NativeEditorExpoView+Updates.swift +312 -0
  369. package/ios/NativeEditorExpoView.swift +349 -0
  370. package/ios/NativeEditorModule.swift +856 -0
  371. package/ios/NativeEditorViewRegistry.swift +226 -0
  372. package/ios/NativeToolbar+ButtonStyle.swift +214 -0
  373. package/ios/NativeToolbar+Buttons.swift +228 -0
  374. package/ios/NativeToolbar+Diagnostics.swift +114 -0
  375. package/ios/NativeToolbar+Menu.swift +101 -0
  376. package/ios/NativeToolbar+Models.swift +519 -0
  377. package/ios/NativeToolbar+Placeholder.swift +39 -0
  378. package/ios/NativeToolbar.swift +612 -0
  379. package/ios/OrderedListMarkerFormatter.swift +103 -0
  380. package/ios/PositionBridge.swift +596 -0
  381. package/ios/ProseViewerView.swift +462 -0
  382. package/ios/RenderBridge+Atoms.swift +288 -0
  383. package/ios/RenderBridge+Attachments.swift +246 -0
  384. package/ios/RenderBridge+BlockBoundaries.swift +313 -0
  385. package/ios/RenderBridge+Style.swift +343 -0
  386. package/ios/RenderBridge.swift +704 -0
  387. package/ios/RichTextEditorView.swift +930 -0
  388. package/ios/SharedNativeImagePipeline+Cache.swift +189 -0
  389. package/ios/SharedNativeImagePipeline+Transport.swift +328 -0
  390. package/ios/SharedNativeImagePipeline.swift +533 -0
  391. package/ios/Viewer/CoreTextProseLayoutEngine+AttributedText.swift +436 -0
  392. package/ios/Viewer/CoreTextProseLayoutEngine+Models.swift +322 -0
  393. package/ios/Viewer/CoreTextProseLayoutEngine.swift +635 -0
  394. package/ios/Viewer/Fabric/PREPPreparedProseViewerComponentView.h +4 -0
  395. package/ios/Viewer/Fabric/PREPPreparedProseViewerComponentView.mm +767 -0
  396. package/ios/Viewer/Fabric/PreparedProseMeasurementsManager.mm +118 -0
  397. package/ios/Viewer/NativeSVGImageDecoder.h +9 -0
  398. package/ios/Viewer/NativeSVGImageDecoder.mm +106 -0
  399. package/ios/Viewer/NativeSVGPreflight.h +11 -0
  400. package/ios/Viewer/NativeSVGPreflight.mm +219 -0
  401. package/ios/Viewer/PreparedProseDrawingView.swift +639 -0
  402. package/ios/Viewer/PreparedProseInstrumentation.swift +387 -0
  403. package/ios/Viewer/PreparedProseLayout.swift +326 -0
  404. package/ios/Viewer/PreparedProseLayoutCache.swift +766 -0
  405. package/ios/Viewer/PreparedProseLayoutRegistry+Artifacts.swift +377 -0
  406. package/ios/Viewer/PreparedProseLayoutRegistry+Fabric.swift +582 -0
  407. package/ios/Viewer/PreparedProseLayoutRegistry+FabricOwnership.swift +128 -0
  408. package/ios/Viewer/PreparedProseLayoutRegistry.swift +381 -0
  409. package/ios/Viewer/ViewerDocument.swift +575 -0
  410. package/ios/Viewer/ViewerFontEnvironment.swift +283 -0
  411. package/ios/Viewer/ViewerImagePipeline.swift +478 -0
  412. package/ios/editor_coreFFI/editor_coreFFI.h +1023 -0
  413. package/ios/editor_coreFFI/module.modulemap +7 -0
  414. package/package.json +151 -0
  415. package/react-native.config.js +17 -0
  416. package/rust/android/arm64-v8a/libeditor_core.so +0 -0
  417. package/rust/android/armeabi-v7a/libeditor_core.so +0 -0
  418. package/rust/android/x86/libeditor_core.so +0 -0
  419. package/rust/android/x86_64/libeditor_core.so +0 -0
  420. package/rust/bindings/kotlin/uniffi/editor_core/editor_core.kt +3146 -0
  421. package/src/AtomHost.tsx +180 -0
  422. package/src/DefaultAtomChip.tsx +27 -0
  423. package/src/EditorAddon.ts +65 -0
  424. package/src/EditorAddonNormalization.ts +49 -0
  425. package/src/EditorMentionThemeNormalization.ts +25 -0
  426. package/src/EditorMentionThemeValidation.ts +133 -0
  427. package/src/EditorStyleSheet.ts +9 -0
  428. package/src/EditorStyleSheetNormalization.ts +219 -0
  429. package/src/EditorStyleSheetTypes.ts +189 -0
  430. package/src/EditorTheme.ts +196 -0
  431. package/src/EditorToolbar.tsx +31 -0
  432. package/src/EditorToolbarComponent.tsx +23 -0
  433. package/src/EditorToolbarItems.tsx +64 -0
  434. package/src/EditorToolbarRegistry.tsx +254 -0
  435. package/src/EditorToolbarTypes.tsx +322 -0
  436. package/src/EditorToolbarVisuals.tsx +270 -0
  437. package/src/EditorUpdateRevision.ts +26 -0
  438. package/src/ExternalTextComposition.ts +658 -0
  439. package/src/ImageLoadingPolicy.ts +125 -0
  440. package/src/NativeEditorBoundaryError.ts +345 -0
  441. package/src/NativeEditorBridge.ts +93 -0
  442. package/src/NativeEditorCollaborationTransport.ts +493 -0
  443. package/src/NativeEditorCreateConfig.ts +326 -0
  444. package/src/NativeEditorCreateJson.ts +579 -0
  445. package/src/NativeEditorCreateValidation.ts +178 -0
  446. package/src/NativeEditorDocumentBridge.ts +485 -0
  447. package/src/NativeEditorDocumentHandle.ts +168 -0
  448. package/src/NativeEditorLocalAwareness.ts +168 -0
  449. package/src/NativeEditorNativeModule.ts +97 -0
  450. package/src/NativeEditorRenderNormalization.ts +320 -0
  451. package/src/NativeEditorResultNormalization.ts +469 -0
  452. package/src/NativeEditorTypes.ts +366 -0
  453. package/src/NativeEditorV2Decimal.ts +13 -0
  454. package/src/NativeProseViewer.tsx +356 -0
  455. package/src/NativeRichTextEditor.tsx +33 -0
  456. package/src/ResourceLimits.ts +187 -0
  457. package/src/RichTextEditor.tsx +27 -0
  458. package/src/RichTextEditorNativeTypes.tsx +144 -0
  459. package/src/RichTextEditorNativeView.tsx +21 -0
  460. package/src/RichTextEditorSerialization.tsx +381 -0
  461. package/src/RichTextEditorTypes.tsx +327 -0
  462. package/src/ViewerConfiguration.ts +23 -0
  463. package/src/YjsCollaboration.ts +692 -0
  464. package/src/addons.ts +311 -0
  465. package/src/atomConstants.ts +3 -0
  466. package/src/atomInstances.ts +123 -0
  467. package/src/atomPolicy.ts +47 -0
  468. package/src/atomUpdates.ts +52 -0
  469. package/src/atoms.ts +379 -0
  470. package/src/attributeValidation.ts +116 -0
  471. package/src/contentExpression.ts +338 -0
  472. package/src/index.ts +295 -0
  473. package/src/listMarkers.ts +18 -0
  474. package/src/schemaDefinition.ts +395 -0
  475. package/src/schemaDocument.ts +92 -0
  476. package/src/schemaDocumentConstruction.ts +148 -0
  477. package/src/schemaNormalization.ts +367 -0
  478. package/src/schemaPresets.ts +250 -0
  479. package/src/schemaResolution.ts +242 -0
  480. package/src/schemas.ts +43 -0
  481. package/src/specs/PreparedProseViewerNativeComponent.ts +40 -0
  482. package/src/useEditorToolbarInteractions.tsx +329 -0
  483. package/src/useEditorToolbarItems.tsx +390 -0
  484. package/src/useEditorToolbarPresentation.tsx +483 -0
  485. package/src/useEditorToolbarState.tsx +172 -0
  486. package/src/useFocusPreservingFrames.ts +171 -0
  487. package/src/useNativeEditor.ts +534 -0
  488. package/src/useRichTextEditorCommands.tsx +478 -0
  489. package/src/useRichTextEditorEvents.tsx +342 -0
  490. package/src/useRichTextEditorMentions.tsx +441 -0
  491. package/src/useRichTextEditorPresentation.tsx +563 -0
  492. package/src/useRichTextEditorState.tsx +620 -0
  493. package/src/useRichTextEditorUpdates.tsx +403 -0
  494. package/src/useViewerAtoms.tsx +427 -0
@@ -0,0 +1,923 @@
1
+ package com.apollohg.editor
2
+
3
+ import android.os.Handler
4
+ import android.os.Looper
5
+ import android.os.SystemClock
6
+ import android.text.Selection
7
+ import android.text.Spanned
8
+ import android.view.KeyEvent
9
+ import android.view.inputmethod.BaseInputConnection
10
+ import android.view.inputmethod.CompletionInfo
11
+ import android.view.inputmethod.CorrectionInfo
12
+ import android.view.inputmethod.ExtractedText
13
+ import android.view.inputmethod.ExtractedTextRequest
14
+ import android.view.inputmethod.InputConnection
15
+ import android.view.inputmethod.InputConnectionWrapper
16
+ import android.view.inputmethod.SurroundingText
17
+ import android.view.inputmethod.TextAttribute
18
+ import android.view.inputmethod.TextSnapshot
19
+ import androidx.annotation.RequiresApi
20
+
21
+ /**
22
+ * Custom [InputConnectionWrapper] that intercepts all text input from the soft keyboard
23
+ * and routes it through the Rust editor-core engine via the hosting [EditorEditText].
24
+ *
25
+ * Instead of letting Android's EditText text storage handle insertions and deletions
26
+ * directly, this class captures the user's intent (typing, deleting, IME composition)
27
+ * and delegates to the Rust editor. The Rust editor returns render elements, which are
28
+ * converted to [android.text.SpannableStringBuilder] via [RenderBridge] and applied
29
+ * back to the EditText.
30
+ *
31
+ * ## Composition (IME) Handling
32
+ *
33
+ * For CJK input methods, swipe keyboards, and some autocorrect flows, [setComposingText],
34
+ * [commitText], and [finishComposingText] are used together. During composition, we let
35
+ * the base [InputConnection] render transient composing text, but keep the original
36
+ * Rust-authorized replacement range so the final committed text lands at the correct
37
+ * document position.
38
+ *
39
+ * ## Key Events
40
+ *
41
+ * Hardware keyboard events (backspace, enter) arrive via [sendKeyEvent]. We intercept
42
+ * DEL and ENTER to route through the Rust editor.
43
+ */
44
+ class EditorInputConnection(
45
+ internal val editorView: EditorEditText,
46
+ baseConnection: InputConnection,
47
+ internal val boundEditorId: Long,
48
+ internal val boundGeneration: Long,
49
+ internal val boundMapperGeneration: Long
50
+ ) : InputConnectionWrapper(baseConnection, true) {
51
+ companion object {
52
+ private fun textTraceSummary(text: CharSequence?): String {
53
+ if (text == null) return "text=null"
54
+ val value = text.toString()
55
+ val codePoints = mutableListOf<String>()
56
+ var index = 0
57
+ while (index < value.length && codePoints.size < 4) {
58
+ val codePoint = Character.codePointAt(value, index)
59
+ codePoints.add(codePoint.toString(16))
60
+ index += Character.charCount(codePoint)
61
+ }
62
+ return "textLength=${value.length} codePoints=${codePoints.joinToString(",")}"
63
+ }
64
+
65
+ internal const val DUPLICATE_CORRECTION_COMMIT_WINDOW_MS = 1_000L
66
+
67
+ internal fun codePointsToUtf16Length(
68
+ text: String,
69
+ fromUtf16Offset: Int,
70
+ codePointCount: Int,
71
+ forward: Boolean
72
+ ): Int {
73
+ if (codePointCount <= 0 || text.isEmpty()) return 0
74
+
75
+ var remaining = codePointCount
76
+ var utf16Length = 0
77
+
78
+ if (forward) {
79
+ var index = fromUtf16Offset.coerceIn(0, text.length)
80
+ while (index < text.length && remaining > 0) {
81
+ val codePoint = Character.codePointAt(text, index)
82
+ val charCount = Character.charCount(codePoint)
83
+ utf16Length += charCount
84
+ index += charCount
85
+ remaining--
86
+ }
87
+ } else {
88
+ var index = fromUtf16Offset.coerceIn(0, text.length)
89
+ while (index > 0 && remaining > 0) {
90
+ val codePoint = Character.codePointBefore(text, index)
91
+ val charCount = Character.charCount(codePoint)
92
+ utf16Length += charCount
93
+ index -= charCount
94
+ remaining--
95
+ }
96
+ }
97
+
98
+ return utf16Length
99
+ }
100
+ }
101
+
102
+ internal var closedForInput = false
103
+ internal var extractedTextRequest: ExtractedTextRequest? = null
104
+ internal var lastPublishedExtractedText: ExtractedText? = null
105
+ internal var lastPublishedSelection: List<Int>? = null
106
+
107
+ override fun commitText(
108
+ text: CharSequence,
109
+ newCursorPosition: Int,
110
+ textAttribute: TextAttribute?
111
+ ): Boolean = commitText(text, newCursorPosition)
112
+
113
+ override fun setComposingText(
114
+ text: CharSequence,
115
+ newCursorPosition: Int,
116
+ textAttribute: TextAttribute?
117
+ ): Boolean = setComposingText(text, newCursorPosition)
118
+
119
+ override fun setComposingRegion(start: Int, end: Int, textAttribute: TextAttribute?): Boolean =
120
+ setComposingRegion(start, end)
121
+
122
+ override fun replaceText(
123
+ start: Int,
124
+ end: Int,
125
+ text: CharSequence,
126
+ newCursorPosition: Int,
127
+ textAttribute: TextAttribute?
128
+ ): Boolean {
129
+ if (!isCurrentInputSessionFor("replaceText") || !editorView.isEditable) return true
130
+ if (start < 0 || end < 0) return false
131
+ val requestedText = currentMapper()?.visibleText?.toString() ?: return false
132
+ if (!editorView.prepareForExternalEditorUpdate()) return true
133
+ if (!isCurrentInputSession() ||
134
+ currentMapper()?.visibleText?.toString() != requestedText
135
+ ) {
136
+ return true
137
+ }
138
+ val range =
139
+ rawRangeForIme(
140
+ start.coerceAtMost(requestedText.length),
141
+ end.coerceAtMost(requestedText.length)
142
+ )
143
+ ?: return false
144
+ val raw = editorView.editableText.toString()
145
+ val normalized = if (range.first == range.second) {
146
+ PositionBridge.snapToScalarBoundary(range.first, raw, biasForward = true).let {
147
+ it to it
148
+ }
149
+ } else {
150
+ PositionBridge.snapRangeToScalarBoundaries(range.first, range.second, raw)
151
+ }
152
+ pendingDuplicateCorrectionCommit = null
153
+ pendingCompositionCorrectionCommit = null
154
+ editorView.runWithTransientInputMutationGuard {
155
+ super.setSelection(normalized.first, normalized.second)
156
+ }
157
+ commitTextToEditor(text.toString(), newCursorPosition)
158
+ return true
159
+ }
160
+
161
+ override fun getExtractedText(request: ExtractedTextRequest?, flags: Int): ExtractedText? =
162
+ extractedTextForIme(request, flags)
163
+
164
+ @RequiresApi(31)
165
+ override fun getSurroundingText(
166
+ beforeLength: Int,
167
+ afterLength: Int,
168
+ flags: Int
169
+ ): SurroundingText? = surroundingTextForIme(beforeLength, afterLength, flags)
170
+
171
+ @RequiresApi(33)
172
+ override fun takeSnapshot(): TextSnapshot? = snapshotForIme()
173
+
174
+ override fun beginBatchEdit(): Boolean = isCurrentInputSession() && super.beginBatchEdit()
175
+
176
+ override fun performContextMenuAction(id: Int): Boolean =
177
+ isCurrentInputSession() && super.performContextMenuAction(id)
178
+
179
+ override fun performEditorAction(actionCode: Int): Boolean =
180
+ isCurrentInputSession() && editorView.isEditable && super.performEditorAction(actionCode)
181
+
182
+ override fun requestCursorUpdates(cursorUpdateMode: Int): Boolean =
183
+ isCurrentInputSession() && super.requestCursorUpdates(cursorUpdateMode)
184
+
185
+ override fun requestCursorUpdates(cursorUpdateMode: Int, cursorUpdateFilter: Int): Boolean =
186
+ isCurrentInputSession() && super.requestCursorUpdates(cursorUpdateMode, cursorUpdateFilter)
187
+
188
+ override fun closeConnection() {
189
+ if (closedForInput) return
190
+ if (isCurrentInputSession()) finishComposingText()
191
+ closedForInput = true
192
+ extractedTextRequest = null
193
+ lastPublishedExtractedText = null
194
+ super.closeConnection()
195
+ }
196
+
197
+ internal var pendingDuplicateCorrectionCommit: PendingDuplicateCorrectionCommit? = null
198
+ internal var pendingCompositionCorrectionCommit: PendingCompositionCorrectionCommit? = null
199
+ internal var pendingCompositionCorrectionGeneration: Long = 0L
200
+ private var generatedCompositionAdjustment: GeneratedCompositionAdjustment? = null
201
+
202
+ /**
203
+ * Called when the IME commits finalized text (single character, word,
204
+ * autocomplete selection, etc.).
205
+ *
206
+ * Routes the text through Rust instead of directly inserting into the EditText.
207
+ */
208
+ override fun commitText(text: CharSequence?, newCursorPosition: Int): Boolean {
209
+ if (!isCurrentInputSessionFor("commitText")) return true
210
+ if (!editorView.commitExternalTextCompositionBeforeInteractionIfNeeded()) return true
211
+ if (!editorView.isEditable) return true
212
+ if (editorView.isApplyingRustState) {
213
+ editorView.recordImeTraceForTesting(
214
+ "commitTextPassthrough",
215
+ "reason=applyingRust ${textTraceSummary(text)} cursor=$newCursorPosition"
216
+ )
217
+ return super.commitText(text, newCursorPosition)
218
+ }
219
+ if (editorView.editorId == 0L) {
220
+ editorView.recordImeTraceForTesting(
221
+ "commitTextPassthrough",
222
+ "reason=noEditor ${textTraceSummary(text)} cursor=$newCursorPosition"
223
+ )
224
+ return super.commitText(text, newCursorPosition)
225
+ }
226
+
227
+ editorView.recordImeTraceForTesting(
228
+ "commitText",
229
+ "${textTraceSummary(text)} cursor=$newCursorPosition"
230
+ )
231
+ val committedText = text?.toString()
232
+ if (consumePendingCompositionCorrectionCommitIfNeeded(committedText, newCursorPosition)) {
233
+ return true
234
+ }
235
+ applyPendingCompositionCorrectionCommitIfNeeded("commitTextBeforePlain")
236
+ if (consumePendingDuplicateCorrectionCommitIfNeeded(committedText)) {
237
+ editorView.recordImeTraceForTesting(
238
+ "commitTextDuplicateCorrectionIgnored",
239
+ "textLength=${committedText?.length ?: 0}"
240
+ )
241
+ return true
242
+ }
243
+ commitTextToEditor(committedText, newCursorPosition)
244
+ return true
245
+ }
246
+
247
+ override fun commitCompletion(text: CompletionInfo?): Boolean {
248
+ if (!isCurrentInputSessionFor("commitCompletion")) return true
249
+ if (!editorView.commitExternalTextCompositionBeforeInteractionIfNeeded()) return true
250
+ if (!editorView.isEditable) return true
251
+ if (editorView.isApplyingRustState) {
252
+ return super.commitCompletion(text)
253
+ }
254
+ if (editorView.editorId == 0L) {
255
+ return super.commitCompletion(text)
256
+ }
257
+ editorView.recordImeTraceForTesting(
258
+ "commitCompletion",
259
+ textTraceSummary(text?.text)
260
+ )
261
+ commitTextToEditor(text?.text?.toString(), 1)
262
+ return true
263
+ }
264
+
265
+ override fun getCursorCapsMode(reqModes: Int): Int {
266
+ val baseCapsMode = super.getCursorCapsMode(reqModes)
267
+ if (!isCurrentInputSession()) return baseCapsMode
268
+ val capsMode = editorView.cursorCapsModeForEditor(reqModes, baseCapsMode)
269
+ if (capsMode != baseCapsMode) {
270
+ editorView.recordImeTraceForTesting(
271
+ "getCursorCapsModeAdjusted",
272
+ "req=$reqModes base=$baseCapsMode caps=$capsMode"
273
+ )
274
+ }
275
+ return capsMode
276
+ }
277
+
278
+ override fun getTextBeforeCursor(n: Int, flags: Int): CharSequence? {
279
+ val mapper = currentMapper() ?: return ""
280
+ val cursor = minOf(editorView.selectionStart, editorView.selectionEnd)
281
+ if (cursor < 0) return ""
282
+ val end = mapper.rawToIme(cursor)
283
+ return imeTextSlice(mapper, maxOf(0, end - n.coerceAtLeast(0)), end, flags)
284
+ }
285
+
286
+ override fun getTextAfterCursor(n: Int, flags: Int): CharSequence? {
287
+ val mapper = currentMapper() ?: return ""
288
+ val cursor = maxOf(editorView.selectionStart, editorView.selectionEnd)
289
+ if (cursor < 0) return ""
290
+ val start = mapper.rawToIme(cursor)
291
+ return imeTextSlice(
292
+ mapper,
293
+ start,
294
+ minOf(mapper.visibleText.length, start + n.coerceAtLeast(0)),
295
+ flags
296
+ )
297
+ }
298
+
299
+ override fun getSelectedText(flags: Int): CharSequence? {
300
+ val mapper = currentMapper() ?: return ""
301
+ val rawStart = editorView.selectionStart
302
+ val rawEnd = editorView.selectionEnd
303
+ if (rawStart < 0 || rawEnd < 0) return ""
304
+ if (rawStart == rawEnd) return null
305
+ val imeStart = mapper.rawToIme(minOf(rawStart, rawEnd))
306
+ val imeEnd = mapper.rawToIme(maxOf(rawStart, rawEnd))
307
+ if (imeStart == imeEnd) return null
308
+ return imeTextSlice(
309
+ mapper,
310
+ imeStart,
311
+ imeEnd,
312
+ flags
313
+ )
314
+ }
315
+
316
+ override fun commitCorrection(correctionInfo: CorrectionInfo?): Boolean {
317
+ if (!isCurrentInputSessionFor("commitCorrection")) return true
318
+ if (!editorView.commitExternalTextCompositionBeforeInteractionIfNeeded()) return true
319
+ if (!editorView.isEditable) return true
320
+ if (editorView.isApplyingRustState) {
321
+ return super.commitCorrection(correctionInfo)
322
+ }
323
+ if (editorView.editorId == 0L) {
324
+ return super.commitCorrection(correctionInfo)
325
+ }
326
+ val newText = correctionInfo?.newText?.toString()
327
+ if (newText == null) return true
328
+ editorView.recordImeTraceForTesting(
329
+ "commitCorrection",
330
+ "offset=${correctionInfo.offset} oldMissing=${correctionInfo.oldText == null} newLength=${newText.length}"
331
+ )
332
+ if (trackedCompositionReplacementRange() != null) {
333
+ editorView.recordImeTraceForTesting(
334
+ "commitCorrectionComposition",
335
+ "newLength=${newText.length}"
336
+ )
337
+ rememberPendingCompositionCorrectionCommit(newText)
338
+ return true
339
+ }
340
+ if (consumeInvalidatedCompositionReplacementRangeAndRestore()) {
341
+ editorView.recordImeTraceForTesting("commitCorrectionRestoredInvalidComposition")
342
+ return true
343
+ }
344
+ val oldText = correctionInfo.oldText?.toString()
345
+ if (oldText?.isEmpty() == true) {
346
+ editorView.recordImeTraceForTesting("correctionExplicitNoop", "reason=emptyOldText")
347
+ return true
348
+ }
349
+ val imeOffset = correctionInfo.offset
350
+ val mapper = currentMapper()
351
+ val applied = if (oldText != null && mapper != null) {
352
+ val validOffset = imeOffset in 0..mapper.visibleText.length
353
+ val imeEnd = if (
354
+ validOffset &&
355
+ oldText.length <= mapper.visibleText.length - imeOffset
356
+ ) {
357
+ imeOffset + oldText.length
358
+ } else {
359
+ -1
360
+ }
361
+ if (
362
+ imeEnd >= 0 &&
363
+ mapper.visibleText.subSequence(imeOffset, imeEnd).toString() == oldText
364
+ ) {
365
+ val rawStart = mapper.imeToRaw(
366
+ imeOffset,
367
+ ImeTextCoordinateMapper.Affinity.AFTER
368
+ )
369
+ val rawEnd = mapper.imeToRaw(
370
+ imeEnd,
371
+ ImeTextCoordinateMapper.Affinity.BEFORE
372
+ )
373
+ val renderedOldText = editorView.text
374
+ ?.subSequence(rawStart, rawEnd)
375
+ ?.toString()
376
+ ?: ""
377
+ editorView.handleCorrectionCommit(
378
+ rawStart,
379
+ rawEnd,
380
+ renderedOldText,
381
+ newText
382
+ )
383
+ } else {
384
+ editorView.recordImeTraceForTesting(
385
+ "correctionExplicitNoop",
386
+ "reason=staleVisibleText offset=$imeOffset oldLength=${oldText.length}"
387
+ )
388
+ false
389
+ }
390
+ } else if (oldText == null) {
391
+ val visibleText = mapper?.visibleText?.toString()
392
+ val tokenRange = visibleText?.let {
393
+ editorView.missingOldTextCorrectionTokenRangeForEditor(it, imeOffset)
394
+ }
395
+ if (mapper != null && tokenRange != null) {
396
+ val rawStart = mapper.imeToRaw(
397
+ tokenRange.first,
398
+ ImeTextCoordinateMapper.Affinity.AFTER
399
+ )
400
+ val rawEnd = mapper.imeToRaw(
401
+ tokenRange.second,
402
+ ImeTextCoordinateMapper.Affinity.BEFORE
403
+ )
404
+ val renderedOldText = editorView.text
405
+ ?.subSequence(rawStart, rawEnd)
406
+ ?.toString()
407
+ ?: ""
408
+ editorView.handleMissingOldTextCorrectionCommit(
409
+ rawStart,
410
+ rawEnd,
411
+ renderedOldText,
412
+ newText
413
+ )
414
+ } else {
415
+ editorView.recordImeTraceForTesting(
416
+ "correctionInferredNoop",
417
+ "reason=noVisibleToken offset=$imeOffset newLength=${newText.length}"
418
+ )
419
+ false
420
+ }
421
+ } else {
422
+ false
423
+ }
424
+ editorView.recordImeTraceForTesting(
425
+ "commitCorrectionResult",
426
+ "applied=$applied"
427
+ )
428
+ if (applied) {
429
+ rememberPendingDuplicateCorrectionCommit(newText)
430
+ }
431
+ return true
432
+ }
433
+
434
+ internal fun commitTextToEditor(committedText: String?, newCursorPosition: Int) {
435
+ val startedAt = System.nanoTime()
436
+ val trackedReplacementRange = trackedCompositionReplacementRange()
437
+ val rawComposingSpanRange = currentComposingSpanRawRange()
438
+ val currentAuthorizedComposingSpanRange = currentComposingSpanRange()
439
+ val visibleReplacementRange = rawComposingSpanRange ?: trackedReplacementRange
440
+ val replacementRange = trackedReplacementRange?.let { range ->
441
+ if (range.first == range.second) {
442
+ currentAuthorizedComposingSpanRange ?: range
443
+ } else {
444
+ range
445
+ }
446
+ }
447
+ if (replacementRange != null) {
448
+ editorView.recordImeTraceForTesting(
449
+ "commitTextRoute",
450
+ "route=composition replacement=${replacementRange.first}..${replacementRange.second} visible=${visibleReplacementRange?.first}..${visibleReplacementRange?.second} textLength=${committedText?.length ?: 0}"
451
+ )
452
+ clearCompositionTracking()
453
+ editorView.runWithTransientInputMutationGuard {
454
+ super.finishComposingText()
455
+ }
456
+ if (committedText != null) {
457
+ var didCommitAlreadyVisibleMutation = false
458
+ if (
459
+ trackedReplacementRange?.first == trackedReplacementRange?.second &&
460
+ rawComposingSpanRange == null
461
+ ) {
462
+ editorView.runWithDeferredRustUpdateApplication {
463
+ didCommitAlreadyVisibleMutation =
464
+ editorView
465
+ .commitVisibleCompositionMutationForPendingImeOperation(
466
+ committedText,
467
+ newCursorPosition
468
+ )
469
+ }
470
+ }
471
+ if (!didCommitAlreadyVisibleMutation) {
472
+ visibleReplacementRange?.let { visibleRange ->
473
+ editorView.applyVisibleCompositionCommitForPendingImeOperationForEditor(
474
+ committedText,
475
+ visibleRange.first,
476
+ visibleRange.second,
477
+ newCursorPosition
478
+ )
479
+ }
480
+ editorView.runWithDeferredRustUpdateApplication {
481
+ editorView.handleCompositionCommit(
482
+ committedText,
483
+ replacementRange.first,
484
+ replacementRange.second,
485
+ newCursorPosition
486
+ )
487
+ }
488
+ }
489
+ } else {
490
+ editorView.restoreAuthorizedTextIfNeeded()
491
+ }
492
+ } else {
493
+ if (consumeInvalidatedCompositionReplacementRangeAndRestore()) {
494
+ editorView.recordImeTraceForTesting(
495
+ "commitTextRoute",
496
+ "route=restoreInvalidComposition textLength=${committedText?.length ?: 0}"
497
+ )
498
+ return
499
+ }
500
+ clearCompositionTracking()
501
+ editorView.recordImeTraceForTesting(
502
+ "commitTextRoute",
503
+ "route=plain textLength=${committedText?.length ?: 0}"
504
+ )
505
+ committedText?.let { editorView.handleTextCommit(it, newCursorPosition) }
506
+ }
507
+ editorView.recordImeTraceForTesting(
508
+ "commitTextRouteDone",
509
+ "textLength=${committedText?.length ?: 0} totalUs=${nanosToMicros(
510
+ System.nanoTime() - startedAt
511
+ )}"
512
+ )
513
+ }
514
+
515
+ /**
516
+ * Called when the IME requests deletion of text surrounding the cursor.
517
+ *
518
+ * Routes the deletion through Rust instead of directly modifying the EditText.
519
+ *
520
+ * @param beforeLength Number of UTF-16 code units to delete before the cursor.
521
+ * @param afterLength Number of UTF-16 code units to delete after the cursor.
522
+ */
523
+ override fun deleteSurroundingText(beforeLength: Int, afterLength: Int): Boolean {
524
+ if (!isCurrentInputSessionFor("deleteSurroundingText")) return true
525
+ if (!editorView.commitExternalTextCompositionBeforeInteractionIfNeeded()) return true
526
+ if (!editorView.isEditable) return true
527
+ if (editorView.isApplyingRustState) {
528
+ return super.deleteSurroundingText(beforeLength, afterLength)
529
+ }
530
+ editorView.recordImeTraceForTesting(
531
+ "deleteSurroundingText",
532
+ "before=$beforeLength after=$afterLength"
533
+ )
534
+ if (
535
+ editorView.hasInvalidatedCompositionReplacementRangeForEditor() &&
536
+ isNoOpSurroundingDelete(beforeLength, afterLength)
537
+ ) {
538
+ return finishStaleComposingUpdateAfterInvalidation()
539
+ }
540
+ if (consumeInvalidatedCompositionReplacementRangeAndRestore()) {
541
+ return true
542
+ }
543
+ if (trackedCompositionReplacementRange() != null) {
544
+ return performMappedCompositionSurroundingDelete(
545
+ beforeLength,
546
+ afterLength,
547
+ deleteInCodePoints = false
548
+ )
549
+ }
550
+ if (shouldDeferPlainSurroundingDelete(beforeLength, afterLength)) {
551
+ return performDeferredPlainSurroundingDelete(
552
+ beforeLength = beforeLength,
553
+ afterLength = afterLength,
554
+ deleteInCodePoints = false
555
+ )
556
+ }
557
+ editorView.handleDelete(beforeLength, afterLength)
558
+ return true
559
+ }
560
+
561
+ override fun deleteSurroundingTextInCodePoints(beforeLength: Int, afterLength: Int): Boolean {
562
+ if (!isCurrentInputSessionFor("deleteSurroundingTextInCodePoints")) return true
563
+ if (!editorView.commitExternalTextCompositionBeforeInteractionIfNeeded()) return true
564
+ if (!editorView.isEditable) return true
565
+ if (editorView.isApplyingRustState) {
566
+ return super.deleteSurroundingTextInCodePoints(beforeLength, afterLength)
567
+ }
568
+ editorView.recordImeTraceForTesting(
569
+ "deleteSurroundingTextInCodePoints",
570
+ "before=$beforeLength after=$afterLength"
571
+ )
572
+ if (
573
+ editorView.hasInvalidatedCompositionReplacementRangeForEditor() &&
574
+ isNoOpSurroundingDelete(beforeLength, afterLength)
575
+ ) {
576
+ return finishStaleComposingUpdateAfterInvalidation()
577
+ }
578
+ if (consumeInvalidatedCompositionReplacementRangeAndRestore()) {
579
+ return true
580
+ }
581
+ if (trackedCompositionReplacementRange() != null) {
582
+ return performMappedCompositionSurroundingDelete(
583
+ beforeLength,
584
+ afterLength,
585
+ deleteInCodePoints = true
586
+ )
587
+ }
588
+ if (shouldDeferPlainSurroundingDelete(beforeLength, afterLength)) {
589
+ return performDeferredPlainSurroundingDelete(
590
+ beforeLength = beforeLength,
591
+ afterLength = afterLength,
592
+ deleteInCodePoints = true
593
+ )
594
+ }
595
+
596
+ val currentText = editorView.text?.toString().orEmpty()
597
+ val cursor = editorView.selectionStart.coerceAtLeast(0)
598
+ val beforeUtf16Length = codePointsToUtf16Length(
599
+ text = currentText,
600
+ fromUtf16Offset = cursor,
601
+ codePointCount = beforeLength,
602
+ forward = false
603
+ )
604
+ val afterUtf16Length = codePointsToUtf16Length(
605
+ text = currentText,
606
+ fromUtf16Offset = editorView.selectionEnd.coerceAtLeast(cursor),
607
+ codePointCount = afterLength,
608
+ forward = true
609
+ )
610
+ editorView.handleDelete(beforeUtf16Length, afterUtf16Length)
611
+ return true
612
+ }
613
+
614
+ /**
615
+ * Called when the IME sets composing (in-progress) text for CJK/swipe input.
616
+ *
617
+ * We let the base InputConnection handle this normally so the user sees
618
+ * the composing text with its underline decoration. The text is NOT sent
619
+ * to Rust during composition — only when the IME commits or finishes it.
620
+ */
621
+ override fun setComposingText(text: CharSequence?, newCursorPosition: Int): Boolean {
622
+ if (!isCurrentInputSessionFor("setComposingText")) return true
623
+ if (!editorView.commitExternalTextCompositionBeforeInteractionIfNeeded()) return true
624
+ if (!editorView.isEditable) return true
625
+ if (editorView.editorId == 0L) return super.setComposingText(text, newCursorPosition)
626
+ if (editorView.hasInvalidatedCompositionReplacementRangeForEditor()) {
627
+ return finishStaleComposingUpdateAfterInvalidation()
628
+ }
629
+ captureCompositionReplacementRangeIfNeeded()
630
+ val composingText = text?.toString()?.let { value ->
631
+ generatedCompositionAdjustment?.sanitize(value) ?: value
632
+ }
633
+ val adjustedComposingText =
634
+ editorView.samsungSentenceCapsComposingTextForEditor(composingText)
635
+ val textForBaseConnection = adjustedComposingText ?: text
636
+ editorView.recordImeTraceForTesting(
637
+ "setComposingText",
638
+ "${textTraceSummary(
639
+ text
640
+ )} cursor=$newCursorPosition adjusted=${textForBaseConnection.toString() != text?.toString()}"
641
+ )
642
+ editorView.setComposingTextForEditor(adjustedComposingText)
643
+ val trackedRange = trackedCompositionReplacementRange()
644
+ val currentText = editorView.text?.toString()
645
+ if (
646
+ trackedRange != null &&
647
+ currentText != null &&
648
+ editorView.isCurrentTextAuthorizedForEditor() &&
649
+ currentText.substring(trackedRange.first, trackedRange.second) == adjustedComposingText
650
+ ) {
651
+ return editorView.runWithTransientInputMutationGuard {
652
+ val regionSet = super.setComposingRegion(trackedRange.first, trackedRange.second)
653
+ val requestedCursor = if (newCursorPosition > 0) {
654
+ trackedRange.second + newCursorPosition - 1
655
+ } else {
656
+ trackedRange.first + newCursorPosition
657
+ }.coerceIn(0, currentText.length)
658
+ val selectionSet = super.setSelection(requestedCursor, requestedCursor)
659
+ if (regionSet) {
660
+ editorView.applyTransientComposingTextStyleForEditor()
661
+ }
662
+ regionSet && selectionSet
663
+ }
664
+ }
665
+ return editorView.runWithTransientInputMutationGuard {
666
+ val result = super.setComposingText(textForBaseConnection, newCursorPosition)
667
+ if (result) {
668
+ editorView.applyTransientComposingTextStyleForEditor()
669
+ }
670
+ result
671
+ }
672
+ }
673
+
674
+ override fun setComposingRegion(start: Int, end: Int): Boolean {
675
+ if (!isCurrentInputSessionFor("setComposingRegion")) return true
676
+ if (!editorView.commitExternalTextCompositionBeforeInteractionIfNeeded()) return true
677
+ if (!editorView.isEditable) return true
678
+ val rawRange = rawRangeForIme(start, end) ?: return true
679
+ if (editorView.editorId == 0L) {
680
+ return super.setComposingRegion(rawRange.first, rawRange.second)
681
+ }
682
+ if (editorView.hasInvalidatedCompositionReplacementRangeForEditor()) {
683
+ return finishStaleComposingUpdateAfterInvalidation()
684
+ }
685
+ val currentText = editorView.text?.toString().orEmpty()
686
+ val requestedStart = minOf(rawRange.first, rawRange.second).coerceIn(0, currentText.length)
687
+ val requestedEnd = maxOf(rawRange.first, rawRange.second).coerceIn(0, currentText.length)
688
+ val contentRange = editorView.compositionContentRangeForEditor(requestedStart, requestedEnd)
689
+ if (contentRange == null) {
690
+ generatedCompositionAdjustment = null
691
+ editorView.recordImeTraceForTesting(
692
+ "setComposingRegionRejected",
693
+ "range=$start..$end reason=generatedInterior"
694
+ )
695
+ return true
696
+ }
697
+ if (editorView.isCurrentTextAuthorizedForEditor()) {
698
+ editorView.setCompositionReplacementRange(contentRange.first, contentRange.second)
699
+ }
700
+ generatedCompositionAdjustment = if (
701
+ contentRange.first != requestedStart || contentRange.second != requestedEnd
702
+ ) {
703
+ GeneratedCompositionAdjustment(
704
+ leadingText = currentText.substring(requestedStart, contentRange.first),
705
+ trailingText = currentText.substring(contentRange.second, requestedEnd)
706
+ )
707
+ } else {
708
+ null
709
+ }
710
+ editorView.recordImeTraceForTesting(
711
+ "setComposingRegion",
712
+ "range=$start..$end content=${contentRange.first}..${contentRange.second}"
713
+ )
714
+ return editorView.runWithTransientInputMutationGuard {
715
+ val result = super.setComposingRegion(contentRange.first, contentRange.second)
716
+ if (result) {
717
+ editorView.applyTransientComposingTextStyleForEditor()
718
+ }
719
+ result
720
+ }
721
+ }
722
+
723
+ override fun setSelection(start: Int, end: Int): Boolean {
724
+ if (!isCurrentInputSessionFor("setSelection")) return true
725
+ if (!editorView.commitExternalTextCompositionBeforeInteractionIfNeeded()) return true
726
+ val rawRange = rawRangeForIme(start, end) ?: return true
727
+ if (!editorView.isEditable) {
728
+ consumeInvalidatedCompositionReplacementRangeAndRestore()
729
+ return true
730
+ }
731
+ if (editorView.isApplyingRustState) {
732
+ return super.setSelection(rawRange.first, rawRange.second)
733
+ }
734
+ if (editorView.editorId == 0L) {
735
+ return super.setSelection(rawRange.first, rawRange.second)
736
+ }
737
+ if (editorView.hasInvalidatedCompositionReplacementRangeForEditor()) {
738
+ return finishStaleComposingUpdateAfterInvalidation()
739
+ }
740
+ return super.setSelection(rawRange.first, rawRange.second)
741
+ }
742
+
743
+ /**
744
+ * Called when IME composition is finalized (user selects a candidate or
745
+ * presses space/enter to commit the composing text).
746
+ *
747
+ * At this point, the composed text is final. We notify the [EditorEditText]
748
+ * so it can capture the result and send it to Rust.
749
+ */
750
+ override fun finishComposingText(): Boolean {
751
+ if (!isCurrentInputSessionFor("finishComposingText")) return true
752
+ if (editorView.hasActiveExternalTextCompositionForEditor()) return true
753
+ if (applyPendingCompositionCorrectionCommitIfNeeded("finishComposingText")) return true
754
+ return finishComposingTextInternal(blockWhenCompositionWasCancelled = false)
755
+ }
756
+
757
+ internal fun flushPendingCompositionForExternalMutation(): Boolean {
758
+ if (!isCurrentInputSessionFor("flushPendingComposition")) return true
759
+ if (!hasPendingComposition()) return true
760
+ return finishComposingTextInternal(blockWhenCompositionWasCancelled = true)
761
+ }
762
+
763
+ internal fun hasPendingComposition(): Boolean {
764
+ if (!isCurrentInputSessionFor("hasPendingComposition")) return false
765
+ if (trackedCompositionReplacementRange() != null) return true
766
+ val editable = editorView.text ?: return false
767
+ val start = BaseInputConnection.getComposingSpanStart(editable)
768
+ val end = BaseInputConnection.getComposingSpanEnd(editable)
769
+ return start >= 0 && end >= 0 && start != end
770
+ }
771
+
772
+ internal fun refreshComposingTextFromEditableForEditor() {
773
+ if (!isCurrentInputSessionFor("refreshComposingText")) return
774
+ refreshComposingTextFromEditable()
775
+ }
776
+
777
+ internal fun clearCompositionTrackingForEditor() {
778
+ if (!isCurrentInputSessionFor("clearCompositionTracking")) return
779
+ clearCompositionTracking()
780
+ }
781
+
782
+ internal fun deleteTransientTextForHardwareKeyEvent(event: KeyEvent): Boolean =
783
+ if (!isCurrentInputSession()) {
784
+ false
785
+ } else {
786
+ when (event.keyCode) {
787
+ KeyEvent.KEYCODE_DEL -> deleteTransientTextAroundSelectionInCodePoints(1, 0)
788
+ KeyEvent.KEYCODE_FORWARD_DEL -> deleteTransientTextAroundSelectionInCodePoints(0, 1)
789
+ else -> false
790
+ }
791
+ }
792
+
793
+ private fun finishComposingTextInternal(blockWhenCompositionWasCancelled: Boolean): Boolean {
794
+ if (!isCurrentInputSessionFor("finishComposingText")) return true
795
+ if (!editorView.isEditable) {
796
+ clearCompositionTracking()
797
+ editorView.restoreAuthorizedTextIfNeeded()
798
+ return true
799
+ }
800
+ if (editorView.editorId == 0L) return super.finishComposingText()
801
+ refreshComposingTextFromEditable()
802
+ val composed = editorView.composingTextForEditor() ?: currentComposingSpanText()
803
+ val trackedReplacementRange = trackedCompositionReplacementRange()
804
+ val didInvalidateReplacementRange = consumeInvalidatedCompositionReplacementRange()
805
+ val replacementRange = if (didInvalidateReplacementRange) {
806
+ null
807
+ } else {
808
+ trackedReplacementRange ?: currentComposingSpanRange()
809
+ }
810
+ editorView.recordImeTraceForTesting(
811
+ "finishComposingText",
812
+ "replacement=${replacementRange?.first}..${replacementRange?.second} composedLength=${composed?.length ?: 0} invalidated=$didInvalidateReplacementRange"
813
+ )
814
+ clearCompositionTracking()
815
+
816
+ // Prevent selection sync while the base connection commits the composed
817
+ // text, since the Rust document doesn't have it yet.
818
+ val result = editorView.runWithTransientInputMutationGuard {
819
+ super.finishComposingText()
820
+ }
821
+
822
+ if (
823
+ replacementRange != null &&
824
+ (!composed.isNullOrEmpty() || replacementRange.first != replacementRange.second)
825
+ ) {
826
+ editorView.runWithDeferredRustUpdateApplication {
827
+ editorView.handleCompositionCommit(
828
+ composed.orEmpty(),
829
+ replacementRange.first,
830
+ replacementRange.second
831
+ )
832
+ }
833
+ return true
834
+ } else if (replacementRange != null) {
835
+ editorView.restoreAuthorizedTextIfNeeded()
836
+ return !blockWhenCompositionWasCancelled
837
+ } else if (didInvalidateReplacementRange) {
838
+ editorView.restoreAuthorizedTextIfNeeded()
839
+ return !blockWhenCompositionWasCancelled
840
+ }
841
+ return result
842
+ }
843
+
844
+ private fun captureCompositionReplacementRangeIfNeeded() {
845
+ editorView.captureCompositionReplacementRangeIfNeeded()
846
+ }
847
+
848
+ private fun trackedCompositionReplacementRange(): Pair<Int, Int>? =
849
+ editorView.compositionReplacementRange()
850
+
851
+ private fun clearCompositionTracking() {
852
+ generatedCompositionAdjustment = null
853
+ editorView.clearCompositionTrackingForEditor()
854
+ }
855
+
856
+ private fun consumeInvalidatedCompositionReplacementRange(): Boolean =
857
+ editorView.consumeInvalidatedCompositionReplacementRangeForEditor()
858
+
859
+ private fun consumeInvalidatedCompositionReplacementRangeAndRestore(): Boolean {
860
+ if (!consumeInvalidatedCompositionReplacementRange()) return false
861
+ clearCompositionTracking()
862
+ editorView.runWithTransientInputMutationGuard {
863
+ super.finishComposingText()
864
+ }
865
+ editorView.restoreAuthorizedTextIfNeeded()
866
+ return true
867
+ }
868
+
869
+ private fun finishStaleComposingUpdateAfterInvalidation(): Boolean {
870
+ clearCompositionTracking()
871
+ val result = editorView.runWithTransientInputMutationGuard {
872
+ super.finishComposingText()
873
+ }
874
+ editorView.restoreAuthorizedTextIfNeeded()
875
+ return result
876
+ }
877
+
878
+ override fun sendKeyEvent(event: KeyEvent?): Boolean {
879
+ if (!isCurrentInputSession()) return true
880
+ if (!editorView.commitExternalTextCompositionBeforeInteractionIfNeeded()) return true
881
+ if (
882
+ event?.action == KeyEvent.ACTION_UP &&
883
+ editorView.hasInvalidatedCompositionReplacementRangeForEditor()
884
+ ) {
885
+ return finishStaleComposingUpdateAfterInvalidation()
886
+ }
887
+ if (
888
+ shouldConsumeInvalidatedCompositionForKeyEvent(event) &&
889
+ consumeInvalidatedCompositionReplacementRangeAndRestore()
890
+ ) {
891
+ return true
892
+ }
893
+ if (!editorView.isEditable &&
894
+ event?.let { editorView.isReadOnlyTextMutationKeyEvent(it) } == true
895
+ ) {
896
+ return true
897
+ }
898
+ if (event != null && editorView.handleCompositionKeyEvent(event) {
899
+ super.sendKeyEvent(event)
900
+ }
901
+ ) {
902
+ return true
903
+ }
904
+ if (event != null && editorView.handleHardwareKeyEvent(event)) {
905
+ return true
906
+ }
907
+ if (event != null && editorView.handlePrintableHardwareKeyEvent(event) {
908
+ super.sendKeyEvent(event)
909
+ }
910
+ ) {
911
+ return true
912
+ }
913
+ return super.sendKeyEvent(event)
914
+ }
915
+
916
+ private fun shouldConsumeInvalidatedCompositionForKeyEvent(event: KeyEvent?): Boolean {
917
+ if (event == null || event.action == KeyEvent.ACTION_UP) return false
918
+ return editorView.isReadOnlyTextMutationKeyEvent(event)
919
+ }
920
+
921
+ private fun isNoOpSurroundingDelete(beforeLength: Int, afterLength: Int): Boolean =
922
+ beforeLength <= 0 && afterLength <= 0
923
+ }