diff --git a/docs/customize/deep-dives/autocomplete.mdx b/docs/customize/deep-dives/autocomplete.mdx
index 87a4ede2450..091b71283ab 100644
--- a/docs/customize/deep-dives/autocomplete.mdx
+++ b/docs/customize/deep-dives/autocomplete.mdx
@@ -195,6 +195,16 @@ In VS Code, if you don't want to be shown suggestions automatically you can:
4. Press the key combination you want to use to trigger suggestions (e.g. cmd/ctrl + space)
5. Now whenever you want to see a suggestion, you can press your key binding (e.g. cmd/ctrl + space) to trigger suggestions manually
+The setting is evaluated for the active document, so you can also configure it for specific languages with VS Code's language-scoped settings. For example:
+
+```json
+"[python]": {
+ "editor.inlineSuggest.enabled": false
+}
+```
+
+Continue honors the manual trigger while automatic inline suggestions are disabled.
+
### Shortcut for Accepting One Line at a Time in Autocomplete
This is a built-in feature of VS Code, but it's just a bit hidden. Follow these settings to reassign the keyboard shortcuts in VS Code:
diff --git a/extensions/vscode/src/autocomplete/__tests__/ContinueCompletionProvider.vitest.ts b/extensions/vscode/src/autocomplete/__tests__/ContinueCompletionProvider.vitest.ts
index 9d6e816c69c..48e2164da5c 100644
--- a/extensions/vscode/src/autocomplete/__tests__/ContinueCompletionProvider.vitest.ts
+++ b/extensions/vscode/src/autocomplete/__tests__/ContinueCompletionProvider.vitest.ts
@@ -46,9 +46,140 @@ beforeEach(() => {
);
(vscode.window as any).activeTextEditor = null;
+ setInlineSuggestEnabled(true);
});
describe("ContinueCompletionProvider triggering logic", () => {
+ it("does not request automatic completions when inline suggestions are disabled", async () => {
+ const document = createDocument();
+ setActiveEditor(document);
+ setInlineSuggestEnabled(false);
+
+ const provider = buildProvider();
+
+ const result = await provider.provideInlineCompletionItems(
+ document,
+ createPosition(),
+ createContext(),
+ createToken(),
+ );
+
+ expect(result).toBeNull();
+ expect(vscode.workspace.getConfiguration).toHaveBeenCalledWith(
+ "editor.inlineSuggest",
+ document,
+ );
+ expect(mockNextEditProvider.startChain).not.toHaveBeenCalled();
+ expect(
+ mockNextEditProvider.provideInlineCompletionItems,
+ ).not.toHaveBeenCalled();
+ });
+
+ it("keeps manual completions available when inline suggestions are disabled", async () => {
+ const document = createDocument();
+ setActiveEditor(document);
+ setInlineSuggestEnabled(false);
+
+ const provider = buildProvider();
+
+ const manualResult = await provider.provideInlineCompletionItems(
+ document,
+ createPosition(),
+ createContext(vscode.InlineCompletionTriggerKind.Invoke),
+ createToken(),
+ );
+
+ const automaticResult = await provider.provideInlineCompletionItems(
+ document,
+ createPosition(),
+ createContext(),
+ createToken(),
+ );
+
+ expect(manualResult).not.toBeNull();
+ expect(automaticResult).toBeNull();
+ expect(mockNextEditProvider.startChain).toHaveBeenCalledTimes(1);
+ expect(
+ mockNextEditProvider.provideInlineCompletionItems,
+ ).toHaveBeenCalledTimes(1);
+ });
+
+ it("uses a language override when it disables inline suggestions", async () => {
+ const document = createDocument(undefined, "python");
+ setActiveEditor(document);
+ setInlineSuggestConfiguration(true, { python: false });
+
+ const provider = buildProvider();
+ const result = await provider.provideInlineCompletionItems(
+ document,
+ createPosition(),
+ createContext(),
+ createToken(),
+ );
+
+ expect(result).toBeNull();
+ expect(vscode.workspace.getConfiguration).toHaveBeenCalledWith(
+ "editor.inlineSuggest",
+ document,
+ );
+ expect(mockNextEditProvider.startChain).not.toHaveBeenCalled();
+ });
+
+ it("uses a language override when it enables inline suggestions", async () => {
+ const document = createDocument(undefined, "python");
+ setActiveEditor(document);
+ setInlineSuggestConfiguration(false, { python: true });
+
+ const provider = buildProvider();
+ const result = await provider.provideInlineCompletionItems(
+ document,
+ createPosition(),
+ createContext(),
+ createToken(),
+ );
+
+ expect(result).not.toBeNull();
+ expect(vscode.workspace.getConfiguration).toHaveBeenCalledWith(
+ "editor.inlineSuggest",
+ document,
+ );
+ expect(mockNextEditProvider.startChain).toHaveBeenCalledTimes(1);
+ });
+
+ it("passes trigger kind to regular autocomplete and allows enabled automatic requests", async () => {
+ const document = createDocument();
+ setActiveEditor(document);
+ setInlineSuggestEnabled(true);
+
+ const provider = buildProvider({ activateNextEdit: false });
+ const completionProvider = (provider as any).completionProvider;
+ completionProvider.provideInlineCompletionItems.mockResolvedValue(
+ mockOutcome,
+ );
+
+ const manualResult = await provider.provideInlineCompletionItems(
+ document,
+ createPosition(),
+ createContext(vscode.InlineCompletionTriggerKind.Invoke),
+ createToken(),
+ );
+ const automaticResult = await provider.provideInlineCompletionItems(
+ document,
+ createPosition(),
+ createContext(),
+ createToken(),
+ );
+
+ expect(manualResult).not.toBeNull();
+ expect(automaticResult).not.toBeNull();
+ expect(
+ completionProvider.provideInlineCompletionItems,
+ ).toHaveBeenNthCalledWith(1, expect.anything(), expect.anything(), true);
+ expect(
+ completionProvider.provideInlineCompletionItems,
+ ).toHaveBeenNthCalledWith(2, expect.anything(), expect.anything(), false);
+ });
+
it("starts a new chain when none exists", async () => {
const document = createDocument();
setActiveEditor(document);
@@ -158,7 +289,9 @@ describe("ContinueCompletionProvider triggering logic", () => {
});
});
-function buildProvider(options: { usingFullFileDiff?: boolean } = {}) {
+function buildProvider(
+ options: { usingFullFileDiff?: boolean; activateNextEdit?: boolean } = {},
+) {
const usingFullFileDiff = options.usingFullFileDiff ?? true;
const configHandler = {
loadConfig: vi.fn(async () => ({
@@ -175,16 +308,20 @@ function buildProvider(options: { usingFullFileDiff?: boolean } = {}) {
webviewProtocol,
usingFullFileDiff,
);
- provider.activateNextEdit();
+ if (options.activateNextEdit ?? true) {
+ provider.activateNextEdit();
+ }
return provider;
}
function createDocument(
text = "function example() {\n return true;\n}",
+ languageId = "typescript",
): vscode.TextDocument {
const lines = text.split("\n");
return {
uri: vscode.Uri.parse("file:///test"),
+ languageId,
isUntitled: false,
getText: (range?: any) => {
if (!range) {
@@ -220,9 +357,11 @@ function createDocument(
} as unknown as vscode.TextDocument;
}
-function createContext(): any {
+function createContext(
+ triggerKind = vscode.InlineCompletionTriggerKind.Automatic,
+): any {
return {
- triggerKind: (vscode.InlineCompletionTriggerKind as any).Automatic,
+ triggerKind,
selectedCompletionInfo: undefined,
};
}
@@ -238,6 +377,21 @@ function createToken(): any {
};
}
+function setInlineSuggestEnabled(enabled: boolean) {
+ setInlineSuggestConfiguration(enabled);
+}
+
+function setInlineSuggestConfiguration(
+ globalEnabled: boolean,
+ languageOverrides: Record = {},
+) {
+ (vscode.workspace.getConfiguration as any).mockImplementation(
+ (_section: string, scope: any) => ({
+ get: vi.fn(() => languageOverrides[scope?.languageId] ?? globalEnabled),
+ }),
+ );
+}
+
function setActiveEditor(document: any, cursor = createPosition()) {
const selection = { active: cursor, anchor: cursor };
(vscode.window as any).activeTextEditor = {
diff --git a/extensions/vscode/src/autocomplete/completionProvider.ts b/extensions/vscode/src/autocomplete/completionProvider.ts
index 498f971d05d..06badabe843 100644
--- a/extensions/vscode/src/autocomplete/completionProvider.ts
+++ b/extensions/vscode/src/autocomplete/completionProvider.ts
@@ -171,6 +171,20 @@ export class ContinueCompletionProvider
return null;
}
+ // VS Code still asks providers for automatic completions after an explicit
+ // invocation, even when inline suggestions are disabled. Only honor those
+ // explicit invocations in that mode. Passing the document as the scope
+ // ensures that language-scoped editor settings are respected.
+ const inlineSuggestEnabled = vscode.workspace
+ .getConfiguration("editor.inlineSuggest", document)
+ .get("enabled", true);
+ if (
+ inlineSuggestEnabled === false &&
+ context.triggerKind === vscode.InlineCompletionTriggerKind.Automatic
+ ) {
+ return null;
+ }
+
if (document.uri.scheme === "vscode-scm") {
return null;
}