Web Inspector: Selection does not show up over execution highlight ranges
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 2 Oct 2016 02:46:37 +0000 (02:46 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 2 Oct 2016 02:46:37 +0000 (02:46 +0000)
https://bugs.webkit.org/show_bug.cgi?id=162844
<rdar://problem/28579121>

Patch by Joseph Pecoraro <pecoraro@apple.com> on 2016-10-01
Reviewed by Matt Baker.

* Scripts/update-codemirror-resources.rb:
* UserInterface/External/CodeMirror/mark-selection.js: Added.
* UserInterface/Main.html:
New add-on that makes selection a text marker so it can be styled
at the same level as other text markers.

* UserInterface/Views/TextEditor.css:
(.text-editor > .CodeMirror .execution-range-highlight:not(.CodeMirror-selectedtext)):
Don't use execution-range-highlight styles if the text is selected.

* UserInterface/Views/TextEditor.js:
(WebInspector.TextEditor):
Enable the text selection as text markers addon.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@206714 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebInspectorUI/ChangeLog
Source/WebInspectorUI/Scripts/update-codemirror-resources.rb
Source/WebInspectorUI/UserInterface/External/CodeMirror/mark-selection.js [new file with mode: 0644]
Source/WebInspectorUI/UserInterface/Main.html
Source/WebInspectorUI/UserInterface/Views/TextEditor.css
Source/WebInspectorUI/UserInterface/Views/TextEditor.js

index 4085ea0..e20d2da 100644 (file)
@@ -1,3 +1,25 @@
+2016-10-01  Joseph Pecoraro  <pecoraro@apple.com>
+
+        Web Inspector: Selection does not show up over execution highlight ranges
+        https://bugs.webkit.org/show_bug.cgi?id=162844
+        <rdar://problem/28579121>
+
+        Reviewed by Matt Baker.
+
+        * Scripts/update-codemirror-resources.rb:
+        * UserInterface/External/CodeMirror/mark-selection.js: Added.
+        * UserInterface/Main.html:
+        New add-on that makes selection a text marker so it can be styled
+        at the same level as other text markers.
+
+        * UserInterface/Views/TextEditor.css:
+        (.text-editor > .CodeMirror .execution-range-highlight:not(.CodeMirror-selectedtext)):
+        Don't use execution-range-highlight styles if the text is selected.
+
+        * UserInterface/Views/TextEditor.js:
+        (WebInspector.TextEditor):
+        Enable the text selection as text markers addon.
+
 2016-09-30  Joseph Pecoraro  <pecoraro@apple.com>
 
         Web Inspector: Make debugger stepping highlights work in inline <script>s
index 8ccc728..c4ab347 100755 (executable)
@@ -36,6 +36,7 @@ CODE_MIRROR_FILES_TO_COPY = %w(
   addon/mode/overlay.js
   addon/runmode/runmode.js
   addon/search/searchcursor.js
+  addon/selection/mark-selection.js
   keymap/sublime.js
   lib/codemirror.css
   lib/codemirror.js
diff --git a/Source/WebInspectorUI/UserInterface/External/CodeMirror/mark-selection.js b/Source/WebInspectorUI/UserInterface/External/CodeMirror/mark-selection.js
new file mode 100644 (file)
index 0000000..5c42d21
--- /dev/null
@@ -0,0 +1,118 @@
+// CodeMirror, copyright (c) by Marijn Haverbeke and others
+// Distributed under an MIT license: http://codemirror.net/LICENSE
+
+// Because sometimes you need to mark the selected *text*.
+//
+// Adds an option 'styleSelectedText' which, when enabled, gives
+// selected text the CSS class given as option value, or
+// "CodeMirror-selectedtext" when the value is not a string.
+
+(function(mod) {
+  if (typeof exports == "object" && typeof module == "object") // CommonJS
+    mod(require("../../lib/codemirror"));
+  else if (typeof define == "function" && define.amd) // AMD
+    define(["../../lib/codemirror"], mod);
+  else // Plain browser env
+    mod(CodeMirror);
+})(function(CodeMirror) {
+  "use strict";
+
+  CodeMirror.defineOption("styleSelectedText", false, function(cm, val, old) {
+    var prev = old && old != CodeMirror.Init;
+    if (val && !prev) {
+      cm.state.markedSelection = [];
+      cm.state.markedSelectionStyle = typeof val == "string" ? val : "CodeMirror-selectedtext";
+      reset(cm);
+      cm.on("cursorActivity", onCursorActivity);
+      cm.on("change", onChange);
+    } else if (!val && prev) {
+      cm.off("cursorActivity", onCursorActivity);
+      cm.off("change", onChange);
+      clear(cm);
+      cm.state.markedSelection = cm.state.markedSelectionStyle = null;
+    }
+  });
+
+  function onCursorActivity(cm) {
+    cm.operation(function() { update(cm); });
+  }
+
+  function onChange(cm) {
+    if (cm.state.markedSelection.length)
+      cm.operation(function() { clear(cm); });
+  }
+
+  var CHUNK_SIZE = 8;
+  var Pos = CodeMirror.Pos;
+  var cmp = CodeMirror.cmpPos;
+
+  function coverRange(cm, from, to, addAt) {
+    if (cmp(from, to) == 0) return;
+    var array = cm.state.markedSelection;
+    var cls = cm.state.markedSelectionStyle;
+    for (var line = from.line;;) {
+      var start = line == from.line ? from : Pos(line, 0);
+      var endLine = line + CHUNK_SIZE, atEnd = endLine >= to.line;
+      var end = atEnd ? to : Pos(endLine, 0);
+      var mark = cm.markText(start, end, {className: cls});
+      if (addAt == null) array.push(mark);
+      else array.splice(addAt++, 0, mark);
+      if (atEnd) break;
+      line = endLine;
+    }
+  }
+
+  function clear(cm) {
+    var array = cm.state.markedSelection;
+    for (var i = 0; i < array.length; ++i) array[i].clear();
+    array.length = 0;
+  }
+
+  function reset(cm) {
+    clear(cm);
+    var ranges = cm.listSelections();
+    for (var i = 0; i < ranges.length; i++)
+      coverRange(cm, ranges[i].from(), ranges[i].to());
+  }
+
+  function update(cm) {
+    if (!cm.somethingSelected()) return clear(cm);
+    if (cm.listSelections().length > 1) return reset(cm);
+
+    var from = cm.getCursor("start"), to = cm.getCursor("end");
+
+    var array = cm.state.markedSelection;
+    if (!array.length) return coverRange(cm, from, to);
+
+    var coverStart = array[0].find(), coverEnd = array[array.length - 1].find();
+    if (!coverStart || !coverEnd || to.line - from.line < CHUNK_SIZE ||
+        cmp(from, coverEnd.to) >= 0 || cmp(to, coverStart.from) <= 0)
+      return reset(cm);
+
+    while (cmp(from, coverStart.from) > 0) {
+      array.shift().clear();
+      coverStart = array[0].find();
+    }
+    if (cmp(from, coverStart.from) < 0) {
+      if (coverStart.to.line - from.line < CHUNK_SIZE) {
+        array.shift().clear();
+        coverRange(cm, from, coverStart.to, 0);
+      } else {
+        coverRange(cm, from, coverStart.from, 0);
+      }
+    }
+
+    while (cmp(to, coverEnd.to) < 0) {
+      array.pop().clear();
+      coverEnd = array[array.length - 1].find();
+    }
+    if (cmp(to, coverEnd.to) > 0) {
+      if (to.line - coverEnd.from.line < CHUNK_SIZE) {
+        array.pop().clear();
+        coverRange(cm, coverEnd.from, to);
+      } else {
+        coverRange(cm, coverEnd.to, to);
+      }
+    }
+  }
+});
index f509b1d..e74f0dd 100644 (file)
     <script src="External/CodeMirror/htmlmixed.js"></script>
     <script src="External/CodeMirror/javascript.js"></script>
     <script src="External/CodeMirror/livescript.js"></script>
+    <script src="External/CodeMirror/mark-selection.js"></script>
     <script src="External/CodeMirror/matchbrackets.js"></script>
     <script src="External/CodeMirror/overlay.js"></script>
     <script src="External/CodeMirror/placeholder.js"></script>
index 5ffb23d..12290e2 100644 (file)
     border-bottom: 1px dotted hsl(78, 18%, 58%);
 }
 
-.text-editor > .CodeMirror .execution-range-highlight {
+.text-editor > .CodeMirror .execution-range-highlight:not(.CodeMirror-selectedtext) {
     background-color: hsl(90, 30%, 82%);
 }
 
index b2c6d78..185c359 100644 (file)
@@ -39,7 +39,8 @@ WebInspector.TextEditor = class TextEditor extends WebInspector.View
             lineNumbers: true,
             lineWrapping: false,
             matchBrackets: true,
-            autoCloseBrackets: true
+            autoCloseBrackets: true,
+            styleSelectedText: true,
         });
 
         this._codeMirror.on("change", this._contentChanged.bind(this));