Skip to content
This repository was archived by the owner on Sep 6, 2021. It is now read-only.

Commit 63962ce

Browse files
bmaxpetetnt
authored andcommitted
Fix for issue #8142: "Ctrl + Space" should move to the next entry when the code hint menu is open (#12251)
* Can now move up with ctrl+space. * Changes made suggested by PR * Found a cleaner way to do the alreadyOpen Bool. Still having trouble with the javascript '.' character hints * Remove unneeded var * Fix issues with CodeHints starting with dots * Fix wrong parameter * Changes made suggested by PR * Fix issues with CodeHints starting with dots * Fix issues with CodeHints starting with dots * Fix issues with CodeHints starting with dots * Remove unneeded var * All tests pass.
1 parent 8cce5ec commit 63962ce

File tree

3 files changed

+157
-39
lines changed

3 files changed

+157
-39
lines changed

src/editor/CodeHintList.js

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -304,14 +304,21 @@ define(function (require, exports, module) {
304304
};
305305

306306
/**
307-
* Check whether keyCode is one of the keys that we handle or not.
307+
* Check whether Event is one of the keys that we handle or not.
308308
*
309-
* @param {number} keyCode
309+
* @param {KeyBoardEvent|keyBoardEvent.keyCode} keyEvent
310310
*/
311-
CodeHintList.prototype.isHandlingKeyCode = function (keyCode) {
311+
CodeHintList.prototype.isHandlingKeyCode = function (keyCodeOrEvent) {
312+
var keyCode = typeof keyCodeOrEvent === "object" ? keyCodeOrEvent.keyCode : keyCodeOrEvent;
313+
var ctrlKey = typeof keyCodeOrEvent === "object" ? keyCodeOrEvent.ctrlKey : false;
314+
315+
312316
return (keyCode === KeyEvent.DOM_VK_UP || keyCode === KeyEvent.DOM_VK_DOWN ||
313317
keyCode === KeyEvent.DOM_VK_PAGE_UP || keyCode === KeyEvent.DOM_VK_PAGE_DOWN ||
314318
keyCode === KeyEvent.DOM_VK_RETURN ||
319+
keyCode === KeyEvent.DOM_VK_CONTROL ||
320+
keyCode === KeyEvent.DOM_VK_ESCAPE ||
321+
(ctrlKey && keyCode === KeyEvent.DOM_VK_SPACE) ||
315322
(keyCode === KeyEvent.DOM_VK_TAB && this.insertHintOnTab));
316323
};
317324

@@ -382,21 +389,23 @@ define(function (require, exports, module) {
382389
}
383390

384391
// (page) up, (page) down, enter and tab key are handled by the list
385-
if (event.type === "keydown" && this.isHandlingKeyCode(event.keyCode)) {
392+
if (event.type === "keydown" && this.isHandlingKeyCode(event)) {
386393
keyCode = event.keyCode;
387394

388-
if (event.shiftKey &&
395+
if (event.keyCode === KeyEvent.DOM_VK_ESCAPE ||
396+
(event.shiftKey &&
389397
(event.keyCode === KeyEvent.DOM_VK_UP ||
390398
event.keyCode === KeyEvent.DOM_VK_DOWN ||
391399
event.keyCode === KeyEvent.DOM_VK_PAGE_UP ||
392-
event.keyCode === KeyEvent.DOM_VK_PAGE_DOWN)) {
400+
event.keyCode === KeyEvent.DOM_VK_PAGE_DOWN))) {
393401
this.handleClose();
394402

395403
// Let the event bubble.
396404
return false;
397405
} else if (keyCode === KeyEvent.DOM_VK_UP) {
398406
_rotateSelection.call(this, -1);
399-
} else if (keyCode === KeyEvent.DOM_VK_DOWN) {
407+
} else if (keyCode === KeyEvent.DOM_VK_DOWN ||
408+
(event.ctrlKey && keyCode === KeyEvent.DOM_VK_SPACE)) {
400409
_rotateSelection.call(this, 1);
401410
} else if (keyCode === KeyEvent.DOM_VK_PAGE_UP) {
402411
_rotateSelection.call(this, -_itemsPerPage());
@@ -478,8 +487,6 @@ define(function (require, exports, module) {
478487
.css({"left": hintPos.left, "top": hintPos.top, "width": hintPos.width + "px"});
479488
this.opened = true;
480489

481-
PopUpManager.addPopUp(this.$hintMenu, this.handleClose, true);
482-
483490
KeyBindingManager.addGlobalKeydownHook(this._keydownHook);
484491
}
485492
};
@@ -501,7 +508,16 @@ define(function (require, exports, module) {
501508
"width": hintPos.width + "px"});
502509
}
503510
};
504-
511+
/**
512+
* Calls the move up keybind to move hint suggestion selector
513+
*
514+
* @param {KeyBoardEvent} keyEvent
515+
*/
516+
CodeHintList.prototype.callMoveUp = function (event) {
517+
delete event.type;
518+
event.type = "keydown";
519+
this._keydownHook(event);
520+
};
505521
/**
506522
* Closes the hint list
507523
*/

src/editor/CodeHintManager.js

Lines changed: 49 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,8 @@ define(function (require, exports, module) {
246246
hintList = null,
247247
deferredHints = null,
248248
keyDownEditor = null,
249-
codeHintsEnabled = true;
249+
codeHintsEnabled = true,
250+
codeHintOpened = false;
250251

251252

252253
PreferencesManager.definePreference("showCodeHints", "boolean", true, {
@@ -376,6 +377,7 @@ define(function (require, exports, module) {
376377
}
377378
hintList.close();
378379
hintList = null;
380+
codeHintOpened = false;
379381
keyDownEditor = null;
380382
sessionProvider = null;
381383
sessionEditor = null;
@@ -407,19 +409,25 @@ define(function (require, exports, module) {
407409
}
408410
return false;
409411
}
410-
411412
/**
412413
* From an active hinting session, get hints from the current provider and
413414
* render the hint list window.
414415
*
415416
* Assumes that it is called when a session is active (i.e. sessionProvider is not null).
416417
*/
417-
function _updateHintList() {
418+
function _updateHintList(callMoveUpEvent) {
419+
420+
callMoveUpEvent = typeof callMoveUpEvent === "undefined" ? false : callMoveUpEvent;
421+
418422
if (deferredHints) {
419423
deferredHints.reject();
420424
deferredHints = null;
421425
}
422426

427+
if (callMoveUpEvent) {
428+
return hintList.callMoveUp(callMoveUpEvent);
429+
}
430+
423431
var response = sessionProvider.getHints(lastChar);
424432
lastChar = null;
425433

@@ -430,6 +438,7 @@ define(function (require, exports, module) {
430438
// if the response is true, end the session and begin another
431439
if (response === true) {
432440
var previousEditor = sessionEditor;
441+
433442
_endSession();
434443
_beginSession(previousEditor);
435444
} else if (response.hasOwnProperty("hints")) { // a synchronous response
@@ -466,6 +475,7 @@ define(function (require, exports, module) {
466475
* @param {Editor} editor
467476
*/
468477
_beginSession = function (editor) {
478+
469479
if (!codeHintsEnabled) {
470480
return;
471481
}
@@ -497,7 +507,6 @@ define(function (require, exports, module) {
497507
}
498508

499509
sessionEditor = editor;
500-
501510
hintList = new CodeHintList(sessionEditor, insertHintOnTab, maxCodeHints);
502511
hintList.onSelect(function (hint) {
503512
var restart = sessionProvider.insertHint(hint),
@@ -515,26 +524,6 @@ define(function (require, exports, module) {
515524
}
516525
};
517526

518-
/**
519-
* Explicitly start a new session. If we have an existing session,
520-
* then close the current one and restart a new one.
521-
* @param {Editor} editor
522-
*/
523-
function _startNewSession(editor) {
524-
if (!editor) {
525-
editor = EditorManager.getFocusedEditor();
526-
}
527-
528-
if (editor) {
529-
lastChar = null;
530-
if (_inSession(editor)) {
531-
_endSession();
532-
}
533-
// Begin a new explicit session
534-
_beginSession(editor);
535-
}
536-
}
537-
538527
/**
539528
* Handles keys related to displaying, searching, and navigating the hint list.
540529
* This gets called before handleChange.
@@ -571,7 +560,8 @@ define(function (require, exports, module) {
571560
function _handleKeyupEvent(jqEvent, editor, event) {
572561
keyDownEditor = editor;
573562
if (_inSession(editor)) {
574-
if (event.keyCode === KeyEvent.DOM_VK_HOME || event.keyCode === KeyEvent.DOM_VK_END) {
563+
if (event.keyCode === KeyEvent.DOM_VK_HOME ||
564+
event.keyCode === KeyEvent.DOM_VK_END) {
575565
_endSession();
576566
} else if (event.keyCode === KeyEvent.DOM_VK_LEFT ||
577567
event.keyCode === KeyEvent.DOM_VK_RIGHT ||
@@ -580,6 +570,8 @@ define(function (require, exports, module) {
580570
// We do this in "keyup" because we want the cursor position to be updated before
581571
// we redraw the list.
582572
_updateHintList();
573+
} else if (event.ctrlKey && event.keyCode === KeyEvent.DOM_VK_SPACE) {
574+
_updateHintList(event);
583575
}
584576
}
585577
}
@@ -664,6 +656,30 @@ define(function (require, exports, module) {
664656
return (hintList && hintList.isOpen());
665657
}
666658

659+
/**
660+
* Explicitly start a new session. If we have an existing session,
661+
* then close the current one and restart a new one.
662+
* @param {Editor} editor
663+
*/
664+
function _startNewSession(editor) {
665+
if (isOpen()) {
666+
return;
667+
}
668+
669+
if (!editor) {
670+
editor = EditorManager.getFocusedEditor();
671+
}
672+
if (editor) {
673+
lastChar = null;
674+
if (_inSession(editor)) {
675+
_endSession();
676+
}
677+
678+
// Begin a new explicit session
679+
_beginSession(editor);
680+
}
681+
}
682+
667683
/**
668684
* Expose CodeHintList for unit testing
669685
*/
@@ -693,12 +709,16 @@ define(function (require, exports, module) {
693709
activeEditorChangeHandler(null, EditorManager.getActiveEditor(), null);
694710

695711
EditorManager.on("activeEditorChange", activeEditorChangeHandler);
696-
697-
// Dismiss code hints before executing any command since the command
712+
713+
// Dismiss code hints before executing any command other than showing code hints since the command
698714
// may make the current hinting session irrevalent after execution.
699715
// For example, when the user hits Ctrl+K to open Quick Doc, it is
700-
// pointless to keep the hint list since the user wants to view the Quick Doc.
701-
CommandManager.on("beforeExecuteCommand", _endSession);
716+
// pointless to keep the hint list since the user wants to view the Quick Doc
717+
CommandManager.on("beforeExecuteCommand", function (event, commandId) {
718+
if (commandId !== Commands.SHOW_CODE_HINTS) {
719+
_endSession();
720+
}
721+
});
702722

703723
CommandManager.register(Strings.CMD_SHOW_CODE_HINTS, Commands.SHOW_CODE_HINTS, _startNewSession);
704724

test/spec/CodeHint-test.js

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,88 @@ define(function (require, exports, module) {
278278
});
279279
});
280280

281+
it("should go to next hint with ctrl+space", function () {
282+
var editor,
283+
pos = {line: 3, ch: 1},
284+
hintBefore,
285+
hintAfter;
286+
287+
// minimal markup with an open '<' before IP
288+
// Note: line for pos is 0-based and editor lines numbers are 1-based
289+
initCodeHintTest("test1.html", pos);
290+
291+
// simulate ctrl+space key to make sure it goes to next hint
292+
runs(function () {
293+
var e = $.Event("keydown");
294+
e.keyCode = KeyEvent.DOM_VK_SPACE;
295+
e.ctrlKey = true;
296+
297+
editor = EditorManager.getCurrentFullEditor();
298+
expect(editor).toBeTruthy();
299+
300+
invokeCodeHints();
301+
var codeHintList = expectSomeHints();
302+
hintBefore = codeHintList.selectedIndex;
303+
304+
// make sure hint list starts at 0
305+
expect(hintBefore).toEqual(0);
306+
307+
// simulate ctrl+space keyhook
308+
CodeHintManager._getCodeHintList()._keydownHook(e);
309+
hintAfter = codeHintList.selectedIndex;
310+
311+
// selectedIndex should be one more after doing ctrl+space key event.
312+
expect(hintBefore).toEqual(hintAfter-1);
313+
314+
editor = null;
315+
});
316+
});
317+
318+
it("should loop to first hint when ctrl+space at last hint", function () {
319+
var editor,
320+
pos = {line: 3, ch: 1},
321+
hintBefore,
322+
hintAfter;
323+
324+
// minimal markup with an open '<' before IP
325+
// Note: line for pos is 0-based and editor lines numbers are 1-based
326+
initCodeHintTest("test1.html", pos);
327+
328+
// simulate ctrl+space key to make sure it goes to next hint
329+
runs(function () {
330+
var e = $.Event("keydown");
331+
e.keyCode = KeyEvent.DOM_VK_UP;
332+
333+
editor = EditorManager.getCurrentFullEditor();
334+
expect(editor).toBeTruthy();
335+
336+
invokeCodeHints();
337+
338+
// simulate up keyhook to send it to last hint
339+
CodeHintManager._getCodeHintList()._keydownHook(e);
340+
341+
var codeHintList = expectSomeHints();
342+
hintBefore = codeHintList.selectedIndex;
343+
var numberOfHints = codeHintList.$hintMenu.find("li").length-1;
344+
345+
// should be at last hint
346+
expect(hintBefore).toEqual(numberOfHints);
347+
348+
// call ctrl+space to loop it to first hint
349+
e.keyCode = KeyEvent.DOM_VK_SPACE;
350+
e.ctrlKey = true;
351+
352+
// simulate ctrl+space keyhook to send it to first hint
353+
CodeHintManager._getCodeHintList()._keydownHook(e);
354+
hintAfter = codeHintList.selectedIndex;
355+
356+
// should now be at hint 0
357+
expect(hintAfter).toEqual(0);
358+
359+
editor = null;
360+
});
361+
});
362+
281363
it("should not show code hints if there is a multiple selection", function () {
282364
// minimal markup with an open '<' before IP
283365
// Note: line for pos is 0-based and editor lines numbers are 1-based

0 commit comments

Comments
 (0)