Skip to content

Commit

Permalink
feat(language-service): sync volar 2.0 formatting refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
johnsoncodehk committed Feb 22, 2024
1 parent 549d036 commit d46aded
Show file tree
Hide file tree
Showing 8 changed files with 70 additions and 116 deletions.
73 changes: 12 additions & 61 deletions extensions/vscode/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -283,67 +283,6 @@
"type": "object",
"title": "Volar",
"properties": {
"volar.format.initialIndent": {
"type": "object",
"description": "Whether to have initial indent.",
"default": {
"html": true
},
"properties": {
"html": {
"type": "boolean",
"default": true
},
"typescript": {
"type": "boolean",
"default": false
},
"javascript": {
"type": "boolean",
"default": false
},
"typescriptreact": {
"type": "boolean",
"default": false
},
"javascriptreact": {
"type": "boolean",
"default": false
},
"css": {
"type": "boolean",
"default": false
},
"scss": {
"type": "boolean",
"default": false
},
"less": {
"type": "boolean",
"default": false
},
"sass": {
"type": "boolean",
"default": false
},
"jade": {
"type": "boolean",
"default": false
},
"json": {
"type": "boolean",
"default": false
},
"jsonc": {
"type": "boolean",
"default": false
},
"json5": {
"type": "boolean",
"default": false
}
}
},
"vue.trace.server": {
"scope": "window",
"type": "string",
Expand Down Expand Up @@ -537,6 +476,18 @@
"type": "boolean",
"default": false,
"description": "Show inlay hints for component options wrapper for type support."
},
"vue.format.initialIndent.template": {
"type": "boolean",
"default": true
},
"vue.format.initialIndent.style": {
"type": "boolean",
"default": false
},
"vue.format.initialIndent.script": {
"type": "boolean",
"default": false
}
}
},
Expand Down
4 changes: 2 additions & 2 deletions packages/language-core/src/generators/template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -480,8 +480,8 @@ export function* generate(
content,
start,
lines.length <= 1 ? formatBrackets.curly : [
formatBrackets.curly[0],
lines[lines.length - 1].trim() === '' ? '' : formatBrackets.curly[1],
lines[0].trim() === '' ? '(' : formatBrackets.curly[0],
lines[lines.length - 1].trim() === '' ? ')' : formatBrackets.curly[1],
],
);
}
Expand Down
19 changes: 4 additions & 15 deletions packages/language-service/src/plugins/vue-extract-file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,23 +70,22 @@ export function create(ts: typeof import('typescript/lib/tsserverlibrary')): Ser
return codeAction;

const languageService = context.inject<Provide, 'typescript/languageService'>('typescript/languageService');
const languageServiceHost = context.inject<Provide, 'typescript/languageServiceHost'>('typescript/languageServiceHost');
const sourceFile = languageService.getProgram()!.getSourceFile(vueCode.fileName)!;
const sourceFileKind = languageServiceHost.getScriptKind?.(vueCode.fileName);
const toExtract = collectExtractProps();
const initialIndentSetting = (await context.env.getConfiguration!('volar.format.initialIndent') ?? { html: true }) as Record<string, boolean>;
const templateInitialIndent = await context.env.getConfiguration!<boolean>('vue.format.initialIndent.template') ?? true;
const scriptInitialIndent = await context.env.getConfiguration!<boolean>('vue.format.initialIndent.script') ?? true;
const newUri = document.uri.substring(0, document.uri.lastIndexOf('/') + 1) + `${newName}.vue`;
const lastImportNode = getLastImportNode(ts, script.ast);

let newFileTags = [];

newFileTags.push(
constructTag('template', [], initialIndentSetting.html, sfc.template.content.substring(templateCodeRange[0], templateCodeRange[1]))
constructTag('template', [], templateInitialIndent, sfc.template.content.substring(templateCodeRange[0], templateCodeRange[1]))
);

