From 6adbf48e5abd94141395c77841b3143298a193e8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 10 Nov 2025 21:07:47 +0000 Subject: [PATCH 1/4] Initial plan From cd132df31eed21b7f6a58bfafb79aa0c4ab44c79 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 10 Nov 2025 21:15:01 +0000 Subject: [PATCH 2/4] Fix auto-indent to respect language-specific tabSize configuration Co-authored-by: dibarbet <5749229+dibarbet@users.noreply.github.com> --- src/lsptoolshost/autoInsert/onAutoInsert.ts | 6 +- .../onAutoInsert.integration.test.ts | 65 +++++++++++++++++++ 2 files changed, 68 insertions(+), 3 deletions(-) diff --git a/src/lsptoolshost/autoInsert/onAutoInsert.ts b/src/lsptoolshost/autoInsert/onAutoInsert.ts index f9e8adafab..a761cb96fe 100644 --- a/src/lsptoolshost/autoInsert/onAutoInsert.ts +++ b/src/lsptoolshost/autoInsert/onAutoInsert.ts @@ -104,7 +104,7 @@ async function applyAutoInsertEdit( languageServer: RoslynLanguageServer, token: vscode.CancellationToken ) { - const formattingOptions = getFormattingOptions(); + const formattingOptions = getFormattingOptions(uri); const request: RoslynProtocol.OnAutoInsertParams = { _vs_textDocument: textDocumentIdentifier, _vs_position: position, @@ -142,8 +142,8 @@ async function applyAutoInsertEdit( } } -function getFormattingOptions(): FormattingOptions { - const editorConfig = vscode.workspace.getConfiguration('editor'); +function getFormattingOptions(resource: vscode.Uri): FormattingOptions { + const editorConfig = vscode.workspace.getConfiguration('editor', resource); const tabSize = editorConfig.get('tabSize') ?? 4; const insertSpaces = editorConfig.get('insertSpaces') ?? true; return FormattingOptions.create(tabSize, insertSpaces); diff --git a/test/lsptoolshost/integrationTests/onAutoInsert.integration.test.ts b/test/lsptoolshost/integrationTests/onAutoInsert.integration.test.ts index 7d73cdc7b9..1447ee6916 100644 --- a/test/lsptoolshost/integrationTests/onAutoInsert.integration.test.ts +++ b/test/lsptoolshost/integrationTests/onAutoInsert.integration.test.ts @@ -110,6 +110,71 @@ describe(`OnAutoInsert Tests`, () => { } ); }); + + test('Enter inside braces respects language-specific tabSize', async () => { + // Set global tabSize to 2 and C# tabSize to 4 + const globalConfig = vscode.workspace.getConfiguration('editor'); + const csharpConfig = vscode.workspace.getConfiguration('editor', { + languageId: 'csharp', + uri: vscode.window.activeTextEditor!.document.uri, + }); + + const originalGlobalTabSize = globalConfig.get('tabSize'); + const originalCsharpTabSize = csharpConfig.get('tabSize'); + + try { + // Configure global tabSize to 2 + await globalConfig.update('tabSize', 2, vscode.ConfigurationTarget.Global); + // Configure C# tabSize to 4 + await vscode.workspace + .getConfiguration('[csharp]', vscode.window.activeTextEditor!.document.uri) + .update('editor.tabSize', 4, vscode.ConfigurationTarget.Global); + + // Wait for configuration to propagate + await sleep(100); + + await vscode.window.activeTextEditor!.edit((editBuilder) => { + editBuilder.insert(new vscode.Position(11, 15), '\n'); + }); + + // OnAutoInsert is triggered by the change event but completes asynchronously, so wait for the buffer to be updated. + + const expectedLines = [ + 'class DocComments', + '{', + ' //', + ' string M(int param1, string param2)', + ' {', + ' return null;', + ' }', + '', + ' /// ', + '', + ' /// ', + ' void M2()', + ' {', + ' ', // Should be 4 spaces (C# setting), not 2 (global setting) + ' }', + '}', + '', + ]; + + await waitForExpectedResult( + async () => vscode.window.activeTextEditor?.document.getText(), + 10000, + 100, + (input) => { + expect(input).toBe(expectedLines.join(EOL)); + } + ); + } finally { + // Restore original settings + await globalConfig.update('tabSize', originalGlobalTabSize, vscode.ConfigurationTarget.Global); + await vscode.workspace + .getConfiguration('[csharp]', vscode.window.activeTextEditor!.document.uri) + .update('editor.tabSize', originalCsharpTabSize, vscode.ConfigurationTarget.Global); + } + }); }); function normalizeNewlines(text: string | undefined): string | undefined { From 6a5d48e3963723ba2ea174949b376537b241c8f0 Mon Sep 17 00:00:00 2001 From: David Barbet Date: Mon, 10 Nov 2025 14:21:13 -0800 Subject: [PATCH 3/4] actually fix (pass in document) and also respect detect indentation --- src/lsptoolshost/autoInsert/onAutoInsert.ts | 32 +++++++++++++++---- .../onAutoInsert.integration.test.ts | 28 ++++++---------- 2 files changed, 35 insertions(+), 25 deletions(-) diff --git a/src/lsptoolshost/autoInsert/onAutoInsert.ts b/src/lsptoolshost/autoInsert/onAutoInsert.ts index a761cb96fe..a34849ad5e 100644 --- a/src/lsptoolshost/autoInsert/onAutoInsert.ts +++ b/src/lsptoolshost/autoInsert/onAutoInsert.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ import * as vscode from 'vscode'; - import { FormattingOptions, InsertTextFormat, @@ -82,10 +81,20 @@ export function registerOnAutoInsert(languageServer: RoslynLanguageServer, langu // We need to calculate what that position would be after the change is applied and send that to the server. const position = vscodeRange.start.translate(0, change.text.length - rangeLength); + const formattingOptions = getFormattingOptions(document); + source.cancel(); source = new vscode.CancellationTokenSource(); try { - await applyAutoInsertEdit(position, changeTrimmed, e.textDocument, uri, languageServer, source.token); + await applyAutoInsertEdit( + position, + changeTrimmed, + e.textDocument, + uri, + formattingOptions, + languageServer, + source.token + ); } catch (e) { if (e instanceof vscode.CancellationError) { return; @@ -101,10 +110,10 @@ async function applyAutoInsertEdit( changeTextTrimmed: string, textDocumentIdentifier: TextDocumentIdentifier, uri: vscode.Uri, + formattingOptions: FormattingOptions, languageServer: RoslynLanguageServer, token: vscode.CancellationToken ) { - const formattingOptions = getFormattingOptions(uri); const request: RoslynProtocol.OnAutoInsertParams = { _vs_textDocument: textDocumentIdentifier, _vs_position: position, @@ -142,9 +151,18 @@ async function applyAutoInsertEdit( } } -function getFormattingOptions(resource: vscode.Uri): FormattingOptions { - const editorConfig = vscode.workspace.getConfiguration('editor', resource); - const tabSize = editorConfig.get('tabSize') ?? 4; - const insertSpaces = editorConfig.get('insertSpaces') ?? true; +function getFormattingOptions(document: vscode.TextDocument): FormattingOptions { + const editorConfig = vscode.workspace.getConfiguration('editor', document); + const detectIndentation = editorConfig.get('detectIndentation'); + + const editor = detectIndentation + ? vscode.window.visibleTextEditors.find((e) => e.document === document) + : undefined; + + // VSCode guarantees that retrieving the editor.options.tabSize will return a number + const tabSize = (editor?.options.tabSize as number | undefined) ?? editorConfig.get('tabSize') ?? 4; + // VSCode guarantees that retrieving the editor.options.insertSpaces will return a boolean + const insertSpaces = + (editor?.options.insertSpaces as boolean | undefined) ?? editorConfig.get('insertSpaces') ?? true; return FormattingOptions.create(tabSize, insertSpaces); } diff --git a/test/lsptoolshost/integrationTests/onAutoInsert.integration.test.ts b/test/lsptoolshost/integrationTests/onAutoInsert.integration.test.ts index 1447ee6916..59717573af 100644 --- a/test/lsptoolshost/integrationTests/onAutoInsert.integration.test.ts +++ b/test/lsptoolshost/integrationTests/onAutoInsert.integration.test.ts @@ -11,7 +11,6 @@ import { closeAllEditorsAsync, openFileInWorkspaceAsync, revertActiveFile, - sleep, waitForExpectedResult, } from './integrationHelpers'; import { describe, beforeAll, beforeEach, afterAll, test, expect, afterEach } from '@jest/globals'; @@ -36,7 +35,6 @@ describe(`OnAutoInsert Tests`, () => { }); test('Triple slash inserts doc comment snippet', async () => { - await sleep(1); await vscode.window.activeTextEditor!.edit((editBuilder) => { editBuilder.insert(new vscode.Position(2, 6), '/'); }); @@ -123,22 +121,17 @@ describe(`OnAutoInsert Tests`, () => { const originalCsharpTabSize = csharpConfig.get('tabSize'); try { - // Configure global tabSize to 2 - await globalConfig.update('tabSize', 2, vscode.ConfigurationTarget.Global); - // Configure C# tabSize to 4 - await vscode.workspace - .getConfiguration('[csharp]', vscode.window.activeTextEditor!.document.uri) - .update('editor.tabSize', 4, vscode.ConfigurationTarget.Global); + // Turn off detect indentation to ensure it consistently uses the settings. + await globalConfig.update('detectIndentation', false, vscode.ConfigurationTarget.Global); - // Wait for configuration to propagate - await sleep(100); + // Customize tab sizes + await globalConfig.update('tabSize', 4, vscode.ConfigurationTarget.Global); + await csharpConfig.update('tabSize', 2, vscode.ConfigurationTarget.Global); await vscode.window.activeTextEditor!.edit((editBuilder) => { editBuilder.insert(new vscode.Position(11, 15), '\n'); }); - // OnAutoInsert is triggered by the change event but completes asynchronously, so wait for the buffer to be updated. - const expectedLines = [ 'class DocComments', '{', @@ -152,9 +145,9 @@ describe(`OnAutoInsert Tests`, () => { '', ' /// ', ' void M2()', - ' {', - ' ', // Should be 4 spaces (C# setting), not 2 (global setting) - ' }', + ' {', + ' ', // Should be 2 spaces (C# setting), not 4 (global setting) + ' }', '}', '', ]; @@ -169,10 +162,9 @@ describe(`OnAutoInsert Tests`, () => { ); } finally { // Restore original settings + await globalConfig.update('detectIndentation', true, vscode.ConfigurationTarget.Global); await globalConfig.update('tabSize', originalGlobalTabSize, vscode.ConfigurationTarget.Global); - await vscode.workspace - .getConfiguration('[csharp]', vscode.window.activeTextEditor!.document.uri) - .update('editor.tabSize', originalCsharpTabSize, vscode.ConfigurationTarget.Global); + await csharpConfig.update('tabSize', originalCsharpTabSize, vscode.ConfigurationTarget.Global); } }); }); From b057a1d8fa938b54b0798b1f8b35eaf8f02d3111 Mon Sep 17 00:00:00 2001 From: David Barbet Date: Mon, 10 Nov 2025 16:31:51 -0800 Subject: [PATCH 4/4] rename variable for clarity --- src/lsptoolshost/autoInsert/onAutoInsert.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lsptoolshost/autoInsert/onAutoInsert.ts b/src/lsptoolshost/autoInsert/onAutoInsert.ts index a34849ad5e..afbfb3e43e 100644 --- a/src/lsptoolshost/autoInsert/onAutoInsert.ts +++ b/src/lsptoolshost/autoInsert/onAutoInsert.ts @@ -152,17 +152,17 @@ async function applyAutoInsertEdit( } function getFormattingOptions(document: vscode.TextDocument): FormattingOptions { - const editorConfig = vscode.workspace.getConfiguration('editor', document); - const detectIndentation = editorConfig.get('detectIndentation'); + const editorSettings = vscode.workspace.getConfiguration('editor', document); + const detectIndentation = editorSettings.get('detectIndentation'); const editor = detectIndentation ? vscode.window.visibleTextEditors.find((e) => e.document === document) : undefined; // VSCode guarantees that retrieving the editor.options.tabSize will return a number - const tabSize = (editor?.options.tabSize as number | undefined) ?? editorConfig.get('tabSize') ?? 4; + const tabSize = (editor?.options.tabSize as number | undefined) ?? editorSettings.get('tabSize') ?? 4; // VSCode guarantees that retrieving the editor.options.insertSpaces will return a boolean const insertSpaces = - (editor?.options.insertSpaces as boolean | undefined) ?? editorConfig.get('insertSpaces') ?? true; + (editor?.options.insertSpaces as boolean | undefined) ?? editorSettings.get('insertSpaces') ?? true; return FormattingOptions.create(tabSize, insertSpaces); }