@codemirror/language 6.7.0 → 6.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/dist/index.cjs +66 -44
- package/dist/index.d.cts +1198 -0
- package/dist/index.d.ts +22 -4
- package/dist/index.js +67 -45
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -587,6 +587,11 @@ declare class TreeIndentContext extends IndentContext {
|
|
|
587
587
|
*/
|
|
588
588
|
get baseIndent(): number;
|
|
589
589
|
/**
|
|
590
|
+
Get the indentation for the reference line of the given node
|
|
591
|
+
(see [`baseIndent`](https://codemirror.net/6/docs/ref/#language.TreeIndentContext.baseIndent)).
|
|
592
|
+
*/
|
|
593
|
+
baseIndentFor(node: SyntaxNode): number;
|
|
594
|
+
/**
|
|
590
595
|
Continue looking for indentations in the node's parent nodes,
|
|
591
596
|
and return the result of that.
|
|
592
597
|
*/
|
|
@@ -684,7 +689,7 @@ declare function foldable(state: EditorState, lineStart: number, lineEnd: number
|
|
|
684
689
|
from: number;
|
|
685
690
|
to: number;
|
|
686
691
|
} | null;
|
|
687
|
-
type DocRange = {
|
|
692
|
+
declare type DocRange = {
|
|
688
693
|
from: number;
|
|
689
694
|
to: number;
|
|
690
695
|
};
|
|
@@ -756,23 +761,36 @@ interface FoldConfig {
|
|
|
756
761
|
position of folded code. The `onclick` argument is the default
|
|
757
762
|
click event handler, which toggles folding on the line that
|
|
758
763
|
holds the element, and should probably be added as an event
|
|
759
|
-
handler to the returned element.
|
|
764
|
+
handler to the returned element. If
|
|
765
|
+
[`preparePlaceholder`](https://codemirror.net/6/docs/ref/#language.FoldConfig.preparePlaceholder)
|
|
766
|
+
is given, its result will be passed as 3rd argument. Otherwise,
|
|
767
|
+
this will be null.
|
|
760
768
|
|
|
761
769
|
When this option isn't given, the `placeholderText` option will
|
|
762
770
|
be used to create the placeholder element.
|
|
763
771
|
*/
|
|
764
|
-
placeholderDOM?: ((view: EditorView, onclick: (event: Event) => void) => HTMLElement) | null;
|
|
772
|
+
placeholderDOM?: ((view: EditorView, onclick: (event: Event) => void, prepared: any) => HTMLElement) | null;
|
|
765
773
|
/**
|
|
766
774
|
Text to use as placeholder for folded text. Defaults to `"…"`.
|
|
767
775
|
Will be styled with the `"cm-foldPlaceholder"` class.
|
|
768
776
|
*/
|
|
769
777
|
placeholderText?: string;
|
|
778
|
+
/**
|
|
779
|
+
Given a range that is being folded, create a value that
|
|
780
|
+
describes it, to be used by `placeholderDOM` to render a custom
|
|
781
|
+
widget that, for example, indicates something about the folded
|
|
782
|
+
range's size or type.
|
|
783
|
+
*/
|
|
784
|
+
preparePlaceholder?: (state: EditorState, range: {
|
|
785
|
+
from: number;
|
|
786
|
+
to: number;
|
|
787
|
+
}) => any;
|
|
770
788
|
}
|
|
771
789
|
/**
|
|
772
790
|
Create an extension that configures code folding.
|
|
773
791
|
*/
|
|
774
792
|
declare function codeFolding(config?: FoldConfig): Extension;
|
|
775
|
-
type Handlers = {
|
|
793
|
+
declare type Handlers = {
|
|
776
794
|
[event: string]: (view: EditorView, line: BlockInfo, event: Event) => boolean;
|
|
777
795
|
};
|
|
778
796
|
interface FoldGutterConfig {
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { NodeProp,
|
|
1
|
+
import { NodeProp, Tree, IterMode, TreeFragment, Parser, NodeType, NodeSet } from '@lezer/common';
|
|
2
2
|
import { StateEffect, StateField, Facet, EditorState, countColumn, combineConfig, RangeSet, RangeSetBuilder, Prec } from '@codemirror/state';
|
|
3
3
|
import { ViewPlugin, logException, EditorView, Decoration, WidgetType, gutter, GutterMarker } from '@codemirror/view';
|
|
4
4
|
import { tags, tagHighlighter, highlightTree, styleTags } from '@lezer/highlight';
|
|
@@ -534,14 +534,14 @@ class LanguageState {
|
|
|
534
534
|
// state updates with parse work beyond the viewport.
|
|
535
535
|
let upto = this.context.treeLen == tr.startState.doc.length ? undefined
|
|
536
536
|
: Math.max(tr.changes.mapPos(this.context.treeLen), newCx.viewport.to);
|
|
537
|
-
if (!newCx.work(20 /*
|
|
537
|
+
if (!newCx.work(20 /* Apply */, upto))
|
|
538
538
|
newCx.takeTree();
|
|
539
539
|
return new LanguageState(newCx);
|
|
540
540
|
}
|
|
541
541
|
static init(state) {
|
|
542
|
-
let vpTo = Math.min(3000 /*
|
|
542
|
+
let vpTo = Math.min(3000 /* InitViewport */, state.doc.length);
|
|
543
543
|
let parseState = ParseContext.create(state.facet(language).parser, state, { from: 0, to: vpTo });
|
|
544
|
-
if (!parseState.work(20 /*
|
|
544
|
+
if (!parseState.work(20 /* Apply */, vpTo))
|
|
545
545
|
parseState.takeTree();
|
|
546
546
|
return new LanguageState(parseState);
|
|
547
547
|
}
|
|
@@ -558,14 +558,14 @@ Language.state = /*@__PURE__*/StateField.define({
|
|
|
558
558
|
}
|
|
559
559
|
});
|
|
560
560
|
let requestIdle = (callback) => {
|
|
561
|
-
let timeout = setTimeout(() => callback(), 500 /*
|
|
561
|
+
let timeout = setTimeout(() => callback(), 500 /* MaxPause */);
|
|
562
562
|
return () => clearTimeout(timeout);
|
|
563
563
|
};
|
|
564
564
|
if (typeof requestIdleCallback != "undefined")
|
|
565
565
|
requestIdle = (callback) => {
|
|
566
566
|
let idle = -1, timeout = setTimeout(() => {
|
|
567
|
-
idle = requestIdleCallback(callback, { timeout: 500 /*
|
|
568
|
-
}, 100 /*
|
|
567
|
+
idle = requestIdleCallback(callback, { timeout: 500 /* MaxPause */ - 100 /* MinPause */ });
|
|
568
|
+
}, 100 /* MinPause */);
|
|
569
569
|
return () => idle < 0 ? clearTimeout(timeout) : cancelIdleCallback(idle);
|
|
570
570
|
};
|
|
571
571
|
const isInputPending = typeof navigator != "undefined" && ((_a = navigator.scheduling) === null || _a === void 0 ? void 0 : _a.isInputPending)
|
|
@@ -588,7 +588,7 @@ const parseWorker = /*@__PURE__*/ViewPlugin.fromClass(class ParseWorker {
|
|
|
588
588
|
this.scheduleWork();
|
|
589
589
|
if (update.docChanged) {
|
|
590
590
|
if (this.view.hasFocus)
|
|
591
|
-
this.chunkBudget += 50 /*
|
|
591
|
+
this.chunkBudget += 50 /* ChangeBonus */;
|
|
592
592
|
this.scheduleWork();
|
|
593
593
|
}
|
|
594
594
|
this.checkAsyncSchedule(cx);
|
|
@@ -604,19 +604,19 @@ const parseWorker = /*@__PURE__*/ViewPlugin.fromClass(class ParseWorker {
|
|
|
604
604
|
this.working = null;
|
|
605
605
|
let now = Date.now();
|
|
606
606
|
if (this.chunkEnd < now && (this.chunkEnd < 0 || this.view.hasFocus)) { // Start a new chunk
|
|
607
|
-
this.chunkEnd = now + 30000 /*
|
|
608
|
-
this.chunkBudget = 3000 /*
|
|
607
|
+
this.chunkEnd = now + 30000 /* ChunkTime */;
|
|
608
|
+
this.chunkBudget = 3000 /* ChunkBudget */;
|
|
609
609
|
}
|
|
610
610
|
if (this.chunkBudget <= 0)
|
|
611
611
|
return; // No more budget
|
|
612
612
|
let { state, viewport: { to: vpTo } } = this.view, field = state.field(Language.state);
|
|
613
|
-
if (field.tree == field.context.tree && field.context.isDone(vpTo + 100000 /*
|
|
613
|
+
if (field.tree == field.context.tree && field.context.isDone(vpTo + 100000 /* MaxParseAhead */))
|
|
614
614
|
return;
|
|
615
|
-
let endTime = Date.now() + Math.min(this.chunkBudget, 100 /*
|
|
615
|
+
let endTime = Date.now() + Math.min(this.chunkBudget, 100 /* Slice */, deadline && !isInputPending ? Math.max(25 /* MinSlice */, deadline.timeRemaining() - 5) : 1e9);
|
|
616
616
|
let viewportFirst = field.context.treeLen < vpTo && state.doc.length > vpTo + 1000;
|
|
617
617
|
let done = field.context.work(() => {
|
|
618
618
|
return isInputPending && isInputPending() || Date.now() > endTime;
|
|
619
|
-
}, vpTo + (viewportFirst ? 0 : 100000 /*
|
|
619
|
+
}, vpTo + (viewportFirst ? 0 : 100000 /* MaxParseAhead */));
|
|
620
620
|
this.chunkBudget -= Date.now() - now;
|
|
621
621
|
if (done || this.chunkBudget <= 0) {
|
|
622
622
|
field.context.takeTree();
|
|
@@ -861,7 +861,7 @@ function getIndentation(context, pos) {
|
|
|
861
861
|
return result;
|
|
862
862
|
}
|
|
863
863
|
let tree = syntaxTree(context.state);
|
|
864
|
-
return tree ? syntaxIndentation(context, tree, pos) : null;
|
|
864
|
+
return tree.length >= pos ? syntaxIndentation(context, tree, pos) : null;
|
|
865
865
|
}
|
|
866
866
|
/**
|
|
867
867
|
Create a change set that auto-indents all lines touched by the
|
|
@@ -1058,13 +1058,20 @@ class TreeIndentContext extends IndentContext {
|
|
|
1058
1058
|
on if it is covered by another such node.
|
|
1059
1059
|
*/
|
|
1060
1060
|
get baseIndent() {
|
|
1061
|
-
|
|
1061
|
+
return this.baseIndentFor(this.node);
|
|
1062
|
+
}
|
|
1063
|
+
/**
|
|
1064
|
+
Get the indentation for the reference line of the given node
|
|
1065
|
+
(see [`baseIndent`](https://codemirror.net/6/docs/ref/#language.TreeIndentContext.baseIndent)).
|
|
1066
|
+
*/
|
|
1067
|
+
baseIndentFor(node) {
|
|
1068
|
+
let line = this.state.doc.lineAt(node.from);
|
|
1062
1069
|
// Skip line starts that are covered by a sibling (or cousin, etc)
|
|
1063
1070
|
for (;;) {
|
|
1064
|
-
let atBreak =
|
|
1071
|
+
let atBreak = node.resolve(line.from);
|
|
1065
1072
|
while (atBreak.parent && atBreak.parent.from == atBreak.from)
|
|
1066
1073
|
atBreak = atBreak.parent;
|
|
1067
|
-
if (isParent(atBreak,
|
|
1074
|
+
if (isParent(atBreak, node))
|
|
1068
1075
|
break;
|
|
1069
1076
|
line = this.state.doc.lineAt(atBreak.from);
|
|
1070
1077
|
}
|
|
@@ -1293,11 +1300,16 @@ const foldState = /*@__PURE__*/StateField.define({
|
|
|
1293
1300
|
update(folded, tr) {
|
|
1294
1301
|
folded = folded.map(tr.changes);
|
|
1295
1302
|
for (let e of tr.effects) {
|
|
1296
|
-
if (e.is(foldEffect) && !foldExists(folded, e.value.from, e.value.to))
|
|
1297
|
-
|
|
1298
|
-
|
|
1303
|
+
if (e.is(foldEffect) && !foldExists(folded, e.value.from, e.value.to)) {
|
|
1304
|
+
let { preparePlaceholder } = tr.state.facet(foldConfig);
|
|
1305
|
+
let widget = !preparePlaceholder ? foldWidget :
|
|
1306
|
+
Decoration.replace({ widget: new PreparedFoldWidget(preparePlaceholder(tr.state, e.value)) });
|
|
1307
|
+
folded = folded.update({ add: [widget.range(e.value.from, e.value.to)] });
|
|
1308
|
+
}
|
|
1309
|
+
else if (e.is(unfoldEffect)) {
|
|
1299
1310
|
folded = folded.update({ filter: (from, to) => e.value.from != from || e.value.to != to,
|
|
1300
1311
|
filterFrom: e.value.from, filterTo: e.value.to });
|
|
1312
|
+
}
|
|
1301
1313
|
}
|
|
1302
1314
|
// Clear folded ranges that cover the selection head
|
|
1303
1315
|
if (tr.selection) {
|
|
@@ -1474,6 +1486,7 @@ const foldKeymap = [
|
|
|
1474
1486
|
];
|
|
1475
1487
|
const defaultConfig = {
|
|
1476
1488
|
placeholderDOM: null,
|
|
1489
|
+
preparePlaceholder: null,
|
|
1477
1490
|
placeholderText: "…"
|
|
1478
1491
|
};
|
|
1479
1492
|
const foldConfig = /*@__PURE__*/Facet.define({
|
|
@@ -1488,27 +1501,36 @@ function codeFolding(config) {
|
|
|
1488
1501
|
result.push(foldConfig.of(config));
|
|
1489
1502
|
return result;
|
|
1490
1503
|
}
|
|
1504
|
+
function widgetToDOM(view, prepared) {
|
|
1505
|
+
let { state } = view, conf = state.facet(foldConfig);
|
|
1506
|
+
let onclick = (event) => {
|
|
1507
|
+
let line = view.lineBlockAt(view.posAtDOM(event.target));
|
|
1508
|
+
let folded = findFold(view.state, line.from, line.to);
|
|
1509
|
+
if (folded)
|
|
1510
|
+
view.dispatch({ effects: unfoldEffect.of(folded) });
|
|
1511
|
+
event.preventDefault();
|
|
1512
|
+
};
|
|
1513
|
+
if (conf.placeholderDOM)
|
|
1514
|
+
return conf.placeholderDOM(view, onclick, prepared);
|
|
1515
|
+
let element = document.createElement("span");
|
|
1516
|
+
element.textContent = conf.placeholderText;
|
|
1517
|
+
element.setAttribute("aria-label", state.phrase("folded code"));
|
|
1518
|
+
element.title = state.phrase("unfold");
|
|
1519
|
+
element.className = "cm-foldPlaceholder";
|
|
1520
|
+
element.onclick = onclick;
|
|
1521
|
+
return element;
|
|
1522
|
+
}
|
|
1491
1523
|
const foldWidget = /*@__PURE__*/Decoration.replace({ widget: /*@__PURE__*/new class extends WidgetType {
|
|
1492
|
-
toDOM(view) {
|
|
1493
|
-
let { state } = view, conf = state.facet(foldConfig);
|
|
1494
|
-
let onclick = (event) => {
|
|
1495
|
-
let line = view.lineBlockAt(view.posAtDOM(event.target));
|
|
1496
|
-
let folded = findFold(view.state, line.from, line.to);
|
|
1497
|
-
if (folded)
|
|
1498
|
-
view.dispatch({ effects: unfoldEffect.of(folded) });
|
|
1499
|
-
event.preventDefault();
|
|
1500
|
-
};
|
|
1501
|
-
if (conf.placeholderDOM)
|
|
1502
|
-
return conf.placeholderDOM(view, onclick);
|
|
1503
|
-
let element = document.createElement("span");
|
|
1504
|
-
element.textContent = conf.placeholderText;
|
|
1505
|
-
element.setAttribute("aria-label", state.phrase("folded code"));
|
|
1506
|
-
element.title = state.phrase("unfold");
|
|
1507
|
-
element.className = "cm-foldPlaceholder";
|
|
1508
|
-
element.onclick = onclick;
|
|
1509
|
-
return element;
|
|
1510
|
-
}
|
|
1524
|
+
toDOM(view) { return widgetToDOM(view, null); }
|
|
1511
1525
|
} });
|
|
1526
|
+
class PreparedFoldWidget extends WidgetType {
|
|
1527
|
+
constructor(value) {
|
|
1528
|
+
super();
|
|
1529
|
+
this.value = value;
|
|
1530
|
+
}
|
|
1531
|
+
eq(other) { return this.value == other.value; }
|
|
1532
|
+
toDOM(view) { return widgetToDOM(view, this.value); }
|
|
1533
|
+
}
|
|
1512
1534
|
const foldGutterDefaults = {
|
|
1513
1535
|
openText: "⌄",
|
|
1514
1536
|
closedText: "›",
|
|
@@ -2196,7 +2218,7 @@ class StreamLanguage extends Language {
|
|
|
2196
2218
|
state = this.streamParser.startState(cx.unit);
|
|
2197
2219
|
statePos = 0;
|
|
2198
2220
|
}
|
|
2199
|
-
if (pos - statePos > 10000 /*
|
|
2221
|
+
if (pos - statePos > 10000 /* MaxIndentScanDist */)
|
|
2200
2222
|
return null;
|
|
2201
2223
|
while (statePos < pos) {
|
|
2202
2224
|
let line = cx.state.doc.lineAt(statePos), end = Math.min(pos, line.to);
|
|
@@ -2278,7 +2300,7 @@ class Parse {
|
|
|
2278
2300
|
this.chunks.push(tree.children[i]);
|
|
2279
2301
|
this.chunkPos.push(tree.positions[i]);
|
|
2280
2302
|
}
|
|
2281
|
-
if (context && this.parsedPos < context.viewport.from - 100000 /*
|
|
2303
|
+
if (context && this.parsedPos < context.viewport.from - 100000 /* MaxDistanceBeforeViewport */) {
|
|
2282
2304
|
this.state = this.lang.streamParser.startState(getIndentUnit(context.state));
|
|
2283
2305
|
context.skipUntilInView(this.parsedPos, context.viewport.from);
|
|
2284
2306
|
this.parsedPos = context.viewport.from;
|
|
@@ -2288,7 +2310,7 @@ class Parse {
|
|
|
2288
2310
|
advance() {
|
|
2289
2311
|
let context = ParseContext.get();
|
|
2290
2312
|
let parseEnd = this.stoppedAt == null ? this.to : Math.min(this.to, this.stoppedAt);
|
|
2291
|
-
let end = Math.min(parseEnd, this.chunkStart + 2048 /*
|
|
2313
|
+
let end = Math.min(parseEnd, this.chunkStart + 2048 /* ChunkSize */);
|
|
2292
2314
|
if (context)
|
|
2293
2315
|
end = Math.min(end, context.viewport.to);
|
|
2294
2316
|
while (this.parsedPos < end)
|
|
@@ -2372,7 +2394,7 @@ class Parse {
|
|
|
2372
2394
|
let token = readToken(streamParser.token, stream, this.state);
|
|
2373
2395
|
if (token)
|
|
2374
2396
|
offset = this.emitToken(this.lang.tokenTable.resolve(token), this.parsedPos + stream.start, this.parsedPos + stream.pos, 4, offset);
|
|
2375
|
-
if (stream.start > 10000 /*
|
|
2397
|
+
if (stream.start > 10000 /* MaxLineLength */)
|
|
2376
2398
|
break;
|
|
2377
2399
|
}
|
|
2378
2400
|
}
|
|
@@ -2388,7 +2410,7 @@ class Parse {
|
|
|
2388
2410
|
length: this.parsedPos - this.chunkStart,
|
|
2389
2411
|
nodeSet,
|
|
2390
2412
|
topID: 0,
|
|
2391
|
-
maxBufferLength: 2048 /*
|
|
2413
|
+
maxBufferLength: 2048 /* ChunkSize */,
|
|
2392
2414
|
reused: this.chunkReused
|
|
2393
2415
|
});
|
|
2394
2416
|
tree = new Tree(tree.type, tree.children, tree.positions, tree.length, [[this.lang.stateAfter, this.lang.streamParser.copyState(this.state)]]);
|
|
@@ -2478,7 +2500,7 @@ function createTokenType(extra, tagStr) {
|
|
|
2478
2500
|
return type.id;
|
|
2479
2501
|
}
|
|
2480
2502
|
function docID(data) {
|
|
2481
|
-
let type = NodeType.define({ id: typeArray.length, name: "Document", props: [languageDataProp.add(() => data)] });
|
|
2503
|
+
let type = NodeType.define({ id: typeArray.length, name: "Document", props: [languageDataProp.add(() => data)], top: true });
|
|
2482
2504
|
typeArray.push(type);
|
|
2483
2505
|
return type;
|
|
2484
2506
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@codemirror/language",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.9.0",
|
|
4
4
|
"description": "Language support infrastructure for the CodeMirror code editor",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"test": "cm-runtests",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"style-mod": "^4.0.0"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
|
-
"@codemirror/buildhelper": "^0.
|
|
37
|
+
"@codemirror/buildhelper": "^1.0.0",
|
|
38
38
|
"@lezer/javascript": "^1.0.0"
|
|
39
39
|
},
|
|
40
40
|
"repository": {
|