Skip to content

Commit 3a626d8

Browse files
committed
shift+tab/shift+enter overwrite suffix when accepting a completion, microsoft#10266
1 parent 13dc6f1 commit 3a626d8

4 files changed

Lines changed: 50 additions & 20 deletions

File tree

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

Lines changed: 44 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import * as nls from 'vs/nls';
2222
import { ICommandService } from 'vs/platform/commands/common/commands';
2323
import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
2424
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
25-
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
25+
import { KeybindingWeight, KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry';
2626
import { Context as SuggestContext, CompletionItem } from './suggest';
2727
import { SuggestAlternatives } from './suggestAlternatives';
2828
import { State, SuggestModel } from './suggestModel';
@@ -34,7 +34,7 @@ import { IdleValue } from 'vs/base/common/async';
3434
import { isObject } from 'vs/base/common/types';
3535
import { CommitCharacterController } from './suggestCommitCharacters';
3636
import { IPosition } from 'vs/editor/common/core/position';
37-
import { TrackedRangeStickiness, ITextModel } from 'vs/editor/common/model';
37+
import { TrackedRangeStickiness, ITextModel, IWordAtPosition } from 'vs/editor/common/model';
3838
import { EditorOption } from 'vs/editor/common/config/editorOptions';
3939
import * as platform from 'vs/base/common/platform';
4040

@@ -115,10 +115,10 @@ export class SuggestController implements IEditorContribution {
115115
const widget = this._instantiationService.createInstance(SuggestWidget, this._editor);
116116

117117
this._toDispose.add(widget);
118-
this._toDispose.add(widget.onDidSelect(item => this._insertSuggestion(item, false, true, true), this));
118+
this._toDispose.add(widget.onDidSelect(item => this._insertSuggestion(item, false, true, true, false), this));
119119

120120
// Wire up logic to accept a suggestion on certain characters
121-
const commitCharacterController = new CommitCharacterController(this._editor, widget, item => this._insertSuggestion(item, false, true, false));
121+
const commitCharacterController = new CommitCharacterController(this._editor, widget, item => this._insertSuggestion(item, false, true, false, false));
122122
this._toDispose.add(commitCharacterController);
123123
this._toDispose.add(this._model.onDidSuggest(e => {
124124
if (e.completionModel.items.length === 0) {
@@ -223,7 +223,12 @@ export class SuggestController implements IEditorContribution {
223223
this._lineSuffix.dispose();
224224
}
225225

226-
protected _insertSuggestion(event: ISelectedSuggestion | undefined, keepAlternativeSuggestions: boolean, undoStopBefore: boolean, undoStopAfter: boolean): void {
226+
protected _insertSuggestion(
227+
event: ISelectedSuggestion | undefined,
228+
keepAlternativeSuggestions: boolean,
229+
undoStopBefore: boolean, undoStopAfter: boolean,
230+
overwriteSuffix: boolean
231+
): void {
227232
if (!event || !event.item) {
228233
this._alternatives.getValue().reset();
229234
this._model.cancel();
@@ -237,8 +242,8 @@ export class SuggestController implements IEditorContribution {
237242
const model = this._editor.getModel();
238243
const modelVersionNow = model.getAlternativeVersionId();
239244
const { completion: suggestion, position } = event.item;
240-
const editorColumn = this._editor.getPosition().column;
241-
const columnDelta = editorColumn - position.column;
245+
const editorPosition = this._editor.getPosition();
246+
const columnDelta = editorPosition.column - position.column;
242247

243248
// pushing undo stops *before* additional text edits and
244249
// *after* the main edit
@@ -251,7 +256,7 @@ export class SuggestController implements IEditorContribution {
251256
}
252257

253258
// keep item in memory
254-
this._memoryService.memorize(model, this._editor.getPosition(), event.item);
259+
this._memoryService.memorize(model, editorPosition, event.item);
255260

256261
let { insertText } = suggestion;
257262
if (!(suggestion.insertTextRules! & CompletionItemInsertTextRule.InsertAsSnippet)) {
@@ -260,7 +265,12 @@ export class SuggestController implements IEditorContribution {
260265

261266
const overwriteBefore = position.column - suggestion.range.startColumn;
262267
const overwriteAfter = suggestion.range.endColumn - position.column;
263-
const suffixDelta = this._lineSuffix.value ? this._lineSuffix.value.delta(this._editor.getPosition()) : 0;
268+
269+
let suffixDelta = this._lineSuffix.value ? this._lineSuffix.value.delta(position) : 0;
270+
let word: IWordAtPosition | null;
271+
if (overwriteAfter === 0 && overwriteSuffix && (word = model.getWordAtPosition(position))) {
272+
suffixDelta += word.endColumn - position.column;
273+
}
264274

265275
SnippetController2.get(this._editor).insert(insertText, {
266276
overwriteBefore: overwriteBefore + columnDelta,
@@ -300,7 +310,7 @@ export class SuggestController implements IEditorContribution {
300310
if (modelVersionNow !== model.getAlternativeVersionId()) {
301311
model.undo();
302312
}
303-
this._insertSuggestion(next, false, false, false);
313+
this._insertSuggestion(next, false, false, false, overwriteSuffix);
304314
break;
305315
}
306316
});
@@ -382,7 +392,7 @@ export class SuggestController implements IEditorContribution {
382392
return;
383393
}
384394
this._editor.pushUndoStop();
385-
this._insertSuggestion({ index, item, model: completionModel }, true, false, false);
395+
this._insertSuggestion({ index, item, model: completionModel }, true, false, false, false);
386396

387397
}, undefined, listener);
388398
});
@@ -392,9 +402,9 @@ export class SuggestController implements IEditorContribution {
392402
this._editor.focus();
393403
}
394404

395-
acceptSelectedSuggestion(keepAlternativeSuggestions?: boolean): void {
405+
acceptSelectedSuggestion(keepAlternativeSuggestions: boolean, overwriteSuffix: boolean): void {
396406
const item = this._widget.getValue().getFocusedItem();
397-
this._insertSuggestion(item, !!keepAlternativeSuggestions, true, true);
407+
this._insertSuggestion(item, keepAlternativeSuggestions, true, true, overwriteSuffix);
398408
}
399409

400410
acceptNextSuggestion() {
@@ -489,18 +499,37 @@ const SuggestCommand = EditorCommand.bindToContribution<SuggestController>(Sugge
489499
registerEditorCommand(new SuggestCommand({
490500
id: 'acceptSelectedSuggestion',
491501
precondition: SuggestContext.Visible,
492-
handler: x => x.acceptSelectedSuggestion(true),
493502
kbOpts: {
494503
weight: weight,
495504
kbExpr: EditorContextKeys.textInputFocus,
496505
primary: KeyCode.Tab
506+
},
507+
handler(x, args) {
508+
let overwriteSuffix: boolean;
509+
if (typeof args !== 'object') {
510+
overwriteSuffix = false;
511+
} else if (typeof args.overwriteSuffix !== 'boolean') {
512+
overwriteSuffix = false;
513+
} else {
514+
overwriteSuffix = args.overwriteSuffix;
515+
}
516+
x.acceptSelectedSuggestion(true, overwriteSuffix);
497517
}
498518
}));
499519

520+
KeybindingsRegistry.registerKeybindingRule({
521+
id: 'acceptSelectedSuggestion',
522+
when: ContextKeyExpr.and(SuggestContext.Visible, EditorContextKeys.textInputFocus),
523+
primary: KeyMod.Shift | KeyCode.Tab,
524+
secondary: [KeyMod.Shift | KeyCode.Enter],
525+
args: { overwriteSuffix: true },
526+
weight
527+
});
528+
500529
registerEditorCommand(new SuggestCommand({
501530
id: 'acceptSelectedSuggestionOnEnter',
502531
precondition: SuggestContext.Visible,
503-
handler: x => x.acceptSelectedSuggestion(false),
532+
handler: x => x.acceptSelectedSuggestion(false, false),
504533
kbOpts: {
505534
weight: weight,
506535
kbExpr: ContextKeyExpr.and(EditorContextKeys.textInputFocus, SuggestContext.AcceptSuggestionsOnEnter, SuggestContext.MakesTextEdit),

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -676,7 +676,7 @@ suite('SuggestModel - TriggerAndCancelOracle', function () {
676676
return withOracle(async (sugget, editor) => {
677677
class TestCtrl extends SuggestController {
678678
_insertSuggestion(item: ISelectedSuggestion) {
679-
super._insertSuggestion(item, false, true, true);
679+
super._insertSuggestion(item, false, true, true, false);
680680
}
681681
}
682682
const ctrl = <TestCtrl>editor.registerAndInstantiateContribution(TestCtrl);

src/vs/platform/keybinding/common/keybindingsRegistry.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ export interface IKeybindings {
3838
export interface IKeybindingRule extends IKeybindings {
3939
id: string;
4040
weight: number;
41+
args?: any;
4142
when: ContextKeyExpr | null | undefined;
4243
}
4344

@@ -132,7 +133,7 @@ class KeybindingsRegistryImpl implements IKeybindingsRegistry {
132133
if (actualKb && actualKb.primary) {
133134
const kk = createKeybinding(actualKb.primary, OS);
134135
if (kk) {
135-
this._registerDefaultKeybinding(kk, rule.id, undefined, rule.weight, 0, rule.when);
136+
this._registerDefaultKeybinding(kk, rule.id, rule.args, rule.weight, 0, rule.when);
136137
}
137138
}
138139

@@ -141,7 +142,7 @@ class KeybindingsRegistryImpl implements IKeybindingsRegistry {
141142
const k = actualKb.secondary[i];
142143
const kk = createKeybinding(k, OS);
143144
if (kk) {
144-
this._registerDefaultKeybinding(kk, rule.id, undefined, rule.weight, -i - 1, rule.when);
145+
this._registerDefaultKeybinding(kk, rule.id, rule.args, rule.weight, -i - 1, rule.when);
145146
}
146147
}
147148
}

src/vs/workbench/contrib/debug/browser/repl.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -919,7 +919,7 @@ class AcceptReplInputAction extends EditorAction {
919919
}
920920

921921
run(accessor: ServicesAccessor, editor: ICodeEditor): void | Promise<void> {
922-
SuggestController.get(editor).acceptSelectedSuggestion();
922+
SuggestController.get(editor).acceptSelectedSuggestion(false, false);
923923
accessor.get(IPrivateReplService).acceptReplInput();
924924
}
925925
}
@@ -941,7 +941,7 @@ class FilterReplAction extends EditorAction {
941941
}
942942

943943
run(accessor: ServicesAccessor, editor: ICodeEditor): void | Promise<void> {
944-
SuggestController.get(editor).acceptSelectedSuggestion();
944+
SuggestController.get(editor).acceptSelectedSuggestion(false, false);
945945
accessor.get(IPrivateReplService).focusRepl();
946946
}
947947
}

0 commit comments

Comments
 (0)