Bug 1485990 - Display 1-item-only autocomplete popup if autocompletion text can't be displayed; r=bgrins.
authorNicolas Chevobbe <nchevobbe@mozilla.com>
Mon, 27 Aug 2018 16:25:57 +0000
changeset 488620 c7c09f0fedf60e9b4137542866d5159e66037286
parent 488619 4c603c11ce8c0cdb1b16735f2148ab0277fe39ed
child 488646 df602a252b663b56faed75655ce13c04884e0ad3
push id9734
push usershindli@mozilla.com
push dateThu, 30 Aug 2018 12:18:07 +0000
treeherdermozilla-beta@71c71ab3afae [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbgrins
bugs1485990
milestone63.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1485990 - Display 1-item-only autocomplete popup if autocompletion text can't be displayed; r=bgrins. If the autocomplete only returns 1 item, we usually close the popup and show the autocompletion text. But in some cases the autocompletion text can't be shown (e.g. there's some text after the cursor). So we end up showing nothing for the user, which is not ideal. In such case, this patch ensures we do show the popup so the user can autocomplete and save some keystrokes. Depends on D4061 Differential Revision: https://phabricator.services.mozilla.com/D4335
devtools/client/webconsole/components/JSTerm.js
devtools/client/webconsole/test/mochitest/browser_jsterm_autocomplete_inside_text.js
--- a/devtools/client/webconsole/components/JSTerm.js
+++ b/devtools/client/webconsole/components/JSTerm.js
@@ -1175,19 +1175,26 @@ class JSTerm extends Component {
     popup.setItems(items);
 
     const minimumAutoCompleteLength = 2;
 
     // We want to show the autocomplete popup if:
     // - there are at least 2 matching results
     // - OR, if there's 1 result, but whose label does not start like the input (this can
     //   happen with insensitive search: `num` will match `Number`).
-    if (items.length >= minimumAutoCompleteLength || (
-      items.length === 1 && items[0].preLabel !== matchProp
-    )) {
+    // - OR, if there's 1 result, but we can't show the completionText (because there's
+    // some text after the cursor), unless the text in the popup is the same as the input.
+    if (items.length >= minimumAutoCompleteLength
+      || (items.length === 1 && items[0].preLabel !== matchProp)
+      || (
+        items.length === 1
+        && !this.canDisplayAutoCompletionText()
+        && items[0].label !== matchProp
+      )
+    ) {
       let popupAlignElement;
       let xOffset;
       let yOffset;
 
       if (this.editor) {
         popupAlignElement = this.node.querySelector(".CodeMirror-cursor");
         // We need to show the popup at the ".".
         xOffset = -1 * matchProp.length * this._inputCharWidth;
--- a/devtools/client/webconsole/test/mochitest/browser_jsterm_autocomplete_inside_text.js
+++ b/devtools/client/webconsole/test/mochitest/browser_jsterm_autocomplete_inside_text.js
@@ -44,19 +44,17 @@ async function performTests() {
   is(popup.selectedIndex, 0, "popup.selectedIndex is correct");
   ok(!getJsTermCompletionValue(jsterm), "there is no completion text");
 
   info("Pressing arrow right");
   let onPopupClose = popup.once("popup-closed");
   EventUtils.synthesizeKey("KEY_ArrowRight");
   await onPopupClose;
   ok(true, "popup was closed");
-  let expectedInput = "dump(window.testB)";
-  is(jsterm.getInputValue(), expectedInput, "input wasn't modified");
-  checkJsTermCursor(jsterm, expectedInput.length, "cursor was moved to the right");
+  checkJsTermValueAndCursor(jsterm, "dump(window.testB)|", "input wasn't modified");
 
   await setInitialState(jsterm);
   EventUtils.synthesizeKey("KEY_ArrowDown");
   is(popup.selectedIndex, 1, "popup.selectedIndex is correct");
   ok(!getJsTermCompletionValue(jsterm), "completeNode.value is empty");
 
   const items = popup.getItems().map(e => e.label);
   const expectedItems = ["testBugAA", "testBugBB"];
@@ -64,51 +62,57 @@ async function performTests() {
 
   info("press Tab and wait for popup to hide");
   onPopupClose = popup.once("popup-closed");
   EventUtils.synthesizeKey("KEY_Tab");
   await onPopupClose;
 
   // At this point the completion suggestion should be accepted.
   ok(!popup.isOpen, "popup is not open");
-  expectedInput = "dump(window.testBugBB)";
-  is(jsterm.getInputValue(), expectedInput, "completion was successful after VK_TAB");
-  checkJsTermCursor(jsterm, expectedInput.length - 1, "cursor location is correct");
+  checkJsTermValueAndCursor(jsterm, "dump(window.testBugBB|)",
+    "completion was successful after VK_TAB");
   ok(!getJsTermCompletionValue(jsterm), "there is no completion text");
 
   info("Test ENTER key when popup is visible with a selected item");
   await setInitialState(jsterm);
   info("press Enter and wait for popup to hide");
   onPopupClose = popup.once("popup-closed");
   EventUtils.synthesizeKey("KEY_Enter");
   await onPopupClose;
 
   ok(!popup.isOpen, "popup is not open");
-  expectedInput = "dump(window.testBugAA)";
-  is(jsterm.getInputValue(), expectedInput, "completion was successful after Enter");
-  checkJsTermCursor(jsterm, expectedInput.length - 1, "cursor location is correct");
+  checkJsTermValueAndCursor(jsterm, "dump(window.testBugAA|)",
+    "completion was successful after Enter");
   ok(!getJsTermCompletionValue(jsterm), "there is no completion text");
 
-  info("Test TAB key when there is no autocomplete suggestion");
+  info("Test autocomplete inside parens");
   jsterm.setInputValue("dump()");
   EventUtils.synthesizeKey("KEY_ArrowLeft");
   const onAutocompleteUpdated = jsterm.once("autocomplete-updated");
   EventUtils.sendString("window.testBugA");
   await onAutocompleteUpdated;
+  ok(popup.isOpen, "popup is open");
+  ok(!getJsTermCompletionValue(jsterm), "there is no completion text");
+
+  info("Matching the completion proposal should close the popup");
+  onPopupClose = popup.once("popup-closed");
+  EventUtils.sendString("A");
+  await onPopupClose;
+
+  info("Test TAB key when there is no autocomplete suggestion");
   ok(!popup.isOpen, "popup is not open");
   ok(!getJsTermCompletionValue(jsterm), "there is no completion text");
 
   EventUtils.synthesizeKey("KEY_Tab");
-
-  expectedInput = "dump(window.testBugAA)";
-  is(jsterm.getInputValue(), "dump(window.testBugA\t)", "Tab inserted a tab char");
-  checkJsTermCursor(jsterm, expectedInput.length - 1, "cursor location is correct");
+  checkJsTermValueAndCursor(jsterm, "dump(window.testBugAA\t|)",
+    "completion was successful after Enter");
 }
 
-function setInitialState(jsterm) {
+async function setInitialState(jsterm) {
   jsterm.focus();
   jsterm.setInputValue("dump()");
   EventUtils.synthesizeKey("KEY_ArrowLeft");
 
   const onPopUpOpen = jsterm.autocompletePopup.once("popup-opened");
   EventUtils.sendString("window.testB");
-  return onPopUpOpen;
+  checkJsTermValueAndCursor(jsterm, "dump(window.testB|)");
+  await onPopUpOpen;
 }