diff --git a/src/lsptoolshost/autoInsert/onAutoInsert.ts b/src/lsptoolshost/autoInsert/onAutoInsert.ts index f9e8adafab..afbfb3e43e 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(); const request: RoslynProtocol.OnAutoInsertParams = { _vs_textDocument: textDocumentIdentifier, _vs_position: position, @@ -142,9 +151,18 @@ async function applyAutoInsertEdit( } } -function getFormattingOptions(): FormattingOptions { - const editorConfig = vscode.workspace.getConfiguration('editor'); - const tabSize = editorConfig.get('tabSize') ?? 4; - const insertSpaces = editorConfig.get('insertSpaces') ?? true; +function getFormattingOptions(document: vscode.TextDocument): FormattingOptions { + 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) ?? editorSettings.get('tabSize') ?? 4; + // VSCode guarantees that retrieving the editor.options.insertSpaces will return a boolean + const insertSpaces = + (editor?.options.insertSpaces as boolean | undefined) ?? editorSettings.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..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), '/'); }); @@ -110,6 +108,65 @@ 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 { + // Turn off detect indentation to ensure it consistently uses the settings. + await globalConfig.update('detectIndentation', false, vscode.ConfigurationTarget.Global); + + // 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'); + }); + + const expectedLines = [ + 'class DocComments', + '{', + ' //', + ' string M(int param1, string param2)', + ' {', + ' return null;', + ' }', + '', + ' /// ', + '', + ' /// ', + ' void M2()', + ' {', + ' ', // Should be 2 spaces (C# setting), not 4 (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('detectIndentation', true, vscode.ConfigurationTarget.Global); + await globalConfig.update('tabSize', originalGlobalTabSize, vscode.ConfigurationTarget.Global); + await csharpConfig.update('tabSize', originalCsharpTabSize, vscode.ConfigurationTarget.Global); + } + }); }); function normalizeNewlines(text: string | undefined): string | undefined {