chrome-devtools-frontend 1.0.941095 → 1.0.943017

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 (254) hide show
  1. package/WATCHLISTS +1 -1
  2. package/config/gni/all_devtools_files.gni +0 -62
  3. package/config/gni/devtools_grd_files.gni +55 -19
  4. package/config/gni/devtools_image_files.gni +2 -3
  5. package/front_end/.eslintrc.js +12 -1
  6. package/front_end/Images/src/feedback_button_icon.svg +3 -0
  7. package/front_end/Images/src/{feedback_thin_16x16_icon.svg → survey_feedback_icon.svg} +1 -1
  8. package/front_end/Tests.js +1 -32
  9. package/front_end/core/common/Color.ts +5 -0
  10. package/front_end/core/i18n/locales/en-US.json +20 -29
  11. package/front_end/core/i18n/locales/en-XL.json +20 -29
  12. package/front_end/core/sdk/CPUProfilerModel.ts +7 -9
  13. package/front_end/core/sdk/ConsoleModel.ts +26 -28
  14. package/front_end/core/sdk/DebuggerModel.ts +4 -14
  15. package/front_end/core/sdk/sdk-meta.ts +17 -3
  16. package/front_end/entrypoints/devtools_app/devtools_app.json +1 -11
  17. package/front_end/entrypoints/inspector/inspector.json +1 -3
  18. package/front_end/entrypoints/js_app/js_app.json +1 -3
  19. package/front_end/entrypoints/main/MainImpl.ts +26 -0
  20. package/front_end/entrypoints/node_app/node_app.json +1 -3
  21. package/front_end/entrypoints/shell/shell.js +0 -11
  22. package/front_end/entrypoints/shell/shell.json +1 -5
  23. package/front_end/entrypoints/worker_app/worker_app.json +1 -7
  24. package/front_end/generated/InspectorBackendCommands.js +19 -0
  25. package/front_end/generated/protocol-mapping.d.ts +31 -1
  26. package/front_end/generated/protocol-proxy-api.d.ts +34 -2
  27. package/front_end/generated/protocol.d.ts +81 -6
  28. package/front_end/global_typings/global_defs.d.ts +5 -0
  29. package/front_end/legacy_test_runner/bindings_test_runner/IsolatedFilesystemTestRunner.js +2 -2
  30. package/front_end/legacy_test_runner/console_test_runner/console_test_runner.js +14 -2
  31. package/front_end/legacy_test_runner/legacy_test_runner.ts +10 -1
  32. package/front_end/legacy_test_runner/test_runner/TestRunner.js +11 -0
  33. package/front_end/models/formatter/SourceFormatter.ts +0 -10
  34. package/front_end/models/workspace/UISourceCode.ts +9 -42
  35. package/front_end/panels/animation/AnimationTimeline.ts +3 -3
  36. package/front_end/panels/application/ApplicationPanelSidebar.ts +3 -3
  37. package/front_end/panels/application/BackForwardCacheStrings.ts +3 -1
  38. package/front_end/panels/application/application-meta.ts +0 -3
  39. package/front_end/panels/application/components/EndpointsGrid.ts +1 -1
  40. package/front_end/panels/application/components/ReportsGrid.ts +1 -1
  41. package/front_end/panels/console/ConsolePinPane.ts +21 -26
  42. package/front_end/panels/coverage/CoverageDecorationManager.ts +4 -5
  43. package/front_end/panels/coverage/CoverageView.ts +2 -105
  44. package/front_end/panels/css_overview/components/CSSOverviewStartView.ts +11 -56
  45. package/front_end/panels/css_overview/components/cssOverviewStartView.css +1 -8
  46. package/front_end/panels/elements/ElementsTreeElement.ts +4 -9
  47. package/front_end/panels/elements/components/StylePropertyEditor.ts +2 -0
  48. package/front_end/panels/elements/components/adornerSettingsPane.css +0 -4
  49. package/front_end/panels/emulation/DeviceModeToolbar.ts +3 -1
  50. package/front_end/panels/emulation/DeviceModeView.ts +2 -1
  51. package/front_end/panels/emulation/InspectedPagePlaceholder.ts +3 -1
  52. package/front_end/panels/emulation/MediaQueryInspector.ts +3 -1
  53. package/front_end/panels/emulation/emulation-meta.ts +2 -4
  54. package/front_end/panels/issues/issues-meta.ts +0 -2
  55. package/front_end/panels/js_profiler/js_profiler-meta.ts +0 -3
  56. package/front_end/panels/layers/module.json +0 -1
  57. package/front_end/panels/lighthouse/LighthousePanel.ts +2 -4
  58. package/front_end/panels/lighthouse/LighthouseReportRenderer.ts +1 -4
  59. package/front_end/panels/lighthouse/lighthouseStartView.css +4 -0
  60. package/front_end/panels/lighthouse/module.json +0 -6
  61. package/front_end/panels/media/media-meta.ts +0 -3
  62. package/front_end/panels/network/ResourceWebSocketFrameView.ts +2 -1
  63. package/front_end/panels/network/network-meta.ts +0 -3
  64. package/front_end/panels/profiler/CPUProfileView.ts +10 -3
  65. package/front_end/panels/profiler/profiler-meta.ts +0 -2
  66. package/front_end/panels/screencast/screencast-meta.ts +0 -3
  67. package/front_end/panels/security/security-meta.ts +0 -3
  68. package/front_end/panels/sources/BreakpointEditDialog.ts +16 -30
  69. package/front_end/panels/sources/CSSPlugin.ts +310 -331
  70. package/front_end/panels/sources/CallStackSidebarPane.ts +28 -34
  71. package/front_end/panels/sources/CoveragePlugin.ts +121 -6
  72. package/front_end/panels/sources/DebuggerPlugin.ts +1166 -1243
  73. package/front_end/panels/sources/EditingLocationHistoryManager.ts +71 -101
  74. package/front_end/panels/sources/GoToLineQuickOpen.ts +4 -3
  75. package/front_end/panels/sources/InplaceFormatterEditorAction.ts +3 -3
  76. package/front_end/panels/sources/JavaScriptCompilerPlugin.ts +26 -23
  77. package/front_end/panels/sources/Plugin.ts +20 -4
  78. package/front_end/panels/sources/ProfilePlugin.ts +185 -0
  79. package/front_end/panels/sources/ScriptFormatterEditorAction.ts +3 -3
  80. package/front_end/panels/sources/ScriptOriginPlugin.ts +0 -10
  81. package/front_end/panels/sources/SnippetsPlugin.ts +1 -10
  82. package/front_end/panels/sources/SourcesPanel.ts +6 -5
  83. package/front_end/panels/sources/SourcesView.ts +10 -8
  84. package/front_end/panels/sources/TabbedEditorContainer.ts +31 -27
  85. package/front_end/panels/sources/UISourceCodeFrame.ts +335 -470
  86. package/front_end/panels/sources/WatchExpressionsSidebarPane.ts +3 -2
  87. package/front_end/panels/sources/sources-legacy.ts +0 -6
  88. package/front_end/panels/sources/sources-meta.ts +1 -4
  89. package/front_end/panels/sources/sources.ts +0 -2
  90. package/front_end/panels/timeline/timeline-meta.ts +0 -5
  91. package/front_end/third_party/codemirror.next/bundle.ts +9 -13
  92. package/front_end/third_party/codemirror.next/chunk/codemirror.js +1 -1
  93. package/front_end/third_party/codemirror.next/chunk/javascript.js +2 -2
  94. package/front_end/third_party/codemirror.next/chunk/markdown.js +2 -6
  95. package/front_end/third_party/codemirror.next/chunk/php.js +2 -6
  96. package/front_end/third_party/codemirror.next/chunk/python.js +1 -1
  97. package/front_end/third_party/codemirror.next/chunk/wast.js +1 -1
  98. package/front_end/third_party/codemirror.next/chunk/xml.js +2 -2
  99. package/front_end/third_party/codemirror.next/codemirror.next.d.ts +279 -198
  100. package/front_end/third_party/codemirror.next/codemirror.next.js +1 -1
  101. package/front_end/third_party/codemirror.next/package.json +13 -11
  102. package/front_end/third_party/lighthouse/lighthouse-dt-bundle.js +1128 -1158
  103. package/front_end/third_party/lighthouse/locales/ar-XB.json +211 -79
  104. package/front_end/third_party/lighthouse/locales/ar.json +213 -81
  105. package/front_end/third_party/lighthouse/locales/bg.json +211 -79
  106. package/front_end/third_party/lighthouse/locales/ca.json +212 -80
  107. package/front_end/third_party/lighthouse/locales/cs.json +211 -79
  108. package/front_end/third_party/lighthouse/locales/da.json +211 -79
  109. package/front_end/third_party/lighthouse/locales/de.json +211 -79
  110. package/front_end/third_party/lighthouse/locales/el.json +213 -81
  111. package/front_end/third_party/lighthouse/locales/en-GB.json +211 -79
  112. package/front_end/third_party/lighthouse/locales/en-US.json +186 -75
  113. package/front_end/third_party/lighthouse/locales/en-XA.json +211 -79
  114. package/front_end/third_party/lighthouse/locales/en-XL.json +186 -75
  115. package/front_end/third_party/lighthouse/locales/es-419.json +211 -79
  116. package/front_end/third_party/lighthouse/locales/es.json +212 -80
  117. package/front_end/third_party/lighthouse/locales/fi.json +211 -79
  118. package/front_end/third_party/lighthouse/locales/fil.json +211 -79
  119. package/front_end/third_party/lighthouse/locales/fr.json +211 -79
  120. package/front_end/third_party/lighthouse/locales/he.json +212 -80
  121. package/front_end/third_party/lighthouse/locales/hi.json +214 -82
  122. package/front_end/third_party/lighthouse/locales/hr.json +211 -79
  123. package/front_end/third_party/lighthouse/locales/hu.json +211 -79
  124. package/front_end/third_party/lighthouse/locales/id.json +211 -79
  125. package/front_end/third_party/lighthouse/locales/it.json +211 -79
  126. package/front_end/third_party/lighthouse/locales/ja.json +211 -79
  127. package/front_end/third_party/lighthouse/locales/ko.json +211 -79
  128. package/front_end/third_party/lighthouse/locales/lt.json +211 -79
  129. package/front_end/third_party/lighthouse/locales/lv.json +214 -82
  130. package/front_end/third_party/lighthouse/locales/nl.json +211 -79
  131. package/front_end/third_party/lighthouse/locales/no.json +211 -79
  132. package/front_end/third_party/lighthouse/locales/pl.json +211 -79
  133. package/front_end/third_party/lighthouse/locales/pt-PT.json +211 -79
  134. package/front_end/third_party/lighthouse/locales/pt.json +211 -79
  135. package/front_end/third_party/lighthouse/locales/ro.json +212 -80
  136. package/front_end/third_party/lighthouse/locales/ru.json +211 -79
  137. package/front_end/third_party/lighthouse/locales/sk.json +211 -79
  138. package/front_end/third_party/lighthouse/locales/sl.json +211 -79
  139. package/front_end/third_party/lighthouse/locales/sr-Latn.json +211 -79
  140. package/front_end/third_party/lighthouse/locales/sr.json +211 -79
  141. package/front_end/third_party/lighthouse/locales/sv.json +211 -79
  142. package/front_end/third_party/lighthouse/locales/ta.json +218 -86
  143. package/front_end/third_party/lighthouse/locales/te.json +251 -119
  144. package/front_end/third_party/lighthouse/locales/th.json +211 -79
  145. package/front_end/third_party/lighthouse/locales/tr.json +211 -79
  146. package/front_end/third_party/lighthouse/locales/uk.json +212 -80
  147. package/front_end/third_party/lighthouse/locales/vi.json +211 -79
  148. package/front_end/third_party/lighthouse/locales/zh-HK.json +211 -79
  149. package/front_end/third_party/lighthouse/locales/zh-TW.json +211 -79
  150. package/front_end/third_party/lighthouse/locales/zh.json +211 -79
  151. package/front_end/third_party/lighthouse/report/bundle.d.ts +72 -34
  152. package/front_end/third_party/lighthouse/report/bundle.js +698 -492
  153. package/front_end/third_party/lighthouse/report-assets/report-generator.js +1 -2
  154. package/front_end/third_party/lighthouse/report-assets/report.js +40 -35
  155. package/front_end/third_party/lighthouse/report-assets/standalone-template.html +2 -4
  156. package/front_end/ui/components/code_highlighter/CodeHighlighter.ts +60 -68
  157. package/front_end/ui/components/data_grid/dataGrid.css +12 -10
  158. package/front_end/ui/components/docs/css_overview/start_view.html +25 -0
  159. package/front_end/ui/components/docs/css_overview/start_view.ts +14 -0
  160. package/front_end/ui/components/docs/icon_button/basic.ts +3 -3
  161. package/front_end/ui/components/docs/panel_feedback/button.html +25 -0
  162. package/front_end/ui/components/docs/panel_feedback/button.ts +18 -0
  163. package/front_end/ui/components/helpers/get-stylesheet.ts +0 -14
  164. package/front_end/ui/components/markdown_view/MarkdownImagesMap.ts +1 -1
  165. package/front_end/ui/components/panel_feedback/FeedbackButton.ts +67 -0
  166. package/front_end/ui/components/panel_feedback/panel_feedback.ts +1 -0
  167. package/front_end/ui/components/survey_link/SurveyLink.ts +1 -1
  168. package/front_end/ui/components/text_editor/TextEditor.ts +79 -36
  169. package/front_end/ui/components/text_editor/config.ts +42 -26
  170. package/front_end/ui/components/text_editor/javascript.ts +2 -3
  171. package/front_end/ui/components/text_editor/position.ts +17 -0
  172. package/front_end/ui/components/text_editor/text_editor.ts +1 -0
  173. package/front_end/ui/components/text_editor/theme.ts +5 -1
  174. package/front_end/ui/legacy/Dialog.ts +3 -1
  175. package/front_end/ui/legacy/DropTarget.ts +2 -1
  176. package/front_end/ui/legacy/EmptyWidget.ts +2 -1
  177. package/front_end/ui/legacy/FilterBar.ts +2 -1
  178. package/front_end/ui/legacy/GlassPane.ts +4 -2
  179. package/front_end/ui/legacy/Infobar.ts +5 -8
  180. package/front_end/ui/legacy/InspectorView.ts +6 -1
  181. package/front_end/ui/legacy/ListWidget.ts +2 -1
  182. package/front_end/ui/legacy/PopoverHelper.ts +2 -1
  183. package/front_end/ui/legacy/ProgressIndicator.ts +2 -1
  184. package/front_end/ui/legacy/RemoteDebuggingTerminatedScreen.ts +2 -1
  185. package/front_end/ui/legacy/ReportView.ts +2 -1
  186. package/front_end/ui/legacy/RootView.ts +2 -1
  187. package/front_end/ui/legacy/SearchableView.ts +2 -1
  188. package/front_end/ui/legacy/ShortcutRegistry.ts +11 -7
  189. package/front_end/ui/legacy/SoftContextMenu.ts +2 -1
  190. package/front_end/ui/legacy/SoftDropDown.ts +4 -2
  191. package/front_end/ui/legacy/SplitWidget.ts +2 -1
  192. package/front_end/ui/legacy/SuggestBox.ts +2 -1
  193. package/front_end/ui/legacy/TabbedPane.ts +2 -1
  194. package/front_end/ui/legacy/TargetCrashedScreen.ts +2 -1
  195. package/front_end/ui/legacy/TextPrompt.ts +2 -1
  196. package/front_end/ui/legacy/Toolbar.ts +3 -2
  197. package/front_end/ui/legacy/Treeoutline.ts +3 -2
  198. package/front_end/ui/legacy/UIUtils.ts +16 -13
  199. package/front_end/ui/legacy/ViewManager.ts +2 -1
  200. package/front_end/ui/legacy/Widget.ts +1 -1
  201. package/front_end/ui/legacy/components/object_ui/object_ui-meta.ts +0 -3
  202. package/front_end/ui/legacy/components/perf_ui/ChartViewport.ts +2 -1
  203. package/front_end/ui/legacy/components/perf_ui/FilmStripView.ts +3 -1
  204. package/front_end/ui/legacy/components/perf_ui/FlameChart.ts +2 -1
  205. package/front_end/ui/legacy/components/perf_ui/LineLevelProfile.ts +35 -131
  206. package/front_end/ui/legacy/components/perf_ui/OverviewGrid.ts +2 -1
  207. package/front_end/ui/legacy/components/perf_ui/TimelineGrid.ts +3 -1
  208. package/front_end/ui/legacy/components/perf_ui/TimelineOverviewPane.ts +2 -1
  209. package/front_end/ui/legacy/components/perf_ui/perf_ui-meta.ts +0 -2
  210. package/front_end/ui/legacy/components/quick_open/filteredListWidget.css +2 -2
  211. package/front_end/ui/legacy/components/source_frame/BinaryResourceViewFactory.ts +3 -6
  212. package/front_end/ui/legacy/components/source_frame/FontView.ts +1 -0
  213. package/front_end/ui/legacy/components/source_frame/ImageView.ts +1 -0
  214. package/front_end/ui/legacy/components/source_frame/JSONView.ts +1 -0
  215. package/front_end/ui/legacy/components/source_frame/ResourceSourceFrame.ts +19 -14
  216. package/front_end/ui/legacy/components/source_frame/SourceFrame.ts +501 -252
  217. package/front_end/ui/legacy/components/source_frame/XMLView.ts +2 -0
  218. package/front_end/ui/legacy/components/source_frame/module.json +0 -3
  219. package/front_end/ui/legacy/components/source_frame/source_frame-legacy.ts +0 -11
  220. package/front_end/ui/legacy/components/source_frame/source_frame.ts +0 -2
  221. package/front_end/ui/legacy/components/text_editor/CodeMirrorTextEditor.ts +2 -0
  222. package/front_end/ui/legacy/components/text_editor/cmdevtools.css +3 -1
  223. package/front_end/ui/legacy/components/text_editor/module.json +0 -3
  224. package/front_end/ui/legacy/components/utils/Linkifier.ts +7 -15
  225. package/front_end/ui/legacy/radioButton.css +1 -13
  226. package/front_end/ui/legacy/textButton.css +5 -4
  227. package/front_end/ui/legacy/themeColors.css +36 -0
  228. package/front_end/ui/legacy/theme_support/theme_support_impl.ts +7 -9
  229. package/front_end/ui/legacy/utils/append-style.ts +9 -4
  230. package/front_end/ui/legacy/utils/create-shadow-root-with-core-styles.ts +2 -2
  231. package/front_end/ui/legacy/utils/inject-core-styles.ts +7 -4
  232. package/package.json +1 -1
  233. package/scripts/build/generate_css_js_files.js +23 -9
  234. package/scripts/build/ninja/generate_css.gni +10 -1
  235. package/scripts/eslint_rules/lib/check_css_import.js +2 -2
  236. package/scripts/eslint_rules/tests/check_css_import_test.js +12 -0
  237. package/front_end/Images/radioDot-dark-theme.png +0 -0
  238. package/front_end/Images/radioDot.png +0 -0
  239. package/front_end/emulated_devices/module.json +0 -6
  240. package/front_end/panels/application/module.json +0 -7
  241. package/front_end/panels/emulation/module.json +0 -11
  242. package/front_end/panels/issues/module.json +0 -6
  243. package/front_end/panels/js_profiler/module.json +0 -5
  244. package/front_end/panels/layer_viewer/module.json +0 -6
  245. package/front_end/panels/media/module.json +0 -6
  246. package/front_end/panels/network/module.json +0 -6
  247. package/front_end/panels/profiler/module.json +0 -6
  248. package/front_end/panels/screencast/module.json +0 -6
  249. package/front_end/panels/security/module.json +0 -5
  250. package/front_end/panels/timeline/module.json +0 -8
  251. package/front_end/third_party/lighthouse/report-assets/report.css +0 -1774
  252. package/front_end/ui/legacy/components/perf_ui/module.json +0 -13
  253. package/front_end/ui/legacy/components/source_frame/SourcesTextEditor.ts +0 -1030
  254. package/front_end/ui/legacy/module.json +0 -41
