chrome-devtools-frontend 1.0.941208 → 1.0.943182

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 (289) hide show
  1. package/WATCHLISTS +1 -1
  2. package/config/gni/all_devtools_files.gni +0 -64
  3. package/config/gni/devtools_grd_files.gni +54 -19
  4. package/config/gni/devtools_image_files.gni +1 -3
  5. package/front_end/.eslintrc.js +11 -1
  6. package/front_end/Images/src/{feedback_thin_16x16_icon.svg → survey_feedback_icon.svg} +1 -1
  7. package/front_end/Tests.js +1 -32
  8. package/front_end/core/common/Color.ts +5 -0
  9. package/front_end/core/i18n/locales/en-US.json +17 -29
  10. package/front_end/core/i18n/locales/en-XL.json +17 -29
  11. package/front_end/core/sdk/CPUProfilerModel.ts +7 -9
  12. package/front_end/core/sdk/ConsoleModel.ts +27 -33
  13. package/front_end/core/sdk/DebuggerModel.ts +4 -14
  14. package/front_end/core/sdk/sdk-meta.ts +17 -3
  15. package/front_end/entrypoints/device_mode_emulation_frame/device_mode_emulation_frame.ts +1 -1
  16. package/front_end/entrypoints/devtools_app/devtools_app.js +1 -1
  17. package/front_end/entrypoints/devtools_app/devtools_app.json +1 -12
  18. package/front_end/entrypoints/formatter_worker/formatter_worker-entrypoint.ts +1 -1
  19. package/front_end/entrypoints/heap_snapshot_worker/heap_snapshot_worker-entrypoint.ts +1 -1
  20. package/front_end/entrypoints/inspector/inspector.js +1 -1
  21. package/front_end/entrypoints/inspector/inspector.json +1 -3
  22. package/front_end/entrypoints/inspector_main/inspector_main-meta.ts +2 -3
  23. package/front_end/entrypoints/js_app/js_app.js +1 -1
  24. package/front_end/entrypoints/js_app/js_app.json +1 -3
  25. package/front_end/entrypoints/main/MainImpl.ts +26 -0
  26. package/front_end/entrypoints/main/main-meta.ts +1 -2
  27. package/front_end/entrypoints/ndb_app/ndb_app.js +1 -1
  28. package/front_end/entrypoints/node_app/node_app-meta.ts +0 -2
  29. package/front_end/entrypoints/node_app/node_app.js +1 -1
  30. package/front_end/entrypoints/node_app/node_app.json +1 -3
  31. package/front_end/entrypoints/node_main/node_main-meta.ts +0 -1
  32. package/front_end/entrypoints/shell/shell.js +0 -11
  33. package/front_end/entrypoints/shell/shell.json +1 -5
  34. package/front_end/entrypoints/wasmparser_worker/wasmparser_worker-entrypoint.ts +1 -1
  35. package/front_end/entrypoints/worker_app/worker_app.js +1 -1
  36. package/front_end/entrypoints/worker_app/worker_app.json +1 -7
  37. package/front_end/generated/InspectorBackendCommands.js +19 -0
  38. package/front_end/generated/protocol-mapping.d.ts +31 -1
  39. package/front_end/generated/protocol-proxy-api.d.ts +34 -2
  40. package/front_end/generated/protocol.d.ts +81 -6
  41. package/front_end/legacy_test_runner/bindings_test_runner/IsolatedFilesystemTestRunner.js +2 -2
  42. package/front_end/legacy_test_runner/console_test_runner/console_test_runner.js +5 -1
  43. package/front_end/legacy_test_runner/legacy_test_runner.ts +10 -1
  44. package/front_end/legacy_test_runner/test_runner/TestRunner.js +3 -1
  45. package/front_end/models/formatter/SourceFormatter.ts +0 -10
  46. package/front_end/models/persistence/persistence-meta.ts +0 -1
  47. package/front_end/models/workspace/UISourceCode.ts +9 -42
  48. package/front_end/panels/accessibility/accessibility-meta.ts +0 -1
  49. package/front_end/panels/animation/AnimationTimeline.ts +3 -3
  50. package/front_end/panels/animation/animation-meta.ts +0 -1
  51. package/front_end/panels/application/ApplicationPanelSidebar.ts +3 -3
  52. package/front_end/panels/application/BackForwardCacheStrings.ts +3 -1
  53. package/front_end/panels/application/application-meta.ts +0 -4
  54. package/front_end/panels/application/components/EndpointsGrid.ts +1 -1
  55. package/front_end/panels/application/components/ReportsGrid.ts +1 -1
  56. package/front_end/panels/application/components/stackTraceRow.css +8 -0
  57. package/front_end/panels/browser_debugger/browser_debugger-meta.ts +1 -2
  58. package/front_end/panels/changes/changes-meta.ts +0 -1
  59. package/front_end/panels/console/ConsolePinPane.ts +23 -32
  60. package/front_end/panels/console/ConsoleViewMessage.ts +8 -1
  61. package/front_end/panels/console/console-meta.ts +0 -1
  62. package/front_end/panels/console_counters/console_counters-meta.ts +0 -1
  63. package/front_end/panels/coverage/CoverageDecorationManager.ts +4 -5
  64. package/front_end/panels/coverage/CoverageView.ts +2 -105
  65. package/front_end/panels/coverage/coverage-meta.ts +0 -1
  66. package/front_end/panels/css_overview/components/CSSOverviewStartView.ts +11 -56
  67. package/front_end/panels/css_overview/components/cssOverviewStartView.css +1 -8
  68. package/front_end/panels/css_overview/css_overview-meta.ts +0 -1
  69. package/front_end/panels/developer_resources/developer_resources-meta.ts +0 -1
  70. package/front_end/panels/elements/ElementsTreeElement.ts +4 -9
  71. package/front_end/panels/elements/components/StylePropertyEditor.ts +2 -0
  72. package/front_end/panels/elements/components/adornerSettingsPane.css +0 -4
  73. package/front_end/panels/elements/elements-meta.ts +0 -1
  74. package/front_end/panels/emulation/DeviceModeToolbar.ts +3 -1
  75. package/front_end/panels/emulation/DeviceModeView.ts +2 -1
  76. package/front_end/panels/emulation/InspectedPagePlaceholder.ts +3 -1
  77. package/front_end/panels/emulation/MediaQueryInspector.ts +3 -1
  78. package/front_end/panels/emulation/emulation-meta.ts +2 -5
  79. package/front_end/panels/help/help-meta.ts +0 -1
  80. package/front_end/panels/input/input-meta.ts +0 -1
  81. package/front_end/panels/issues/issues-meta.ts +0 -3
  82. package/front_end/panels/js_profiler/js_profiler-meta.ts +0 -4
  83. package/front_end/panels/layers/layers-meta.ts +0 -4
  84. package/front_end/panels/lighthouse/LighthousePanel.ts +2 -4
  85. package/front_end/panels/lighthouse/LighthouseReportRenderer.ts +1 -4
  86. package/front_end/panels/lighthouse/lighthouse-meta.ts +0 -1
  87. package/front_end/panels/lighthouse/lighthouseStartView.css +4 -0
  88. package/front_end/panels/lighthouse/module.json +0 -6
  89. package/front_end/panels/media/media-meta.ts +0 -4
  90. package/front_end/panels/mobile_throttling/mobile_throttling-meta.ts +0 -1
  91. package/front_end/panels/network/ResourceWebSocketFrameView.ts +2 -1
  92. package/front_end/panels/network/network-meta.ts +1 -5
  93. package/front_end/panels/performance_monitor/performance_monitor-meta.ts +0 -1
  94. package/front_end/panels/profiler/CPUProfileView.ts +10 -3
  95. package/front_end/panels/profiler/profiler-meta.ts +0 -3
  96. package/front_end/panels/protocol_monitor/protocol_monitor-meta.ts +0 -1
  97. package/front_end/panels/screencast/screencast-meta.ts +0 -4
  98. package/front_end/panels/security/security-meta.ts +0 -4
  99. package/front_end/panels/sensors/sensors-meta.ts +0 -1
  100. package/front_end/panels/settings/emulation/emulation-meta.ts +0 -1
  101. package/front_end/panels/settings/settings-meta.ts +0 -1
  102. package/front_end/panels/sources/BreakpointEditDialog.ts +16 -30
  103. package/front_end/panels/sources/CSSPlugin.ts +310 -331
  104. package/front_end/panels/sources/CallStackSidebarPane.ts +28 -34
  105. package/front_end/panels/sources/CoveragePlugin.ts +121 -6
  106. package/front_end/panels/sources/DebuggerPlugin.ts +1166 -1243
  107. package/front_end/panels/sources/EditingLocationHistoryManager.ts +71 -101
  108. package/front_end/panels/sources/GoToLineQuickOpen.ts +4 -3
  109. package/front_end/panels/sources/InplaceFormatterEditorAction.ts +3 -3
  110. package/front_end/panels/sources/JavaScriptCompilerPlugin.ts +26 -23
  111. package/front_end/panels/sources/Plugin.ts +20 -4
  112. package/front_end/panels/sources/ProfilePlugin.ts +185 -0
  113. package/front_end/panels/sources/ScriptFormatterEditorAction.ts +3 -3
  114. package/front_end/panels/sources/ScriptOriginPlugin.ts +0 -10
  115. package/front_end/panels/sources/SnippetsPlugin.ts +1 -10
  116. package/front_end/panels/sources/SourcesPanel.ts +6 -5
  117. package/front_end/panels/sources/SourcesView.ts +10 -8
  118. package/front_end/panels/sources/TabbedEditorContainer.ts +31 -27
  119. package/front_end/panels/sources/UISourceCodeFrame.ts +335 -470
  120. package/front_end/panels/sources/WatchExpressionsSidebarPane.ts +3 -2
  121. package/front_end/panels/sources/sources-legacy.ts +0 -6
  122. package/front_end/panels/sources/sources-meta.ts +2 -6
  123. package/front_end/panels/sources/sources.ts +0 -2
  124. package/front_end/panels/timeline/timeline-meta.ts +2 -9
  125. package/front_end/panels/web_audio/web_audio-meta.ts +0 -1
  126. package/front_end/panels/webauthn/webauthn-meta.ts +0 -1
  127. package/front_end/third_party/codemirror.next/bundle.ts +9 -13
  128. package/front_end/third_party/codemirror.next/chunk/codemirror.js +1 -1
  129. package/front_end/third_party/codemirror.next/chunk/javascript.js +2 -2
  130. package/front_end/third_party/codemirror.next/chunk/markdown.js +2 -6
  131. package/front_end/third_party/codemirror.next/chunk/php.js +2 -6
  132. package/front_end/third_party/codemirror.next/chunk/python.js +1 -1
  133. package/front_end/third_party/codemirror.next/chunk/wast.js +1 -1
  134. package/front_end/third_party/codemirror.next/chunk/xml.js +2 -2
  135. package/front_end/third_party/codemirror.next/codemirror.next.d.ts +279 -198
  136. package/front_end/third_party/codemirror.next/codemirror.next.js +1 -1
  137. package/front_end/third_party/codemirror.next/package.json +13 -11
  138. package/front_end/third_party/lighthouse/lighthouse-dt-bundle.js +1128 -1158
  139. package/front_end/third_party/lighthouse/locales/ar-XB.json +211 -79
  140. package/front_end/third_party/lighthouse/locales/ar.json +213 -81
  141. package/front_end/third_party/lighthouse/locales/bg.json +211 -79
  142. package/front_end/third_party/lighthouse/locales/ca.json +212 -80
  143. package/front_end/third_party/lighthouse/locales/cs.json +211 -79
  144. package/front_end/third_party/lighthouse/locales/da.json +211 -79
  145. package/front_end/third_party/lighthouse/locales/de.json +211 -79
  146. package/front_end/third_party/lighthouse/locales/el.json +213 -81
  147. package/front_end/third_party/lighthouse/locales/en-GB.json +211 -79
  148. package/front_end/third_party/lighthouse/locales/en-US.json +186 -75
  149. package/front_end/third_party/lighthouse/locales/en-XA.json +211 -79
  150. package/front_end/third_party/lighthouse/locales/en-XL.json +186 -75
  151. package/front_end/third_party/lighthouse/locales/es-419.json +211 -79
  152. package/front_end/third_party/lighthouse/locales/es.json +212 -80
  153. package/front_end/third_party/lighthouse/locales/fi.json +211 -79
  154. package/front_end/third_party/lighthouse/locales/fil.json +211 -79
  155. package/front_end/third_party/lighthouse/locales/fr.json +211 -79
  156. package/front_end/third_party/lighthouse/locales/he.json +212 -80
  157. package/front_end/third_party/lighthouse/locales/hi.json +214 -82
  158. package/front_end/third_party/lighthouse/locales/hr.json +211 -79
  159. package/front_end/third_party/lighthouse/locales/hu.json +211 -79
  160. package/front_end/third_party/lighthouse/locales/id.json +211 -79
  161. package/front_end/third_party/lighthouse/locales/it.json +211 -79
  162. package/front_end/third_party/lighthouse/locales/ja.json +211 -79
  163. package/front_end/third_party/lighthouse/locales/ko.json +211 -79
  164. package/front_end/third_party/lighthouse/locales/lt.json +211 -79
  165. package/front_end/third_party/lighthouse/locales/lv.json +214 -82
  166. package/front_end/third_party/lighthouse/locales/nl.json +211 -79
  167. package/front_end/third_party/lighthouse/locales/no.json +211 -79
  168. package/front_end/third_party/lighthouse/locales/pl.json +211 -79
  169. package/front_end/third_party/lighthouse/locales/pt-PT.json +211 -79
  170. package/front_end/third_party/lighthouse/locales/pt.json +211 -79
  171. package/front_end/third_party/lighthouse/locales/ro.json +212 -80
  172. package/front_end/third_party/lighthouse/locales/ru.json +211 -79
  173. package/front_end/third_party/lighthouse/locales/sk.json +211 -79
  174. package/front_end/third_party/lighthouse/locales/sl.json +211 -79
  175. package/front_end/third_party/lighthouse/locales/sr-Latn.json +211 -79
  176. package/front_end/third_party/lighthouse/locales/sr.json +211 -79
  177. package/front_end/third_party/lighthouse/locales/sv.json +211 -79
  178. package/front_end/third_party/lighthouse/locales/ta.json +218 -86
  179. package/front_end/third_party/lighthouse/locales/te.json +251 -119
  180. package/front_end/third_party/lighthouse/locales/th.json +211 -79
  181. package/front_end/third_party/lighthouse/locales/tr.json +211 -79
  182. package/front_end/third_party/lighthouse/locales/uk.json +212 -80
  183. package/front_end/third_party/lighthouse/locales/vi.json +211 -79
  184. package/front_end/third_party/lighthouse/locales/zh-HK.json +211 -79
  185. package/front_end/third_party/lighthouse/locales/zh-TW.json +211 -79
  186. package/front_end/third_party/lighthouse/locales/zh.json +211 -79
  187. package/front_end/third_party/lighthouse/report/bundle.d.ts +72 -34
  188. package/front_end/third_party/lighthouse/report/bundle.js +698 -492
  189. package/front_end/third_party/lighthouse/report-assets/report-generator.js +1 -2
  190. package/front_end/third_party/lighthouse/report-assets/report.js +40 -35
  191. package/front_end/third_party/lighthouse/report-assets/standalone-template.html +2 -4
  192. package/front_end/ui/components/code_highlighter/CodeHighlighter.ts +60 -68
  193. package/front_end/ui/components/data_grid/dataGrid.css +12 -10
  194. package/front_end/ui/components/docs/component_docs.ts +14 -0
  195. package/front_end/ui/components/docs/create_breadcrumbs.ts +1 -1
  196. package/front_end/ui/components/docs/css_overview/start_view.html +25 -0
  197. package/front_end/ui/components/docs/css_overview/start_view.ts +14 -0
  198. package/front_end/ui/components/docs/icon_button/basic.ts +3 -3
  199. package/front_end/ui/components/docs/toggle_dark_mode.ts +1 -0
  200. package/front_end/ui/components/docs/toggle_fonts.ts +2 -0
  201. package/front_end/ui/components/helpers/get-stylesheet.ts +0 -15
  202. package/front_end/ui/components/linear_memory_inspector/linear_memory_inspector-meta.ts +1 -2
  203. package/front_end/ui/components/markdown_view/MarkdownImagesMap.ts +1 -1
  204. package/front_end/ui/components/survey_link/SurveyLink.ts +1 -1
  205. package/front_end/ui/components/text_editor/TextEditor.ts +79 -36
  206. package/front_end/ui/components/text_editor/config.ts +42 -26
  207. package/front_end/ui/components/text_editor/javascript.ts +2 -3
  208. package/front_end/ui/components/text_editor/position.ts +17 -0
  209. package/front_end/ui/components/text_editor/text_editor.ts +1 -0
  210. package/front_end/ui/components/text_editor/theme.ts +5 -1
  211. package/front_end/ui/components/tree_outline/TreeOutline.ts +63 -8
  212. package/front_end/ui/components/tree_outline/TreeOutlineUtils.ts +8 -6
  213. package/front_end/ui/legacy/Dialog.ts +3 -1
  214. package/front_end/ui/legacy/DropTarget.ts +2 -1
  215. package/front_end/ui/legacy/EmptyWidget.ts +2 -1
  216. package/front_end/ui/legacy/FilterBar.ts +2 -1
  217. package/front_end/ui/legacy/GlassPane.ts +4 -2
  218. package/front_end/ui/legacy/Infobar.ts +5 -8
  219. package/front_end/ui/legacy/InspectorView.ts +6 -1
  220. package/front_end/ui/legacy/ListWidget.ts +2 -1
  221. package/front_end/ui/legacy/PopoverHelper.ts +2 -1
  222. package/front_end/ui/legacy/ProgressIndicator.ts +2 -1
  223. package/front_end/ui/legacy/RemoteDebuggingTerminatedScreen.ts +2 -1
  224. package/front_end/ui/legacy/ReportView.ts +2 -1
  225. package/front_end/ui/legacy/RootView.ts +2 -1
  226. package/front_end/ui/legacy/SearchableView.ts +2 -1
  227. package/front_end/ui/legacy/ShortcutRegistry.ts +11 -7
  228. package/front_end/ui/legacy/SoftContextMenu.ts +3 -2
  229. package/front_end/ui/legacy/SoftDropDown.ts +4 -2
  230. package/front_end/ui/legacy/SplitWidget.ts +2 -1
  231. package/front_end/ui/legacy/SuggestBox.ts +2 -1
  232. package/front_end/ui/legacy/TabbedPane.ts +2 -1
  233. package/front_end/ui/legacy/TargetCrashedScreen.ts +2 -1
  234. package/front_end/ui/legacy/TextPrompt.ts +2 -1
  235. package/front_end/ui/legacy/Toolbar.ts +3 -2
  236. package/front_end/ui/legacy/Treeoutline.ts +4 -3
  237. package/front_end/ui/legacy/UIUtils.ts +17 -14
  238. package/front_end/ui/legacy/ViewManager.ts +2 -1
  239. package/front_end/ui/legacy/components/inline_editor/CSSAngle.ts +1 -2
  240. package/front_end/ui/legacy/components/inline_editor/cssAngle.css +4 -0
  241. package/front_end/ui/legacy/components/object_ui/JavaScriptREPL.ts +2 -2
  242. package/front_end/ui/legacy/components/object_ui/object_ui-meta.ts +0 -4
  243. package/front_end/ui/legacy/components/perf_ui/LineLevelProfile.ts +35 -131
  244. package/front_end/ui/legacy/components/perf_ui/perf_ui-meta.ts +0 -3
  245. package/front_end/ui/legacy/components/quick_open/filteredListWidget.css +2 -2
  246. package/front_end/ui/legacy/components/quick_open/quick_open-meta.ts +2 -3
  247. package/front_end/ui/legacy/components/source_frame/BinaryResourceViewFactory.ts +3 -6
  248. package/front_end/ui/legacy/components/source_frame/FontView.ts +4 -1
  249. package/front_end/ui/legacy/components/source_frame/ImageView.ts +4 -1
  250. package/front_end/ui/legacy/components/source_frame/JSONView.ts +4 -1
  251. package/front_end/ui/legacy/components/source_frame/ResourceSourceFrame.ts +21 -15
  252. package/front_end/ui/legacy/components/source_frame/SourceFrame.ts +501 -252
  253. package/front_end/ui/legacy/components/source_frame/XMLView.ts +7 -2
  254. package/front_end/ui/legacy/components/source_frame/source_frame-legacy.ts +0 -11
  255. package/front_end/ui/legacy/components/source_frame/source_frame.ts +0 -2
  256. package/front_end/ui/legacy/components/text_editor/CodeMirrorTextEditor.ts +2 -0
  257. package/front_end/ui/legacy/components/text_editor/cmdevtools.css +3 -1
  258. package/front_end/ui/legacy/components/text_editor/module.json +0 -3
  259. package/front_end/ui/legacy/components/utils/Linkifier.ts +7 -15
  260. package/front_end/ui/legacy/radioButton.css +1 -13
  261. package/front_end/ui/legacy/textButton.css +5 -4
  262. package/front_end/ui/legacy/themeColors.css +36 -0
  263. package/front_end/ui/legacy/theme_support/theme_support_impl.ts +7 -9
  264. package/front_end/ui/legacy/utils/create-shadow-root-with-core-styles.ts +2 -2
  265. package/front_end/ui/legacy/utils/inject-core-styles.ts +7 -4
  266. package/package.json +1 -1
  267. package/scripts/check_gn.js +0 -35
  268. package/scripts/eslint_rules/lib/es_modules_import.js +15 -8
  269. package/scripts/eslint_rules/tests/es_modules_import_test.js +8 -0
  270. package/front_end/Images/radioDot-dark-theme.png +0 -0
  271. package/front_end/Images/radioDot.png +0 -0
  272. package/front_end/emulated_devices/module.json +0 -6
  273. package/front_end/panels/application/module.json +0 -6
  274. package/front_end/panels/emulation/module.json +0 -11
  275. package/front_end/panels/issues/module.json +0 -6
  276. package/front_end/panels/js_profiler/module.json +0 -5
  277. package/front_end/panels/layer_viewer/module.json +0 -5
  278. package/front_end/panels/layers/module.json +0 -5
  279. package/front_end/panels/media/module.json +0 -5
  280. package/front_end/panels/network/module.json +0 -5
  281. package/front_end/panels/profiler/module.json +0 -5
  282. package/front_end/panels/screencast/module.json +0 -6
  283. package/front_end/panels/security/module.json +0 -5
  284. package/front_end/panels/timeline/module.json +0 -7
  285. package/front_end/third_party/lighthouse/report-assets/report.css +0 -1774
  286. package/front_end/ui/legacy/components/source_frame/SourcesTextEditor.ts +0 -1030
  287. package/front_end/ui/legacy/components/source_frame/messagesPopover.css +0 -32
  288. package/front_end/ui/legacy/components/source_frame/module.json +0 -14
  289. package/front_end/ui/legacy/module.json +0 -41
