-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathSongEditorHighlight.tish
More file actions
157 lines (153 loc) · 4.3 KB
/
Copy pathSongEditorHighlight.tish
File metadata and controls
157 lines (153 loc) · 4.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
// Host (Deckard) song-editor HTML highlight — not part of @spacedevin/deck.
import {
tokenize,
classifyLine,
isKeyword,
isInlineKeyword,
isStepToken
} from '@spacedevin/deck'
// Build HTML for mirrored deck highlight layer (textarea overlay). All logic in Tish.
fn escapeHtml(s) {
if ((s === null)) {
return ""
}
let x = String(s).split("&").join("&")
x = x.split("<").join("<")
x = x.split(">").join(">")
return x
}
fn lineIndentAndCore(line) {
if ((line === null)) {
return { indent: 0, core: "", tail: "" }
}
let a = 0
while (a < line.length) {
let c = line.charAt(a)
if (c === " " || c === "\t") {
a = a + 1
} else {
break
}
}
let trimmed = line.substring(a)
let b = trimmed.length
while (b > 0) {
let c2 = trimmed.charAt(b - 1)
if (c2 === " " || c2 === "\t" || c2 === "\r") {
b = b - 1
} else {
break
}
}
let core = trimmed.substring(0, b)
let tail = line.substring(a + core.length)
return { indent: a, core: core, tail: tail }
}
// HTML for one line (no comment segment; caller appends comment).
fn highlightCoreHtml(core, indentStr, tailStr, activeStep, playing) {
let html = escapeHtml(indentStr)
if (core.length === 0) {
return html + escapeHtml(tailStr)
}
let toks = tokenize(core)
if (toks.length === 0) {
return html + escapeHtml(core) + escapeHtml(tailStr)
}
let cl = classifyLine(core)
let stepSlotOfTok = {}
if (cl.kind === "steps") {
let si = 0
while (si < cl.stepIndices.length) {
let ti = cl.stepIndices[si]
stepSlotOfTok[String(ti)] = si
si = si + 1
}
}
let pos = 0
let ti = 0
while (ti < toks.length) {
let tok = toks[ti]
let found = core.indexOf(tok, pos)
if (found < 0) {
break
}
html = html + escapeHtml(core.substring(pos, found))
let inner = escapeHtml(tok)
let slotStr = stepSlotOfTok[String(ti)]
if (ti === 0 && isKeyword(tok)) {
let kwClass = "tpl-hl-kw"
if (cl.kind === "note") {
kwClass = kwClass + " tpl-hl-note"
}
inner = "<span class=\"" + kwClass + "\">" + inner + "</span>"
} else {
if (ti > 0 && isInlineKeyword(tok)) {
inner = "<span class=\"tpl-hl-kw tpl-hl-inline\">" + inner + "</span>"
} else {
if (cl.kind === "steps" && slotStr !== null) {
let slot = slotStr
let on = tok === "x" || tok === "X" || tok === "1"
let off = tok === "." || tok === "0"
if (on || off) {
let cls = on ? "tpl-hl-st-on" : "tpl-hl-st-off"
if (playing && slot === activeStep) {
cls = cls + " tpl-hl-st-act"
}
inner = "<span class=\"" + cls + "\">" + inner + "</span>"
}
}
}
}
html = html + inner
pos = found + tok.length
ti = ti + 1
}
html = html + escapeHtml(core.substring(pos))
html = html + escapeHtml(tailStr)
return html
}
export fn tplDocumentToHighlightHtml(source, playbackStep, playing, lastAppliedLineCount, lastAppliedAt) {
let active = Math.floor(playbackStep) % 16
let src = source
if ((src === null)) {
src = ""
}
let lines = String(src).split("\n")
let totalLines = lines.length
let now = typeof Date !== "undefined" && Date.now ? Date.now() : 0
let updatedWindowMs = 32000
let isRecentlyApplied =
lastAppliedLineCount > 0 &&
lastAppliedAt > 0 &&
(now - lastAppliedAt) < updatedWindowMs
let li = 0
let out = ""
while (li < lines.length) {
let fullLine = lines[li]
let hash = fullLine.indexOf("#")
let main = fullLine
let com = ""
if (hash >= 0) {
main = fullLine.substring(0, hash)
com = fullLine.substring(hash)
}
let ic = lineIndentAndCore(main)
let indentStr = main.substring(0, ic.indent)
let lineInLastBlock = isRecentlyApplied && (totalLines - li) <= lastAppliedLineCount
let lineClass = "tpl-hl-line"
if (lineInLastBlock) {
lineClass = lineClass + " tpl-hl-updated"
}
out = out + "<span class=\"" + lineClass + "\">"
out = out + highlightCoreHtml(ic.core, indentStr, ic.tail, active, playing)
if (com.length > 0) {
out = out + "<span class=\"tpl-hl-comment\">" + escapeHtml(com) + "</span>"
}
out = out + "</span>"
if (li < lines.length - 1) {
out = out + "\n"
}
li = li + 1
}
return out
}