diff options
author | Akshay <[email protected]> | 2021-06-12 16:31:51 +0100 |
---|---|---|
committer | Akshay <[email protected]> | 2021-06-12 16:31:51 +0100 |
commit | 73177af78f61975a0eaef9a88758d59db4ccc473 (patch) | |
tree | a0b2fb434e4bebb500635b257b331487549be8cb /www | |
parent | 987ce60b9fc60ccdb91e0d271fcba10a0a6cf51a (diff) |
syntax tree <-> dom tree
Diffstat (limited to 'www')
-rw-r--r-- | www/index.html | 15 | ||||
-rw-r--r-- | www/index.js | 69 |
2 files changed, 70 insertions, 14 deletions
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 | } | ||
20 | pre { | ||
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 @@ | |||
1 | import {SynNode, put_cst} from "cstea"; | 1 | import {SynNode, put_cst} from "cstea"; |
2 | import {EditorState, EditorView, basicSetup} from "@codemirror/basic-setup" | 2 | import {EditorState, EditorView, basicSetup} from "@codemirror/basic-setup" |
3 | import {Decoration, DecorationSet} from "@codemirror/view" | ||
4 | import {StateField, StateEffect} from "@codemirror/state" | ||
3 | import {rust} from "@codemirror/lang-rust" | 5 | import {rust} from "@codemirror/lang-rust" |
4 | 6 | ||
5 | let cst = document.getElementById('cst'); | 7 | let 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 | ||
23 | const doHighlight = StateEffect.define() | ||
24 | |||
25 | const 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 | |||
39 | const hlMark = Decoration.mark({class: "cm-highlight"}) | ||
40 | |||
41 | const hlTheme = EditorView.baseTheme({ | ||
42 | ".cm-highlight": { textDecoration: "underline 3px red" } | ||
43 | }) | ||
44 | |||
45 | function 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 | |||
21 | function render_cst(synRoot) { | 53 | function 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 | |||
71 | function wrap(s, tag) { | ||
72 | let t = document.createElement(tag); | ||
73 | t.innerText = s; | ||
74 | return t; | ||
31 | } | 75 | } |
32 | 76 | ||
33 | function render_err(errorList) { | 77 | function 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 | ||
40 | function doRender() { | 87 | function 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 | } |