From f7f63f96f3b77486fdf5dc872a41bdf900549bb0 Mon Sep 17 00:00:00 2001 From: Johnson Chu Date: Sat, 24 Feb 2024 00:50:04 +0800 Subject: [PATCH] feat(css, html, typescript): consume `initialIndentLevel` in embedded code formatting (#75) --- package.json | 4 +- packages/css/index.ts | 99 +++++++++++++- packages/css/package.json | 6 +- packages/emmet/package.json | 2 +- packages/html/index.ts | 129 +++++++++++------- packages/html/package.json | 6 +- packages/json/package.json | 2 +- packages/markdown/package.json | 2 +- packages/prettier/package.json | 2 +- packages/pretty-ts-errors/package.json | 2 +- packages/prettyhtml/package.json | 2 +- packages/pug-beautify/package.json | 2 +- packages/pug/index.ts | 2 +- packages/pug/lib/services/completion.ts | 2 +- .../pug/lib/services/documentHighlight.ts | 2 +- packages/pug/lib/services/documentLinks.ts | 2 +- packages/pug/lib/services/hover.ts | 2 +- packages/pug/lib/services/selectionRanges.ts | 2 +- packages/pug/package.json | 2 +- packages/sass-formatter/package.json | 2 +- packages/tsconfig/package.json | 2 +- .../typescript-twoslash-queries/package.json | 2 +- packages/typescript/index.ts | 53 ++----- .../lib/configs/getFormatCodeSettings.ts | 8 +- .../typescript/lib/features/formatting.ts | 21 ++- packages/typescript/package.json | 7 +- packages/vetur/package.json | 2 +- packages/yaml/package.json | 2 +- pnpm-lock.yaml | 15 +- 29 files changed, 240 insertions(+), 146 deletions(-) diff --git a/package.json b/package.json index ebf53899..5bcb4b10 100644 --- a/package.json +++ b/package.json @@ -6,14 +6,14 @@ "watch": "tsc -b -w", "prerelease": "npm run build", "release": "lerna publish --exact --force-publish --yes --sync-workspace-lock", - "postrelease": "lerna exec --no-bail --no-private --no-sort --stream -- '[ -n \"$(npm v . dist-tags.latest)\" ] && npm dist-tag add ${LERNA_PACKAGE_NAME}@$(npm v . dist-tags.latest) volar-2.0'", + "postrelease": "lerna exec --no-bail --no-private --no-sort --stream -- '[ -n \"$(npm v . dist-tags.latest)\" ] && npm dist-tag add ${LERNA_PACKAGE_NAME}@$(npm v . dist-tags.latest) volar-2.1'", "release:next": "npm run release -- --dist-tag next" }, "devDependencies": { "@lerna-lite/cli": "latest", "@lerna-lite/exec": "latest", "@lerna-lite/publish": "latest", - "@volar/language-service": "~2.0.4", + "@volar/language-service": "~2.1.0", "typescript": "latest", "vscode-languageserver-protocol": "^3.17.5" } diff --git a/packages/css/index.ts b/packages/css/index.ts index 1b3323af..752e1760 100644 --- a/packages/css/index.ts +++ b/packages/css/index.ts @@ -1,6 +1,6 @@ import type { CodeAction, Diagnostic, LocationLink, ServicePluginInstance, ServicePlugin } from '@volar/language-service'; import * as css from 'vscode-css-languageservice'; -import type { TextDocument } from 'vscode-languageserver-textdocument'; +import { TextDocument } from 'vscode-languageserver-textdocument'; import { URI, Utils } from 'vscode-uri'; export interface Provide { @@ -180,18 +180,103 @@ export function create(): ServicePlugin { }); }, - async provideDocumentFormattingEdits(document, formatRange, options) { + async provideDocumentFormattingEdits(document, formatRange, options, codeOptions) { return worker(document, async (_stylesheet, cssLs) => { - const options_2 = await context.env.getConfiguration?.(document.languageId + '.format'); - if (options_2?.enable === false) { + const formatSettings = await context.env.getConfiguration?.(document.languageId + '.format'); + if (formatSettings?.enable === false) { return; } - return cssLs.format(document, formatRange, { - ...options_2, + const formatOptions: css.CSSFormatConfiguration = { ...options, - }); + ...formatSettings, + }; + + let formatDocument = document; + let prefixes = []; + let suffixes = []; + + if (codeOptions?.initialIndentLevel) { + for (let i = 0; i < codeOptions.initialIndentLevel; i++) { + if (i === codeOptions.initialIndentLevel - 1) { + prefixes.push('_', '{'); + suffixes.unshift('}'); + } + else { + prefixes.push('_', '{\n'); + suffixes.unshift('\n}'); + } + } + formatDocument = TextDocument.create(document.uri, document.languageId, document.version, prefixes.join('') + document.getText() + suffixes.join('')); + formatRange = { + start: formatDocument.positionAt(0), + end: formatDocument.positionAt(formatDocument.getText().length), + }; + } + + let edits = cssLs.format(formatDocument, formatRange, formatOptions); + + if (codeOptions) { + let newText = TextDocument.applyEdits(formatDocument, edits); + for (const prefix of prefixes) { + newText = newText.trimStart().slice(prefix.trim().length); + } + for (const suffix of suffixes.reverse()) { + newText = newText.trimEnd().slice(0, -suffix.trim().length); + } + if (!codeOptions.initialIndentLevel && codeOptions.level > 0) { + newText = ensureNewLines(newText); + } + edits = [{ + range: { + start: document.positionAt(0), + end: document.positionAt(document.getText().length), + }, + newText, + }]; + } + + return edits; + + function ensureNewLines(newText: string) { + const verifyDocument = TextDocument.create(document.uri, document.languageId, document.version, '_ {' + newText + '}'); + const verifyEdits = cssLs.format(verifyDocument, undefined, formatOptions); + let verifyText = TextDocument.applyEdits(verifyDocument, verifyEdits); + verifyText = verifyText.trimStart().slice('_'.length); + verifyText = verifyText.trim().slice('{'.length, -'}'.length); + if (startWithNewLine(verifyText) !== startWithNewLine(newText)) { + if (startWithNewLine(verifyText)) { + newText = '\n' + newText; + } + else if (newText.startsWith('\n')) { + newText = newText.slice(1); + } + else if (newText.startsWith('\r\n')) { + newText = newText.slice(2); + } + } + if (endWithNewLine(verifyText) !== endWithNewLine(newText)) { + if (endWithNewLine(verifyText)) { + newText = newText + '\n'; + } + else if (newText.endsWith('\n')) { + newText = newText.slice(0, -1); + } + else if (newText.endsWith('\r\n')) { + newText = newText.slice(0, -2); + } + } + return newText; + } + + function startWithNewLine(text: string) { + return text.startsWith('\n') || text.startsWith('\r\n'); + } + + function endWithNewLine(text: string) { + return text.endsWith('\n') || text.endsWith('\r\n'); + } }); }, }; diff --git a/packages/css/package.json b/packages/css/package.json index 9a738cd3..18ceef0e 100644 --- a/packages/css/package.json +++ b/packages/css/package.json @@ -25,14 +25,14 @@ }, "dependencies": { "vscode-css-languageservice": "^6.2.10", + "vscode-languageserver-textdocument": "^1.0.11", "vscode-uri": "^3.0.8" }, "devDependencies": { - "@types/node": "latest", - "vscode-languageserver-textdocument": "^1.0.11" + "@types/node": "latest" }, "peerDependencies": { - "@volar/language-service": "~2.0.4" + "@volar/language-service": "~2.1.0" }, "peerDependenciesMeta": { "@volar/language-service": { diff --git a/packages/emmet/package.json b/packages/emmet/package.json index 77e50d93..b4503f24 100644 --- a/packages/emmet/package.json +++ b/packages/emmet/package.json @@ -28,7 +28,7 @@ "volar-service-html": "0.0.30" }, "peerDependencies": { - "@volar/language-service": "~2.0.4" + "@volar/language-service": "~2.1.0" }, "peerDependenciesMeta": { "@volar/language-service": { diff --git a/packages/html/index.ts b/packages/html/index.ts index a1976e61..a0339cdf 100644 --- a/packages/html/index.ts +++ b/packages/html/index.ts @@ -1,6 +1,6 @@ import type { ServicePluginInstance, ServicePlugin } from '@volar/language-service'; import * as html from 'vscode-html-languageservice'; -import type { TextDocument } from 'vscode-languageserver-textdocument'; +import { TextDocument } from 'vscode-languageserver-textdocument'; import { URI, Utils } from 'vscode-uri'; const parserLs = html.getLanguageService(); @@ -143,7 +143,7 @@ export function create({ }); }, - async provideDocumentFormattingEdits(document, formatRange, options) { + async provideDocumentFormattingEdits(document, formatRange, options, codeOptions) { return worker(document, async () => { const formatSettings = await context.env.getConfiguration?.('html.format') ?? {}; @@ -174,62 +174,95 @@ export function create({ }; } - return htmlLs.format(document, formatRange, { + const formatOptions: html.HTMLFormatConfiguration = { ...options, ...formatSettings, - }); - }); - }, + endWithNewline: options.insertFinalNewline ? true : options.trimFinalNewlines ? false : undefined, + }; + + let formatDocument = document; + let prefixes = []; + let suffixes = []; + + if (codeOptions?.initialIndentLevel) { + for (let i = 0; i < codeOptions.initialIndentLevel; i++) { + if (i === codeOptions.initialIndentLevel - 1) { + prefixes.push(''); + } + else { + prefixes.push(''); + } + } + formatDocument = TextDocument.create(document.uri, document.languageId, document.version, prefixes.join('') + document.getText() + suffixes.join('')); + formatRange = { + start: formatDocument.positionAt(0), + end: formatDocument.positionAt(formatDocument.getText().length), + }; + } - provideFormattingIndentSensitiveLines(document) { - return worker(document, (htmlDocument) => { - const lines: number[] = []; - /** - * comments - */ - const scanner = htmlLs.createScanner(document.getText()); - let token = scanner.scan(); - let startCommentTagLine: number | undefined; - while (token !== html.TokenType.EOS) { - if (token === html.TokenType.StartCommentTag) { - startCommentTagLine = document.positionAt(scanner.getTokenOffset()).line; + let edits = htmlLs.format(formatDocument, formatRange, formatOptions); + + if (codeOptions) { + let newText = TextDocument.applyEdits(formatDocument, edits); + for (const prefix of prefixes) { + newText = newText.trimStart().slice(prefix.trim().length); } - else if (token === html.TokenType.EndCommentTag) { - const line = document.positionAt(scanner.getTokenOffset()).line; - for (let i = startCommentTagLine! + 1; i <= line; i++) { - lines.push(i); - } - startCommentTagLine = undefined; + for (const suffix of suffixes.reverse()) { + newText = newText.trimEnd().slice(0, -suffix.trim().length); } - else if (token === html.TokenType.AttributeValue) { - const startLine = document.positionAt(scanner.getTokenOffset()).line; - for (let i = 1; i < scanner.getTokenText().split('\n').length; i++) { - lines.push(startLine + i); - } + if (!codeOptions.initialIndentLevel && codeOptions.level > 0) { + newText = ensureNewLines(newText); } - token = scanner.scan(); + edits = [{ + range: { + start: document.positionAt(0), + end: document.positionAt(document.getText().length), + }, + newText, + }]; } - /** - * tags - */ - // https://github.com/beautify-web/js-beautify/blob/686f8c1b265990908ece86ce39291733c75c997c/js/src/html/options.js#L81 - const indentSensitiveTags = new Set(['pre', 'textarea']); - htmlDocument.roots.forEach(function visit(node) { - if ( - node.tag !== undefined - && node.startTagEnd !== undefined - && node.endTagStart !== undefined - && indentSensitiveTags.has(node.tag) - ) { - for (let i = document.positionAt(node.startTagEnd).line + 1; i <= document.positionAt(node.endTagStart).line; i++) { - lines.push(i); + + return edits; + + function ensureNewLines(newText: string) { + const verifyDocument = TextDocument.create(document.uri, document.languageId, document.version, ''); + const verifyEdits = htmlLs.format(verifyDocument, undefined, formatOptions); + let verifyText = TextDocument.applyEdits(verifyDocument, verifyEdits); + verifyText = verifyText.trim().slice(''.length); + if (startWithNewLine(verifyText) !== startWithNewLine(newText)) { + if (startWithNewLine(verifyText)) { + newText = '\n' + newText; + } + else if (newText.startsWith('\n')) { + newText = newText.slice(1); + } + else if (newText.startsWith('\r\n')) { + newText = newText.slice(2); } } - else { - node.children.forEach(visit); + if (endWithNewLine(verifyText) !== endWithNewLine(newText)) { + if (endWithNewLine(verifyText)) { + newText = newText + '\n'; + } + else if (newText.endsWith('\n')) { + newText = newText.slice(0, -1); + } + else if (newText.endsWith('\r\n')) { + newText = newText.slice(0, -2); + } } - }); - return lines; + return newText; + } + + function startWithNewLine(text: string) { + return text.startsWith('\n') || text.startsWith('\r\n'); + } + + function endWithNewLine(text: string) { + return text.endsWith('\n') || text.endsWith('\r\n'); + } }); }, diff --git a/packages/html/package.json b/packages/html/package.json index 46ceb13e..2de70e2d 100644 --- a/packages/html/package.json +++ b/packages/html/package.json @@ -25,14 +25,14 @@ }, "dependencies": { "vscode-html-languageservice": "^5.1.0", + "vscode-languageserver-textdocument": "^1.0.11", "vscode-uri": "^3.0.8" }, "devDependencies": { - "@types/node": "latest", - "vscode-languageserver-textdocument": "^1.0.11" + "@types/node": "latest" }, "peerDependencies": { - "@volar/language-service": "~2.0.4" + "@volar/language-service": "~2.1.0" }, "peerDependenciesMeta": { "@volar/language-service": { diff --git a/packages/json/package.json b/packages/json/package.json index bf40e58c..f2a214c3 100644 --- a/packages/json/package.json +++ b/packages/json/package.json @@ -31,7 +31,7 @@ "vscode-languageserver-textdocument": "^1.0.11" }, "peerDependencies": { - "@volar/language-service": "~2.0.4" + "@volar/language-service": "~2.1.0" }, "peerDependenciesMeta": { "@volar/language-service": { diff --git a/packages/markdown/package.json b/packages/markdown/package.json index bb985081..bf742d79 100644 --- a/packages/markdown/package.json +++ b/packages/markdown/package.json @@ -34,7 +34,7 @@ "vscode-languageserver-textdocument": "^1.0.11" }, "peerDependencies": { - "@volar/language-service": "~2.0.4" + "@volar/language-service": "~2.1.0" }, "peerDependenciesMeta": { "@volar/language-service": { diff --git a/packages/prettier/package.json b/packages/prettier/package.json index 3530748f..968bf53a 100644 --- a/packages/prettier/package.json +++ b/packages/prettier/package.json @@ -32,7 +32,7 @@ "prettier": "^3.0.3" }, "peerDependencies": { - "@volar/language-service": "~2.0.4", + "@volar/language-service": "~2.1.0", "prettier": "^2.2 || ^3.0" }, "peerDependenciesMeta": { diff --git a/packages/pretty-ts-errors/package.json b/packages/pretty-ts-errors/package.json index 5fcbf9d5..5b9b54b3 100644 --- a/packages/pretty-ts-errors/package.json +++ b/packages/pretty-ts-errors/package.json @@ -27,7 +27,7 @@ "pretty-ts-errors-lsp": "^0.0.3" }, "peerDependencies": { - "@volar/language-service": "~2.0.4" + "@volar/language-service": "~2.1.0" }, "peerDependenciesMeta": { "@volar/language-service": { diff --git a/packages/prettyhtml/package.json b/packages/prettyhtml/package.json index c31904e5..0e3fc83e 100644 --- a/packages/prettyhtml/package.json +++ b/packages/prettyhtml/package.json @@ -27,7 +27,7 @@ "@starptech/prettyhtml": "^0.10.0" }, "peerDependencies": { - "@volar/language-service": "~2.0.4" + "@volar/language-service": "~2.1.0" }, "peerDependenciesMeta": { "@volar/language-service": { diff --git a/packages/pug-beautify/package.json b/packages/pug-beautify/package.json index 84340ea0..dacb74c1 100644 --- a/packages/pug-beautify/package.json +++ b/packages/pug-beautify/package.json @@ -27,7 +27,7 @@ "@johnsoncodehk/pug-beautify": "^0.2.2" }, "peerDependencies": { - "@volar/language-service": "~2.0.4" + "@volar/language-service": "~2.1.0" }, "peerDependenciesMeta": { "@volar/language-service": { diff --git a/packages/pug/index.ts b/packages/pug/index.ts index 29325ade..555f0dbf 100644 --- a/packages/pug/index.ts +++ b/packages/pug/index.ts @@ -81,7 +81,7 @@ export function create(): ServicePlugin { provideDocumentSymbols(document, token) { return worker(document, async (pugDoc) => { - const htmlResult = await htmlService.provideDocumentSymbols?.(pugDoc.map.virtualFileDocument, token) ?? []; + const htmlResult = await htmlService.provideDocumentSymbols?.(pugDoc.map.embeddedDocument, token) ?? []; const pugResult = htmlResult.map(htmlSymbol => transformDocumentSymbol( htmlSymbol, range => pugDoc.map.getSourceRange(range), diff --git a/packages/pug/lib/services/completion.ts b/packages/pug/lib/services/completion.ts index 092de7ec..7021bdcc 100644 --- a/packages/pug/lib/services/completion.ts +++ b/packages/pug/lib/services/completion.ts @@ -53,7 +53,7 @@ export function register(htmlLs: html.LanguageService) { return transformCompletionList( htmlComplete, htmlRange => pugDoc.map.getSourceRange(htmlRange), - pugDoc.map.virtualFileDocument, + pugDoc.map.embeddedDocument, serviceContext, ); }; diff --git a/packages/pug/lib/services/documentHighlight.ts b/packages/pug/lib/services/documentHighlight.ts index 6bb509e4..024416cd 100644 --- a/packages/pug/lib/services/documentHighlight.ts +++ b/packages/pug/lib/services/documentHighlight.ts @@ -10,7 +10,7 @@ export function register(htmlLs: html.LanguageService) { return; const htmlResult = htmlLs.findDocumentHighlights( - pugDoc.map.virtualFileDocument, + pugDoc.map.embeddedDocument, htmlPos, pugDoc.htmlDocument, ); diff --git a/packages/pug/lib/services/documentLinks.ts b/packages/pug/lib/services/documentLinks.ts index d524fa8f..1baecadd 100644 --- a/packages/pug/lib/services/documentLinks.ts +++ b/packages/pug/lib/services/documentLinks.ts @@ -6,7 +6,7 @@ export function register(htmlLs: html.LanguageService) { return (pugDoc: PugDocument, docContext: html.DocumentContext) => { const htmlResult = htmlLs.findDocumentLinks( - pugDoc.map.virtualFileDocument, + pugDoc.map.embeddedDocument, docContext, ); diff --git a/packages/pug/lib/services/hover.ts b/packages/pug/lib/services/hover.ts index 728e0d59..0e96f272 100644 --- a/packages/pug/lib/services/hover.ts +++ b/packages/pug/lib/services/hover.ts @@ -10,7 +10,7 @@ export function register(htmlLs: html.LanguageService) { return; const htmlResult = htmlLs.doHover( - pugDoc.map.virtualFileDocument, + pugDoc.map.embeddedDocument, htmlPos, pugDoc.htmlDocument, options, diff --git a/packages/pug/lib/services/selectionRanges.ts b/packages/pug/lib/services/selectionRanges.ts index 325a05c3..9349cd9f 100644 --- a/packages/pug/lib/services/selectionRanges.ts +++ b/packages/pug/lib/services/selectionRanges.ts @@ -10,7 +10,7 @@ export function register(htmlLs: html.LanguageService) { .filter((v): v is NonNullable => !!v); const htmlResult = htmlLs.getSelectionRanges( - pugDoc.map.virtualFileDocument, + pugDoc.map.embeddedDocument, htmlPosArr, ); diff --git a/packages/pug/package.json b/packages/pug/package.json index 83b59997..08b7d1db 100644 --- a/packages/pug/package.json +++ b/packages/pug/package.json @@ -24,7 +24,7 @@ "url": "https://github.com/johnsoncodehk" }, "dependencies": { - "@volar/language-service": "~2.0.4", + "@volar/language-service": "~2.1.0", "pug-lexer": "^5.0.1", "pug-parser": "^6.0.0", "volar-service-html": "0.0.30", diff --git a/packages/sass-formatter/package.json b/packages/sass-formatter/package.json index 683d481c..d9433042 100644 --- a/packages/sass-formatter/package.json +++ b/packages/sass-formatter/package.json @@ -27,7 +27,7 @@ "sass-formatter": "^0.7.8" }, "peerDependencies": { - "@volar/language-service": "~2.0.4" + "@volar/language-service": "~2.1.0" }, "peerDependenciesMeta": { "@volar/language-service": { diff --git a/packages/tsconfig/package.json b/packages/tsconfig/package.json index 33b7858e..35a82bc7 100644 --- a/packages/tsconfig/package.json +++ b/packages/tsconfig/package.json @@ -32,7 +32,7 @@ "vscode-uri": "^3.0.8" }, "peerDependencies": { - "@volar/language-service": "~2.0.4" + "@volar/language-service": "~2.1.0" }, "peerDependenciesMeta": { "@volar/language-service": { diff --git a/packages/typescript-twoslash-queries/package.json b/packages/typescript-twoslash-queries/package.json index f0497835..435e8793 100644 --- a/packages/typescript-twoslash-queries/package.json +++ b/packages/typescript-twoslash-queries/package.json @@ -27,7 +27,7 @@ "volar-service-typescript": "0.0.30" }, "peerDependencies": { - "@volar/language-service": "~2.0.4" + "@volar/language-service": "~2.1.0" }, "peerDependenciesMeta": { "@volar/language-service": { diff --git a/packages/typescript/index.ts b/packages/typescript/index.ts index dd95ef63..a1fdc865 100644 --- a/packages/typescript/index.ts +++ b/packages/typescript/index.ts @@ -3,7 +3,6 @@ import * as semver from 'semver'; import type * as ts from 'typescript'; import type { TextDocument } from 'vscode-languageserver-textdocument'; import { getConfigTitle, isJsonDocument, isTsDocument } from './lib/shared'; -import { URI } from 'vscode-uri'; import { getDocumentRegistry } from '@volar/typescript'; import * as tsFaster from 'typescript-auto-import-cache'; @@ -68,7 +67,7 @@ export function create(ts: typeof import('typescript')): ServicePlugin { getScriptVersion: fileName => fileName === syntacticHostCtx.fileName ? syntacticHostCtx.fileVersion.toString() : '', getScriptSnapshot: fileName => fileName === syntacticHostCtx.fileName ? syntacticHostCtx.snapshot : undefined, getCompilationSettings: () => ({}), - getCurrentDirectory: () => '/', + getCurrentDirectory: () => '', getDefaultLibFileName: () => '', readFile: () => undefined, fileExists: fileName => fileName === syntacticHostCtx.fileName, @@ -148,7 +147,7 @@ export function create(ts: typeof import('typescript')): ServicePlugin { return findDocumentSymbols(document.uri); }, - async provideDocumentFormattingEdits(document, range, options_2) { + async provideDocumentFormattingEdits(document, range, options, codeOptions) { if (!isTsDocument(document)) return; @@ -160,10 +159,10 @@ export function create(ts: typeof import('typescript')): ServicePlugin { prepareSyntacticService(document); - return await doFormatting.onRange(document, range, options_2); + return await doFormatting.onRange(document, range, options, codeOptions); }, - async provideOnTypeFormattingEdits(document, position, key, options_2) { + async provideOnTypeFormattingEdits(document, position, key, options, codeOptions) { if (!isTsDocument(document)) return; @@ -175,43 +174,13 @@ export function create(ts: typeof import('typescript')): ServicePlugin { prepareSyntacticService(document); - return doFormatting.onType(document, options_2, position, key); - }, - - provideFormattingIndentSensitiveLines(document) { - - if (!isTsDocument(document)) - return; - - const ctx = prepareSyntacticService(document); - const sourceFile = ts.createSourceFile(ctx.fileName, document.getText(), ts.ScriptTarget.ESNext); - - if (sourceFile) { - - const lines: number[] = []; - - sourceFile.forEachChild(function walk(node) { - if ( - node.kind === ts.SyntaxKind.FirstTemplateToken - || node.kind === ts.SyntaxKind.LastTemplateToken - || node.kind === ts.SyntaxKind.TemplateHead - ) { - const startLine = document.positionAt(node.getStart(sourceFile)).line; - const endLine = document.positionAt(node.getEnd()).line; - for (let i = startLine + 1; i <= endLine; i++) { - lines.push(i); - } - } - node.forEachChild(walk); - }); - - return lines; - } + return doFormatting.onType(document, options, codeOptions, position, key); }, }; const syntacticHostCtx = { projectVersion: -1, document: undefined as TextDocument | undefined, + documentVersion: undefined as number | undefined, fileName: '', fileVersion: 0, snapshot: ts.ScriptSnapshot.fromString(''), @@ -681,10 +650,14 @@ export function create(ts: typeof import('typescript')): ServicePlugin { } function prepareSyntacticService(document: TextDocument) { - if (syntacticHostCtx.document !== document || syntacticHostCtx.fileVersion !== document.version) { + if (syntacticHostCtx.document !== document || syntacticHostCtx.documentVersion !== document.version) { syntacticHostCtx.document = document; - syntacticHostCtx.fileName = URI.parse(document.uri).fsPath.replace(/\\/g, '/'); - syntacticHostCtx.fileVersion = document.version; + syntacticHostCtx.fileName = '/tmp.' + + document.languageId === 'javascript' ? 'js' : + document.languageId === 'typescriptreact' ? 'tsx' : + document.languageId === 'javascriptreact' ? 'jsx' : + 'ts'; + syntacticHostCtx.fileVersion++; syntacticHostCtx.snapshot = ts.ScriptSnapshot.fromString(document.getText()); syntacticHostCtx.projectVersion++; } diff --git a/packages/typescript/lib/configs/getFormatCodeSettings.ts b/packages/typescript/lib/configs/getFormatCodeSettings.ts index cc13480a..eb26d9f3 100644 --- a/packages/typescript/lib/configs/getFormatCodeSettings.ts +++ b/packages/typescript/lib/configs/getFormatCodeSettings.ts @@ -9,16 +9,12 @@ export async function getFormatCodeSettings( document: TextDocument, options?: FormattingOptions, ): Promise { - - let config = await ctx.env.getConfiguration?.(getConfigTitle(document) + '.format'); - - config = config ?? {}; - + const config = await ctx.env.getConfiguration?.(getConfigTitle(document) + '.format') ?? {}; return { convertTabsToSpaces: options?.insertSpaces, tabSize: options?.tabSize, indentSize: options?.tabSize, - indentStyle: 2 /** ts.IndentStyle.Smart */, + indentStyle: 2 satisfies ts.IndentStyle.Smart, newLineCharacter: '\n', insertSpaceAfterCommaDelimiter: config.insertSpaceAfterCommaDelimiter ?? true, insertSpaceAfterConstructor: config.insertSpaceAfterConstructor ?? false, diff --git a/packages/typescript/lib/features/formatting.ts b/packages/typescript/lib/features/formatting.ts index a98767cf..eb4f0037 100644 --- a/packages/typescript/lib/features/formatting.ts +++ b/packages/typescript/lib/features/formatting.ts @@ -6,16 +6,22 @@ import type { SharedContext } from '../types'; export function register(ctx: SharedContext) { return { - onRange: async (document: TextDocument, range: vscode.Range | undefined, options: vscode.FormattingOptions): Promise => { + onRange: async (document: TextDocument, range: vscode.Range | undefined, options: vscode.FormattingOptions, codeOptions: vscode.EmbeddedCodeFormattingOptions | undefined): Promise => { const fileName = ctx.uriToFileName(document.uri); const tsOptions = await getFormatCodeSettings(ctx, document, options); - if (typeof (tsOptions.indentSize) === "boolean" || typeof (tsOptions.indentSize) === "string") { - tsOptions.indentSize = undefined; + + if (codeOptions) { + tsOptions.baseIndentSize = codeOptions.initialIndentLevel * options.tabSize; } const scriptEdits = range - ? safeCall(() => ctx.languageService.getFormattingEditsForRange(fileName, document.offsetAt(range.start), document.offsetAt(range.end), tsOptions)) + ? safeCall(() => ctx.languageService.getFormattingEditsForRange( + fileName, + document.offsetAt(range.start), + document.offsetAt(range.end), + tsOptions, + )) : safeCall(() => ctx.languageService.getFormattingEditsForDocument(fileName, tsOptions)); if (!scriptEdits) return []; @@ -33,10 +39,15 @@ export function register(ctx: SharedContext) { return result; }, - onType: async (document: TextDocument, options: vscode.FormattingOptions, position: vscode.Position, key: string): Promise => { + onType: async (document: TextDocument, options: vscode.FormattingOptions, codeOptions: vscode.EmbeddedCodeFormattingOptions | undefined, position: vscode.Position, key: string): Promise => { const fileName = ctx.uriToFileName(document.uri); const tsOptions = await getFormatCodeSettings(ctx, document, options); + + if (codeOptions) { + tsOptions.baseIndentSize = codeOptions.initialIndentLevel * options.tabSize; + } + const scriptEdits = safeCall(() => ctx.languageService.getFormattingEditsAfterKeystroke(fileName, document.offsetAt(position), key, tsOptions)); if (!scriptEdits) return []; diff --git a/packages/typescript/package.json b/packages/typescript/package.json index 699e81aa..04e48605 100644 --- a/packages/typescript/package.json +++ b/packages/typescript/package.json @@ -33,12 +33,11 @@ "semver": "^7.5.4", "typescript-auto-import-cache": "^0.3.1", "vscode-languageserver-textdocument": "^1.0.11", - "vscode-nls": "^5.2.0", - "vscode-uri": "^3.0.8" + "vscode-nls": "^5.2.0" }, "peerDependencies": { - "@volar/language-service": "~2.0.4", - "@volar/typescript": "~2.0.4" + "@volar/language-service": "~2.1.0", + "@volar/typescript": "~2.1.0" }, "peerDependenciesMeta": { "@volar/language-service": { diff --git a/packages/vetur/package.json b/packages/vetur/package.json index 2256382f..541857b8 100644 --- a/packages/vetur/package.json +++ b/packages/vetur/package.json @@ -28,7 +28,7 @@ "vscode-html-languageservice": "^5.1.0" }, "peerDependencies": { - "@volar/language-service": "~2.0.4" + "@volar/language-service": "~2.1.0" }, "peerDependenciesMeta": { "@volar/language-service": { diff --git a/packages/yaml/package.json b/packages/yaml/package.json index 0fba6177..cc88ce49 100644 --- a/packages/yaml/package.json +++ b/packages/yaml/package.json @@ -30,7 +30,7 @@ "vscode-languageserver-textdocument": "^1.0.11" }, "peerDependencies": { - "@volar/language-service": "~2.0.4" + "@volar/language-service": "~2.1.0" }, "peerDependenciesMeta": { "@volar/language-service": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 18f61b6e..cb12cecd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -35,6 +35,9 @@ importers: vscode-css-languageservice: specifier: ^6.2.10 version: 6.2.12 + vscode-languageserver-textdocument: + specifier: ^1.0.11 + version: 1.0.11 vscode-uri: specifier: ^3.0.8 version: 3.0.8 @@ -42,9 +45,6 @@ importers: '@types/node': specifier: latest version: 20.11.17 - vscode-languageserver-textdocument: - specifier: ^1.0.11 - version: 1.0.11 packages/emmet: dependencies: @@ -66,6 +66,9 @@ importers: vscode-html-languageservice: specifier: ^5.1.0 version: 5.1.2 + vscode-languageserver-textdocument: + specifier: ^1.0.11 + version: 1.0.11 vscode-uri: specifier: ^3.0.8 version: 3.0.8 @@ -73,9 +76,6 @@ importers: '@types/node': specifier: latest version: 20.11.17 - vscode-languageserver-textdocument: - specifier: ^1.0.11 - version: 1.0.11 packages/json: dependencies: @@ -238,9 +238,6 @@ importers: vscode-nls: specifier: ^5.2.0 version: 5.2.0 - vscode-uri: - specifier: ^3.0.8 - version: 3.0.8 devDependencies: '@types/path-browserify': specifier: latest