@@ -1,43 +1,14 @@
1
- /*
2
- * Copyright (C) 2013 Google Inc. All rights reserved.
3
- *
4
- * Redistribution and use in source and binary forms, with or without
5
- * modification, are permitted provided that the following conditions are
6
- * met:
7
- *
8
- * * Redistributions of source code must retain the above copyright
9
- * notice, this list of conditions and the following disclaimer.
10
- * * Redistributions in binary form must reproduce the above
11
- * copyright notice, this list of conditions and the following disclaimer
12
- * in the documentation and/or other materials provided with the
13
- * distribution.
14
- * * Neither the name of Google Inc. nor the names of its
15
- * contributors may be used to endorse or promote products derived from
16
- * this software without specific prior written permission.
17
- *
18
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
- */
1
+ // Copyright 2021 The Chromium Authors. All rights reserved.
2
+ // Use of this source code is governed by a BSD-style license that can be
3
+ // found in the LICENSE file.
30
4
 
31
5
  import * as Common from '../../core/common/common.js';
32
6
  import * as i18n from '../../core/i18n/i18n.js';
33
- import * as Platform from '../../core/platform/platform.js';
34
7
  import * as SDK from '../../core/sdk/sdk.js';
35
- import * as TextUtils from '../../models/text_utils/text_utils.js';
36
8
  import type * as Workspace from '../../models/workspace/workspace.js';
