Compare commits
No commits in common. "f60725b341da9c0b78c5dd4485e1dfadcc8788bd" and "e89be0feffaf583316b6f5266fbaed0977561ec2" have entirely different histories.
f60725b341
...
e89be0feff
@ -49,8 +49,6 @@
|
|||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
color: transparent;
|
color: transparent;
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
word-wrap: break-word;
|
|
||||||
overflow-y: scroll;
|
|
||||||
|
|
||||||
.highlighted {
|
.highlighted {
|
||||||
background: #ffff00;
|
background: #ffff00;
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import React, { ReactNode, useMemo, useRef, useState } from "react";
|
import React, { ReactNode, useState } from "react";
|
||||||
import "./Editor.css";
|
import "./Editor.css";
|
||||||
import { Highlight } from "./highlight";
|
import { Highlight } from "./highlight";
|
||||||
import { buildShadow } from "./shadow";
|
import { buildShadow } from "./shadow";
|
||||||
import OrgAst, { OrgNodeReference } from "./OrgAst";
|
import OrgAst from "./OrgAst";
|
||||||
import { parse_org } from "../../organic/target/wasm32-unknown-unknown/js/wasm";
|
import { parse_org } from "../../organic/target/wasm32-unknown-unknown/js/wasm";
|
||||||
|
|
||||||
const default_org_source: string = `Welcome to the Organic Wasm Demo!
|
const default_org_source: string = `Welcome to the Organic Wasm Demo!
|
||||||
@ -31,21 +31,8 @@ function Editor({ defaultValue = default_org_source }) {
|
|||||||
|
|
||||||
const [highlights, setHighlights] = useState<Array<Highlight>>([]);
|
const [highlights, setHighlights] = useState<Array<Highlight>>([]);
|
||||||
|
|
||||||
const astTree = useMemo(() => {
|
function setHighlight(start: number, end: number) {
|
||||||
const astTree = parse_org(value);
|
let new_highlights = [new Highlight(start, end)];
|
||||||
console.log(JSON.stringify(astTree));
|
|
||||||
return astTree;
|
|
||||||
}, [value]);
|
|
||||||
|
|
||||||
function setHighlight(nodes: OrgNodeReference[]) {
|
|
||||||
let new_highlights = nodes.map((node: OrgNodeReference) => {
|
|
||||||
return new Highlight(node.start - 1, node.end - 1);
|
|
||||||
});
|
|
||||||
new_highlights.sort(function (a, b) {
|
|
||||||
if (a.start < b.start) return -1;
|
|
||||||
if (a.start > b.start) return 1;
|
|
||||||
return 0;
|
|
||||||
});
|
|
||||||
setHighlights(new_highlights);
|
setHighlights(new_highlights);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,29 +50,18 @@ function Editor({ defaultValue = default_org_source }) {
|
|||||||
setHighlights([]);
|
setHighlights([]);
|
||||||
}
|
}
|
||||||
|
|
||||||
const textAreaRef = useRef<HTMLTextAreaElement>(null);
|
const astTree = parse_org(value);
|
||||||
const shadowRef = useRef<HTMLDivElement>(null);
|
console.log(JSON.stringify(astTree));
|
||||||
function onTextAreaScroll() {
|
|
||||||
if (shadowRef.current !== null && textAreaRef.current !== null) {
|
|
||||||
const textAreaScrollTop = textAreaRef.current.scrollTop;
|
|
||||||
shadowRef.current.scrollTop = textAreaScrollTop;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="Editor">
|
<div className="Editor">
|
||||||
<div className="Editor-textwrapper">
|
<div className="Editor-textwrapper">
|
||||||
<textarea
|
<textarea
|
||||||
ref={textAreaRef}
|
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
className="Editor-textarea"
|
className="Editor-textarea"
|
||||||
value={value}
|
value={value}
|
||||||
onScroll={onTextAreaScroll}
|
|
||||||
/>
|
/>
|
||||||
<div ref={shadowRef} className="Editor-underlay">
|
<div className="Editor-underlay">{buildShadow(highlights, value)}</div>
|
||||||
{buildShadow(highlights, value)}
|
|
||||||
<br />
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<OrgAst
|
<OrgAst
|
||||||
setHighlight={setHighlight}
|
setHighlight={setHighlight}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
flex: 1;
|
flex: 1;
|
||||||
background: #eeeeee;
|
background: #eeeeee;
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
overflow: auto;
|
overflow: scroll;
|
||||||
}
|
}
|
||||||
|
|
||||||
.OrgAstNode {
|
.OrgAstNode {
|
||||||
@ -35,31 +35,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.OrgAstNode.hovered:not(.selected) {
|
|
||||||
> .OrgAstNodeType {
|
|
||||||
background: #70f8ba;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.OrgAstNodeType {
|
.OrgAstNodeType {
|
||||||
|
font-size: 1.3rem;
|
||||||
|
font-weight: 700;
|
||||||
background: #6ccff6;
|
background: #6ccff6;
|
||||||
padding: 3px;
|
padding: 3px;
|
||||||
overflow: hidden;
|
|
||||||
|
|
||||||
> span:first-child {
|
|
||||||
font-size: 1.1rem;
|
|
||||||
font-weight: 700;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
> span:nth-child(2) {
|
|
||||||
margin-left: 1rem;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
overflow: hidden;
|
|
||||||
white-space: nowrap;
|
|
||||||
font-family: ui-monospace, "Cascadia Code", "Source Code Pro", Menlo,
|
|
||||||
Consolas, "DejaVu Sans Mono", monospace;
|
|
||||||
font-size: 0.8rem;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.OrgAstChildren {
|
.OrgAstChildren {
|
||||||
@ -68,8 +48,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.OrgAstProperties,
|
.OrgAstProperties,
|
||||||
.OrgAstObjectTree,
|
.OrgAstObjectTree {
|
||||||
.OrgAstOptionalPair {
|
|
||||||
border: 1px solid #000000;
|
border: 1px solid #000000;
|
||||||
margin: 5px;
|
margin: 5px;
|
||||||
|
|
||||||
|
2
src/OrgAst.module.css.d.ts
vendored
2
src/OrgAst.module.css.d.ts
vendored
@ -3,7 +3,5 @@ export const OrgAstNode: string;
|
|||||||
export const OrgAstNodeType: string;
|
export const OrgAstNodeType: string;
|
||||||
export const OrgAstChildren: string;
|
export const OrgAstChildren: string;
|
||||||
export const selected: string;
|
export const selected: string;
|
||||||
export const hovered: string;
|
|
||||||
export const OrgAstProperties: string;
|
export const OrgAstProperties: string;
|
||||||
export const OrgAstObjectTree: string;
|
export const OrgAstObjectTree: string;
|
||||||
export const OrgAstOptionalPair: string;
|
|
||||||
|
193
src/OrgAst.tsx
193
src/OrgAst.tsx
@ -8,28 +8,11 @@ const OrgAst = (props: {
|
|||||||
astTree: any;
|
astTree: any;
|
||||||
value: string;
|
value: string;
|
||||||
}) => {
|
}) => {
|
||||||
const [selectedNode, setSelectedNode] = useState<OrgNodeReference | null>(
|
const [selectedNode, setSelectedNode] = useState<string>("");
|
||||||
null,
|
|
||||||
);
|
|
||||||
const [hoveredNode, setHoveredNode] = useState<OrgNodeReference | null>(null);
|
|
||||||
|
|
||||||
function selectNode(uid: string, start: number, end: number) {
|
function selectNode(uid: string, start: number, end: number) {
|
||||||
const new_node: OrgNodeReference = { uid: uid, start: start, end: end };
|
props.setHighlight(start, end);
|
||||||
props.setHighlight([new_node, hoveredNode].filter((node) => node !== null));
|
setSelectedNode(uid);
|
||||||
setSelectedNode({ uid: uid, start: start, end: end });
|
|
||||||
}
|
|
||||||
|
|
||||||
function startHoverNode(uid: string, start: number, end: number) {
|
|
||||||
const new_node: OrgNodeReference = { uid: uid, start: start, end: end };
|
|
||||||
props.setHighlight(
|
|
||||||
[selectedNode, new_node].filter((node) => node !== null),
|
|
||||||
);
|
|
||||||
setHoveredNode({ uid: uid, start: start, end: end });
|
|
||||||
}
|
|
||||||
|
|
||||||
function endHoverNode(uid: string) {
|
|
||||||
props.setHighlight([selectedNode].filter((node) => node !== null));
|
|
||||||
setHoveredNode(null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (props.astTree.status !== "success") {
|
if (props.astTree.status !== "success") {
|
||||||
@ -41,127 +24,45 @@ const OrgAst = (props: {
|
|||||||
key="^"
|
key="^"
|
||||||
uid="^"
|
uid="^"
|
||||||
selectNode={selectNode}
|
selectNode={selectNode}
|
||||||
startHoverNode={startHoverNode}
|
|
||||||
endHoverNode={endHoverNode}
|
|
||||||
node={props.astTree.content}
|
node={props.astTree.content}
|
||||||
selectedNode={selectedNode}
|
selectedNode={selectedNode}
|
||||||
fullSource={props.value}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
interface OrgNodeReference {
|
|
||||||
uid: string;
|
|
||||||
start: number;
|
|
||||||
end: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
const OrgAstNode = (props: {
|
const OrgAstNode = (props: {
|
||||||
selectNode: Function;
|
selectNode: Function;
|
||||||
startHoverNode: Function;
|
|
||||||
endHoverNode: Function;
|
|
||||||
node: any;
|
node: any;
|
||||||
uid: string;
|
uid: string;
|
||||||
selectedNode: OrgNodeReference | null;
|
selectedNode: string;
|
||||||
fullSource: string;
|
|
||||||
}) => {
|
}) => {
|
||||||
const [isHovered, setIsHovered] = useState(false);
|
|
||||||
|
|
||||||
function selectNode() {
|
function selectNode() {
|
||||||
props.selectNode(
|
props.selectNode(
|
||||||
props.uid,
|
props.uid,
|
||||||
props.node["standard-properties"]["begin"],
|
props.node["standard-properties"]["begin"] - 1,
|
||||||
props.node["standard-properties"]["end"],
|
props.node["standard-properties"]["end"] - 1,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function hoverNode() {
|
const nodeClassName =
|
||||||
props.startHoverNode(
|
props.selectedNode === props.uid
|
||||||
props.uid,
|
? styles.OrgAstNode + " " + styles.selected
|
||||||
props.node["standard-properties"]["begin"],
|
: styles.OrgAstNode;
|
||||||
props.node["standard-properties"]["end"],
|
|
||||||
);
|
|
||||||
setIsHovered(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
function endHoverNode() {
|
|
||||||
props.endHoverNode(props.uid);
|
|
||||||
setIsHovered(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
function unicodeAwareSlice(text: string, start: number, end: number) {
|
|
||||||
// Boooo javascript
|
|
||||||
let i = 0;
|
|
||||||
let output = "";
|
|
||||||
for (const chr of text) {
|
|
||||||
if (i >= end) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (i >= start) {
|
|
||||||
output += chr;
|
|
||||||
}
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
let nodeClassName = styles.OrgAstNode;
|
|
||||||
if (props.selectedNode?.uid === props.uid) {
|
|
||||||
nodeClassName = nodeClassName + " " + styles.selected;
|
|
||||||
}
|
|
||||||
if (isHovered) {
|
|
||||||
nodeClassName = nodeClassName + " " + styles.hovered;
|
|
||||||
}
|
|
||||||
|
|
||||||
const selfSource = JSON.stringify(
|
|
||||||
unicodeAwareSlice(
|
|
||||||
props.fullSource,
|
|
||||||
props.node["standard-properties"].begin - 1,
|
|
||||||
props.node["standard-properties"].end - 1,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (props.node["ast-node"] === "plain-text") {
|
|
||||||
return (
|
|
||||||
<div className={nodeClassName}>
|
|
||||||
<div
|
|
||||||
className={styles.OrgAstNodeType}
|
|
||||||
onClick={selectNode}
|
|
||||||
onMouseEnter={hoverNode}
|
|
||||||
onMouseLeave={endHoverNode}
|
|
||||||
title={selfSource}
|
|
||||||
>
|
|
||||||
<span>{props.node["ast-node"]}</span>
|
|
||||||
<span>{selfSource}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={nodeClassName}>
|
<div className={nodeClassName}>
|
||||||
<div
|
<div className={styles.OrgAstNodeType} onClick={selectNode}>
|
||||||
className={styles.OrgAstNodeType}
|
{props.node["ast-node"]}
|
||||||
onClick={selectNode}
|
|
||||||
onMouseEnter={hoverNode}
|
|
||||||
onMouseLeave={endHoverNode}
|
|
||||||
title={selfSource}
|
|
||||||
>
|
|
||||||
<span>{props.node["ast-node"]}</span>
|
|
||||||
<span>{selfSource}</span>
|
|
||||||
</div>
|
</div>
|
||||||
<details>
|
<details>
|
||||||
<summary>Standard Properties</summary>
|
<summary>Standard Properties</summary>
|
||||||
<OrgPropertiesList
|
<OrgPropertiesList
|
||||||
selectNode={props.selectNode}
|
selectNode={props.selectNode}
|
||||||
startHoverNode={props.startHoverNode}
|
|
||||||
endHoverNode={props.endHoverNode}
|
|
||||||
parentUniqueId={props.uid}
|
parentUniqueId={props.uid}
|
||||||
selectedNode={props.selectedNode}
|
selectedNode={props.selectedNode}
|
||||||
properties={props.node["standard-properties"]}
|
properties={props.node["standard-properties"]}
|
||||||
fullSource={props.fullSource}
|
|
||||||
/>
|
/>
|
||||||
</details>
|
</details>
|
||||||
{!!Object.keys(props.node.properties).length ? (
|
{!!Object.keys(props.node.properties).length ? (
|
||||||
@ -170,12 +71,9 @@ const OrgAstNode = (props: {
|
|||||||
<summary>Properties</summary>
|
<summary>Properties</summary>
|
||||||
<OrgPropertiesList
|
<OrgPropertiesList
|
||||||
selectNode={props.selectNode}
|
selectNode={props.selectNode}
|
||||||
startHoverNode={props.startHoverNode}
|
|
||||||
endHoverNode={props.endHoverNode}
|
|
||||||
parentUniqueId={props.uid}
|
parentUniqueId={props.uid}
|
||||||
selectedNode={props.selectedNode}
|
selectedNode={props.selectedNode}
|
||||||
properties={props.node.properties}
|
properties={props.node.properties}
|
||||||
fullSource={props.fullSource}
|
|
||||||
/>
|
/>
|
||||||
</details>
|
</details>
|
||||||
</>
|
</>
|
||||||
@ -186,12 +84,9 @@ const OrgAstNode = (props: {
|
|||||||
<div className={styles.OrgAstChildren}>
|
<div className={styles.OrgAstChildren}>
|
||||||
<OrgAstNodeList
|
<OrgAstNodeList
|
||||||
selectNode={props.selectNode}
|
selectNode={props.selectNode}
|
||||||
startHoverNode={props.startHoverNode}
|
|
||||||
endHoverNode={props.endHoverNode}
|
|
||||||
parentUniqueId={props.uid}
|
parentUniqueId={props.uid}
|
||||||
selectedNode={props.selectedNode}
|
selectedNode={props.selectedNode}
|
||||||
node_list={props.node.children}
|
node_list={props.node.children}
|
||||||
fullSource={props.fullSource}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</details>
|
</details>
|
||||||
@ -202,12 +97,9 @@ const OrgAstNode = (props: {
|
|||||||
|
|
||||||
const OrgAstNodeList = (props: {
|
const OrgAstNodeList = (props: {
|
||||||
selectNode: Function;
|
selectNode: Function;
|
||||||
startHoverNode: Function;
|
|
||||||
endHoverNode: Function;
|
|
||||||
parentUniqueId: string;
|
parentUniqueId: string;
|
||||||
selectedNode: OrgNodeReference | null;
|
selectedNode: string;
|
||||||
node_list: any[];
|
node_list: any[];
|
||||||
fullSource: string;
|
|
||||||
}): React.JSX.Element[] => {
|
}): React.JSX.Element[] => {
|
||||||
return props.node_list.map((node) => {
|
return props.node_list.map((node) => {
|
||||||
const uid =
|
const uid =
|
||||||
@ -224,11 +116,8 @@ const OrgAstNodeList = (props: {
|
|||||||
key={uid}
|
key={uid}
|
||||||
uid={uid}
|
uid={uid}
|
||||||
selectNode={props.selectNode}
|
selectNode={props.selectNode}
|
||||||
startHoverNode={props.startHoverNode}
|
|
||||||
endHoverNode={props.endHoverNode}
|
|
||||||
selectedNode={props.selectedNode}
|
selectedNode={props.selectedNode}
|
||||||
node={node}
|
node={node}
|
||||||
fullSource={props.fullSource}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -236,12 +125,9 @@ const OrgAstNodeList = (props: {
|
|||||||
|
|
||||||
const OrgPropertiesList = (props: {
|
const OrgPropertiesList = (props: {
|
||||||
selectNode: Function;
|
selectNode: Function;
|
||||||
startHoverNode: Function;
|
|
||||||
endHoverNode: Function;
|
|
||||||
parentUniqueId: string;
|
parentUniqueId: string;
|
||||||
selectedNode: OrgNodeReference | null;
|
selectedNode: string;
|
||||||
properties: Object;
|
properties: Object;
|
||||||
fullSource: string;
|
|
||||||
}): React.JSX.Element => {
|
}): React.JSX.Element => {
|
||||||
const entries = Object.entries(props.properties)
|
const entries = Object.entries(props.properties)
|
||||||
.sort((a, b) => {
|
.sort((a, b) => {
|
||||||
@ -264,12 +150,9 @@ const OrgPropertiesList = (props: {
|
|||||||
<td>
|
<td>
|
||||||
<OrgPropertyValue
|
<OrgPropertyValue
|
||||||
selectNode={props.selectNode}
|
selectNode={props.selectNode}
|
||||||
startHoverNode={props.startHoverNode}
|
|
||||||
endHoverNode={props.endHoverNode}
|
|
||||||
parentUniqueId={props.parentUniqueId}
|
parentUniqueId={props.parentUniqueId}
|
||||||
selectedNode={props.selectedNode}
|
selectedNode={props.selectedNode}
|
||||||
value={value}
|
value={value}
|
||||||
fullSource={props.fullSource}
|
|
||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@ -285,12 +168,9 @@ const OrgPropertiesList = (props: {
|
|||||||
|
|
||||||
const OrgPropertyValue = (props: {
|
const OrgPropertyValue = (props: {
|
||||||
selectNode: Function;
|
selectNode: Function;
|
||||||
startHoverNode: Function;
|
|
||||||
endHoverNode: Function;
|
|
||||||
parentUniqueId: string;
|
parentUniqueId: string;
|
||||||
selectedNode: OrgNodeReference | null;
|
selectedNode: string;
|
||||||
value: any;
|
value: any;
|
||||||
fullSource: string;
|
|
||||||
}): React.ReactNode => {
|
}): React.ReactNode => {
|
||||||
if (
|
if (
|
||||||
props.value === null ||
|
props.value === null ||
|
||||||
@ -303,40 +183,19 @@ const OrgPropertyValue = (props: {
|
|||||||
<div className={styles.OrgAstChildren}>
|
<div className={styles.OrgAstChildren}>
|
||||||
<OrgAstNodeList
|
<OrgAstNodeList
|
||||||
selectNode={props.selectNode}
|
selectNode={props.selectNode}
|
||||||
startHoverNode={props.startHoverNode}
|
|
||||||
endHoverNode={props.endHoverNode}
|
|
||||||
parentUniqueId={props.parentUniqueId}
|
parentUniqueId={props.parentUniqueId}
|
||||||
selectedNode={props.selectedNode}
|
selectedNode={props.selectedNode}
|
||||||
node_list={props.value}
|
node_list={props.value}
|
||||||
fullSource={props.fullSource}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
} else if (is_optional_pair(props.value)) {
|
|
||||||
return (
|
|
||||||
<table className={styles.OrgAstOptionalPair}>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Optional value:</th>
|
|
||||||
<td>{JSON.stringify(props.value.optval)}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Value:</th>
|
|
||||||
<td>{JSON.stringify(props.value.val)}</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
);
|
|
||||||
} else if (is_object_tree(props.value)) {
|
} else if (is_object_tree(props.value)) {
|
||||||
return (
|
return (
|
||||||
<OrgObjectTree
|
<OrgObjectTree
|
||||||
selectNode={props.selectNode}
|
selectNode={props.selectNode}
|
||||||
startHoverNode={props.startHoverNode}
|
|
||||||
endHoverNode={props.endHoverNode}
|
|
||||||
parentUniqueId={props.parentUniqueId}
|
parentUniqueId={props.parentUniqueId}
|
||||||
selectedNode={props.selectedNode}
|
selectedNode={props.selectedNode}
|
||||||
value={props.value}
|
value={props.value}
|
||||||
fullSource={props.fullSource}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
@ -346,22 +205,16 @@ const OrgPropertyValue = (props: {
|
|||||||
|
|
||||||
interface OrgObjectTreeProps {
|
interface OrgObjectTreeProps {
|
||||||
selectNode: Function;
|
selectNode: Function;
|
||||||
startHoverNode: Function;
|
|
||||||
endHoverNode: Function;
|
|
||||||
parentUniqueId: string;
|
parentUniqueId: string;
|
||||||
selectedNode: OrgNodeReference | null;
|
selectedNode: string;
|
||||||
value: any;
|
value: any;
|
||||||
fullSource: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function OrgObjectTree({
|
function OrgObjectTree({
|
||||||
selectNode,
|
selectNode,
|
||||||
startHoverNode,
|
|
||||||
endHoverNode,
|
|
||||||
parentUniqueId,
|
parentUniqueId,
|
||||||
selectedNode,
|
selectedNode,
|
||||||
value,
|
value,
|
||||||
fullSource,
|
|
||||||
}: OrgObjectTreeProps): React.ReactNode {
|
}: OrgObjectTreeProps): React.ReactNode {
|
||||||
const entries = value["object-tree"].map((entry: any) => {
|
const entries = value["object-tree"].map((entry: any) => {
|
||||||
return (
|
return (
|
||||||
@ -371,12 +224,9 @@ function OrgObjectTree({
|
|||||||
<td>
|
<td>
|
||||||
<OrgAstNodeList
|
<OrgAstNodeList
|
||||||
selectNode={selectNode}
|
selectNode={selectNode}
|
||||||
startHoverNode={startHoverNode}
|
|
||||||
endHoverNode={endHoverNode}
|
|
||||||
parentUniqueId={parentUniqueId}
|
parentUniqueId={parentUniqueId}
|
||||||
selectedNode={selectedNode}
|
selectedNode={selectedNode}
|
||||||
node_list={entry[0]}
|
node_list={entry[0]}
|
||||||
fullSource={fullSource}
|
|
||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@ -385,12 +235,9 @@ function OrgObjectTree({
|
|||||||
<td>
|
<td>
|
||||||
<OrgAstNodeList
|
<OrgAstNodeList
|
||||||
selectNode={selectNode}
|
selectNode={selectNode}
|
||||||
startHoverNode={startHoverNode}
|
|
||||||
endHoverNode={endHoverNode}
|
|
||||||
parentUniqueId={parentUniqueId}
|
parentUniqueId={parentUniqueId}
|
||||||
selectedNode={selectedNode}
|
selectedNode={selectedNode}
|
||||||
node_list={entry[1]}
|
node_list={entry[1]}
|
||||||
fullSource={fullSource}
|
|
||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@ -424,14 +271,8 @@ function is_list_of_ast_nodes(val: any): boolean {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function is_optional_pair(val: any): boolean {
|
|
||||||
return (
|
|
||||||
is_object(val) && val.hasOwnProperty("optval") && val.hasOwnProperty("val")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function is_object_tree(val: any): boolean {
|
function is_object_tree(val: any): boolean {
|
||||||
return is_object(val) && val.hasOwnProperty("object-tree");
|
return is_object(val) && val.hasOwnProperty("object-tree");
|
||||||
}
|
}
|
||||||
|
|
||||||
export { OrgAst as default, OrgNodeReference };
|
export default OrgAst;
|
||||||
|
@ -2,32 +2,36 @@ import React, { ReactNode, useState } from "react";
|
|||||||
import { Highlight } from "./highlight";
|
import { Highlight } from "./highlight";
|
||||||
|
|
||||||
function buildShadow(highlights: Highlight[], text: string): ReactNode[] {
|
function buildShadow(highlights: Highlight[], text: string): ReactNode[] {
|
||||||
|
let remaining_highlights = highlights.slice();
|
||||||
let output: ReactNode[] = [];
|
let output: ReactNode[] = [];
|
||||||
let i = 0;
|
let i = 0;
|
||||||
let state = ShadowState.Text;
|
let state = ShadowState.Text;
|
||||||
let buffer = "";
|
let buffer = "";
|
||||||
for (let chr of text) {
|
for (let chr of text) {
|
||||||
const thisCharHighlighted = isInHighlight(highlights, i);
|
if (state == ShadowState.Text) {
|
||||||
if (state == ShadowState.Text && thisCharHighlighted) {
|
if (
|
||||||
// Start a span
|
remaining_highlights.length > 0 &&
|
||||||
output.push(buffer);
|
i == remaining_highlights[0].start
|
||||||
buffer = chr;
|
) {
|
||||||
state = ShadowState.Highlight;
|
// Start a span
|
||||||
} else if (state == ShadowState.Text && !thisCharHighlighted) {
|
output.push(buffer);
|
||||||
// Add a character
|
buffer = chr;
|
||||||
buffer += chr;
|
state = ShadowState.Highlight;
|
||||||
} else if (state == ShadowState.Highlight && thisCharHighlighted) {
|
} else {
|
||||||
// Add a character
|
// Add a character
|
||||||
buffer += chr;
|
buffer += chr;
|
||||||
} else if (state == ShadowState.Highlight && !thisCharHighlighted) {
|
}
|
||||||
// End the span
|
} else if (state == ShadowState.Highlight) {
|
||||||
output.push(
|
if (remaining_highlights.length > 0 && i == remaining_highlights[0].end) {
|
||||||
<span key={i} className="highlighted">
|
// End the span
|
||||||
{buffer}
|
output.push(<span className="highlighted">{buffer}</span>);
|
||||||
</span>,
|
buffer = chr;
|
||||||
);
|
state = ShadowState.Text;
|
||||||
buffer = chr;
|
remaining_highlights = remaining_highlights.slice(1);
|
||||||
state = ShadowState.Text;
|
} else {
|
||||||
|
// Add a character
|
||||||
|
buffer += chr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
@ -36,23 +40,26 @@ function buildShadow(highlights: Highlight[], text: string): ReactNode[] {
|
|||||||
if (state == ShadowState.Text) {
|
if (state == ShadowState.Text) {
|
||||||
output.push(buffer);
|
output.push(buffer);
|
||||||
} else if (state == ShadowState.Highlight) {
|
} else if (state == ShadowState.Highlight) {
|
||||||
output.push(
|
output.push(<span className="highlighted">{buffer}</span>);
|
||||||
<span key={i} className="highlighted">
|
|
||||||
{buffer}
|
|
||||||
</span>,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isInHighlight(highlights: Highlight[], offset: number): boolean {
|
function unicodeAwareSlice(text: string, start: number, end: number): string {
|
||||||
for (const highlight of highlights) {
|
// Boooo javascript
|
||||||
if (highlight.start <= offset && offset < highlight.end) {
|
let i = 0;
|
||||||
return true;
|
let output = "";
|
||||||
|
for (let chr of text) {
|
||||||
|
if (i >= end) {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
if (i >= start) {
|
||||||
|
output += chr;
|
||||||
|
}
|
||||||
|
++i;
|
||||||
}
|
}
|
||||||
return false;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
const enum ShadowState {
|
const enum ShadowState {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user