aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/lib.rs36
-rw-r--r--www/index.html15
-rw-r--r--www/index.js69
3 files changed, 99 insertions, 21 deletions
diff --git a/src/lib.rs b/src/lib.rs
index f9a6a26..a1e085f 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -53,7 +53,16 @@ impl SynNode {
53 } 53 }
54 54
55 pub fn to_string(&self) -> String { 55 pub fn to_string(&self) -> String {
56 format!("{:?}@{:?}", self.node.kind(), self.node.text_range(),) 56 format!("{:?} {:?}", self.node.kind(), self.node.text_range(),)
57 }
58
59 pub fn range(&self) -> TextRange {
60 let r = self.node.text_range();
61 (r.start().into(), r.end().into()).into()
62 }
63
64 pub fn text(&self) -> String {
65 format!("{:?}", self.node.kind())
57 } 66 }
58 67
59 pub fn from_str(s: &str) -> Result<JsValue, JsValue> { 68 pub fn from_str(s: &str) -> Result<JsValue, JsValue> {
@@ -95,7 +104,18 @@ impl SynErr {
95} 104}
96 105
97#[wasm_bindgen] 106#[wasm_bindgen]
98struct TextRange { 107impl SynErr {
108 pub fn range(&self) -> TextRange {
109 let r = self.err.range();
110 (r.start().into(), r.end().into()).into()
111 }
112 pub fn to_string(&self) -> String {
113 self.err.to_string()
114 }
115}
116
117#[wasm_bindgen]
118pub struct TextRange {
99 start: u32, 119 start: u32,
100 end: u32, 120 end: u32,
101} 121}
@@ -107,12 +127,14 @@ impl From<(u32, u32)> for TextRange {
107} 127}
108 128
109#[wasm_bindgen] 129#[wasm_bindgen]
110impl SynErr { 130impl TextRange {
111 pub fn range(&self) -> TextRange { 131 pub fn start(&self) -> u32 {
112 let r = self.err.range(); 132 self.start
113 (r.start().into(), r.end().into()).into() 133 }
134 pub fn end(&self) -> u32 {
135 self.end
114 } 136 }
115 pub fn to_string(&self) -> String { 137 pub fn to_string(&self) -> String {
116 self.err.to_string() 138 format!("{}..{}", self.start, self.end)
117 } 139 }
118} 140}
diff --git a/www/index.html b/www/index.html
index 01ba57d..1404993 100644
--- a/www/index.html
+++ b/www/index.html
@@ -10,15 +10,24 @@
10 grid-template-columns: 1fr 1fr; 10 grid-template-columns: 1fr 1fr;
11 grid-gap: 20px; 11 grid-gap: 20px;
12} 12}
13.syntax-node {
14 padding: 0px;
15 padding-left: 20px;
16}
17.syntax-err {
18 color: red;
19}
20pre {
21 padding: 0px;
22 margin: 0px
23}
13 </style> 24 </style>
14 <body> 25 <body>
15 <noscript>This page contains webassembly and javascript content, please enable javascript in your browser.</noscript> 26 <noscript>This page contains webassembly and javascript content, please enable javascript in your browser.</noscript>
16 <script src="./bootstrap.js"></script> 27 <script src="./bootstrap.js"></script>
17 <div class="grid-container"> 28 <div class="grid-container">
18 <div id="source-code"></div> 29 <div id="source-code"></div>
19 <div> 30 <div id="cst">
20 <pre id="cst">
21 </pre>
22 </div> 31 </div>
23 </div> 32 </div>
24 <!-- button id="gen-cst">Generate CST</button --> 33 <!-- button id="gen-cst">Generate CST</button -->
diff --git a/www/index.js b/www/index.js
index 2665873..52253c0 100644
--- a/www/index.js
+++ b/www/index.js
@@ -1,5 +1,7 @@
1import {SynNode, put_cst} from "cstea"; 1import {SynNode, put_cst} from "cstea";
2import {EditorState, EditorView, basicSetup} from "@codemirror/basic-setup" 2import {EditorState, EditorView, basicSetup} from "@codemirror/basic-setup"
3import {Decoration, DecorationSet} from "@codemirror/view"
4import {StateField, StateEffect} from "@codemirror/state"
3import {rust} from "@codemirror/lang-rust" 5import {rust} from "@codemirror/lang-rust"
4 6
5let cst = document.getElementById('cst'); 7let cst = document.getElementById('cst');
@@ -18,32 +20,77 @@ let view = new EditorView({
18 parent: document.getElementById('source-code') 20 parent: document.getElementById('source-code')
19}) 21})
20 22
23const doHighlight = StateEffect.define()
24
25const highlightField = StateField.define({
26 create() {
27 return Decoration.none;
28 },
29 update(highlight, tr) {
30 for (let e of tr.effects) if (e.is(doHighlight)) {
31 return (Decoration.none).update({
32 add: [hlMark.range(e.value.from, e.value.to)]
33 });
34 }
35 },
36 provide: f => EditorView.decorations.from(f)
37})
38
39const hlMark = Decoration.mark({class: "cm-highlight"})
40
41const hlTheme = EditorView.baseTheme({
42 ".cm-highlight": { textDecoration: "underline 3px red" }
43})
44
45function highlightArea(view, textRange) {
46 let effects = [doHighlight.of({from: textRange.start(), to: textRange.end()})];
47 if (!view.state.field(highlightField, false)) {
48 effects.push(StateEffect.appendConfig.of([highlightField, hlTheme]));
49 }
50 view.dispatch({effects});
51}
52
21function render_cst(synRoot) { 53function render_cst(synRoot) {
22 cst.innerText += "\n" + synRoot.to_string(); 54 let nodeDiv = document.createElement("div");
55 nodeDiv.className = "syntax-node";
56 let r = synRoot.range();
57 let synText = wrap(synRoot.text() + synRoot.range().to_string(), "pre");
58 synText.onmouseover = () => {
59 console.log(r.to_string());
60 highlightArea(view, r);
61 }
62 nodeDiv.appendChild(synText);
23 if (!synRoot.is_token()) { 63 if (!synRoot.is_token()) {
24 synRoot.children().forEach(node => { 64 synRoot.children().forEach(node => {
25 render_cst(node); 65 nodeDiv.appendChild(render_cst(node));
26 return;
27 }); 66 });
28 } else {
29 return;
30 } 67 }
68 return nodeDiv;
69}
70
71function wrap(s, tag) {
72 let t = document.createElement(tag);
73 t.innerText = s;
74 return t;
31} 75}
32 76
33function render_err(errorList) { 77function render_err(errorList) {
34 cst.innerText = ""; 78 let errDiv = document.createElement("div");
79 errDiv.className = "syntax-err";
35 errorList.forEach(err => { 80 errorList.forEach(err => {
36 cst.innerText += "\n" + err.to_string(); 81 errDiv.appendChild(wrap(err.to_string(), "pre"));
82 highlightArea(view, err.range());
37 }); 83 });
84 return errDiv;
38} 85}
39 86
40function doRender() { 87function doRender() {
41 let sourceFile = view.state.doc.toString();; 88 let sourceFile = view.state.doc.toString();;
42 cst.innerText = ""; 89 cst.innerHTML = "";
43 try { 90 try {
44 var synRoot = SynNode.from_str(sourceFile); 91 let synRoot = SynNode.from_str(sourceFile);
45 render_cst(synRoot); 92 cst.appendChild(render_cst(synRoot));
46 } catch (synError) { 93 } catch (synError) {
47 render_err(synError) 94 cst.appendChild(render_err(synError));
48 } 95 }
49} 96}