You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
927 lines
29 KiB
927 lines
29 KiB
import { NodeProp } from '@lezer/common'; |
|
|
|
let nextTagID = 0; |
|
/** |
|
Highlighting tags are markers that denote a highlighting category. |
|
They are [associated](#highlight.styleTags) with parts of a syntax |
|
tree by a language mode, and then mapped to an actual CSS style by |
|
a [highlighter](#highlight.Highlighter). |
|
|
|
Because syntax tree node types and highlight styles have to be |
|
able to talk the same language, CodeMirror uses a mostly _closed_ |
|
[vocabulary](#highlight.tags) of syntax tags (as opposed to |
|
traditional open string-based systems, which make it hard for |
|
highlighting themes to cover all the tokens produced by the |
|
various languages). |
|
|
|
It _is_ possible to [define](#highlight.Tag^define) your own |
|
highlighting tags for system-internal use (where you control both |
|
the language package and the highlighter), but such tags will not |
|
be picked up by regular highlighters (though you can derive them |
|
from standard tags to allow highlighters to fall back to those). |
|
*/ |
|
class Tag { |
|
/** |
|
@internal |
|
*/ |
|
constructor( |
|
/** |
|
The optional name of the base tag @internal |
|
*/ |
|
name, |
|
/** |
|
The set of this tag and all its parent tags, starting with |
|
this one itself and sorted in order of decreasing specificity. |
|
*/ |
|
set, |
|
/** |
|
The base unmodified tag that this one is based on, if it's |
|
modified @internal |
|
*/ |
|
base, |
|
/** |
|
The modifiers applied to this.base @internal |
|
*/ |
|
modified) { |
|
this.name = name; |
|
this.set = set; |
|
this.base = base; |
|
this.modified = modified; |
|
/** |
|
@internal |
|
*/ |
|
this.id = nextTagID++; |
|
} |
|
toString() { |
|
let { name } = this; |
|
for (let mod of this.modified) |
|
if (mod.name) |
|
name = `${mod.name}(${name})`; |
|
return name; |
|
} |
|
static define(nameOrParent, parent) { |
|
let name = typeof nameOrParent == "string" ? nameOrParent : "?"; |
|
if (nameOrParent instanceof Tag) |
|
parent = nameOrParent; |
|
if (parent === null || parent === void 0 ? void 0 : parent.base) |
|
throw new Error("Can not derive from a modified tag"); |
|
let tag = new Tag(name, [], null, []); |
|
tag.set.push(tag); |
|
if (parent) |
|
for (let t of parent.set) |
|
tag.set.push(t); |
|
return tag; |
|
} |
|
/** |
|
Define a tag _modifier_, which is a function that, given a tag, |
|
will return a tag that is a subtag of the original. Applying the |
|
same modifier to a twice tag will return the same value (`m1(t1) |
|
== m1(t1)`) and applying multiple modifiers will, regardless or |
|
order, produce the same tag (`m1(m2(t1)) == m2(m1(t1))`). |
|
|
|
When multiple modifiers are applied to a given base tag, each |
|
smaller set of modifiers is registered as a parent, so that for |
|
example `m1(m2(m3(t1)))` is a subtype of `m1(m2(t1))`, |
|
`m1(m3(t1)`, and so on. |
|
*/ |
|
static defineModifier(name) { |
|
let mod = new Modifier(name); |
|
return (tag) => { |
|
if (tag.modified.indexOf(mod) > -1) |
|
return tag; |
|
return Modifier.get(tag.base || tag, tag.modified.concat(mod).sort((a, b) => a.id - b.id)); |
|
}; |
|
} |
|
} |
|
let nextModifierID = 0; |
|
class Modifier { |
|
constructor(name) { |
|
this.name = name; |
|
this.instances = []; |
|
this.id = nextModifierID++; |
|
} |
|
static get(base, mods) { |
|
if (!mods.length) |
|
return base; |
|
let exists = mods[0].instances.find(t => t.base == base && sameArray(mods, t.modified)); |
|
if (exists) |
|
return exists; |
|
let set = [], tag = new Tag(base.name, set, base, mods); |
|
for (let m of mods) |
|
m.instances.push(tag); |
|
let configs = powerSet(mods); |
|
for (let parent of base.set) |
|
if (!parent.modified.length) |
|
for (let config of configs) |
|
set.push(Modifier.get(parent, config)); |
|
return tag; |
|
} |
|
} |
|
function sameArray(a, b) { |
|
return a.length == b.length && a.every((x, i) => x == b[i]); |
|
} |
|
function powerSet(array) { |
|
let sets = [[]]; |
|
for (let i = 0; i < array.length; i++) { |
|
for (let j = 0, e = sets.length; j < e; j++) { |
|
sets.push(sets[j].concat(array[i])); |
|
} |
|
} |
|
return sets.sort((a, b) => b.length - a.length); |
|
} |
|
/** |
|
This function is used to add a set of tags to a language syntax |
|
via [`NodeSet.extend`](#common.NodeSet.extend) or |
|
[`LRParser.configure`](#lr.LRParser.configure). |
|
|
|
The argument object maps node selectors to [highlighting |
|
tags](#highlight.Tag) or arrays of tags. |
|
|
|
Node selectors may hold one or more (space-separated) node paths. |
|
Such a path can be a [node name](#common.NodeType.name), or |
|
multiple node names (or `*` wildcards) separated by slash |
|
characters, as in `"Block/Declaration/VariableName"`. Such a path |
|
matches the final node but only if its direct parent nodes are the |
|
other nodes mentioned. A `*` in such a path matches any parent, |
|
but only a single level—wildcards that match multiple parents |
|
aren't supported, both for efficiency reasons and because Lezer |
|
trees make it rather hard to reason about what they would match.) |
|
|
|
A path can be ended with `/...` to indicate that the tag assigned |
|
to the node should also apply to all child nodes, even if they |
|
match their own style (by default, only the innermost style is |
|
used). |
|
|
|
When a path ends in `!`, as in `Attribute!`, no further matching |
|
happens for the node's child nodes, and the entire node gets the |
|
given style. |
|
|
|
In this notation, node names that contain `/`, `!`, `*`, or `...` |
|
must be quoted as JSON strings. |
|
|
|
For example: |
|
|
|
```javascript |
|
parser.configure({props: [ |
|
styleTags({ |
|
// Style Number and BigNumber nodes |
|
"Number BigNumber": tags.number, |
|
// Style Escape nodes whose parent is String |
|
"String/Escape": tags.escape, |
|
// Style anything inside Attributes nodes |
|
"Attributes!": tags.meta, |
|
// Add a style to all content inside Italic nodes |
|
"Italic/...": tags.emphasis, |
|
// Style InvalidString nodes as both `string` and `invalid` |
|
"InvalidString": [tags.string, tags.invalid], |
|
// Style the node named "/" as punctuation |
|
'"/"': tags.punctuation |
|
}) |
|
]}) |
|
``` |
|
*/ |
|
function styleTags(spec) { |
|
let byName = Object.create(null); |
|
for (let prop in spec) { |
|
let tags = spec[prop]; |
|
if (!Array.isArray(tags)) |
|
tags = [tags]; |
|
for (let part of prop.split(" ")) |
|
if (part) { |
|
let pieces = [], mode = 2 /* Mode.Normal */, rest = part; |
|
for (let pos = 0;;) { |
|
if (rest == "..." && pos > 0 && pos + 3 == part.length) { |
|
mode = 1 /* Mode.Inherit */; |
|
break; |
|
} |
|
let m = /^"(?:[^"\\]|\\.)*?"|[^\/!]+/.exec(rest); |
|
if (!m) |
|
throw new RangeError("Invalid path: " + part); |
|
pieces.push(m[0] == "*" ? "" : m[0][0] == '"' ? JSON.parse(m[0]) : m[0]); |
|
pos += m[0].length; |
|
if (pos == part.length) |
|
break; |
|
let next = part[pos++]; |
|
if (pos == part.length && next == "!") { |
|
mode = 0 /* Mode.Opaque */; |
|
break; |
|
} |
|
if (next != "/") |
|
throw new RangeError("Invalid path: " + part); |
|
rest = part.slice(pos); |
|
} |
|
let last = pieces.length - 1, inner = pieces[last]; |
|
if (!inner) |
|
throw new RangeError("Invalid path: " + part); |
|
let rule = new Rule(tags, mode, last > 0 ? pieces.slice(0, last) : null); |
|
byName[inner] = rule.sort(byName[inner]); |
|
} |
|
} |
|
return ruleNodeProp.add(byName); |
|
} |
|
const ruleNodeProp = new NodeProp({ |
|
combine(a, b) { |
|
let cur, root, take; |
|
while (a || b) { |
|
if (!a || b && a.depth >= b.depth) { |
|
take = b; |
|
b = b.next; |
|
} |
|
else { |
|
take = a; |
|
a = a.next; |
|
} |
|
if (cur && cur.mode == take.mode && !take.context && !cur.context) |
|
continue; |
|
let copy = new Rule(take.tags, take.mode, take.context); |
|
if (cur) |
|
cur.next = copy; |
|
else |
|
root = copy; |
|
cur = copy; |
|
} |
|
return root; |
|
} |
|
}); |
|
class Rule { |
|
constructor(tags, mode, context, next) { |
|
this.tags = tags; |
|
this.mode = mode; |
|
this.context = context; |
|
this.next = next; |
|
} |
|
get opaque() { return this.mode == 0 /* Mode.Opaque */; } |
|
get inherit() { return this.mode == 1 /* Mode.Inherit */; } |
|
sort(other) { |
|
if (!other || other.depth < this.depth) { |
|
this.next = other; |
|
return this; |
|
} |
|
other.next = this.sort(other.next); |
|
return other; |
|
} |
|
get depth() { return this.context ? this.context.length : 0; } |
|
} |
|
Rule.empty = new Rule([], 2 /* Mode.Normal */, null); |
|
/** |
|
Define a [highlighter](#highlight.Highlighter) from an array of |
|
tag/class pairs. Classes associated with more specific tags will |
|
take precedence. |
|
*/ |
|
function tagHighlighter(tags, options) { |
|
let map = Object.create(null); |
|
for (let style of tags) { |
|
if (!Array.isArray(style.tag)) |
|
map[style.tag.id] = style.class; |
|
else |
|
for (let tag of style.tag) |
|
map[tag.id] = style.class; |
|
} |
|
let { scope, all = null } = options || {}; |
|
return { |
|
style: (tags) => { |
|
let cls = all; |
|
for (let tag of tags) { |
|
for (let sub of tag.set) { |
|
let tagClass = map[sub.id]; |
|
if (tagClass) { |
|
cls = cls ? cls + " " + tagClass : tagClass; |
|
break; |
|
} |
|
} |
|
} |
|
return cls; |
|
}, |
|
scope |
|
}; |
|
} |
|
function highlightTags(highlighters, tags) { |
|
let result = null; |
|
for (let highlighter of highlighters) { |
|
let value = highlighter.style(tags); |
|
if (value) |
|
result = result ? result + " " + value : value; |
|
} |
|
return result; |
|
} |
|
/** |
|
Highlight the given [tree](#common.Tree) with the given |
|
[highlighter](#highlight.Highlighter). Often, the higher-level |
|
[`highlightCode`](#highlight.highlightCode) function is easier to |
|
use. |
|
*/ |
|
function highlightTree(tree, highlighter, |
|
/** |
|
Assign styling to a region of the text. Will be called, in order |
|
of position, for any ranges where more than zero classes apply. |
|
`classes` is a space separated string of CSS classes. |
|
*/ |
|
putStyle, |
|
/** |
|
The start of the range to highlight. |
|
*/ |
|
from = 0, |
|
/** |
|
The end of the range. |
|
*/ |
|
to = tree.length) { |
|
let builder = new HighlightBuilder(from, Array.isArray(highlighter) ? highlighter : [highlighter], putStyle); |
|
builder.highlightRange(tree.cursor(), from, to, "", builder.highlighters); |
|
builder.flush(to); |
|
} |
|
/** |
|
Highlight the given tree with the given highlighter, calling |
|
`putText` for every piece of text, either with a set of classes or |
|
with the empty string when unstyled, and `putBreak` for every line |
|
break. |
|
*/ |
|
function highlightCode(code, tree, highlighter, putText, putBreak, from = 0, to = code.length) { |
|
let pos = from; |
|
function writeTo(p, classes) { |
|
if (p <= pos) |
|
return; |
|
for (let text = code.slice(pos, p), i = 0;;) { |
|
let nextBreak = text.indexOf("\n", i); |
|
let upto = nextBreak < 0 ? text.length : nextBreak; |
|
if (upto > i) |
|
putText(text.slice(i, upto), classes); |
|
if (nextBreak < 0) |
|
break; |
|
putBreak(); |
|
i = nextBreak + 1; |
|
} |
|
pos = p; |
|
} |
|
highlightTree(tree, highlighter, (from, to, classes) => { |
|
writeTo(from, ""); |
|
writeTo(to, classes); |
|
}, from, to); |
|
writeTo(to, ""); |
|
} |
|
class HighlightBuilder { |
|
constructor(at, highlighters, span) { |
|
this.at = at; |
|
this.highlighters = highlighters; |
|
this.span = span; |
|
this.class = ""; |
|
} |
|
startSpan(at, cls) { |
|
if (cls != this.class) { |
|
this.flush(at); |
|
if (at > this.at) |
|
this.at = at; |
|
this.class = cls; |
|
} |
|
} |
|
flush(to) { |
|
if (to > this.at && this.class) |
|
this.span(this.at, to, this.class); |
|
} |
|
highlightRange(cursor, from, to, inheritedClass, highlighters) { |
|
let { type, from: start, to: end } = cursor; |
|
if (start >= to || end <= from) |
|
return; |
|
if (type.isTop) |
|
highlighters = this.highlighters.filter(h => !h.scope || h.scope(type)); |
|
let cls = inheritedClass; |
|
let rule = getStyleTags(cursor) || Rule.empty; |
|
let tagCls = highlightTags(highlighters, rule.tags); |
|
if (tagCls) { |
|
if (cls) |
|
cls += " "; |
|
cls += tagCls; |
|
if (rule.mode == 1 /* Mode.Inherit */) |
|
inheritedClass += (inheritedClass ? " " : "") + tagCls; |
|
} |
|
this.startSpan(Math.max(from, start), cls); |
|
if (rule.opaque) |
|
return; |
|
let mounted = cursor.tree && cursor.tree.prop(NodeProp.mounted); |
|
if (mounted && mounted.overlay) { |
|
let inner = cursor.node.enter(mounted.overlay[0].from + start, 1); |
|
let innerHighlighters = this.highlighters.filter(h => !h.scope || h.scope(mounted.tree.type)); |
|
let hasChild = cursor.firstChild(); |
|
for (let i = 0, pos = start;; i++) { |
|
let next = i < mounted.overlay.length ? mounted.overlay[i] : null; |
|
let nextPos = next ? next.from + start : end; |
|
let rangeFrom = Math.max(from, pos), rangeTo = Math.min(to, nextPos); |
|
if (rangeFrom < rangeTo && hasChild) { |
|
while (cursor.from < rangeTo) { |
|
this.highlightRange(cursor, rangeFrom, rangeTo, inheritedClass, highlighters); |
|
this.startSpan(Math.min(rangeTo, cursor.to), cls); |
|
if (cursor.to >= nextPos || !cursor.nextSibling()) |
|
break; |
|
} |
|
} |
|
if (!next || nextPos > to) |
|
break; |
|
pos = next.to + start; |
|
if (pos > from) { |
|
this.highlightRange(inner.cursor(), Math.max(from, next.from + start), Math.min(to, pos), "", innerHighlighters); |
|
this.startSpan(Math.min(to, pos), cls); |
|
} |
|
} |
|
if (hasChild) |
|
cursor.parent(); |
|
} |
|
else if (cursor.firstChild()) { |
|
if (mounted) |
|
inheritedClass = ""; |
|
do { |
|
if (cursor.to <= from) |
|
continue; |
|
if (cursor.from >= to) |
|
break; |
|
this.highlightRange(cursor, from, to, inheritedClass, highlighters); |
|
this.startSpan(Math.min(to, cursor.to), cls); |
|
} while (cursor.nextSibling()); |
|
cursor.parent(); |
|
} |
|
} |
|
} |
|
/** |
|
Match a syntax node's [highlight rules](#highlight.styleTags). If |
|
there's a match, return its set of tags, and whether it is |
|
opaque (uses a `!`) or applies to all child nodes (`/...`). |
|
*/ |
|
function getStyleTags(node) { |
|
let rule = node.type.prop(ruleNodeProp); |
|
while (rule && rule.context && !node.matchContext(rule.context)) |
|
rule = rule.next; |
|
return rule || null; |
|
} |
|
const t = Tag.define; |
|
const 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(); |
|
/** |
|
The default set of highlighting [tags](#highlight.Tag). |
|
|
|
This collection is heavily biased towards programming languages, |
|
and necessarily incomplete. A full ontology of syntactic |
|
constructs would fill a stack of books, and be impractical to |
|
write themes for. So try to make do with this set. If all else |
|
fails, [open an |
|
issue](https://github.com/codemirror/codemirror.next) to propose a |
|
new tag, or [define](#highlight.Tag^define) a local custom tag for |
|
your use case. |
|
|
|
Note that it is not obligatory to always attach the most specific |
|
tag possible to an element—if your grammar can't easily |
|
distinguish a certain type of element (such as a local variable), |
|
it is okay to style it as its more general variant (a variable). |
|
|
|
For tags that extend some parent tag, the documentation links to |
|
the parent. |
|
*/ |
|
const tags = { |
|
/** |
|
A comment. |
|
*/ |
|
comment, |
|
/** |
|
A line [comment](#highlight.tags.comment). |
|
*/ |
|
lineComment: t(comment), |
|
/** |
|
A block [comment](#highlight.tags.comment). |
|
*/ |
|
blockComment: t(comment), |
|
/** |
|
A documentation [comment](#highlight.tags.comment). |
|
*/ |
|
docComment: t(comment), |
|
/** |
|
Any kind of identifier. |
|
*/ |
|
name, |
|
/** |
|
The [name](#highlight.tags.name) of a variable. |
|
*/ |
|
variableName: t(name), |
|
/** |
|
A type [name](#highlight.tags.name). |
|
*/ |
|
typeName: typeName, |
|
/** |
|
A tag name (subtag of [`typeName`](#highlight.tags.typeName)). |
|
*/ |
|
tagName: t(typeName), |
|
/** |
|
A property or field [name](#highlight.tags.name). |
|
*/ |
|
propertyName: propertyName, |
|
/** |
|
An attribute name (subtag of [`propertyName`](#highlight.tags.propertyName)). |
|
*/ |
|
attributeName: t(propertyName), |
|
/** |
|
The [name](#highlight.tags.name) of a class. |
|
*/ |
|
className: t(name), |
|
/** |
|
A label [name](#highlight.tags.name). |
|
*/ |
|
labelName: t(name), |
|
/** |
|
A namespace [name](#highlight.tags.name). |
|
*/ |
|
namespace: t(name), |
|
/** |
|
The [name](#highlight.tags.name) of a macro. |
|
*/ |
|
macroName: t(name), |
|
/** |
|
A literal value. |
|
*/ |
|
literal, |
|
/** |
|
A string [literal](#highlight.tags.literal). |
|
*/ |
|
string, |
|
/** |
|
A documentation [string](#highlight.tags.string). |
|
*/ |
|
docString: t(string), |
|
/** |
|
A character literal (subtag of [string](#highlight.tags.string)). |
|
*/ |
|
character: t(string), |
|
/** |
|
An attribute value (subtag of [string](#highlight.tags.string)). |
|
*/ |
|
attributeValue: t(string), |
|
/** |
|
A number [literal](#highlight.tags.literal). |
|
*/ |
|
number, |
|
/** |
|
An integer [number](#highlight.tags.number) literal. |
|
*/ |
|
integer: t(number), |
|
/** |
|
A floating-point [number](#highlight.tags.number) literal. |
|
*/ |
|
float: t(number), |
|
/** |
|
A boolean [literal](#highlight.tags.literal). |
|
*/ |
|
bool: t(literal), |
|
/** |
|
Regular expression [literal](#highlight.tags.literal). |
|
*/ |
|
regexp: t(literal), |
|
/** |
|
An escape [literal](#highlight.tags.literal), for example a |
|
backslash escape in a string. |
|
*/ |
|
escape: t(literal), |
|
/** |
|
A color [literal](#highlight.tags.literal). |
|
*/ |
|
color: t(literal), |
|
/** |
|
A URL [literal](#highlight.tags.literal). |
|
*/ |
|
url: t(literal), |
|
/** |
|
A language keyword. |
|
*/ |
|
keyword, |
|
/** |
|
The [keyword](#highlight.tags.keyword) for the self or this |
|
object. |
|
*/ |
|
self: t(keyword), |
|
/** |
|
The [keyword](#highlight.tags.keyword) for null. |
|
*/ |
|
null: t(keyword), |
|
/** |
|
A [keyword](#highlight.tags.keyword) denoting some atomic value. |
|
*/ |
|
atom: t(keyword), |
|
/** |
|
A [keyword](#highlight.tags.keyword) that represents a unit. |
|
*/ |
|
unit: t(keyword), |
|
/** |
|
A modifier [keyword](#highlight.tags.keyword). |
|
*/ |
|
modifier: t(keyword), |
|
/** |
|
A [keyword](#highlight.tags.keyword) that acts as an operator. |
|
*/ |
|
operatorKeyword: t(keyword), |
|
/** |
|
A control-flow related [keyword](#highlight.tags.keyword). |
|
*/ |
|
controlKeyword: t(keyword), |
|
/** |
|
A [keyword](#highlight.tags.keyword) that defines something. |
|
*/ |
|
definitionKeyword: t(keyword), |
|
/** |
|
A [keyword](#highlight.tags.keyword) related to defining or |
|
interfacing with modules. |
|
*/ |
|
moduleKeyword: t(keyword), |
|
/** |
|
An operator. |
|
*/ |
|
operator, |
|
/** |
|
An [operator](#highlight.tags.operator) that dereferences something. |
|
*/ |
|
derefOperator: t(operator), |
|
/** |
|
Arithmetic-related [operator](#highlight.tags.operator). |
|
*/ |
|
arithmeticOperator: t(operator), |
|
/** |
|
Logical [operator](#highlight.tags.operator). |
|
*/ |
|
logicOperator: t(operator), |
|
/** |
|
Bit [operator](#highlight.tags.operator). |
|
*/ |
|
bitwiseOperator: t(operator), |
|
/** |
|
Comparison [operator](#highlight.tags.operator). |
|
*/ |
|
compareOperator: t(operator), |
|
/** |
|
[Operator](#highlight.tags.operator) that updates its operand. |
|
*/ |
|
updateOperator: t(operator), |
|
/** |
|
[Operator](#highlight.tags.operator) that defines something. |
|
*/ |
|
definitionOperator: t(operator), |
|
/** |
|
Type-related [operator](#highlight.tags.operator). |
|
*/ |
|
typeOperator: t(operator), |
|
/** |
|
Control-flow [operator](#highlight.tags.operator). |
|
*/ |
|
controlOperator: t(operator), |
|
/** |
|
Program or markup punctuation. |
|
*/ |
|
punctuation, |
|
/** |
|
[Punctuation](#highlight.tags.punctuation) that separates |
|
things. |
|
*/ |
|
separator: t(punctuation), |
|
/** |
|
Bracket-style [punctuation](#highlight.tags.punctuation). |
|
*/ |
|
bracket, |
|
/** |
|
Angle [brackets](#highlight.tags.bracket) (usually `<` and `>` |
|
tokens). |
|
*/ |
|
angleBracket: t(bracket), |
|
/** |
|
Square [brackets](#highlight.tags.bracket) (usually `[` and `]` |
|
tokens). |
|
*/ |
|
squareBracket: t(bracket), |
|
/** |
|
Parentheses (usually `(` and `)` tokens). Subtag of |
|
[bracket](#highlight.tags.bracket). |
|
*/ |
|
paren: t(bracket), |
|
/** |
|
Braces (usually `{` and `}` tokens). Subtag of |
|
[bracket](#highlight.tags.bracket). |
|
*/ |
|
brace: t(bracket), |
|
/** |
|
Content, for example plain text in XML or markup documents. |
|
*/ |
|
content, |
|
/** |
|
[Content](#highlight.tags.content) that represents a heading. |
|
*/ |
|
heading, |
|
/** |
|
A level 1 [heading](#highlight.tags.heading). |
|
*/ |
|
heading1: t(heading), |
|
/** |
|
A level 2 [heading](#highlight.tags.heading). |
|
*/ |
|
heading2: t(heading), |
|
/** |
|
A level 3 [heading](#highlight.tags.heading). |
|
*/ |
|
heading3: t(heading), |
|
/** |
|
A level 4 [heading](#highlight.tags.heading). |
|
*/ |
|
heading4: t(heading), |
|
/** |
|
A level 5 [heading](#highlight.tags.heading). |
|
*/ |
|
heading5: t(heading), |
|
/** |
|
A level 6 [heading](#highlight.tags.heading). |
|
*/ |
|
heading6: t(heading), |
|
/** |
|
A prose [content](#highlight.tags.content) separator (such as a horizontal rule). |
|
*/ |
|
contentSeparator: t(content), |
|
/** |
|
[Content](#highlight.tags.content) that represents a list. |
|
*/ |
|
list: t(content), |
|
/** |
|
[Content](#highlight.tags.content) that represents a quote. |
|
*/ |
|
quote: t(content), |
|
/** |
|
[Content](#highlight.tags.content) that is emphasized. |
|
*/ |
|
emphasis: t(content), |
|
/** |
|
[Content](#highlight.tags.content) that is styled strong. |
|
*/ |
|
strong: t(content), |
|
/** |
|
[Content](#highlight.tags.content) that is part of a link. |
|
*/ |
|
link: t(content), |
|
/** |
|
[Content](#highlight.tags.content) that is styled as code or |
|
monospace. |
|
*/ |
|
monospace: t(content), |
|
/** |
|
[Content](#highlight.tags.content) that has a strike-through |
|
style. |
|
*/ |
|
strikethrough: t(content), |
|
/** |
|
Inserted text in a change-tracking format. |
|
*/ |
|
inserted: t(), |
|
/** |
|
Deleted text. |
|
*/ |
|
deleted: t(), |
|
/** |
|
Changed text. |
|
*/ |
|
changed: t(), |
|
/** |
|
An invalid or unsyntactic element. |
|
*/ |
|
invalid: t(), |
|
/** |
|
Metadata or meta-instruction. |
|
*/ |
|
meta, |
|
/** |
|
[Metadata](#highlight.tags.meta) that applies to the entire |
|
document. |
|
*/ |
|
documentMeta: t(meta), |
|
/** |
|
[Metadata](#highlight.tags.meta) that annotates or adds |
|
attributes to a given syntactic element. |
|
*/ |
|
annotation: t(meta), |
|
/** |
|
Processing instruction or preprocessor directive. Subtag of |
|
[meta](#highlight.tags.meta). |
|
*/ |
|
processingInstruction: t(meta), |
|
/** |
|
[Modifier](#highlight.Tag^defineModifier) that indicates that a |
|
given element is being defined. Expected to be used with the |
|
various [name](#highlight.tags.name) tags. |
|
*/ |
|
definition: Tag.defineModifier("definition"), |
|
/** |
|
[Modifier](#highlight.Tag^defineModifier) that indicates that |
|
something is constant. Mostly expected to be used with |
|
[variable names](#highlight.tags.variableName). |
|
*/ |
|
constant: Tag.defineModifier("constant"), |
|
/** |
|
[Modifier](#highlight.Tag^defineModifier) used to indicate that |
|
a [variable](#highlight.tags.variableName) or [property |
|
name](#highlight.tags.propertyName) is being called or defined |
|
as a function. |
|
*/ |
|
function: Tag.defineModifier("function"), |
|
/** |
|
[Modifier](#highlight.Tag^defineModifier) that can be applied to |
|
[names](#highlight.tags.name) to indicate that they belong to |
|
the language's standard environment. |
|
*/ |
|
standard: Tag.defineModifier("standard"), |
|
/** |
|
[Modifier](#highlight.Tag^defineModifier) that indicates a given |
|
[names](#highlight.tags.name) is local to some scope. |
|
*/ |
|
local: Tag.defineModifier("local"), |
|
/** |
|
A generic variant [modifier](#highlight.Tag^defineModifier) that |
|
can be used to tag language-specific alternative variants of |
|
some common tag. It is recommended for themes to define special |
|
forms of at least the [string](#highlight.tags.string) and |
|
[variable name](#highlight.tags.variableName) tags, since those |
|
come up a lot. |
|
*/ |
|
special: Tag.defineModifier("special") |
|
}; |
|
for (let name in tags) { |
|
let val = tags[name]; |
|
if (val instanceof Tag) |
|
val.name = name; |
|
} |
|
/** |
|
This is a highlighter that adds stable, predictable classes to |
|
tokens, for styling with external CSS. |
|
|
|
The following tags are mapped to their name prefixed with `"tok-"` |
|
(for example `"tok-comment"`): |
|
|
|
* [`link`](#highlight.tags.link) |
|
* [`heading`](#highlight.tags.heading) |
|
* [`emphasis`](#highlight.tags.emphasis) |
|
* [`strong`](#highlight.tags.strong) |
|
* [`keyword`](#highlight.tags.keyword) |
|
* [`atom`](#highlight.tags.atom) |
|
* [`bool`](#highlight.tags.bool) |
|
* [`url`](#highlight.tags.url) |
|
* [`labelName`](#highlight.tags.labelName) |
|
* [`inserted`](#highlight.tags.inserted) |
|
* [`deleted`](#highlight.tags.deleted) |
|
* [`literal`](#highlight.tags.literal) |
|
* [`string`](#highlight.tags.string) |
|
* [`number`](#highlight.tags.number) |
|
* [`variableName`](#highlight.tags.variableName) |
|
* [`typeName`](#highlight.tags.typeName) |
|
* [`namespace`](#highlight.tags.namespace) |
|
* [`className`](#highlight.tags.className) |
|
* [`macroName`](#highlight.tags.macroName) |
|
* [`propertyName`](#highlight.tags.propertyName) |
|
* [`operator`](#highlight.tags.operator) |
|
* [`comment`](#highlight.tags.comment) |
|
* [`meta`](#highlight.tags.meta) |
|
* [`punctuation`](#highlight.tags.punctuation) |
|
* [`invalid`](#highlight.tags.invalid) |
|
|
|
In addition, these mappings are provided: |
|
|
|
* [`regexp`](#highlight.tags.regexp), |
|
[`escape`](#highlight.tags.escape), and |
|
[`special`](#highlight.tags.special)[`(string)`](#highlight.tags.string) |
|
are mapped to `"tok-string2"` |
|
* [`special`](#highlight.tags.special)[`(variableName)`](#highlight.tags.variableName) |
|
to `"tok-variableName2"` |
|
* [`local`](#highlight.tags.local)[`(variableName)`](#highlight.tags.variableName) |
|
to `"tok-variableName tok-local"` |
|
* [`definition`](#highlight.tags.definition)[`(variableName)`](#highlight.tags.variableName) |
|
to `"tok-variableName tok-definition"` |
|
* [`definition`](#highlight.tags.definition)[`(propertyName)`](#highlight.tags.propertyName) |
|
to `"tok-propertyName tok-definition"` |
|
*/ |
|
const classHighlighter = tagHighlighter([ |
|
{ tag: tags.link, class: "tok-link" }, |
|
{ tag: tags.heading, class: "tok-heading" }, |
|
{ tag: tags.emphasis, class: "tok-emphasis" }, |
|
{ tag: tags.strong, class: "tok-strong" }, |
|
{ tag: tags.keyword, class: "tok-keyword" }, |
|
{ tag: tags.atom, class: "tok-atom" }, |
|
{ tag: tags.bool, class: "tok-bool" }, |
|
{ tag: tags.url, class: "tok-url" }, |
|
{ tag: tags.labelName, class: "tok-labelName" }, |
|
{ tag: tags.inserted, class: "tok-inserted" }, |
|
{ tag: tags.deleted, class: "tok-deleted" }, |
|
{ tag: tags.literal, class: "tok-literal" }, |
|
{ tag: tags.string, class: "tok-string" }, |
|
{ tag: tags.number, class: "tok-number" }, |
|
{ tag: [tags.regexp, tags.escape, tags.special(tags.string)], class: "tok-string2" }, |
|
{ tag: tags.variableName, class: "tok-variableName" }, |
|
{ tag: tags.local(tags.variableName), class: "tok-variableName tok-local" }, |
|
{ tag: tags.definition(tags.variableName), class: "tok-variableName tok-definition" }, |
|
{ tag: tags.special(tags.variableName), class: "tok-variableName2" }, |
|
{ tag: tags.definition(tags.propertyName), class: "tok-propertyName tok-definition" }, |
|
{ tag: tags.typeName, class: "tok-typeName" }, |
|
{ tag: tags.namespace, class: "tok-namespace" }, |
|
{ tag: tags.className, class: "tok-className" }, |
|
{ tag: tags.macroName, class: "tok-macroName" }, |
|
{ tag: tags.propertyName, class: "tok-propertyName" }, |
|
{ tag: tags.operator, class: "tok-operator" }, |
|
{ tag: tags.comment, class: "tok-comment" }, |
|
{ tag: tags.meta, class: "tok-meta" }, |
|
{ tag: tags.invalid, class: "tok-invalid" }, |
|
{ tag: tags.punctuation, class: "tok-punctuation" } |
|
]); |
|
|
|
export { Tag, classHighlighter, getStyleTags, highlightCode, highlightTree, styleTags, tagHighlighter, tags };
|
|
|