if (toExtract.length) {
newFileTags.push(
constructTag('script', ['setup', 'lang="ts"'], isInitialIndentNeeded(ts, sourceFileKind!, initialIndentSetting), generateNewScriptContents())
constructTag('script', ['setup', 'lang="ts"'], scriptInitialIndent, generateNewScriptContents())
);
}
if (sfc.template.startTagEnd > script.startTagEnd) {
Expand Down Expand Up @@ -290,16 +289,6 @@ function constructTag(name: string, attributes: string[], initialIndent: boolean
return `<${name}${attributesString}>\n${content}\n</${name}>\n`;
}

function isInitialIndentNeeded(ts: typeof import("typescript/lib/tsserverlibrary"), languageKind: ts.ScriptKind, initialIndentSetting: Record<string, boolean>) {
const languageKindIdMap = {
[ts.ScriptKind.JS]: 'javascript',
[ts.ScriptKind.TS]: 'typescript',
[ts.ScriptKind.JSX]: 'javascriptreact',
[ts.ScriptKind.TSX]: 'typescriptreact',
} as Record<ts.ScriptKind, string>;
return initialIndentSetting[languageKindIdMap[languageKind]] ?? false;
}

export function getLastImportNode(ts: typeof import('typescript/lib/tsserverlibrary'), sourceFile: ts.SourceFile) {

let lastImportNode: ts.Node | undefined;
Expand Down
73 changes: 44 additions & 29 deletions packages/language-service/src/plugins/vue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@ export function create(): ServicePlugin {
create(context): ServicePluginInstance<Provide> {

const htmlPlugin = createHtmlService({ languageId: 'vue', useCustomDataProviders: false }).create(context);
const htmlLanguageService: html.LanguageService = htmlPlugin.provide['html/languageService']();

sfcDataProvider ??= html.newHTMLDataProvider('vue', loadLanguageBlocks(context.env.locale ?? 'en'));

htmlPlugin.provide['html/languageService']().setDataProviders(false, [sfcDataProvider]);
htmlLanguageService.setDataProviders(false, [sfcDataProvider]);

return {

Expand All @@ -36,6 +37,31 @@ export function create(): ServicePlugin {
},
},

async resolveEmbeddedCodeFormattingOptions(code, options) {

Check failure on line 40 in packages/language-service/src/plugins/vue.ts

View workflow job for this annotation

GitHub Actions / build (16, macos-latest)

Object literal may only specify known properties, and 'resolveEmbeddedCodeFormattingOptions' does not exist in type 'ServicePluginInstance<Provide>'.

Check failure on line 40 in packages/language-service/src/plugins/vue.ts

View workflow job for this annotation

GitHub Actions / build (16, macos-latest)

Parameter 'code' implicitly has an 'any' type.

Check failure on line 40 in packages/language-service/src/plugins/vue.ts

View workflow job for this annotation

GitHub Actions / build (16, macos-latest)

Parameter 'options' implicitly has an 'any' type.

Check failure on line 40 in packages/language-service/src/plugins/vue.ts

View workflow job for this annotation

GitHub Actions / build (16, ubuntu-latest)

Object literal may only specify known properties, and 'resolveEmbeddedCodeFormattingOptions' does not exist in type 'ServicePluginInstance<Provide>'.

Check failure on line 40 in packages/language-service/src/plugins/vue.ts

View workflow job for this annotation

GitHub Actions / build (16, ubuntu-latest)

Parameter 'code' implicitly has an 'any' type.

Check failure on line 40 in packages/language-service/src/plugins/vue.ts

View workflow job for this annotation

GitHub Actions / build (16, ubuntu-latest)

Parameter 'options' implicitly has an 'any' type.

const sourceFile = context.language.files.getByVirtualCode(code);

if (sourceFile.generated?.code instanceof vue.VueGeneratedCode) {
if (code.id === 'scriptFormat' || code.id === 'scriptSetupFormat') {
if (await context.env.getConfiguration?.('vue.format.initialIndent.script') ?? false) {
options.initialIndentLevel++;
}
}
else if (code.id.startsWith('style_')) {
if (await context.env.getConfiguration?.('vue.format.initialIndent.style') ?? false) {
options.initialIndentLevel++;
}
}
else if (code.id === 'template') {
if (await context.env.getConfiguration?.('vue.format.initialIndent.template') ?? true) {
options.initialIndentLevel++;
}
}
}

return options;
},

provideSemanticDiagnostics(document) {
return worker(document, (vueCode) => {

Expand Down Expand Up @@ -154,37 +180,26 @@ export function create(): ServicePlugin {
});
},

provideDocumentFormattingEdits(document) {
return worker(document, (vueSourceFile) => {
provideDocumentFormattingEdits(document, range, options) {
return worker(document, async vueCode => {

const blocks = [
vueSourceFile.sfc.script,
vueSourceFile.sfc.scriptSetup,
vueSourceFile.sfc.template,
...vueSourceFile.sfc.styles,
...vueSourceFile.sfc.customBlocks,
].filter((block): block is NonNullable<typeof block> => !!block)
.sort((a, b) => b.start - a.start);

const edits: vscode.TextEdit[] = [];

for (const block of blocks) {
const startPos = document.positionAt(block.start);
if (startPos.character !== 0) {
edits.push({
range: {
start: {
line: startPos.line,
character: 0,
},
end: startPos,
},
newText: '',
});
}
const formatSettings = await context.env.getConfiguration?.<html.HTMLFormatConfiguration>('html.format') ?? {};
const blockTypes = ['template', 'script', 'style'];

for (const customBlock of vueCode.sfc.customBlocks) {
blockTypes.push(customBlock.type);
}

return edits;
return htmlLanguageService.format(document, range, {
...options,
...formatSettings,
unformatted: '',
contentUnformatted: blockTypes.join(','),
extraLiners: blockTypes.join(','),
endWithNewline: options.insertFinalNewline ? true
: options.trimFinalNewlines ? false
: document.getText().endsWith('\n'),
});
});
},
};
Expand Down
8 changes: 3 additions & 5 deletions packages/language-service/tests/format/1806.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,8 @@ export { }
</style>
`.trim(),
settings: {
'volar.format.initialIndent': {
html: false,
javascript: true,
css: true
}
'vue.format.initialIndent.template': false,
'vue.format.initialIndent.script': true,
'vue.format.initialIndent.style': true,
},
});
3 changes: 3 additions & 0 deletions packages/language-service/tests/format/2520.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,7 @@ defineFormatTest({
</pre>
</template>
`.trim(),
settings: {
'html.format.contentUnformatted': 'pre',
},
});
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,6 @@ txt
</script>
`.trim(),
settings: {
'volar.format.initialIndent': {
javascript: true
}
'vue.format.initialIndent.script': true,
},
});
2 changes: 1 addition & 1 deletion packages/language-service/tests/utils/format.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export function defineFormatTest(options: {
{ insertSpaces: false, tabSize: 4 },
);

expect(formatted).toBe((options.output ?? options.input));
expect(formatted.replace(/\r\n/g, '\n')).toBe((options.output ?? options.input).replace(/\r\n/g, '\n'));
});
});
}

0 comments on commit d46aded

Please sign in to comment.