1
0
Fork 0
mirror of https://github.com/DanielnetoDotCom/YouPHPTube synced 2025-10-05 02:39:46 +02:00

Update npm

This commit is contained in:
Daniel Neto 2024-04-03 15:54:35 -03:00
parent 8341712d58
commit 1bd85100b9
5320 changed files with 58396 additions and 344722 deletions

View file

@ -1,3 +1,45 @@
## 6.10.1 (2024-02-02)
### Bug fixes
Fix an issue where, when a lot of code is visible in the initial editor, the bottom bit of code is shown without highlighting for one frame.
## 6.10.0 (2023-12-28)
### New features
The new `bidiIsolates` extension can be used to wrap syntactic elements where this is appropriate in an element that isolates their text direction, avoiding weird ordering of neutral characters on direction boundaries.
## 6.9.3 (2023-11-27)
### Bug fixes
Fix an issue in `StreamLanguage` where it ran out of node type ids if you repeatedly redefined a language with the same token table.
## 6.9.2 (2023-10-24)
### Bug fixes
Allow `StreamParser` tokens get multiple highlighting tags.
## 6.9.1 (2023-09-20)
### Bug fixes
Indentation now works a lot better in mixed-language documents that interleave the languages in a complex way.
Code folding is now able to pick the right foldable syntax node when the line end falls in a mixed-parsing language that doesn't match the target node.
## 6.9.0 (2023-08-16)
### Bug fixes
Make `getIndentation` return null, rather than 0, when there is no syntax tree available.
### New features
The new `preparePlaceholder` option to `codeFolding` makes it possible to display contextual information in a folded range placeholder widget.
## 6.8.0 (2023-06-12)
### New features

View file

