Files
visualization/visualization-bundle/src/visualizers/ast-visualizer/index.tsx

128 lines
3.0 KiB
TypeScript

import {
Serializer,
sLazy,
sOpenObject,
sArrayOf,
sString,
sOptionalProp,
sUnion,
sLiteral,
sBoolean,
sProp,
sNumber,
} from "@hediet/semantic-json";
import { visualizationNs } from "../../consts";
import {
createVisualizer,
ReactVisualization,
globalVisualizationFactory,
} from "@hediet/visualization-core";
import { createTreeViewModelFromTreeNodeData } from "../tree-visualizer";
import { AstTree, NodeInfo } from "./AstVisualizer";
import * as React from "react";
import LineColumn from "line-column";
import * as monacoTypes from "monaco-editor";
import { getLoadedMonaco } from "@hediet/monaco-editor-react";
interface AstTreeNode {
children: AstTreeNode[];
items: Item[];
segment?: string; // like "root", ".name" or "[0]"
isMarked?: boolean;
span: NodeInfo;
}
interface Item {
text: string;
emphasis?: "style1" | "style2" | "style3" | string;
}
export const sAstTreeNode: Serializer<AstTreeNode> = sLazy(() =>
sOpenObject({
children: sArrayOf(sAstTreeNode),
items: sArrayOf(
sOpenObject({
text: sString(),
emphasis: sOptionalProp(
sUnion(
[
sLiteral("style1"),
sLiteral("style2"),
sLiteral("style3"),
sString(),
],
{ inclusive: true }
)
),
}).defineAs(visualizationNs("AstTreeNodeItem"))
),
segment: sOptionalProp(sString()),
isMarked: sOptionalProp(sBoolean()),
span: sOpenObject({
start: sNumber(),
length: sNumber(),
}),
}).defineAs(visualizationNs("AstTreeNode"))
);
export const sAstTree = sOpenObject({
kind: sOpenObject({
ast: sLiteral(true),
tree: sLiteral(true),
text: sLiteral(true),
}),
root: sAstTreeNode,
text: sString(),
fileName: sOptionalProp(sString()),
}).defineAs(visualizationNs("AstTreeVisualizationData"));
export const astVisualizer = createVisualizer({
id: "ast",
name: "AST",
serializer: sAstTree,
getVisualization: (data, self) =>
new ReactVisualization(self, { priority: 1500 }, theme => {
const m = createTreeViewModelFromTreeNodeData(
data.root,
node => node.span
);
const l = LineColumn(data.text);
function translatePosition(pos: number): monacoTypes.IPosition {
let r = l.fromIndex(pos);
if (!r) {
r = l.fromIndex(data.text.length - 1);
r.col++;
}
return {
column: r.col,
lineNumber: r.line,
};
}
const nodeInfoToRange = (info: NodeInfo): monacoTypes.IRange => {
const start = translatePosition(info.start);
const end = translatePosition(info.start + info.length);
const range = getLoadedMonaco().Range.fromPositions(start, end);
return range;
};
function posToIndex(pos: monacoTypes.IPosition): number {
const i = l.toIndex(pos.lineNumber, pos.column);
if (i == -1) {
return data.text.length;
}
return i;
}
return (
<AstTree
model={m}
theme={theme}
data={data}
nodeInfoToRange={nodeInfoToRange}
posToIndex={posToIndex}
/>
);
}),
});
globalVisualizationFactory.addVisualizer(astVisualizer);