OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | |
5 /** | 4 /** |
6 * @constructor | 5 * @unrestricted |
7 * @extends {WebInspector.Widget} | |
8 */ | 6 */ |
9 WebInspector.ConsolePrompt = function() | 7 WebInspector.ConsolePrompt = class extends WebInspector.Widget { |
10 { | 8 constructor() { |
11 WebInspector.Widget.call(this); | 9 super(); |
12 this._addCompletionsFromHistory = true; | 10 this._addCompletionsFromHistory = true; |
13 this._history = new WebInspector.ConsoleHistoryManager(); | 11 this._history = new WebInspector.ConsoleHistoryManager(); |
14 | 12 |
15 this._initialText = ""; | 13 this._initialText = ''; |
16 this._editor = null; | 14 this._editor = null; |
17 | 15 |
18 this.element.tabIndex = 0; | 16 this.element.tabIndex = 0; |
19 | 17 |
20 self.runtime.extension(WebInspector.TextEditorFactory).instance().then(gotFa
ctory.bind(this)); | 18 self.runtime.extension(WebInspector.TextEditorFactory).instance().then(gotFa
ctory.bind(this)); |
21 | 19 |
22 /** | 20 /** |
23 * @param {!WebInspector.TextEditorFactory} factory | 21 * @param {!WebInspector.TextEditorFactory} factory |
24 * @this {WebInspector.ConsolePrompt} | 22 * @this {WebInspector.ConsolePrompt} |
25 */ | 23 */ |
26 function gotFactory(factory) | 24 function gotFactory(factory) { |
27 { | 25 this._editor = |
28 this._editor = factory.createEditor({ | 26 factory.createEditor({lineNumbers: false, lineWrapping: true, mimeType
: 'javascript', autoHeight: true}); |
29 lineNumbers: false, | 27 |
30 lineWrapping: true, | 28 this._editor.configureAutocomplete({ |
31 mimeType: "javascript", | 29 substituteRangeCallback: this._substituteRange.bind(this), |
32 autoHeight: true | 30 suggestionsCallback: this._wordsWithPrefix.bind(this), |
33 }); | 31 captureEnter: true |
34 | 32 }); |
35 this._editor.configureAutocomplete({ | 33 this._editor.widget().element.addEventListener('keydown', this._editorKeyD
own.bind(this), true); |
36 substituteRangeCallback: this._substituteRange.bind(this), | 34 this._editor.widget().show(this.element); |
37 suggestionsCallback: this._wordsWithPrefix.bind(this), | 35 |
38 captureEnter: true | 36 this.setText(this._initialText); |
39 }); | 37 delete this._initialText; |
40 this._editor.widget().element.addEventListener("keydown", this._editorKe
yDown.bind(this), true); | 38 if (this.hasFocus()) |
41 this._editor.widget().show(this.element); | 39 this.focus(); |
42 | 40 this.element.tabIndex = -1; |
43 this.setText(this._initialText); | 41 |
44 delete this._initialText; | 42 this._editorSetForTest(); |
45 if (this.hasFocus()) | 43 } |
46 this.focus(); | 44 } |
47 this.element.tabIndex = -1; | 45 |
48 | 46 /** |
49 this._editorSetForTest(); | 47 * @return {!WebInspector.ConsoleHistoryManager} |
50 } | 48 */ |
| 49 history() { |
| 50 return this._history; |
| 51 } |
| 52 |
| 53 clearAutocomplete() { |
| 54 if (this._editor) |
| 55 this._editor.clearAutocomplete(); |
| 56 } |
| 57 |
| 58 /** |
| 59 * @return {boolean} |
| 60 */ |
| 61 _isCaretAtEndOfPrompt() { |
| 62 return !!this._editor && this._editor.selection().collapseToEnd().equal(this
._editor.fullRange().collapseToEnd()); |
| 63 } |
| 64 |
| 65 moveCaretToEndOfPrompt() { |
| 66 if (this._editor) |
| 67 this._editor.setSelection(WebInspector.TextRange.createFromLocation(Infini
ty, Infinity)); |
| 68 } |
| 69 |
| 70 /** |
| 71 * @param {string} text |
| 72 */ |
| 73 setText(text) { |
| 74 if (this._editor) |
| 75 this._editor.setText(text); |
| 76 else |
| 77 this._initialText = text; |
| 78 } |
| 79 |
| 80 /** |
| 81 * @return {string} |
| 82 */ |
| 83 text() { |
| 84 return this._editor ? this._editor.text() : this._initialText; |
| 85 } |
| 86 |
| 87 /** |
| 88 * @param {boolean} value |
| 89 */ |
| 90 setAddCompletionsFromHistory(value) { |
| 91 this._addCompletionsFromHistory = value; |
| 92 } |
| 93 |
| 94 /** |
| 95 * @param {!Event} event |
| 96 */ |
| 97 _editorKeyDown(event) { |
| 98 var keyboardEvent = /** @type {!KeyboardEvent} */ (event); |
| 99 var newText; |
| 100 var isPrevious; |
| 101 |
| 102 switch (keyboardEvent.keyCode) { |
| 103 case WebInspector.KeyboardShortcut.Keys.Up.code: |
| 104 if (this._editor.selection().endLine > 0) |
| 105 break; |
| 106 newText = this._history.previous(this.text()); |
| 107 isPrevious = true; |
| 108 break; |
| 109 case WebInspector.KeyboardShortcut.Keys.Down.code: |
| 110 if (this._editor.selection().endLine < this._editor.fullRange().endLine) |
| 111 break; |
| 112 newText = this._history.next(); |
| 113 break; |
| 114 case WebInspector.KeyboardShortcut.Keys.P.code: // Ctrl+P = Previous |
| 115 if (WebInspector.isMac() && keyboardEvent.ctrlKey && !keyboardEvent.meta
Key && !keyboardEvent.altKey && |
| 116 !keyboardEvent.shiftKey) { |
| 117 newText = this._history.previous(this.text()); |
| 118 isPrevious = true; |
| 119 } |
| 120 break; |
| 121 case WebInspector.KeyboardShortcut.Keys.N.code: // Ctrl+N = Next |
| 122 if (WebInspector.isMac() && keyboardEvent.ctrlKey && !keyboardEvent.meta
Key && !keyboardEvent.altKey && |
| 123 !keyboardEvent.shiftKey) |
| 124 newText = this._history.next(); |
| 125 break; |
| 126 case WebInspector.KeyboardShortcut.Keys.Enter.code: |
| 127 this._enterKeyPressed(keyboardEvent); |
| 128 break; |
| 129 } |
| 130 |
| 131 if (newText === undefined) |
| 132 return; |
| 133 keyboardEvent.consume(true); |
| 134 this.setText(newText); |
| 135 |
| 136 if (isPrevious) |
| 137 this._editor.setSelection(WebInspector.TextRange.createFromLocation(0, Inf
inity)); |
| 138 else |
| 139 this.moveCaretToEndOfPrompt(); |
| 140 } |
| 141 |
| 142 /** |
| 143 * @param {!KeyboardEvent} event |
| 144 */ |
| 145 _enterKeyPressed(event) { |
| 146 if (event.altKey || event.ctrlKey || event.shiftKey) |
| 147 return; |
| 148 |
| 149 event.consume(true); |
| 150 |
| 151 this.clearAutocomplete(); |
| 152 |
| 153 var str = this.text(); |
| 154 if (!str.length) |
| 155 return; |
| 156 |
| 157 var currentExecutionContext = WebInspector.context.flavor(WebInspector.Execu
tionContext); |
| 158 if (!this._isCaretAtEndOfPrompt() || !currentExecutionContext) { |
| 159 this._appendCommand(str, true); |
| 160 return; |
| 161 } |
| 162 currentExecutionContext.target().runtimeModel.compileScript( |
| 163 str, '', false, currentExecutionContext.id, compileCallback.bind(this)); |
| 164 |
| 165 /** |
| 166 * @param {!RuntimeAgent.ScriptId=} scriptId |
| 167 * @param {?RuntimeAgent.ExceptionDetails=} exceptionDetails |
| 168 * @this {WebInspector.ConsolePrompt} |
| 169 */ |
| 170 function compileCallback(scriptId, exceptionDetails) { |
| 171 if (str !== this.text()) |
| 172 return; |
| 173 if (exceptionDetails && |
| 174 (exceptionDetails.exception.description.startsWith('SyntaxError: Unexp
ected end of input') || |
| 175 exceptionDetails.exception.description.startsWith('SyntaxError: Unter
minated template literal'))) { |
| 176 this._editor.newlineAndIndent(); |
| 177 this._enterProcessedForTest(); |
| 178 return; |
| 179 } |
| 180 this._appendCommand(str, true); |
| 181 this._enterProcessedForTest(); |
| 182 } |
| 183 } |
| 184 |
| 185 /** |
| 186 * @param {string} text |
| 187 * @param {boolean} useCommandLineAPI |
| 188 */ |
| 189 _appendCommand(text, useCommandLineAPI) { |
| 190 this.setText(''); |
| 191 var currentExecutionContext = WebInspector.context.flavor(WebInspector.Execu
tionContext); |
| 192 if (currentExecutionContext) { |
| 193 WebInspector.ConsoleModel.evaluateCommandInConsole(currentExecutionContext
, text, useCommandLineAPI); |
| 194 if (WebInspector.ConsolePanel.instance().isShowing()) |
| 195 WebInspector.userMetrics.actionTaken(WebInspector.UserMetrics.Action.Com
mandEvaluatedInConsolePanel); |
| 196 } |
| 197 } |
| 198 |
| 199 _enterProcessedForTest() { |
| 200 } |
| 201 |
| 202 /** |
| 203 * @param {string} prefix |
| 204 * @return {!WebInspector.SuggestBox.Suggestions} |
| 205 */ |
| 206 _historyCompletions(prefix) { |
| 207 if (!this._addCompletionsFromHistory || !this._isCaretAtEndOfPrompt()) |
| 208 return []; |
| 209 var result = []; |
| 210 var text = this.text(); |
| 211 var set = new Set(); |
| 212 var data = this._history.historyData(); |
| 213 for (var i = data.length - 1; i >= 0 && result.length < 50; --i) { |
| 214 var item = data[i]; |
| 215 if (!item.startsWith(text)) |
| 216 continue; |
| 217 if (set.has(item)) |
| 218 continue; |
| 219 set.add(item); |
| 220 result.push({title: item.substring(text.length - prefix.length), className
: 'additional'}); |
| 221 } |
| 222 return result; |
| 223 } |
| 224 |
| 225 /** |
| 226 * @override |
| 227 */ |
| 228 focus() { |
| 229 if (this._editor) |
| 230 this._editor.widget().focus(); |
| 231 else |
| 232 this.element.focus(); |
| 233 } |
| 234 |
| 235 /** |
| 236 * @param {number} lineNumber |
| 237 * @param {number} columnNumber |
| 238 * @return {?WebInspector.TextRange} |
| 239 */ |
| 240 _substituteRange(lineNumber, columnNumber) { |
| 241 var lineText = this._editor.line(lineNumber); |
| 242 var index; |
| 243 for (index = lineText.length - 1; index >= 0; index--) { |
| 244 if (' =:[({;,!+-*/&|^<>.'.indexOf(lineText.charAt(index)) !== -1) |
| 245 break; |
| 246 } |
| 247 return new WebInspector.TextRange(lineNumber, index + 1, lineNumber, columnN
umber); |
| 248 } |
| 249 |
| 250 /** |
| 251 * @param {!WebInspector.TextRange} prefixRange |
| 252 * @param {!WebInspector.TextRange} substituteRange |
| 253 * @return {!Promise<!WebInspector.SuggestBox.Suggestions>} |
| 254 */ |
| 255 _wordsWithPrefix(prefixRange, substituteRange) { |
| 256 var prefix = this._editor.text(prefixRange); |
| 257 var before = this._editor.text(new WebInspector.TextRange(0, 0, prefixRange.
startLine, prefixRange.startColumn)); |
| 258 var historyWords = this._historyCompletions(prefix); |
| 259 return WebInspector.ExecutionContextSelector.completionsForTextInCurrentCont
ext(before, prefix, true /* force */) |
| 260 .then(innerWordsWithPrefix); |
| 261 |
| 262 /** |
| 263 * @param {!Array<string>} words |
| 264 * @return {!WebInspector.SuggestBox.Suggestions} |
| 265 */ |
| 266 function innerWordsWithPrefix(words) { |
| 267 return words.map(item => ({title: item})).concat(historyWords); |
| 268 } |
| 269 } |
| 270 |
| 271 _editorSetForTest() { |
| 272 } |
51 }; | 273 }; |
52 | 274 |
53 WebInspector.ConsolePrompt.prototype = { | |
54 /** | |
55 * @return {!WebInspector.ConsoleHistoryManager} | |
56 */ | |
57 history: function() | |
58 { | |
59 return this._history; | |
60 }, | |
61 | |
62 clearAutocomplete: function() | |
63 { | |
64 if (this._editor) | |
65 this._editor.clearAutocomplete(); | |
66 }, | |
67 | |
68 /** | |
69 * @return {boolean} | |
70 */ | |
71 _isCaretAtEndOfPrompt: function() | |
72 { | |
73 return !!this._editor && this._editor.selection().collapseToEnd().equal(
this._editor.fullRange().collapseToEnd()); | |
74 }, | |
75 | |
76 moveCaretToEndOfPrompt: function() | |
77 { | |
78 if (this._editor) | |
79 this._editor.setSelection(WebInspector.TextRange.createFromLocation(
Infinity, Infinity)); | |
80 }, | |
81 | |
82 /** | |
83 * @param {string} text | |
84 */ | |
85 setText: function(text) | |
86 { | |
87 if (this._editor) | |
88 this._editor.setText(text); | |
89 else | |
90 this._initialText = text; | |
91 }, | |
92 | |
93 /** | |
94 * @return {string} | |
95 */ | |
96 text: function() | |
97 { | |
98 return this._editor ? this._editor.text() : this._initialText; | |
99 }, | |
100 | |
101 /** | |
102 * @param {boolean} value | |
103 */ | |
104 setAddCompletionsFromHistory: function(value) | |
105 { | |
106 this._addCompletionsFromHistory = value; | |
107 }, | |
108 | |
109 /** | |
110 * @param {!Event} event | |
111 */ | |
112 _editorKeyDown: function(event) | |
113 { | |
114 var keyboardEvent = /** @type {!KeyboardEvent} */ (event); | |
115 var newText; | |
116 var isPrevious; | |
117 | |
118 switch (keyboardEvent.keyCode) { | |
119 case WebInspector.KeyboardShortcut.Keys.Up.code: | |
120 if (this._editor.selection().endLine > 0) | |
121 break; | |
122 newText = this._history.previous(this.text()); | |
123 isPrevious = true; | |
124 break; | |
125 case WebInspector.KeyboardShortcut.Keys.Down.code: | |
126 if (this._editor.selection().endLine < this._editor.fullRange().endL
ine) | |
127 break; | |
128 newText = this._history.next(); | |
129 break; | |
130 case WebInspector.KeyboardShortcut.Keys.P.code: // Ctrl+P = Previous | |
131 if (WebInspector.isMac() && keyboardEvent.ctrlKey && !keyboardEvent.
metaKey && !keyboardEvent.altKey && !keyboardEvent.shiftKey) { | |
132 newText = this._history.previous(this.text()); | |
133 isPrevious = true; | |
134 } | |
135 break; | |
136 case WebInspector.KeyboardShortcut.Keys.N.code: // Ctrl+N = Next | |
137 if (WebInspector.isMac() && keyboardEvent.ctrlKey && !keyboardEvent.
metaKey && !keyboardEvent.altKey && !keyboardEvent.shiftKey) | |
138 newText = this._history.next(); | |
139 break; | |
140 case WebInspector.KeyboardShortcut.Keys.Enter.code: | |
141 this._enterKeyPressed(keyboardEvent); | |
142 break; | |
143 } | |
144 | |
145 if (newText === undefined) | |
146 return; | |
147 keyboardEvent.consume(true); | |
148 this.setText(newText); | |
149 | |
150 if (isPrevious) | |
151 this._editor.setSelection(WebInspector.TextRange.createFromLocation(
0, Infinity)); | |
152 else | |
153 this.moveCaretToEndOfPrompt(); | |
154 }, | |
155 | |
156 /** | |
157 * @param {!KeyboardEvent} event | |
158 */ | |
159 _enterKeyPressed: function(event) | |
160 { | |
161 if (event.altKey || event.ctrlKey || event.shiftKey) | |
162 return; | |
163 | |
164 event.consume(true); | |
165 | |
166 this.clearAutocomplete(); | |
167 | |
168 var str = this.text(); | |
169 if (!str.length) | |
170 return; | |
171 | |
172 var currentExecutionContext = WebInspector.context.flavor(WebInspector.E
xecutionContext); | |
173 if (!this._isCaretAtEndOfPrompt() || !currentExecutionContext) { | |
174 this._appendCommand(str, true); | |
175 return; | |
176 } | |
177 currentExecutionContext.target().runtimeModel.compileScript(str, "", fal
se, currentExecutionContext.id, compileCallback.bind(this)); | |
178 | |
179 /** | |
180 * @param {!RuntimeAgent.ScriptId=} scriptId | |
181 * @param {?RuntimeAgent.ExceptionDetails=} exceptionDetails | |
182 * @this {WebInspector.ConsolePrompt} | |
183 */ | |
184 function compileCallback(scriptId, exceptionDetails) | |
185 { | |
186 if (str !== this.text()) | |
187 return; | |
188 if (exceptionDetails && (exceptionDetails.exception.description.star
tsWith("SyntaxError: Unexpected end of input") | |
189 || exceptionDetails.exception.description.startsWith("SyntaxErro
r: Unterminated template literal"))) { | |
190 this._editor.newlineAndIndent(); | |
191 this._enterProcessedForTest(); | |
192 return; | |
193 } | |
194 this._appendCommand(str, true); | |
195 this._enterProcessedForTest(); | |
196 } | |
197 }, | |
198 | |
199 /** | |
200 * @param {string} text | |
201 * @param {boolean} useCommandLineAPI | |
202 */ | |
203 _appendCommand: function(text, useCommandLineAPI) | |
204 { | |
205 this.setText(""); | |
206 var currentExecutionContext = WebInspector.context.flavor(WebInspector.E
xecutionContext); | |
207 if (currentExecutionContext) { | |
208 WebInspector.ConsoleModel.evaluateCommandInConsole(currentExecutionC
ontext, text, useCommandLineAPI); | |
209 if (WebInspector.ConsolePanel.instance().isShowing()) | |
210 WebInspector.userMetrics.actionTaken(WebInspector.UserMetrics.Ac
tion.CommandEvaluatedInConsolePanel); | |
211 } | |
212 }, | |
213 | |
214 _enterProcessedForTest: function() { }, | |
215 | |
216 /** | |
217 * @param {string} prefix | |
218 * @return {!WebInspector.SuggestBox.Suggestions} | |
219 */ | |
220 _historyCompletions: function(prefix) | |
221 { | |
222 if (!this._addCompletionsFromHistory || !this._isCaretAtEndOfPrompt()) | |
223 return []; | |
224 var result = []; | |
225 var text = this.text(); | |
226 var set = new Set(); | |
227 var data = this._history.historyData(); | |
228 for (var i = data.length - 1; i >= 0 && result.length < 50; --i) { | |
229 var item = data[i]; | |
230 if (!item.startsWith(text)) | |
231 continue; | |
232 if (set.has(item)) | |
233 continue; | |
234 set.add(item); | |
235 result.push({ title: item.substring(text.length - prefix.length), cl
assName: "additional" }); | |
236 } | |
237 return result; | |
238 }, | |
239 | |
240 /** | |
241 * @override | |
242 */ | |
243 focus: function() | |
244 { | |
245 if (this._editor) | |
246 this._editor.widget().focus(); | |
247 else | |
248 this.element.focus(); | |
249 }, | |
250 | |
251 /** | |
252 * @param {number} lineNumber | |
253 * @param {number} columnNumber | |
254 * @return {?WebInspector.TextRange} | |
255 */ | |
256 _substituteRange: function(lineNumber, columnNumber) | |
257 { | |
258 var lineText = this._editor.line(lineNumber); | |
259 var index; | |
260 for (index = lineText.length - 1; index >= 0; index--) { | |
261 if (" =:[({;,!+-*/&|^<>.".indexOf(lineText.charAt(index)) !== -1) | |
262 break; | |
263 } | |
264 return new WebInspector.TextRange(lineNumber, index + 1, lineNumber, col
umnNumber); | |
265 }, | |
266 | |
267 /** | |
268 * @param {!WebInspector.TextRange} prefixRange | |
269 * @param {!WebInspector.TextRange} substituteRange | |
270 * @return {!Promise<!WebInspector.SuggestBox.Suggestions>} | |
271 */ | |
272 _wordsWithPrefix: function(prefixRange, substituteRange) | |
273 { | |
274 var prefix = this._editor.text(prefixRange); | |
275 var before = this._editor.text(new WebInspector.TextRange(0, 0, prefixRa
nge.startLine, prefixRange.startColumn)); | |
276 var historyWords = this._historyCompletions(prefix); | |
277 return WebInspector.ExecutionContextSelector.completionsForTextInCurrent
Context(before, prefix, true /* force */).then(innerWordsWithPrefix); | |
278 | |
279 /** | |
280 * @param {!Array<string>} words | |
281 * @return {!WebInspector.SuggestBox.Suggestions} | |
282 */ | |
283 function innerWordsWithPrefix(words) | |
284 { | |
285 return words.map(item => ({title:item})).concat(historyWords); | |
286 } | |
287 }, | |
288 | |
289 _editorSetForTest: function() { }, | |
290 | |
291 __proto__: WebInspector.Widget.prototype | |
292 }; | |
293 | |
294 /** | 275 /** |
295 * @constructor | 276 * @unrestricted |
296 */ | 277 */ |
297 WebInspector.ConsoleHistoryManager = function() | 278 WebInspector.ConsoleHistoryManager = class { |
298 { | 279 constructor() { |
299 /** | 280 /** |
300 * @type {!Array.<string>} | 281 * @type {!Array.<string>} |
301 */ | 282 */ |
302 this._data = []; | 283 this._data = []; |
303 | 284 |
304 /** | 285 /** |
305 * 1-based entry in the history stack. | 286 * 1-based entry in the history stack. |
306 * @type {number} | 287 * @type {number} |
307 */ | 288 */ |
308 this._historyOffset = 1; | 289 this._historyOffset = 1; |
| 290 } |
| 291 |
| 292 /** |
| 293 * @return {!Array.<string>} |
| 294 */ |
| 295 historyData() { |
| 296 return this._data; |
| 297 } |
| 298 |
| 299 /** |
| 300 * @param {!Array.<string>} data |
| 301 */ |
| 302 setHistoryData(data) { |
| 303 this._data = data.slice(); |
| 304 this._historyOffset = 1; |
| 305 } |
| 306 |
| 307 /** |
| 308 * Pushes a committed text into the history. |
| 309 * @param {string} text |
| 310 */ |
| 311 pushHistoryItem(text) { |
| 312 if (this._uncommittedIsTop) { |
| 313 this._data.pop(); |
| 314 delete this._uncommittedIsTop; |
| 315 } |
| 316 |
| 317 this._historyOffset = 1; |
| 318 if (text === this._currentHistoryItem()) |
| 319 return; |
| 320 this._data.push(text); |
| 321 } |
| 322 |
| 323 /** |
| 324 * Pushes the current (uncommitted) text into the history. |
| 325 * @param {string} currentText |
| 326 */ |
| 327 _pushCurrentText(currentText) { |
| 328 if (this._uncommittedIsTop) |
| 329 this._data.pop(); // Throw away obsolete uncommitted text. |
| 330 this._uncommittedIsTop = true; |
| 331 this._data.push(currentText); |
| 332 } |
| 333 |
| 334 /** |
| 335 * @param {string} currentText |
| 336 * @return {string|undefined} |
| 337 */ |
| 338 previous(currentText) { |
| 339 if (this._historyOffset > this._data.length) |
| 340 return undefined; |
| 341 if (this._historyOffset === 1) |
| 342 this._pushCurrentText(currentText); |
| 343 ++this._historyOffset; |
| 344 return this._currentHistoryItem(); |
| 345 } |
| 346 |
| 347 /** |
| 348 * @return {string|undefined} |
| 349 */ |
| 350 next() { |
| 351 if (this._historyOffset === 1) |
| 352 return undefined; |
| 353 --this._historyOffset; |
| 354 return this._currentHistoryItem(); |
| 355 } |
| 356 |
| 357 /** |
| 358 * @return {string|undefined} |
| 359 */ |
| 360 _currentHistoryItem() { |
| 361 return this._data[this._data.length - this._historyOffset]; |
| 362 } |
309 }; | 363 }; |
310 | |
311 WebInspector.ConsoleHistoryManager.prototype = { | |
312 /** | |
313 * @return {!Array.<string>} | |
314 */ | |
315 historyData: function() | |
316 { | |
317 return this._data; | |
318 }, | |
319 | |
320 /** | |
321 * @param {!Array.<string>} data | |
322 */ | |
323 setHistoryData: function(data) | |
324 { | |
325 this._data = data.slice(); | |
326 this._historyOffset = 1; | |
327 }, | |
328 | |
329 /** | |
330 * Pushes a committed text into the history. | |
331 * @param {string} text | |
332 */ | |
333 pushHistoryItem: function(text) | |
334 { | |
335 if (this._uncommittedIsTop) { | |
336 this._data.pop(); | |
337 delete this._uncommittedIsTop; | |
338 } | |
339 | |
340 this._historyOffset = 1; | |
341 if (text === this._currentHistoryItem()) | |
342 return; | |
343 this._data.push(text); | |
344 }, | |
345 | |
346 /** | |
347 * Pushes the current (uncommitted) text into the history. | |
348 * @param {string} currentText | |
349 */ | |
350 _pushCurrentText: function(currentText) | |
351 { | |
352 if (this._uncommittedIsTop) | |
353 this._data.pop(); // Throw away obsolete uncommitted text. | |
354 this._uncommittedIsTop = true; | |
355 this._data.push(currentText); | |
356 }, | |
357 | |
358 /** | |
359 * @param {string} currentText | |
360 * @return {string|undefined} | |
361 */ | |
362 previous: function(currentText) | |
363 { | |
364 if (this._historyOffset > this._data.length) | |
365 return undefined; | |
366 if (this._historyOffset === 1) | |
367 this._pushCurrentText(currentText); | |
368 ++this._historyOffset; | |
369 return this._currentHistoryItem(); | |
370 }, | |
371 | |
372 /** | |
373 * @return {string|undefined} | |
374 */ | |
375 next: function() | |
376 { | |
377 if (this._historyOffset === 1) | |
378 return undefined; | |
379 --this._historyOffset; | |
380 return this._currentHistoryItem(); | |
381 }, | |
382 | |
383 /** | |
384 * @return {string|undefined} | |
385 */ | |
386 _currentHistoryItem: function() | |
387 { | |
388 return this._data[this._data.length - this._historyOffset]; | |
389 } | |
390 }; | |
OLD | NEW |