🐛 Fix (most) bugs in cache

This commit is contained in:
Robin van der Linde 2025-01-09 00:08:02 +01:00
parent 3fa4e39342
commit 3b0b58e44b
Signed by: Robin-van-der-Linde
GPG key ID: 53956B3252478F0D
2 changed files with 244 additions and 207 deletions

View file

@ -210,18 +210,26 @@ export const tagRenderingImplementationProvider =
const links: vscode.DefinitionLink[] = []; const links: vscode.DefinitionLink[] = [];
for (const reference of references) { for (const reference of references) {
console.log( console.log(
`Pushing link from ${document.fileName} to ${reference.reference?.to.uri?.fsPath} at ${reference.reference?.to.range?.start.line}.${reference.reference?.to.range?.start.character} to ${reference.reference?.to.range?.end.line}.${reference.reference?.to.range?.end.character}` `Pushing link from ${document.fileName} to ${reference.reference?.from.uri?.fsPath} at ${reference.reference?.to.range?.[0]?.line}:${reference.reference?.to.range?.[0]?.character}`,
reference
); );
// Check if we have a targetRange and targetUri // Check if we have a targetUri
if ( if (reference.reference?.from.uri) {
reference.reference?.to.range &&
reference.reference?.to.uri
) {
links.push({ links.push({
originSelectionRange: reference.reference?.from.range, originSelectionRange: new vscode.Range(
targetRange: reference.reference?.to.range, reference.reference?.to?.range?.[0]?.line ?? 0,
targetUri: reference.reference?.to.uri, reference.reference?.to?.range?.[0]?.character ?? 0,
reference.reference?.to?.range?.[1]?.line ?? 0,
reference.reference?.to?.range?.[1]?.character ?? 0
),
targetRange: new vscode.Range(
reference.reference?.from?.range?.[0]?.line ?? 0,
reference.reference?.from?.range?.[0]?.character ?? 0,
reference.reference?.from?.range?.[1]?.line ?? 0,
reference.reference?.from?.range?.[1]?.character ?? 0
),
targetUri: reference.reference?.from?.uri,
}); });
} else { } else {
console.error("Incomplete reference", reference); console.error("Incomplete reference", reference);

View file

@ -176,7 +176,7 @@ export class CacheWorker {
// Reference if it's a string // Reference if it's a string
if (typeof layer === "string") { if (typeof layer === "string") {
// It is a reference // It is a reference
console.log(`Reference found to ${layer} in ${filePath}`); console.log(`Reference found to layer ${layer} in ${filePath}`);
const fromStartEnd = getStartEnd(text, ["layers", layerIndex]); const fromStartEnd = getStartEnd(text, ["layers", layerIndex]);
const to = `layers.${layer}`; const to = `layers.${layer}`;
@ -193,7 +193,7 @@ export class CacheWorker {
from: { from: {
id: from, id: from,
uri: fromFile, uri: fromFile,
range: fromStartEnd, range: [fromStartEnd.start, fromStartEnd.end],
}, },
to: { to: {
id: to, id: to,
@ -207,7 +207,9 @@ export class CacheWorker {
else if (layer.builtin) { else if (layer.builtin) {
if (typeof layer.builtin === "string") { if (typeof layer.builtin === "string") {
// Single layer // Single layer
console.log(`Reference found to ${layer.builtin} in ${filePath}`); console.log(
`Reference found to builtin layer ${layer.builtin} in ${filePath}`
);
const fromStartEnd = getStartEnd(text, [ const fromStartEnd = getStartEnd(text, [
"layers", "layers",
@ -228,7 +230,7 @@ export class CacheWorker {
from: { from: {
id: from, id: from,
uri: fromFile, uri: fromFile,
range: fromStartEnd, range: [fromStartEnd.start, fromStartEnd.end],
}, },
to: { to: {
id: to, id: to,
@ -240,7 +242,9 @@ export class CacheWorker {
} else { } else {
// Multiple layers // Multiple layers
for (const builtinLayer of layer.builtin) { for (const builtinLayer of layer.builtin) {
console.log(`Reference found to ${builtinLayer} in ${filePath}`); console.log(
`Reference found to builtin layer ${builtinLayer} in ${filePath}`
);
const builtinLayerIndex = layer.builtin.indexOf(builtinLayer); const builtinLayerIndex = layer.builtin.indexOf(builtinLayer);
const fromStartEnd = getStartEnd(text, [ const fromStartEnd = getStartEnd(text, [
@ -263,7 +267,7 @@ export class CacheWorker {
from: { from: {
id: from, id: from,
uri: fromFile, uri: fromFile,
range: fromStartEnd, range: [fromStartEnd.start, fromStartEnd.end],
}, },
to: { to: {
id: to, id: to,
@ -279,7 +283,7 @@ export class CacheWorker {
else { else {
console.log(`Found inline layer ${layer.id} in ${filePath}`); console.log(`Found inline layer ${layer.id} in ${filePath}`);
const layerText = JSON.stringify(layer); const layerText = JSON.stringify(layer);
const from = `themes.${json.id}.layers.${layer.id}`; const from = `themes.${json.id}.layers.${layerIndex}`;
await this.saveLayerTextToCache(layerText, uri, from, true, text); await this.saveLayerTextToCache(layerText, uri, from, true, text);
} }
} }
@ -294,6 +298,10 @@ export class CacheWorker {
* @param uri The URI of the layer * @param uri The URI of the layer
*/ */
private async saveLayerToCache(uri: vscode.Uri) { private async saveLayerToCache(uri: vscode.Uri) {
if (uri.fsPath.endsWith("favourite.json")) {
return;
}
// Read the file // Read the file
const content = vscode.workspace.fs.readFile(uri); const content = vscode.workspace.fs.readFile(uri);
const text = new TextDecoder().decode(await content); const text = new TextDecoder().decode(await content);
@ -372,6 +380,16 @@ export class CacheWorker {
this.printCache(); this.printCache();
} }
/**
* Save tag renderings to cache
* TODO: references for tagRenderings can also be a label/group, which we don't support yet
*
* @param text Text representation of layer
* @param from The theme or layer where the layer is from, e.g. layers.bicycle_rental or themes.cyclofix.layers.0
* @param fromUri URI of the layer file
* @param referencesOnly Whether to only save references, or also the tagRenderings and filters. This is useful for inline layers, because their filters and tagRenderings can't be reused
* @param fullFileText The full text of the original theme file, used for calculating position
*/
private async saveTagRenderingsToCache( private async saveTagRenderingsToCache(
text: string, text: string,
from: string, from: string,
@ -382,6 +400,9 @@ export class CacheWorker {
const json = JSON.parse(text); const json = JSON.parse(text);
for (const tagRendering of json.tagRenderings) { for (const tagRendering of json.tagRenderings) {
const tagRenderingReferenceIndex =
json.tagRenderings.indexOf(tagRendering);
// Check if it is a string and not an object // Check if it is a string and not an object
if (typeof tagRendering === "string") { if (typeof tagRendering === "string") {
// It is a reference // It is a reference
@ -390,191 +411,192 @@ export class CacheWorker {
); );
// The range is dependent on whether we're dealing with a full file or not // The range is dependent on whether we're dealing with a full file or not
// const fromStartEnd = fullFileText const path = fullFileText
// ? getStartEnd(fullFileText, [ ? [
// ...from.split("."), from.split(".")[2],
// "", parseInt(from.split(".")[3]),
// filterReferenceIndex, "tagRenderings",
// ]) tagRenderingReferenceIndex,
// : getStartEnd(text, ["filter", filterReferenceIndex]); ]
: ["tagRenderings", tagRenderingReferenceIndex];
const fromStartEnd = fullFileText
? getStartEnd(fullFileText, path)
: getStartEnd(text, path);
const to = tagRendering.includes(".")
? `layers.${tagRendering.split(".")[0]}.tagRenderings.${
tagRendering.split(".")[1]
}`
: `layers.questions.tagRenderings.${tagRendering}`;
const toFileName = tagRendering.includes(".")
? `**/assets/layers/${tagRendering.split(".")[0]}/${
tagRendering.split(".")[0]
}.json`
: `**/assets/layers/questions/questions.json`;
const toFile = await vscode.workspace.findFiles(toFileName);
// The range depends on whether we're dealing with a full file or not // Read toFile and get the text
// const fromStartEnd = fullFileText const toContent = await vscode.workspace.fs.readFile(toFile[0]);
// ? getStartEnd(fullFileText, [ const toText = new TextDecoder().decode(toContent);
// ...from.split("."), const toJson = JSON.parse(toText);
// "tagRenderings", const trIndex = toJson.tagRenderings.findIndex(
// json.tagRenderings.indexOf(tagRendering), // eslint-disable-next-line @typescript-eslint/no-explicit-any
// ]) (tr: any) => tr.id === tagRendering.split(".")?.pop()
// : getStartEnd(text, [ );
// "tagRenderings", const toRange = getStartEnd(toText, ["tagRenderings", trIndex]);
// json.tagRenderings.indexOf(tagRendering),
// ]);
// const to = tagRendering.includes(".") this.cache.push({
// ? `layers.${tagRendering.split(".")[0]}.tagRenderings.${ id: tagRendering,
// tagRendering.split(".")[1] filePath: fromUri,
// }` jsonPath: ["tagRenderings"],
// : `layers.questions.tagRenderings.${tagRendering}`; type: "reference",
// const toFile = await vscode.workspace.findFiles( reference: {
// `**/assets/layers/${to.split("."[1])}/${to.split(".")[1]}.json` from: {
// ); id: from,
// // Read toFile and get the text uri: fromUri,
// const toContent = await vscode.workspace.fs.readFile(toFile[0]); range: [fromStartEnd.start, fromStartEnd.end],
// const toText = new TextDecoder().decode(toContent); },
// const toJson = JSON.parse(toText); to: {
// const trIndex = toJson.tagRenderings.findIndex( id: to,
// // eslint-disable-next-line @typescript-eslint/no-explicit-any uri: toFile[0],
// (tr: any) => tr.id === tagRendering.split(".")?.pop() range: [toRange.start, toRange.end],
// ); },
// const toRange = getStartEnd(toText, ["tagRenderings", trIndex]); type: "tagRendering",
},
});
} else if (typeof tagRendering === "object") {
// This is a tagRendering, or a reference to one, but with an override
if (tagRendering.builtin) {
// This is a reference to a built-in tagRendering (or multiple ones)
if (typeof tagRendering.builtin === "string") {
// Single tagRendering reference
console.log(
`Reference found to builtin tagRendering ${tagRendering.builtin} in ${from}`
);
// The range is dependent on whether we're dealing with a full file or not
const path = fullFileText
? [
from.split(".")[2],
parseInt(from.split(".")[3]),
"tagRenderings",
tagRenderingReferenceIndex,
"builtin",
]
: ["tagRenderings", tagRenderingReferenceIndex, "builtin"];
const fromStartEnd = fullFileText
? getStartEnd(fullFileText, path)
: getStartEnd(text, path);
const to = tagRendering.builtin.includes(".")
? `layers.${tagRendering.builtin.split(".")[0]}.tagRenderings.${
tagRendering.builtin.split(".")[1]
}`
: `layers.questions.tagRenderings.${tagRendering}`;
const toFileName = tagRendering.builtin.includes(".")
? `**/assets/layers/${tagRendering.builtin.split(".")[0]}/${
tagRendering.builtin.split(".")[0]
}.json`
: `**/assets/layers/questions/questions.json`;
const toFile = await vscode.workspace.findFiles(toFileName);
// this.cache.push({ // Read toFile and get the text
// id: tagRendering, const toContent = await vscode.workspace.fs.readFile(toFile[0]);
// filePath: fromUri, const toText = new TextDecoder().decode(toContent);
// jsonPath: ["tagRenderings"], const toJson = JSON.parse(toText);
// type: "reference", const trIndex = toJson.tagRenderings.findIndex(
// reference: { // eslint-disable-next-line @typescript-eslint/no-explicit-any
// from: { (tr: any) => tr.id === tagRendering.builtin.split(".")?.pop()
// id: from, );
// uri: fromUri, const toRange = getStartEnd(toText, ["tagRenderings", trIndex]);
// range: fromStartEnd,
// }, this.cache.push({
// to: { id: tagRendering.builtin,
// id: to, filePath: fromUri,
// uri: toFile[0], jsonPath: ["tagRenderings"],
// range: toRange, type: "reference",
// }, reference: {
// type: "tagRendering", from: {
// }, id: from,
// }); uri: fromUri,
range: [fromStartEnd.start, fromStartEnd.end],
},
to: {
id: to,
uri: toFile[0],
range: [toRange.start, toRange.end],
},
type: "tagRendering",
},
});
} else {
// Multiple tagRenderings
for (const builtinTagRendering of tagRendering.builtin) {
console.log(
`Reference found to builtin tagRendering ${builtinTagRendering} in ${from}`
);
// The range depends on whether we're dealing with a full file or not
const fromStartEnd = fullFileText
? getStartEnd(fullFileText, [
...from.split("."),
"tagRenderings",
json.tagRenderings.indexOf(tagRendering),
])
: getStartEnd(text, [
"tagRenderings",
json.tagRenderings.indexOf(tagRendering),
]);
const to = builtinTagRendering.includes(".")
? `layers.${builtinTagRendering.split(".")[0]}.tagRenderings.${
builtinTagRendering.split(".")[1]
}`
: `layers.questions.tagRenderings.${builtinTagRendering}`;
const toFileName = builtinTagRendering.includes(".")
? `**/assets/layers/${builtinTagRendering.split(".")[0]}/${
builtinTagRendering.split(".")[0]
}.json`
: `**/assets/layers/questions/questions.json`;
const toFile = await vscode.workspace.findFiles(toFileName);
// Read toFile and get the text
const toContent = await vscode.workspace.fs.readFile(toFile[0]);
const toText = new TextDecoder().decode(toContent);
const toJson = JSON.parse(toText);
const trIndex = toJson.tagRenderings.findIndex(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(tr: any) => tr.id === builtinTagRendering.split(".")?.pop()
);
const toRange = getStartEnd(toText, ["tagRenderings", trIndex]);
this.cache.push({
id: builtinTagRendering,
filePath: fromUri,
jsonPath: ["tagRenderings"],
type: "reference",
reference: {
from: {
id: from,
uri: fromUri,
range: [fromStartEnd.start, fromStartEnd.end],
},
to: {
id: to,
uri: toFile[0],
range: [toRange.start, toRange.end],
},
type: "tagRendering",
},
});
}
}
} else if (!referencesOnly) {
// We've now had all possible references, so now we must have an acutal tagRendering
console.log(`TagRendering found in ${from}`);
this.cache.push({
id: `${json.id}.${tagRendering.id}`,
filePath: fromUri,
jsonPath: ["tagRenderings"],
type: "tagRendering",
});
}
} }
// } else if (typeof tagRendering === "object") {
// // This is a tagRendering, or a reference to one
// if (tagRendering.builtin) {
// // This is a reference to a built-in tagRendering (or multiple ones)
// if (typeof tagRendering.builtin === "string") {
// // Single tagRendering
// console.log(
// `Reference found to ${tagRendering.builtin} in ${from}`
// );
// // The range depends on whether we're dealing with a full file or not
// const fromStartEnd = fullFileText
// ? getStartEnd(fullFileText, [
// ...from.split("."),
// "tagRenderings",
// json.tagRenderings.indexOf(tagRendering),
// ])
// : getStartEnd(text, [
// "tagRenderings",
// json.tagRenderings.indexOf(tagRendering),
// ]);
// const to = tagRendering.builtin.includes(".")
// ? `layers.${tagRendering.builtin.split(".")[0]}.tagRenderings.${
// tagRendering.builtin.split(".")[1]
// }`
// : `layers.questions.tagRenderings.${tagRendering.builtin}`;
// const toFile = await vscode.workspace.findFiles(
// `**/assets/layers/${to.split("."[1])}/${to.split(".")[1]}.json`
// );
// // Read toFile and get the text
// const toContent = await vscode.workspace.fs.readFile(toFile[0]);
// const toText = new TextDecoder().decode(toContent);
// const toJson = JSON.parse(toText);
// const trIndex = toJson.tagRenderings.findIndex(
// // eslint-disable-next-line @typescript-eslint/no-explicit-any
// (tr: any) => tr.id === tagRendering.builtin.split(".")?.pop()
// );
// const toRange = getStartEnd(toText, ["tagRenderings", trIndex]);
// this.cache.push({
// id: tagRendering.builtin,
// filePath: fromUri,
// jsonPath: ["tagRenderings"],
// type: "reference",
// reference: {
// from: {
// id: from,
// uri: fromUri,
// range: fromStartEnd,
// },
// to: {
// id: to,
// uri: toFile[0],
// range: toRange,
// },
// type: "tagRendering",
// },
// });
// } else {
// // Multiple tagRenderings
// for (const builtinTagRendering of tagRendering.builtin) {
// console.log(
// `Reference found to ${builtinTagRendering} in ${from}`
// );
// // The range depends on whether we're dealing with a full file or not
// const fromStartEnd = fullFileText
// ? getStartEnd(fullFileText, [
// ...from.split("."),
// "tagRenderings",
// json.tagRenderings.indexOf(tagRendering),
// ])
// : getStartEnd(text, [
// "tagRenderings",
// json.tagRenderings.indexOf(tagRendering),
// ]);
// const to = builtinTagRendering.includes(".")
// ? `layers.${builtinTagRendering.split(".")[0]}.tagRenderings.${
// builtinTagRendering.split(".")[1]
// }`
// : `layers.questions.tagRenderings.${builtinTagRendering}`;
// const toFile = await vscode.workspace.findFiles(
// `**/assets/layers/${to.split("."[1])}/${to.split(".")[1]}.json`
// );
// // Read toFile and get the text
// const toContent = await vscode.workspace.fs.readFile(toFile[0]);
// const toText = new TextDecoder().decode(toContent);
// const toJson = JSON.parse(toText);
// const trIndex = toJson.tagRenderings.findIndex(
// // eslint-disable-next-line @typescript-eslint/no-explicit-any
// (tr: any) => tr.id === builtinTagRendering.split(".")?.pop()
// );
// const toRange = getStartEnd(toText, ["tagRenderings", trIndex]);
// this.cache.push({
// id: builtinTagRendering,
// filePath: fromUri,
// jsonPath: ["tagRenderings"],
// type: "reference",
// reference: {
// from: {
// id: from,
// uri: fromUri,
// range: fromStartEnd,
// },
// to: {
// id: to,
// uri: toFile[0],
// range: toRange,
// },
// type: "tagRendering",
// },
// });
// }
// }
// } else if (!referencesOnly) {
// // This is a tagRendering, which can be reused
// console.log(`TagRendering found in ${from}`);
// this.cache.push({
// id: `${json.id}.${tagRendering.id}`,
// filePath: fromUri,
// jsonPath: ["tagRenderings"],
// type: "tagRendering",
// });
// }
} }
} }
@ -605,14 +627,17 @@ export class CacheWorker {
console.log(`Reference found to filter ${filter} in ${from}`); console.log(`Reference found to filter ${filter} in ${from}`);
// The range is dependent on whether we're dealing with a full file or not // The range is dependent on whether we're dealing with a full file or not
const fromStartEnd = fullFileText const path = fullFileText
? getStartEnd(fullFileText, [ ? [
...from.split("."), from.split(".")[2],
parseInt(from.split(".")[3]),
"filter", "filter",
filterReferenceIndex, filterReferenceIndex,
]) ]
: getStartEnd(text, ["filter", filterReferenceIndex]); : ["filter", filterReferenceIndex];
const fromStartEnd = fullFileText
? getStartEnd(fullFileText, path)
: getStartEnd(text, path);
const filterId = filter.includes(".") ? filter.split(".")[1] : filter; const filterId = filter.includes(".") ? filter.split(".")[1] : filter;
const to = filter.includes(".") const to = filter.includes(".")
? `layers.${filter.split(".")[0]}` ? `layers.${filter.split(".")[0]}`
@ -624,7 +649,6 @@ export class CacheWorker {
}.json` }.json`
: `**/assets/layers/filters/filters.json`; : `**/assets/layers/filters/filters.json`;
const toFile = await vscode.workspace.findFiles(toFileName); const toFile = await vscode.workspace.findFiles(toFileName);
const toContent = await vscode.workspace.fs.readFile(toFile[0]); const toContent = await vscode.workspace.fs.readFile(toFile[0]);
const toText = new TextDecoder().decode(toContent); const toText = new TextDecoder().decode(toContent);
const toJson = JSON.parse(toText); const toJson = JSON.parse(toText);
@ -648,12 +672,12 @@ export class CacheWorker {
from: { from: {
id: from, id: from,
uri: fromUri, uri: fromUri,
range: fromStartEnd, range: [fromStartEnd.start, fromStartEnd.end],
}, },
to: { to: {
id: to, id: to,
uri: toFile[0], uri: toFile[0],
range: toRange, range: [toRange.start, toRange.end],
}, },
type: "filter", type: "filter",
}, },
@ -857,5 +881,10 @@ interface ReferenceDetail {
* *
* Only defined when referencing to a part of a file * Only defined when referencing to a part of a file
*/ */
range?: vscode.Range; range?: [ReferencePosition, ReferencePosition];
}
interface ReferencePosition {
character: number;
line: number;
} }