Skip to content

Commit

Permalink
feat(css, html, typescript): consume initialIndentLevel in embedded…
Browse files Browse the repository at this point in the history
… code formatting (#75)
  • Loading branch information
johnsoncodehk committed Feb 26, 2024
1 parent 975e317 commit 7729de6
Show file tree
Hide file tree
Showing 29 changed files with 240 additions and 146 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
Expand Down
99 changes: 92 additions & 7 deletions packages/css/index.ts
Original file line number Diff line number Diff line change
@@ -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 {
Expand Down Expand Up @@ -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?.<css.CSSFormatConfiguration & { enable: boolean; }>(document.languageId + '.format');
if (options_2?.enable === false) {
const formatSettings = await context.env.getConfiguration?.<css.CSSFormatConfiguration & { enable: boolean; }>(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');
}
});
},
};
Expand Down
6 changes: 3 additions & 3 deletions packages/css/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": {
Expand Down
2 changes: 1 addition & 1 deletion packages/emmet/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": {
Expand Down
129 changes: 81 additions & 48 deletions packages/html/index.ts
Original file line number Diff line number Diff line change
@@ -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();
Expand Down Expand Up @@ -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.HTMLFormatConfiguration & { enable?: boolean; }>('html.format') ?? {};
Expand Down Expand Up @@ -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('<template>');
suffixes.unshift('</template>');
}
else {
prefixes.push('<template>\n');
suffixes.unshift('\n</template>');
}
}
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, '<template>' + newText + '</template>');
const verifyEdits = htmlLs.format(verifyDocument, undefined, formatOptions);
let verifyText = TextDocument.applyEdits(verifyDocument, verifyEdits);
verifyText = verifyText.trim().slice('<template>'.length, -'</template>'.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');
}
});
},

Expand Down
6 changes: 3 additions & 3 deletions packages/html/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": {
Expand Down
2 changes: 1 addition & 1 deletion packages/json/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": {
Expand Down
2 changes: 1 addition & 1 deletion packages/markdown/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": {
Expand Down
2 changes: 1 addition & 1 deletion packages/prettier/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": {
Expand Down
2 changes: 1 addition & 1 deletion packages/pretty-ts-errors/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": {
Expand Down
2 changes: 1 addition & 1 deletion packages/prettyhtml/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": {
Expand Down
2 changes: 1 addition & 1 deletion packages/pug-beautify/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": {
Expand Down
Loading

0 comments on commit 7729de6

Please sign in to comment.