126 lines
4.2 KiB
JavaScript
126 lines
4.2 KiB
JavaScript
// src/html.ts
|
|
var highlightMarkHtml = {
|
|
enter: {
|
|
highlight() {
|
|
this.tag("<mark>");
|
|
}
|
|
},
|
|
exit: {
|
|
highlight() {
|
|
this.tag("</mark>");
|
|
}
|
|
}
|
|
};
|
|
|
|
// src/syntax.ts
|
|
import { ok as assert } from "uvu/assert";
|
|
import { splice } from "micromark-util-chunked";
|
|
import { classifyCharacter } from "micromark-util-classify-character";
|
|
import { resolveAll } from "micromark-util-resolve-all";
|
|
import { codes, constants, types } from "micromark-util-symbol";
|
|
var HIGHLIGHT_SEQUENCE_TEMPORTARY = "highlightSequenceTemporary";
|
|
var HIGHLIGHT_SEQUENCE = "highlightSequence";
|
|
var HIGHLIGHT = "highlight";
|
|
var HIGHLIGHT_TEXT = "highlightText";
|
|
function highlightMark() {
|
|
const tokenizer = {
|
|
name: "highlight",
|
|
tokenize: tokenizeHighlight,
|
|
resolveAll: resolveAllHighlight
|
|
};
|
|
return {
|
|
text: { [codes.equalsTo]: tokenizer },
|
|
insideSpan: { null: [tokenizer] },
|
|
attentionMarkers: { null: [codes.equalsTo] }
|
|
};
|
|
function resolveAllHighlight(events, context) {
|
|
let index = -1;
|
|
while (++index < events.length) {
|
|
if (events[index][0] === "enter" && events[index][1].type === HIGHLIGHT_SEQUENCE_TEMPORTARY && events[index][1]._close) {
|
|
let open = index;
|
|
while (open--) {
|
|
if (events[open][0] === "exit" && events[open][1].type === HIGHLIGHT_SEQUENCE_TEMPORTARY && events[open][1]._open && // If the sizes are the same:
|
|
events[index][1].end.offset - events[index][1].start.offset === events[open][1].end.offset - events[open][1].start.offset) {
|
|
events[index][1].type = HIGHLIGHT_SEQUENCE;
|
|
events[open][1].type = HIGHLIGHT_SEQUENCE;
|
|
const highlight = {
|
|
type: HIGHLIGHT,
|
|
start: Object.assign({}, events[open][1].start),
|
|
end: Object.assign({}, events[index][1].end)
|
|
};
|
|
const text = {
|
|
type: HIGHLIGHT_TEXT,
|
|
start: Object.assign({}, events[open][1].end),
|
|
end: Object.assign({}, events[index][1].start)
|
|
};
|
|
const nextEvents = [
|
|
["enter", highlight, context],
|
|
["enter", events[open][1], context],
|
|
["exit", events[open][1], context],
|
|
["enter", text, context]
|
|
];
|
|
const insideSpan = context.parser.constructs.insideSpan.null;
|
|
if (insideSpan) {
|
|
splice(
|
|
nextEvents,
|
|
nextEvents.length,
|
|
0,
|
|
resolveAll(insideSpan, events.slice(open + 1, index), context)
|
|
);
|
|
}
|
|
splice(nextEvents, nextEvents.length, 0, [
|
|
["exit", text, context],
|
|
["enter", events[index][1], context],
|
|
["exit", events[index][1], context],
|
|
["exit", highlight, context]
|
|
]);
|
|
splice(events, open - 1, index - open + 3, nextEvents);
|
|
index = open + nextEvents.length - 2;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
index = -1;
|
|
while (++index < events.length) {
|
|
if (events[index][1].type === HIGHLIGHT_SEQUENCE_TEMPORTARY) {
|
|
events[index][1].type = types.data;
|
|
}
|
|
}
|
|
return events;
|
|
}
|
|
function tokenizeHighlight(effects, ok, nok) {
|
|
const previous = this.previous;
|
|
const events = this.events;
|
|
let size = 0;
|
|
return start;
|
|
function start(code) {
|
|
assert(code === codes.equalsTo, "expected `=`");
|
|
if (previous === codes.equalsTo && events[events.length - 1][1].type !== types.characterEscape) {
|
|
return nok(code);
|
|
}
|
|
effects.enter(HIGHLIGHT_SEQUENCE_TEMPORTARY);
|
|
return more(code);
|
|
}
|
|
function more(code) {
|
|
const before = classifyCharacter(previous);
|
|
if (code === codes.equalsTo) {
|
|
if (size > 1) return nok(code);
|
|
effects.consume(code);
|
|
size++;
|
|
return more;
|
|
}
|
|
if (size < 2) return nok(code);
|
|
const token = effects.exit(HIGHLIGHT_SEQUENCE_TEMPORTARY);
|
|
const after = classifyCharacter(code);
|
|
token._open = !after || after === constants.attentionSideAfter && Boolean(before);
|
|
token._close = !before || before === constants.attentionSideAfter && Boolean(after);
|
|
return ok(code);
|
|
}
|
|
}
|
|
}
|
|
export {
|
|
highlightMark,
|
|
highlightMarkHtml
|
|
};
|