Skip to content

Commit 454eddc

Browse files
committed
🎨 frontend: Add syntax colouring (#111)
Add evy syntax colouring by implementing a custom highlight function for lightweight JS code editor Yace. Copy all relevant Yace source files with minor tweaks into a single file `frontend/module/yace-editor.js` as we are not (yet) using a JS bundler. Link: https://github.com/petersolopov/yace Link: https://github.com/petersolopov/mdhl This merges the following commits: * frontend: Copy relevant yace editor source files * frontend: Reformat Yace * frontend: Add evy syntax colouring frontend/index.css | 112 +++++- frontend/index.html | 23 +- frontend/index.js | 32 +- frontend/module/yace-editor.js | 641 +++++++++++++++++++++++++++++++++ 4 files changed, 771 insertions(+), 37 deletions(-) Pull-Request: #111
2 parents 5fd5cfc + 422152c commit 454eddc

File tree

4 files changed

+771
-37
lines changed

4 files changed

+771
-37
lines changed

frontend/index.css

Lines changed: 100 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,14 @@
1515
--output-border-mid: hsl(0deg 0% 85%);
1616
--output-border-light: hsl(0deg 0% 92%);
1717

18+
--syntax-num: hsl(204deg 100% 75%);
19+
--syntax-string: hsl(203deg 100% 86%);
20+
--syntax-func: hsl(266deg 100% 86%);
21+
--syntax-builtin: hsl(27deg 100% 74%);
22+
--syntax-keyword: hsl(359deg 100% 75%);
23+
--syntax-comment: hsl(210deg, 13%, 72%);
24+
--syntax-error-bg: hsl(209deg 100% 33%);
25+
1826
--btn-color: hsl(0deg 0% 33%);
1927
--btn-color-active: hsl(0deg 0% 100%);
2028
--btn-color-disabled: hsl(0deg 0% 33% / 50%);
@@ -222,30 +230,110 @@ main.view-output {
222230
}
223231

224232
/* --- Editor --------------------------------------------------------*/
225-
.editor {
226-
padding-top: var(--editor-padding);
233+
.editor-wrap {
234+
margin-top: var(--editor-padding);
235+
padding-left: var(--editor-padding);
236+
padding-right: var(--editor-padding);
237+
padding-bottom: var(--editor-padding-bottom);
227238
font-size: 1rem;
228239
flex: 1;
229-
overflow: clip;
240+
overflow: auto;
230241
width: var(--editor-width);
231242
}
232-
.editor textarea {
233-
padding-left: var(--editor-padding);
234-
padding-right: var(--editor-padding);
243+
.editor {
235244
color: var(--color);
236245
background: var(--bg);
237246
font-size: 1rem;
238247
font-family: var(--ff-code);
239248
font-variant-ligatures: none;
240-
overflow: auto;
241-
249+
position: relative;
250+
overflow: hidden;
251+
width: max-content;
252+
}
253+
.editor textarea {
254+
line-height: inherit;
255+
white-space: pre-wrap;
256+
background: none;
257+
position: absolute;
258+
width: 100%;
259+
height: 100%;
260+
z-index: 1;
242261
resize: none;
262+
caret-color: var(--color);
263+
padding: inherit;
243264
outline: none;
244-
-webkit-text-fill-color: var(--ccolor);
245-
height: 100%;
246-
width: 100%;
265+
font-size: inherit;
266+
font-family: inherit;
267+
font-variant-ligatures: inherit;
268+
letter-spacing: inherit;
247269
border: none;
248-
padding-bottom: var(--editor-padding-bottom);
270+
top: 0px;
271+
left: 0px;
272+
color: transparent;
273+
overflow: hidden;
274+
}
275+
.editor pre {
276+
line-height: inherit;
277+
position: relative;
278+
white-space: pre-wrap;
279+
word-break: keep-all;
280+
padding: 0;
281+
width: max-content;
282+
margin: 0;
283+
font-size: inherit;
284+
font-family: inherit;
285+
font-variant-ligatures: inherit;
286+
letter-spacing: inherit;
287+
pointer-events: none;
288+
font-family: inherit;
289+
overflow: hidden;
290+
}
291+
.editor pre.lines {
292+
position: absolute;
293+
height: 100%;
294+
top: 0px;
295+
left: 0px;
296+
pointer-events: none;
297+
overflow: auto;
298+
}
299+
.editor pre.lines .num {
300+
position: aboslute;
301+
color: hsl(212deg 8% 47%);
302+
left: 0;
303+
}
304+
.editor pre.lines .txt {
305+
padding-left: 1ch;
306+
color: transparent;
307+
pointer-events: none;
308+
}
309+
.editor .num,
310+
.editor .bool {
311+
color: var(--syntax-num);
312+
}
313+
.editor .str {
314+
color: var(--syntax-string);
315+
}
316+
.editor .func {
317+
color: var(--syntax-func);
318+
}
319+
.editor .builtin {
320+
color: var(--syntax-builtin);
321+
}
322+
.editor .keyword {
323+
color: var(--syntax-keyword);
324+
}
325+
.editor .error {
326+
background: var(--syntax-error-bg);
327+
color: var(--color);
328+
font-style: italic;
329+
}
330+
.editor .op {
331+
color: var(--syntax-keyword);
332+
}
333+
.editor .comment {
334+
color: var(--syntax-comment);
335+
font-style: italic;
336+
font-weight: 300;
249337
}
250338

251339
/* --- Output --------------------------------------------------------*/

frontend/index.html

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,14 @@
1313
href="https://fonts.googleapis.com/css2?family=Fira+Code&family=Inter:wght@400;700&display=swap"
1414
/>
1515
<script src="wasm_exec.js" defer></script>
16-
<script src="index.js" defer></script>
16+
<script src="index.js" type="module" defer></script>
1717
</head>
1818
<body>
1919
<div class="max-width-wrapper">
2020
<header>
2121
<ul class="breadcrumbs">
22-
<li><button onclick="showModal()">Getting Started</button></li>
23-
<li><button onclick="showModal()">Welcome</button></li>
22+
<li><button>Tour</button></li>
23+
<li><button>Welcome</button></li>
2424
</ul>
2525
<a href="/" class="logo">
2626
<img src="img/logo.svg" alt="Evy logo" class="desktop" />
@@ -32,21 +32,8 @@
3232
</div>
3333
</header>
3434
<main>
35-
<div class="editor">
36-
<textarea id="code" spellcheck="false" autocorrect="off" autocapitalize="none" wrap="off">
37-
move 10 20
38-
line 50 50
39-
rect 25 25
40-
color "red"
41-
circle 10
42-
43-
x := 12
44-
print "x:" x
45-
if x > 10
46-
print "🍦 big x"
47-
end
48-
</textarea
49-
>
35+
<div class="editor-wrap">
36+
<div class="editor"></div>
5037
</div>
5138
<div class="output">
5239
<div class="canvas">

frontend/index.js

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
"use strict"
2+
import Yace from "./module/yace-editor.js"
23

34
// --- Globals ---------------------------------------------------------
45

@@ -11,7 +12,7 @@ let stopped = true
1112
let animationStart
1213
let courses
1314
let actions = "fmt,ui,eval"
14-
15+
let editor
1516
// --- Initialise ------------------------------------------------------
1617

1718
initWasm()
@@ -110,14 +111,14 @@ function jsRead() {
110111
// evySource writes the evy source code into wasm memory as bytes
111112
// and returns pointer and length encoded into a single 64 bit number
112113
function evySource() {
113-
const code = document.querySelector("#code").value
114+
const code = editor.value
114115
return stringToMemAddr(code)
115116
}
116117

117118
// setEvySource is exported to evy go/wasm and called after formatting
118119
function setEvySource(ptr, len) {
119120
const source = memToString(ptr, len)
120-
document.querySelector("#code").value = source
121+
editor.update({ value: source })
121122
}
122123

123124
function memToString(ptr, len) {
@@ -257,7 +258,8 @@ async function initUI() {
257258
window.addEventListener("hashchange", handleHashChange)
258259
document.querySelector("#modal-close").onclick = hideModal
259260
initModal()
260-
window.location.hash && handleHashChange()
261+
handleHashChange()
262+
initEditor()
261263
}
262264

263265
async function fetchCourses() {
@@ -273,7 +275,7 @@ async function fetchCourses() {
273275

274276
function ctrlEnterListener(e) {
275277
if ((e.metaKey || e.ctrlKey) && event.key === "Enter") {
276-
document.querySelector("#code").blur()
278+
document.querySelector(".editor textarea").blur()
277279
handleRun()
278280
}
279281
}
@@ -299,7 +301,8 @@ async function handleHashChange() {
299301
throw new Error("invalid response status", response.status)
300302
}
301303
const source = await response.text()
302-
document.querySelector("#code").value = source
304+
editor.update({ value: source })
305+
document.querySelector(".editor-wrap").scrollTo(0, 0)
303306
updateBreadcrumbs(crumbs)
304307
clearOutput()
305308
format()
@@ -434,6 +437,21 @@ function logicalY(e) {
434437
return e.offsetY * scaleY - canvas.offset.y
435438
}
436439

440+
function initEditor() {
441+
const value = `move 10 20
442+
line 50 50
443+
rect 25 25
444+
color "red"
445+
circle 10
446+
447+
x := 12
448+
print "x:" x
449+
if x > 10
450+
print "🍦 big x"
451+
end`
452+
editor = new Yace(".editor", { value })
453+
}
454+
437455
// --- eventHandlers, evy `on` -----------------------------------------
438456

439457
// registerEventHandler is exported to evy go/wasm
@@ -552,7 +570,7 @@ function updateBreadcrumbs(crumbs) {
552570
function breadcrumb(s) {
553571
const btn = document.createElement("button")
554572
btn.textContent = s
555-
btn.onclick = showModal
573+
btn.onclick = () => showModal()
556574
const li = document.createElement("li")
557575
li.appendChild(btn)
558576
return li

0 commit comments

Comments
 (0)