@ -1,7 +1,5 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var common = require('@lezer/common');
var state = require('@codemirror/state');
var view = require('@codemirror/view');
@ -538,14 +536,14 @@ class LanguageState {
// state updates with parse work beyond the viewport.
let upto = this.context.treeLen == tr.startState.doc.length ? undefined
: Math.max(tr.changes.mapPos(this.context.treeLen), newCx.viewport.to);
if (!newCx.work(20 /* Apply */, upto))
if (!newCx.work(20 /* Work.Apply */, upto))
newCx.takeTree();
return new LanguageState(newCx);
}
static init(state) {
let vpTo = Math.min(3000 /* InitViewport */, state.doc.length);
let vpTo = Math.min(3000 /* Work.InitViewport */, state.doc.length);
let parseState = ParseContext.create(state.facet(language).parser, state, { from: 0, to: vpTo });
if (!parseState.work(20 /* Apply */, vpTo))
if (!parseState.work(20 /* Work.Apply */, vpTo))
parseState.takeTree();
return new LanguageState(parseState);
}
@ -562,14 +560,14 @@ Language.state = state.StateField.define({
}
});
let requestIdle = (callback) => {
let timeout = setTimeout(() => callback(), 500 /* MaxPause */);
let timeout = setTimeout(() => callback(), 500 /* Work.MaxPause */);
return () => clearTimeout(timeout);
};
if (typeof requestIdleCallback != "undefined")
requestIdle = (callback) => {
let idle = -1, timeout = setTimeout(() => {
idle = requestIdleCallback(callback, { timeout: 500 /* MaxPause */ - 100 /* MinPause */ });
}, 100 /* MinPause */);
idle = requestIdleCallback(callback, { timeout: 500 /* Work.MaxPause */ - 100 /* Work.MinPause */ });
}, 100 /* Work.MinPause */);
return () => idle < 0 ? clearTimeout(timeout) : cancelIdleCallback(idle);
};
const isInputPending = typeof navigator != "undefined" && ((_a = navigator.scheduling) === null || _a === void 0 ? void 0 : _a.isInputPending)
@ -590,9 +588,9 @@ const parseWorker = view.ViewPlugin.fromClass(class ParseWorker {
let cx = this.view.state.field(Language.state).context;
if (cx.updateViewport(update.view.viewport) || this.view.viewport.to > cx.treeLen)
this.scheduleWork();
if (update.docChanged) {
if (update.docChanged || update.selectionSet) {
if (this.view.hasFocus)
this.chunkBudget += 50 /* ChangeBonus */;
this.chunkBudget += 50 /* Work.ChangeBonus */;
this.scheduleWork();
}
this.checkAsyncSchedule(cx);
@ -608,19 +606,19 @@ const parseWorker = view.ViewPlugin.fromClass(class ParseWorker {
this.working = null;
let now = Date.now();
if (this.chunkEnd < now && (this.chunkEnd < 0 || this.view.hasFocus)) { // Start a new chunk
this.chunkEnd = now + 30000 /* ChunkTime */;
this.chunkBudget = 3000 /* ChunkBudget */;
this.chunkEnd = now + 30000 /* Work.ChunkTime */;
this.chunkBudget = 3000 /* Work.ChunkBudget */;
}
if (this.chunkBudget <= 0)
return; // No more budget
let { state, viewport: { to: vpTo } } = this.view, field = state.field(Language.state);
if (field.tree == field.context.tree && field.context.isDone(vpTo + 100000 /* MaxParseAhead */))
if (field.tree == field.context.tree && field.context.isDone(vpTo + 100000 /* Work.MaxParseAhead */))
return;
let endTime = Date.now() + Math.min(this.chunkBudget, 100 /* Slice */, deadline && !isInputPending ? Math.max(25 /* MinSlice */, deadline.timeRemaining() - 5) : 1e9);
let endTime = Date.now() + Math.min(this.chunkBudget, 100 /* Work.Slice */, deadline && !isInputPending ? Math.max(25 /* Work.MinSlice */, deadline.timeRemaining() - 5) : 1e9);
let viewportFirst = field.context.treeLen < vpTo && state.doc.length > vpTo + 1000;
let done = field.context.work(() => {
return isInputPending && isInputPending() || Date.now() > endTime;
}, vpTo + (viewportFirst ? 0 : 100000 /* MaxParseAhead */));
}, vpTo + (viewportFirst ? 0 : 100000 /* Work.MaxParseAhead */));
this.chunkBudget -= Date.now() - now;
if (done || this.chunkBudget <= 0) {
field.context.takeTree();
@ -865,7 +863,7 @@ function getIndentation(context, pos) {
return result;
}
let tree = syntaxTree(context.state);
return tree ? syntaxIndentation(context, tree, pos) : null;
return tree.length >= pos ? syntaxIndentation(context, tree, pos) : null;
}
/**
Create a change set that auto-indents all lines touched by the
@ -996,7 +994,24 @@ indicates that no definitive indentation can be determined.
const indentNodeProp = new common.NodeProp();
// Compute the indentation for a given position from the syntax tree.
function syntaxIndentation(cx, ast, pos) {
return indentFrom(ast.resolveInner(pos).enterUnfinishedNodesBefore(pos), pos, cx);
let stack = ast.resolveStack(pos);
let inner = stack.node.enterUnfinishedNodesBefore(pos);
if (inner != stack.node) {
let add = [];
for (let cur = inner; cur != stack.node; cur = cur.parent)
add.push(cur);
for (let i = add.length - 1; i >= 0; i--)
stack = { node: add[i], next: stack };
}
return indentFor(stack, cx, pos);
}
function indentFor(stack, cx, pos) {
for (let cur = stack; cur; cur = cur.next) {
let strategy = indentStrategy(cur.node);
if (strategy)
return strategy(TreeIndentContext.create(cx, pos, cur));
}
return 0;
}
function ignoreClosed(cx) {
return cx.pos == cx.options.simulateBreak && cx.options.simulateDoubleBreak;
@ -1012,14 +1027,6 @@ function indentStrategy(tree) {
}
return tree.parent == null ? topIndent : null;
}
function indentFrom(node, pos, base) {
for (; node; node = node.parent) {
let strategy = indentStrategy(node);
if (strategy)
return strategy(TreeIndentContext.create(base, pos, node));
}
return null;
}
function topIndent() { return 0; }
/**
Objects of this type provide context information and helper
@ -1032,20 +1039,24 @@ class TreeIndentContext extends IndentContext {
*/
pos,
/**
The syntax tree node to which the indentation strategy
applies.
@internal
*/
node) {
context) {
super(base.state, base.options);
this.base = base;
this.pos = pos;
this.node = node;
this.context = context;
}
/**
The syntax tree node to which the indentation strategy
applies.
*/
get node() { return this.context.node; }
/**
@internal
*/
static create(base, pos, node) {
return new TreeIndentContext(base, pos, node);
static create(base, pos, context) {
return new TreeIndentContext(base, pos, context);
}
/**
Get the text directly after `this.pos`, either the entire line
@ -1086,8 +1097,7 @@ class TreeIndentContext extends IndentContext {
and return the result of that.
*/
continue() {
let parent = this.node.parent;
return parent ? indentFrom(parent, this.pos, this.base) : 0;
return indentFor(this.context.next, this.base, this.pos);
}
}
function isParent(parent, of) {
@ -1229,9 +1239,10 @@ function syntaxFolding(state, start, end) {
let tree = syntaxTree(state);
if (tree.length < end)
return null;
let inner = tree.resolveInner(end, 1);
let stack = tree.resolveStack(end, 1);
let found = null;
for (let cur = inner; cur; cur = cur.parent) {
for (let iter = stack; iter; iter = iter.next) {
let cur = iter.node;
if (cur.to <= end || cur.from > end)
continue;
if (found && cur.from < start)
@ -1304,11 +1315,16 @@ const foldState = state.StateField.define({
update(folded, tr) {
folded = folded.map(tr.changes);
for (let e of tr.effects) {
if (e.is(foldEffect) && !foldExists(folded, e.value.from, e.value.to))
folded = folded.update({ add: [foldWidget.range(e.value.from, e.value.to)] });
else if (e.is(unfoldEffect))
if (e.is(foldEffect) && !foldExists(folded, e.value.from, e.value.to)) {
let { preparePlaceholder } = tr.state.facet(foldConfig);
let widget = !preparePlaceholder ? foldWidget :
view.Decoration.replace({ widget: new PreparedFoldWidget(preparePlaceholder(tr.state, e.value)) });
folded = folded.update({ add: [widget.range(e.value.from, e.value.to)] });
}
else if (e.is(unfoldEffect)) {
folded = folded.update({ filter: (from, to) => e.value.from != from || e.value.to != to,
filterFrom: e.value.from, filterTo: e.value.to });
}
}
// Clear folded ranges that cover the selection head
if (tr.selection) {
@ -1485,6 +1501,7 @@ const foldKeymap = [
];
const defaultConfig = {
placeholderDOM: null,
preparePlaceholder: null,
placeholderText: "…"
};
const foldConfig = state.Facet.define({
@ -1499,27 +1516,36 @@ function codeFolding(config) {
result.push(foldConfig.of(config));
return result;
}
function widgetToDOM(view, prepared) {
let { state } = view, conf = state.facet(foldConfig);
let onclick = (event) => {
let line = view.lineBlockAt(view.posAtDOM(event.target));
let folded = findFold(view.state, line.from, line.to);
if (folded)
view.dispatch({ effects: unfoldEffect.of(folded) });
event.preventDefault();
};
if (conf.placeholderDOM)
return conf.placeholderDOM(view, onclick, prepared);
let element = document.createElement("span");
element.textContent = conf.placeholderText;
element.setAttribute("aria-label", state.phrase("folded code"));
element.title = state.phrase("unfold");
element.className = "cm-foldPlaceholder";
element.onclick = onclick;
return element;
}
const foldWidget = view.Decoration.replace({ widget: new class extends view.WidgetType {
toDOM(view) {
let { state } = view, conf = state.facet(foldConfig);
let onclick = (event) => {
let line = view.lineBlockAt(view.posAtDOM(event.target));
let folded = findFold(view.state, line.from, line.to);
if (folded)
view.dispatch({ effects: unfoldEffect.of(folded) });
event.preventDefault();
};
if (conf.placeholderDOM)
return conf.placeholderDOM(view, onclick);
let element = document.createElement("span");
element.textContent = conf.placeholderText;
element.setAttribute("aria-label", state.phrase("folded code"));
element.title = state.phrase("unfold");
element.className = "cm-foldPlaceholder";
element.onclick = onclick;
return element;
}
toDOM(view) { return widgetToDOM(view, null); }
} });
class PreparedFoldWidget extends view.WidgetType {
constructor(value) {
super();
this.value = value;
}
eq(other) { return this.value == other.value; }
toDOM(view) { return widgetToDOM(view, this.value); }
}
const foldGutterDefaults = {
openText: "⌄",
closedText: "",
@ -1725,16 +1751,20 @@ class TreeHighlighter {
this.markCache = Object.create(null);
this.tree = syntaxTree(view.state);
this.decorations = this.buildDeco(view, getHighlighters(view.state));
this.decoratedTo = view.viewport.to;
}
update(update) {
let tree = syntaxTree(update.state), highlighters = getHighlighters(update.state);
let styleChange = highlighters != getHighlighters(update.startState);
if (tree.length < update.view.viewport.to && !styleChange && tree.type == this.tree.type) {
let { viewport } = update.view, decoratedToMapped = update.changes.mapPos(this.decoratedTo, 1);
if (tree.length < viewport.to && !styleChange && tree.type == this.tree.type && decoratedToMapped >= viewport.to) {
this.decorations = this.decorations.map(update.changes);
this.decoratedTo = decoratedToMapped;
}
else if (tree != this.tree || update.viewportChanged || styleChange) {
this.tree = tree;
this.decorations = this.buildDeco(update.view, highlighters);
this.decoratedTo = viewport.to;
}
}
buildDeco(view$1, highlighters) {
@ -2207,7 +2237,7 @@ class StreamLanguage extends Language {
state = this.streamParser.startState(cx.unit);
statePos = 0;
}
if (pos - statePos > 10000 /* MaxIndentScanDist */)
if (pos - statePos > 10000 /* C.MaxIndentScanDist */)
return null;
while (statePos < pos) {
let line = cx.state.doc.lineAt(statePos), end = Math.min(pos, line.to);
@ -2289,7 +2319,7 @@ class Parse {
this.chunks.push(tree.children[i]);
this.chunkPos.push(tree.positions[i]);
}
if (context && this.parsedPos < context.viewport.from - 100000 /* MaxDistanceBeforeViewport */) {
if (context && this.parsedPos < context.viewport.from - 100000 /* C.MaxDistanceBeforeViewport */) {
this.state = this.lang.streamParser.startState(getIndentUnit(context.state));
context.skipUntilInView(this.parsedPos, context.viewport.from);
this.parsedPos = context.viewport.from;
@ -2299,7 +2329,7 @@ class Parse {
advance() {
let context = ParseContext.get();
let parseEnd = this.stoppedAt == null ? this.to : Math.min(this.to, this.stoppedAt);
let end = Math.min(parseEnd, this.chunkStart + 2048 /* ChunkSize */);
let end = Math.min(parseEnd, this.chunkStart + 2048 /* C.ChunkSize */);
if (context)
end = Math.min(end, context.viewport.to);
while (this.parsedPos < end)
@ -2383,7 +2413,7 @@ class Parse {
let token = readToken(streamParser.token, stream, this.state);
if (token)
offset = this.emitToken(this.lang.tokenTable.resolve(token), this.parsedPos + stream.start, this.parsedPos + stream.pos, 4, offset);
if (stream.start > 10000 /* MaxLineLength */)
if (stream.start > 10000 /* C.MaxLineLength */)
break;
}
}
@ -2399,7 +2429,7 @@ class Parse {
length: this.parsedPos - this.chunkStart,
nodeSet,
topID: 0,
maxBufferLength: 2048 /* ChunkSize */,
maxBufferLength: 2048 /* C.ChunkSize */,
reused: this.chunkReused
});
tree = new common.Tree(tree.type, tree.children, tree.positions, tree.length, [[this.lang.stateAfter, this.lang.streamParser.copyState(this.state)]]);
@ -2426,6 +2456,8 @@ const noTokens = Object.create(null);
const typeArray = [common.NodeType.none];
const nodeSet = new common.NodeSet(typeArray);
const warned = [];
// Cache of node types by name and tags
const byTag = Object.create(null);
const defaultTable = Object.create(null);
for (let [legacyName, name] of [
["variable", "variableName"],
@ -2459,41 +2491,161 @@ function warnForPart(part, msg) {
console.warn(msg);
}
function createTokenType(extra, tagStr) {
let tag = null;
for (let part of tagStr.split(".")) {
let value = (extra[part] || highlight.tags[part]);
if (!value) {
warnForPart(part, `Unknown highlighting tag ${part}`);
}
else if (typeof value == "function") {
if (!tag)
warnForPart(part, `Modifier ${part} used at start of tag`);
else
tag = value(tag);
}
else {
if (tag)
warnForPart(part, `Tag ${part} used as modifier`);
else
tag = value;
let tags = [];
for (let name of tagStr.split(" ")) {
let found = [];
for (let part of name.split(".")) {
let value = (extra[part] || highlight.tags[part]);
if (!value) {
warnForPart(part, `Unknown highlighting tag ${part}`);
}
else if (typeof value == "function") {
if (!found.length)
warnForPart(part, `Modifier ${part} used at start of tag`);
else
found = found.map(value);
}
else {
if (found.length)
warnForPart(part, `Tag ${part} used as modifier`);
else
found = Array.isArray(value) ? value : [value];
}
}
for (let tag of found)
tags.push(tag);
}
if (!tag)
if (!tags.length)
return 0;
let name = tagStr.replace(/ /g, "_"), type = common.NodeType.define({
let name = tagStr.replace(/ /g, "_"), key = name + " " + tags.map(t => t.id);
let known = byTag[key];
if (known)
return known.id;
let type = byTag[key] = common.NodeType.define({
id: typeArray.length,
name,
props: [highlight.styleTags({ [name]: tag })]
props: [highlight.styleTags({ [name]: tags })]
});
typeArray.push(type);
return type.id;
}
function docID(data) {
let type = common.NodeType.define({ id: typeArray.length, name: "Document", props: [languageDataProp.add(() => data)] });
let type = common.NodeType.define({ id: typeArray.length, name: "Document", props: [languageDataProp.add(() => data)], top: true });
typeArray.push(type);
return type;
}
function buildForLine(line) {
return line.length <= 4096 && /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac\ufb50-\ufdff]/.test(line);
}
function textHasRTL(text) {
for (let i = text.iter(); !i.next().done;)
if (buildForLine(i.value))
return true;
return false;
}
function changeAddsRTL(change) {
let added = false;
change.iterChanges((fA, tA, fB, tB, ins) => {
if (!added && textHasRTL(ins))
added = true;
});
return added;
}
const alwaysIsolate = state.Facet.define({ combine: values => values.some(x => x) });
/**
Make sure nodes
[marked](https://lezer.codemirror.net/docs/ref/#common.NodeProp^isolate)
as isolating for bidirectional text are rendered in a way that
isolates them from the surrounding text.
*/
function bidiIsolates(options = {}) {
let extensions = [isolateMarks];
if (options.alwaysIsolate)
extensions.push(alwaysIsolate.of(true));
return extensions;
}
const isolateMarks = view.ViewPlugin.fromClass(class {
constructor(view$1) {
this.always = view$1.state.facet(alwaysIsolate) ||
view$1.textDirection != view.Direction.LTR ||
view$1.state.facet(view.EditorView.perLineTextDirection);
this.hasRTL = !this.always && textHasRTL(view$1.state.doc);
this.tree = syntaxTree(view$1.state);
this.decorations = this.always || this.hasRTL ? buildDeco(view$1, this.tree, this.always) : view.Decoration.none;
}
update(update) {
let always = update.state.facet(alwaysIsolate) ||
update.view.textDirection != view.Direction.LTR ||
update.state.facet(view.EditorView.perLineTextDirection);
if (!always && !this.hasRTL && changeAddsRTL(update.changes))
this.hasRTL = true;
if (!always && !this.hasRTL)
return;
let tree = syntaxTree(update.state);
if (always != this.always || tree != this.tree || update.docChanged || update.viewportChanged) {
this.tree = tree;
this.always = always;
this.decorations = buildDeco(update.view, tree, always);
}
}
}, {
provide: plugin => {
function access(view$1) {
var _a, _b;
return (_b = (_a = view$1.plugin(plugin)) === null || _a === void 0 ? void 0 : _a.decorations) !== null && _b !== void 0 ? _b : view.Decoration.none;
}
return [view.EditorView.outerDecorations.of(access),
state.Prec.lowest(view.EditorView.bidiIsolatedRanges.of(access))];
}
});
function buildDeco(view, tree, always) {
let deco = new state.RangeSetBuilder();
let ranges = view.visibleRanges;
if (!always)
ranges = clipRTLLines(ranges, view.state.doc);
for (let { from, to } of ranges) {
tree.iterate({
enter: node => {
let iso = node.type.prop(common.NodeProp.isolate);
if (iso)
deco.add(node.from, node.to, marks[iso]);
},
from, to
});
}
return deco.finish();
}
function clipRTLLines(ranges, doc) {
let cur = doc.iter(), pos = 0, result = [], last = null;
for (let { from, to } of ranges) {
if (from != pos) {
if (pos < from)
cur.next(from - pos);
pos = from;
}
for (;;) {
let start = pos, end = pos + cur.value.length;
if (!cur.lineBreak && buildForLine(cur.value)) {
if (last && last.to > start - 10)
last.to = Math.min(to, end);
else
result.push(last = { from: start, to: Math.min(to, end) });
}
if (pos >= to)
break;
pos = end;
cur.next();
}
}
return result;
}
const marks = {
rtl: view.Decoration.mark({ class: "cm-iso", inclusive: true, attributes: { dir: "rtl" }, bidiIsolate: view.Direction.RTL }),
ltr: view.Decoration.mark({ class: "cm-iso", inclusive: true, attributes: { dir: "ltr" }, bidiIsolate: view.Direction.LTR }),
auto: view.Decoration.mark({ class: "cm-iso", inclusive: true, attributes: { dir: "auto" }, bidiIsolate: null })
};
exports.DocInput = DocInput;
exports.HighlightStyle = HighlightStyle;
exports.IndentContext = IndentContext;
@ -2505,6 +2657,7 @@ exports.ParseContext = ParseContext;
exports.StreamLanguage = StreamLanguage;
exports.StringStream = StringStream;
exports.TreeIndentContext = TreeIndentContext;
exports.bidiIsolates = bidiIsolates;
exports.bracketMatching = bracketMatching;
exports.bracketMatchingHandle = bracketMatchingHandle;
exports.codeFolding = codeFolding;

View file

@ -567,12 +567,12 @@ declare class TreeIndentContext extends IndentContext {
The position at which indentation is being computed.
*/
readonly pos: number;
private constructor();
/**
The syntax tree node to which the indentation strategy
applies.
*/
readonly node: SyntaxNode;
private constructor();
get node(): SyntaxNode;
/**
Get the text directly after `this.pos`, either the entire line
or the next 100 characters, whichever is shorter.
@ -689,7 +689,7 @@ declare function foldable(state: EditorState, lineStart: number, lineEnd: number
from: number;
to: number;
} | null;
declare type DocRange = {
type DocRange = {
from: number;
to: number;
};
@ -761,23 +761,36 @@ interface FoldConfig {
position of folded code. The `onclick` argument is the default
click event handler, which toggles folding on the line that
holds the element, and should probably be added as an event
handler to the returned element.
handler to the returned element. If
[`preparePlaceholder`](https://codemirror.net/6/docs/ref/#language.FoldConfig.preparePlaceholder)
is given, its result will be passed as 3rd argument. Otherwise,
this will be null.
When this option isn't given, the `placeholderText` option will
be used to create the placeholder element.
*/
placeholderDOM?: ((view: EditorView, onclick: (event: Event) => void) => HTMLElement) | null;
placeholderDOM?: ((view: EditorView, onclick: (event: Event) => void, prepared: any) => HTMLElement) | null;
/**
Text to use as placeholder for folded text. Defaults to `"…"`.
Will be styled with the `"cm-foldPlaceholder"` class.
*/
placeholderText?: string;
/**
Given a range that is being folded, create a value that
describes it, to be used by `placeholderDOM` to render a custom
widget that, for example, indicates something about the folded
range's size or type.
*/
preparePlaceholder?: (state: EditorState, range: {
from: number;
to: number;
}) => any;
}
/**
Create an extension that configures code folding.
*/
declare function codeFolding(config?: FoldConfig): Extension;
declare type Handlers = {
type Handlers = {
[event: string]: (view: EditorView, line: BlockInfo, event: Event) => boolean;
};
interface FoldGutterConfig {
@ -1126,11 +1139,13 @@ interface StreamParser<State> {
Read one token, advancing the stream past it, and returning a
string indicating the token's style tageither the name of one
of the tags in
[`tags`](https://lezer.codemirror.net/docs/ref#highlight.tags),
or such a name suffixed by one or more tag
[`tags`](https://lezer.codemirror.net/docs/ref#highlight.tags)
or [`tokenTable`](https://codemirror.net/6/docs/ref/#language.StreamParser.tokenTable), or such a
name suffixed by one or more tag
[modifier](https://lezer.codemirror.net/docs/ref#highlight.Tag^defineModifier)
names, separated by periods. For example `"keyword"` or
"`variableName.constant"`.
"`variableName.constant"`, or a space-separated set of such
token types.
It is okay to return a zero-length token, but only if that
updates the state so that the next call will return a non-empty
@ -1162,10 +1177,10 @@ interface StreamParser<State> {
/**
Extra tokens to use in this parser. When the tokenizer returns a
token name that exists as a property in this object, the
corresponding tag will be assigned to the token.
corresponding tags will be assigned to the token.
*/
tokenTable?: {
[name: string]: Tag;
[name: string]: Tag | readonly Tag[];
};
}
/**
@ -1182,4 +1197,20 @@ declare class StreamLanguage<State> extends Language {
get allowsNesting(): boolean;
}
export { Config, DocInput, HighlightStyle, IndentContext, LRLanguage, Language, LanguageDescription, LanguageSupport, MatchResult, ParseContext, StreamLanguage, StreamParser, StringStream, Sublanguage, TagStyle, TreeIndentContext, bracketMatching, bracketMatchingHandle, codeFolding, continuedIndent, defaultHighlightStyle, defineLanguageFacet, delimitedIndent, ensureSyntaxTree, flatIndent, foldAll, foldCode, foldEffect, foldGutter, foldInside, foldKeymap, foldNodeProp, foldService, foldState, foldable, foldedRanges, forceParsing, getIndentUnit, getIndentation, highlightingFor, indentNodeProp, indentOnInput, indentRange, indentService, indentString, indentUnit, language, languageDataProp, matchBrackets, sublanguageProp, syntaxHighlighting, syntaxParserRunning, syntaxTree, syntaxTreeAvailable, toggleFold, unfoldAll, unfoldCode, unfoldEffect };
/**
Make sure nodes
[marked](https://lezer.codemirror.net/docs/ref/#common.NodeProp^isolate)
as isolating for bidirectional text are rendered in a way that
isolates them from the surrounding text.
*/
declare function bidiIsolates(options?: {
/**
By default, isolating elements are only added when the editor
direction isn't uniformly left-to-right, or if it is, on lines
that contain right-to-left character. When true, disable this
optimization and add them everywhere.
*/
alwaysIsolate?: boolean;
}): Extension;
export { type Config, DocInput, HighlightStyle, IndentContext, LRLanguage, Language, LanguageDescription, LanguageSupport, type MatchResult, ParseContext, StreamLanguage, type StreamParser, StringStream, type Sublanguage, type TagStyle, TreeIndentContext, bidiIsolates, bracketMatching, bracketMatchingHandle, codeFolding, continuedIndent, defaultHighlightStyle, defineLanguageFacet, delimitedIndent, ensureSyntaxTree, flatIndent, foldAll, foldCode, foldEffect, foldGutter, foldInside, foldKeymap, foldNodeProp, foldService, foldState, foldable, foldedRanges, forceParsing, getIndentUnit, getIndentation, highlightingFor, indentNodeProp, indentOnInput, indentRange, indentService, indentString, indentUnit, language, languageDataProp, matchBrackets, sublanguageProp, syntaxHighlighting, syntaxParserRunning, syntaxTree, syntaxTreeAvailable, toggleFold, unfoldAll, unfoldCode, unfoldEffect };

View file

@ -567,12 +567,12 @@ declare class TreeIndentContext extends IndentContext {
The position at which indentation is being computed.
*/
readonly pos: number;
private constructor();
/**
The syntax tree node to which the indentation strategy
applies.
*/
readonly node: SyntaxNode;
private constructor();
get node(): SyntaxNode;
/**
Get the text directly after `this.pos`, either the entire line
or the next 100 characters, whichever is shorter.
@ -689,7 +689,7 @@ declare function foldable(state: EditorState, lineStart: number, lineEnd: number
from: number;
to: number;
} | null;
declare type DocRange = {
type DocRange = {
from: number;
to: number;
};
@ -761,23 +761,36 @@ interface FoldConfig {
position of folded code. The `onclick` argument is the default
click event handler, which toggles folding on the line that
holds the element, and should probably be added as an event
handler to the returned element.
handler to the returned element. If
[`preparePlaceholder`](https://codemirror.net/6/docs/ref/#language.FoldConfig.preparePlaceholder)
is given, its result will be passed as 3rd argument. Otherwise,
this will be null.
When this option isn't given, the `placeholderText` option will
be used to create the placeholder element.
*/
placeholderDOM?: ((view: EditorView, onclick: (event: Event) => void) => HTMLElement) | null;
placeholderDOM?: ((view: EditorView, onclick: (event: Event) => void, prepared: any) => HTMLElement) | null;
/**
Text to use as placeholder for folded text. Defaults to `"…"`.
Will be styled with the `"cm-foldPlaceholder"` class.
*/
placeholderText?: string;
/**
Given a range that is being folded, create a value that
describes it, to be used by `placeholderDOM` to render a custom
widget that, for example, indicates something about the folded
range's size or type.
*/
preparePlaceholder?: (state: EditorState, range: {
from: number;
to: number;
}) => any;
}
/**
Create an extension that configures code folding.
*/
declare function codeFolding(config?: FoldConfig): Extension;
declare type Handlers = {
type Handlers = {
[event: string]: (view: EditorView, line: BlockInfo, event: Event) => boolean;
};
interface FoldGutterConfig {
@ -1126,11 +1139,13 @@ interface StreamParser<State> {
Read one token, advancing the stream past it, and returning a
string indicating the token's style tageither the name of one
of the tags in
[`tags`](https://lezer.codemirror.net/docs/ref#highlight.tags),
or such a name suffixed by one or more tag
[`tags`](https://lezer.codemirror.net/docs/ref#highlight.tags)
or [`tokenTable`](https://codemirror.net/6/docs/ref/#language.StreamParser.tokenTable), or such a
name suffixed by one or more tag
[modifier](https://lezer.codemirror.net/docs/ref#highlight.Tag^defineModifier)
names, separated by periods. For example `"keyword"` or
"`variableName.constant"`.
"`variableName.constant"`, or a space-separated set of such
token types.
It is okay to return a zero-length token, but only if that
updates the state so that the next call will return a non-empty
@ -1162,10 +1177,10 @@ interface StreamParser<State> {
/**
Extra tokens to use in this parser. When the tokenizer returns a
token name that exists as a property in this object, the
corresponding tag will be assigned to the token.
corresponding tags will be assigned to the token.
*/
tokenTable?: {
[name: string]: Tag;
[name: string]: Tag | readonly Tag[];
};
}
/**
@ -1182,4 +1197,20 @@ declare class StreamLanguage<State> extends Language {
get allowsNesting(): boolean;
}
export { Config, DocInput, HighlightStyle, IndentContext, LRLanguage, Language, LanguageDescription, LanguageSupport, MatchResult, ParseContext, StreamLanguage, StreamParser, StringStream, Sublanguage, TagStyle, TreeIndentContext, bracketMatching, bracketMatchingHandle, codeFolding, continuedIndent, defaultHighlightStyle, defineLanguageFacet, delimitedIndent, ensureSyntaxTree, flatIndent, foldAll, foldCode, foldEffect, foldGutter, foldInside, foldKeymap, foldNodeProp, foldService, foldState, foldable, foldedRanges, forceParsing, getIndentUnit, getIndentation, highlightingFor, indentNodeProp, indentOnInput, indentRange, indentService, indentString, indentUnit, language, languageDataProp, matchBrackets, sublanguageProp, syntaxHighlighting, syntaxParserRunning, syntaxTree, syntaxTreeAvailable, toggleFold, unfoldAll, unfoldCode, unfoldEffect };
/**
Make sure nodes
[marked](https://lezer.codemirror.net/docs/ref/#common.NodeProp^isolate)
as isolating for bidirectional text are rendered in a way that
isolates them from the surrounding text.
*/
declare function bidiIsolates(options?: {
/**
By default, isolating elements are only added when the editor
direction isn't uniformly left-to-right, or if it is, on lines
that contain right-to-left character. When true, disable this
optimization and add them everywhere.
*/
alwaysIsolate?: boolean;
}): Extension;
export { type Config, DocInput, HighlightStyle, IndentContext, LRLanguage, Language, LanguageDescription, LanguageSupport, type MatchResult, ParseContext, StreamLanguage, type StreamParser, StringStream, type Sublanguage, type TagStyle, TreeIndentContext, bidiIsolates, bracketMatching, bracketMatchingHandle, codeFolding, continuedIndent, defaultHighlightStyle, defineLanguageFacet, delimitedIndent, ensureSyntaxTree, flatIndent, foldAll, foldCode, foldEffect, foldGutter, foldInside, foldKeymap, foldNodeProp, foldService, foldState, foldable, foldedRanges, forceParsing, getIndentUnit, getIndentation, highlightingFor, indentNodeProp, indentOnInput, indentRange, indentService, indentString, indentUnit, language, languageDataProp, matchBrackets, sublanguageProp, syntaxHighlighting, syntaxParserRunning, syntaxTree, syntaxTreeAvailable, toggleFold, unfoldAll, unfoldCode, unfoldEffect };

View file

@ -1,6 +1,6 @@
import { NodeProp, Tree, IterMode, TreeFragment, Parser, NodeType, NodeSet } from '@lezer/common';
import { NodeProp, IterMode, Tree, TreeFragment, Parser, NodeType, NodeSet } from '@lezer/common';
import { StateEffect, StateField, Facet, EditorState, countColumn, combineConfig, RangeSet, RangeSetBuilder, Prec } from '@codemirror/state';
import { ViewPlugin, logException, EditorView, Decoration, WidgetType, gutter, GutterMarker } from '@codemirror/view';
import { ViewPlugin, logException, EditorView, Decoration, WidgetType, gutter, GutterMarker, Direction } from '@codemirror/view';
import { tags, tagHighlighter, highlightTree, styleTags } from '@lezer/highlight';
import { StyleModule } from 'style-mod';
@ -534,14 +534,14 @@ class LanguageState {
// state updates with parse work beyond the viewport.
let upto = this.context.treeLen == tr.startState.doc.length ? undefined
: Math.max(tr.changes.mapPos(this.context.treeLen), newCx.viewport.to);
if (!newCx.work(20 /* Apply */, upto))
if (!newCx.work(20 /* Work.Apply */, upto))
newCx.takeTree();
return new LanguageState(newCx);
}
static init(state) {
let vpTo = Math.min(3000 /* InitViewport */, state.doc.length);
let vpTo = Math.min(3000 /* Work.InitViewport */, state.doc.length);
let parseState = ParseContext.create(state.facet(language).parser, state, { from: 0, to: vpTo });
if (!parseState.work(20 /* Apply */, vpTo))
if (!parseState.work(20 /* Work.Apply */, vpTo))
parseState.takeTree();
return new LanguageState(parseState);
}
@ -558,14 +558,14 @@ Language.state = /*@__PURE__*/StateField.define({
}
});
let requestIdle = (callback) => {
let timeout = setTimeout(() => callback(), 500 /* MaxPause */);
let timeout = setTimeout(() => callback(), 500 /* Work.MaxPause */);
return () => clearTimeout(timeout);
};
if (typeof requestIdleCallback != "undefined")
requestIdle = (callback) => {
let idle = -1, timeout = setTimeout(() => {
idle = requestIdleCallback(callback, { timeout: 500 /* MaxPause */ - 100 /* MinPause */ });
}, 100 /* MinPause */);
idle = requestIdleCallback(callback, { timeout: 500 /* Work.MaxPause */ - 100 /* Work.MinPause */ });
}, 100 /* Work.MinPause */);
return () => idle < 0 ? clearTimeout(timeout) : cancelIdleCallback(idle);
};
const isInputPending = typeof navigator != "undefined" && ((_a = navigator.scheduling) === null || _a === void 0 ? void 0 : _a.isInputPending)
@ -586,9 +586,9 @@ const parseWorker = /*@__PURE__*/ViewPlugin.fromClass(class ParseWorker {
let cx = this.view.state.field(Language.state).context;
if (cx.updateViewport(update.view.viewport) || this.view.viewport.to > cx.treeLen)
this.scheduleWork();
if (update.docChanged) {
if (update.docChanged || update.selectionSet) {
if (this.view.hasFocus)
this.chunkBudget += 50 /* ChangeBonus */;
this.chunkBudget += 50 /* Work.ChangeBonus */;
this.scheduleWork();
}
this.checkAsyncSchedule(cx);
@ -604,19 +604,19 @@ const parseWorker = /*@__PURE__*/ViewPlugin.fromClass(class ParseWorker {
this.working = null;
let now = Date.now();
if (this.chunkEnd < now && (this.chunkEnd < 0 || this.view.hasFocus)) { // Start a new chunk
this.chunkEnd = now + 30000 /* ChunkTime */;
this.chunkBudget = 3000 /* ChunkBudget */;
this.chunkEnd = now + 30000 /* Work.ChunkTime */;
this.chunkBudget = 3000 /* Work.ChunkBudget */;
}
if (this.chunkBudget <= 0)
return; // No more budget
let { state, viewport: { to: vpTo } } = this.view, field = state.field(Language.state);
if (field.tree == field.context.tree && field.context.isDone(vpTo + 100000 /* MaxParseAhead */))
if (field.tree == field.context.tree && field.context.isDone(vpTo + 100000 /* Work.MaxParseAhead */))
return;
let endTime = Date.now() + Math.min(this.chunkBudget, 100 /* Slice */, deadline && !isInputPending ? Math.max(25 /* MinSlice */, deadline.timeRemaining() - 5) : 1e9);
let endTime = Date.now() + Math.min(this.chunkBudget, 100 /* Work.Slice */, deadline && !isInputPending ? Math.max(25 /* Work.MinSlice */, deadline.timeRemaining() - 5) : 1e9);
let viewportFirst = field.context.treeLen < vpTo && state.doc.length > vpTo + 1000;
let done = field.context.work(() => {
return isInputPending && isInputPending() || Date.now() > endTime;
}, vpTo + (viewportFirst ? 0 : 100000 /* MaxParseAhead */));
}, vpTo + (viewportFirst ? 0 : 100000 /* Work.MaxParseAhead */));
this.chunkBudget -= Date.now() - now;
if (done || this.chunkBudget <= 0) {
field.context.takeTree();
@ -861,7 +861,7 @@ function getIndentation(context, pos) {
return result;
}
let tree = syntaxTree(context.state);
return tree ? syntaxIndentation(context, tree, pos) : null;
return tree.length >= pos ? syntaxIndentation(context, tree, pos) : null;
}
/**
Create a change set that auto-indents all lines touched by the
@ -992,7 +992,24 @@ indicates that no definitive indentation can be determined.
const indentNodeProp = /*@__PURE__*/new NodeProp();
// Compute the indentation for a given position from the syntax tree.
function syntaxIndentation(cx, ast, pos) {
return indentFrom(ast.resolveInner(pos).enterUnfinishedNodesBefore(pos), pos, cx);
let stack = ast.resolveStack(pos);
let inner = stack.node.enterUnfinishedNodesBefore(pos);
if (inner != stack.node) {
let add = [];
for (let cur = inner; cur != stack.node; cur = cur.parent)
add.push(cur);
for (let i = add.length - 1; i >= 0; i--)
stack = { node: add[i], next: stack };
}
return indentFor(stack, cx, pos);
}
function indentFor(stack, cx, pos) {
for (let cur = stack; cur; cur = cur.next) {
let strategy = indentStrategy(cur.node);
if (strategy)
return strategy(TreeIndentContext.create(cx, pos, cur));
}
return 0;
}
function ignoreClosed(cx) {
return cx.pos == cx.options.simulateBreak && cx.options.simulateDoubleBreak;
@ -1008,14 +1025,6 @@ function indentStrategy(tree) {
}
return tree.parent == null ? topIndent : null;
}
function indentFrom(node, pos, base) {
for (; node; node = node.parent) {
let strategy = indentStrategy(node);
if (strategy)
return strategy(TreeIndentContext.create(base, pos, node));
}
return null;
}
function topIndent() { return 0; }
/**
Objects of this type provide context information and helper
@ -1028,20 +1037,24 @@ class TreeIndentContext extends IndentContext {
*/
pos,
/**
The syntax tree node to which the indentation strategy
applies.
@internal
*/
node) {
context) {
super(base.state, base.options);
this.base = base;
this.pos = pos;
this.node = node;
this.context = context;
}
/**
The syntax tree node to which the indentation strategy
applies.
*/
get node() { return this.context.node; }
/**
@internal
*/
static create(base, pos, node) {
return new TreeIndentContext(base, pos, node);
static create(base, pos, context) {
return new TreeIndentContext(base, pos, context);
}
/**
Get the text directly after `this.pos`, either the entire line
@ -1082,8 +1095,7 @@ class TreeIndentContext extends IndentContext {
and return the result of that.
*/
continue() {
let parent = this.node.parent;
return parent ? indentFrom(parent, this.pos, this.base) : 0;
return indentFor(this.context.next, this.base, this.pos);
}
}
function isParent(parent, of) {
@ -1225,9 +1237,10 @@ function syntaxFolding(state, start, end) {
let tree = syntaxTree(state);
if (tree.length < end)
return null;
let inner = tree.resolveInner(end, 1);
let stack = tree.resolveStack(end, 1);
let found = null;
for (let cur = inner; cur; cur = cur.parent) {
for (let iter = stack; iter; iter = iter.next) {
let cur = iter.node;
if (cur.to <= end || cur.from > end)
continue;
if (found && cur.from < start)
@ -1300,11 +1313,16 @@ const foldState = /*@__PURE__*/StateField.define({
update(folded, tr) {
folded = folded.map(tr.changes);
for (let e of tr.effects) {
if (e.is(foldEffect) && !foldExists(folded, e.value.from, e.value.to))
folded = folded.update({ add: [foldWidget.range(e.value.from, e.value.to)] });
else if (e.is(unfoldEffect))
if (e.is(foldEffect) && !foldExists(folded, e.value.from, e.value.to)) {
let { preparePlaceholder } = tr.state.facet(foldConfig);
let widget = !preparePlaceholder ? foldWidget :
Decoration.replace({ widget: new PreparedFoldWidget(preparePlaceholder(tr.state, e.value)) });
folded = folded.update({ add: [widget.range(e.value.from, e.value.to)] });
}
else if (e.is(unfoldEffect)) {
folded = folded.update({ filter: (from, to) => e.value.from != from || e.value.to != to,
filterFrom: e.value.from, filterTo: e.value.to });
}
}
// Clear folded ranges that cover the selection head
if (tr.selection) {
@ -1481,6 +1499,7 @@ const foldKeymap = [
];
const defaultConfig = {
placeholderDOM: null,
preparePlaceholder: null,
placeholderText: "…"
};
const foldConfig = /*@__PURE__*/Facet.define({
@ -1495,27 +1514,36 @@ function codeFolding(config) {
result.push(foldConfig.of(config));
return result;
}
function widgetToDOM(view, prepared) {
let { state } = view, conf = state.facet(foldConfig);
let onclick = (event) => {
let line = view.lineBlockAt(view.posAtDOM(event.target));
let folded = findFold(view.state, line.from, line.to);
if (folded)
view.dispatch({ effects: unfoldEffect.of(folded) });
event.preventDefault();
};
if (conf.placeholderDOM)
return conf.placeholderDOM(view, onclick, prepared);
let element = document.createElement("span");
element.textContent = conf.placeholderText;
element.setAttribute("aria-label", state.phrase("folded code"));
element.title = state.phrase("unfold");
element.className = "cm-foldPlaceholder";
element.onclick = onclick;
return element;
}
const foldWidget = /*@__PURE__*/Decoration.replace({ widget: /*@__PURE__*/new class extends WidgetType {
toDOM(view) {
let { state } = view, conf = state.facet(foldConfig);
let onclick = (event) => {
let line = view.lineBlockAt(view.posAtDOM(event.target));
let folded = findFold(view.state, line.from, line.to);
if (folded)
view.dispatch({ effects: unfoldEffect.of(folded) });
event.preventDefault();
};
if (conf.placeholderDOM)
return conf.placeholderDOM(view, onclick);
let element = document.createElement("span");
element.textContent = conf.placeholderText;
element.setAttribute("aria-label", state.phrase("folded code"));
element.title = state.phrase("unfold");
element.className = "cm-foldPlaceholder";
element.onclick = onclick;
return element;
}
toDOM(view) { return widgetToDOM(view, null); }
} });
class PreparedFoldWidget extends WidgetType {
constructor(value) {
super();
this.value = value;
}
eq(other) { return this.value == other.value; }
toDOM(view) { return widgetToDOM(view, this.value); }
}
const foldGutterDefaults = {
openText: "⌄",
closedText: "",
@ -1721,16 +1749,20 @@ class TreeHighlighter {
this.markCache = Object.create(null);
this.tree = syntaxTree(view.state);
this.decorations = this.buildDeco(view, getHighlighters(view.state));
this.decoratedTo = view.viewport.to;
}
update(update) {
let tree = syntaxTree(update.state), highlighters = getHighlighters(update.state);
let styleChange = highlighters != getHighlighters(update.startState);
if (tree.length < update.view.viewport.to && !styleChange && tree.type == this.tree.type) {
let { viewport } = update.view, decoratedToMapped = update.changes.mapPos(this.decoratedTo, 1);
if (tree.length < viewport.to && !styleChange && tree.type == this.tree.type && decoratedToMapped >= viewport.to) {
this.decorations = this.decorations.map(update.changes);
this.decoratedTo = decoratedToMapped;
}
else if (tree != this.tree || update.viewportChanged || styleChange) {
this.tree = tree;
this.decorations = this.buildDeco(update.view, highlighters);
this.decoratedTo = viewport.to;
}
}
buildDeco(view, highlighters) {
@ -2203,7 +2235,7 @@ class StreamLanguage extends Language {
state = this.streamParser.startState(cx.unit);
statePos = 0;
}
if (pos - statePos > 10000 /* MaxIndentScanDist */)
if (pos - statePos > 10000 /* C.MaxIndentScanDist */)
return null;
while (statePos < pos) {
let line = cx.state.doc.lineAt(statePos), end = Math.min(pos, line.to);
@ -2285,7 +2317,7 @@ class Parse {
this.chunks.push(tree.children[i]);
this.chunkPos.push(tree.positions[i]);
}
if (context && this.parsedPos < context.viewport.from - 100000 /* MaxDistanceBeforeViewport */) {
if (context && this.parsedPos < context.viewport.from - 100000 /* C.MaxDistanceBeforeViewport */) {
this.state = this.lang.streamParser.startState(getIndentUnit(context.state));
context.skipUntilInView(this.parsedPos, context.viewport.from);
this.parsedPos = context.viewport.from;
@ -2295,7 +2327,7 @@ class Parse {
advance() {
let context = ParseContext.get();
let parseEnd = this.stoppedAt == null ? this.to : Math.min(this.to, this.stoppedAt);
let end = Math.min(parseEnd, this.chunkStart + 2048 /* ChunkSize */);
let end = Math.min(parseEnd, this.chunkStart + 2048 /* C.ChunkSize */);
if (context)
end = Math.min(end, context.viewport.to);
while (this.parsedPos < end)
@ -2379,7 +2411,7 @@ class Parse {
let token = readToken(streamParser.token, stream, this.state);
if (token)
offset = this.emitToken(this.lang.tokenTable.resolve(token), this.parsedPos + stream.start, this.parsedPos + stream.pos, 4, offset);
if (stream.start > 10000 /* MaxLineLength */)
if (stream.start > 10000 /* C.MaxLineLength */)
break;
}
}
@ -2395,7 +2427,7 @@ class Parse {
length: this.parsedPos - this.chunkStart,
nodeSet,
topID: 0,
maxBufferLength: 2048 /* ChunkSize */,
maxBufferLength: 2048 /* C.ChunkSize */,
reused: this.chunkReused
});
tree = new Tree(tree.type, tree.children, tree.positions, tree.length, [[this.lang.stateAfter, this.lang.streamParser.copyState(this.state)]]);
@ -2422,6 +2454,8 @@ const noTokens = /*@__PURE__*/Object.create(null);
const typeArray = [NodeType.none];
const nodeSet = /*@__PURE__*/new NodeSet(typeArray);
const warned = [];
// Cache of node types by name and tags
const byTag = /*@__PURE__*/Object.create(null);
const defaultTable = /*@__PURE__*/Object.create(null);
for (let [legacyName, name] of [
["variable", "variableName"],
@ -2455,39 +2489,159 @@ function warnForPart(part, msg) {
console.warn(msg);
}
function createTokenType(extra, tagStr) {
let tag = null;
for (let part of tagStr.split(".")) {
let value = (extra[part] || tags[part]);
if (!value) {
warnForPart(part, `Unknown highlighting tag ${part}`);
}
else if (typeof value == "function") {
if (!tag)
warnForPart(part, `Modifier ${part} used at start of tag`);
else
tag = value(tag);
}
else {
if (tag)
warnForPart(part, `Tag ${part} used as modifier`);
else
tag = value;
let tags$1 = [];
for (let name of tagStr.split(" ")) {
let found = [];
for (let part of name.split(".")) {
let value = (extra[part] || tags[part]);
if (!value) {
warnForPart(part, `Unknown highlighting tag ${part}`);
}
else if (typeof value == "function") {
if (!found.length)
warnForPart(part, `Modifier ${part} used at start of tag`);
else
found = found.map(value);
}
else {
if (found.length)
warnForPart(part, `Tag ${part} used as modifier`);
else
found = Array.isArray(value) ? value : [value];
}
}
for (let tag of found)
tags$1.push(tag);
}
if (!tag)
if (!tags$1.length)
return 0;
let name = tagStr.replace(/ /g, "_"), type = NodeType.define({
let name = tagStr.replace(/ /g, "_"), key = name + " " + tags$1.map(t => t.id);
let known = byTag[key];
if (known)
return known.id;
let type = byTag[key] = NodeType.define({
id: typeArray.length,
name,
props: [styleTags({ [name]: tag })]
props: [styleTags({ [name]: tags$1 })]
});
typeArray.push(type);
return type.id;
}
function docID(data) {
let type = NodeType.define({ id: typeArray.length, name: "Document", props: [languageDataProp.add(() => data)] });
let type = NodeType.define({ id: typeArray.length, name: "Document", props: [languageDataProp.add(() => data)], top: true });
typeArray.push(type);
return type;
}
export { DocInput, HighlightStyle, IndentContext, LRLanguage, Language, LanguageDescription, LanguageSupport, ParseContext, StreamLanguage, StringStream, TreeIndentContext, bracketMatching, bracketMatchingHandle, codeFolding, continuedIndent, defaultHighlightStyle, defineLanguageFacet, delimitedIndent, ensureSyntaxTree, flatIndent, foldAll, foldCode, foldEffect, foldGutter, foldInside, foldKeymap, foldNodeProp, foldService, foldState, foldable, foldedRanges, forceParsing, getIndentUnit, getIndentation, highlightingFor, indentNodeProp, indentOnInput, indentRange, indentService, indentString, indentUnit, language, languageDataProp, matchBrackets, sublanguageProp, syntaxHighlighting, syntaxParserRunning, syntaxTree, syntaxTreeAvailable, toggleFold, unfoldAll, unfoldCode, unfoldEffect };
function buildForLine(line) {
return line.length <= 4096 && /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac\ufb50-\ufdff]/.test(line);
}
function textHasRTL(text) {
for (let i = text.iter(); !i.next().done;)
if (buildForLine(i.value))
return true;
return false;
}
function changeAddsRTL(change) {
let added = false;
change.iterChanges((fA, tA, fB, tB, ins) => {
if (!added && textHasRTL(ins))
added = true;
});
return added;
}
const alwaysIsolate = /*@__PURE__*/Facet.define({ combine: values => values.some(x => x) });
/**
Make sure nodes
[marked](https://lezer.codemirror.net/docs/ref/#common.NodeProp^isolate)
as isolating for bidirectional text are rendered in a way that
isolates them from the surrounding text.
*/
function bidiIsolates(options = {}) {
let extensions = [isolateMarks];
if (options.alwaysIsolate)
extensions.push(alwaysIsolate.of(true));
return extensions;
}
const isolateMarks = /*@__PURE__*/ViewPlugin.fromClass(class {
constructor(view) {
this.always = view.state.facet(alwaysIsolate) ||
view.textDirection != Direction.LTR ||
view.state.facet(EditorView.perLineTextDirection);
this.hasRTL = !this.always && textHasRTL(view.state.doc);
this.tree = syntaxTree(view.state);
this.decorations = this.always || this.hasRTL ? buildDeco(view, this.tree, this.always) : Decoration.none;
}
update(update) {
let always = update.state.facet(alwaysIsolate) ||
update.view.textDirection != Direction.LTR ||
update.state.facet(EditorView.perLineTextDirection);
if (!always && !this.hasRTL && changeAddsRTL(update.changes))
this.hasRTL = true;
if (!always && !this.hasRTL)
return;
let tree = syntaxTree(update.state);
if (always != this.always || tree != this.tree || update.docChanged || update.viewportChanged) {
this.tree = tree;
this.always = always;
this.decorations = buildDeco(update.view, tree, always);
}
}
}, {
provide: plugin => {
function access(view) {
var _a, _b;
return (_b = (_a = view.plugin(plugin)) === null || _a === void 0 ? void 0 : _a.decorations) !== null && _b !== void 0 ? _b : Decoration.none;
}
return [EditorView.outerDecorations.of(access),
Prec.lowest(EditorView.bidiIsolatedRanges.of(access))];
}
});
function buildDeco(view, tree, always) {
let deco = new RangeSetBuilder();
let ranges = view.visibleRanges;
if (!always)
ranges = clipRTLLines(ranges, view.state.doc);
for (let { from, to } of ranges) {
tree.iterate({
enter: node => {
let iso = node.type.prop(NodeProp.isolate);
if (iso)
deco.add(node.from, node.to, marks[iso]);
},
from, to
});
}
return deco.finish();
}
function clipRTLLines(ranges, doc) {
let cur = doc.iter(), pos = 0, result = [], last = null;
for (let { from, to } of ranges) {
if (from != pos) {
if (pos < from)
cur.next(from - pos);
pos = from;
}
for (;;) {
let start = pos, end = pos + cur.value.length;
if (!cur.lineBreak && buildForLine(cur.value)) {
if (last && last.to > start - 10)
last.to = Math.min(to, end);
else
result.push(last = { from: start, to: Math.min(to, end) });
}
if (pos >= to)
break;
pos = end;
cur.next();
}
}
return result;
}
const marks = {
rtl: /*@__PURE__*/Decoration.mark({ class: "cm-iso", inclusive: true, attributes: { dir: "rtl" }, bidiIsolate: Direction.RTL }),
ltr: /*@__PURE__*/Decoration.mark({ class: "cm-iso", inclusive: true, attributes: { dir: "ltr" }, bidiIsolate: Direction.LTR }),
auto: /*@__PURE__*/Decoration.mark({ class: "cm-iso", inclusive: true, attributes: { dir: "auto" }, bidiIsolate: null })
};
export { DocInput, HighlightStyle, IndentContext, LRLanguage, Language, LanguageDescription, LanguageSupport, ParseContext, StreamLanguage, StringStream, TreeIndentContext, bidiIsolates, bracketMatching, bracketMatchingHandle, codeFolding, continuedIndent, defaultHighlightStyle, defineLanguageFacet, delimitedIndent, ensureSyntaxTree, flatIndent, foldAll, foldCode, foldEffect, foldGutter, foldInside, foldKeymap, foldNodeProp, foldService, foldState, foldable, foldedRanges, forceParsing, getIndentUnit, getIndentation, highlightingFor, indentNodeProp, indentOnInput, indentRange, indentService, indentString, indentUnit, language, languageDataProp, matchBrackets, sublanguageProp, syntaxHighlighting, syntaxParserRunning, syntaxTree, syntaxTreeAvailable, toggleFold, unfoldAll, unfoldCode, unfoldEffect };

View file

@ -1,6 +1,6 @@
{
"name": "@codemirror/language",
"version": "6.8.0",
"version": "6.10.1",
"description": "Language support infrastructure for the CodeMirror code editor",
"scripts": {
"test": "cm-runtests",
@ -27,8 +27,8 @@
"license": "MIT",
"dependencies": {
"@codemirror/state": "^6.0.0",
"@codemirror/view": "^6.0.0",
"@lezer/common": "^1.0.0",
"@codemirror/view": "^6.23.0",
"@lezer/common": "^1.1.0",
"@lezer/highlight": "^1.0.0",
"@lezer/lr": "^1.0.0",
"style-mod": "^4.0.0"