Skip to content

Commit

Permalink
feat: Add most of relaxng elements
Browse files Browse the repository at this point in the history
  • Loading branch information
tihonove committed Jan 18, 2025
1 parent 1e3e46c commit c74e47f
Show file tree
Hide file tree
Showing 4 changed files with 4,683 additions and 11 deletions.
46 changes: 41 additions & 5 deletions src/extension.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,15 @@ exports.activate = function activate(context) {
getTreeItem: e => currentTreeViewProvider?.getTreeItem(e),
};

async function ensureTreeViewProviderExists() {
if (treeView.visible) return;
const children = treeViewProvider.getChildren();
for (const child of children) {
await treeView.reveal(child, { select: false, focus: false, expand: false });
return;
}
}

const treeView = vscode.window.createTreeView("relaxng-outline.relaxNGOutline", {
treeDataProvider: treeViewProvider,
showCollapseAll: true,
Expand Down Expand Up @@ -115,21 +124,22 @@ exports.activate = function activate(context) {
});

context.subscriptions.push(
vscode.window.onDidChangeTextEditorSelection(event => {
vscode.window.onDidChangeTextEditorSelection(async event => {
if (!followCursor) return;
revealNodeAtCursorForEditor(event.textEditor, false, true);
await revealNodeAtCursorForEditor(event.textEditor, false, true);
})
);

function revealNodeAtCursorForEditor(textEditor, focus, skipIfInvisible) {
async function revealNodeAtCursorForEditor(textEditor, focus, skipIfInvisible) {
if (textEditor?.document?.uri.toString() !== currentDocumentUri?.toString()) return;
if (skipIfInvisible && !(treeView?.visible ?? false)) return;
await ensureTreeViewProviderExists();
const position = textEditor.selections[0]?.active;
const offset = textEditor.document.offsetAt(position);
if (position) {
const node = currentTreeViewProvider?.getNodeForOffset(offset);
if (node) {
treeView.reveal(node, { select: true, focus: focus });
await treeView.reveal(node, { select: true, focus: focus });
}
}
}
Expand Down Expand Up @@ -195,6 +205,7 @@ class DocumentTreeViewProvider {
if (rngNode.type == "choice") return [...(rngNode.attributes ?? []), ...(rngNode.elements ?? [])];
if (rngNode.type == "attribute") return [rngNode.dataType];
if (rngNode.type == "type") return rngNode.constraints;
return rngNode.children ?? [];
}

getTreeItem(rngNode) {
Expand Down Expand Up @@ -282,10 +293,35 @@ class DocumentTreeViewProvider {
}
return {
label: rngNode.name,
collapsibleState: vscode.TreeItemCollapsibleState.Expanded,
description: rngNode.name != rngNode.type ? rngNode.type : "",
collapsibleState: rngNode.children?.length > 0 ? vscode.TreeItemCollapsibleState.Expanded : vscode.TreeItemCollapsibleState.None,
contextValue: "relaxng-outline.rngNode",
iconPath: new vscode.ThemeIcon(rngNodeTypeIcons[rngNode.type] ?? "code")
};
}
}

exports.deactivate = () => {};

const rngNodeTypeIcons = {
"group": "code",
"interleave": "code",
"optional": "code",
"zeroOrMore": "code",
"oneOrMore": "plus",
"list": "checklist",
"mixed": "symbol-misc",
"ref": "symbol-reference",
"parentRef": "references",
"empty": "remove-close",
"text": "symbol-string",
"value": "symbol-constant",
"data": "symbol-constant",
"notAllowed": "remove-close",
"externalRef": "symbol-reference",
"grammar": "symbol-class",
"define": "symbol-class",
"div": "code",
"include": "symbol-reference",
"start": "target",
};
46 changes: 40 additions & 6 deletions src/parseRng.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,29 @@
const sax = require("sax");

const rngPatternNames = new Set([
"group",
"interleave",
"optional",
"zeroOrMore",
"oneOrMore",
"list",
"mixed",
"ref",
"parentRef",
"empty",
"text",
"value",
"data",
"notAllowed",
"externalRef",
"grammar",
]);

const grammarContentNames = new Set(["define", "div", "include", "start"]);

const otherNames = new Set(["anyName", "except"]);


exports.parseRng = function parseRng(xml) {
const parser = sax.parser(true);
let root = { elements: [] };
Expand Down Expand Up @@ -27,17 +51,17 @@ exports.parseRng = function parseRng(xml) {
.join("/") +
"/" +
node.attributes.name,
name: node.attributes.name,
name: node.attributes.name ?? "element",
elements: [],
attributes: [],
properties: node.attributes,
};
top().elements ??= [];
top().elements.push(result);
if (top().children != undefined) top().children.push(result);
else (top().elements ??= []).push(result);
} else if (node.name === "attribute") {
result = {
type: "attribute",
name: node.attributes.name,
name: node.attributes.name ?? "attribute",
fullPath:
stack
.filter(x => x.type === "element")
Expand All @@ -48,15 +72,25 @@ exports.parseRng = function parseRng(xml) {
properties: node.attributes,
dataType: undefined,
};
if (top().attributes != undefined) top().attributes.push(result);
if (top().children != undefined) top().children.push(result);
else if (top().attributes != undefined) top().attributes.push(result);
} else if (node.name === "choice") {
result = {
type: "choice",
name: "choice",
elements: [],
attributes: [],
};
if (top().elements != undefined) top().elements.push(result);
if (top().children != undefined) top().children.push(result);
else if (top().elements != undefined) top().elements.push(result);
} else if (rngPatternNames.has(node.name) || grammarContentNames.has(node.name)) {
result = {
type: node.name,
name: node.attributes.name ?? node.name,
children: [],
};
if (top().children != undefined) top().children.push(result);
else if (top().elements != undefined) top().elements.push(result);
} else if (node.name === "type") {
result = {
type: "type",
Expand Down
Loading

0 comments on commit c74e47f

Please sign in to comment.