astro-ghostcms/.pnpm-store/v3/files/78/ddfd9503f01728337a5408a98e5...

241 lines
9.9 KiB
Plaintext

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.register = exports.errorMarkups = exports.updateRange = void 0;
const language_core_1 = require("@volar/language-core");
const cancellation_1 = require("../utils/cancellation");
const common_1 = require("../utils/common");
const dedupe = require("../utils/dedupe");
const featureWorkers_1 = require("../utils/featureWorkers");
function updateRange(range, change) {
if (!updatePosition(range.start, change, false)) {
return;
}
if (!updatePosition(range.end, change, true)) {
return;
}
if (range.end.line === range.start.line && range.end.character <= range.start.character) {
range.end.character++;
}
return range;
}
exports.updateRange = updateRange;
function updatePosition(position, change, isEnd) {
if (change.range.end.line > position.line) {
if (change.newEnd.line > position.line) {
// No change
return true;
}
else if (change.newEnd.line === position.line) {
position.character = Math.min(position.character, change.newEnd.character);
return true;
}
else if (change.newEnd.line < position.line) {
position.line = change.newEnd.line;
position.character = change.newEnd.character;
return true;
}
}
else if (change.range.end.line === position.line) {
const characterDiff = change.newEnd.character - change.range.end.character;
if (position.character >= change.range.end.character) {
if (change.newEnd.line !== change.range.end.line) {
position.line = change.newEnd.line;
position.character = change.newEnd.character + position.character - change.range.end.character;
}
else {
if (isEnd ? change.range.end.character < position.character : change.range.end.character <= position.character) {
position.character += characterDiff;
}
else {
const offset = change.range.end.character - position.character;
if (-characterDiff > offset) {
position.character += characterDiff + offset;
}
}
}
return true;
}
else {
if (change.newEnd.line === change.range.end.line) {
const offset = change.range.end.character - position.character;
if (-characterDiff > offset) {
position.character += characterDiff + offset;
}
}
else if (change.newEnd.line < change.range.end.line) {
position.line = change.newEnd.line;
position.character = change.newEnd.character;
}
else {
// No change
}
return true;
}
}
else if (change.range.end.line < position.line) {
position.line += change.newEnd.line - change.range.end.line;
return true;
}
return false;
}
exports.errorMarkups = {};
function register(context) {
const lastResponses = new Map();
const cacheMaps = {
semantic: new Map(),
syntactic: new Map(),
};
context.env.onDidChangeConfiguration?.(() => {
lastResponses.clear();
cacheMaps.semantic.clear();
cacheMaps.syntactic.clear();
});
return async (uri, token = cancellation_1.NoneCancellationToken, response) => {
const sourceFile = context.language.files.get(uri);
if (!sourceFile) {
return [];
}
const document = context.documents.get(uri, sourceFile.languageId, sourceFile.snapshot);
const lastResponse = lastResponses.get(uri) ?? lastResponses.set(uri, {
semantic: { errors: [] },
syntactic: { errors: [] },
}).get(uri);
let updateCacheRangeFailed = false;
let errorsUpdated = false;
let lastCheckCancelAt = 0;
for (const cache of Object.values(lastResponse)) {
const oldSnapshot = cache.snapshot;
const oldDocument = cache.document;
const change = oldSnapshot ? sourceFile.snapshot.getChangeRange(oldSnapshot) : undefined;
cache.snapshot = sourceFile.snapshot;
cache.document = document;
if (!updateCacheRangeFailed && oldDocument && change) {
const changeRange = {
range: {
start: oldDocument.positionAt(change.span.start),
end: oldDocument.positionAt(change.span.start + change.span.length),
},
newEnd: document.positionAt(change.span.start + change.newLength),
};
for (const error of cache.errors) {
if (!updateRange(error.range, changeRange)) {
updateCacheRangeFailed = true;
break;
}
}
}
}
await worker('provideDiagnostics', cacheMaps.syntactic, lastResponse.syntactic);
await doResponse();
await worker('provideSemanticDiagnostics', cacheMaps.semantic, lastResponse.semantic);
return await collectErrors();
async function doResponse() {
if (errorsUpdated && !updateCacheRangeFailed) {
response?.(await collectErrors());
errorsUpdated = false;
}
}
async function collectErrors() {
const errors = Object.values(lastResponse).flatMap(({ errors }) => errors);
exports.errorMarkups[uri] = [];
for (const error of errors) {
for (const service of context.services) {
if (context.disabledServicePlugins.has(service[1])) {
continue;
}
const markup = await service[1].provideDiagnosticMarkupContent?.(error, token);
if (markup) {
exports.errorMarkups[uri].push({ error, markup });
}
}
}
return errors;
}
async function worker(api, cacheMap, cache) {
const result = await (0, featureWorkers_1.documentFeatureWorker)(context, uri, map => map.map.mappings.some(mapping => (0, language_core_1.isDiagnosticsEnabled)(mapping.data)), async (service, document) => {
if (token) {
if (Date.now() - lastCheckCancelAt >= 5) {
await (0, common_1.sleep)(5); // waiting LSP event polling
lastCheckCancelAt = Date.now();
}
if (token.isCancellationRequested) {
return;
}
}
const serviceIndex = context.services.indexOf(service);
const serviceCache = cacheMap.get(serviceIndex) ?? cacheMap.set(serviceIndex, new Map()).get(serviceIndex);
const cache = serviceCache.get(document.uri);
if (api !== 'provideSemanticDiagnostics' && cache && cache.documentVersion === document.version) {
return cache.errors;
}
const errors = await service[1][api]?.(document, token);
errors?.forEach(error => {
error.data = {
uri,
version: document.version,
serviceIndex,
isFormat: false,
original: {
data: error.data,
},
documentUri: document.uri,
};
});
errorsUpdated = true;
serviceCache.set(document.uri, {
documentVersion: document.version,
errors,
});
return errors;
}, (errors, map) => {
return transformErrorRangeBase(errors, map, language_core_1.shouldReportDiagnostics);
}, arr => dedupe.withDiagnostics(arr.flat()));
if (result) {
cache.errors = result;
cache.snapshot = sourceFile?.snapshot;
}
}
};
function transformErrorRangeBase(errors, map, filter) {
const result = [];
for (const error of errors) {
// clone it to avoid modify cache
let _error = { ...error };
if (map) {
const range = map.getSourceRange(error.range, filter);
if (!range) {
continue;
}
_error.range = range;
}
if (_error.relatedInformation) {
const relatedInfos = [];
for (const info of _error.relatedInformation) {
const [virtualCode] = context.documents.getVirtualCodeByUri(info.location.uri);
if (virtualCode) {
for (const map of context.documents.getMaps(virtualCode)) {
const range = map.getSourceRange(info.location.range, filter);
if (range) {
relatedInfos.push({
location: {
uri: map.sourceFileDocument.uri,
range,
},
message: info.message,
});
}
}
}
else {
relatedInfos.push(info);
}
}
_error.relatedInformation = relatedInfos;
}
result.push(_error);
}
return result;
}
}
exports.register = register;
//# sourceMappingURL=provideDiagnostics.js.map