Diffdown is a real-time collaborative Markdown editor/previewer built on the AT Protocol
diffdown.com
1import { NodeProp } from '@lezer/common';
2
3let nextTagID = 0;
4/**
5Highlighting tags are markers that denote a highlighting category.
6They are [associated](#highlight.styleTags) with parts of a syntax
7tree by a language mode, and then mapped to an actual CSS style by
8a [highlighter](#highlight.Highlighter).
9
10Because syntax tree node types and highlight styles have to be
11able to talk the same language, CodeMirror uses a mostly _closed_
12[vocabulary](#highlight.tags) of syntax tags (as opposed to
13traditional open string-based systems, which make it hard for
14highlighting themes to cover all the tokens produced by the
15various languages).
16
17It _is_ possible to [define](#highlight.Tag^define) your own
18highlighting tags for system-internal use (where you control both
19the language package and the highlighter), but such tags will not
20be picked up by regular highlighters (though you can derive them
21from standard tags to allow highlighters to fall back to those).
22*/
23class Tag {
24 /**
25 @internal
26 */
27 constructor(
28 /**
29 The optional name of the base tag @internal
30 */
31 name,
32 /**
33 The set of this tag and all its parent tags, starting with
34 this one itself and sorted in order of decreasing specificity.
35 */
36 set,
37 /**
38 The base unmodified tag that this one is based on, if it's
39 modified @internal
40 */
41 base,
42 /**
43 The modifiers applied to this.base @internal
44 */
45 modified) {
46 this.name = name;
47 this.set = set;
48 this.base = base;
49 this.modified = modified;
50 /**
51 @internal
52 */
53 this.id = nextTagID++;
54 }
55 toString() {
56 let { name } = this;
57 for (let mod of this.modified)
58 if (mod.name)
59 name = `${mod.name}(${name})`;
60 return name;
61 }
62 static define(nameOrParent, parent) {
63 let name = typeof nameOrParent == "string" ? nameOrParent : "?";
64 if (nameOrParent instanceof Tag)
65 parent = nameOrParent;
66 if (parent === null || parent === void 0 ? void 0 : parent.base)
67 throw new Error("Can not derive from a modified tag");
68 let tag = new Tag(name, [], null, []);
69 tag.set.push(tag);
70 if (parent)
71 for (let t of parent.set)
72 tag.set.push(t);
73 return tag;
74 }
75 /**
76 Define a tag _modifier_, which is a function that, given a tag,
77 will return a tag that is a subtag of the original. Applying the
78 same modifier to a twice tag will return the same value (`m1(t1)
79 == m1(t1)`) and applying multiple modifiers will, regardless or
80 order, produce the same tag (`m1(m2(t1)) == m2(m1(t1))`).
81
82 When multiple modifiers are applied to a given base tag, each
83 smaller set of modifiers is registered as a parent, so that for
84 example `m1(m2(m3(t1)))` is a subtype of `m1(m2(t1))`,
85 `m1(m3(t1)`, and so on.
86 */
87 static defineModifier(name) {
88 let mod = new Modifier(name);
89 return (tag) => {
90 if (tag.modified.indexOf(mod) > -1)
91 return tag;
92 return Modifier.get(tag.base || tag, tag.modified.concat(mod).sort((a, b) => a.id - b.id));
93 };
94 }
95}
96let nextModifierID = 0;
97class Modifier {
98 constructor(name) {
99 this.name = name;
100 this.instances = [];
101 this.id = nextModifierID++;
102 }
103 static get(base, mods) {
104 if (!mods.length)
105 return base;
106 let exists = mods[0].instances.find(t => t.base == base && sameArray(mods, t.modified));
107 if (exists)
108 return exists;
109 let set = [], tag = new Tag(base.name, set, base, mods);
110 for (let m of mods)
111 m.instances.push(tag);
112 let configs = powerSet(mods);
113 for (let parent of base.set)
114 if (!parent.modified.length)
115 for (let config of configs)
116 set.push(Modifier.get(parent, config));
117 return tag;
118 }
119}
120function sameArray(a, b) {
121 return a.length == b.length && a.every((x, i) => x == b[i]);
122}
123function powerSet(array) {
124 let sets = [[]];
125 for (let i = 0; i < array.length; i++) {
126 for (let j = 0, e = sets.length; j < e; j++) {
127 sets.push(sets[j].concat(array[i]));
128 }
129 }
130 return sets.sort((a, b) => b.length - a.length);
131}
132/**
133This function is used to add a set of tags to a language syntax
134via [`NodeSet.extend`](#common.NodeSet.extend) or
135[`LRParser.configure`](#lr.LRParser.configure).
136
137The argument object maps node selectors to [highlighting
138tags](#highlight.Tag) or arrays of tags.
139
140Node selectors may hold one or more (space-separated) node paths.
141Such a path can be a [node name](#common.NodeType.name), or
142multiple node names (or `*` wildcards) separated by slash
143characters, as in `"Block/Declaration/VariableName"`. Such a path
144matches the final node but only if its direct parent nodes are the
145other nodes mentioned. A `*` in such a path matches any parent,
146but only a single level—wildcards that match multiple parents
147aren't supported, both for efficiency reasons and because Lezer
148trees make it rather hard to reason about what they would match.)
149
150A path can be ended with `/...` to indicate that the tag assigned
151to the node should also apply to all child nodes, even if they
152match their own style (by default, only the innermost style is
153used).
154
155When a path ends in `!`, as in `Attribute!`, no further matching
156happens for the node's child nodes, and the entire node gets the
157given style.
158
159In this notation, node names that contain `/`, `!`, `*`, or `...`
160must be quoted as JSON strings.
161
162For example:
163
164```javascript
165parser.configure({props: [
166 styleTags({
167 // Style Number and BigNumber nodes
168 "Number BigNumber": tags.number,
169 // Style Escape nodes whose parent is String
170 "String/Escape": tags.escape,
171 // Style anything inside Attributes nodes
172 "Attributes!": tags.meta,
173 // Add a style to all content inside Italic nodes
174 "Italic/...": tags.emphasis,
175 // Style InvalidString nodes as both `string` and `invalid`
176 "InvalidString": [tags.string, tags.invalid],
177 // Style the node named "/" as punctuation
178 '"/"': tags.punctuation
179 })
180]})
181```
182*/
183function styleTags(spec) {
184 let byName = Object.create(null);
185 for (let prop in spec) {
186 let tags = spec[prop];
187 if (!Array.isArray(tags))
188 tags = [tags];
189 for (let part of prop.split(" "))
190 if (part) {
191 let pieces = [], mode = 2 /* Mode.Normal */, rest = part;
192 for (let pos = 0;;) {
193 if (rest == "..." && pos > 0 && pos + 3 == part.length) {
194 mode = 1 /* Mode.Inherit */;
195 break;
196 }
197 let m = /^"(?:[^"\\]|\\.)*?"|[^\/!]+/.exec(rest);
198 if (!m)
199 throw new RangeError("Invalid path: " + part);
200 pieces.push(m[0] == "*" ? "" : m[0][0] == '"' ? JSON.parse(m[0]) : m[0]);
201 pos += m[0].length;
202 if (pos == part.length)
203 break;
204 let next = part[pos++];
205 if (pos == part.length && next == "!") {
206 mode = 0 /* Mode.Opaque */;
207 break;
208 }
209 if (next != "/")
210 throw new RangeError("Invalid path: " + part);
211 rest = part.slice(pos);
212 }
213 let last = pieces.length - 1, inner = pieces[last];
214 if (!inner)
215 throw new RangeError("Invalid path: " + part);
216 let rule = new Rule(tags, mode, last > 0 ? pieces.slice(0, last) : null);
217 byName[inner] = rule.sort(byName[inner]);
218 }
219 }
220 return ruleNodeProp.add(byName);
221}
222const ruleNodeProp = new NodeProp({
223 combine(a, b) {
224 let cur, root, take;
225 while (a || b) {
226 if (!a || b && a.depth >= b.depth) {
227 take = b;
228 b = b.next;
229 }
230 else {
231 take = a;
232 a = a.next;
233 }
234 if (cur && cur.mode == take.mode && !take.context && !cur.context)
235 continue;
236 let copy = new Rule(take.tags, take.mode, take.context);
237 if (cur)
238 cur.next = copy;
239 else
240 root = copy;
241 cur = copy;
242 }
243 return root;
244 }
245});
246class Rule {
247 constructor(tags, mode, context, next) {
248 this.tags = tags;
249 this.mode = mode;
250 this.context = context;
251 this.next = next;
252 }
253 get opaque() { return this.mode == 0 /* Mode.Opaque */; }
254 get inherit() { return this.mode == 1 /* Mode.Inherit */; }
255 sort(other) {
256 if (!other || other.depth < this.depth) {
257 this.next = other;
258 return this;
259 }
260 other.next = this.sort(other.next);
261 return other;
262 }
263 get depth() { return this.context ? this.context.length : 0; }
264}
265Rule.empty = new Rule([], 2 /* Mode.Normal */, null);
266/**
267Define a [highlighter](#highlight.Highlighter) from an array of
268tag/class pairs. Classes associated with more specific tags will
269take precedence.
270*/
271function tagHighlighter(tags, options) {
272 let map = Object.create(null);
273 for (let style of tags) {
274 if (!Array.isArray(style.tag))
275 map[style.tag.id] = style.class;
276 else
277 for (let tag of style.tag)
278 map[tag.id] = style.class;
279 }
280 let { scope, all = null } = options || {};
281 return {
282 style: (tags) => {
283 let cls = all;
284 for (let tag of tags) {
285 for (let sub of tag.set) {
286 let tagClass = map[sub.id];
287 if (tagClass) {
288 cls = cls ? cls + " " + tagClass : tagClass;
289 break;
290 }
291 }
292 }
293 return cls;
294 },
295 scope
296 };
297}
298function highlightTags(highlighters, tags) {
299 let result = null;
300 for (let highlighter of highlighters) {
301 let value = highlighter.style(tags);
302 if (value)
303 result = result ? result + " " + value : value;
304 }
305 return result;
306}
307/**
308Highlight the given [tree](#common.Tree) with the given
309[highlighter](#highlight.Highlighter). Often, the higher-level
310[`highlightCode`](#highlight.highlightCode) function is easier to
311use.
312*/
313function highlightTree(tree, highlighter,
314/**
315Assign styling to a region of the text. Will be called, in order
316of position, for any ranges where more than zero classes apply.
317`classes` is a space separated string of CSS classes.
318*/
319putStyle,
320/**
321The start of the range to highlight.
322*/
323from = 0,
324/**
325The end of the range.
326*/
327to = tree.length) {
328 let builder = new HighlightBuilder(from, Array.isArray(highlighter) ? highlighter : [highlighter], putStyle);
329 builder.highlightRange(tree.cursor(), from, to, "", builder.highlighters);
330 builder.flush(to);
331}
332/**
333Highlight the given tree with the given highlighter, calling
334`putText` for every piece of text, either with a set of classes or
335with the empty string when unstyled, and `putBreak` for every line
336break.
337*/
338function highlightCode(code, tree, highlighter, putText, putBreak, from = 0, to = code.length) {
339 let pos = from;
340 function writeTo(p, classes) {
341 if (p <= pos)
342 return;
343 for (let text = code.slice(pos, p), i = 0;;) {
344 let nextBreak = text.indexOf("\n", i);
345 let upto = nextBreak < 0 ? text.length : nextBreak;
346 if (upto > i)
347 putText(text.slice(i, upto), classes);
348 if (nextBreak < 0)
349 break;
350 putBreak();
351 i = nextBreak + 1;
352 }
353 pos = p;
354 }
355 highlightTree(tree, highlighter, (from, to, classes) => {
356 writeTo(from, "");
357 writeTo(to, classes);
358 }, from, to);
359 writeTo(to, "");
360}
361class HighlightBuilder {
362 constructor(at, highlighters, span) {
363 this.at = at;
364 this.highlighters = highlighters;
365 this.span = span;
366 this.class = "";
367 }
368 startSpan(at, cls) {
369 if (cls != this.class) {
370 this.flush(at);
371 if (at > this.at)
372 this.at = at;
373 this.class = cls;
374 }
375 }
376 flush(to) {
377 if (to > this.at && this.class)
378 this.span(this.at, to, this.class);
379 }
380 highlightRange(cursor, from, to, inheritedClass, highlighters) {
381 let { type, from: start, to: end } = cursor;
382 if (start >= to || end <= from)
383 return;
384 if (type.isTop)
385 highlighters = this.highlighters.filter(h => !h.scope || h.scope(type));
386 let cls = inheritedClass;
387 let rule = getStyleTags(cursor) || Rule.empty;
388 let tagCls = highlightTags(highlighters, rule.tags);
389 if (tagCls) {
390 if (cls)
391 cls += " ";
392 cls += tagCls;
393 if (rule.mode == 1 /* Mode.Inherit */)
394 inheritedClass += (inheritedClass ? " " : "") + tagCls;
395 }
396 this.startSpan(Math.max(from, start), cls);
397 if (rule.opaque)
398 return;
399 let mounted = cursor.tree && cursor.tree.prop(NodeProp.mounted);
400 if (mounted && mounted.overlay) {
401 let inner = cursor.node.enter(mounted.overlay[0].from + start, 1);
402 let innerHighlighters = this.highlighters.filter(h => !h.scope || h.scope(mounted.tree.type));
403 let hasChild = cursor.firstChild();
404 for (let i = 0, pos = start;; i++) {
405 let next = i < mounted.overlay.length ? mounted.overlay[i] : null;
406 let nextPos = next ? next.from + start : end;
407 let rangeFrom = Math.max(from, pos), rangeTo = Math.min(to, nextPos);
408 if (rangeFrom < rangeTo && hasChild) {
409 while (cursor.from < rangeTo) {
410 this.highlightRange(cursor, rangeFrom, rangeTo, inheritedClass, highlighters);
411 this.startSpan(Math.min(rangeTo, cursor.to), cls);
412 if (cursor.to >= nextPos || !cursor.nextSibling())
413 break;
414 }
415 }
416 if (!next || nextPos > to)
417 break;
418 pos = next.to + start;
419 if (pos > from) {
420 this.highlightRange(inner.cursor(), Math.max(from, next.from + start), Math.min(to, pos), "", innerHighlighters);
421 this.startSpan(Math.min(to, pos), cls);
422 }
423 }
424 if (hasChild)
425 cursor.parent();
426 }
427 else if (cursor.firstChild()) {
428 if (mounted)
429 inheritedClass = "";
430 do {
431 if (cursor.to <= from)
432 continue;
433 if (cursor.from >= to)
434 break;
435 this.highlightRange(cursor, from, to, inheritedClass, highlighters);
436 this.startSpan(Math.min(to, cursor.to), cls);
437 } while (cursor.nextSibling());
438 cursor.parent();
439 }
440 }
441}
442/**
443Match a syntax node's [highlight rules](#highlight.styleTags). If
444there's a match, return its set of tags, and whether it is
445opaque (uses a `!`) or applies to all child nodes (`/...`).
446*/
447function getStyleTags(node) {
448 let rule = node.type.prop(ruleNodeProp);
449 while (rule && rule.context && !node.matchContext(rule.context))
450 rule = rule.next;
451 return rule || null;
452}
453const t = Tag.define;
454const comment = t(), name = t(), typeName = t(name), propertyName = t(name), literal = t(), string = t(literal), number = t(literal), content = t(), heading = t(content), keyword = t(), operator = t(), punctuation = t(), bracket = t(punctuation), meta = t();
455/**
456The default set of highlighting [tags](#highlight.Tag).
457
458This collection is heavily biased towards programming languages,
459and necessarily incomplete. A full ontology of syntactic
460constructs would fill a stack of books, and be impractical to
461write themes for. So try to make do with this set. If all else
462fails, [open an
463issue](https://github.com/codemirror/codemirror.next) to propose a
464new tag, or [define](#highlight.Tag^define) a local custom tag for
465your use case.
466
467Note that it is not obligatory to always attach the most specific
468tag possible to an element—if your grammar can't easily
469distinguish a certain type of element (such as a local variable),
470it is okay to style it as its more general variant (a variable).
471
472For tags that extend some parent tag, the documentation links to
473the parent.
474*/
475const tags = {
476 /**
477 A comment.
478 */
479 comment,
480 /**
481 A line [comment](#highlight.tags.comment).
482 */
483 lineComment: t(comment),
484 /**
485 A block [comment](#highlight.tags.comment).
486 */
487 blockComment: t(comment),
488 /**
489 A documentation [comment](#highlight.tags.comment).
490 */
491 docComment: t(comment),
492 /**
493 Any kind of identifier.
494 */
495 name,
496 /**
497 The [name](#highlight.tags.name) of a variable.
498 */
499 variableName: t(name),
500 /**
501 A type [name](#highlight.tags.name).
502 */
503 typeName: typeName,
504 /**
505 A tag name (subtag of [`typeName`](#highlight.tags.typeName)).
506 */
507 tagName: t(typeName),
508 /**
509 A property or field [name](#highlight.tags.name).
510 */
511 propertyName: propertyName,
512 /**
513 An attribute name (subtag of [`propertyName`](#highlight.tags.propertyName)).
514 */
515 attributeName: t(propertyName),
516 /**
517 The [name](#highlight.tags.name) of a class.
518 */
519 className: t(name),
520 /**
521 A label [name](#highlight.tags.name).
522 */
523 labelName: t(name),
524 /**
525 A namespace [name](#highlight.tags.name).
526 */
527 namespace: t(name),
528 /**
529 The [name](#highlight.tags.name) of a macro.
530 */
531 macroName: t(name),
532 /**
533 A literal value.
534 */
535 literal,
536 /**
537 A string [literal](#highlight.tags.literal).
538 */
539 string,
540 /**
541 A documentation [string](#highlight.tags.string).
542 */
543 docString: t(string),
544 /**
545 A character literal (subtag of [string](#highlight.tags.string)).
546 */
547 character: t(string),
548 /**
549 An attribute value (subtag of [string](#highlight.tags.string)).
550 */
551 attributeValue: t(string),
552 /**
553 A number [literal](#highlight.tags.literal).
554 */
555 number,
556 /**
557 An integer [number](#highlight.tags.number) literal.
558 */
559 integer: t(number),
560 /**
561 A floating-point [number](#highlight.tags.number) literal.
562 */
563 float: t(number),
564 /**
565 A boolean [literal](#highlight.tags.literal).
566 */
567 bool: t(literal),
568 /**
569 Regular expression [literal](#highlight.tags.literal).
570 */
571 regexp: t(literal),
572 /**
573 An escape [literal](#highlight.tags.literal), for example a
574 backslash escape in a string.
575 */
576 escape: t(literal),
577 /**
578 A color [literal](#highlight.tags.literal).
579 */
580 color: t(literal),
581 /**
582 A URL [literal](#highlight.tags.literal).
583 */
584 url: t(literal),
585 /**
586 A language keyword.
587 */
588 keyword,
589 /**
590 The [keyword](#highlight.tags.keyword) for the self or this
591 object.
592 */
593 self: t(keyword),
594 /**
595 The [keyword](#highlight.tags.keyword) for null.
596 */
597 null: t(keyword),
598 /**
599 A [keyword](#highlight.tags.keyword) denoting some atomic value.
600 */
601 atom: t(keyword),
602 /**
603 A [keyword](#highlight.tags.keyword) that represents a unit.
604 */
605 unit: t(keyword),
606 /**
607 A modifier [keyword](#highlight.tags.keyword).
608 */
609 modifier: t(keyword),
610 /**
611 A [keyword](#highlight.tags.keyword) that acts as an operator.
612 */
613 operatorKeyword: t(keyword),
614 /**
615 A control-flow related [keyword](#highlight.tags.keyword).
616 */
617 controlKeyword: t(keyword),
618 /**
619 A [keyword](#highlight.tags.keyword) that defines something.
620 */
621 definitionKeyword: t(keyword),
622 /**
623 A [keyword](#highlight.tags.keyword) related to defining or
624 interfacing with modules.
625 */
626 moduleKeyword: t(keyword),
627 /**
628 An operator.
629 */
630 operator,
631 /**
632 An [operator](#highlight.tags.operator) that dereferences something.
633 */
634 derefOperator: t(operator),
635 /**
636 Arithmetic-related [operator](#highlight.tags.operator).
637 */
638 arithmeticOperator: t(operator),
639 /**
640 Logical [operator](#highlight.tags.operator).
641 */
642 logicOperator: t(operator),
643 /**
644 Bit [operator](#highlight.tags.operator).
645 */
646 bitwiseOperator: t(operator),
647 /**
648 Comparison [operator](#highlight.tags.operator).
649 */
650 compareOperator: t(operator),
651 /**
652 [Operator](#highlight.tags.operator) that updates its operand.
653 */
654 updateOperator: t(operator),
655 /**
656 [Operator](#highlight.tags.operator) that defines something.
657 */
658 definitionOperator: t(operator),
659 /**
660 Type-related [operator](#highlight.tags.operator).
661 */
662 typeOperator: t(operator),
663 /**
664 Control-flow [operator](#highlight.tags.operator).
665 */
666 controlOperator: t(operator),
667 /**
668 Program or markup punctuation.
669 */
670 punctuation,
671 /**
672 [Punctuation](#highlight.tags.punctuation) that separates
673 things.
674 */
675 separator: t(punctuation),
676 /**
677 Bracket-style [punctuation](#highlight.tags.punctuation).
678 */
679 bracket,
680 /**
681 Angle [brackets](#highlight.tags.bracket) (usually `<` and `>`
682 tokens).
683 */
684 angleBracket: t(bracket),
685 /**
686 Square [brackets](#highlight.tags.bracket) (usually `[` and `]`
687 tokens).
688 */
689 squareBracket: t(bracket),
690 /**
691 Parentheses (usually `(` and `)` tokens). Subtag of
692 [bracket](#highlight.tags.bracket).
693 */
694 paren: t(bracket),
695 /**
696 Braces (usually `{` and `}` tokens). Subtag of
697 [bracket](#highlight.tags.bracket).
698 */
699 brace: t(bracket),
700 /**
701 Content, for example plain text in XML or markup documents.
702 */
703 content,
704 /**
705 [Content](#highlight.tags.content) that represents a heading.
706 */
707 heading,
708 /**
709 A level 1 [heading](#highlight.tags.heading).
710 */
711 heading1: t(heading),
712 /**
713 A level 2 [heading](#highlight.tags.heading).
714 */
715 heading2: t(heading),
716 /**
717 A level 3 [heading](#highlight.tags.heading).
718 */
719 heading3: t(heading),
720 /**
721 A level 4 [heading](#highlight.tags.heading).
722 */
723 heading4: t(heading),
724 /**
725 A level 5 [heading](#highlight.tags.heading).
726 */
727 heading5: t(heading),
728 /**
729 A level 6 [heading](#highlight.tags.heading).
730 */
731 heading6: t(heading),
732 /**
733 A prose [content](#highlight.tags.content) separator (such as a horizontal rule).
734 */
735 contentSeparator: t(content),
736 /**
737 [Content](#highlight.tags.content) that represents a list.
738 */
739 list: t(content),
740 /**
741 [Content](#highlight.tags.content) that represents a quote.
742 */
743 quote: t(content),
744 /**
745 [Content](#highlight.tags.content) that is emphasized.
746 */
747 emphasis: t(content),
748 /**
749 [Content](#highlight.tags.content) that is styled strong.
750 */
751 strong: t(content),
752 /**
753 [Content](#highlight.tags.content) that is part of a link.
754 */
755 link: t(content),
756 /**
757 [Content](#highlight.tags.content) that is styled as code or
758 monospace.
759 */
760 monospace: t(content),
761 /**
762 [Content](#highlight.tags.content) that has a strike-through
763 style.
764 */
765 strikethrough: t(content),
766 /**
767 Inserted text in a change-tracking format.
768 */
769 inserted: t(),
770 /**
771 Deleted text.
772 */
773 deleted: t(),
774 /**
775 Changed text.
776 */
777 changed: t(),
778 /**
779 An invalid or unsyntactic element.
780 */
781 invalid: t(),
782 /**
783 Metadata or meta-instruction.
784 */
785 meta,
786 /**
787 [Metadata](#highlight.tags.meta) that applies to the entire
788 document.
789 */
790 documentMeta: t(meta),
791 /**
792 [Metadata](#highlight.tags.meta) that annotates or adds
793 attributes to a given syntactic element.
794 */
795 annotation: t(meta),
796 /**
797 Processing instruction or preprocessor directive. Subtag of
798 [meta](#highlight.tags.meta).
799 */
800 processingInstruction: t(meta),
801 /**
802 [Modifier](#highlight.Tag^defineModifier) that indicates that a
803 given element is being defined. Expected to be used with the
804 various [name](#highlight.tags.name) tags.
805 */
806 definition: Tag.defineModifier("definition"),
807 /**
808 [Modifier](#highlight.Tag^defineModifier) that indicates that
809 something is constant. Mostly expected to be used with
810 [variable names](#highlight.tags.variableName).
811 */
812 constant: Tag.defineModifier("constant"),
813 /**
814 [Modifier](#highlight.Tag^defineModifier) used to indicate that
815 a [variable](#highlight.tags.variableName) or [property
816 name](#highlight.tags.propertyName) is being called or defined
817 as a function.
818 */
819 function: Tag.defineModifier("function"),
820 /**
821 [Modifier](#highlight.Tag^defineModifier) that can be applied to
822 [names](#highlight.tags.name) to indicate that they belong to
823 the language's standard environment.
824 */
825 standard: Tag.defineModifier("standard"),
826 /**
827 [Modifier](#highlight.Tag^defineModifier) that indicates a given
828 [names](#highlight.tags.name) is local to some scope.
829 */
830 local: Tag.defineModifier("local"),
831 /**
832 A generic variant [modifier](#highlight.Tag^defineModifier) that
833 can be used to tag language-specific alternative variants of
834 some common tag. It is recommended for themes to define special
835 forms of at least the [string](#highlight.tags.string) and
836 [variable name](#highlight.tags.variableName) tags, since those
837 come up a lot.
838 */
839 special: Tag.defineModifier("special")
840};
841for (let name in tags) {
842 let val = tags[name];
843 if (val instanceof Tag)
844 val.name = name;
845}
846/**
847This is a highlighter that adds stable, predictable classes to
848tokens, for styling with external CSS.
849
850The following tags are mapped to their name prefixed with `"tok-"`
851(for example `"tok-comment"`):
852
853* [`link`](#highlight.tags.link)
854* [`heading`](#highlight.tags.heading)
855* [`emphasis`](#highlight.tags.emphasis)
856* [`strong`](#highlight.tags.strong)
857* [`keyword`](#highlight.tags.keyword)
858* [`atom`](#highlight.tags.atom)
859* [`bool`](#highlight.tags.bool)
860* [`url`](#highlight.tags.url)
861* [`labelName`](#highlight.tags.labelName)
862* [`inserted`](#highlight.tags.inserted)
863* [`deleted`](#highlight.tags.deleted)
864* [`literal`](#highlight.tags.literal)
865* [`string`](#highlight.tags.string)
866* [`number`](#highlight.tags.number)
867* [`variableName`](#highlight.tags.variableName)
868* [`typeName`](#highlight.tags.typeName)
869* [`namespace`](#highlight.tags.namespace)
870* [`className`](#highlight.tags.className)
871* [`macroName`](#highlight.tags.macroName)
872* [`propertyName`](#highlight.tags.propertyName)
873* [`operator`](#highlight.tags.operator)
874* [`comment`](#highlight.tags.comment)
875* [`meta`](#highlight.tags.meta)
876* [`punctuation`](#highlight.tags.punctuation)
877* [`invalid`](#highlight.tags.invalid)
878
879In addition, these mappings are provided:
880
881* [`regexp`](#highlight.tags.regexp),
882 [`escape`](#highlight.tags.escape), and
883 [`special`](#highlight.tags.special)[`(string)`](#highlight.tags.string)
884 are mapped to `"tok-string2"`
885* [`special`](#highlight.tags.special)[`(variableName)`](#highlight.tags.variableName)
886 to `"tok-variableName2"`
887* [`local`](#highlight.tags.local)[`(variableName)`](#highlight.tags.variableName)
888 to `"tok-variableName tok-local"`
889* [`definition`](#highlight.tags.definition)[`(variableName)`](#highlight.tags.variableName)
890 to `"tok-variableName tok-definition"`
891* [`definition`](#highlight.tags.definition)[`(propertyName)`](#highlight.tags.propertyName)
892 to `"tok-propertyName tok-definition"`
893*/
894const classHighlighter = tagHighlighter([
895 { tag: tags.link, class: "tok-link" },
896 { tag: tags.heading, class: "tok-heading" },
897 { tag: tags.emphasis, class: "tok-emphasis" },
898 { tag: tags.strong, class: "tok-strong" },
899 { tag: tags.keyword, class: "tok-keyword" },
900 { tag: tags.atom, class: "tok-atom" },
901 { tag: tags.bool, class: "tok-bool" },
902 { tag: tags.url, class: "tok-url" },
903 { tag: tags.labelName, class: "tok-labelName" },
904 { tag: tags.inserted, class: "tok-inserted" },
905 { tag: tags.deleted, class: "tok-deleted" },
906 { tag: tags.literal, class: "tok-literal" },
907 { tag: tags.string, class: "tok-string" },
908 { tag: tags.number, class: "tok-number" },
909 { tag: [tags.regexp, tags.escape, tags.special(tags.string)], class: "tok-string2" },
910 { tag: tags.variableName, class: "tok-variableName" },
911 { tag: tags.local(tags.variableName), class: "tok-variableName tok-local" },
912 { tag: tags.definition(tags.variableName), class: "tok-variableName tok-definition" },
913 { tag: tags.special(tags.variableName), class: "tok-variableName2" },
914 { tag: tags.definition(tags.propertyName), class: "tok-propertyName tok-definition" },
915 { tag: tags.typeName, class: "tok-typeName" },
916 { tag: tags.namespace, class: "tok-namespace" },
917 { tag: tags.className, class: "tok-className" },
918 { tag: tags.macroName, class: "tok-macroName" },
919 { tag: tags.propertyName, class: "tok-propertyName" },
920 { tag: tags.operator, class: "tok-operator" },
921 { tag: tags.comment, class: "tok-comment" },
922 { tag: tags.meta, class: "tok-meta" },
923 { tag: tags.invalid, class: "tok-invalid" },
924 { tag: tags.punctuation, class: "tok-punctuation" }
925]);
926
927export { Tag, classHighlighter, getStyleTags, highlightCode, highlightTree, styleTags, tagHighlighter, tags };