37
9
  import * as ColorPicker from '../../ui/legacy/components/color_picker/color_picker.js';
38
10
  import * as InlineEditor from '../../ui/legacy/components/inline_editor/inline_editor.js';
39
- import * as SourceFrame from '../../ui/legacy/components/source_frame/source_frame.js';
40
- import type * as TextEditor from '../../ui/legacy/components/text_editor/text_editor.js';
11
+ import * as CodeMirror from '../../third_party/codemirror.next/codemirror.next.js';
41
12
  import * as UI from '../../ui/legacy/legacy.js';
42
13
 
43
14
  import {Plugin} from './Plugin.js';
@@ -54,354 +25,362 @@ const UIStrings = {
54
25
  };
55
26
  const str_ = i18n.i18n.registerUIStrings('panels/sources/CSSPlugin.ts', UIStrings);
56
27
  const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
57
- export class CSSPlugin extends Plugin {
58
- private textEditor: SourceFrame.SourcesTextEditor.SourcesTextEditor;
59
- private readonly swatchPopoverHelper: InlineEditor.SwatchPopoverHelper.SwatchPopoverHelper;
60
- private muteSwatchProcessing: boolean;
61
- private hadSwatchChange: boolean;
62
- private bezierEditor: InlineEditor.BezierEditor.BezierEditor|null;
63
- private editedSwatchTextRange: TextUtils.TextRange.TextRange|null;
64
- private spectrum: ColorPicker.Spectrum.Spectrum|null;
65
- private currentSwatch: Element|null;
66
- private boundHandleKeyDown: ((arg0: Event) => void)|null;
67
- constructor(textEditor: SourceFrame.SourcesTextEditor.SourcesTextEditor) {
68
- super();
69
- this.textEditor = textEditor;
70
- this.swatchPopoverHelper = new InlineEditor.SwatchPopoverHelper.SwatchPopoverHelper();
71
- this.muteSwatchProcessing = false;
72
- this.hadSwatchChange = false;
73
- this.bezierEditor = null;
74
- this.editedSwatchTextRange = null;
75
- this.spectrum = null;
76
- this.currentSwatch = null;
77
- this.textEditor.configureAutocomplete({
78
- suggestionsCallback: this.cssSuggestions.bind(this),
79
- isWordChar: this.isWordChar.bind(this),
80
- anchorBehavior: undefined,
81
- substituteRangeCallback: undefined,
82
- tooltipCallback: undefined,
83
- });
84
- this.textEditor.addEventListener(SourceFrame.SourcesTextEditor.Events.ScrollChanged, this.textEditorScrolled, this);
85
- this.textEditor.addEventListener(UI.TextEditor.Events.TextChanged, this.onTextChanged, this);
86
- this.updateSwatches(0, this.textEditor.linesCount - 1);
87
- this.boundHandleKeyDown = null;
88
28
 
89
- this.registerShortcuts();
90
- }
29
+ export function completion(): CodeMirror.Extension {
30
+ const {cssCompletionSource} = CodeMirror.css;
31
+ return CodeMirror.autocompletion({
32
+ override:
33
+ [async(cx: CodeMirror.CompletionContext):
34
+ Promise<CodeMirror.CompletionResult|null> => {
35
+ return (await specificCssCompletion(cx)) || cssCompletionSource(cx);
36
+ }],
37
+ });
38
+ }
91
39
 
92
- static accepts(uiSourceCode: Workspace.UISourceCode.UISourceCode): boolean {
93
- return uiSourceCode.contentType().isStyleSheet();
94
- }
40
+ const dontCompleteIn = new Set(['ColorLiteral', 'NumberLiteral', 'StringLiteral', 'Comment', 'Important']);
95
41
 
96
- private registerShortcuts(): void {
97
- this.boundHandleKeyDown =
98
- UI.ShortcutRegistry.ShortcutRegistry.instance().addShortcutListener(this.textEditor.element, {
99
- 'sources.increment-css': this.handleUnitModification.bind(this, 1),
100
- 'sources.increment-css-by-ten': this.handleUnitModification.bind(this, 10),
101
- 'sources.decrement-css': this.handleUnitModification.bind(this, -1),
102
- 'sources.decrement-css-by-ten': this.handleUnitModification.bind(this, -10),
103
- });
42
+ function findPropertyAt(node: CodeMirror.SyntaxNode, pos: number): CodeMirror.SyntaxNode|null {
43
+ if (dontCompleteIn.has(node.name)) {
44
+ return null;
104
45
  }
105
-
106
- private textEditorScrolled(): void {
107
- if (this.swatchPopoverHelper.isShowing()) {
108
- this.swatchPopoverHelper.hide(true);
46
+ for (let cur: CodeMirror.SyntaxNode|null = node; cur; cur = cur.parent) {
47
+ if (cur.name === 'StyleSheet') {
48
+ break;
49
+ } else if (cur.name === 'Declaration') {
50
+ const name = cur.getChild('PropertyName'), colon = cur.getChild(':');
51
+ return name && colon && colon.to <= pos ? name : null;
109
52
  }
110
53
  }
54
+ return null;
55
+ }
56
+
57
+ function specificCssCompletion(cx: CodeMirror.CompletionContext): CodeMirror.CompletionResult|null {
58
+ const node = CodeMirror.syntaxTree(cx.state).resolveInner(cx.pos, -1);
59
+ const property = findPropertyAt(node, cx.pos);
60
+ if (!property) {
61
+ return null;
62
+ }
63
+ const propertyValues = SDK.CSSMetadata.cssMetadata().getPropertyValues(cx.state.sliceDoc(property.from, property.to));
64
+ return {
65
+ from: node.name === 'ValueName' ? node.from : cx.pos,
66
+ options: propertyValues.map(value => ({type: 'constant', label: value})),
67
+ span: /^[\w\P{ASCII}\-]+$/u,
68
+ };
69
+ }
111
70
 
112
- private modifyUnit(unit: string, change: number): string|null {
113
- const unitValue = parseInt(unit, 10);
114
- if (isNaN(unitValue)) {
115
- return null;
71
+ function findColorsAndCurves(
72
+ state: CodeMirror.EditorState,
73
+ from: number,
74
+ to: number,
75
+ onColor: (pos: number, color: Common.Color.Color, text: string) => void,
76
+ onCurve: (pos: number, curve: UI.Geometry.CubicBezier, text: string) => void,
77
+ ): void {
78
+ let line = state.doc.lineAt(from);
79
+ function getToken(from: number, to: number): string {
80
+ if (from >= line.to) {
81
+ line = state.doc.lineAt(from);
116
82
  }
117
- const tail = unit.substring((unitValue).toString().length);
118
- return Platform.StringUtilities.sprintf('%d%s', unitValue + change, tail);
83
+ return line.text.slice(from - line.from, to - line.from);
119
84
  }
120
85
 
121
- private async handleUnitModification(change: number): Promise<boolean> {
122
- const selection = this.textEditor.selection().normalize();
123
- let token = this.textEditor.tokenAtTextPosition(selection.startLine, selection.startColumn);
124
- if (!token) {
125
- if (selection.startColumn > 0) {
126
- token = this.textEditor.tokenAtTextPosition(selection.startLine, selection.startColumn - 1);
86
+ const tree = CodeMirror.ensureSyntaxTree(state, to, 100);
87
+ if (!tree) {
88
+ return;
89
+ }
90
+ tree.iterate({
91
+ from,
92
+ to,
93
+ enter: (type, from, to, node) => {
94
+ let content;
95
+ if (type.name === 'ValueName' || type.name === 'ColorLiteral') {
96
+ content = getToken(from, to);
97
+ } else if (type.name === 'Callee' && /^(?:(?:rgb|hsl)a?|cubic-bezier)$/.test(getToken(from, to))) {
98
+ content = state.sliceDoc(from, (node().parent as CodeMirror.SyntaxNode).to);
127
99
  }
128
- if (!token) {
129
- return false;
100
+ if (content) {
101
+ const parsedColor = Common.Color.Color.parse(content);
102
+ if (parsedColor) {
103
+ onColor(from, parsedColor, content);
104
+ } else {
105
+ const parsedCurve = UI.Geometry.CubicBezier.parse(content);
106
+ if (parsedCurve) {
107
+ onCurve(from, parsedCurve, content);
108
+ }
109
+ }
130
110
  }
131
- }
132
- if (token.type !== 'css-number') {
133
- return false;
134
- }
111
+ },
112
+ });
113
+ }
135
114
 
136
- const cssUnitRange =
137
- new TextUtils.TextRange.TextRange(selection.startLine, token.startColumn, selection.startLine, token.endColumn);
138
- const cssUnitText = this.textEditor.text(cssUnitRange);
139
- const newUnitText = this.modifyUnit(cssUnitText, change);
140
- if (!newUnitText) {
141
- return false;
142
- }
143
- this.textEditor.editRange(cssUnitRange, newUnitText);
144
- selection.startColumn = token.startColumn;
145
- selection.endColumn = selection.startColumn + newUnitText.length;
146
- this.textEditor.setSelection(selection);
147
- return true;
115
+ class ColorSwatchWidget extends CodeMirror.WidgetType {
116
+ constructor(readonly color: Common.Color.Color, readonly text: string) {
117
+ super();
148
118
  }
149
119
 
150
- private updateSwatches(startLine: number, endLine: number): void {
151
- const swatches: HTMLElement[] = [];
152
- const swatchPositions: TextUtils.TextRange.TextRange[] = [];
153
-
154
- const regexes =
155
- [SDK.CSSMetadata.VariableRegex, SDK.CSSMetadata.URLRegex, UI.Geometry.CubicBezier.Regex, Common.Color.Regex];
156
- const handlers = new Map<RegExp, (text: string) => HTMLElement | null>();
157
- handlers.set(Common.Color.Regex, this.createColorSwatch.bind(this));
158
- handlers.set(UI.Geometry.CubicBezier.Regex, this.createBezierSwatch.bind(this));
159
-
160
- for (let lineNumber = startLine; lineNumber <= endLine; lineNumber++) {
161
- const line = this.textEditor.line(lineNumber).substring(0, maxSwatchProcessingLength);
162
- const results = TextUtils.TextUtils.Utils.splitStringByRegexes(line, regexes);
163
- for (let i = 0; i < results.length; i++) {
164
- const result = results[i];
165
- const handler = handlers.get(regexes[result.regexIndex]);
166
- if (result.regexIndex === -1 || !handler) {
167
- continue;
168
- }
169
- const delimiters = /[\s:;,(){}]/;
170
- const positionBefore = result.position - 1;
171
- const positionAfter = result.position + result.value.length;
172
- if (positionBefore >= 0 && !delimiters.test(line.charAt(positionBefore)) ||
173
- positionAfter < line.length && !delimiters.test(line.charAt(positionAfter))) {
174
- continue;
175
- }
176
- const swatch = handler(result.value);
177
- if (!swatch) {
178
- continue;
179
- }
180
- swatches.push(swatch);
181
- swatchPositions.push(TextUtils.TextRange.TextRange.createFromLocation(lineNumber, result.position));
182
- }
183
- }
184
- this.textEditor.operation(putSwatchesInline.bind(this));
185
-
186
- function putSwatchesInline(this: CSSPlugin): void {
187
- const clearRange = new TextUtils.TextRange.TextRange(startLine, 0, endLine, this.textEditor.line(endLine).length);
188
- this.textEditor.bookmarks(clearRange, SwatchBookmark).forEach(marker => marker.clear());
189
-
190
- for (let i = 0; i < swatches.length; i++) {
191
- const swatch = swatches[i];
192
- const swatchPosition = swatchPositions[i];
193
- const bookmark =
194
- this.textEditor.addBookmark(swatchPosition.startLine, swatchPosition.startColumn, swatch, SwatchBookmark);
195
- swatchToBookmark.set(swatch, bookmark);
196
- }
197
- }
120
+ eq(other: ColorSwatchWidget): boolean {
121
+ return this.color.equal(other.color) && this.text === other.text;
198
122
  }
199
123
 
200
- private createColorSwatch(text: string): HTMLElement|null {
201
- const color = Common.Color.Color.parse(text);
202
- if (!color) {
203
- return null;
204
- }
124
+ toDOM(view: CodeMirror.EditorView): HTMLElement {
205
125
  const swatch = new InlineEditor.ColorSwatch.ColorSwatch();
206
- swatch.renderColor(color, false, i18nString(UIStrings.openColorPicker));
126
+ swatch.renderColor(this.color, false, i18nString(UIStrings.openColorPicker));
207
127
  const value = swatch.createChild('span');
208
- value.textContent = text;
128
+ value.textContent = this.text;
209
129
  value.setAttribute('hidden', 'true');
210
-
211
- swatch.addEventListener(
212
- InlineEditor.ColorSwatch.ClickEvent.eventName, this.swatchIconClicked.bind(this, swatch), false);
130
+ swatch.addEventListener(InlineEditor.ColorSwatch.ClickEvent.eventName, event => {
131
+ event.consume(true);
132
+ view.dispatch({
133
+ effects: setTooltip.of({
134
+ type: TooltipType.Color,
135
+ pos: view.posAtDOM(swatch),
136
+ text: this.text,
137
+ swatch,
138
+ color: this.color,
139
+ }),
140
+ });
141
+ });
213
142
  return swatch;
214
143
  }
215
144
 
216
- private createBezierSwatch(text: string): InlineEditor.Swatches.BezierSwatch|null {
217
- if (!UI.Geometry.CubicBezier.parse(text)) {
218
- return null;
219
- }
220
- const swatch = InlineEditor.Swatches.BezierSwatch.create();
221
- swatch.setBezierText(text);
222
- UI.Tooltip.Tooltip.install(swatch.iconElement(), i18nString(UIStrings.openCubicBezierEditor));
223
- swatch.iconElement().addEventListener('click', this.swatchIconClicked.bind(this, swatch), false);
224
- swatch.hideText(true);
225
- return swatch;
145
+ ignoreEvent(): boolean {
146
+ return true;
226
147
  }
148
+ }
227
149
 
228
- private swatchIconClicked(swatch: Element, event: Event): void {
229
- event.consume(true);
230
- this.hadSwatchChange = false;
231
- this.muteSwatchProcessing = true;
232
- const bookmark = swatchToBookmark.get(swatch);
233
- if (!bookmark) {
234
- return;
235
- }
236
- const swatchPosition = bookmark.position();
237
- if (!swatchPosition) {
238
- return;
239
- }
240
- this.textEditor.setSelection(swatchPosition);
241
- this.editedSwatchTextRange = swatchPosition.clone();
242
- if (this.editedSwatchTextRange) {
243
- this.editedSwatchTextRange.endColumn += (swatch.textContent || '').length;
244
- }
245
- this.currentSwatch = swatch;
150
+ class CurveSwatchWidget extends CodeMirror.WidgetType {
151
+ constructor(readonly curve: UI.Geometry.CubicBezier, readonly text: string) {
152
+ super();
153
+ }
246
154
 
247
- if (InlineEditor.ColorSwatch.ColorSwatch.isColorSwatch(swatch)) {
248
- this.showSpectrum((swatch as InlineEditor.ColorSwatch.ColorSwatch));
249
- } else if (swatch instanceof InlineEditor.Swatches.BezierSwatch) {
250
- this.showBezierEditor(swatch);
251
- }
155
+ eq(other: CurveSwatchWidget): boolean {
156
+ return this.curve.asCSSText() === other.curve.asCSSText() && this.text === other.text;
252
157
  }
253
158
 
254
- private showSpectrum(swatch: InlineEditor.ColorSwatch.ColorSwatch): void {
255
- if (!this.spectrum) {
256
- this.spectrum = new ColorPicker.Spectrum.Spectrum();
257
- this.spectrum.addEventListener(ColorPicker.Spectrum.Events.SizeChanged, this.spectrumResized, this);
258
- this.spectrum.addEventListener(ColorPicker.Spectrum.Events.ColorChanged, this.spectrumChanged, this);
259
- }
260
- this.spectrum.setColor((swatch.getColor() as Common.Color.Color), swatch.getFormat() || '');
261
- this.swatchPopoverHelper.show(this.spectrum, swatch, this.swatchPopoverHidden.bind(this));
159
+ toDOM(view: CodeMirror.EditorView): HTMLElement {
160
+ const swatch = InlineEditor.Swatches.BezierSwatch.create();
161
+ swatch.setBezierText(this.text);
162
+ UI.Tooltip.Tooltip.install(swatch.iconElement(), i18nString(UIStrings.openCubicBezierEditor));
163
+ swatch.iconElement().addEventListener('click', (event: MouseEvent) => {
164
+ event.consume(true);
165
+ view.dispatch({
166
+ effects: setTooltip.of({
167
+ type: TooltipType.Curve,
168
+ pos: view.posAtDOM(swatch),
169
+ text: this.text,
170
+ swatch,
171
+ curve: this.curve,
172
+ }),
173
+ });
174
+ }, false);
175
+ swatch.hideText(true);
176
+ return swatch;
262
177
  }
263
178
 
264
- private spectrumResized(): void {
265
- this.swatchPopoverHelper.reposition();
179
+ ignoreEvent(): boolean {
180
+ return true;
266
181
  }
182
+ }
267
183
 
268
- private spectrumChanged(event: Common.EventTarget.EventTargetEvent<string>): void {
269
- const colorString = event.data;
270
- const color = Common.Color.Color.parse(colorString);
271
- if (!color || !this.currentSwatch) {
272
- return;
273
- }
184
+ const enum TooltipType {
185
+ Color = 0,
186
+ Curve = 1,
187
+ }
274
188
 
275
- if (InlineEditor.ColorSwatch.ColorSwatch.isColorSwatch(this.currentSwatch)) {
276
- const swatch = (this.currentSwatch as InlineEditor.ColorSwatch.ColorSwatch);
277
- swatch.renderColor(color);
278
- }
279
- this.changeSwatchText(colorString);
280
- }
189
+ type ActiveTooltip = {
190
+ type: TooltipType.Color,
191
+ pos: number,
192
+ text: string,
193
+ color: Common.Color.Color,
194
+ swatch: InlineEditor.ColorSwatch.ColorSwatch,
195
+ }|{
196
+ type: TooltipType.Curve,
197
+ pos: number,
198
+ text: string,
199
+ curve: UI.Geometry.CubicBezier,
200
+ swatch: InlineEditor.Swatches.BezierSwatch,
201
+ };
281
202
 
282
- private showBezierEditor(swatch: InlineEditor.Swatches.BezierSwatch): void {
283
- const cubicBezier = UI.Geometry.CubicBezier.parse(swatch.bezierText()) ||
284
- (UI.Geometry.CubicBezier.parse('linear') as UI.Geometry.CubicBezier);
285
- if (!this.bezierEditor) {
286
- this.bezierEditor = new InlineEditor.BezierEditor.BezierEditor(cubicBezier);
287
- this.bezierEditor.addEventListener(InlineEditor.BezierEditor.Events.BezierChanged, this.bezierChanged, this);
288
- } else {
289
- this.bezierEditor.setBezier(cubicBezier);
290
- }
291
- this.swatchPopoverHelper.show(this.bezierEditor, swatch.iconElement(), this.swatchPopoverHidden.bind(this));
292
- }
203
+ function createCSSTooltip(active: ActiveTooltip): CodeMirror.Tooltip {
204
+ return {
205
+ pos: active.pos,
206
+ arrow: true,
207
+ create(view): CodeMirror.TooltipView {
208
+ let text = active.text;
209
+ let widget: UI.Widget.VBox, addListener: (handler: (event: {data: string}) => void) => void;
210
+ if (active.type === TooltipType.Color) {
211
+ const spectrum = new ColorPicker.Spectrum.Spectrum();
212
+ addListener = (handler): void => {
213
+ spectrum.addEventListener(ColorPicker.Spectrum.Events.ColorChanged, handler);
214
+ };
215
+ spectrum.addEventListener(ColorPicker.Spectrum.Events.SizeChanged, () => view.requestMeasure());
216
+ spectrum.setColor(active.color, active.color.format());
217
+ widget = spectrum;
218
+ } else {
219
+ const spectrum = new InlineEditor.BezierEditor.BezierEditor(active.curve);
220
+ widget = spectrum;
221
+ addListener = (handler): void => {
222
+ spectrum.addEventListener(InlineEditor.BezierEditor.Events.BezierChanged, handler);
223
+ };
224
+ }
225
+ const dom = document.createElement('div');
226
+ dom.className = 'cm-tooltip-swatchEdit';
227
+ widget.markAsRoot();
228
+ widget.show(dom);
229
+ widget.showWidget();
230
+ widget.element.addEventListener('keydown', event => {
231
+ if (event.key === 'Escape') {
232
+ event.consume();
233
+ view.dispatch({
234
+ effects: setTooltip.of(null),
235
+ changes: text === active.text ? undefined :
236
+ {from: active.pos, to: active.pos + text.length, insert: active.text},
237
+ });
238
+ view.focus();
239
+ }
240
+ });
241
+ widget.element.addEventListener('focusout', event => {
242
+ if (event.relatedTarget && !widget.element.contains(event.relatedTarget as Node)) {
243
+ view.dispatch({effects: setTooltip.of(null)});
244
+ }
245
+ }, false);
246
+ widget.element.addEventListener('mousedown', event => event.consume());
247
+ return {
248
+ dom,
249
+ offset: {x: -8, y: 0},
250
+ mount: (): void => {
251
+ widget.focus();
252
+ widget.wasShown();
253
+ addListener((event: {data: string}): void => {
254
+ view.dispatch({
255
+ changes: {from: active.pos, to: active.pos + text.length, insert: event.data},
256
+ annotations: isSwatchEdit.of(true),
257
+ });
258
+ text = event.data;
259
+ });
260
+ },
261
+ };
262
+ },
263
+ };
264
+ }
293
265
 
294
- private bezierChanged(event: Common.EventTarget.EventTargetEvent<string>): void {
295
- const bezierString = event.data;
296
- if (this.currentSwatch instanceof InlineEditor.Swatches.BezierSwatch) {
297
- this.currentSwatch.setBezierText(bezierString);
298
- }
299
- this.changeSwatchText(bezierString);
300
- }
266
+ const setTooltip = CodeMirror.StateEffect.define<ActiveTooltip|null>();
301
267
 
302
- private changeSwatchText(text: string): void {
303
- this.hadSwatchChange = true;
304
- const editedRange = (this.editedSwatchTextRange as TextUtils.TextRange.TextRange);
305
- this.textEditor.editRange(editedRange, text, '*swatch-text-changed');
306
- editedRange.endColumn = editedRange.startColumn + text.length;
307
- }
268
+ const isSwatchEdit = CodeMirror.Annotation.define<boolean>();
308
269
 
309
- private swatchPopoverHidden(commitEdit: boolean): void {
310
- this.muteSwatchProcessing = false;
311
- if (!commitEdit && this.hadSwatchChange) {
312
- this.textEditor.undo();
313
- }
314
- }
270
+ const cssTooltipState = CodeMirror.StateField.define<ActiveTooltip|null>({
271
+ create() {
272
+ return null;
273
+ },
315
274
 
316
- private onTextChanged(event: Common.EventTarget.EventTargetEvent<UI.TextEditor.TextChangedEvent>): void {
317
- if (!this.muteSwatchProcessing) {
318
- this.updateSwatches(event.data.newRange.startLine, event.data.newRange.endLine);
319
- }
320
- }
275
+ update(value: ActiveTooltip|null, tr: CodeMirror.Transaction): ActiveTooltip |
276
+ null {
277
+ if ((tr.docChanged || tr.selection) && !tr.annotation(isSwatchEdit)) {
278
+ value = null;
279
+ }
280
+ for (const effect of tr.effects) {
281
+ if (effect.is(setTooltip)) {
282
+ value = effect.value;
283
+ }
284
+ }
285
+ return value;
286
+ },
287
+
288
+ provide: field => CodeMirror.showTooltip.from(field, active => active && createCSSTooltip(active)),
289
+ });
290
+
291
+ function computeSwatchDeco(state: CodeMirror.EditorState, from: number, to: number): CodeMirror.DecorationSet {
292
+ const builder = new CodeMirror.RangeSetBuilder<CodeMirror.Decoration>();
293
+ findColorsAndCurves(
294
+ state, from, to,
295
+ (pos, color, text) => {
296
+ builder.add(pos, pos, CodeMirror.Decoration.widget({widget: new ColorSwatchWidget(color, text)}));
297
+ },
298
+ (pos, curve, text) => {
299
+ builder.add(pos, pos, CodeMirror.Decoration.widget({widget: new CurveSwatchWidget(curve, text)}));
300
+ });
301
+ return builder.finish();
302
+ }
321
303
 
322
- private isWordChar(char: string): boolean {
323
- return TextUtils.TextUtils.Utils.isWordChar(char) || char === '.' || char === '-' || char === '$';
304
+ const cssSwatchPlugin = CodeMirror.ViewPlugin.fromClass(class {
305
+ decorations: CodeMirror.DecorationSet;
306
+
307
+ constructor(view: CodeMirror.EditorView) {
308
+ this.decorations = computeSwatchDeco(view.state, view.viewport.from, view.viewport.to);
324
309
  }
325
310
 
326
- private cssSuggestions(prefixRange: TextUtils.TextRange.TextRange, _substituteRange: TextUtils.TextRange.TextRange):
327
- Promise<UI.SuggestBox.Suggestions>|null {
328
- const prefix = this.textEditor.text(prefixRange);
329
- if (prefix.startsWith('$')) {
330
- return null;
311
+ update(update: CodeMirror.ViewUpdate): void {
312
+ if (update.viewportChanged || update.docChanged) {
313
+ this.decorations = computeSwatchDeco(update.state, update.view.viewport.from, update.view.viewport.to);
331
314
  }
315
+ }
316
+ }, {
317
+ decorations: v => v.decorations,
318
+ });
332
319
 
333
- const propertyToken = this.backtrackPropertyToken(prefixRange.startLine, prefixRange.startColumn - 1);
334
- if (!propertyToken) {
335
- return null;
336
- }
320
+ function cssSwatches(): CodeMirror.Extension {
321
+ return [cssSwatchPlugin, cssTooltipState];
322
+ }
337
323
 
338
- const line = this.textEditor.line(prefixRange.startLine);
339
- const tokenContent = line.substring(propertyToken.startColumn, propertyToken.endColumn);
340
- const propertyValues = SDK.CSSMetadata.cssMetadata().getPropertyValues(tokenContent);
341
- return Promise.resolve(propertyValues.filter(value => value.startsWith(prefix)).map(value => {
342
- return {
343
- text: value,
344
- title: undefined,
345
- subtitle: undefined,
346
- iconType: undefined,
347
- priority: undefined,
348
- isSecondary: undefined,
349
- subtitleRenderer: undefined,
350
- selectionRange: undefined,
351
- hideGhostText: undefined,
352
- iconElement: undefined,
353
- };
354
- }));
324
+ function getNumberAt(node: CodeMirror.SyntaxNode): {from: number, to: number}|null {
325
+ if (node.name === 'Unit') {
326
+ node = node.parent as CodeMirror.SyntaxNode;
355
327
  }
328
+ if (node.name === 'NumberLiteral') {
329
+ const lastChild = node.lastChild;
330
+ return {from: node.from, to: lastChild && lastChild.name === 'Unit' ? lastChild.from : node.to};
331
+ }
332
+ return null;
333
+ }
356
334
 
357
- private backtrackPropertyToken(lineNumber: number, columnNumber: number): {
358
- startColumn: number,
359
- endColumn: number,
360
- type: string,
361
- }|null {
362
- const backtrackDepth = 10;
363
- let tokenPosition: number = columnNumber;
364
- const line = this.textEditor.line(lineNumber);
365
- let seenColon = false;
366
-
367
- for (let i = 0; i < backtrackDepth && tokenPosition >= 0; ++i) {
368
- const token = this.textEditor.tokenAtTextPosition(lineNumber, tokenPosition);
369
- if (!token) {
370
- return null;
371
- }
372
- if (token.type === 'css-property') {
373
- return seenColon ? token : null;
374
- }
375
- if (token.type && !(token.type.indexOf('whitespace') !== -1 || token.type.startsWith('css-comment'))) {
376
- return null;
377
- }
378
-
379
- if (!token.type && line.substring(token.startColumn, token.endColumn) === ':') {
380
- if (!seenColon) {
381
- seenColon = true;
382
- } else {
383
- return null;
384
- }
385
- }
386
- tokenPosition = token.startColumn - 1;
387
- }
388
- return null;
335
+ function modifyUnit(view: CodeMirror.EditorView, by: number): boolean {
336
+ const {head} = view.state.selection.main;
337
+ const context = CodeMirror.syntaxTree(view.state).resolveInner(head, -1);
338
+ const numberRange = getNumberAt(context) || getNumberAt(context.resolve(head, 1));
339
+ if (!numberRange) {
340
+ return false;
389
341
  }
390
342
 
391
- dispose(): void {
392
- if (this.swatchPopoverHelper.isShowing()) {
393
- this.swatchPopoverHelper.hide(true);
394
- }
395
- this.textEditor.removeEventListener(
396
- SourceFrame.SourcesTextEditor.Events.ScrollChanged, this.textEditorScrolled, this);
397
- this.textEditor.removeEventListener(UI.TextEditor.Events.TextChanged, this.onTextChanged, this);
398
- this.textEditor.bookmarks(this.textEditor.fullRange(), SwatchBookmark).forEach(marker => marker.clear());
399
- this.textEditor.element.removeEventListener('keydown', (this.boundHandleKeyDown as EventListener));
343
+ const currentNumber = Number(view.state.sliceDoc(numberRange.from, numberRange.to));
344
+ if (isNaN(currentNumber)) {
345
+ return false;
400
346
  }
347
+
348
+ view.dispatch({
349
+ changes: {from: numberRange.from, to: numberRange.to, insert: String(currentNumber + by)},
350
+ scrollIntoView: true,
351
+ userEvent: 'insert.modifyUnit',
352
+ });
353
+ return true;
401
354
  }
402
355
 
403
- export const maxSwatchProcessingLength: number = 300;
356
+ export function cssBindings(): CodeMirror.Extension {
357
+ // This is an awkward way to pass the argument given to the editor
358
+ // event handler through the ShortcutRegistry calling convention.
359
+ let currentView: CodeMirror.EditorView = null as unknown as CodeMirror.EditorView;
360
+ const listener = UI.ShortcutRegistry.ShortcutRegistry.instance().getShortcutListener({
361
+ 'sources.increment-css': () => Promise.resolve(modifyUnit(currentView, 1)),
362
+ 'sources.increment-css-by-ten': () => Promise.resolve(modifyUnit(currentView, 10)),
363
+ 'sources.decrement-css': () => Promise.resolve(modifyUnit(currentView, -1)),
364
+ 'sources.decrement-css-by-ten': () => Promise.resolve(modifyUnit(currentView, -10)),
365
+ });
366
+
367
+ return CodeMirror.EditorView.domEventHandlers({
368
+ keydown: (event, view): boolean => {
369
+ const prevView = currentView;
370
+ currentView = view;
371
+ listener(event);
372
+ currentView = prevView;
373
+ return event.defaultPrevented;
374
+ },
375
+ });
376
+ }
404
377
 
405
- export const SwatchBookmark: symbol = Symbol('swatch');
378
+ export class CSSPlugin extends Plugin {
379
+ static accepts(uiSourceCode: Workspace.UISourceCode.UISourceCode): boolean {
380
+ return uiSourceCode.contentType().isStyleSheet();
381
+ }
406
382
 
407
- const swatchToBookmark = new WeakMap<Element, TextEditor.CodeMirrorTextEditor.TextEditorBookMark>();
383
+ editorExtension(): CodeMirror.Extension {
384
+ return [cssBindings(), completion(), cssSwatches()];
385
+ }
386
+ }