@@ -33,12 +33,11 @@ import * as i18n from '../../../../core/i18n/i18n.js';
33
33
  import * as Platform from '../../../../core/platform/platform.js';
34
34
  import * as Formatter from '../../../../models/formatter/formatter.js';
35
35
  import * as TextUtils from '../../../../models/text_utils/text_utils.js';
36
- import type * as Workspace from '../../../../models/workspace/workspace.js';
36
+ import * as CodeMirror from '../../../../third_party/codemirror.next/codemirror.next.js';
37
+ import * as CodeHighlighter from '../../../components/code_highlighter/code_highlighter.js';
38
+ import * as TextEditor from '../../../components/text_editor/text_editor.js';
37
39
  import * as UI from '../../legacy.js';
38
40
 
39
- import type {SourcesTextEditorDelegate} from './SourcesTextEditor.js';
40
- import {Events, SourcesTextEditor} from './SourcesTextEditor.js';
41
-
42
41
  const UIStrings = {
43
42
  /**
44
43
  *@description Text for the source of something
@@ -85,9 +84,25 @@ const UIStrings = {
85
84
  const str_ = i18n.i18n.registerUIStrings('ui/legacy/components/source_frame/SourceFrame.ts', UIStrings);
86
85
  const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
87
86
 
88
- export class SourceFrameImpl extends UI.View.SimpleView implements UI.SearchableView.Searchable,
89
- UI.SearchableView.Replaceable,
90
- SourcesTextEditorDelegate, Transformer {
87
+ export interface SourceFrameOptions {
88
+ // Whether to show line numbers. Defaults to true.
89
+ lineNumbers?: boolean;
90
+ // Whether to wrap lines. Defaults to false.
91
+ lineWrapping?: boolean;
92
+ }
93
+
94
+ export const enum Events {
95
+ EditorUpdate = 'EditorUpdate',
96
+ EditorScroll = 'EditorScroll',
97
+ }
98
+
99
+ export type EventTypes = {
100
+ [Events.EditorUpdate]: CodeMirror.ViewUpdate,
101
+ [Events.EditorScroll]: void,
102
+ };
103
+
104
+ export class SourceFrameImpl extends Common.ObjectWrapper.eventMixin<EventTypes, typeof UI.View.SimpleView>(
105
+ UI.View.SimpleView) implements UI.SearchableView.Searchable, UI.SearchableView.Replaceable, Transformer {
91
106
  private readonly lazyContent: () => Promise<TextUtils.ContentProvider.DeferredContent>;
92
107
  private prettyInternal: boolean;
93
108
  private rawContent: string|null;
@@ -96,13 +111,14 @@ export class SourceFrameImpl extends UI.View.SimpleView implements UI.Searchable
96
111
  private readonly prettyToggle: UI.Toolbar.ToolbarToggle;
97
112
  private shouldAutoPrettyPrint: boolean;
98
113
  private readonly progressToolbarItem: UI.Toolbar.ToolbarItem;
99
- private textEditorInternal: SourcesTextEditor;
100
- private prettyCleanGeneration: number|null;
101
- private cleanGeneration: number;
114
+ private textEditorInternal: TextEditor.TextEditor.TextEditor;
115
+ private prettyBaseDoc: CodeMirror.Text|null = null;
116
+ private baseDoc: CodeMirror.Text;
117
+ private displayedSelection: CodeMirror.EditorSelection|null = null;
102
118
  private searchConfig: UI.SearchableView.SearchConfig|null;
103
119
  private delayedFindSearchMatches: (() => void)|null;
104
120
  private currentSearchResultIndex: number;
105
- private searchResults: TextUtils.TextRange.TextRange[];
121
+ private searchResults: SearchMatch[];
106
122
  private searchRegex: RegExp|null;
107
123
  private loadError: boolean;
108
124
  private muteChangeEventsForSetContent: boolean;
@@ -118,12 +134,11 @@ export class SourceFrameImpl extends UI.View.SimpleView implements UI.Searchable
118
134
  private selectionToSet: TextUtils.TextRange.TextRange|null;
119
135
  private loadedInternal: boolean;
120
136
  private contentRequested: boolean;
121
- private highlighterTypeInternal: string;
122
137
  private wasmDisassemblyInternal: Common.WasmDisassembly.WasmDisassembly|null;
123
138
  contentSet: boolean;
124
139
  constructor(
125
140
  lazyContent: () => Promise<TextUtils.ContentProvider.DeferredContent>,
126
- codeMirrorOptions?: UI.TextEditor.Options) {
141
+ private readonly options: SourceFrameOptions = {}) {
127
142
  super(i18nString(UIStrings.source));
128
143
 
129
144
  this.lazyContent = lazyContent;
@@ -141,11 +156,11 @@ export class SourceFrameImpl extends UI.View.SimpleView implements UI.Searchable
141
156
 
142
157
  this.progressToolbarItem = new UI.Toolbar.ToolbarItem(document.createElement('div'));
143
158
 
144
- this.textEditorInternal = new SourcesTextEditor(this, codeMirrorOptions);
145
- this.textEditorInternal.show(this.element);
159
+ this.textEditorInternal = new TextEditor.TextEditor.TextEditor(this.placeholderEditorState(''));
160
+ this.textEditorInternal.style.flexGrow = '1';
161
+ this.element.appendChild(this.textEditorInternal);
146
162
 
147
- this.prettyCleanGeneration = null;
148
- this.cleanGeneration = 0;
163
+ this.baseDoc = this.textEditorInternal.state.doc;
149
164
 
150
165
  this.searchConfig = null;
151
166
  this.delayedFindSearchMatches = null;
@@ -154,36 +169,109 @@ export class SourceFrameImpl extends UI.View.SimpleView implements UI.Searchable
154
169
  this.searchRegex = null;
155
170
  this.loadError = false;
156
171
 
157
- this.textEditorInternal.addEventListener(Events.EditorFocused, this.resetCurrentSearchResultIndex, this);
158
- this.textEditorInternal.addEventListener(Events.SelectionChanged, this.updateSourcePosition, this);
159
- this.textEditorInternal.addEventListener(UI.TextEditor.Events.TextChanged, event => {
160
- if (!this.muteChangeEventsForSetContent) {
161
- this.onTextChanged(event.data.oldRange, event.data.newRange);
162
- }
163
- });
164
172
  this.muteChangeEventsForSetContent = false;
165
173
 
166
174
  this.sourcePosition = new UI.Toolbar.ToolbarText();
167
175
 
168
176
  this.searchableView = null;
169
177
  this.editable = false;
170
- this.textEditorInternal.setReadOnly(true);
171
178
 
172
179
  this.positionToReveal = null;
173
180
  this.lineToScrollTo = null;
174
181
  this.selectionToSet = null;
175
182
  this.loadedInternal = false;
176
183
  this.contentRequested = false;
177
- this.highlighterTypeInternal = '';
178
184
 
179
185
  this.wasmDisassemblyInternal = null;
180
186
  this.contentSet = false;
181
187
  }
182
188
 
189
+ private placeholderEditorState(content: string): CodeMirror.EditorState {
190
+ return CodeMirror.EditorState.create({
191
+ doc: content,
192
+ extensions: [
193
+ CodeMirror.EditorState.readOnly.of(true),
194
+ this.options.lineNumbers !== false ? CodeMirror.lineNumbers() : [],
195
+ TextEditor.Config.theme(),
196
+ ],
197
+ });
198
+ }
199
+
200
+ protected editorConfiguration(doc: string): CodeMirror.Extension {
201
+ return [
202
+ CodeMirror.EditorView.updateListener.of(update => this.dispatchEventToListeners(Events.EditorUpdate, update)),
203
+ TextEditor.Config.baseConfiguration(doc),
204
+ TextEditor.Config.sourcesAutocompletion.instance(),
205
+ TextEditor.Config.showWhitespace.instance(),
206
+ TextEditor.Config.allowScrollPastEof.instance(),
207
+ TextEditor.Config.codeFolding.instance(),
208
+ TextEditor.Config.autoDetectIndent.instance(),
209
+ CodeMirror.EditorView.theme({
210
+ '&.cm-editor': {height: '100%'},
211
+ '.cm-scroller': {overflow: 'auto'},
212
+ '.cm-lineNumbers .cm-gutterElement.cm-nonBreakableLine': {color: 'var(--color-non-breakable-line)'},
213
+ '.cm-searchMatch': {
214
+ border: '1px solid var(--color-search-match-border)',
215
+ borderRadius: '3px',
216
+ margin: '0 -1px',
217
+ '&.cm-searchMatch-selected': {
218
+ borderRadius: '1px',
219
+ backgroundColor: 'var(--color-selected-search-match-background)',
220
+ borderColor: 'var(--color-selected-search-match-background)',
221
+ '&, & *': {
222
+ color: 'var(--color-selected-search-match) !important',
223
+ },
224
+ },
225
+ },
226
+ }),
227
+ CodeMirror.EditorView.domEventHandlers({
228
+ focus: () => this.onFocus(),
229
+ blur: () => this.onBlur(),
230
+ scroll: () => this.dispatchEventToListeners(Events.EditorScroll),
231
+ contextmenu: event => this.onContextMenu(event),
232
+ }),
233
+ CodeMirror.lineNumbers({
234
+ domEventHandlers:
235
+ {contextmenu: (_view, block, event) => this.onLineGutterContextMenu(block.from, event as MouseEvent)},
236
+ }),
237
+ CodeMirror.EditorView.updateListener.of(
238
+ (update):
239
+ void => {
240
+ if (update.selectionSet || update.docChanged) {
241
+ this.updateSourcePosition();
242
+ }
243
+ if (update.docChanged) {
244
+ this.onTextChanged();
245
+ }
246
+ }),
247
+ activeSearchState,
248
+ CodeMirror.Prec.lowest(searchHighlighter),
249
+ config.language.of([]),
250
+ this.wasmDisassemblyInternal ? markNonBreakableLines(this.wasmDisassemblyInternal) : nonBreakableLines,
251
+ this.options.lineWrapping ? CodeMirror.EditorView.lineWrapping : [],
252
+ this.options.lineNumbers !== false ? CodeMirror.lineNumbers() : [],
253
+ ];
254
+ }
255
+
256
+ protected onBlur(): void {
257
+ }
258
+
259
+ protected onFocus(): void {
260
+ this.resetCurrentSearchResultIndex();
261
+ }
262
+
183
263
  get wasmDisassembly(): Common.WasmDisassembly.WasmDisassembly|null {
184
264
  return this.wasmDisassemblyInternal;
185
265
  }
186
266
 
267
+ editorLocationToUILocation(lineNumber: number, columnNumber: number): {
268
+ lineNumber: number,
269
+ columnNumber: number,
270
+ };
271
+ editorLocationToUILocation(lineNumber: number): {
272
+ lineNumber: number,
273
+ columnNumber: number|undefined,
274
+ };
187
275
  editorLocationToUILocation(lineNumber: number, columnNumber?: number): {
188
276
  lineNumber: number,
189
277
  columnNumber?: number|undefined,
@@ -215,47 +303,62 @@ export class SourceFrameImpl extends UI.View.SimpleView implements UI.Searchable
215
303
  this.prettyToggle.setVisible(canPrettyPrint);
216
304
  }
217
305
 
306
+ setEditable(editable: boolean): void {
307
+ this.editable = editable;
308
+ if (this.loaded && editable !== !this.textEditor.state.readOnly) {
309
+ this.textEditor.dispatch({effects: config.editable.reconfigure(CodeMirror.EditorState.readOnly.of(!editable))});
310
+ }
311
+ }
312
+
218
313
  private async setPretty(value: boolean): Promise<void> {
219
314
  this.prettyInternal = value;
220
315
  this.prettyToggle.setEnabled(false);
221
316
 
222
317
  const wasLoaded = this.loaded;
223
- const selection = this.selection();
318
+ const {textEditor} = this;
319
+ const selection = textEditor.state.selection.main;
320
+ const startPos = textEditor.toLineColumn(selection.from), endPos = textEditor.toLineColumn(selection.to);
224
321
  let newSelection;
225
322
  if (this.prettyInternal) {
226
323
  const formatInfo = await this.requestFormattedContent();
227
324
  this.formattedMap = formatInfo.formattedMapping;
228
- this.setContent(formatInfo.formattedContent, null);
229
- this.prettyCleanGeneration = this.textEditorInternal.markClean();
230
- const start = this.rawToPrettyLocation(selection.startLine, selection.startColumn);
231
- const end = this.rawToPrettyLocation(selection.endLine, selection.endColumn);
232
- newSelection = new TextUtils.TextRange.TextRange(start[0], start[1], end[0], end[1]);
325
+ await this.setContent(formatInfo.formattedContent);
326
+ this.prettyBaseDoc = textEditor.state.doc;
327
+ const start = this.rawToPrettyLocation(startPos.lineNumber, startPos.columnNumber);
328
+ const end = this.rawToPrettyLocation(endPos.lineNumber, endPos.columnNumber);
329
+ newSelection = textEditor.createSelection(
330
+ {lineNumber: start[0], columnNumber: start[1]}, {lineNumber: end[0], columnNumber: end[1]});
233
331
  } else {
234
- this.setContent(this.rawContent, null);
235
- this.cleanGeneration = this.textEditorInternal.markClean();
236
- const start = this.prettyToRawLocation(selection.startLine, selection.startColumn);
237
- const end = this.prettyToRawLocation(selection.endLine, selection.endColumn);
238
- newSelection = new TextUtils.TextRange.TextRange(start[0], start[1], end[0], end[1]);
332
+ await this.setContent(this.rawContent || '');
333
+ this.baseDoc = textEditor.state.doc;
334
+ const start = this.prettyToRawLocation(startPos.lineNumber, startPos.columnNumber);
335
+ const end = this.prettyToRawLocation(endPos.lineNumber, endPos.columnNumber);
336
+ newSelection = textEditor.createSelection(
337
+ {lineNumber: start[0], columnNumber: start[1]}, {lineNumber: end[0], columnNumber: end[1]});
239
338
  }
240
339
  if (wasLoaded) {
241
- this.textEditor.revealPosition(newSelection.endLine, newSelection.endColumn, this.editable);
242
- this.textEditor.setSelection(newSelection);
340
+ textEditor.revealPosition(newSelection, false);
243
341
  }
244
342
  this.prettyToggle.setEnabled(true);
245
343
  this.updatePrettyPrintState();
246
344
  }
247
345
 
248
- private updateLineNumberFormatter(): void {
346
+ private getLineNumberFormatter(): CodeMirror.Extension {
347
+ if (this.options.lineNumbers === false) {
348
+ return [];
349
+ }
350
+ let formatNumber = null;
249
351
  if (this.wasmDisassemblyInternal) {
250
352
  const disassembly = this.wasmDisassemblyInternal;
251
353
  const lastBytecodeOffset = disassembly.lineNumberToBytecodeOffset(disassembly.lineNumbers - 1);
252
354
  const bytecodeOffsetDigits = lastBytecodeOffset.toString(16).length + 1;
253
- this.textEditorInternal.setLineNumberFormatter(lineNumber => {
254
- const bytecodeOffset = disassembly.lineNumberToBytecodeOffset(lineNumber - 1);
355
+ formatNumber = (lineNumber: number): string => {
356
+ const bytecodeOffset =
357
+ disassembly.lineNumberToBytecodeOffset(Math.min(disassembly.lineNumbers, lineNumber) - 1);
255
358
  return `0x${bytecodeOffset.toString(16).padStart(bytecodeOffsetDigits, '0')}`;
256
- });
359
+ };
257
360
  } else if (this.prettyInternal) {
258
- this.textEditorInternal.setLineNumberFormatter(lineNumber => {
361
+ formatNumber = (lineNumber: number): string => {
259
362
  const line = this.prettyToRawLocation(lineNumber - 1, 0)[0] + 1;
260
363
  if (lineNumber === 1) {
261
364
  return String(line);
@@ -264,17 +367,18 @@ export class SourceFrameImpl extends UI.View.SimpleView implements UI.Searchable
264
367
  return String(line);
265
368
  }
266
369
  return '-';
267
- });
268
- } else {
269
- this.textEditorInternal.setLineNumberFormatter(lineNumber => {
270
- return String(lineNumber);
271
- });
370
+ };
272
371
  }
372
+ return formatNumber ? CodeMirror.lineNumbers({formatNumber}) : [];
373
+ }
374
+
375
+ private updateLineNumberFormatter(): void {
376
+ this.textEditor.dispatch({effects: config.lineNumbers.reconfigure(this.getLineNumberFormatter())});
273
377
  }
274
378
 
275
379
  private updatePrettyPrintState(): void {
276
380
  this.prettyToggle.setToggled(this.prettyInternal);
277
- this.textEditorInternal.element.classList.toggle('pretty-printed', this.prettyInternal);
381
+ this.textEditorInternal.classList.toggle('pretty-printed', this.prettyInternal);
278
382
  this.updateLineNumberFormatter();
279
383
  }
280
384
 
@@ -292,13 +396,6 @@ export class SourceFrameImpl extends UI.View.SimpleView implements UI.Searchable
292
396
  return this.formattedMap.originalToFormatted(line, column);
293
397
  }
294
398
 
295
- setEditable(editable: boolean): void {
296
- this.editable = editable;
297
- if (this.loadedInternal) {
298
- this.textEditorInternal.setReadOnly(!editable);
299
- }
300
- }
301
-
302
399
  hasLoadError(): boolean {
303
400
  return this.loadError;
304
401
  }
@@ -322,7 +419,7 @@ export class SourceFrameImpl extends UI.View.SimpleView implements UI.Searchable
322
419
  return this.loadedInternal;
323
420
  }
324
421
 
325
- get textEditor(): SourcesTextEditor {
422
+ get textEditor(): TextEditor.TextEditor.TextEditor {
326
423
  return this.textEditorInternal;
327
424
  }
328
425
 
@@ -330,6 +427,14 @@ export class SourceFrameImpl extends UI.View.SimpleView implements UI.Searchable
330
427
  return this.prettyInternal;
331
428
  }
332
429
 
430
+ get contentType(): string {
431
+ return this.loadError ? '' : this.getContentType();
432
+ }
433
+
434
+ protected getContentType(): string {
435
+ return '';
436
+ }
437
+
333
438
  private async ensureContentLoaded(): Promise<void> {
334
439
  if (!this.contentRequested) {
335
440
  this.contentRequested = true;
@@ -351,7 +456,7 @@ export class SourceFrameImpl extends UI.View.SimpleView implements UI.Searchable
351
456
 
352
457
  progressIndicator.setWorked(1);
353
458
 
354
- if (!error && this.highlighterTypeInternal === 'application/wasm') {
459
+ if (!error && this.contentType === 'application/wasm') {
355
460
  const worker = Common.Worker.WorkerWrapper.fromURL(
356
461
  new URL('../../../../entrypoints/wasmparser_worker/wasmparser_worker-entrypoint.js', import.meta.url));
357
462
  const promise = new Promise<{
@@ -407,24 +512,14 @@ export class SourceFrameImpl extends UI.View.SimpleView implements UI.Searchable
407
512
  this.prettyToggle.setEnabled(true);
408
513
 
409
514
  if (error) {
410
- this.setContent(null, error);
515
+ this.loadError = true;
516
+ this.textEditor.editor.setState(this.placeholderEditorState(error));
411
517
  this.prettyToggle.setEnabled(false);
412
-
413
- // Occasionally on load, there can be a race in which it appears the CodeMirror plugin
414
- // runs the highlighter type assignment out of order. In case of an error then, set
415
- // the highlighter type after a short delay. This appears to only occur the first
416
- // time that CodeMirror is initialized, likely because the highlighter type was first
417
- // initialized based on the file type, and the syntax highlighting is in a race
418
- // with the new highlighter assignment. As the option is just an option and is not
419
- // observable, we can't handle waiting for it here.
420
- // https://github.com/codemirror/CodeMirror/issues/6019
421
- // CRBug 1011445
422
- setTimeout(() => this.setHighlighterType('text/plain'), 50);
423
518
  } else {
424
519
  if (this.shouldAutoPrettyPrint && TextUtils.TextUtils.isMinified(content)) {
425
520
  await this.setPretty(true);
426
521
  } else {
427
- this.setContent(this.rawContent, null);
522
+ await this.setContent(this.rawContent || '');
428
523
  }
429
524
  }
430
525
  this.contentSet = true;
@@ -436,14 +531,28 @@ export class SourceFrameImpl extends UI.View.SimpleView implements UI.Searchable
436
531
  return this.formattedContentPromise;
437
532
  }
438
533
  this.formattedContentPromise =
439
- Formatter.ScriptFormatter.formatScriptContent(this.highlighterTypeInternal, this.rawContent || '');
534
+ Formatter.ScriptFormatter.formatScriptContent(this.contentType, this.rawContent || '');
440
535
  return this.formattedContentPromise;
441
536
  }
442
537
 
443
- revealPosition(line: number, column?: number, shouldHighlight?: boolean): void {
538
+ revealPosition(position: {lineNumber: number, columnNumber?: number}|number, shouldHighlight?: boolean): void {
444
539
  this.lineToScrollTo = null;
445
540
  this.selectionToSet = null;
446
- this.positionToReveal = {line: line, column: column, shouldHighlight: shouldHighlight};
541
+ let line = 0, column = 0;
542
+ if (typeof position === 'number') {
543
+ const {doc} = this.textEditor.state;
544
+ if (position > doc.length) {
545
+ line = doc.lines - 1;
546
+ } else if (position >= 0) {
547
+ const lineObj = doc.lineAt(position);
548
+ line = lineObj.number - 1;
549
+ column = position - lineObj.from;
550
+ }
551
+ } else {
552
+ line = position.lineNumber;
553
+ column = position.columnNumber ?? 0;
554
+ }
555
+ this.positionToReveal = {line, column, shouldHighlight: shouldHighlight};
447
556
  this.innerRevealPositionIfNeeded();
448
557
  }
449
558
 
@@ -456,15 +565,14 @@ export class SourceFrameImpl extends UI.View.SimpleView implements UI.Searchable
456
565
  return;
457
566
  }
458
567
 
459
- const {lineNumber, columnNumber} =
460
- this.uiLocationToEditorLocation(this.positionToReveal.line, this.positionToReveal.column);
568
+ const location = this.uiLocationToEditorLocation(this.positionToReveal.line, this.positionToReveal.column);
461
569
 
462
- this.textEditorInternal.revealPosition(lineNumber, columnNumber, this.positionToReveal.shouldHighlight);
570
+ const {textEditor} = this;
571
+ textEditor.revealPosition(textEditor.createSelection(location), this.positionToReveal.shouldHighlight);
463
572
  this.positionToReveal = null;
464
573
  }
465
574
 
466
575
  private clearPositionToReveal(): void {
467
- this.textEditorInternal.clearPositionHighlight();
468
576
  this.positionToReveal = null;
469
577
  }
470
578
 
@@ -477,24 +585,28 @@ export class SourceFrameImpl extends UI.View.SimpleView implements UI.Searchable
477
585
  private innerScrollToLineIfNeeded(): void {
478
586
  if (this.lineToScrollTo !== null) {
479
587
  if (this.loaded && this.isShowing()) {
480
- this.textEditorInternal.scrollToLine(this.lineToScrollTo);
588
+ const {textEditor} = this;
589
+ const position = textEditor.toOffset({lineNumber: this.lineToScrollTo, columnNumber: 0});
590
+ textEditor.dispatch({effects: CodeMirror.EditorView.scrollTo.of(CodeMirror.EditorSelection.cursor(position))});
481
591
  this.lineToScrollTo = null;
482
592
  }
483
593
  }
484
594
  }
485
595
 
486
- selection(): TextUtils.TextRange.TextRange {
487
- return this.textEditor.selection();
488
- }
489
-
490
596
  setSelection(textRange: TextUtils.TextRange.TextRange): void {
491
597
  this.selectionToSet = textRange;
492
598
  this.innerSetSelectionIfNeeded();
493
599
  }
494
600
 
495
601
  private innerSetSelectionIfNeeded(): void {
496
- if (this.selectionToSet && this.loaded && this.isShowing()) {
497
- this.textEditorInternal.setSelection(this.selectionToSet, true);
602
+ const sel = this.selectionToSet;
603
+ if (sel && this.loaded && this.isShowing()) {
604
+ const {textEditor} = this;
605
+ textEditor.dispatch({
606
+ selection: textEditor.createSelection(
607
+ {lineNumber: sel.startLine, columnNumber: sel.startColumn},
608
+ {lineNumber: sel.endLine, columnNumber: sel.endColumn}),
609
+ });
498
610
  this.selectionToSet = null;
499
611
  }
500
612
  }
@@ -505,9 +617,9 @@ export class SourceFrameImpl extends UI.View.SimpleView implements UI.Searchable
505
617
  this.innerScrollToLineIfNeeded();
506
618
  }
507
619
 
508
- onTextChanged(_oldRange: TextUtils.TextRange.TextRange, _newRange: TextUtils.TextRange.TextRange): void {
620
+ onTextChanged(): void {
509
621
  const wasPretty = this.pretty;
510
- this.prettyInternal = this.prettyCleanGeneration !== null && this.textEditor.isClean(this.prettyCleanGeneration);
622
+ this.prettyInternal = Boolean(this.prettyBaseDoc && this.textEditor.state.doc.eq(this.prettyBaseDoc));
511
623
  if (this.prettyInternal !== wasPretty) {
512
624
  this.updatePrettyPrintState();
513
625
  }
@@ -519,14 +631,14 @@ export class SourceFrameImpl extends UI.View.SimpleView implements UI.Searchable
519
631
  }
520
632
 
521
633
  isClean(): boolean {
522
- return this.textEditor.isClean(this.cleanGeneration) ||
523
- (this.prettyCleanGeneration !== null && this.textEditor.isClean(this.prettyCleanGeneration));
634
+ return this.textEditor.state.doc.eq(this.baseDoc) ||
635
+ (this.prettyBaseDoc !== null && this.textEditor.state.doc.eq(this.prettyBaseDoc));
524
636
  }
525
637
 
526
638
  contentCommitted(): void {
527
- this.cleanGeneration = this.textEditorInternal.markClean();
528
- this.prettyCleanGeneration = null;
529
- this.rawContent = this.textEditor.text();
639
+ this.baseDoc = this.textEditorInternal.state.doc;
640
+ this.prettyBaseDoc = null;
641
+ this.rawContent = this.textEditor.state.doc.toString();
530
642
  this.formattedMap = null;
531
643
  this.formattedContentPromise = null;
532
644
  if (this.prettyInternal) {
@@ -562,52 +674,49 @@ export class SourceFrameImpl extends UI.View.SimpleView implements UI.Searchable
562
674
  return mimeType;
563
675
  }
564
676
 
565
- setHighlighterType(highlighterType: string): void {
566
- this.highlighterTypeInternal = highlighterType;
567
- this.updateHighlighterType('');
568
- }
569
-
570
- highlighterType(): string {
571
- return this.highlighterTypeInternal;
677
+ protected async getLanguageSupport(content: string): Promise<CodeMirror.Extension> {
678
+ const mimeType = this.simplifyMimeType(content, this.contentType) || '';
679
+ const languageDesc = await CodeHighlighter.CodeHighlighter.languageFromMIME(mimeType);
680
+ if (!languageDesc) {
681
+ return [];
682
+ }
683
+ if (mimeType === 'text/jsx') {
684
+ return [
685
+ languageDesc,
686
+ CodeMirror.javascript.javascriptLanguage.data.of({autocomplete: CodeMirror.completeAnyWord}),
687
+ ];
688
+ }
689
+ return languageDesc;
572
690
  }
573
691
 
574
- private updateHighlighterType(content: string): void {
575
- this.textEditorInternal.setMimeType(this.simplifyMimeType(content, this.highlighterTypeInternal));
692
+ async updateLanguageMode(content: string): Promise<void> {
693
+ const langExtension = await this.getLanguageSupport(content);
694
+ this.textEditor.dispatch({effects: config.language.reconfigure(langExtension)});
576
695
  }
577
696
 
578
- setContent(content: string|null, loadError: string|null): void {
697
+ async setContent(content: string): Promise<void> {
579
698
  this.muteChangeEventsForSetContent = true;
580
- if (!this.loadedInternal) {
581
- this.loadedInternal = true;
582
- if (!loadError) {
583
- this.textEditorInternal.setText(content || '');
584
- this.cleanGeneration = this.textEditorInternal.markClean();
585
- this.textEditorInternal.setReadOnly(!this.editable);
586
- this.loadError = false;
587
- } else {
588
- this.textEditorInternal.setText(loadError || '');
589
- this.highlighterTypeInternal = 'text/plain';
590
- this.textEditorInternal.setReadOnly(true);
591
- this.loadError = true;
592
- }
593
- } else {
594
- const scrollTop = this.textEditorInternal.scrollTop();
595
- const selection = this.textEditorInternal.selection();
596
- this.textEditorInternal.setText(content || '');
597
- this.textEditorInternal.setScrollTop(scrollTop);
598
- this.textEditorInternal.setSelection(selection);
599
- }
600
-
601
- // Mark non-breakable lines in the Wasm disassembly after setting
602
- // up the content for the text editor (which creates the gutter).
603
- if (this.wasmDisassemblyInternal) {
604
- for (const lineNumber of this.wasmDisassemblyInternal.nonBreakableLineNumbers()) {
605
- this.textEditorInternal.toggleLineClass(lineNumber, 'cm-non-breakable-line', true);
606
- }
699
+ const {textEditor} = this;
700
+ const wasLoaded = this.loadedInternal;
701
+ const scrollTop = textEditor.editor.scrollDOM.scrollTop;
702
+ this.loadedInternal = true;
703
+
704
+ const languageSupport = await this.getLanguageSupport(content);
705
+ const editorState = CodeMirror.EditorState.create({
706
+ doc: content,
707
+ extensions: [
708
+ this.editorConfiguration(content),
709
+ languageSupport,
710
+ config.lineNumbers.of(this.getLineNumberFormatter()),
711
+ config.editable.of(this.editable ? [] : CodeMirror.EditorState.readOnly.of(true)),
712
+ ],
713
+ });
714
+ this.baseDoc = editorState.doc;
715
+ textEditor.editor.setState(editorState);
716
+ if (wasLoaded) {
717
+ textEditor.editor.scrollDOM.scrollTop = scrollTop;
607
718
  }
608
-
609
- this.updateLineNumberFormatter();
610
- this.updateHighlighterType(content || '');
719
+ this.editorInitialized();
611
720
  this.wasShownOrLoaded();
612
721
 
613
722
  if (this.delayedFindSearchMatches) {
@@ -617,6 +726,9 @@ export class SourceFrameImpl extends UI.View.SimpleView implements UI.Searchable
617
726
  this.muteChangeEventsForSetContent = false;
618
727
  }
619
728
 
729
+ protected editorInitialized(): void {
730
+ }
731
+
620
732
  setSearchableView(view: UI.SearchableView.SearchableView|null): void {
621
733
  this.searchableView = view;
622
734
  }
@@ -624,24 +736,25 @@ export class SourceFrameImpl extends UI.View.SimpleView implements UI.Searchable
624
736
  private doFindSearchMatches(
625
737
  searchConfig: UI.SearchableView.SearchConfig, shouldJump: boolean, jumpBackwards: boolean): void {
626
738
  this.currentSearchResultIndex = -1;
627
- this.searchResults = [];
628
739
 
629
- const regex = searchConfig.toSearchRegex();
630
- this.searchRegex = regex;
631
- this.searchResults = this.collectRegexMatches(regex);
740
+ this.searchRegex = searchConfig.toSearchRegex(true);
741
+ this.searchResults = this.collectRegexMatches(this.searchRegex);
632
742
 
633
743
  if (this.searchableView) {
634
744
  this.searchableView.updateSearchMatchesCount(this.searchResults.length);
635
745
  }
636
746
 
747
+ const editor = this.textEditor;
637
748
  if (!this.searchResults.length) {
638
- this.textEditorInternal.cancelSearchResultsHighlight();
749
+ if (editor.state.field(activeSearchState)) {
750
+ editor.dispatch({effects: setActiveSearch.of(null)});
751
+ }
639
752
  } else if (shouldJump && jumpBackwards) {
640
753
  this.jumpToPreviousSearchResult();
641
754
  } else if (shouldJump) {
642
755
  this.jumpToNextSearchResult();
643
756
  } else {
644
- this.textEditorInternal.highlightSearchResults(regex, null);
757
+ editor.dispatch({effects: setActiveSearch.of(new ActiveSearch(this.searchRegex, null))});
645
758
  }
646
759
  }
647
760
 
@@ -670,7 +783,11 @@ export class SourceFrameImpl extends UI.View.SimpleView implements UI.Searchable
670
783
  if (this.searchableView) {
671
784
  this.searchableView.updateCurrentMatchIndex(this.currentSearchResultIndex);
672
785
  }
673
- this.textEditorInternal.highlightSearchResults((this.searchRegex as RegExp), null);
786
+ const editor = this.textEditor;
787
+ const currentActiveSearch = editor.state.field(activeSearchState);
788
+ if (currentActiveSearch && currentActiveSearch.currentRange) {
789
+ editor.dispatch({effects: setActiveSearch.of(new ActiveSearch(currentActiveSearch.regexp, null))});
790
+ }
674
791
  }
675
792
 
676
793
  private resetSearch(): void {
@@ -687,10 +804,13 @@ export class SourceFrameImpl extends UI.View.SimpleView implements UI.Searchable
687
804
  if (!this.loaded) {
688
805
  return;
689
806
  }
690
- this.textEditorInternal.cancelSearchResultsHighlight();
691
- if (range) {
692
- this.setSelection(range);
693
- }
807
+ const editor = this.textEditor;
808
+ editor.dispatch({
809
+ effects: setActiveSearch.of(null),
810
+ selection: range ? {anchor: range.from, head: range.to} : undefined,
811
+ scrollIntoView: true,
812
+ userEvent: 'select.search.cancel',
813
+ });
694
814
  }
695
815
 
696
816
  jumpToLastSearchResult(): void {
@@ -699,8 +819,7 @@ export class SourceFrameImpl extends UI.View.SimpleView implements UI.Searchable
699
819
 
700
820
  private searchResultIndexForCurrentSelection(): number {
701
821
  return Platform.ArrayUtilities.lowerBound(
702
- this.searchResults, this.textEditorInternal.selection().collapseToEnd(),
703
- TextUtils.TextRange.TextRange.comparator);
822
+ this.searchResults, this.textEditor.state.selection.main, (a, b): number => a.to - b.to);
704
823
  }
705
824
 
706
825
  jumpToNextSearchResult(): void {
@@ -730,8 +849,14 @@ export class SourceFrameImpl extends UI.View.SimpleView implements UI.Searchable
730
849
  if (this.searchableView) {
731
850
  this.searchableView.updateCurrentMatchIndex(this.currentSearchResultIndex);
732
851
  }
733
- this.textEditorInternal.highlightSearchResults(
734
- (this.searchRegex as RegExp), this.searchResults[this.currentSearchResultIndex]);
852
+ const editor = this.textEditor;
853
+ const range = this.searchResults[this.currentSearchResultIndex];
854
+ editor.dispatch({
855
+ effects: setActiveSearch.of(new ActiveSearch(this.searchRegex as RegExp, range)),
856
+ selection: {anchor: range.from, head: range.to},
857
+ scrollIntoView: true,
858
+ userEvent: 'select.search',
859
+ });
735
860
  }
736
861
 
737
862
  replaceSelectionWith(searchConfig: UI.SearchableView.SearchConfig, replacement: string): void {
@@ -739,146 +864,153 @@ export class SourceFrameImpl extends UI.View.SimpleView implements UI.Searchable
739
864
  if (!range) {
740
865
  return;
741
866
  }
742
- this.textEditorInternal.highlightSearchResults((this.searchRegex as RegExp), null);
743
-
744
- const oldText = this.textEditorInternal.text(range);
745
- const regex = searchConfig.toSearchRegex();
746
- let text;
747
- if (regex.__fromRegExpQuery) {
748
- text = oldText.replace(regex, replacement);
749
- } else {
750
- text = oldText.replace(regex, function() {
751
- return replacement;
752
- });
753
- }
754
867
 
755
- const newRange = this.textEditorInternal.editRange(range, text);
756
- this.textEditorInternal.setSelection(newRange.collapseToEnd());
868
+ const insert = (this.searchRegex as RegExp).__fromRegExpQuery ? range.insertPlaceholders(replacement) : replacement;
869
+ const editor = this.textEditor;
870
+ const changes = editor.state.changes({from: range.from, to: range.to, insert});
871
+ editor.dispatch(
872
+ {changes, selection: {anchor: changes.mapPos(editor.state.selection.main.to, 1)}, userEvent: 'input.replace'});
757
873
  }
758
874
 
759
875
  replaceAllWith(searchConfig: UI.SearchableView.SearchConfig, replacement: string): void {
760
876
  this.resetCurrentSearchResultIndex();
761
877
 
762
- let text = this.textEditorInternal.text();
763
- const range = this.textEditorInternal.fullRange();
764
-
765
878
  const regex = searchConfig.toSearchRegex(true);
766
- if (regex.__fromRegExpQuery) {
767
- text = text.replace(regex, replacement);
768
- } else {
769
- text = text.replace(regex, function() {
770
- return replacement;
771
- });
772
- }
773
-
774
879
  const ranges = this.collectRegexMatches(regex);
775
880
  if (!ranges.length) {
776
881
  return;
777
882
  }
778
883
 
779
- // Calculate the position of the end of the last range to be edited.
780
- const currentRangeIndex = Platform.ArrayUtilities.lowerBound(
781
- ranges, this.textEditorInternal.selection(), TextUtils.TextRange.TextRange.comparator);
782
- const lastRangeIndex = Platform.NumberUtilities.mod(currentRangeIndex - 1, ranges.length);
783
- const lastRange = ranges[lastRangeIndex];
784
- const replacementLineEndings = Platform.StringUtilities.findLineEndingIndexes(replacement);
785
- const replacementLineCount = replacementLineEndings.length;
786
- const lastLineNumber = lastRange.startLine + replacementLineEndings.length - 1;
787
- let lastColumnNumber: number = lastRange.startColumn;
788
- if (replacementLineEndings.length > 1) {
789
- lastColumnNumber =
790
- replacementLineEndings[replacementLineCount - 1] - replacementLineEndings[replacementLineCount - 2] - 1;
791
- }
884
+ const isRegExp = regex.__fromRegExpQuery;
885
+ const changes = ranges.map(
886
+ match =>
887
+ ({from: match.from, to: match.to, insert: isRegExp ? match.insertPlaceholders(replacement) : replacement}));
792
888
 
793
- this.textEditorInternal.editRange(range, text);
794
- this.textEditorInternal.revealPosition(lastLineNumber, lastColumnNumber);
795
- this.textEditorInternal.setSelection(
796
- TextUtils.TextRange.TextRange.createFromLocation(lastLineNumber, lastColumnNumber));
889
+ this.textEditor.dispatch({changes, scrollIntoView: true, userEvent: 'input.replace.all'});
797
890
  }
798
891
 
799
- private collectRegexMatches(regexObject: RegExp): TextUtils.TextRange.TextRange[] {
892
+ private collectRegexMatches(regexObject: RegExp): SearchMatch[] {
800
893
  const ranges = [];
801
- for (let i = 0; i < this.textEditorInternal.linesCount; ++i) {
802
- let line = this.textEditorInternal.line(i);
803
- let offset = 0;
804
- let match;
805
- do {
806
- match = regexObject.exec(line);
807
- if (match) {
808
- const matchEndIndex = match.index + Math.max(match[0].length, 1);
809
- if (match[0].length) {
810
- ranges.push(new TextUtils.TextRange.TextRange(i, offset + match.index, i, offset + matchEndIndex));
811
- }
812
- offset += matchEndIndex;
813
- line = line.substring(matchEndIndex);
894
+ let pos = 0;
895
+ for (const line of this.textEditor.state.doc.iterLines()) {
896
+ regexObject.lastIndex = 0;
897
+ for (;;) {
898
+ const match = regexObject.exec(line);
899
+ if (!match) {
900
+ break;
814
901
  }
815
- } while (match && line);
902
+ if (match[0].length) {
903
+ const from = pos + match.index;
904
+ ranges.push(new SearchMatch(from, from + match[0].length, match));
905
+ }
906
+ }
907
+ pos += line.length + 1;
816
908
  }
817
909
  return ranges;
818
910
  }
819
911
 
820
- populateLineGutterContextMenu(_contextMenu: UI.ContextMenu.ContextMenu, _editorLineNumber: number): Promise<void> {
821
- return Promise.resolve();
822
- }
823
-
824
- populateTextAreaContextMenu(
825
- _contextMenu: UI.ContextMenu.ContextMenu, _editorLineNumber: number, _editorColumnNumber: number): Promise<void> {
826
- return Promise.resolve();
827
- }
828
-
829
912
  canEditSource(): boolean {
830
913
  return this.editable;
831
914
  }
832
915
 
833
916
  private updateSourcePosition(): void {
834
- const selections = this.textEditorInternal.selections();
835
- if (!selections.length) {
917
+ const {textEditor} = this, {state} = textEditor, {selection} = state;
918
+ if (this.displayedSelection?.eq(selection)) {
836
919
  return;
837
920
  }
838
- if (selections.length > 1) {
839
- this.sourcePosition.setText(i18nString(UIStrings.dSelectionRegions, {PH1: selections.length}));
921
+ this.displayedSelection = selection;
922
+
923
+ if (selection.ranges.length > 1) {
924
+ this.sourcePosition.setText(i18nString(UIStrings.dSelectionRegions, {PH1: selection.ranges.length}));
840
925
  return;
841
926
  }
842
- let textRange: TextUtils.TextRange.TextRange = selections[0];
843
- if (textRange.isEmpty()) {
844
- const location = this.prettyToRawLocation(textRange.endLine, textRange.endColumn);
927
+ const {main} = state.selection;
928
+ if (main.empty) {
929
+ const {lineNumber, columnNumber} = textEditor.toLineColumn(main.head);
930
+ const location = this.prettyToRawLocation(lineNumber, columnNumber);
845
931
  if (this.wasmDisassemblyInternal) {
846
932
  const disassembly = this.wasmDisassemblyInternal;
847
933
  const lastBytecodeOffset = disassembly.lineNumberToBytecodeOffset(disassembly.lineNumbers - 1);
848
934
  const bytecodeOffsetDigits = lastBytecodeOffset.toString(16).length;
849
935
  const bytecodeOffset = disassembly.lineNumberToBytecodeOffset(location[0]);
850
-
851
936
  this.sourcePosition.setText(i18nString(
852
937
  UIStrings.bytecodePositionXs, {PH1: bytecodeOffset.toString(16).padStart(bytecodeOffsetDigits, '0')}));
853
938
  } else {
854
- if (!this.canEditSource()) {
855
- this.textEditorInternal.revealPosition(textRange.endLine, textRange.endColumn, true);
856
- }
857
939
  this.sourcePosition.setText(i18nString(UIStrings.lineSColumnS, {PH1: location[0] + 1, PH2: location[1] + 1}));
858
940
  }
859
- return;
860
- }
861
- textRange = textRange.normalize();
862
-
863
- const selectedText = this.textEditorInternal.text(textRange);
864
- if (textRange.startLine === textRange.endLine) {
865
- this.sourcePosition.setText(i18nString(UIStrings.dCharactersSelected, {PH1: selectedText.length}));
866
941
  } else {
867
- this.sourcePosition.setText(i18nString(
868
- UIStrings.dLinesDCharactersSelected,
869
- {PH1: textRange.endLine - textRange.startLine + 1, PH2: selectedText.length}));
942
+ const startLine = state.doc.lineAt(main.from), endLine = state.doc.lineAt(main.to);
943
+ if (startLine.number === endLine.number) {
944
+ this.sourcePosition.setText(i18nString(UIStrings.dCharactersSelected, {PH1: main.to - main.from}));
945
+ } else {
946
+ this.sourcePosition.setText(i18nString(
947
+ UIStrings.dLinesDCharactersSelected,
948
+ {PH1: endLine.number - startLine.number + 1, PH2: main.to - main.from}));
949
+ }
870
950
  }
871
951
  }
952
+
953
+ onContextMenu(event: MouseEvent): boolean {
954
+ event.consume(true); // Consume event now to prevent document from handling the async menu
955
+ const contextMenu = new UI.ContextMenu.ContextMenu(event);
956
+ const {state} = this.textEditor;
957
+ const pos = state.selection.main.from, line = state.doc.lineAt(pos);
958
+ this.populateTextAreaContextMenu(contextMenu, line.number - 1, pos - line.from);
959
+ contextMenu.appendApplicableItems(this);
960
+ contextMenu.show();
961
+ return true;
962
+ }
963
+
964
+ protected populateTextAreaContextMenu(_menu: UI.ContextMenu.ContextMenu, _lineNumber: number, _columnNumber: number):
965
+ void {
966
+ }
967
+
968
+ onLineGutterContextMenu(position: number, event: MouseEvent): boolean {
969
+ event.consume(true); // Consume event now to prevent document from handling the async menu
970
+ const contextMenu = new UI.ContextMenu.ContextMenu(event);
971
+ const lineNumber = this.textEditor.state.doc.lineAt(position).number - 1;
972
+ this.populateLineGutterContextMenu(contextMenu, lineNumber);
973
+ contextMenu.appendApplicableItems(this);
974
+ contextMenu.show();
975
+ return true;
976
+ }
977
+
978
+ protected populateLineGutterContextMenu(_menu: UI.ContextMenu.ContextMenu, _lineNumber: number): void {
979
+ }
980
+
981
+ focus(): void {
982
+ this.textEditor.focus();
983
+ }
872
984
  }
873
985
 
874
- export interface LineDecorator {
875
- decorate(uiSourceCode: Workspace.UISourceCode.UISourceCode, textEditor: SourcesTextEditor, type: string): void;
986
+ class SearchMatch {
987
+ constructor(readonly from: number, readonly to: number, readonly match: RegExpMatchArray) {
988
+ }
989
+
990
+ insertPlaceholders(replacement: string): string {
991
+ return replacement.replace(/\$(\$|&|\d+|<[^>]+>)/g, (_, selector): string => {
992
+ if (selector === '$') {
993
+ return '$';
994
+ }
995
+ if (selector === '&') {
996
+ return this.match[0];
997
+ }
998
+ if (selector[0] === '<') {
999
+ return (this.match.groups && this.match.groups[selector.slice(1, selector.length - 1)]) || '';
1000
+ }
1001
+ return this.match[Number.parseInt(selector, 10)] || '';
1002
+ });
1003
+ }
876
1004
  }
877
1005
 
878
1006
  export interface Transformer {
879
- editorLocationToUILocation(lineNumber: number, columnNumber?: number): {
1007
+ editorLocationToUILocation(lineNumber: number, columnNumber: number): {
880
1008
  lineNumber: number,
881
- columnNumber?: number|undefined,
1009
+ columnNumber: number,
1010
+ };
1011
+ editorLocationToUILocation(lineNumber: number): {
1012
+ lineNumber: number,
1013
+ columnNumber: number|undefined,
882
1014
  };
883
1015
 
884
1016
  uiLocationToEditorLocation(lineNumber: number, columnNumber?: number): {
@@ -887,16 +1019,6 @@ export interface Transformer {
887
1019
  };
888
1020
  }
889
1021
 
890
- const registeredLineDecorators: LineDecoratorRegistration[] = [];
891
-
892
- export function registerLineDecorator(registration: LineDecoratorRegistration): void {
893
- registeredLineDecorators.push(registration);
894
- }
895
-
896
- export function getRegisteredLineDecorators(): LineDecoratorRegistration[] {
897
- return registeredLineDecorators;
898
- }
899
-
900
1022
  // TODO(crbug.com/1167717): Make this a const enum again
901
1023
  // eslint-disable-next-line rulesdir/const_enum
902
1024
  export enum DecoratorType {
@@ -905,7 +1027,134 @@ export enum DecoratorType {
905
1027
  COVERAGE = 'coverage',
906
1028
  }
907
1029
 
908
- export interface LineDecoratorRegistration {
909
- lineDecorator: () => LineDecorator;
910
- decoratorType: DecoratorType;
1030
+ const config = {
1031
+ editable: new CodeMirror.Compartment(),
1032
+ language: new CodeMirror.Compartment(),
1033
+ lineNumbers: new CodeMirror.Compartment(),
1034
+ };
1035
+
1036
+ class ActiveSearch {
1037
+ constructor(readonly regexp: RegExp, readonly currentRange: {from: number, to: number}|null) {
1038
+ }
1039
+
1040
+ map(change: CodeMirror.ChangeDesc): ActiveSearch {
1041
+ return change.empty || !this.currentRange ?
1042
+ this :
1043
+ new ActiveSearch(
1044
+ this.regexp, {from: change.mapPos(this.currentRange.from), to: change.mapPos(this.currentRange.to)});
1045
+ }
1046
+
1047
+ static eq(a: ActiveSearch|null, b: ActiveSearch|null): boolean {
1048
+ return Boolean(
1049
+ a === b ||
1050
+ a && b && a.currentRange?.from === b.currentRange?.from && a.currentRange?.to === b.currentRange?.to &&
1051
+ a.regexp.source === b.regexp.source && a.regexp.flags === b.regexp.flags);
1052
+ }
1053
+ }
1054
+
1055
+ const setActiveSearch = CodeMirror.StateEffect.define<ActiveSearch|null>(
1056
+ {map: (value, mapping): ActiveSearch | null => value && value.map(mapping)});
1057
+
1058
+ const activeSearchState = CodeMirror.StateField.define<ActiveSearch|null>({
1059
+ create(): null {
1060
+ return null;
1061
+ },
1062
+ update(state, tr): ActiveSearch |
1063
+ null {
1064
+ return tr.effects.reduce(
1065
+ (state, effect) => effect.is(setActiveSearch) ? effect.value : state, state && state.map(tr.changes));
1066
+ },
1067
+ });
1068
+
1069
+ const searchMatchDeco = CodeMirror.Decoration.mark({class: 'cm-searchMatch'});
1070
+ const currentSearchMatchDeco = CodeMirror.Decoration.mark({class: 'cm-searchMatch cm-searchMatch-selected'});
1071
+
1072
+ const searchHighlighter = CodeMirror.ViewPlugin.fromClass(class {
1073
+ decorations: CodeMirror.DecorationSet;
1074
+
1075
+ constructor(view: CodeMirror.EditorView) {
1076
+ this.decorations = this.computeDecorations(view);
1077
+ }
1078
+
1079
+ update(update: CodeMirror.ViewUpdate): void {
1080
+ const active = update.state.field(activeSearchState);
1081
+ if (!ActiveSearch.eq(active, update.startState.field(activeSearchState)) ||
1082
+ (active && (update.viewportChanged || update.docChanged))) {
1083
+ this.decorations = this.computeDecorations(update.view);
1084
+ }
1085
+ }
1086
+
1087
+ private computeDecorations(view: CodeMirror.EditorView): CodeMirror.DecorationSet {
1088
+ const active = view.state.field(activeSearchState);
1089
+ if (!active) {
1090
+ return CodeMirror.Decoration.none;
1091
+ }
1092
+
1093
+ const builder = new CodeMirror.RangeSetBuilder<CodeMirror.Decoration>();
1094
+ const {doc} = view.state;
1095
+ for (const {from, to} of view.visibleRanges) {
1096
+ let pos = from;
1097
+ for (const line of doc.iterLines(doc.lineAt(from).number, doc.lineAt(to).number + 1)) {
1098
+ active.regexp.lastIndex = 0;
1099
+ for (;;) {
1100
+ const match = active.regexp.exec(line);
1101
+ if (!match) {
1102
+ break;
1103
+ }
1104
+ const start = pos + match.index, end = start + match[0].length;
1105
+ const current = active.currentRange && active.currentRange.from === start && active.currentRange.to === end;
1106
+ builder.add(start, end, current ? currentSearchMatchDeco : searchMatchDeco);
1107
+ }
1108
+ pos += line.length + 1;
1109
+ }
1110
+ }
1111
+ return builder.finish();
1112
+ }
1113
+ }, {decorations: (value): CodeMirror.DecorationSet => value.decorations});
1114
+
1115
+ const nonBreakableLineMark = new (class extends CodeMirror.GutterMarker {
1116
+ elementClass = 'cm-nonBreakableLine';
1117
+ })();
1118
+
1119
+ // Effect to add lines (by position) to the set of non-breakable lines.
1120
+ export const addNonBreakableLines = CodeMirror.StateEffect.define<readonly number[]>();
1121
+
1122
+ const nonBreakableLines = CodeMirror.StateField.define<CodeMirror.RangeSet<CodeMirror.GutterMarker>>({
1123
+ create(): CodeMirror.RangeSet<CodeMirror.GutterMarker> {
1124
+ return CodeMirror.RangeSet.empty;
1125
+ },
1126
+ update(deco, tr): CodeMirror.RangeSet<CodeMirror.GutterMarker> {
1127
+ return tr.effects.reduce((deco, effect) => {
1128
+ return !effect.is(addNonBreakableLines) ?
1129
+ deco :
1130
+ deco.update({add: effect.value.map(pos => nonBreakableLineMark.range(pos))});
1131
+ }, deco.map(tr.changes));
1132
+ },
1133
+ provide: field => CodeMirror.lineNumberMarkers.from(field),
1134
+ });
1135
+
1136
+ export function isBreakableLine(state: CodeMirror.EditorState, line: CodeMirror.Line): boolean {
1137
+ const nonBreakable = state.field(nonBreakableLines);
1138
+ if (!nonBreakable.size) {
1139
+ return true;
1140
+ }
1141
+ let found = false;
1142
+ nonBreakable.between(line.from, line.from, () => {
1143
+ found = true;
1144
+ });
1145
+ return !found;
1146
+ }
1147
+
1148
+ function markNonBreakableLines(disassembly: Common.WasmDisassembly.WasmDisassembly): CodeMirror.Extension {
1149
+ // Mark non-breakable lines in the Wasm disassembly after setting
1150
+ // up the content for the text editor (which creates the gutter).
1151
+ return nonBreakableLines.init(state => {
1152
+ const marks = [];
1153
+ for (const lineNumber of disassembly.nonBreakableLineNumbers()) {
1154
+ if (lineNumber < state.doc.lines) {
1155
+ marks.push(nonBreakableLineMark.range(state.doc.line(lineNumber + 1).from));
1156
+ }
1157
+ }
1158
+ return CodeMirror.RangeSet.of(marks);
1159
+ });
911
1160
  }