Bug 1578283 - Don't scroll jsterm viewport when inserting a tab character. r=Honza.

When we wanted to insert a string in the webconsole input,
we were setting the input value, and setting the cursor
manually. But since the editor setCursor function is calling
alignLine, there could be cases where the editor scroll position
would jump, feeling awkward for the user.
It turns out we can simplify this code a lot since codeMirror
provides a replaceRange function, which is a perfect replacement
for what we were using, without having to manage the cursor position.

The only downside to that is that inserting characters this
way *does* fire a `changes` event, that we are listening to
in the JsTerm to request autocompletion (which we don't need
as we only insert characters when accepting a completion or
adding a tab).
To mitigate that, we pass a specific jsterm origin string to
replaceRange, which let's us discriminate in the changes event
listener if those changes originate from jsterm only actions.

A test is added to ensure this works as expected (the test was
failing without the fix).

Differential Revision: https://phabricator.services.mozilla.com/D44466

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Nicolas Chevobbe 2019-09-04 09:02:09 +00:00
parent d4fab048af
commit 010f6b2666
3 changed files with 64 additions and 22 deletions

View File

@ -65,6 +65,8 @@ const {
HISTORY_FORWARD,
} = require("devtools/client/webconsole/constants");
const JSTERM_CODEMIRROR_ORIGIN = "jsterm";
/**
* Create a JSTerminal (a JavaScript command line). This is attached to an
* existing HeadsUpDisplay (a Web Console instance). This code is responsible
@ -645,10 +647,20 @@ class JSTerm extends Component {
/**
* The editor "changes" event handler.
*/
_onEditorChanges() {
_onEditorChanges(cm, changes) {
const value = this._getValue();
if (this.lastInputValue !== value) {
if (this.props.autocomplete || this.autocompletePopup.isOpen) {
// We don't autocomplete if the changes were made by JsTerm (e.g. autocomplete was
// accepted).
const isJsTermChangeOnly = changes.every(
({ origin }) => origin === JSTERM_CODEMIRROR_ORIGIN
);
if (
!isJsTermChangeOnly &&
(this.props.autocomplete || this.autocompletePopup.isOpen)
) {
this.autocompleteUpdate();
}
this.lastInputValue = value;
@ -944,27 +956,15 @@ class JSTerm extends Component {
return;
}
const value = this._getValue();
let prefix = this.getInputValueBeforeCursor();
const suffix = value.replace(prefix, "");
const cursor = this.editor.getCursor();
const from = {
line: cursor.line,
ch: cursor.ch - numberOfCharsToReplaceCharsBeforeCursor,
};
if (numberOfCharsToReplaceCharsBeforeCursor) {
prefix = prefix.substring(
0,
prefix.length - numberOfCharsToReplaceCharsBeforeCursor
);
}
// We need to retrieve the cursor before setting the new value.
const { line, ch } = this.editor.getCursor();
this._setValue(prefix + str + suffix);
// Set the cursor on the same line it was already at, after the autocompleted text
this.editor.setCursor({
line,
ch: ch + str.length - numberOfCharsToReplaceCharsBeforeCursor,
});
this.editor
.getDoc()
.replaceRange(str, from, cursor, JSTERM_CODEMIRROR_ORIGIN);
}
/**

View File

@ -262,6 +262,7 @@ skip-if = (os == "win" && processor == "aarch64") # disabled on aarch64 due to 1
[browser_jsterm_history_arrow_keys.js]
[browser_jsterm_history_nav.js]
[browser_jsterm_history_persist.js]
[browser_jsterm_insert_tab_when_overflows_no_scroll.js]
[browser_jsterm_inspect.js]
[browser_jsterm_inspect_panels.js]
[browser_jsterm_instance_of.js]

View File

@ -0,0 +1,41 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// Check that when the input overflows, inserting a tab doesn't not impact the
// scroll position. See Bug 1578283.
"use strict";
const TEST_URI = "data:text/html,<meta charset=utf8>";
add_task(async function() {
const hud = await openNewTabAndConsole(TEST_URI);
const cmScroller = hud.ui.outputNode.querySelector(".CodeMirror-scroll");
info("Fill in the input with a hundred lines to make it overflow");
await setInputValue(hud, "x;\n".repeat(100));
ok(hasVerticalOverflow(cmScroller), "input overflows");
info("Put the cursor at the very beginning");
hud.jsterm.editor.setCursor({
line: 0,
ch: 0,
});
is(cmScroller.scrollTop, 0, "input is scrolled all the way up");
info("Move the cursor one line down and hit Tab");
EventUtils.synthesizeKey("KEY_ArrowDown");
EventUtils.synthesizeKey("KEY_Tab");
checkInputValueAndCursorPosition(
hud,
`x;\n\t|x;\n${"x;\n".repeat(98)}`,
"a tab char was added at the start of the second line after hitting Tab"
);
is(
cmScroller.scrollTop,
0,
"Scroll position wasn't affected by new char addition"
);
});