Commit 8bb1cb18 authored by Erik Luo's avatar Erik Luo Committed by Commit Bot

DevTools: make console prompt aware of linewrap in handling arrow keys

The console prompt currently listens for ArrowUp/ArrowDown and loads
the next/previous command from history, if the cursor is on the
first/last line.

Since a logical CodeMirror line may wrap onto multiple visual rows,
this may unintentionally load the next command. This CL adds a check
whether the cursor is truly on the first/last visual row.

Problem gif: https://imgur.com/a/s7gPL

Bug: 808130
Change-Id: I04363e25206cece28b32b80dfc548340413112cf
Reviewed-on: https://chromium-review.googlesource.com/927690
Commit-Queue: Erik Luo <luoe@chromium.org>
Reviewed-by: default avatarDmitry Gozman <dgozman@chromium.org>
Reviewed-by: default avatarJoel Einbinder <einbinder@chromium.org>
Cr-Commit-Position: refs/heads/master@{#541714}
parent 60aa5ce2
Tests that console prompt keyboard events work.
Adding first message: First
multiline command
Setting prompt text: Second
multiline command
Adding first message: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
Setting prompt text: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
Test that arrow Up stays in the same command
{"startLine":1,"startColumn":0,"endLine":1,"endColumn":0}
Prompt text:Second
multiline command
Prompt is displaying SECOND message
Test that ArrowUp+shift stays in the same command
{"startLine":0,"startColumn":0,"endLine":0,"endColumn":1}
Prompt text:Second
multiline command
Prompt is displaying SECOND message
Test that arrow Up on the first line, second visual row stays in the same command
{"startLine":0,"startColumn":100,"endLine":0,"endColumn":100}
Prompt is displaying SECOND message
Test that arrow Up from the first line loads previous command
{"startLine":0,"startColumn":0,"endLine":0,"endColumn":0}
Prompt text:First
multiline command
Prompt is displaying FIRST message
Test that arrow Down stays in the same command
{"startLine":0,"startColumn":0,"endLine":0,"endColumn":0}
Prompt text:First
multiline command
Prompt is displaying FIRST message
Test that ArrowDown+shift stays in the same command
{"startLine":1,"startColumn":0,"endLine":1,"endColumn":1}
Prompt text:First
multiline command
Prompt is displaying FIRST message
Test that arrow Down from the first line loads next command
Test that arrow Down on the last line, first visual row stays in the same command
{"startLine":1,"startColumn":0,"endLine":1,"endColumn":0}
Prompt text:Second
multiline command
Prompt is displaying FIRST message
Test that arrow Down from the first line loads next command
{"startLine":1,"startColumn":100,"endLine":1,"endColumn":100}
Prompt is displaying SECOND message
......@@ -8,12 +8,15 @@
await TestRunner.loadModule('console_test_runner');
await TestRunner.showPanel('console');
await ConsoleTestRunner.waitUntilConsoleEditorLoaded();
// Make sure that `singleLineCharCount` wraps onto multiple lines.
var singleLineCharCount = 100;
ConsoleTestRunner.fixConsoleViewportDimensions(300, 200);
var firstCommand = 'First\nmultiline command';
var secondCommand = 'Second\nmultiline command';
var firstCommand = 'a'.repeat(singleLineCharCount) + '\n' + 'b'.repeat(singleLineCharCount);
TestRunner.addResult('Adding first message: ' + firstCommand);
await ConsoleTestRunner.evaluateInConsolePromise(firstCommand);
var secondCommand = 'x'.repeat(singleLineCharCount) + '\n' + 'y'.repeat(singleLineCharCount);
TestRunner.addResult('Setting prompt text: ' + secondCommand);
var prompt = Console.ConsoleView.instance()._prompt;
prompt.setText(secondCommand);
......@@ -22,41 +25,62 @@
prompt._editor.setSelection(TextUtils.TextRange.createFromLocation(1, 0));
dumpSelection();
sendKeyUpToPrompt();
TestRunner.addResult('Prompt text:' + prompt.text());
printSelectedCommand();
TestRunner.addResult('\nTest that ArrowUp+shift stays in the same command');
prompt._editor.setSelection(new TextUtils.TextRange(0, 0, 0, 1));
dumpSelection();
sendKeyUpToPrompt(true);
TestRunner.addResult('Prompt text:' + prompt.text());
printSelectedCommand();
TestRunner.addResult('\nTest that arrow Up on the first line, second visual row stays in the same command');
prompt._editor.setSelection(TextUtils.TextRange.createFromLocation(0, singleLineCharCount));
dumpSelection();
sendKeyUpToPrompt();
printSelectedCommand();
TestRunner.addResult('\nTest that arrow Up from the first line loads previous command');
prompt._editor.setSelection(TextUtils.TextRange.createFromLocation(0, 0));
dumpSelection();
sendKeyUpToPrompt();
TestRunner.addResult('Prompt text:' + prompt.text());
printSelectedCommand();
TestRunner.addResult('\nTest that arrow Down stays in the same command');
prompt._editor.setSelection(TextUtils.TextRange.createFromLocation(0, 0));
dumpSelection();
sendKeyDownToPrompt();
TestRunner.addResult('Prompt text:' + prompt.text());
printSelectedCommand();
TestRunner.addResult('\nTest that ArrowDown+shift stays in the same command');
prompt._editor.setSelection(new TextUtils.TextRange(1, 0, 1, 1));
dumpSelection();
sendKeyDownToPrompt(true);
TestRunner.addResult('Prompt text:' + prompt.text());
printSelectedCommand();
TestRunner.addResult('\nTest that arrow Down from the first line loads next command');
TestRunner.addResult('\nTest that arrow Down on the last line, first visual row stays in the same command');
prompt._editor.setSelection(TextUtils.TextRange.createFromLocation(1, 0));
dumpSelection();
sendKeyDownToPrompt();
TestRunner.addResult('Prompt text:' + prompt.text());
printSelectedCommand();
TestRunner.addResult('\nTest that arrow Down from the first line loads next command');
prompt._editor.setSelection(TextUtils.TextRange.createFromLocation(1, singleLineCharCount));
dumpSelection();
sendKeyDownToPrompt();
printSelectedCommand();
TestRunner.completeTest();
function printSelectedCommand() {
if (prompt.text().startsWith('a'))
TestRunner.addResult('Prompt is displaying FIRST message');
else if (prompt.text().startsWith('x'))
TestRunner.addResult('Prompt is displaying SECOND message');
else
TestRunner.addResult('TEST FAILURE');
}
/**
* @param {boolean} shiftKey
*/
......
......@@ -104,16 +104,22 @@ Console.ConsolePrompt = class extends UI.Widget {
const keyboardEvent = /** @type {!KeyboardEvent} */ (event);
let newText;
let isPrevious;
// Check against visual coordinates in case lines wrap.
const selection = this._editor.selection();
const cursorY = this._editor.visualCoordinates(selection.endLine, selection.endColumn).y;
switch (keyboardEvent.keyCode) {
case UI.KeyboardShortcut.Keys.Up.code:
if (keyboardEvent.shiftKey || this._editor.selection().endLine > 0)
const startY = this._editor.visualCoordinates(0, 0).y;
if (keyboardEvent.shiftKey || !selection.isEmpty() || cursorY !== startY)
break;
newText = this._history.previous(this.text());
isPrevious = true;
break;
case UI.KeyboardShortcut.Keys.Down.code:
if (keyboardEvent.shiftKey || this._editor.selection().endLine < this._editor.fullRange().endLine)
const fullRange = this._editor.fullRange();
const endY = this._editor.visualCoordinates(fullRange.endLine, fullRange.endColumn).y;
if (keyboardEvent.shiftKey || !selection.isEmpty() || cursorY !== endY)
break;
newText = this._history.next();
break;
......
......@@ -609,6 +609,17 @@ TextEditor.CodeMirrorTextEditor = class extends UI.VBox {
return TextEditor.CodeMirrorUtils.toRange(coords, coords);
}
/**
* @override
* @param {number} lineNumber
* @param {number} columnNumber
* @return {!{x: number, y: number}}
*/
visualCoordinates(lineNumber, columnNumber) {
const metrics = this._codeMirror.cursorCoords(new CodeMirror.Pos(lineNumber, columnNumber));
return {x: metrics.left, y: metrics.top};
}
/**
* @override
* @param {number} lineNumber
......
......@@ -73,6 +73,13 @@ UI.TextEditor.prototype = {
clearAutocomplete() {},
/**
* @param {number} lineNumber
* @param {number} columnNumber
* @return {!{x: number, y: number}}
*/
visualCoordinates(lineNumber, columnNumber) {},
/**
* @param {number} lineNumber
* @param {number} columnNumber
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment