This commit is contained in:
226
node_modules/@volar/language-service/lib/features/provideDocumentFormattingEdits.js
generated
vendored
Normal file
226
node_modules/@volar/language-service/lib/features/provideDocumentFormattingEdits.js
generated
vendored
Normal file
@@ -0,0 +1,226 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.register = register;
|
||||
const language_core_1 = require("@volar/language-core");
|
||||
const vscode_languageserver_textdocument_1 = require("vscode-languageserver-textdocument");
|
||||
const vscode_uri_1 = require("vscode-uri");
|
||||
const cancellation_1 = require("../utils/cancellation");
|
||||
const common_1 = require("../utils/common");
|
||||
const featureWorkers_1 = require("../utils/featureWorkers");
|
||||
function register(context) {
|
||||
return async (uri, options, range, onTypeParams, token = cancellation_1.NoneCancellationToken) => {
|
||||
const sourceScript = context.language.scripts.get(uri);
|
||||
if (!sourceScript) {
|
||||
return;
|
||||
}
|
||||
let document = context.documents.get(uri, sourceScript.languageId, sourceScript.snapshot);
|
||||
range ??= {
|
||||
start: document.positionAt(0),
|
||||
end: document.positionAt(document.getText().length),
|
||||
};
|
||||
if (!sourceScript.generated) {
|
||||
return onTypeParams
|
||||
? (await tryFormat(document, document, sourceScript, undefined, 0, onTypeParams.position, onTypeParams.ch))?.edits
|
||||
: (await tryFormat(document, document, sourceScript, undefined, 0, range, undefined))?.edits;
|
||||
}
|
||||
const embeddedRanges = new Map(); // TODO: Formatting of upper-level virtual code may cause offset of lower-level selection range
|
||||
const startOffset = document.offsetAt(range.start);
|
||||
const endOffset = document.offsetAt(range.end);
|
||||
for (const code of (0, language_core_1.forEachEmbeddedCode)(sourceScript.generated.root)) {
|
||||
const map = context.language.maps.get(code, sourceScript);
|
||||
if (map) {
|
||||
const embeddedRange = (0, common_1.findOverlapCodeRange)(startOffset, endOffset, map, language_core_1.isFormattingEnabled);
|
||||
if (embeddedRange) {
|
||||
if (embeddedRange.start === map.mappings[0].generatedOffsets[0]) {
|
||||
embeddedRange.start = 0;
|
||||
}
|
||||
const lastMapping = map.mappings[map.mappings.length - 1];
|
||||
if (embeddedRange.end === lastMapping.generatedOffsets[lastMapping.generatedOffsets.length - 1] + (lastMapping.generatedLengths ?? lastMapping.lengths)[lastMapping.lengths.length - 1]) {
|
||||
embeddedRange.end = code.snapshot.getLength();
|
||||
}
|
||||
embeddedRanges.set(code.id, embeddedRange);
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
const originalDocument = document;
|
||||
let tempSourceSnapshot = sourceScript.snapshot;
|
||||
let tempVirtualFile = context.language.scripts.set(vscode_uri_1.URI.parse(sourceScript.id.toString() + '.tmp'), sourceScript.snapshot, sourceScript.languageId, [sourceScript.generated.languagePlugin])?.generated?.root;
|
||||
if (!tempVirtualFile) {
|
||||
return;
|
||||
}
|
||||
let currentCodes = [];
|
||||
for (let depth = 0; (currentCodes = getNestedEmbeddedFiles(context, sourceScript.id, tempVirtualFile, depth)).length > 0; depth++) {
|
||||
let edits = [];
|
||||
for (const code of currentCodes) {
|
||||
if (!code.mappings.some(mapping => (0, language_core_1.isFormattingEnabled)(mapping.data))) {
|
||||
continue;
|
||||
}
|
||||
const currentRange = embeddedRanges.get(code.id);
|
||||
if (!currentRange) {
|
||||
continue;
|
||||
}
|
||||
const isChildRange = [...(0, language_core_1.forEachEmbeddedCode)(code)].some(child => {
|
||||
if (child === code) {
|
||||
return false;
|
||||
}
|
||||
const childRange = embeddedRanges.get(child.id);
|
||||
return childRange && childRange.end - childRange.start >= currentRange.end - currentRange.start;
|
||||
});
|
||||
if (isChildRange) {
|
||||
continue;
|
||||
}
|
||||
const docs = [
|
||||
context.documents.get(uri, sourceScript.languageId, tempSourceSnapshot),
|
||||
context.documents.get(context.encodeEmbeddedDocumentUri(uri, code.id), code.languageId, code.snapshot),
|
||||
context.language.mapperFactory(code.mappings),
|
||||
];
|
||||
let embeddedResult;
|
||||
if (onTypeParams) {
|
||||
for (const embeddedPosition of (0, featureWorkers_1.getGeneratedPositions)(docs, onTypeParams.position)) {
|
||||
embeddedResult = await tryFormat(docs[0], docs[1], sourceScript, code, depth, embeddedPosition, onTypeParams.ch);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (currentRange) {
|
||||
embeddedResult = await tryFormat(docs[0], docs[1], sourceScript, code, depth, {
|
||||
start: docs[1].positionAt(currentRange.start),
|
||||
end: docs[1].positionAt(currentRange.end),
|
||||
});
|
||||
}
|
||||
if (!embeddedResult) {
|
||||
continue;
|
||||
}
|
||||
for (const textEdit of embeddedResult.edits) {
|
||||
const range = (0, featureWorkers_1.getSourceRange)(docs, textEdit.range);
|
||||
if (range) {
|
||||
edits.push({
|
||||
newText: textEdit.newText,
|
||||
range,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
if (edits.length > 0) {
|
||||
const newText = vscode_languageserver_textdocument_1.TextDocument.applyEdits(document, edits);
|
||||
document = vscode_languageserver_textdocument_1.TextDocument.create(document.uri, document.languageId, document.version + 1, newText);
|
||||
tempSourceSnapshot = (0, common_1.stringToSnapshot)(newText);
|
||||
tempVirtualFile = context.language.scripts.set(vscode_uri_1.URI.parse(sourceScript.id.toString() + '.tmp'), tempSourceSnapshot, sourceScript.languageId, [sourceScript.generated.languagePlugin])?.generated?.root;
|
||||
if (!tempVirtualFile) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (document.getText() === originalDocument.getText()) {
|
||||
return;
|
||||
}
|
||||
const editRange = {
|
||||
start: originalDocument.positionAt(0),
|
||||
end: originalDocument.positionAt(originalDocument.getText().length),
|
||||
};
|
||||
const textEdit = {
|
||||
range: editRange,
|
||||
newText: document.getText(),
|
||||
};
|
||||
return [textEdit];
|
||||
}
|
||||
finally {
|
||||
context.language.scripts.delete(vscode_uri_1.URI.parse(sourceScript.id.toString() + '.tmp'));
|
||||
}
|
||||
async function tryFormat(sourceDocument, document, sourceScript, virtualCode, embeddedLevel, rangeOrPosition, ch) {
|
||||
if (context.disabledEmbeddedDocumentUris.get(vscode_uri_1.URI.parse(document.uri))) {
|
||||
return;
|
||||
}
|
||||
let codeOptions;
|
||||
rangeOrPosition ??= {
|
||||
start: document.positionAt(0),
|
||||
end: document.positionAt(document.getText().length),
|
||||
};
|
||||
if (virtualCode) {
|
||||
codeOptions = {
|
||||
level: embeddedLevel,
|
||||
initialIndentLevel: 0,
|
||||
};
|
||||
if (virtualCode.mappings.length) {
|
||||
const firstMapping = virtualCode.mappings[0];
|
||||
const startOffset = firstMapping.sourceOffsets[0];
|
||||
const startPosition = sourceDocument.positionAt(startOffset);
|
||||
codeOptions.initialIndentLevel = computeInitialIndent(sourceDocument.getText(), sourceDocument.offsetAt({ line: startPosition.line, character: 0 }), options);
|
||||
}
|
||||
for (const plugin of context.plugins) {
|
||||
if (context.disabledServicePlugins.has(plugin[1])) {
|
||||
continue;
|
||||
}
|
||||
codeOptions = await plugin[1].resolveEmbeddedCodeFormattingOptions?.(sourceScript, virtualCode, codeOptions, token) ?? codeOptions;
|
||||
}
|
||||
}
|
||||
for (const plugin of context.plugins) {
|
||||
if (context.disabledServicePlugins.has(plugin[1])) {
|
||||
continue;
|
||||
}
|
||||
if (token.isCancellationRequested) {
|
||||
break;
|
||||
}
|
||||
let edits;
|
||||
try {
|
||||
if (ch !== undefined && rangeOrPosition && 'line' in rangeOrPosition && 'character' in rangeOrPosition) {
|
||||
if (plugin[0].capabilities.documentOnTypeFormattingProvider?.triggerCharacters?.includes(ch)) {
|
||||
edits = await plugin[1].provideOnTypeFormattingEdits?.(document, rangeOrPosition, ch, options, codeOptions, token);
|
||||
}
|
||||
}
|
||||
else if (ch === undefined && rangeOrPosition && 'start' in rangeOrPosition && 'end' in rangeOrPosition) {
|
||||
edits = await plugin[1].provideDocumentFormattingEdits?.(document, rangeOrPosition, options, codeOptions, token);
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
console.warn(err);
|
||||
}
|
||||
if (!edits) {
|
||||
continue;
|
||||
}
|
||||
return {
|
||||
plugin,
|
||||
edits,
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
function getNestedEmbeddedFiles(context, uri, rootCode, depth) {
|
||||
const nestedCodesByLevel = [[rootCode]];
|
||||
while (true) {
|
||||
if (nestedCodesByLevel.length > depth) {
|
||||
return nestedCodesByLevel[depth];
|
||||
}
|
||||
const nestedCodes = [];
|
||||
for (const code of nestedCodesByLevel[nestedCodesByLevel.length - 1]) {
|
||||
if (code.embeddedCodes) {
|
||||
for (const embedded of code.embeddedCodes) {
|
||||
if (!context.disabledEmbeddedDocumentUris.get(context.encodeEmbeddedDocumentUri(uri, embedded.id))) {
|
||||
nestedCodes.push(embedded);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
nestedCodesByLevel.push(nestedCodes);
|
||||
}
|
||||
}
|
||||
function computeInitialIndent(content, i, options) {
|
||||
let nChars = 0;
|
||||
const tabSize = options.tabSize || 4;
|
||||
while (i < content.length) {
|
||||
const ch = content.charAt(i);
|
||||
if (ch === ' ') {
|
||||
nChars++;
|
||||
}
|
||||
else if (ch === '\t') {
|
||||
nChars += tabSize;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return Math.floor(nChars / tabSize);
|
||||
}
|
||||
//# sourceMappingURL=provideDocumentFormattingEdits.js.map
|
||||
Reference in New Issue
Block a user