Files
WRNexusJS/editors/vscode/src/definition.js
T

117 lines
2.4 KiB
JavaScript

"use strict";
const vscode = require("vscode");
const COMPONENT_DECLARATION = /^\s*(component|layout)\s+([A-Za-z_$][\w$]*)\s*\{/gm;
function getTagAtPosition(document, position) {
const range = document.getWordRangeAtPosition(position, /[A-Za-z_$][\w$]*/);
if (!range) {
return null;
}
const name = document.getText(range);
if (!/^[A-Z][A-Za-z0-9_$]*$/.test(name)) {
return null;
}
const line = document.lineAt(position.line).text;
const offset = document.offsetAt(position);
const lineStart = document.offsetAt(new vscode.Position(position.line, 0));
const characterOffset = offset - lineStart;
const before = line.slice(0, characterOffset);
const after = line.slice(characterOffset);
const insideTag = before.lastIndexOf("<") > before.lastIndexOf(">") && after.includes(">");
if (!insideTag) {
return null;
}
return {
name,
range,
};
}
async function findDeclaration(name) {
const files = await vscode.workspace.findFiles(
"**/*.wrn",
"**/{node_modules,dist,.wrnexus,.git}/**",
);
const matches = [];
for (const uri of files) {
let document;
try {
document = await vscode.workspace.openTextDocument(uri);
} catch {
continue;
}
const source = document.getText();
COMPONENT_DECLARATION.lastIndex = 0;
let match;
while ((match = COMPONENT_DECLARATION.exec(source)) !== null) {
const declarationName = match[2];
if (declarationName !== name) {
continue;
}
const nameOffset = match.index + match[0].indexOf(declarationName);
const start = document.positionAt(nameOffset);
const end = document.positionAt(nameOffset + declarationName.length);
matches.push(new vscode.Location(uri, new vscode.Range(start, end)));
}
}
return matches;
}
async function provideDefinition(document, position) {
const tag = getTagAtPosition(document, position);
if (!tag) {
return null;
}
const matches = await findDeclaration(tag.name);
if (matches.length === 0) {
return null;
}
return matches.length === 1 ? matches[0] : matches;
}
function registerDefinitionProvider(context) {
const disposable = vscode.languages.registerDefinitionProvider(
{
language: "wrn",
},
{
provideDefinition,
},
);
context.subscriptions.push(disposable);
}
module.exports = {
findDeclaration,
getTagAtPosition,
provideDefinition,
registerDefinitionProvider,
};