Bug 1509440 - Fix JsTerm completionText handling with Left/Home/End keys; r=Honza.
authorNicolas Chevobbe <nchevobbe@mozilla.com>
Tue, 27 Nov 2018 12:39:45 +0000
changeset 507519 614d2236358a744b6650d3f1b6f3b9c30a0357a9
parent 507518 40e1670547263c1b86b6f58dd4f481830eecd10c
child 507520 d4382e31f5e4560776a548c597014554bb76b74f
push id1905
push userffxbld-merge
push dateMon, 21 Jan 2019 12:33:13 +0000
treeherdermozilla-release@c2fca1944d8c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersHonza
bugs1509440
milestone65.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 1509440 - Fix JsTerm completionText handling with Left/Home/End keys; r=Honza. Differential Revision: https://phabricator.services.mozilla.com/D12772
devtools/client/webconsole/components/JSTerm.js
devtools/client/webconsole/test/mochitest/browser_jsterm_autocomplete_arrow_keys.js
devtools/client/webconsole/test/mochitest/browser_jsterm_autocomplete_nav_and_tab_key.js
--- a/devtools/client/webconsole/components/JSTerm.js
+++ b/devtools/client/webconsole/components/JSTerm.js
@@ -167,16 +167,23 @@ class JSTerm extends Component {
           }
 
           if (!inputUpdated) {
             return "CodeMirror.Pass";
           }
           return null;
         };
 
