tangled
alpha
login
or
join now
ansxor.ca
/
markup2
0
fork
atom
this repo has no description
0
fork
atom
overview
issues
1
pulls
pipelines
cleanup
12Me21
3 years ago
ac42160e
577a120b
+88
-98
3 changed files
expand all
collapse all
unified
split
package.json
parse.js
render.js
+1
-1
package.json
···
61
61
"objects": "always-multiline",
62
62
"functions": "never"
63
63
}],
64
64
+
"no-useless-escape": ["off"],
64
65
"comma-spacing": ["warn"],
65
66
"comma-style": ["warn"],
66
67
"computed-property-spacing": ["warn"],
67
68
"dot-location": ["error", "property"],
68
69
"func-call-spacing": ["error"],
69
69
-
"key-spacing": ["warn"],
70
70
"keyword-spacing": ["warn"],
71
71
"max-len": ["error", {"code": 400}],
72
72
"new-parens": ["warn"],
+86
-96
parse.js
···
107
107
'\\key': ARGS_WORD,
108
108
}
109
109
110
110
-
function find_style(token) {
111
111
-
for (let c=current; 'style'===c.type; c=c.parent)
112
112
-
if (c.token===token)
113
113
-
return c
114
114
-
}
115
115
-
116
110
// process a token
117
111
// ๐ฅ _token_type ๐ท TokenType ๐
118
112
// ๐ฅ token ๐ท Text ๐ token text, including arguments
···
129
123
let level = base_token.length
130
124
let args = {level}
131
125
// todo: anchor name (and, can this be chosen automatically based on contents?)
132
132
-
OPEN('heading', token, args, body)
126
126
+
OPEN('heading', args, body)
133
127
} break; case 'DIVIDER': {
134
128
BLOCK('divider')
135
129
} break; case 'BLOCK_END': {
···
149
143
TEXT("}")
150
144
}
151
145
} break; case 'NULL_ENV': {
152
152
-
OPEN('null_env', token, null, true)
146
146
+
OPEN('null_env', null, true)
153
147
current.prev = current.parent.prev
154
148
} break; case 'ESCAPED': {
155
149
if ("\\\n"===token)
···
161
155
} else
162
156
TEXT(token.substr(1))
163
157
} break; case 'QUOTE': {
164
164
-
OPEN('quote', token, {cite: rargs[0]}, body)
158
158
+
OPEN('quote', {cite: rargs[0]}, body)
165
159
} break; case 'CODE_BLOCK': {
166
160
let lang = rargs
167
161
BLOCK('code', {text: body, lang})
168
162
} break; case 'INLINE_CODE': {
169
163
BLOCK('icode', {text: token.replace(/`(`)?/g, "$1")})
170
170
-
/* } break; case 'INLINE_CODE_2': {
171
171
-
token = token.slice(2, token.endsWith("``") ? -2 : 1/0)
172
172
-
BLOCK('icode', {text: token})
173
173
-
} break; case 'LINE_CODE': {
174
174
-
BLOCK('icode', {text: token.substring(2)})*/
175
164
} break; case 'EMBED': {
176
165
let url = base_token.substr(1) // ehh better
177
166
let [type, args] = process_embed(url, rargs)
···
180
169
let url = base_token
181
170
let args = {url}
182
171
if (body) {
183
183
-
OPEN('link', token, args, body)
172
172
+
OPEN('link', args, body)
184
173
} else {
185
174
args.text = rargs[0]
186
175
BLOCK('simple_link', args)
187
176
}
188
177
} break; case 'TABLE_START': {
189
189
-
OPEN('table_row', token, {})
190
190
-
OPEN('table_cell', "", rargs, body)
178
178
+
OPEN('table_row', token) // special OPEN call
179
179
+
OPEN('table_cell', rargs, body)
191
180
} break; case 'TABLE_CELL': {
192
181
while (current.type!=='table_cell')
193
182
CANCEL()
194
183
CLOSE() // cell
195
184
// we don't know whether these are row args or cell args,
196
185
// so just pass the raw args directly, and parse them later.
197
197
-
OPEN('table_cell', token, rargs, body)
186
186
+
OPEN('table_cell', rargs, body)
198
187
} break; case 'INVALID_TAG': {
199
188
if (body)
200
200
-
OPEN('invalid', token, {text: token, reason: "invalid tag"}, body)
189
189
+
OPEN('invalid', {text: token, reason: "invalid tag"}, body)
201
190
else
202
191
BLOCK('invalid', {text: token, reason: "invalid tag"})
203
192
} break; case 'LIST_ITEM': {
204
193
let indent = token.indexOf("-")
205
205
-
OPEN('list_item', token, {indent}, body)
194
194
+
OPEN('list_item', {indent}, body)
206
195
207
196
} break; case '\\sub': {
208
208
-
OPEN('subscript', token, null, body)
197
197
+
OPEN('subscript', null, body)
209
198
} break; case '\\sup': {
210
210
-
OPEN('superscript', token, null, body)
199
199
+
OPEN('superscript', null, body)
211
200
} break; case '\\b': {
212
212
-
OPEN('bold', token, null, body)
201
201
+
OPEN('bold', null, body)
213
202
} break; case '\\i': {
214
214
-
OPEN('italic', token, null, body)
203
203
+
OPEN('italic', null, body)
215
204
} break; case '\\u': {
216
216
-
OPEN('underline', token, null, body)
205
205
+
OPEN('underline', null, body)
217
206
} break; case '\\s': {
218
218
-
OPEN('strikethrough', token, null, body)
207
207
+
OPEN('strikethrough', null, body)
219
208
} break; case '\\quote': {
220
220
-
OPEN('quote', token, {cite: rargs[0]}, body)
209
209
+
OPEN('quote', {cite: rargs[0]}, body)
221
210
} break; case '\\align': {
222
211
let a = rargs[0]
223
212
if (!['left', 'right', 'center'].includes(a))
224
213
a = 'center'
225
225
-
OPEN('align', token, {align: a}, body)
214
214
+
OPEN('align', {align: a}, body)
226
215
} break; case '\\spoiler': {
227
216
let label = arg0(rargs, "spoiler") // todo: handle this default value in the renderer
228
228
-
OPEN('spoiler', token, {label}, body)
217
217
+
OPEN('spoiler', {label}, body)
229
218
} break; case '\\ruby': {
230
219
let text = arg0(rargs, "true")
231
231
-
OPEN('ruby', token, {text}, body)
220
220
+
OPEN('ruby', {text}, body)
232
221
} break; case '\\key': {
233
233
-
OPEN('key', token, null, body)
222
222
+
OPEN('key', null, body)
234
223
} }
235
224
}
236
225
···
301
290
}
302
291
303
292
// start a new block
304
304
-
function OPEN(type, token, args, body) {
293
293
+
function OPEN(type, args, body) {
305
294
current = Object.seal({
306
295
type, args, content: [],
307
307
-
token, body, parent: current,
296
296
+
body, parent: current,
308
297
prev: 'all_newline',
309
298
})
310
299
if (body)
···
319
308
return o
320
309
}
321
310
322
322
-
function can_cancel(o) {
323
323
-
return 'style'===o.type
324
324
-
}
325
325
-
326
311
function CANCEL() {
327
327
-
if (can_cancel(current)) {
312
312
+
if ('style'===current.type) {
328
313
let o = pop()
329
329
-
330
330
-
if (o.token)
331
331
-
current.content.push(o.token)
332
332
-
else if ('block'===current.prev && "\n"===o.content[0])
333
333
-
o.content.shift() // strip newline
334
334
-
335
335
-
current.content.push(...o.content)
314
314
+
current.content.push(o.args, ...o.content)
336
315
current.prev = o.prev
337
337
-
} else if ('table_cell'===current.type && !current.content.length) {
338
338
-
// cancelling an empty table cell means it's the end of the row
339
339
-
// so, discard the cell
340
340
-
let o = pop()
341
341
-
// if the row is empty (i.e. we just have a single | )
342
342
-
if (!current.content.length) {
343
343
-
let o = pop() // discard the row
344
344
-
TEXT(o.token)
345
345
-
return
346
346
-
}
347
347
-
// transfer args to the row, and parse as table row args:
348
348
-
let ret = current.args
349
349
-
for (let arg of o.args) {
350
350
-
if ("*"===arg || "#"===arg) {
351
351
-
ret.header = true
316
316
+
return
317
317
+
}
318
318
+
if ('table_cell'===current.type) {
319
319
+
if (current.content.length) {
320
320
+
CLOSE() // table_cell
321
321
+
current.args = {}
322
322
+
} else {
323
323
+
// cancelling an empty table cell means:
324
324
+
// it's the end of the row, so discard the cell
325
325
+
let o = pop()
326
326
+
// if the ROW is empty (i.e. we just have a single | )
327
327
+
if (!current.content.length) {
328
328
+
let o = pop() // discard the row
329
329
+
TEXT(o.args)
330
330
+
return
331
331
+
// todo: maybe also cancel rows with 1 unclosed cell?
332
332
+
// like `| abc` -> text
333
333
+
}
334
334
+
// transfer args to the row, and parse as table row args:
335
335
+
let ret = current.args = {}
336
336
+
for (let arg of o.args) {
337
337
+
if ("*"===arg || "#"===arg) {
338
338
+
ret.header = true
339
339
+
}
352
340
}
353
341
}
354
354
-
// close the row
355
355
-
CLOSE()
356
356
-
} else
357
357
-
CLOSE()
358
358
-
// todo: maybe also cancel rows with just 1 unclosed cell?
359
359
-
// like `| abc` -> text
342
342
+
// fallthrough to close the table_row
343
343
+
}
344
344
+
CLOSE()
360
345
}
361
346
362
347
function get_last(block) {
···
418
403
if (+h > 1) ret.rowspan = +h
419
404
}
420
405
}
406
406
+
} else if ('style'===o.type) {
407
407
+
node.type = {
408
408
+
__proto__:null,
409
409
+
'**': 'bold', '__': 'underline',
410
410
+
'~~': 'strikethrough', '/': 'italic',
411
411
+
}[o.args]
412
412
+
node.args = null
421
413
}
422
414
423
415
dest.content.push(node)
···
448
440
449
441
function in_table() {
450
442
for (let c=current; ; c=c.parent) {
451
451
-
if (c.type==='table_cell')
443
443
+
if ('table_cell'===c.type)
452
444
return true
453
453
-
if (!can_cancel(c))
445
445
+
if ('style'!==c.type)
454
446
return false
455
447
}
448
448
+
}
449
449
+
// todo: this should check for body
450
450
+
function find_style(token) {
451
451
+
for (let c=current; 'style'===c.type; c=c.parent)
452
452
+
if (c.args===token)
453
453
+
return c
456
454
}
457
455
458
456
function parse(text) {
···
466
464
let match
467
465
function nevermind() {
468
466
REGEX.lastIndex = match.index+1
469
469
-
//last = match.index
470
467
}
471
471
-
function accept(i) {
468
468
+
function accept() {
472
469
TEXT(text.substring(last, match.index))
473
473
-
last = i
470
470
+
last = REGEX.lastIndex
471
471
+
}
472
472
+
function start_line() {
473
473
+
text = text.substring(last)
474
474
+
last = REGEX.lastIndex = 0
475
475
+
prev = -1
474
476
}
475
477
main: while (match = REGEX.exec(text)) {
476
478
// check for infinite loops
477
479
if (match.index===prev)
478
480
throw ["INFINITE LOOP", match]
479
481
prev = match.index
480
480
-
// 1: insert the text from after previous token
481
481
-
// idea: defer this until we actually KNOW we matched a token
482
482
-
//TEXT(text.substring(last, match.index))
483
482
// 2: figure out which token type was matched
484
483
let token_text = match[0]
485
484
let group_num = match.indexOf("", 1)-1
···
487
486
// 3: get type + argument pattern
488
487
let type = GROUPS[group_num]
489
488
let argregex
489
489
+
// 4: special cases:
490
490
if ('TAG'===type) {
491
491
if (token_text in TAGS) {
492
492
type = token_text
···
502
502
if ('style'===current.type && !` \t\n,'"`.includes(before) && `- \t\n.,:;!?'")}`.includes(after)) {
503
503
let c = find_style(token_text)
504
504
if (c) {
505
505
-
accept(REGEX.lastIndex)
505
505
+
accept()
506
506
while (current != c)
507
507
CANCEL()
508
508
-
current.type = {
509
509
-
__proto__:null,
510
510
-
'**': 'bold', '__': 'underline',
511
511
-
'~~': 'strikethrough', '/': 'italic',
512
512
-
}[current.token]
513
508
CLOSE()
514
509
continue main
515
510
}
516
511
}
517
512
// open?
518
513
if (` \t\n({'"`.includes(before) && !` \t\n,'"`.includes(after)) {
519
519
-
accept(REGEX.lastIndex)
514
514
+
accept()
520
515
OPEN('style', token_text)
521
516
continue main
522
517
}
···
528
523
} else {
529
524
argregex = ARGTYPES[group_num]
530
525
}
531
531
-
// 4: parse args and {
532
532
-
let start_line = false
526
526
+
// 5: parse args and {
533
527
if (!argregex) {
534
534
-
accept(REGEX.lastIndex)
528
528
+
accept()
535
529
let body = 'NULL_ENV'===type //h
536
530
PROCESS(type, token_text, null, body, token_text)
537
531
if (body || 'NEWLINE'===type)
538
538
-
start_line = true
532
532
+
start_line()
539
533
} else {
540
534
// try to match arguments
541
535
argregex.lastIndex = REGEX.lastIndex
···
549
543
let body = argmatch[2] // the {, or contents of raw tags
550
544
let word = argmatch[3] // only for syntax like \sub word
551
545
552
552
-
if (ARGS_CODE!==argregex) {
546
546
+
if (ARGS_CODE!==argregex)
553
547
args = parse_args(args)
554
554
-
start_line = body
555
555
-
}
556
556
-
accept(REGEX.lastIndex = argregex.lastIndex)
548
548
+
549
549
+
REGEX.lastIndex = argregex.lastIndex
550
550
+
accept()
557
551
558
552
PROCESS(type, full_token, args, body, token_text)
559
553
// word
560
554
if (undefined!==word) {
561
555
TEXT(word.replace(/\\([^])/g, "$1"))
562
556
CLOSE()
563
563
-
start_line = false
564
557
}
565
565
-
}
566
566
-
// 5: handle start-of-line
567
567
-
if (start_line) {
568
568
-
text = text.substring(last)
569
569
-
last = REGEX.lastIndex = 0
570
570
-
prev = -1
558
558
+
// start new line at `{`
559
559
+
if (body && ARGS_CODE!==argregex && undefined!==word)
560
560
+
start_line()
571
561
}
572
562
} // end of main loop
573
563
+1
-1
render.js
···
162
162
}
163
163
audio.onvolumechange = e=>{
164
164
let volume = audio.volume
165
165
-
vol.textContent = volume ? ["๐","๐","๐"][volume*2.99|0] : "๐"
165
165
+
vol.textContent = volume ? ["๐", "๐", "๐"][volume*2.99|0] : "๐"
166
166
}
167
167
volume.value = audio.volume
168
168
audio.onvolumechange()