Chromium Code Reviews| Index: third_party/WebKit/Source/devtools/front_end/console/ConsolePrompt.js |
| diff --git a/third_party/WebKit/Source/devtools/front_end/console/ConsolePrompt.js b/third_party/WebKit/Source/devtools/front_end/console/ConsolePrompt.js |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..1e94c4bc5bbfc327495f978e7cd3c7b47880572c |
| --- /dev/null |
| +++ b/third_party/WebKit/Source/devtools/front_end/console/ConsolePrompt.js |
| @@ -0,0 +1,259 @@ |
| +/** |
|
pfeldman
2016/09/14 00:31:52
Where is my copyright?
einbinder
2016/09/14 20:21:06
Done.
|
| + * @constructor |
| + * @extends {WebInspector.Widget} |
| + */ |
| +WebInspector.ConsolePrompt = function() |
| +{ |
| + WebInspector.Widget.call(this); |
|
pfeldman
2016/09/14 00:31:53
There is no point in making something a widget unl
einbinder
2016/09/14 20:21:06
Even if it needs a public .element and needs .focu
|
| + this._addCompletionsFromHistory = true; |
| + this._history = new WebInspector.HistoryManager(); |
| + |
| + this._initialText = ""; |
| + this._needsFocus = false; |
| + this._editor = null; |
| + |
| + this.element.addEventListener("keydown", this._editorKeyDown.bind(this), true); |
| + |
| + self.runtime.extension(WebInspector.TextEditorFactory).instance().then(gotFactory.bind(this)); |
| + |
| + /** |
| + * @param {!WebInspector.TextEditorFactory} factory |
| + * @this {!WebInspector.ConsolePrompt} |
|
pfeldman
2016/09/14 00:31:52
drop !
einbinder
2016/09/14 20:21:05
Done.
|
| + */ |
| + function gotFactory(factory) |
| + { |
| + this._editor = factory.createEditor({ |
| + lineNumbers: false, |
| + lineWrapping: true, |
| + bracketMatchingFlag: "consoleBracketMatching", |
| + mimeType: "javascript", |
| + autoHeight: true |
| + }); |
| + |
| + this._editor.configureAutocomplete({ |
| + substituteRangeCallback: this._substituteRange.bind(this), |
| + suggestionsCallback: this._wordsWithPrefix.bind(this), |
| + captureEnter: true |
| + }) |
| + this._editor.widget().show(this.element); |
| + |
| + this.setText(this._initialText) |
|
dgozman
2016/09/14 04:26:17
semicolon
einbinder
2016/09/14 20:21:06
Done.
|
| + if (this._needsFocus) |
|
pfeldman
2016/09/14 00:31:52
What if I already clicked away? Might need to set
dgozman
2016/09/14 04:26:17
delete this._initialText;
einbinder
2016/09/14 20:21:06
I thought it was acceptable losses. I can make it
|
| + this.focus(); |
| + this._needsFocus = false; |
| + } |
| +} |
| + |
| +WebInspector.ConsolePrompt.prototype = { |
| + |
|
lushnikov
2016/09/14 01:11:21
nit: stray line
einbinder
2016/09/14 20:21:06
Done.
|
| + /** |
| + * @return {!WebInspector.HistoryManager} |
| + */ |
| + history: function() |
| + { |
| + return this._history; |
| + }, |
| + |
| + clearAutocomplete: function() |
| + { |
| + if (this._editor) |
| + this._editor.clearAutocomplete(); |
| + }, |
| + |
| + /** |
| + * @return {boolean} |
| + */ |
| + isCaretInsidePrompt: function() |
| + { |
| + return this.hasFocus(); |
| + }, |
| + |
| + /** |
| + * @return {boolean} |
| + */ |
| + isCaretAtEndOfPrompt: function() |
| + { |
| + return !!this._editor && this._editor.selection().collapseToEnd().compareTo(this._editor.fullRange().collapseToEnd()) === 0; |
|
lushnikov
2016/09/14 01:11:21
nit: compareTo -> .equal
einbinder
2016/09/14 20:21:06
Done.
|
| + }, |
| + |
| + /** |
| + * @return {boolean} |
| + */ |
| + isCaretOnLastLine: function() |
| + { |
| + return !!this._editor && this._editor.selection().endLine === this._editor.fullRange().endLine; |
| + }, |
| + |
| + /** |
| + * @return {boolean} |
| + */ |
| + isCaretOnFirstLine: function() |
| + { |
| + return !!this._editor && this._editor.selection().endLine === 0; |
| + }, |
| + |
| + moveCaretToEndOfPrompt: function() |
| + { |
| + if (this._editor) |
| + this._editor.setSelection(WebInspector.TextRange.createFromLocation(Infinity,Infinity)); |
| + }, |
| + |
| + moveCaretToEndOfFirstLine: function() |
| + { |
| + if (this._editor) |
| + this._editor.setSelection(WebInspector.TextRange.createFromLocation(0,Infinity)); |
| + }, |
| + |
| + /** |
| + * @param {string} text |
| + */ |
| + setText: function(text) |
| + { |
| + if (this._editor) |
| + this._editor.setText(text); |
| + else |
| + this._initialText = text; |
| + }, |
| + |
| + /** |
| + * @return {string} |
| + */ |
| + text: function() |
| + { |
| + return this._editor ? this._editor.text() : this._initialText; |
| + }, |
| + |
| + /** |
| + * @param {boolean} value |
| + */ |
| + setAddCompletionsFromHistory: function(value) |
| + { |
| + this._addCompletionsFromHistory = value; |
| + }, |
| + |
| + /** |
| + * @param {!Event} event |
| + */ |
| + _editorKeyDown: function(event) |
| + { |
| + var keyboardEvent = /** @type {!KeyboardEvent} */ (event); |
| + var newText; |
| + var isPrevious; |
| + |
| + switch (keyboardEvent.keyCode) { |
|
lushnikov
2016/09/14 01:11:21
You probably will simplify key handling if you use
einbinder
2016/09/14 20:21:06
I stole this code from TextPrompt. How about I cle
|
| + case WebInspector.KeyboardShortcut.Keys.Up.code: |
| + if (!this.isCaretOnFirstLine()) |
| + break; |
| + newText = this._history.previous(this.text()); |
| + isPrevious = true; |
| + break; |
| + case WebInspector.KeyboardShortcut.Keys.Down.code: |
| + if (!this.isCaretOnLastLine()) |
| + break; |
| + newText = this._history.next(); |
| + break; |
| + case WebInspector.KeyboardShortcut.Keys.P.code: // Ctrl+P = Previous |
| + if (WebInspector.isMac() && keyboardEvent.ctrlKey && !keyboardEvent.metaKey && !keyboardEvent.altKey && !keyboardEvent.shiftKey) { |
| + newText = this._history.previous(this.text()); |
| + isPrevious = true; |
| + } |
| + break; |
| + case WebInspector.KeyboardShortcut.Keys.N.code: // Ctrl+N = Next |
| + if (WebInspector.isMac() && keyboardEvent.ctrlKey && !keyboardEvent.metaKey && !keyboardEvent.altKey && !keyboardEvent.shiftKey) |
| + newText = this._history.next(); |
| + break; |
| + } |
| + |
| + if (newText !== undefined) { |
|
lushnikov
2016/09/14 01:11:21
fast-return?
einbinder
2016/09/14 20:21:06
Done.
|
| + keyboardEvent.consume(true); |
| + this.setText(newText); |
| + |
| + if (isPrevious) |
| + this.moveCaretToEndOfFirstLine(); |
| + else |
| + this.moveCaretToEndOfPrompt(); |
| + } |
| + }, |
| + |
| + /** |
| + * @param {string} prefix |
| + * @return {!WebInspector.SuggestBox.Suggestions} |
| + */ |
| + _historyCompletions: function(prefix) |
| + { |
| + if (!this._addCompletionsFromHistory || !this.isCaretAtEndOfPrompt()) |
| + return []; |
| + var result = []; |
| + var text = this.text(); |
| + var set = new Set(); |
| + var data = this._history.historyData(); |
| + for (var i = data.length - 1; i >= 0 && result.length < 50; --i) { |
| + var item = data[i]; |
| + if (!item.startsWith(text)) |
| + continue; |
| + if (set.has(item)) |
| + continue; |
| + set.add(item); |
| + result.push({title: item.substring(text.length - prefix.length), className: "additional"}); |
| + } |
| + return result; |
| + }, |
| + |
| + /** |
| + * @override |
| + */ |
| + focus: function() |
| + { |
| + if (this._editor) |
| + this._editor.widget().focus(); |
| + else |
| + this._needsFocus = true; |
|
dgozman
2016/09/14 04:26:17
Let's instead focus this.element here, and switch
einbinder
2016/09/14 20:21:05
Done.
|
| + }, |
| + |
| + /** |
| + * @param {number} lineNumber |
| + * @param {number} columnNumber |
| + * @return {?WebInspector.TextRange} |
| + */ |
| + _substituteRange: function(lineNumber, columnNumber) |
| + { |
| + if (!this._editor) |
| + return null; |
| + |
| + var lineText = this._editor.line(lineNumber); |
| + var index; |
| + for (index = lineText.length - 1; index >= 0; index--) { |
| + if (" =:[({;,!+-*/&|^<>.".indexOf(lineText.charAt(index)) !== -1) |
| + break; |
| + } |
| + return new WebInspector.TextRange(lineNumber, index + 1, lineNumber, columnNumber); |
| + }, |
| + |
| + /** |
| + * @param {!WebInspector.TextRange} prefixRange |
| + * @param {!WebInspector.TextRange} substituteRange |
| + * @return {!Promise.<!Array.<{title: string, className: (string|undefined)}>>} |
| + */ |
| + _wordsWithPrefix: function(prefixRange, substituteRange) |
| + { |
| + if (!this._editor) |
|
lushnikov
2016/09/14 01:11:21
how could there be no editor?
|
| + return Promise.resolve([]); |
| + |
| + var resolve; |
| + var promise = new Promise(fufill => resolve = fufill); |
| + var prefix = this._editor.text(prefixRange); |
| + var before = this._editor.text(new WebInspector.TextRange(0,0,prefixRange.startLine,prefixRange.startColumn)); |
|
dgozman
2016/09/14 04:26:18
spaces
einbinder
2016/09/14 20:21:06
Done.
|
| + var historyWords = this._historyCompletions(prefix); |
| + WebInspector.ExecutionContextSelector.completionsForTextInCurrentContext(before, prefix, false, innerWordsWithPrefix); |
|
dgozman
2016/09/14 04:26:17
Let's annotate false /* doSomething */
einbinder
2016/09/14 20:21:06
Done.
|
| + return promise; |
| + /** |
|
dgozman
2016/09/14 04:26:17
empty line please
einbinder
2016/09/14 20:21:05
Done.
|
| + * @param {!Array.<string>} words |
| + */ |
| + function innerWordsWithPrefix(words) |
| + { |
| + resolve(words.map(item => ({title:item})).concat(historyWords)); |
| + } |
| + }, |
| + |
| + __proto__: WebInspector.Widget.prototype |
| +} |