+        const onArrowLeft = () => {
+          if (this.autocompletePopup.isOpen || this.getAutoCompletionText()) {
+            this.clearCompletion();
+          }
+          return "CodeMirror.Pass";
+        };
+
         this.editor = new Editor({
           autofocus: true,
           enableCodeFolding: false,
           autoCloseBrackets: false,
           gutters: [],
           lineWrapping: true,
           mode: Editor.modes.js,
           styleActiveLine: false,
@@ -225,22 +232,19 @@ class JSTerm extends Component {
             },
 
             "Up": onArrowUp,
             "Cmd-Up": onArrowUp,
 
             "Down": onArrowDown,
             "Cmd-Down": onArrowDown,
 
-            "Left": () => {
-              if (this.autocompletePopup.isOpen || this.getAutoCompletionText()) {
-                this.clearCompletion();
-              }
-              return "CodeMirror.Pass";
-            },
+            "Left": onArrowLeft,
+            "Ctrl-Left": onArrowLeft,
+            "Cmd-Left": onArrowLeft,
 
             "Right": () => {
               // We only want to complete on Right arrow if the completion text is
               // displayed.
               if (this.getAutoCompletionText()) {
                 this.acceptProposedCompletion();
                 return null;
               }
@@ -313,31 +317,39 @@ class JSTerm extends Component {
                 return null;
               }
 
               if (!this.getInputValue()) {
                 this.hud.outputScroller.scrollTop = 0;
                 return null;
               }
 
+              if (this.getAutoCompletionText()) {
+                this.clearCompletion();
+              }
+
               return "CodeMirror.Pass";
             },
 
             "End": () => {
               if (this.autocompletePopup.isOpen) {
                 this.autocompletePopup.selectItemAtIndex(
                   this.autocompletePopup.itemCount - 1);
                 return null;
               }
 
               if (!this.getInputValue()) {
                 this.hud.outputScroller.scrollTop = this.hud.outputScroller.scrollHeight;
                 return null;
               }
 
+              if (this.getAutoCompletionText()) {
+                this.clearCompletion();
+              }
+
               return "CodeMirror.Pass";
             },
 
             "Ctrl-Space": () => {
               if (!this.autocompletePopup.isOpen) {
                 this.fetchAutocompletionProperties(true);
                 return null;
               }
@@ -860,16 +872,22 @@ class JSTerm extends Component {
       }
 
       if (event.key === " " && !this.autocompletePopup.isOpen) {
         // Open the autocompletion popup on Ctrl-Space (if it wasn't displayed).
         this.fetchAutocompletionProperties(true);
         event.preventDefault();
       }
 
+      if (event.keyCode === KeyCodes.DOM_VK_LEFT &&
+        (this.autocompletePopup.isOpen || this.getAutoCompletionText())
+      ) {
+        this.clearCompletion();
+      }
+
       return;
     } else if (event.keyCode == KeyCodes.DOM_VK_RETURN) {
       if (!this.autocompletePopup.isOpen && (
         event.shiftKey || !Debugger.isCompilableUnit(this.getInputValue())
       )) {
         // shift return or incomplete statement
         return;
       }
@@ -942,26 +960,30 @@ class JSTerm extends Component {
         }
         event.preventDefault();
         break;
 
       case KeyCodes.DOM_VK_HOME:
         if (this.autocompletePopup.isOpen) {
           this.autocompletePopup.selectItemAtIndex(0);
           event.preventDefault();
+        } else if (this.getAutoCompletionText()) {
+          this.clearCompletion();
         } else if (inputValue.length <= 0) {
           this.hud.outputScroller.scrollTop = 0;
           event.preventDefault();
         }
         break;
 
       case KeyCodes.DOM_VK_END:
         if (this.autocompletePopup.isOpen) {
           this.autocompletePopup.selectItemAtIndex(this.autocompletePopup.itemCount - 1);
           event.preventDefault();
+        } else if (this.getAutoCompletionText()) {
+          this.clearCompletion();
         } else if (inputValue.length <= 0) {
           this.hud.outputScroller.scrollTop = this.hud.outputScroller.scrollHeight;
           event.preventDefault();
         }
         break;
 
       case KeyCodes.DOM_VK_LEFT:
         if (this.autocompletePopup.isOpen || this.getAutoCompletionText()) {
--- a/devtools/client/webconsole/test/mochitest/browser_jsterm_autocomplete_arrow_keys.js
+++ b/devtools/client/webconsole/test/mochitest/browser_jsterm_autocomplete_arrow_keys.js
@@ -62,9 +62,20 @@ async function performTests() {
 
   info("Test that arrow right selects selected autocomplete item");
   onPopUpClose = popup.once("popup-closed");
   EventUtils.synthesizeKey("KEY_ArrowRight");
   await onPopUpClose;
   checkInput("window.foo.aa|");
   is(popup.isOpen, false, "popup is closed");
   checkJsTermCompletionValue(jsterm, "", "completeNode is empty");
+
+  await setInputValueForAutocompletion(jsterm, "window.foo.a");
+  const prefix = jsterm.getInputValue().replace(/[\S]/g, " ");
+  checkJsTermCompletionValue(jsterm, prefix + "a", "completeNode has expected value");
+
+  const isOSX = Services.appinfo.OS == "Darwin";
+  EventUtils.synthesizeKey("KEY_ArrowLeft", {
+    [isOSX ? "metaKey" : "ctrlKey"]: true,
+  });
+  checkJsTermCompletionValue(jsterm, "",
+    "completeNode was cleared after Ctrl/Cmd + left");
 }
--- a/devtools/client/webconsole/test/mochitest/browser_jsterm_autocomplete_nav_and_tab_key.js
+++ b/devtools/client/webconsole/test/mochitest/browser_jsterm_autocomplete_nav_and_tab_key.js
@@ -8,23 +8,22 @@
 // See Bug 585991.
 
 const TEST_URI = `data:text/html;charset=utf-8,
 <head>
   <script>
     /* Create a prototype-less object so popup does not contain native
      * Object prototype properties.
      */
-    window.foo = Object.create(null);
-    Object.assign(window.foo, {
-      item0: "value0",
+    window.foo = Object.create(null, Object.getOwnPropertyDescriptors({
+      item00: "value0",
       item1: "value1",
       item2: "value2",
       item3: "value3",
-    });
+    }));
   </script>
 </head>
 <body>bug 585991 - autocomplete popup navigation and tab key usage test</body>`;
 
 add_task(async function() {
   // Run test with legacy JsTerm
   await pushPref("devtools.webconsole.jsterm.codeMirror", false);
   await performTests();
@@ -47,30 +46,30 @@ async function performTests() {
   // Shows the popup
   EventUtils.sendString(".");
   await onPopUpOpen;
 
   ok(popup.isOpen, "popup is open");
 
   const popupItems = popup.getItems().map(e => e.label);
   const expectedPopupItems = [
-    "item0",
+    "item00",
     "item1",
     "item2",
     "item3",
   ];
 
   is(popup.itemCount, expectedPopupItems.length, "popup.itemCount is correct");
   is(popupItems.join("-"), expectedPopupItems.join("-"),
     "getItems returns the items we expect");
   is(popup.selectedIndex, 0, "Index of the first item is selected.");
 
   EventUtils.synthesizeKey("KEY_ArrowUp");
 
-  const prefix = jsterm.getInputValue().replace(/[\S]/g, " ");
+  let prefix = jsterm.getInputValue().replace(/[\S]/g, " ");
   is(popup.selectedIndex, 3, "index 3 is selected");
   is(popup.selectedItem.label, "item3", "item3 is selected");
   checkJsTermCompletionValue(jsterm, prefix + "item3", "completeNode.value holds item3");
 
   EventUtils.synthesizeKey("KEY_ArrowUp");
 
   is(popup.selectedIndex, 2, "index 2 is selected");
   is(popup.selectedItem.label, "item2", "item2 is selected");
@@ -103,9 +102,23 @@ async function performTests() {
 
   await onPopupClose;
 
   // At this point the completion suggestion should be accepted.
   ok(!popup.isOpen, "popup is not open");
   is(jsterm.getInputValue(), "window.foo.item3",
      "completion was successful after KEY_Tab");
   ok(!getJsTermCompletionValue(jsterm), "completeNode is empty");
+
+  info("Check that hitting Home hides the completion text when the popup is hidden");
+  await setInputValueForAutocompletion(jsterm, "window.foo.item0");
+  prefix = jsterm.getInputValue().replace(/[\S]/g, " ");
+  checkJsTermCompletionValue(jsterm, prefix + "0", "completeNode has expected value");
+  EventUtils.synthesizeKey("KEY_Home");
+  checkJsTermCompletionValue(jsterm, "", "completeNode was cleared after hitting Home");
+
+  info("Check that hitting End hides the completion text when the popup is hidden");
+  await setInputValueForAutocompletion(jsterm, "window.foo.item0");
+  prefix = jsterm.getInputValue().replace(/[\S]/g, " ");
+  checkJsTermCompletionValue(jsterm, prefix + "0", "completeNode has expected value");
+  EventUtils.synthesizeKey("KEY_End");
+  checkJsTermCompletionValue(jsterm, "", "completeNode was cleared after hitting End");
 }