🚧 First kind of working version for tagRenderingImplementationProvider

This commit is contained in:
Robin van der Linde 2025-01-08 00:46:51 +01:00
parent b7ebfee84d
commit 4d1ea863df
Signed by: Robin-van-der-Linde
GPG key ID: 53956B3252478F0D
3 changed files with 165 additions and 3 deletions

View file

@ -6,6 +6,7 @@ import {
filterDefinitionProvider,
tagRenderingCompletionProvider,
tagRenderingDefinitionProvider,
tagRenderingImplementationProvider,
} from "./layers";
import { pathDefinitionProvider } from "./license_info";
import { CacheWorker } from "./utils/cache";
@ -19,7 +20,8 @@ export async function activate(context: vscode.ExtensionContext) {
tagRenderingCompletionProvider,
tagRenderingDefinitionProvider,
filterCompletionProvider,
filterDefinitionProvider
filterDefinitionProvider,
tagRenderingImplementationProvider
);
// Activate all license info related features

View file

@ -13,6 +13,7 @@ import { getCursorPath, getRawCursorPath, getStartEnd } from "./utils/cursor";
import { getFilters, getTagRenderings } from "./utils/mapcomplete";
import { getValueFromPath } from "./utils/json";
import { JSONPath } from "jsonc-parser";
import { Cache } from "./utils/cache";
/**
* Tag rendering completion provider
@ -172,6 +173,151 @@ export const tagRenderingDefinitionProvider =
}
);
export const tagRenderingImplementationProvider =
vscode.languages.registerImplementationProvider(
{
language: "json",
scheme: "file",
pattern: "**/assets/*/*/*.json",
},
{
async provideImplementation(
document: vscode.TextDocument,
position: vscode.Position,
_token: vscode.CancellationToken
) {
console.log("tagRenderingImplementationProvider");
const text = document.getText();
const jsonPath = getCursorPath(text, position);
const rawJsonPath = getRawCursorPath(text, position);
const regex = /^tagRenderings(\+)?\.\d+\.id$/;
if (regex.exec(jsonPath)) {
const tagRenderingId = getValueFromPath(text, rawJsonPath);
const layerName = document.fileName.split("/").pop()?.split(".")[0];
const to = `layers.${layerName}.tagRenderings.${tagRenderingId}`;
try {
const cache = await Cache.create();
const references = cache.getReferences(to);
if (references.length === 0) {
return null;
} else {
// TODO: This is way too much to be executing at this time, most of this should be cached
// TODO: Also, this seems to fail for the first time, but work for every subsequent time
console.log(`Found ${references.length} references to ${to}`);
const links: vscode.DefinitionLink[] = [];
for (const reference of references) {
const originType = reference.reference?.from.split(".")[0];
const originName = reference.reference?.from.split(".")[1];
// We need to open the file where the reference is located
const originFile = await vscode.workspace.findFiles(
`assets/${originType}/${originName}/${originName}.json`
);
if (originFile.length === 0) {
continue;
}
const originText = await vscode.workspace.fs.readFile(
originFile[0]
);
const originTextString = new TextDecoder().decode(originText);
const origin = JSON.parse(originTextString);
let tagRenderings: unknown[] = [];
let tagRenderingsPath: JSONPath = [];
// Now we'll need to find the tagRenderings object, and its path
if (originType === "themes") {
const parts = reference.reference?.from.split(".");
if (!parts) {
continue;
} else {
console.log("Parts", parts);
// Now we need to find the correct inline layer
const layerIndex = origin.layers.findIndex(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(layer: any) => layer.id === parts[3]
);
const path: JSONPath = [
parts[2],
layerIndex,
...reference.jsonPath,
];
console.log("Trying to get tagRenderings from theme", path);
const tagRenderingsFromOrigin = getValueFromPath(
originTextString,
path
);
if (!tagRenderingsFromOrigin) {
console.error(
"Could not find tagRenderings in theme",
originName
);
continue;
} else {
// Yaay, we found the tagRenderings
console.log("Found tagRenderings in theme", originName);
tagRenderings = tagRenderingsFromOrigin as unknown[];
tagRenderingsPath = path;
}
}
} else if (originType === "layers") {
tagRenderings = origin.tagRenderings;
tagRenderingsPath = ["tagRenderings"];
}
// The index is actually a really complicated, because a reference could be a string or an object with a builtin property, which can be a string or a list of strings
// Also if the reference is from an inline layer
const tagRenderingIndex = tagRenderings.findIndex(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(tr: any) => {
if (typeof tr === "string") {
return tr === reference.id;
} else if (typeof tr.builtin === "string") {
return tr.builtin === reference.id;
}
// } else if (tr.builtin) {
// return tr.builtin.includes(reference.id);
// }
}
);
const path: JSONPath = [
...tagRenderingsPath,
tagRenderingIndex,
];
const startEnd = getStartEnd(originTextString, path);
console.log(
`Pushing link from ${document.fileName} to ${originFile[0].path} at ${startEnd.start.line}.${startEnd.start.character} to ${startEnd.end.line}.${startEnd.end.character}`
);
links.push({
originSelectionRange: getStartEnd(text, rawJsonPath),
targetRange: startEnd,
targetUri: originFile[0],
});
}
console.log(`Found ${links.length} implementations`);
return links;
}
} catch (error) {
console.error("Error get implementation", error);
}
}
return null;
},
}
);
/**
* Filter completion provider
*

View file

@ -280,7 +280,7 @@ export class CacheWorker {
const json = JSON.parse(text);
// Check if this layer doesn't have a special source, or uses a geoJson source
if (json.source === "special" || json.source.geoJson) {
if (json.source === "special" || json.source?.geoJson) {
console.log("Layer has a special source, only saving references");
referencesOnly = true;
}
@ -453,7 +453,6 @@ export class Cache {
const cache = await vscode.workspace.fs.readFile(cacheUri);
const cacheString = new TextDecoder().decode(cache);
this.cache = JSON.parse(cacheString);
console.log(`Cache loaded, ${this.cache.length} items`);
} else {
console.error("No workspace folder found");
throw new Error("No workspace folder found");
@ -513,6 +512,21 @@ export class Cache {
}
return filters;
}
/**
* Get all references to a specific item
*
* @param to Item to get references for (e.g. layers.bicycle_rental)
* @returns List of references
*/
public getReferences(to: string): CacheItem[] {
return this.cache.filter((item) => {
if (item.type === "reference") {
return item.reference?.to === to;
}
return false;
});
}
}
/**