| Index: third_party/WebKit/Source/devtools/front_end/source_frame/SourcesTextEditor.js
|
| diff --git a/third_party/WebKit/Source/devtools/front_end/source_frame/SourcesTextEditor.js b/third_party/WebKit/Source/devtools/front_end/source_frame/SourcesTextEditor.js
|
| index 663760dd138308b51d67997ff084fc2db0056c68..399048116797147f49a4c8e698e7050b82b7e6df 100644
|
| --- a/third_party/WebKit/Source/devtools/front_end/source_frame/SourcesTextEditor.js
|
| +++ b/third_party/WebKit/Source/devtools/front_end/source_frame/SourcesTextEditor.js
|
| @@ -1,620 +1,620 @@
|
| // Copyright (c) 2016 The Chromium Authors. All rights reserved.
|
| // Use of this source code is governed by a BSD-style license that can be
|
| // found in the LICENSE file.
|
| -
|
| /**
|
| - * @constructor
|
| - * @extends {WebInspector.CodeMirrorTextEditor}
|
| - * @param {!WebInspector.SourcesTextEditorDelegate} delegate
|
| + * @unrestricted
|
| */
|
| -WebInspector.SourcesTextEditor = function(delegate)
|
| -{
|
| - WebInspector.CodeMirrorTextEditor.call(this, {
|
| - lineNumbers: true,
|
| - lineWrapping: false,
|
| - bracketMatchingSetting: WebInspector.moduleSetting("textEditorBracketMatching"),
|
| +WebInspector.SourcesTextEditor = class extends WebInspector.CodeMirrorTextEditor {
|
| + /**
|
| + * @param {!WebInspector.SourcesTextEditorDelegate} delegate
|
| + */
|
| + constructor(delegate) {
|
| + super({
|
| + lineNumbers: true,
|
| + lineWrapping: false,
|
| + bracketMatchingSetting: WebInspector.moduleSetting('textEditorBracketMatching'),
|
| });
|
|
|
| - this.codeMirror().addKeyMap({
|
| - "Enter": "smartNewlineAndIndent",
|
| - "Esc": "sourcesDismiss"
|
| - });
|
| + this.codeMirror().addKeyMap({'Enter': 'smartNewlineAndIndent', 'Esc': 'sourcesDismiss'});
|
|
|
| this._delegate = delegate;
|
|
|
| - this.codeMirror().on("changes", this._fireTextChanged.bind(this));
|
| - this.codeMirror().on("cursorActivity", this._cursorActivity.bind(this));
|
| - this.codeMirror().on("gutterClick", this._gutterClick.bind(this));
|
| - this.codeMirror().on("scroll", this._scroll.bind(this));
|
| - this.codeMirror().on("focus", this._focus.bind(this));
|
| - this.codeMirror().on("blur", this._blur.bind(this));
|
| - this.codeMirror().on("beforeSelectionChange", this._fireBeforeSelectionChanged.bind(this));
|
| - this.element.addEventListener("contextmenu", this._contextMenu.bind(this), false);
|
| + this.codeMirror().on('changes', this._fireTextChanged.bind(this));
|
| + this.codeMirror().on('cursorActivity', this._cursorActivity.bind(this));
|
| + this.codeMirror().on('gutterClick', this._gutterClick.bind(this));
|
| + this.codeMirror().on('scroll', this._scroll.bind(this));
|
| + this.codeMirror().on('focus', this._focus.bind(this));
|
| + this.codeMirror().on('blur', this._blur.bind(this));
|
| + this.codeMirror().on('beforeSelectionChange', this._fireBeforeSelectionChanged.bind(this));
|
| + this.element.addEventListener('contextmenu', this._contextMenu.bind(this), false);
|
|
|
| - this._blockIndentController = new WebInspector.SourcesTextEditor.BlockIndentController(this.codeMirror());
|
| + this.codeMirror().addKeyMap(WebInspector.SourcesTextEditor._BlockIndentController);
|
| this._tokenHighlighter = new WebInspector.SourcesTextEditor.TokenHighlighter(this, this.codeMirror());
|
|
|
| /** @type {!Array<string>} */
|
| - this._gutters = ["CodeMirror-linenumbers"];
|
| - this.codeMirror().setOption("gutters", this._gutters.slice());
|
| + this._gutters = ['CodeMirror-linenumbers'];
|
| + this.codeMirror().setOption('gutters', this._gutters.slice());
|
|
|
| - this.codeMirror().setOption("electricChars", false);
|
| - this.codeMirror().setOption("smartIndent", false);
|
| + this.codeMirror().setOption('electricChars', false);
|
| + this.codeMirror().setOption('smartIndent', false);
|
|
|
| /**
|
| * @this {WebInspector.SourcesTextEditor}
|
| */
|
| - function updateAnticipateJumpFlag(value)
|
| - {
|
| - this._isHandlingMouseDownEvent = value;
|
| + function updateAnticipateJumpFlag(value) {
|
| + this._isHandlingMouseDownEvent = value;
|
| }
|
|
|
| - this.element.addEventListener("mousedown", updateAnticipateJumpFlag.bind(this, true), true);
|
| - this.element.addEventListener("mousedown", updateAnticipateJumpFlag.bind(this, false), false);
|
| - WebInspector.moduleSetting("textEditorIndent").addChangeListener(this._onUpdateEditorIndentation, this);
|
| - WebInspector.moduleSetting("textEditorAutoDetectIndent").addChangeListener(this._onUpdateEditorIndentation, this);
|
| - WebInspector.moduleSetting("showWhitespacesInEditor").addChangeListener(this._updateWhitespace, this);
|
| + this.element.addEventListener('mousedown', updateAnticipateJumpFlag.bind(this, true), true);
|
| + this.element.addEventListener('mousedown', updateAnticipateJumpFlag.bind(this, false), false);
|
| + WebInspector.moduleSetting('textEditorIndent').addChangeListener(this._onUpdateEditorIndentation, this);
|
| + WebInspector.moduleSetting('textEditorAutoDetectIndent').addChangeListener(this._onUpdateEditorIndentation, this);
|
| + WebInspector.moduleSetting('showWhitespacesInEditor').addChangeListener(this._updateWhitespace, this);
|
|
|
| this._onUpdateEditorIndentation();
|
| this._setupWhitespaceHighlight();
|
| -};
|
| -WebInspector.SourcesTextEditor.prototype = {
|
| - /**
|
| - * @return {boolean}
|
| - */
|
| - _isSearchActive: function()
|
| - {
|
| - return !!this._tokenHighlighter.highlightedRegex();
|
| - },
|
| -
|
| - /**
|
| - * @override
|
| - * @param {number} lineNumber
|
| - */
|
| - scrollToLine: function(lineNumber)
|
| - {
|
| - WebInspector.CodeMirrorTextEditor.prototype.scrollToLine.call(this, lineNumber);
|
| - this._scroll();
|
| - },
|
| -
|
| - /**
|
| - * @param {!RegExp} regex
|
| - * @param {?WebInspector.TextRange} range
|
| - */
|
| - highlightSearchResults: function(regex, range)
|
| - {
|
| - /**
|
| - * @this {WebInspector.CodeMirrorTextEditor}
|
| - */
|
| - function innerHighlightRegex()
|
| - {
|
| - if (range) {
|
| - this.scrollLineIntoView(range.startLine);
|
| - if (range.endColumn > WebInspector.CodeMirrorTextEditor.maxHighlightLength)
|
| - this.setSelection(range);
|
| - else
|
| - this.setSelection(WebInspector.TextRange.createFromLocation(range.startLine, range.startColumn));
|
| - }
|
| - this._tokenHighlighter.highlightSearchResults(regex, range);
|
| - }
|
| -
|
| - if (!this._selectionBeforeSearch)
|
| - this._selectionBeforeSearch = this.selection();
|
| -
|
| - this.codeMirror().operation(innerHighlightRegex.bind(this));
|
| - },
|
| -
|
| - cancelSearchResultsHighlight: function()
|
| - {
|
| - this.codeMirror().operation(this._tokenHighlighter.highlightSelectedTokens.bind(this._tokenHighlighter));
|
| -
|
| - if (this._selectionBeforeSearch) {
|
| - this._reportJump(this._selectionBeforeSearch, this.selection());
|
| - delete this._selectionBeforeSearch;
|
| - }
|
| - },
|
| -
|
| - /**
|
| - * @param {!Object} highlightDescriptor
|
| - */
|
| - removeHighlight: function(highlightDescriptor)
|
| - {
|
| - highlightDescriptor.clear();
|
| - },
|
| -
|
| - /**
|
| - * @param {!WebInspector.TextRange} range
|
| - * @param {string} cssClass
|
| - * @return {!Object}
|
| - */
|
| - highlightRange: function(range, cssClass)
|
| - {
|
| - cssClass = "CodeMirror-persist-highlight " + cssClass;
|
| - var pos = WebInspector.CodeMirrorUtils.toPos(range);
|
| - ++pos.end.ch;
|
| - return this.codeMirror().markText(pos.start, pos.end, {
|
| - className: cssClass,
|
| - startStyle: cssClass + "-start",
|
| - endStyle: cssClass + "-end"
|
| - });
|
| - },
|
| -
|
| - /**
|
| - * @param {number} lineNumber
|
| - * @param {boolean} disabled
|
| - * @param {boolean} conditional
|
| - */
|
| - addBreakpoint: function(lineNumber, disabled, conditional)
|
| - {
|
| - if (lineNumber < 0 || lineNumber >= this.codeMirror().lineCount())
|
| - return;
|
| -
|
| - var className = "cm-breakpoint" + (conditional ? " cm-breakpoint-conditional" : "") + (disabled ? " cm-breakpoint-disabled" : "");
|
| - this.codeMirror().addLineClass(lineNumber, "wrap", className);
|
| - },
|
| + }
|
|
|
| - /**
|
| - * @param {number} lineNumber
|
| - */
|
| - removeBreakpoint: function(lineNumber)
|
| - {
|
| - if (lineNumber < 0 || lineNumber >= this.codeMirror().lineCount())
|
| - return;
|
| -
|
| - var wrapClasses = this.codeMirror().getLineHandle(lineNumber).wrapClass;
|
| - if (!wrapClasses)
|
| - return;
|
| -
|
| - var classes = wrapClasses.split(" ");
|
| - for (var i = 0; i < classes.length; ++i) {
|
| - if (classes[i].startsWith("cm-breakpoint"))
|
| - this.codeMirror().removeLineClass(lineNumber, "wrap", classes[i]);
|
| - }
|
| - },
|
| -
|
| - /**
|
| - * @param {string} type
|
| - * @param {boolean} leftToNumbers
|
| - */
|
| - installGutter: function(type, leftToNumbers)
|
| - {
|
| - if (this._gutters.indexOf(type) !== -1)
|
| - return;
|
| -
|
| - if (leftToNumbers)
|
| - this._gutters.unshift(type);
|
| + /**
|
| + * @param {!Array.<string>} lines
|
| + * @return {string}
|
| + */
|
| + static _guessIndentationLevel(lines) {
|
| + var tabRegex = /^\t+/;
|
| + var tabLines = 0;
|
| + var indents = {};
|
| + for (var lineNumber = 0; lineNumber < lines.length; ++lineNumber) {
|
| + var text = lines[lineNumber];
|
| + if (text.length === 0 || !WebInspector.TextUtils.isSpaceChar(text[0]))
|
| + continue;
|
| + if (tabRegex.test(text)) {
|
| + ++tabLines;
|
| + continue;
|
| + }
|
| + var i = 0;
|
| + while (i < text.length && WebInspector.TextUtils.isSpaceChar(text[i]))
|
| + ++i;
|
| + if (i % 2 !== 0)
|
| + continue;
|
| + indents[i] = 1 + (indents[i] || 0);
|
| + }
|
| + var linesCountPerIndentThreshold = 3 * lines.length / 100;
|
| + if (tabLines && tabLines > linesCountPerIndentThreshold)
|
| + return '\t';
|
| + var minimumIndent = Infinity;
|
| + for (var i in indents) {
|
| + if (indents[i] < linesCountPerIndentThreshold)
|
| + continue;
|
| + var indent = parseInt(i, 10);
|
| + if (minimumIndent > indent)
|
| + minimumIndent = indent;
|
| + }
|
| + if (minimumIndent === Infinity)
|
| + return WebInspector.moduleSetting('textEditorIndent').get();
|
| + return ' '.repeat(minimumIndent);
|
| + }
|
| +
|
| + /**
|
| + * @return {boolean}
|
| + */
|
| + _isSearchActive() {
|
| + return !!this._tokenHighlighter.highlightedRegex();
|
| + }
|
| +
|
| + /**
|
| + * @override
|
| + * @param {number} lineNumber
|
| + */
|
| + scrollToLine(lineNumber) {
|
| + super.scrollToLine(lineNumber);
|
| + this._scroll();
|
| + }
|
| +
|
| + /**
|
| + * @param {!RegExp} regex
|
| + * @param {?WebInspector.TextRange} range
|
| + */
|
| + highlightSearchResults(regex, range) {
|
| + /**
|
| + * @this {WebInspector.CodeMirrorTextEditor}
|
| + */
|
| + function innerHighlightRegex() {
|
| + if (range) {
|
| + this.scrollLineIntoView(range.startLine);
|
| + if (range.endColumn > WebInspector.CodeMirrorTextEditor.maxHighlightLength)
|
| + this.setSelection(range);
|
| else
|
| - this._gutters.push(type);
|
| -
|
| - this.codeMirror().setOption("gutters", this._gutters.slice());
|
| - this.refresh();
|
| - },
|
| -
|
| - /**
|
| - * @param {string} type
|
| - */
|
| - uninstallGutter: function(type)
|
| - {
|
| - var index = this._gutters.indexOf(type);
|
| - if (index === -1)
|
| - return;
|
| - this._gutters.splice(index,1);
|
| - this.codeMirror().setOption("gutters", this._gutters.slice());
|
| - this.refresh();
|
| - },
|
| -
|
| - /**
|
| - * @param {number} lineNumber
|
| - * @param {string} type
|
| - * @param {?Element} element
|
| - */
|
| - setGutterDecoration: function(lineNumber, type, element)
|
| - {
|
| - console.assert(this._gutters.indexOf(type) !== -1, "Cannot decorate unexisting gutter.");
|
| - this.codeMirror().setGutterMarker(lineNumber, type, element);
|
| - },
|
| -
|
| - /**
|
| - * @param {number} lineNumber
|
| - * @param {number} columnNumber
|
| - */
|
| - setExecutionLocation: function(lineNumber, columnNumber)
|
| - {
|
| - this.clearPositionHighlight();
|
| -
|
| - this._executionLine = this.codeMirror().getLineHandle(lineNumber);
|
| - if (!this._executionLine)
|
| - return;
|
| -
|
| - this.codeMirror().addLineClass(this._executionLine, "wrap", "cm-execution-line");
|
| - this._executionLineTailMarker = this.codeMirror().markText({ line: lineNumber, ch: columnNumber }, { line: lineNumber, ch: this.codeMirror().getLine(lineNumber).length }, { className: "cm-execution-line-tail" });
|
| - },
|
| -
|
| - clearExecutionLine: function()
|
| - {
|
| - this.clearPositionHighlight();
|
| -
|
| - if (this._executionLine)
|
| - this.codeMirror().removeLineClass(this._executionLine, "wrap", "cm-execution-line");
|
| - delete this._executionLine;
|
| -
|
| - if (this._executionLineTailMarker)
|
| - this._executionLineTailMarker.clear();
|
| - delete this._executionLineTailMarker;
|
| - },
|
| -
|
| - /**
|
| - * @param {number} lineNumber
|
| - * @param {string} className
|
| - * @param {boolean} toggled
|
| - */
|
| - toggleLineClass: function(lineNumber, className, toggled)
|
| - {
|
| - if (this.hasLineClass(lineNumber, className) === toggled)
|
| - return;
|
| -
|
| - var lineHandle = this.codeMirror().getLineHandle(lineNumber);
|
| - if (!lineHandle)
|
| - return;
|
| -
|
| - if (toggled) {
|
| - this.codeMirror().addLineClass(lineHandle, "gutter", className);
|
| - this.codeMirror().addLineClass(lineHandle, "wrap", className);
|
| - } else {
|
| - this.codeMirror().removeLineClass(lineHandle, "gutter", className);
|
| - this.codeMirror().removeLineClass(lineHandle, "wrap", className);
|
| - }
|
| - },
|
| -
|
| - /**
|
| - * @param {number} lineNumber
|
| - * @param {string} className
|
| - * @return {boolean}
|
| - */
|
| - hasLineClass: function(lineNumber, className)
|
| - {
|
| - var lineInfo = this.codeMirror().lineInfo(lineNumber);
|
| - var wrapClass = lineInfo.wrapClass || "";
|
| - var classNames = wrapClass.split(" ");
|
| - return classNames.indexOf(className) !== -1;
|
| - },
|
| -
|
| - _gutterClick: function(instance, lineNumber, gutter, event)
|
| - {
|
| - this.dispatchEventToListeners(WebInspector.SourcesTextEditor.Events.GutterClick, { lineNumber: lineNumber, event: event });
|
| - },
|
| -
|
| - _contextMenu: function(event)
|
| - {
|
| - var contextMenu = new WebInspector.ContextMenu(event);
|
| - event.consume(true); // Consume event now to prevent document from handling the async menu
|
| - var target = event.target.enclosingNodeOrSelfWithClass("CodeMirror-gutter-elt");
|
| - var promise;
|
| - if (target) {
|
| - promise = this._delegate.populateLineGutterContextMenu(contextMenu, parseInt(target.textContent, 10) - 1);
|
| - } else {
|
| - var textSelection = this.selection();
|
| - promise = this._delegate.populateTextAreaContextMenu(contextMenu, textSelection.startLine, textSelection.startColumn);
|
| - }
|
| - promise.then(showAsync.bind(this));
|
| -
|
| - /**
|
| - * @this {WebInspector.SourcesTextEditor}
|
| - */
|
| - function showAsync()
|
| - {
|
| - contextMenu.appendApplicableItems(this);
|
| - contextMenu.show();
|
| - }
|
| - },
|
| -
|
| - /**
|
| - * @override
|
| - * @param {!WebInspector.TextRange} range
|
| - * @param {string} text
|
| - * @param {string=} origin
|
| - * @return {!WebInspector.TextRange}
|
| - */
|
| - editRange: function(range, text, origin)
|
| - {
|
| - var newRange = WebInspector.CodeMirrorTextEditor.prototype.editRange.call(this, range, text, origin);
|
| - this.dispatchEventToListeners(WebInspector.SourcesTextEditor.Events.TextChanged, { oldRange: range, newRange: newRange });
|
| -
|
| - if (WebInspector.moduleSetting("textEditorAutoDetectIndent").get())
|
| - this._onUpdateEditorIndentation();
|
| -
|
| - return newRange;
|
| - },
|
| -
|
| - _onUpdateEditorIndentation: function()
|
| - {
|
| - this._setEditorIndentation(WebInspector.CodeMirrorUtils.pullLines(this.codeMirror(), WebInspector.SourcesTextEditor.LinesToScanForIndentationGuessing));
|
| - },
|
| -
|
| - /**
|
| - * @param {!Array.<string>} lines
|
| - */
|
| - _setEditorIndentation: function(lines)
|
| - {
|
| - var extraKeys = {};
|
| - var indent = WebInspector.moduleSetting("textEditorIndent").get();
|
| - if (WebInspector.moduleSetting("textEditorAutoDetectIndent").get())
|
| - indent = WebInspector.SourcesTextEditor._guessIndentationLevel(lines);
|
| -
|
| - if (indent === WebInspector.TextUtils.Indent.TabCharacter) {
|
| - this.codeMirror().setOption("indentWithTabs", true);
|
| - this.codeMirror().setOption("indentUnit", 4);
|
| - } else {
|
| - this.codeMirror().setOption("indentWithTabs", false);
|
| - this.codeMirror().setOption("indentUnit", indent.length);
|
| - extraKeys.Tab = function(codeMirror)
|
| - {
|
| - if (codeMirror.somethingSelected())
|
| - return CodeMirror.Pass;
|
| - var pos = codeMirror.getCursor("head");
|
| - codeMirror.replaceRange(indent.substring(pos.ch % indent.length), codeMirror.getCursor());
|
| - };
|
| - }
|
| -
|
| - this.codeMirror().setOption("extraKeys", extraKeys);
|
| - this._indentationLevel = indent;
|
| - },
|
| -
|
| - /**
|
| - * @return {string}
|
| - */
|
| - indent: function()
|
| - {
|
| - return this._indentationLevel;
|
| - },
|
| -
|
| - _onAutoAppendedSpaces: function()
|
| - {
|
| - this._autoAppendedSpaces = this._autoAppendedSpaces || [];
|
| -
|
| - for (var i = 0; i < this._autoAppendedSpaces.length; ++i) {
|
| - var position = this._autoAppendedSpaces[i].resolve();
|
| - if (!position)
|
| - continue;
|
| - var line = this.line(position.lineNumber);
|
| - if (line.length === position.columnNumber && WebInspector.TextUtils.lineIndent(line).length === line.length)
|
| - this.codeMirror().replaceRange("", new CodeMirror.Pos(position.lineNumber, 0), new CodeMirror.Pos(position.lineNumber, position.columnNumber));
|
| - }
|
| -
|
| - this._autoAppendedSpaces = [];
|
| - var selections = this.selections();
|
| - for (var i = 0; i < selections.length; ++i) {
|
| - var selection = selections[i];
|
| - this._autoAppendedSpaces.push(this.textEditorPositionHandle(selection.startLine, selection.startColumn));
|
| - }
|
| - },
|
| -
|
| - /**
|
| - * @param {!CodeMirror} codeMirror
|
| - * @param {!Array.<!CodeMirror.ChangeObject>} changes
|
| - */
|
| - _fireTextChanged: function(codeMirror, changes)
|
| - {
|
| - if (!changes.length || this._muteTextChangedEvent)
|
| - return;
|
| - var edits = [];
|
| - var currentEdit;
|
| -
|
| - for (var changeIndex = 0; changeIndex < changes.length; ++changeIndex) {
|
| - var changeObject = changes[changeIndex];
|
| - var edit = WebInspector.CodeMirrorUtils.changeObjectToEditOperation(changeObject);
|
| - if (currentEdit && edit.oldRange.equal(currentEdit.newRange)) {
|
| - currentEdit.newRange = edit.newRange;
|
| - } else {
|
| - currentEdit = edit;
|
| - edits.push(currentEdit);
|
| - }
|
| - }
|
| -
|
| - for (var i = 0; i < edits.length; ++i)
|
| - this.dispatchEventToListeners(WebInspector.SourcesTextEditor.Events.TextChanged, edits[i]);
|
| - },
|
| -
|
| - _cursorActivity: function()
|
| - {
|
| - if (!this._isSearchActive())
|
| - this.codeMirror().operation(this._tokenHighlighter.highlightSelectedTokens.bind(this._tokenHighlighter));
|
| -
|
| - var start = this.codeMirror().getCursor("anchor");
|
| - var end = this.codeMirror().getCursor("head");
|
| - this.dispatchEventToListeners(WebInspector.SourcesTextEditor.Events.SelectionChanged, WebInspector.CodeMirrorUtils.toRange(start, end));
|
| - },
|
| + this.setSelection(WebInspector.TextRange.createFromLocation(range.startLine, range.startColumn));
|
| + }
|
| + this._tokenHighlighter.highlightSearchResults(regex, range);
|
| + }
|
|
|
| - /**
|
| - * @param {?WebInspector.TextRange} from
|
| - * @param {?WebInspector.TextRange} to
|
| - */
|
| - _reportJump: function(from, to)
|
| - {
|
| - if (from && to && from.equal(to))
|
| - return;
|
| - this.dispatchEventToListeners(WebInspector.SourcesTextEditor.Events.JumpHappened, { from: from, to: to });
|
| - },
|
| -
|
| - _scroll: function()
|
| - {
|
| - var topmostLineNumber = this.codeMirror().lineAtHeight(this.codeMirror().getScrollInfo().top, "local");
|
| - this.dispatchEventToListeners(WebInspector.SourcesTextEditor.Events.ScrollChanged, topmostLineNumber);
|
| - },
|
| -
|
| - _focus: function()
|
| - {
|
| - this.dispatchEventToListeners(WebInspector.SourcesTextEditor.Events.EditorFocused);
|
| - },
|
| -
|
| - _blur: function()
|
| - {
|
| - this.dispatchEventToListeners(WebInspector.SourcesTextEditor.Events.EditorBlurred);
|
| - },
|
| + if (!this._selectionBeforeSearch)
|
| + this._selectionBeforeSearch = this.selection();
|
|
|
| - /**
|
| - * @param {!CodeMirror} codeMirror
|
| - * @param {{ranges: !Array.<{head: !CodeMirror.Pos, anchor: !CodeMirror.Pos}>}} selection
|
| - */
|
| - _fireBeforeSelectionChanged: function(codeMirror, selection)
|
| - {
|
| - if (!this._isHandlingMouseDownEvent)
|
| - return;
|
| - if (!selection.ranges.length)
|
| - return;
|
| + this.codeMirror().operation(innerHighlightRegex.bind(this));
|
| + }
|
|
|
| - var primarySelection = selection.ranges[0];
|
| - this._reportJump(this.selection(), WebInspector.CodeMirrorUtils.toRange(primarySelection.anchor, primarySelection.head));
|
| - },
|
| + cancelSearchResultsHighlight() {
|
| + this.codeMirror().operation(this._tokenHighlighter.highlightSelectedTokens.bind(this._tokenHighlighter));
|
|
|
| - /**
|
| - * @override
|
| - */
|
| - dispose: function()
|
| - {
|
| - WebInspector.CodeMirrorTextEditor.prototype.dispose.call(this);
|
| - WebInspector.moduleSetting("textEditorIndent").removeChangeListener(this._onUpdateEditorIndentation, this);
|
| - WebInspector.moduleSetting("textEditorAutoDetectIndent").removeChangeListener(this._onUpdateEditorIndentation, this);
|
| - WebInspector.moduleSetting("showWhitespacesInEditor").removeChangeListener(this._updateWhitespace, this);
|
| - },
|
| -
|
| - /**
|
| - * @override
|
| - * @param {string} text
|
| - */
|
| - setText: function(text)
|
| - {
|
| - this._muteTextChangedEvent = true;
|
| - this._setEditorIndentation(text.split("\n").slice(0, WebInspector.SourcesTextEditor.LinesToScanForIndentationGuessing));
|
| - WebInspector.CodeMirrorTextEditor.prototype.setText.call(this, text);
|
| - delete this._muteTextChangedEvent;
|
| - },
|
| -
|
| - /**
|
| - * @override
|
| - * @param {string} mimeType
|
| - * @return {!Promise}
|
| - */
|
| - setMimeType: function(mimeType)
|
| - {
|
| - this._mimeType = mimeType;
|
| - return WebInspector.CodeMirrorTextEditor.prototype.setMimeType.call(this, mimeType)
|
| - .then(() => this._codeMirror.setOption("mode", this._applyWhitespaceMimetype(mimeType)));
|
| - },
|
| -
|
| - _updateWhitespace: function()
|
| - {
|
| - if (this._mimeType)
|
| - this.setMimeType(this._mimeType);
|
| - },
|
| + if (this._selectionBeforeSearch) {
|
| + this._reportJump(this._selectionBeforeSearch, this.selection());
|
| + delete this._selectionBeforeSearch;
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * @param {!Object} highlightDescriptor
|
| + */
|
| + removeHighlight(highlightDescriptor) {
|
| + highlightDescriptor.clear();
|
| + }
|
| +
|
| + /**
|
| + * @param {!WebInspector.TextRange} range
|
| + * @param {string} cssClass
|
| + * @return {!Object}
|
| + */
|
| + highlightRange(range, cssClass) {
|
| + cssClass = 'CodeMirror-persist-highlight ' + cssClass;
|
| + var pos = WebInspector.CodeMirrorUtils.toPos(range);
|
| + ++pos.end.ch;
|
| + return this.codeMirror().markText(
|
| + pos.start, pos.end, {className: cssClass, startStyle: cssClass + '-start', endStyle: cssClass + '-end'});
|
| + }
|
| +
|
| + /**
|
| + * @param {number} lineNumber
|
| + * @param {boolean} disabled
|
| + * @param {boolean} conditional
|
| + */
|
| + addBreakpoint(lineNumber, disabled, conditional) {
|
| + if (lineNumber < 0 || lineNumber >= this.codeMirror().lineCount())
|
| + return;
|
| +
|
| + var className = 'cm-breakpoint' + (conditional ? ' cm-breakpoint-conditional' : '') +
|
| + (disabled ? ' cm-breakpoint-disabled' : '');
|
| + this.codeMirror().addLineClass(lineNumber, 'wrap', className);
|
| + }
|
| +
|
| + /**
|
| + * @param {number} lineNumber
|
| + */
|
| + removeBreakpoint(lineNumber) {
|
| + if (lineNumber < 0 || lineNumber >= this.codeMirror().lineCount())
|
| + return;
|
| +
|
| + var wrapClasses = this.codeMirror().getLineHandle(lineNumber).wrapClass;
|
| + if (!wrapClasses)
|
| + return;
|
| +
|
| + var classes = wrapClasses.split(' ');
|
| + for (var i = 0; i < classes.length; ++i) {
|
| + if (classes[i].startsWith('cm-breakpoint'))
|
| + this.codeMirror().removeLineClass(lineNumber, 'wrap', classes[i]);
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * @param {string} type
|
| + * @param {boolean} leftToNumbers
|
| + */
|
| + installGutter(type, leftToNumbers) {
|
| + if (this._gutters.indexOf(type) !== -1)
|
| + return;
|
| +
|
| + if (leftToNumbers)
|
| + this._gutters.unshift(type);
|
| + else
|
| + this._gutters.push(type);
|
| +
|
| + this.codeMirror().setOption('gutters', this._gutters.slice());
|
| + this.refresh();
|
| + }
|
| +
|
| + /**
|
| + * @param {string} type
|
| + */
|
| + uninstallGutter(type) {
|
| + var index = this._gutters.indexOf(type);
|
| + if (index === -1)
|
| + return;
|
| + this._gutters.splice(index, 1);
|
| + this.codeMirror().setOption('gutters', this._gutters.slice());
|
| + this.refresh();
|
| + }
|
| +
|
| + /**
|
| + * @param {number} lineNumber
|
| + * @param {string} type
|
| + * @param {?Element} element
|
| + */
|
| + setGutterDecoration(lineNumber, type, element) {
|
| + console.assert(this._gutters.indexOf(type) !== -1, 'Cannot decorate unexisting gutter.');
|
| + this.codeMirror().setGutterMarker(lineNumber, type, element);
|
| + }
|
| +
|
| + /**
|
| + * @param {number} lineNumber
|
| + * @param {number} columnNumber
|
| + */
|
| + setExecutionLocation(lineNumber, columnNumber) {
|
| + this.clearPositionHighlight();
|
| +
|
| + this._executionLine = this.codeMirror().getLineHandle(lineNumber);
|
| + if (!this._executionLine)
|
| + return;
|
| +
|
| + this.codeMirror().addLineClass(this._executionLine, 'wrap', 'cm-execution-line');
|
| + this._executionLineTailMarker = this.codeMirror().markText(
|
| + {line: lineNumber, ch: columnNumber}, {line: lineNumber, ch: this.codeMirror().getLine(lineNumber).length},
|
| + {className: 'cm-execution-line-tail'});
|
| + }
|
| +
|
| + clearExecutionLine() {
|
| + this.clearPositionHighlight();
|
| +
|
| + if (this._executionLine)
|
| + this.codeMirror().removeLineClass(this._executionLine, 'wrap', 'cm-execution-line');
|
| + delete this._executionLine;
|
| +
|
| + if (this._executionLineTailMarker)
|
| + this._executionLineTailMarker.clear();
|
| + delete this._executionLineTailMarker;
|
| + }
|
| +
|
| + /**
|
| + * @param {number} lineNumber
|
| + * @param {string} className
|
| + * @param {boolean} toggled
|
| + */
|
| + toggleLineClass(lineNumber, className, toggled) {
|
| + if (this.hasLineClass(lineNumber, className) === toggled)
|
| + return;
|
| +
|
| + var lineHandle = this.codeMirror().getLineHandle(lineNumber);
|
| + if (!lineHandle)
|
| + return;
|
| +
|
| + if (toggled) {
|
| + this.codeMirror().addLineClass(lineHandle, 'gutter', className);
|
| + this.codeMirror().addLineClass(lineHandle, 'wrap', className);
|
| + } else {
|
| + this.codeMirror().removeLineClass(lineHandle, 'gutter', className);
|
| + this.codeMirror().removeLineClass(lineHandle, 'wrap', className);
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * @param {number} lineNumber
|
| + * @param {string} className
|
| + * @return {boolean}
|
| + */
|
| + hasLineClass(lineNumber, className) {
|
| + var lineInfo = this.codeMirror().lineInfo(lineNumber);
|
| + var wrapClass = lineInfo.wrapClass || '';
|
| + var classNames = wrapClass.split(' ');
|
| + return classNames.indexOf(className) !== -1;
|
| + }
|
| +
|
| + _gutterClick(instance, lineNumber, gutter, event) {
|
| + this.dispatchEventToListeners(
|
| + WebInspector.SourcesTextEditor.Events.GutterClick, {lineNumber: lineNumber, event: event});
|
| + }
|
| +
|
| + _contextMenu(event) {
|
| + var contextMenu = new WebInspector.ContextMenu(event);
|
| + event.consume(true); // Consume event now to prevent document from handling the async menu
|
| + var target = event.target.enclosingNodeOrSelfWithClass('CodeMirror-gutter-elt');
|
| + var promise;
|
| + if (target) {
|
| + promise = this._delegate.populateLineGutterContextMenu(contextMenu, parseInt(target.textContent, 10) - 1);
|
| + } else {
|
| + var textSelection = this.selection();
|
| + promise =
|
| + this._delegate.populateTextAreaContextMenu(contextMenu, textSelection.startLine, textSelection.startColumn);
|
| + }
|
| + promise.then(showAsync.bind(this));
|
|
|
| /**
|
| - * @param {string} mimeType
|
| - * @return {string}
|
| + * @this {WebInspector.SourcesTextEditor}
|
| */
|
| - _applyWhitespaceMimetype: function(mimeType)
|
| - {
|
| - this._setupWhitespaceHighlight();
|
| - var whitespaceMode = WebInspector.moduleSetting("showWhitespacesInEditor").get();
|
| - this.element.classList.toggle("show-whitespaces", whitespaceMode === "all");
|
| -
|
| - if (whitespaceMode === "all")
|
| - return this._allWhitespaceOverlayMode(mimeType);
|
| - else if (whitespaceMode === "trailing")
|
| - return this._trailingWhitespaceOverlayMode(mimeType);
|
| + function showAsync() {
|
| + contextMenu.appendApplicableItems(this);
|
| + contextMenu.show();
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * @override
|
| + * @param {!WebInspector.TextRange} range
|
| + * @param {string} text
|
| + * @param {string=} origin
|
| + * @return {!WebInspector.TextRange}
|
| + */
|
| + editRange(range, text, origin) {
|
| + var newRange = super.editRange(range, text, origin);
|
| + this.dispatchEventToListeners(
|
| + WebInspector.SourcesTextEditor.Events.TextChanged, {oldRange: range, newRange: newRange});
|
| +
|
| + if (WebInspector.moduleSetting('textEditorAutoDetectIndent').get())
|
| + this._onUpdateEditorIndentation();
|
| +
|
| + return newRange;
|
| + }
|
| +
|
| + _onUpdateEditorIndentation() {
|
| + this._setEditorIndentation(WebInspector.CodeMirrorUtils.pullLines(
|
| + this.codeMirror(), WebInspector.SourcesTextEditor.LinesToScanForIndentationGuessing));
|
| + }
|
| +
|
| + /**
|
| + * @param {!Array.<string>} lines
|
| + */
|
| + _setEditorIndentation(lines) {
|
| + var extraKeys = {};
|
| + var indent = WebInspector.moduleSetting('textEditorIndent').get();
|
| + if (WebInspector.moduleSetting('textEditorAutoDetectIndent').get())
|
| + indent = WebInspector.SourcesTextEditor._guessIndentationLevel(lines);
|
| +
|
| + if (indent === WebInspector.TextUtils.Indent.TabCharacter) {
|
| + this.codeMirror().setOption('indentWithTabs', true);
|
| + this.codeMirror().setOption('indentUnit', 4);
|
| + } else {
|
| + this.codeMirror().setOption('indentWithTabs', false);
|
| + this.codeMirror().setOption('indentUnit', indent.length);
|
| + extraKeys.Tab = function(codeMirror) {
|
| + if (codeMirror.somethingSelected())
|
| + return CodeMirror.Pass;
|
| + var pos = codeMirror.getCursor('head');
|
| + codeMirror.replaceRange(indent.substring(pos.ch % indent.length), codeMirror.getCursor());
|
| + };
|
| + }
|
|
|
| - return mimeType;
|
| - },
|
| + this.codeMirror().setOption('extraKeys', extraKeys);
|
| + this._indentationLevel = indent;
|
| + }
|
| +
|
| + /**
|
| + * @return {string}
|
| + */
|
| + indent() {
|
| + return this._indentationLevel;
|
| + }
|
| +
|
| + _onAutoAppendedSpaces() {
|
| + this._autoAppendedSpaces = this._autoAppendedSpaces || [];
|
| +
|
| + for (var i = 0; i < this._autoAppendedSpaces.length; ++i) {
|
| + var position = this._autoAppendedSpaces[i].resolve();
|
| + if (!position)
|
| + continue;
|
| + var line = this.line(position.lineNumber);
|
| + if (line.length === position.columnNumber && WebInspector.TextUtils.lineIndent(line).length === line.length)
|
| + this.codeMirror().replaceRange(
|
| + '', new CodeMirror.Pos(position.lineNumber, 0),
|
| + new CodeMirror.Pos(position.lineNumber, position.columnNumber));
|
| + }
|
|
|
| - /**
|
| - * @param {string} mimeType
|
| - * @return {string}
|
| - */
|
| - _allWhitespaceOverlayMode: function(mimeType)
|
| - {
|
| - var modeName = CodeMirror.mimeModes[mimeType] ? (CodeMirror.mimeModes[mimeType].name || CodeMirror.mimeModes[mimeType]) : CodeMirror.mimeModes["text/plain"];
|
| - modeName += "+all-whitespaces";
|
| - if (CodeMirror.modes[modeName])
|
| - return modeName;
|
| -
|
| - function modeConstructor(config, parserConfig)
|
| - {
|
| - function nextToken(stream)
|
| - {
|
| - if (stream.peek() === " ") {
|
| - var spaces = 0;
|
| - while (spaces < WebInspector.SourcesTextEditor.MaximumNumberOfWhitespacesPerSingleSpan && stream.peek() === " ") {
|
| - ++spaces;
|
| - stream.next();
|
| - }
|
| - return "whitespace whitespace-" + spaces;
|
| - }
|
| - while (!stream.eol() && stream.peek() !== " ")
|
| - stream.next();
|
| - return null;
|
| - }
|
| - var whitespaceMode = {
|
| - token: nextToken
|
| - };
|
| - return CodeMirror.overlayMode(CodeMirror.getMode(config, mimeType), whitespaceMode, false);
|
| - }
|
| - CodeMirror.defineMode(modeName, modeConstructor);
|
| - return modeName;
|
| - },
|
| + this._autoAppendedSpaces = [];
|
| + var selections = this.selections();
|
| + for (var i = 0; i < selections.length; ++i) {
|
| + var selection = selections[i];
|
| + this._autoAppendedSpaces.push(this.textEditorPositionHandle(selection.startLine, selection.startColumn));
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * @param {!CodeMirror} codeMirror
|
| + * @param {!Array.<!CodeMirror.ChangeObject>} changes
|
| + */
|
| + _fireTextChanged(codeMirror, changes) {
|
| + if (!changes.length || this._muteTextChangedEvent)
|
| + return;
|
| + var edits = [];
|
| + var currentEdit;
|
| +
|
| + for (var changeIndex = 0; changeIndex < changes.length; ++changeIndex) {
|
| + var changeObject = changes[changeIndex];
|
| + var edit = WebInspector.CodeMirrorUtils.changeObjectToEditOperation(changeObject);
|
| + if (currentEdit && edit.oldRange.equal(currentEdit.newRange)) {
|
| + currentEdit.newRange = edit.newRange;
|
| + } else {
|
| + currentEdit = edit;
|
| + edits.push(currentEdit);
|
| + }
|
| + }
|
|
|
| - /**
|
| - * @param {string} mimeType
|
| - * @return {string}
|
| - */
|
| - _trailingWhitespaceOverlayMode: function(mimeType)
|
| - {
|
| - var modeName = CodeMirror.mimeModes[mimeType] ? (CodeMirror.mimeModes[mimeType].name || CodeMirror.mimeModes[mimeType]) : CodeMirror.mimeModes["text/plain"];
|
| - modeName += "+trailing-whitespaces";
|
| - if (CodeMirror.modes[modeName])
|
| - return modeName;
|
| -
|
| - function modeConstructor(config, parserConfig)
|
| - {
|
| - function nextToken(stream)
|
| - {
|
| - var pos = stream.pos;
|
| - if (stream.match(/^\s+$/, true))
|
| - return true ? "trailing-whitespace" : null;
|
| - do {
|
| - stream.next();
|
| - } while (!stream.eol() && stream.peek() !== " ");
|
| - return null;
|
| - }
|
| - var whitespaceMode = {
|
| - token: nextToken
|
| - };
|
| - return CodeMirror.overlayMode(CodeMirror.getMode(config, mimeType), whitespaceMode, false);
|
| - }
|
| - CodeMirror.defineMode(modeName, modeConstructor);
|
| - return modeName;
|
| - },
|
| -
|
| - _setupWhitespaceHighlight: function()
|
| - {
|
| - var doc = this.element.ownerDocument;
|
| - if (doc._codeMirrorWhitespaceStyleInjected || !WebInspector.moduleSetting("showWhitespacesInEditor").get())
|
| - return;
|
| - doc._codeMirrorWhitespaceStyleInjected = true;
|
| - const classBase = ".show-whitespaces .CodeMirror .cm-whitespace-";
|
| - const spaceChar = "·";
|
| - var spaceChars = "";
|
| - var rules = "";
|
| - for (var i = 1; i <= WebInspector.SourcesTextEditor.MaximumNumberOfWhitespacesPerSingleSpan; ++i) {
|
| - spaceChars += spaceChar;
|
| - var rule = classBase + i + "::before { content: '" + spaceChars + "';}\n";
|
| - rules += rule;
|
| + for (var i = 0; i < edits.length; ++i)
|
| + this.dispatchEventToListeners(WebInspector.SourcesTextEditor.Events.TextChanged, edits[i]);
|
| + }
|
| +
|
| + _cursorActivity() {
|
| + if (!this._isSearchActive())
|
| + this.codeMirror().operation(this._tokenHighlighter.highlightSelectedTokens.bind(this._tokenHighlighter));
|
| +
|
| + var start = this.codeMirror().getCursor('anchor');
|
| + var end = this.codeMirror().getCursor('head');
|
| + this.dispatchEventToListeners(
|
| + WebInspector.SourcesTextEditor.Events.SelectionChanged, WebInspector.CodeMirrorUtils.toRange(start, end));
|
| + }
|
| +
|
| + /**
|
| + * @param {?WebInspector.TextRange} from
|
| + * @param {?WebInspector.TextRange} to
|
| + */
|
| + _reportJump(from, to) {
|
| + if (from && to && from.equal(to))
|
| + return;
|
| + this.dispatchEventToListeners(WebInspector.SourcesTextEditor.Events.JumpHappened, {from: from, to: to});
|
| + }
|
| +
|
| + _scroll() {
|
| + var topmostLineNumber = this.codeMirror().lineAtHeight(this.codeMirror().getScrollInfo().top, 'local');
|
| + this.dispatchEventToListeners(WebInspector.SourcesTextEditor.Events.ScrollChanged, topmostLineNumber);
|
| + }
|
| +
|
| + _focus() {
|
| + this.dispatchEventToListeners(WebInspector.SourcesTextEditor.Events.EditorFocused);
|
| + }
|
| +
|
| + _blur() {
|
| + this.dispatchEventToListeners(WebInspector.SourcesTextEditor.Events.EditorBlurred);
|
| + }
|
| +
|
| + /**
|
| + * @param {!CodeMirror} codeMirror
|
| + * @param {{ranges: !Array.<{head: !CodeMirror.Pos, anchor: !CodeMirror.Pos}>}} selection
|
| + */
|
| + _fireBeforeSelectionChanged(codeMirror, selection) {
|
| + if (!this._isHandlingMouseDownEvent)
|
| + return;
|
| + if (!selection.ranges.length)
|
| + return;
|
| +
|
| + var primarySelection = selection.ranges[0];
|
| + this._reportJump(
|
| + this.selection(), WebInspector.CodeMirrorUtils.toRange(primarySelection.anchor, primarySelection.head));
|
| + }
|
| +
|
| + /**
|
| + * @override
|
| + */
|
| + dispose() {
|
| + super.dispose();
|
| + WebInspector.moduleSetting('textEditorIndent').removeChangeListener(this._onUpdateEditorIndentation, this);
|
| + WebInspector.moduleSetting('textEditorAutoDetectIndent')
|
| + .removeChangeListener(this._onUpdateEditorIndentation, this);
|
| + WebInspector.moduleSetting('showWhitespacesInEditor').removeChangeListener(this._updateWhitespace, this);
|
| + }
|
| +
|
| + /**
|
| + * @override
|
| + * @param {string} text
|
| + */
|
| + setText(text) {
|
| + this._muteTextChangedEvent = true;
|
| + this._setEditorIndentation(
|
| + text.split('\n').slice(0, WebInspector.SourcesTextEditor.LinesToScanForIndentationGuessing));
|
| + super.setText(text);
|
| + delete this._muteTextChangedEvent;
|
| + }
|
| +
|
| + /**
|
| + * @override
|
| + * @param {string} mimeType
|
| + * @return {!Promise}
|
| + */
|
| + setMimeType(mimeType) {
|
| + this._mimeType = mimeType;
|
| + return super.setMimeType(mimeType).then(
|
| + () => this._codeMirror.setOption('mode', this._applyWhitespaceMimetype(mimeType)));
|
| + }
|
| +
|
| + _updateWhitespace() {
|
| + if (this._mimeType)
|
| + this.setMimeType(this._mimeType);
|
| + }
|
| +
|
| + /**
|
| + * @param {string} mimeType
|
| + * @return {string}
|
| + */
|
| + _applyWhitespaceMimetype(mimeType) {
|
| + this._setupWhitespaceHighlight();
|
| + var whitespaceMode = WebInspector.moduleSetting('showWhitespacesInEditor').get();
|
| + this.element.classList.toggle('show-whitespaces', whitespaceMode === 'all');
|
| +
|
| + if (whitespaceMode === 'all')
|
| + return this._allWhitespaceOverlayMode(mimeType);
|
| + else if (whitespaceMode === 'trailing')
|
| + return this._trailingWhitespaceOverlayMode(mimeType);
|
| +
|
| + return mimeType;
|
| + }
|
| +
|
| + /**
|
| + * @param {string} mimeType
|
| + * @return {string}
|
| + */
|
| + _allWhitespaceOverlayMode(mimeType) {
|
| + var modeName = CodeMirror.mimeModes[mimeType] ?
|
| + (CodeMirror.mimeModes[mimeType].name || CodeMirror.mimeModes[mimeType]) :
|
| + CodeMirror.mimeModes['text/plain'];
|
| + modeName += '+all-whitespaces';
|
| + if (CodeMirror.modes[modeName])
|
| + return modeName;
|
| +
|
| + function modeConstructor(config, parserConfig) {
|
| + function nextToken(stream) {
|
| + if (stream.peek() === ' ') {
|
| + var spaces = 0;
|
| + while (spaces < WebInspector.SourcesTextEditor.MaximumNumberOfWhitespacesPerSingleSpan &&
|
| + stream.peek() === ' ') {
|
| + ++spaces;
|
| + stream.next();
|
| + }
|
| + return 'whitespace whitespace-' + spaces;
|
| }
|
| - var style = doc.createElement("style");
|
| - style.textContent = rules;
|
| - doc.head.appendChild(style);
|
| - },
|
| -
|
| - __proto__: WebInspector.CodeMirrorTextEditor.prototype
|
| + while (!stream.eol() && stream.peek() !== ' ')
|
| + stream.next();
|
| + return null;
|
| + }
|
| + var whitespaceMode = {token: nextToken};
|
| + return CodeMirror.overlayMode(CodeMirror.getMode(config, mimeType), whitespaceMode, false);
|
| + }
|
| + CodeMirror.defineMode(modeName, modeConstructor);
|
| + return modeName;
|
| + }
|
| +
|
| + /**
|
| + * @param {string} mimeType
|
| + * @return {string}
|
| + */
|
| + _trailingWhitespaceOverlayMode(mimeType) {
|
| + var modeName = CodeMirror.mimeModes[mimeType] ?
|
| + (CodeMirror.mimeModes[mimeType].name || CodeMirror.mimeModes[mimeType]) :
|
| + CodeMirror.mimeModes['text/plain'];
|
| + modeName += '+trailing-whitespaces';
|
| + if (CodeMirror.modes[modeName])
|
| + return modeName;
|
| +
|
| + function modeConstructor(config, parserConfig) {
|
| + function nextToken(stream) {
|
| + var pos = stream.pos;
|
| + if (stream.match(/^\s+$/, true))
|
| + return true ? 'trailing-whitespace' : null;
|
| + do {
|
| + stream.next();
|
| + } while (!stream.eol() && stream.peek() !== ' ');
|
| + return null;
|
| + }
|
| + var whitespaceMode = {token: nextToken};
|
| + return CodeMirror.overlayMode(CodeMirror.getMode(config, mimeType), whitespaceMode, false);
|
| + }
|
| + CodeMirror.defineMode(modeName, modeConstructor);
|
| + return modeName;
|
| + }
|
| +
|
| + _setupWhitespaceHighlight() {
|
| + var doc = this.element.ownerDocument;
|
| + if (doc._codeMirrorWhitespaceStyleInjected || !WebInspector.moduleSetting('showWhitespacesInEditor').get())
|
| + return;
|
| + doc._codeMirrorWhitespaceStyleInjected = true;
|
| + const classBase = '.show-whitespaces .CodeMirror .cm-whitespace-';
|
| + const spaceChar = '·';
|
| + var spaceChars = '';
|
| + var rules = '';
|
| + for (var i = 1; i <= WebInspector.SourcesTextEditor.MaximumNumberOfWhitespacesPerSingleSpan; ++i) {
|
| + spaceChars += spaceChar;
|
| + var rule = classBase + i + '::before { content: \'' + spaceChars + '\';}\n';
|
| + rules += rule;
|
| + }
|
| + var style = doc.createElement('style');
|
| + style.textContent = rules;
|
| + doc.head.appendChild(style);
|
| + }
|
| };
|
|
|
| /** @typedef {{lineNumber: number, event: !Event}} */
|
| @@ -622,367 +622,299 @@ WebInspector.SourcesTextEditor.GutterClickEventData;
|
|
|
| /** @enum {symbol} */
|
| WebInspector.SourcesTextEditor.Events = {
|
| - GutterClick: Symbol("GutterClick"),
|
| - TextChanged: Symbol("TextChanged"),
|
| - SelectionChanged: Symbol("SelectionChanged"),
|
| - ScrollChanged: Symbol("ScrollChanged"),
|
| - EditorFocused: Symbol("EditorFocused"),
|
| - EditorBlurred: Symbol("EditorBlurred"),
|
| - JumpHappened: Symbol("JumpHappened")
|
| + GutterClick: Symbol('GutterClick'),
|
| + TextChanged: Symbol('TextChanged'),
|
| + SelectionChanged: Symbol('SelectionChanged'),
|
| + ScrollChanged: Symbol('ScrollChanged'),
|
| + EditorFocused: Symbol('EditorFocused'),
|
| + EditorBlurred: Symbol('EditorBlurred'),
|
| + JumpHappened: Symbol('JumpHappened')
|
| };
|
|
|
| /**
|
| * @interface
|
| */
|
| -WebInspector.SourcesTextEditorDelegate = function() { };
|
| +WebInspector.SourcesTextEditorDelegate = function() {};
|
| WebInspector.SourcesTextEditorDelegate.prototype = {
|
| - /**
|
| - * @param {!WebInspector.ContextMenu} contextMenu
|
| - * @param {number} lineNumber
|
| - * @return {!Promise}
|
| - */
|
| - populateLineGutterContextMenu: function(contextMenu, lineNumber) { },
|
| -
|
| - /**
|
| - * @param {!WebInspector.ContextMenu} contextMenu
|
| - * @param {number} lineNumber
|
| - * @param {number} columnNumber
|
| - * @return {!Promise}
|
| - */
|
| - populateTextAreaContextMenu: function(contextMenu, lineNumber, columnNumber) { },
|
| + /**
|
| + * @param {!WebInspector.ContextMenu} contextMenu
|
| + * @param {number} lineNumber
|
| + * @return {!Promise}
|
| + */
|
| + populateLineGutterContextMenu: function(contextMenu, lineNumber) {},
|
| +
|
| + /**
|
| + * @param {!WebInspector.ContextMenu} contextMenu
|
| + * @param {number} lineNumber
|
| + * @param {number} columnNumber
|
| + * @return {!Promise}
|
| + */
|
| + populateTextAreaContextMenu: function(contextMenu, lineNumber, columnNumber) {},
|
| };
|
|
|
| /**
|
| * @param {!CodeMirror} codeMirror
|
| */
|
| -CodeMirror.commands.smartNewlineAndIndent = function(codeMirror)
|
| -{
|
| - codeMirror.operation(innerSmartNewlineAndIndent.bind(null, codeMirror));
|
| - function innerSmartNewlineAndIndent(codeMirror)
|
| - {
|
| - var selections = codeMirror.listSelections();
|
| - var replacements = [];
|
| - for (var i = 0; i < selections.length; ++i) {
|
| - var selection = selections[i];
|
| - var cur = CodeMirror.cmpPos(selection.head, selection.anchor) < 0 ? selection.head : selection.anchor;
|
| - var line = codeMirror.getLine(cur.line);
|
| - var indent = WebInspector.TextUtils.lineIndent(line);
|
| - replacements.push("\n" + indent.substring(0, Math.min(cur.ch, indent.length)));
|
| - }
|
| - codeMirror.replaceSelections(replacements);
|
| - codeMirror._codeMirrorTextEditor._onAutoAppendedSpaces();
|
| +CodeMirror.commands.smartNewlineAndIndent = function(codeMirror) {
|
| + codeMirror.operation(innerSmartNewlineAndIndent.bind(null, codeMirror));
|
| + function innerSmartNewlineAndIndent(codeMirror) {
|
| + var selections = codeMirror.listSelections();
|
| + var replacements = [];
|
| + for (var i = 0; i < selections.length; ++i) {
|
| + var selection = selections[i];
|
| + var cur = CodeMirror.cmpPos(selection.head, selection.anchor) < 0 ? selection.head : selection.anchor;
|
| + var line = codeMirror.getLine(cur.line);
|
| + var indent = WebInspector.TextUtils.lineIndent(line);
|
| + replacements.push('\n' + indent.substring(0, Math.min(cur.ch, indent.length)));
|
| }
|
| + codeMirror.replaceSelections(replacements);
|
| + codeMirror._codeMirrorTextEditor._onAutoAppendedSpaces();
|
| + }
|
| };
|
|
|
| /**
|
| * @return {!Object|undefined}
|
| */
|
| -CodeMirror.commands.sourcesDismiss = function(codemirror)
|
| -{
|
| - if (codemirror.listSelections().length === 1 && codemirror._codeMirrorTextEditor._isSearchActive())
|
| - return CodeMirror.Pass;
|
| - return CodeMirror.commands.dismiss(codemirror);
|
| +CodeMirror.commands.sourcesDismiss = function(codemirror) {
|
| + if (codemirror.listSelections().length === 1 && codemirror._codeMirrorTextEditor._isSearchActive())
|
| + return CodeMirror.Pass;
|
| + return CodeMirror.commands.dismiss(codemirror);
|
| };
|
|
|
| -/**
|
| - * @constructor
|
| - * @param {!CodeMirror} codeMirror
|
| - */
|
| -WebInspector.SourcesTextEditor.BlockIndentController = function(codeMirror)
|
| -{
|
| - codeMirror.addKeyMap(this);
|
| -};
|
| -
|
| -WebInspector.SourcesTextEditor.BlockIndentController.prototype = {
|
| - name: "blockIndentKeymap",
|
| -
|
| - /**
|
| - * @return {*}
|
| - */
|
| - Enter: function(codeMirror)
|
| - {
|
| - var selections = codeMirror.listSelections();
|
| - var replacements = [];
|
| - var allSelectionsAreCollapsedBlocks = false;
|
| - for (var i = 0; i < selections.length; ++i) {
|
| - var selection = selections[i];
|
| - var start = CodeMirror.cmpPos(selection.head, selection.anchor) < 0 ? selection.head : selection.anchor;
|
| - var line = codeMirror.getLine(start.line);
|
| - var indent = WebInspector.TextUtils.lineIndent(line);
|
| - var indentToInsert = "\n" + indent + codeMirror._codeMirrorTextEditor.indent();
|
| - var isCollapsedBlock = false;
|
| - if (selection.head.ch === 0)
|
| - return CodeMirror.Pass;
|
| - if (line.substr(selection.head.ch - 1, 2) === "{}") {
|
| - indentToInsert += "\n" + indent;
|
| - isCollapsedBlock = true;
|
| - } else if (line.substr(selection.head.ch - 1, 1) !== "{") {
|
| - return CodeMirror.Pass;
|
| - }
|
| - if (i > 0 && allSelectionsAreCollapsedBlocks !== isCollapsedBlock)
|
| - return CodeMirror.Pass;
|
| - replacements.push(indentToInsert);
|
| - allSelectionsAreCollapsedBlocks = isCollapsedBlock;
|
| - }
|
| - codeMirror.replaceSelections(replacements);
|
| - if (!allSelectionsAreCollapsedBlocks) {
|
| - codeMirror._codeMirrorTextEditor._onAutoAppendedSpaces();
|
| - return;
|
| - }
|
| - selections = codeMirror.listSelections();
|
| - var updatedSelections = [];
|
| - for (var i = 0; i < selections.length; ++i) {
|
| - var selection = selections[i];
|
| - var line = codeMirror.getLine(selection.head.line - 1);
|
| - var position = new CodeMirror.Pos(selection.head.line - 1, line.length);
|
| - updatedSelections.push({
|
| - head: position,
|
| - anchor: position
|
| - });
|
| - }
|
| - codeMirror.setSelections(updatedSelections);
|
| - codeMirror._codeMirrorTextEditor._onAutoAppendedSpaces();
|
| - },
|
| -
|
| - /**
|
| - * @return {*}
|
| - */
|
| - "'}'": function(codeMirror)
|
| - {
|
| - if (codeMirror.somethingSelected())
|
| - return CodeMirror.Pass;
|
| - var selections = codeMirror.listSelections();
|
| - var replacements = [];
|
| - for (var i = 0; i < selections.length; ++i) {
|
| - var selection = selections[i];
|
| - var line = codeMirror.getLine(selection.head.line);
|
| - if (line !== WebInspector.TextUtils.lineIndent(line))
|
| - return CodeMirror.Pass;
|
| - replacements.push("}");
|
| - }
|
| - codeMirror.replaceSelections(replacements);
|
| - selections = codeMirror.listSelections();
|
| - replacements = [];
|
| - var updatedSelections = [];
|
| - for (var i = 0; i < selections.length; ++i) {
|
| - var selection = selections[i];
|
| - var matchingBracket = codeMirror.findMatchingBracket(selection.head);
|
| - if (!matchingBracket || !matchingBracket.match)
|
| - return;
|
| - updatedSelections.push({
|
| - head: selection.head,
|
| - anchor: new CodeMirror.Pos(selection.head.line, 0)
|
| - });
|
| - var line = codeMirror.getLine(matchingBracket.to.line);
|
| - var indent = WebInspector.TextUtils.lineIndent(line);
|
| - replacements.push(indent + "}");
|
| - }
|
| - codeMirror.setSelections(updatedSelections);
|
| - codeMirror.replaceSelections(replacements);
|
| +WebInspector.SourcesTextEditor._BlockIndentController = {
|
| + name: 'blockIndentKeymap',
|
| +
|
| + /**
|
| + * @return {*}
|
| + */
|
| + Enter: function(codeMirror) {
|
| + var selections = codeMirror.listSelections();
|
| + var replacements = [];
|
| + var allSelectionsAreCollapsedBlocks = false;
|
| + for (var i = 0; i < selections.length; ++i) {
|
| + var selection = selections[i];
|
| + var start = CodeMirror.cmpPos(selection.head, selection.anchor) < 0 ? selection.head : selection.anchor;
|
| + var line = codeMirror.getLine(start.line);
|
| + var indent = WebInspector.TextUtils.lineIndent(line);
|
| + var indentToInsert = '\n' + indent + codeMirror._codeMirrorTextEditor.indent();
|
| + var isCollapsedBlock = false;
|
| + if (selection.head.ch === 0)
|
| + return CodeMirror.Pass;
|
| + if (line.substr(selection.head.ch - 1, 2) === '{}') {
|
| + indentToInsert += '\n' + indent;
|
| + isCollapsedBlock = true;
|
| + } else if (line.substr(selection.head.ch - 1, 1) !== '{') {
|
| + return CodeMirror.Pass;
|
| + }
|
| + if (i > 0 && allSelectionsAreCollapsedBlocks !== isCollapsedBlock)
|
| + return CodeMirror.Pass;
|
| + replacements.push(indentToInsert);
|
| + allSelectionsAreCollapsedBlocks = isCollapsedBlock;
|
| }
|
| -};
|
| -
|
| -/**
|
| - * @param {!Array.<string>} lines
|
| - * @return {string}
|
| - */
|
| -WebInspector.SourcesTextEditor._guessIndentationLevel = function(lines)
|
| -{
|
| - var tabRegex = /^\t+/;
|
| - var tabLines = 0;
|
| - var indents = {};
|
| - for (var lineNumber = 0; lineNumber < lines.length; ++lineNumber) {
|
| - var text = lines[lineNumber];
|
| - if (text.length === 0 || !WebInspector.TextUtils.isSpaceChar(text[0]))
|
| - continue;
|
| - if (tabRegex.test(text)) {
|
| - ++tabLines;
|
| - continue;
|
| - }
|
| - var i = 0;
|
| - while (i < text.length && WebInspector.TextUtils.isSpaceChar(text[i]))
|
| - ++i;
|
| - if (i % 2 !== 0)
|
| - continue;
|
| - indents[i] = 1 + (indents[i] || 0);
|
| + codeMirror.replaceSelections(replacements);
|
| + if (!allSelectionsAreCollapsedBlocks) {
|
| + codeMirror._codeMirrorTextEditor._onAutoAppendedSpaces();
|
| + return;
|
| }
|
| - var linesCountPerIndentThreshold = 3 * lines.length / 100;
|
| - if (tabLines && tabLines > linesCountPerIndentThreshold)
|
| - return "\t";
|
| - var minimumIndent = Infinity;
|
| - for (var i in indents) {
|
| - if (indents[i] < linesCountPerIndentThreshold)
|
| - continue;
|
| - var indent = parseInt(i, 10);
|
| - if (minimumIndent > indent)
|
| - minimumIndent = indent;
|
| + selections = codeMirror.listSelections();
|
| + var updatedSelections = [];
|
| + for (var i = 0; i < selections.length; ++i) {
|
| + var selection = selections[i];
|
| + var line = codeMirror.getLine(selection.head.line - 1);
|
| + var position = new CodeMirror.Pos(selection.head.line - 1, line.length);
|
| + updatedSelections.push({head: position, anchor: position});
|
| }
|
| - if (minimumIndent === Infinity)
|
| - return WebInspector.moduleSetting("textEditorIndent").get();
|
| - return " ".repeat(minimumIndent);
|
| + codeMirror.setSelections(updatedSelections);
|
| + codeMirror._codeMirrorTextEditor._onAutoAppendedSpaces();
|
| + },
|
| +
|
| + /**
|
| + * @return {*}
|
| + */
|
| + '\'}\'': function(codeMirror) {
|
| + if (codeMirror.somethingSelected())
|
| + return CodeMirror.Pass;
|
| + var selections = codeMirror.listSelections();
|
| + var replacements = [];
|
| + for (var i = 0; i < selections.length; ++i) {
|
| + var selection = selections[i];
|
| + var line = codeMirror.getLine(selection.head.line);
|
| + if (line !== WebInspector.TextUtils.lineIndent(line))
|
| + return CodeMirror.Pass;
|
| + replacements.push('}');
|
| + }
|
| + codeMirror.replaceSelections(replacements);
|
| + selections = codeMirror.listSelections();
|
| + replacements = [];
|
| + var updatedSelections = [];
|
| + for (var i = 0; i < selections.length; ++i) {
|
| + var selection = selections[i];
|
| + var matchingBracket = codeMirror.findMatchingBracket(selection.head);
|
| + if (!matchingBracket || !matchingBracket.match)
|
| + return;
|
| + updatedSelections.push({head: selection.head, anchor: new CodeMirror.Pos(selection.head.line, 0)});
|
| + var line = codeMirror.getLine(matchingBracket.to.line);
|
| + var indent = WebInspector.TextUtils.lineIndent(line);
|
| + replacements.push(indent + '}');
|
| + }
|
| + codeMirror.setSelections(updatedSelections);
|
| + codeMirror.replaceSelections(replacements);
|
| + }
|
| };
|
|
|
| +
|
| /**
|
| - * @constructor
|
| - * @param {!WebInspector.SourcesTextEditor} textEditor
|
| - * @param {!CodeMirror} codeMirror
|
| + * @unrestricted
|
| */
|
| -WebInspector.SourcesTextEditor.TokenHighlighter = function(textEditor, codeMirror)
|
| -{
|
| +WebInspector.SourcesTextEditor.TokenHighlighter = class {
|
| + /**
|
| + * @param {!WebInspector.SourcesTextEditor} textEditor
|
| + * @param {!CodeMirror} codeMirror
|
| + */
|
| + constructor(textEditor, codeMirror) {
|
| this._textEditor = textEditor;
|
| this._codeMirror = codeMirror;
|
| -};
|
| -
|
| -WebInspector.SourcesTextEditor.TokenHighlighter.prototype = {
|
| - /**
|
| - * @param {!RegExp} regex
|
| - * @param {?WebInspector.TextRange} range
|
| - */
|
| - highlightSearchResults: function(regex, range)
|
| - {
|
| - var oldRegex = this._highlightRegex;
|
| - this._highlightRegex = regex;
|
| - this._highlightRange = range;
|
| - if (this._searchResultMarker) {
|
| - this._searchResultMarker.clear();
|
| - delete this._searchResultMarker;
|
| - }
|
| - if (this._highlightDescriptor && this._highlightDescriptor.selectionStart)
|
| - this._codeMirror.removeLineClass(this._highlightDescriptor.selectionStart.line, "wrap", "cm-line-with-selection");
|
| - var selectionStart = this._highlightRange ? new CodeMirror.Pos(this._highlightRange.startLine, this._highlightRange.startColumn) : null;
|
| - if (selectionStart)
|
| - this._codeMirror.addLineClass(selectionStart.line, "wrap", "cm-line-with-selection");
|
| - if (this._highlightRegex === oldRegex) {
|
| - // Do not re-add overlay mode if regex did not change for better performance.
|
| - if (this._highlightDescriptor)
|
| - this._highlightDescriptor.selectionStart = selectionStart;
|
| - } else {
|
| - this._removeHighlight();
|
| - this._setHighlighter(this._searchHighlighter.bind(this, this._highlightRegex), selectionStart);
|
| - }
|
| - if (this._highlightRange) {
|
| - var pos = WebInspector.CodeMirrorUtils.toPos(this._highlightRange);
|
| - this._searchResultMarker = this._codeMirror.markText(pos.start, pos.end, {className: "cm-column-with-selection"});
|
| - }
|
| - },
|
| -
|
| - /**
|
| - * @return {!RegExp|undefined}
|
| - */
|
| - highlightedRegex: function()
|
| - {
|
| - return this._highlightRegex;
|
| - },
|
| -
|
| - highlightSelectedTokens: function()
|
| - {
|
| - delete this._highlightRegex;
|
| - delete this._highlightRange;
|
| - if (this._highlightDescriptor && this._highlightDescriptor.selectionStart)
|
| - this._codeMirror.removeLineClass(this._highlightDescriptor.selectionStart.line, "wrap", "cm-line-with-selection");
|
| - this._removeHighlight();
|
| - var selectionStart = this._codeMirror.getCursor("start");
|
| - var selectionEnd = this._codeMirror.getCursor("end");
|
| - if (selectionStart.line !== selectionEnd.line)
|
| - return;
|
| - if (selectionStart.ch === selectionEnd.ch)
|
| - return;
|
| - var selections = this._codeMirror.getSelections();
|
| - if (selections.length > 1)
|
| - return;
|
| - var selectedText = selections[0];
|
| - if (this._isWord(selectedText, selectionStart.line, selectionStart.ch, selectionEnd.ch)) {
|
| - if (selectionStart)
|
| - this._codeMirror.addLineClass(selectionStart.line, "wrap", "cm-line-with-selection");
|
| - this._setHighlighter(this._tokenHighlighter.bind(this, selectedText, selectionStart), selectionStart);
|
| - }
|
| - },
|
| -
|
| - /**
|
| - * @param {string} selectedText
|
| - * @param {number} lineNumber
|
| - * @param {number} startColumn
|
| - * @param {number} endColumn
|
| - */
|
| - _isWord: function(selectedText, lineNumber, startColumn, endColumn)
|
| - {
|
| - var line = this._codeMirror.getLine(lineNumber);
|
| - var leftBound = startColumn === 0 || !WebInspector.TextUtils.isWordChar(line.charAt(startColumn - 1));
|
| - var rightBound = endColumn === line.length || !WebInspector.TextUtils.isWordChar(line.charAt(endColumn));
|
| - return leftBound && rightBound && WebInspector.TextUtils.isWord(selectedText);
|
| - },
|
| -
|
| - _removeHighlight: function()
|
| - {
|
| - if (this._highlightDescriptor) {
|
| - this._codeMirror.removeOverlay(this._highlightDescriptor.overlay);
|
| - delete this._highlightDescriptor;
|
| - }
|
| - },
|
| -
|
| - /**
|
| - * @param {!RegExp} regex
|
| - * @param {!CodeMirror.StringStream} stream
|
| - */
|
| - _searchHighlighter: function(regex, stream)
|
| - {
|
| - if (stream.column() === 0)
|
| - delete this._searchMatchLength;
|
| - if (this._searchMatchLength) {
|
| - if (this._searchMatchLength > 2) {
|
| - for (var i = 0; i < this._searchMatchLength - 2; ++i)
|
| - stream.next();
|
| - this._searchMatchLength = 1;
|
| - return "search-highlight";
|
| - } else {
|
| - stream.next();
|
| - delete this._searchMatchLength;
|
| - return "search-highlight search-highlight-end";
|
| - }
|
| - }
|
| - var match = stream.match(regex, false);
|
| - if (match) {
|
| - stream.next();
|
| - var matchLength = match[0].length;
|
| - if (matchLength === 1)
|
| - return "search-highlight search-highlight-full";
|
| - this._searchMatchLength = matchLength;
|
| - return "search-highlight search-highlight-start";
|
| - }
|
| - while (!stream.match(regex, false) && stream.next()) {}
|
| - },
|
| -
|
| - /**
|
| - * @param {string} token
|
| - * @param {!CodeMirror.Pos} selectionStart
|
| - * @param {!CodeMirror.StringStream} stream
|
| - */
|
| - _tokenHighlighter: function(token, selectionStart, stream)
|
| - {
|
| - var tokenFirstChar = token.charAt(0);
|
| - if (stream.match(token) && (stream.eol() || !WebInspector.TextUtils.isWordChar(stream.peek())))
|
| - return stream.column() === selectionStart.ch ? "token-highlight column-with-selection" : "token-highlight";
|
| - var eatenChar;
|
| - do {
|
| - eatenChar = stream.next();
|
| - } while (eatenChar && (WebInspector.TextUtils.isWordChar(eatenChar) || stream.peek() !== tokenFirstChar));
|
| - },
|
| -
|
| - /**
|
| - * @param {function(!CodeMirror.StringStream)} highlighter
|
| - * @param {?CodeMirror.Pos} selectionStart
|
| - */
|
| - _setHighlighter: function(highlighter, selectionStart)
|
| - {
|
| - var overlayMode = {
|
| - token: highlighter
|
| - };
|
| - this._codeMirror.addOverlay(overlayMode);
|
| - this._highlightDescriptor = {
|
| - overlay: overlayMode,
|
| - selectionStart: selectionStart
|
| - };
|
| + }
|
| +
|
| + /**
|
| + * @param {!RegExp} regex
|
| + * @param {?WebInspector.TextRange} range
|
| + */
|
| + highlightSearchResults(regex, range) {
|
| + var oldRegex = this._highlightRegex;
|
| + this._highlightRegex = regex;
|
| + this._highlightRange = range;
|
| + if (this._searchResultMarker) {
|
| + this._searchResultMarker.clear();
|
| + delete this._searchResultMarker;
|
| + }
|
| + if (this._highlightDescriptor && this._highlightDescriptor.selectionStart)
|
| + this._codeMirror.removeLineClass(this._highlightDescriptor.selectionStart.line, 'wrap', 'cm-line-with-selection');
|
| + var selectionStart = this._highlightRange ?
|
| + new CodeMirror.Pos(this._highlightRange.startLine, this._highlightRange.startColumn) :
|
| + null;
|
| + if (selectionStart)
|
| + this._codeMirror.addLineClass(selectionStart.line, 'wrap', 'cm-line-with-selection');
|
| + if (this._highlightRegex === oldRegex) {
|
| + // Do not re-add overlay mode if regex did not change for better performance.
|
| + if (this._highlightDescriptor)
|
| + this._highlightDescriptor.selectionStart = selectionStart;
|
| + } else {
|
| + this._removeHighlight();
|
| + this._setHighlighter(this._searchHighlighter.bind(this, this._highlightRegex), selectionStart);
|
| + }
|
| + if (this._highlightRange) {
|
| + var pos = WebInspector.CodeMirrorUtils.toPos(this._highlightRange);
|
| + this._searchResultMarker = this._codeMirror.markText(pos.start, pos.end, {className: 'cm-column-with-selection'});
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * @return {!RegExp|undefined}
|
| + */
|
| + highlightedRegex() {
|
| + return this._highlightRegex;
|
| + }
|
| +
|
| + highlightSelectedTokens() {
|
| + delete this._highlightRegex;
|
| + delete this._highlightRange;
|
| + if (this._highlightDescriptor && this._highlightDescriptor.selectionStart)
|
| + this._codeMirror.removeLineClass(this._highlightDescriptor.selectionStart.line, 'wrap', 'cm-line-with-selection');
|
| + this._removeHighlight();
|
| + var selectionStart = this._codeMirror.getCursor('start');
|
| + var selectionEnd = this._codeMirror.getCursor('end');
|
| + if (selectionStart.line !== selectionEnd.line)
|
| + return;
|
| + if (selectionStart.ch === selectionEnd.ch)
|
| + return;
|
| + var selections = this._codeMirror.getSelections();
|
| + if (selections.length > 1)
|
| + return;
|
| + var selectedText = selections[0];
|
| + if (this._isWord(selectedText, selectionStart.line, selectionStart.ch, selectionEnd.ch)) {
|
| + if (selectionStart)
|
| + this._codeMirror.addLineClass(selectionStart.line, 'wrap', 'cm-line-with-selection');
|
| + this._setHighlighter(this._tokenHighlighter.bind(this, selectedText, selectionStart), selectionStart);
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * @param {string} selectedText
|
| + * @param {number} lineNumber
|
| + * @param {number} startColumn
|
| + * @param {number} endColumn
|
| + */
|
| + _isWord(selectedText, lineNumber, startColumn, endColumn) {
|
| + var line = this._codeMirror.getLine(lineNumber);
|
| + var leftBound = startColumn === 0 || !WebInspector.TextUtils.isWordChar(line.charAt(startColumn - 1));
|
| + var rightBound = endColumn === line.length || !WebInspector.TextUtils.isWordChar(line.charAt(endColumn));
|
| + return leftBound && rightBound && WebInspector.TextUtils.isWord(selectedText);
|
| + }
|
| +
|
| + _removeHighlight() {
|
| + if (this._highlightDescriptor) {
|
| + this._codeMirror.removeOverlay(this._highlightDescriptor.overlay);
|
| + delete this._highlightDescriptor;
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * @param {!RegExp} regex
|
| + * @param {!CodeMirror.StringStream} stream
|
| + */
|
| + _searchHighlighter(regex, stream) {
|
| + if (stream.column() === 0)
|
| + delete this._searchMatchLength;
|
| + if (this._searchMatchLength) {
|
| + if (this._searchMatchLength > 2) {
|
| + for (var i = 0; i < this._searchMatchLength - 2; ++i)
|
| + stream.next();
|
| + this._searchMatchLength = 1;
|
| + return 'search-highlight';
|
| + } else {
|
| + stream.next();
|
| + delete this._searchMatchLength;
|
| + return 'search-highlight search-highlight-end';
|
| + }
|
| + }
|
| + var match = stream.match(regex, false);
|
| + if (match) {
|
| + stream.next();
|
| + var matchLength = match[0].length;
|
| + if (matchLength === 1)
|
| + return 'search-highlight search-highlight-full';
|
| + this._searchMatchLength = matchLength;
|
| + return 'search-highlight search-highlight-start';
|
| + }
|
| + while (!stream.match(regex, false) && stream.next()) {
|
| }
|
| + }
|
| +
|
| + /**
|
| + * @param {string} token
|
| + * @param {!CodeMirror.Pos} selectionStart
|
| + * @param {!CodeMirror.StringStream} stream
|
| + */
|
| + _tokenHighlighter(token, selectionStart, stream) {
|
| + var tokenFirstChar = token.charAt(0);
|
| + if (stream.match(token) && (stream.eol() || !WebInspector.TextUtils.isWordChar(stream.peek())))
|
| + return stream.column() === selectionStart.ch ? 'token-highlight column-with-selection' : 'token-highlight';
|
| + var eatenChar;
|
| + do {
|
| + eatenChar = stream.next();
|
| + } while (eatenChar && (WebInspector.TextUtils.isWordChar(eatenChar) || stream.peek() !== tokenFirstChar));
|
| + }
|
| +
|
| + /**
|
| + * @param {function(!CodeMirror.StringStream)} highlighter
|
| + * @param {?CodeMirror.Pos} selectionStart
|
| + */
|
| + _setHighlighter(highlighter, selectionStart) {
|
| + var overlayMode = {token: highlighter};
|
| + this._codeMirror.addOverlay(overlayMode);
|
| + this._highlightDescriptor = {overlay: overlayMode, selectionStart: selectionStart};
|
| + }
|
| };
|
|
|
| WebInspector.SourcesTextEditor.LinesToScanForIndentationGuessing = 1000;
|
|
|