Skip to content

Commit f8fe0c2

Browse files
authored
Merge pull request microsoft#165927 from microsoft/joh/evil-shark
joh/evil shark
2 parents 2cd8ea2 + 04536a1 commit f8fe0c2

File tree

6 files changed

+83
-66
lines changed

6 files changed

+83
-66
lines changed

src/vs/editor/common/config/editorOptions.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3921,6 +3921,10 @@ export interface ISuggestOptions {
39213921
* Enable using global storage for remembering suggestions.
39223922
*/
39233923
shareSuggestSelections?: boolean;
3924+
/**
3925+
* Select suggestions when triggered via quick suggest or trigger characters
3926+
*/
3927+
selectQuickSuggestions?: boolean;
39243928
/**
39253929
* Enable or disable icons in suggestions. Defaults to true.
39263930
*/
@@ -4073,6 +4077,7 @@ class EditorSuggest extends BaseEditorOption<EditorOption.suggest, ISuggestOptio
40734077
snippetsPreventQuickSuggestions: true,
40744078
localityBonus: false,
40754079
shareSuggestSelections: false,
4080+
selectQuickSuggestions: true,
40764081
showIcons: true,
40774082
showStatusBar: false,
40784083
preview: false,
@@ -4334,6 +4339,7 @@ class EditorSuggest extends BaseEditorOption<EditorOption.suggest, ISuggestOptio
43344339
snippetsPreventQuickSuggestions: boolean(input.snippetsPreventQuickSuggestions, this.defaultValue.filterGraceful),
43354340
localityBonus: boolean(input.localityBonus, this.defaultValue.localityBonus),
43364341
shareSuggestSelections: boolean(input.shareSuggestSelections, this.defaultValue.shareSuggestSelections),
4342+
selectQuickSuggestions: boolean(input.selectQuickSuggestions, this.defaultValue.selectQuickSuggestions),
43374343
showIcons: boolean(input.showIcons, this.defaultValue.showIcons),
43384344
showStatusBar: boolean(input.showStatusBar, this.defaultValue.showStatusBar),
43394345
preview: boolean(input.preview, this.defaultValue.preview),

src/vs/editor/contrib/suggest/browser/suggestController.ts

Lines changed: 39 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,12 @@ export class SuggestController implements IEditorContribution {
130130
this.editor = editor;
131131
this.model = _instantiationService.createInstance(SuggestModel, this.editor,);
132132

133+
// default selector
134+
this._selectors.register({
135+
priority: 0,
136+
select: (model, pos, items) => this._memoryService.select(model, pos, items)
137+
});
138+
133139
// context key: update insert/replace mode
134140
const ctxInsertMode = SuggestContext.InsertMode.bindTo(_contextKeyService);
135141
ctxInsertMode.set(editor.getOption(EditorOption.suggest).insertMode);
@@ -227,18 +233,16 @@ export class SuggestController implements IEditorContribution {
227233
return;
228234
}
229235
let index = -1;
230-
if (!e.noSelect) {
231-
for (const selector of this._selectors.itemsOrderedByPriorityDesc) {
232-
index = selector.select(this.editor.getModel()!, this.editor.getPosition()!, e.completionModel.items);
233-
if (index !== -1) {
234-
break;
235-
}
236-
}
237-
if (index === -1) {
238-
index = this._memoryService.select(this.editor.getModel()!, this.editor.getPosition()!, e.completionModel.items);
236+
for (const selector of this._selectors.itemsOrderedByPriorityDesc) {
237+
index = selector.select(this.editor.getModel()!, this.editor.getPosition()!, e.completionModel.items);
238+
if (index !== -1) {
239+
break;
239240
}
240241
}
241-
this.widget.value.showSuggestions(e.completionModel, index, e.isFrozen, e.auto);
242+
if (index === -1) {
243+
index = 0;
244+
}
245+
this.widget.value.showSuggestions(e.completionModel, index, e.isFrozen, e.auto, e.auto && !this.editor.getOption(EditorOption.suggest).selectQuickSuggestions);
242246
}));
243247
this._toDispose.add(this.model.onDidCancel(e => {
244248
if (!e.retrigger) {
@@ -400,7 +404,7 @@ export class SuggestController implements IEditorContribution {
400404
if (item.completion.command) {
401405
if (item.completion.command.id === TriggerSuggestAction.id) {
402406
// retigger
403-
this.model.trigger({ auto: true, shy: false, noSelect: false }, true);
407+
this.model.trigger({ auto: true, shy: false }, true);
404408
} else {
405409
// exec command, done
406410
tasks.push(this._commandService.executeCommand(item.completion.command.id, ...(item.completion.command.arguments ? [...item.completion.command.arguments] : [])).catch(onUnexpectedError));
@@ -493,9 +497,9 @@ export class SuggestController implements IEditorContribution {
493497
}
494498
}
495499

496-
triggerSuggest(onlyFrom?: Set<CompletionItemProvider>, auto?: boolean, noFilter?: boolean, noSelect?: boolean): void {
500+
triggerSuggest(onlyFrom?: Set<CompletionItemProvider>, auto?: boolean, noFilter?: boolean): void {
497501
if (this.editor.hasModel()) {
498-
this.model.trigger({ auto: auto ?? false, shy: false, noSelect: noSelect ?? false }, false, onlyFrom, undefined, noFilter);
502+
this.model.trigger({ auto: auto ?? false, shy: false }, false, onlyFrom, undefined, noFilter);
499503
this.editor.revealPosition(this.editor.getPosition(), ScrollType.Smooth);
500504
this.editor.focus();
501505
}
@@ -564,7 +568,7 @@ export class SuggestController implements IEditorContribution {
564568
}, undefined, listener);
565569
});
566570

567-
this.model.trigger({ auto: false, shy: true, noSelect: false });
571+
this.model.trigger({ auto: false, shy: true });
568572
this.editor.revealPosition(positionNow, ScrollType.Smooth);
569573
this.editor.focus();
570574
}
@@ -580,6 +584,7 @@ export class SuggestController implements IEditorContribution {
580584
}
581585
this._insertSuggestion(item, flags);
582586
}
587+
583588
acceptNextSuggestion() {
584589
this._alternatives.value.next();
585590
}
@@ -594,6 +599,10 @@ export class SuggestController implements IEditorContribution {
594599
this.widget.value.hideWidget();
595600
}
596601

602+
focusSuggestion(): void {
603+
this.widget.value.focusSelected();
604+
}
605+
597606
selectNextSuggestion(): void {
598607
this.widget.value.selectNext();
599608
}
@@ -705,19 +714,15 @@ export class TriggerSuggestAction extends EditorAction {
705714
return;
706715
}
707716

708-
type TriggerArgs = { auto: boolean; noSelection: boolean };
717+
type TriggerArgs = { auto: boolean };
709718
let auto: boolean | undefined;
710-
let noSelect: boolean | undefined;
711719
if (args && typeof args === 'object') {
712720
if ((<TriggerArgs>args).auto === true) {
713721
auto = true;
714722
}
715-
if ((<TriggerArgs>args).noSelection === true) {
716-
noSelect = true;
717-
}
718723
}
719724

720-
controller.triggerSuggest(undefined, auto, undefined, noSelect);
725+
controller.triggerSuggest(undefined, auto, undefined);
721726
}
722727
}
723728

@@ -872,9 +877,22 @@ registerEditorCommand(new SuggestCommand({
872877
handler: c => c.selectFirstSuggestion()
873878
}));
874879

880+
registerEditorCommand(new SuggestCommand({
881+
id: 'focusSuggestion',
882+
precondition: ContextKeyExpr.and(SuggestContext.Visible, SuggestContext.HasFocusedSuggestion.negate(), ContextKeyExpr.equals('config.editor.suggest.selectQuickSuggestions', false)),
883+
handler: x => x.focusSuggestion(),
884+
kbOpts: {
885+
weight: weight,
886+
kbExpr: EditorContextKeys.textInputFocus,
887+
primary: KeyMod.CtrlCmd | KeyCode.Space,
888+
secondary: [KeyMod.CtrlCmd | KeyCode.KeyI],
889+
mac: { primary: KeyMod.WinCtrl | KeyCode.Space, secondary: [KeyMod.CtrlCmd | KeyCode.KeyI] }
890+
},
891+
}));
892+
875893
registerEditorCommand(new SuggestCommand({
876894
id: 'toggleSuggestionDetails',
877-
precondition: SuggestContext.Visible,
895+
precondition: ContextKeyExpr.and(SuggestContext.Visible, SuggestContext.HasFocusedSuggestion),
878896
handler: x => x.toggleSuggestionDetails(),
879897
kbOpts: {
880898
weight: weight,

src/vs/editor/contrib/suggest/browser/suggestModel.ts

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,11 @@ export interface ISuggestEvent {
4646
readonly isFrozen: boolean;
4747
readonly auto: boolean;
4848
readonly shy: boolean;
49-
readonly noSelect: boolean;
5049
}
5150

5251
export interface SuggestTriggerContext {
5352
readonly auto: boolean;
5453
readonly shy: boolean;
55-
readonly noSelect: boolean;
5654
readonly triggerKind?: CompletionTriggerKind;
5755
readonly triggerCharacter?: string;
5856
}
@@ -86,16 +84,14 @@ export class LineContext {
8684
readonly leadingWord: IWordAtPosition;
8785
readonly auto: boolean;
8886
readonly shy: boolean;
89-
readonly noSelect: boolean;
9087

91-
constructor(model: ITextModel, position: Position, auto: boolean, shy: boolean, noSelect: boolean) {
88+
constructor(model: ITextModel, position: Position, auto: boolean, shy: boolean) {
9289
this.leadingLineContent = model.getLineContent(position.lineNumber).substr(0, position.column - 1);
9390
this.leadingWord = model.getWordUntilPosition(position);
9491
this.lineNumber = position.lineNumber;
9592
this.column = position.column;
9693
this.auto = auto;
9794
this.shy = shy;
98-
this.noSelect = noSelect;
9995
}
10096
}
10197

@@ -285,7 +281,7 @@ export class SuggestModel implements IDisposable {
285281
const existing = this._completionModel
286282
? { items: this._completionModel.adopt(supports), clipboardText: this._completionModel.clipboardText }
287283
: undefined;
288-
this.trigger({ auto: true, shy: false, noSelect: false, triggerCharacter: lastChar }, Boolean(this._completionModel), supports, existing);
284+
this.trigger({ auto: true, shy: false, triggerCharacter: lastChar }, Boolean(this._completionModel), supports, existing);
289285
}
290286
};
291287

@@ -320,7 +316,7 @@ export class SuggestModel implements IDisposable {
320316
if (!this._editor.hasModel() || !this._languageFeaturesService.completionProvider.has(this._editor.getModel())) {
321317
this.cancel();
322318
} else {
323-
this.trigger({ auto: this._state === State.Auto, shy: false, noSelect: false }, true);
319+
this.trigger({ auto: this._state === State.Auto, shy: false }, true);
324320
}
325321
}
326322
}
@@ -419,7 +415,7 @@ export class SuggestModel implements IDisposable {
419415
}
420416

421417
// we made it till here -> trigger now
422-
this.trigger({ auto: true, shy: false, noSelect: false });
418+
this.trigger({ auto: true, shy: false });
423419

424420
}, this._editor.getOption(EditorOption.quickSuggestionsDelay));
425421
}
@@ -429,7 +425,7 @@ export class SuggestModel implements IDisposable {
429425

430426
const model = this._editor.getModel();
431427
const position = this._editor.getPosition();
432-
const ctx = new LineContext(model, position, this._state === State.Auto, false, false);
428+
const ctx = new LineContext(model, position, this._state === State.Auto, false);
433429
this._onNewContext(ctx);
434430
}
435431

@@ -440,7 +436,7 @@ export class SuggestModel implements IDisposable {
440436

441437
const model = this._editor.getModel();
442438
const auto = context.auto;
443-
const ctx = new LineContext(model, this._editor.getPosition(), auto, context.shy, context.noSelect);
439+
const ctx = new LineContext(model, this._editor.getPosition(), auto, context.shy);
444440

445441
// Cancel previous requests, change state & update UI
446442
this.cancel(retrigger);
@@ -515,7 +511,7 @@ export class SuggestModel implements IDisposable {
515511
items = items.concat(existing.items).sort(cmpFn);
516512
}
517513

518-
const ctx = new LineContext(model, this._editor.getPosition(), auto, context.shy, context.noSelect);
514+
const ctx = new LineContext(model, this._editor.getPosition(), auto, context.shy);
519515
const fuzzySearchOptions = {
520516
...FuzzyScoreOptions.default,
521517
firstMatchCanBeWeak: !this._editor.getOption(EditorOption.suggest).matchOnWordStartOnly
@@ -629,7 +625,7 @@ export class SuggestModel implements IDisposable {
629625
if (ctx.column < this._context.column) {
630626
// typed -> moved cursor LEFT -> retrigger if still on a word
631627
if (ctx.leadingWord.word) {
632-
this.trigger({ auto: this._context.auto, shy: false, noSelect: false }, true);
628+
this.trigger({ auto: this._context.auto, shy: false }, true);
633629
} else {
634630
this.cancel();
635631
}
@@ -651,15 +647,15 @@ export class SuggestModel implements IDisposable {
651647
inactiveProvider.delete(provider);
652648
}
653649
const items = this._completionModel.adopt(new Set());
654-
this.trigger({ auto: this._context.auto, shy: false, noSelect: false }, true, inactiveProvider, { items, clipboardText: this._completionModel.clipboardText });
650+
this.trigger({ auto: this._context.auto, shy: false }, true, inactiveProvider, { items, clipboardText: this._completionModel.clipboardText });
655651
return;
656652
}
657653

658654
if (ctx.column > this._context.column && this._completionModel.incomplete.size > 0 && ctx.leadingWord.word.length !== 0) {
659655
// typed -> moved cursor RIGHT & incomple model & still on a word -> retrigger
660656
const { incomplete } = this._completionModel;
661657
const items = this._completionModel.adopt(incomplete);
662-
this.trigger({ auto: this._state === State.Auto, shy: false, noSelect: false, triggerKind: CompletionTriggerKind.TriggerForIncompleteCompletions }, true, incomplete, { items, clipboardText: this._completionModel.clipboardText });
658+
this.trigger({ auto: this._state === State.Auto, shy: false, triggerKind: CompletionTriggerKind.TriggerForIncompleteCompletions }, true, incomplete, { items, clipboardText: this._completionModel.clipboardText });
663659

664660
} else {
665661
// typed -> moved cursor RIGHT -> update UI
@@ -675,7 +671,7 @@ export class SuggestModel implements IDisposable {
675671

676672
if (LineContext.shouldAutoTrigger(this._editor) && this._context.leadingWord.endColumn < ctx.leadingWord.startColumn) {
677673
// retrigger when heading into a new word
678-
this.trigger({ auto: this._context.auto, shy: false, noSelect: false }, true);
674+
this.trigger({ auto: this._context.auto, shy: false }, true);
679675
return;
680676
}
681677

@@ -702,7 +698,6 @@ export class SuggestModel implements IDisposable {
702698
completionModel: this._completionModel,
703699
auto: this._context.auto,
704700
shy: this._context.shy,
705-
noSelect: this._context.noSelect,
706701
isFrozen,
707702
});
708703
}

src/vs/editor/contrib/suggest/browser/suggestWidget.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -516,7 +516,7 @@ export class SuggestWidget implements IDisposable {
516516
}
517517
}
518518

519-
showSuggestions(completionModel: CompletionModel, selectionIndex: number, isFrozen: boolean, isAuto: boolean): void {
519+
showSuggestions(completionModel: CompletionModel, selectionIndex: number, isFrozen: boolean, isAuto: boolean, noFocus: boolean): void {
520520

521521
this._contentWidget.setPosition(this.editor.getPosition());
522522
this._loadingTimeout?.dispose();
@@ -554,8 +554,8 @@ export class SuggestWidget implements IDisposable {
554554
try {
555555
this._list.splice(0, this._list.length, this._completionModel.items);
556556
this._setState(isFrozen ? State.Frozen : State.Open);
557-
if (selectionIndex >= 0) {
558-
this._list.reveal(selectionIndex, 0);
557+
this._list.reveal(selectionIndex, 0);
558+
if (!noFocus) {
559559
this._list.setFocus([selectionIndex]);
560560
}
561561
} finally {
@@ -571,6 +571,15 @@ export class SuggestWidget implements IDisposable {
571571
});
572572
}
573573

574+
focusSelected(): void {
575+
const selection = this._list.getSelection();
576+
if (selection.length !== 1) {
577+
this._list.setFocus([0]);
578+
} else {
579+
this._list.setFocus([selection[0]]);
580+
}
581+
}
582+
574583
selectNextPage(): boolean {
575584
switch (this._state) {
576585
case State.Hidden:

0 commit comments

Comments
 (0)