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; |