Skip to content

Commit dd540d6

Browse files
authored
(fix) fall back to FormattingOptions (#554)
In case no prettier configs are found #539 BREAKING CHANGE: If user has no prettier config, he now gets the tab size / space/tabs-settings of his IDE, not the default prettier config
1 parent 923f448 commit dd540d6

File tree

6 files changed

+106
-20
lines changed

6 files changed

+106
-20
lines changed

packages/language-server/src/plugins/PluginHost.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818
CompletionItem,
1919
CompletionContext,
2020
WorkspaceEdit,
21+
FormattingOptions,
2122
} from 'vscode-languageserver';
2223
import { LSConfig, LSConfigManager } from '../ls-config';
2324
import { DocumentManager } from '../lib/documents';
@@ -136,14 +137,21 @@ export class PluginHost implements LSProvider, OnWatchFileChanges {
136137
return result ?? completionItem;
137138
}
138139

139-
async formatDocument(textDocument: TextDocumentIdentifier): Promise<TextEdit[]> {
140+
async formatDocument(
141+
textDocument: TextDocumentIdentifier,
142+
options: FormattingOptions,
143+
): Promise<TextEdit[]> {
140144
const document = this.getDocument(textDocument.uri);
141145
if (!document) {
142146
throw new Error('Cannot call methods on an unopened document');
143147
}
144148

145149
return flatten(
146-
await this.execute<TextEdit[]>('formatDocument', [document], ExecuteMode.Collect),
150+
await this.execute<TextEdit[]>(
151+
'formatDocument',
152+
[document, options],
153+
ExecuteMode.Collect,
154+
),
147155
);
148156
}
149157

packages/language-server/src/plugins/interfaces.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
CompletionList,
1010
DefinitionLink,
1111
Diagnostic,
12+
FormattingOptions,
1213
Hover,
1314
Position,
1415
Range,
@@ -51,7 +52,7 @@ export interface CompletionsProvider<T extends TextDocumentIdentifier = any> {
5152
}
5253

5354
export interface FormattingProvider {
54-
formatDocument(document: Document): Resolvable<TextEdit[]>;
55+
formatDocument(document: Document, options: FormattingOptions): Resolvable<TextEdit[]>;
5556
}
5657

5758
export interface TagCompleteProvider {

packages/language-server/src/plugins/svelte/SveltePlugin.ts

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {
33
CodeActionContext,
44
CompletionList,
55
Diagnostic,
6+
FormattingOptions,
67
Hover,
78
Position,
89
Range,
@@ -35,11 +36,7 @@ export class SveltePlugin
3536
CodeActionsProvider {
3637
private docManager = new Map<Document, SvelteDocument>();
3738

38-
constructor(
39-
private configManager: LSConfigManager,
40-
private prettierConfig: any,
41-
private editorConfig?: any,
42-
) {}
39+
constructor(private configManager: LSConfigManager, private prettierConfig?: any) {}
4340

4441
async getDiagnostics(document: Document): Promise<Diagnostic[]> {
4542
if (!this.featureEnabled('diagnostics')) {
@@ -62,7 +59,7 @@ export class SveltePlugin
6259
}
6360
}
6461

65-
async formatDocument(document: Document): Promise<TextEdit[]> {
62+
async formatDocument(document: Document, options: FormattingOptions): Promise<TextEdit[]> {
6663
if (!this.featureEnabled('format')) {
6764
return [];
6865
}
@@ -74,9 +71,9 @@ export class SveltePlugin
7471
(await prettier.resolveConfig(filePath, { editorconfig: true })) ||
7572
this.prettierConfig ||
7673
// Be defensive here because IDEs other than VSCode might not have these settings
77-
(this.editorConfig && this.editorConfig.tabSize && {
78-
tabWidth: this.editorConfig.tabSize,
79-
useTabs: !this.editorConfig.insertSpaces,
74+
(options && {
75+
tabWidth: options.tabSize,
76+
useTabs: !options.insertSpaces,
8077
});
8178
// Take .prettierignore into account
8279
const fileInfo = await prettier.getFileInfo(filePath, {

packages/language-server/src/server.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,9 @@ export function startServer(options?: LSOptions) {
8686
let sveltePlugin: SveltePlugin = undefined as any;
8787

8888
connection.onInitialize((evt) => {
89-
const workspaceUris = evt.workspaceFolders?.map(folder => folder.uri.toString())
90-
?? [evt.rootUri ?? ''];
89+
const workspaceUris = evt.workspaceFolders?.map((folder) => folder.uri.toString()) ?? [
90+
evt.rootUri ?? '',
91+
];
9192
Logger.log('Initialize language server at ', workspaceUris.join(', '));
9293
if (workspaceUris.length === 0) {
9394
Logger.error('No workspace path set');
@@ -98,8 +99,7 @@ export function startServer(options?: LSOptions) {
9899
pluginHost.register(
99100
(sveltePlugin = new SveltePlugin(
100101
configManager,
101-
evt.initializationOptions?.prettierConfig || {},
102-
evt.initializationOptions?.editorConfig, // deliberatly don't fall back to empty object
102+
evt.initializationOptions?.prettierConfig,
103103
)),
104104
);
105105
pluginHost.register(new HTMLPlugin(docManager, configManager));
@@ -206,7 +206,9 @@ export function startServer(options?: LSOptions) {
206206
connection.onCompletion((evt) =>
207207
pluginHost.getCompletions(evt.textDocument, evt.position, evt.context),
208208
);
209-
connection.onDocumentFormatting((evt) => pluginHost.formatDocument(evt.textDocument));
209+
connection.onDocumentFormatting((evt) =>
210+
pluginHost.formatDocument(evt.textDocument, evt.options),
211+
);
210212
connection.onRequest(TagCloseRequest.type, (evt) =>
211213
pluginHost.doTagComplete(evt.textDocument, evt.position),
212214
);

packages/language-server/test/plugins/svelte/SveltePlugin.test.ts

Lines changed: 81 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,15 @@ import { SveltePlugin } from '../../../src/plugins';
33
import { DocumentManager, Document } from '../../../src/lib/documents';
44
import { Diagnostic, Range, DiagnosticSeverity } from 'vscode-languageserver';
55
import { LSConfigManager } from '../../../src/ls-config';
6+
import * as importPackage from '../../../src/importPackage';
7+
import sinon from 'sinon';
68

79
describe('Svelte Plugin', () => {
8-
function setup(content: string) {
10+
function setup(content: string, prettierConfig?: any) {
911
const document = new Document('file:///hello.svelte', content);
1012
const docManager = new DocumentManager(() => document);
1113
const pluginManager = new LSConfigManager();
12-
const plugin = new SveltePlugin(pluginManager, {});
14+
const plugin = new SveltePlugin(pluginManager, prettierConfig);
1315
docManager.openDocument(<any>'some doc');
1416
return { plugin, document };
1517
}
@@ -43,4 +45,81 @@ describe('Svelte Plugin', () => {
4345

4446
assert.deepStrictEqual(diagnostics, [diagnostic]);
4547
});
48+
49+
describe('#formatDocument', () => {
50+
function stubPrettier(configExists: boolean) {
51+
const formatStub = sinon.stub().returns('formatted');
52+
53+
sinon.stub(importPackage, 'importPrettier').returns(<any>{
54+
resolveConfig: () => Promise.resolve(configExists && { fromConfig: true }),
55+
getFileInfo: () => ({ ignored: false }),
56+
format: formatStub,
57+
getSupportInfo: () => ({ languages: [{ name: 'svelte' }] }),
58+
});
59+
60+
return formatStub;
61+
}
62+
63+
async function testFormat(configExists: boolean, fallbackPrettierConfigExists: boolean) {
64+
const { plugin, document } = setup(
65+
'unformatted',
66+
fallbackPrettierConfigExists ? { fallbackConfig: true } : undefined,
67+
);
68+
const formatStub = stubPrettier(configExists);
69+
70+
const formatted = await plugin.formatDocument(document, {
71+
insertSpaces: true,
72+
tabSize: 4,
73+
});
74+
assert.deepStrictEqual(formatted, [
75+
{
76+
newText: 'formatted',
77+
range: {
78+
end: {
79+
character: 11,
80+
line: 0,
81+
},
82+
start: {
83+
character: 0,
84+
line: 0,
85+
},
86+
},
87+
},
88+
]);
89+
90+
return formatStub;
91+
}
92+
93+
afterEach(() => {
94+
sinon.restore();
95+
});
96+
97+
it('should use config for formatting', async () => {
98+
const formatStub = await testFormat(true, true);
99+
sinon.assert.calledOnceWithExactly(formatStub, 'unformatted', {
100+
fromConfig: true,
101+
plugins: [],
102+
parser: 'svelte',
103+
});
104+
});
105+
106+
it('should use prettier fallback config for formatting', async () => {
107+
const formatStub = await testFormat(false, true);
108+
sinon.assert.calledOnceWithExactly(formatStub, 'unformatted', {
109+
fallbackConfig: true,
110+
plugins: [],
111+
parser: 'svelte',
112+
});
113+
});
114+
115+
it('should use FormattingOptions for formatting', async () => {
116+
const formatStub = await testFormat(false, false);
117+
sinon.assert.calledOnceWithExactly(formatStub, 'unformatted', {
118+
tabWidth: 4,
119+
useTabs: false,
120+
plugins: [],
121+
parser: 'svelte',
122+
});
123+
});
124+
});
46125
});

packages/svelte-vscode/src/extension.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,6 @@ export function activate(context: ExtensionContext) {
9494
initializationOptions: {
9595
config: workspace.getConfiguration('svelte.plugin'),
9696
prettierConfig: workspace.getConfiguration('prettier'),
97-
editorConfig: workspace.getConfiguration('editor', { languageId: 'svelte' }),
9897
dontFilterIncompleteCompletions: true, // VSCode filters client side and is smarter at it than us
9998
},
10099
};

0 commit comments

Comments
 (0)