Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions src/lsptoolshost/options/configurationMiddleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,20 @@ export function readConfigurations(params: ConfigurationParams): (string | null)
// Note: null means there is no such configuration in client.
// If the configuration is null, should push 'null' to result.
const result: (string | null)[] = [];
const settings = vscode.workspace.getConfiguration();

for (const configurationItem of params.items) {
const section = configurationItem.section;
// Currently only support global option.
if (section === undefined || configurationItem.scopeUri !== undefined) {
if (section === undefined) {
result.push(null);
continue;
}

const scope =
configurationItem.scopeUri === undefined
? { languageId: 'csharp' }
: { languageId: 'csharp', uri: vscode.Uri.parse(configurationItem.scopeUri) };
const settings = vscode.workspace.getConfiguration(undefined, scope);

// Server use a different name compare to the name defined in client, so do the remapping.
const clientSideName = convertServerOptionNameToClientConfigurationName(section);
if (clientSideName == null) {
Expand All @@ -35,7 +39,7 @@ export function readConfigurations(params: ConfigurationParams): (string | null)
continue;
}

value = readEquivalentVsCodeConfiguration(clientSideName);
value = readEquivalentVsCodeConfiguration(clientSideName, scope);
if (value !== undefined) {
result.push(value);
continue;
Expand Down
9 changes: 6 additions & 3 deletions src/lsptoolshost/options/universalEditorConfigProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { WorkspaceConfiguration, workspace } from 'vscode';
import { ConfigurationScope, WorkspaceConfiguration, workspace } from 'vscode';

// By default we don't want to provide any fall back value for code style options.
// These values are exceptions because they already exist in vscode's configuration.
Expand All @@ -18,13 +18,16 @@ const universalEditorConfigOptionsToReaderMap: Map<
['codeStyle.formatting.newLine.insertFinalNewline', readInsertFinalNewline],
]);

export function readEquivalentVsCodeConfiguration(serverSideOptionName: string): string | undefined {
export function readEquivalentVsCodeConfiguration(
serverSideOptionName: string,
scope: ConfigurationScope = { languageId: 'csharp' }
): string | undefined {
if (!universalEditorConfigOptionsToReaderMap.has(serverSideOptionName)) {
return undefined;
}

const readerFunction = universalEditorConfigOptionsToReaderMap.get(serverSideOptionName)!;
const config = workspace.getConfiguration('', { languageId: 'csharp' });
const config = workspace.getConfiguration('', scope);
return readerFunction(config);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,14 @@ describe(`Formatting With EditorConfig Tests`, () => {
'namespace Formatting;',
'',
'class DocumentFormattingWithEditorConfig {',
' public int Property1 {',
' get; set;',
' }',
' public int Property1 {',
' get; set;',
' }',
'',
' public void Method1() {',
' if (true) {',
' }',
' public void Method1() {',
' if (true) {',
' }',
' }',
'}',
];
await expectText(vscode.window.activeTextEditor!.document, expectedText);
Expand All @@ -61,16 +61,16 @@ describe(`Formatting With EditorConfig Tests`, () => {
'namespace Formatting;',
'class DocumentFormattingWithEditorConfig',
'{',
' public int Property1 {',
' get; set;',
' }',
' public int Property1 {',
' get; set;',
' }',
'',
' public void Method1()',
' public void Method1()',
' {',
' if (true)',
' {',
' if (true)',
' {',
' }',
' }',
' }',
'}',
];
await expectText(vscode.window.activeTextEditor!.document, expectedText);
Expand All @@ -84,16 +84,16 @@ describe(`Formatting With EditorConfig Tests`, () => {
'namespace Formatting;',
'class DocumentFormattingWithEditorConfig',
'{',
' public int Property1',
' {',
' get; set;',
' }',
' public int Property1',
' {',
' get; set;',
' }',
'',
' public void Method1()',
' {',
' if (true) {',
' }',
' public void Method1()',
' {',
' if (true) {',
' }',
' }',
'}',
];
await expectText(vscode.window.activeTextEditor!.document, expectedText);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
[*.{cs}]
indent_size = 2
indent_style = space
csharp_new_line_before_open_brace = none
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import * as vscode from 'vscode';
import { beforeEach, describe, expect, jest, test } from '@jest/globals';
import { readConfigurations } from '../../../src/lsptoolshost/options/configurationMiddleware';

describe('configurationMiddleware.readConfigurations', () => {
const getConfiguration = jest.fn<typeof vscode.workspace.getConfiguration>();
const uriParse = jest.fn<typeof vscode.Uri.parse>();

beforeEach(() => {
jest.resetAllMocks();
vscode.workspace.getConfiguration = getConfiguration;
vscode.Uri.parse = uriParse;
});

test('reads scoped client configuration values when scopeUri is provided', () => {
const scopedSettings = {
get: jest.fn().mockImplementation((...args: unknown[]) => {
const name = args[0] as string;
return name === 'dotnet.formatting.organizeImportsOnFormat' ? 'true' : undefined;
}),
} as unknown as vscode.WorkspaceConfiguration;
const uri = { fsPath: '/workspace/Program.cs' } as vscode.Uri;

uriParse.mockReturnValue(uri);
getConfiguration.mockReturnValue(scopedSettings);

const values = readConfigurations({
items: [
{
section: 'csharp|formatting.dotnet_organize_imports_on_format',
scopeUri: 'file:///workspace/Program.cs',
},
],
});

expect(values).toEqual(['true']);
expect(uriParse).toHaveBeenCalledWith('file:///workspace/Program.cs');
expect(getConfiguration).toHaveBeenCalledWith(undefined, { languageId: 'csharp', uri });
expect(scopedSettings.get).toHaveBeenCalledWith('dotnet.formatting.organizeImportsOnFormat');
});

test('reads scoped fallback vscode formatting configuration when explicit client setting is absent', () => {
const scopedSettings = {
get: jest.fn().mockImplementation((...args: unknown[]) => {
const name = args[0] as string;
return name === 'editor.indentSize' ? '2' : undefined;
}),
} as unknown as vscode.WorkspaceConfiguration;
const uri = { fsPath: '/workspace/Program.cs' } as vscode.Uri;

uriParse.mockReturnValue(uri);
getConfiguration.mockReturnValue(scopedSettings);

const values = readConfigurations({
items: [
{
section: 'csharp|code_style.formatting.indentation_and_spacing.indent_size',
scopeUri: 'file:///workspace/Program.cs',
},
],
});

expect(values).toEqual(['2']);
expect(getConfiguration).toHaveBeenCalledWith(undefined, { languageId: 'csharp', uri });
expect(getConfiguration).toHaveBeenCalledWith('', { languageId: 'csharp', uri });
expect(scopedSettings.get).toHaveBeenCalledWith('codeStyle.formatting.indentationAndSpacing.indentSize');
expect(scopedSettings.get).toHaveBeenCalledWith('editor.indentSize');
});

test('resolves indentSize=tabSize through scoped vscode formatting configuration', () => {
const scopedSettings = {
get: jest.fn().mockImplementation((...args: unknown[]) => {
const name = args[0] as string;
if (name === 'codeStyle.formatting.indentationAndSpacing.indentSize') {
return undefined;
}

if (name === 'editor.indentSize') {
return 'tabSize';
}

if (name === 'editor.tabSize') {
return '2';
}

return undefined;
}),
} as unknown as vscode.WorkspaceConfiguration;
const uri = { fsPath: '/workspace/Program.cs' } as vscode.Uri;

uriParse.mockReturnValue(uri);
getConfiguration.mockReturnValue(scopedSettings);

const values = readConfigurations({
items: [
{
section: 'csharp|code_style.formatting.indentation_and_spacing.indent_size',
scopeUri: 'file:///workspace/Program.cs',
},
],
});

expect(values).toEqual(['2']);
expect(scopedSettings.get).toHaveBeenCalledWith('editor.indentSize');
expect(scopedSettings.get).toHaveBeenCalledWith('editor.tabSize');
});
});
Loading