@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/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,19 @@
|
|
|
1
|
+
## 6.9.0 (2023-08-16)
|
|
2
|
+
|
|
3
|
+
### Bug fixes
|
|
4
|
+
|
|
5
|
+
Make `getIndentation` return null, rather than 0, when there is no syntax tree available.
|
|
6
|
+
|
|
7
|
+
### New features
|
|
8
|
+
|
|
9
|
+
The new `preparePlaceholder` option to `codeFolding` makes it possible to display contextual information in a folded range placeholder widget.
|
|
10
|
+
|
|
11
|
+
## 6.8.0 (2023-06-12)
|
|
12
|
+
|
|
13
|
+
### New features
|
|
14
|
+
|
|
15
|
+
The new `baseIndentFor` method in `TreeIndentContext` can be used to find the base indentation for an arbitrary node.
|
|
16
|
+
|
|
1
17
|
## 6.7.0 (2023-05-19)
|
|
2
18
|
|
|
3
19
|
### New features
|
package/dist/index.cjs
CHANGED
|
@@ -538,14 +538,14 @@ class LanguageState {
|
|
|
538
538
|
// state updates with parse work beyond the viewport.
|
|
539
539
|
let upto = this.context.treeLen == tr.startState.doc.length ? undefined
|
|
540
540
|
: Math.max(tr.changes.mapPos(this.context.treeLen), newCx.viewport.to);
|
|
541
|
-
if (!newCx.work(20 /*
|
|
541
|
+
if (!newCx.work(20 /* Apply */, upto))
|
|
542
542
|
newCx.takeTree();
|
|
543
543
|
return new LanguageState(newCx);
|
|
544
544
|
}
|
|
545
545
|
static init(state) {
|
|
546
|
-
let vpTo = Math.min(3000 /*
|
|
546
|
+
let vpTo = Math.min(3000 /* InitViewport */, state.doc.length);
|
|
547
547
|
let parseState = ParseContext.create(state.facet(language).parser, state, { from: 0, to: vpTo });
|
|
548
|
-
if (!parseState.work(20 /*
|
|
548
|
+
if (!parseState.work(20 /* Apply */, vpTo))
|
|
549
549
|
parseState.takeTree();
|
|
550
550
|
return new LanguageState(parseState);
|
|
551
551
|
}
|
|
@@ -562,14 +562,14 @@ Language.state = state.StateField.define({
|
|
|
562
562
|
}
|
|
563
563
|
});
|
|
564
564
|
let requestIdle = (callback) => {
|
|
565
|
-
let timeout = setTimeout(() => callback(), 500 /*
|
|
565
|
+
let timeout = setTimeout(() => callback(), 500 /* MaxPause */);
|
|
566
566
|
return () => clearTimeout(timeout);
|
|
567
567
|
};
|
|
568
568
|
if (typeof requestIdleCallback != "undefined")
|
|
569
569
|
requestIdle = (callback) => {
|
|
570
570
|
let idle = -1, timeout = setTimeout(() => {
|
|
571
|
-
idle = requestIdleCallback(callback, { timeout: 500 /*
|
|
572
|
-
}, 100 /*
|
|
571
|
+
idle = requestIdleCallback(callback, { timeout: 500 /* MaxPause */ - 100 /* MinPause */ });
|
|
572
|
+
}, 100 /* MinPause */);
|
|
573
573
|
return () => idle < 0 ? clearTimeout(timeout) : cancelIdleCallback(idle);
|
|
574
574
|
};
|
|
575
575
|
const isInputPending = typeof navigator != "undefined" && ((_a = navigator.scheduling) === null || _a === void 0 ? void 0 : _a.isInputPending)
|
|
@@ -592,7 +592,7 @@ const parseWorker = view.ViewPlugin.fromClass(class ParseWorker {
|
|
|
592
592
|
this.scheduleWork();
|
|
593
593
|
if (update.docChanged) {
|
|
594
594
|
if (this.view.hasFocus)
|
|
595
|
-
this.chunkBudget += 50 /*
|
|
595
|
+
this.chunkBudget += 50 /* ChangeBonus */;
|
|
596
596
|
this.scheduleWork();
|
|
597
597
|
}
|
|
598
598
|
this.checkAsyncSchedule(cx);
|
|
@@ -608,19 +608,19 @@ const parseWorker = view.ViewPlugin.fromClass(class ParseWorker {
|
|
|
608
608
|
this.working = null;
|
|
609
609
|
let now = Date.now();
|
|
610
610
|
if (this.chunkEnd < now && (this.chunkEnd < 0 || this.view.hasFocus)) { // Start a new chunk
|
|
611
|
-
this.chunkEnd = now + 30000 /*
|
|
612
|
-
this.chunkBudget = 3000 /*
|
|
611
|
+
this.chunkEnd = now + 30000 /* ChunkTime */;
|
|
612
|
+
this.chunkBudget = 3000 /* ChunkBudget */;
|
|
613
613
|
}
|
|
614
614
|
if (this.chunkBudget <= 0)
|
|
615
615
|
return; // No more budget
|
|
616
616
|
let { state, viewport: { to: vpTo } } = this.view, field = state.field(Language.state);
|
|
617
|
-
if (field.tree == field.context.tree && field.context.isDone(vpTo + 100000 /*
|
|
617
|
+
if (field.tree == field.context.tree && field.context.isDone(vpTo + 100000 /* MaxParseAhead */))
|
|
618
618
|
return;
|
|
619
|
-
let endTime = Date.now() + Math.min(this.chunkBudget, 100 /*
|
|
619
|
+
let endTime = Date.now() + Math.min(this.chunkBudget, 100 /* Slice */, deadline && !isInputPending ? Math.max(25 /* MinSlice */, deadline.timeRemaining() - 5) : 1e9);
|
|
620
620
|
let viewportFirst = field.context.treeLen < vpTo && state.doc.length > vpTo + 1000;
|
|
621
621
|
let done = field.context.work(() => {
|
|
622
622
|
return isInputPending && isInputPending() || Date.now() > endTime;
|
|
623
|
-
}, vpTo + (viewportFirst ? 0 : 100000 /*
|
|
623
|
+
}, vpTo + (viewportFirst ? 0 : 100000 /* MaxParseAhead */));
|
|
624
624
|
this.chunkBudget -= Date.now() - now;
|
|
625
625
|
if (done || this.chunkBudget <= 0) {
|
|
626
626
|
field.context.takeTree();
|
|
@@ -865,7 +865,7 @@ function getIndentation(context, pos) {
|
|
|
865
865
|
return result;
|
|
866
866
|
}
|
|
867
867
|
let tree = syntaxTree(context.state);
|
|
868
|
-
return tree ? syntaxIndentation(context, tree, pos) : null;
|
|
868
|
+
return tree.length >= pos ? syntaxIndentation(context, tree, pos) : null;
|
|
869
869
|
}
|
|
870
870
|
/**
|
|
871
871
|
Create a change set that auto-indents all lines touched by the
|
|
@@ -1062,13 +1062,20 @@ class TreeIndentContext extends IndentContext {
|
|
|
1062
1062
|
on if it is covered by another such node.
|
|
1063
1063
|
*/
|
|
1064
1064
|
get baseIndent() {
|
|
1065
|
-
|
|
1065
|
+
return this.baseIndentFor(this.node);
|
|
1066
|
+
}
|
|
1067
|
+
/**
|
|
1068
|
+
Get the indentation for the reference line of the given node
|
|
1069
|
+
(see [`baseIndent`](https://codemirror.net/6/docs/ref/#language.TreeIndentContext.baseIndent)).
|
|
1070
|
+
*/
|
|
1071
|
+
baseIndentFor(node) {
|
|
1072
|
+
let line = this.state.doc.lineAt(node.from);
|
|
1066
1073
|
// Skip line starts that are covered by a sibling (or cousin, etc)
|
|
1067
1074
|
for (;;) {
|
|
1068
|
-
let atBreak =
|
|
1075
|
+
let atBreak = node.resolve(line.from);
|
|
1069
1076
|
while (atBreak.parent && atBreak.parent.from == atBreak.from)
|
|
1070
1077
|
atBreak = atBreak.parent;
|
|
1071
|
-
if (isParent(atBreak,
|
|
1078
|
+
if (isParent(atBreak, node))
|
|
1072
1079
|
break;
|
|
1073
1080
|
line = this.state.doc.lineAt(atBreak.from);
|
|
1074
1081
|
}
|
|
@@ -1297,11 +1304,16 @@ const foldState = state.StateField.define({
|
|
|
1297
1304
|
update(folded, tr) {
|
|
1298
1305
|
folded = folded.map(tr.changes);
|
|
1299
1306
|
for (let e of tr.effects) {
|
|
1300
|
-
if (e.is(foldEffect) && !foldExists(folded, e.value.from, e.value.to))
|
|
1301
|
-
|
|
1302
|
-
|
|
1307
|
+
if (e.is(foldEffect) && !foldExists(folded, e.value.from, e.value.to)) {
|
|
1308
|
+
let { preparePlaceholder } = tr.state.facet(foldConfig);
|
|
1309
|
+
let widget = !preparePlaceholder ? foldWidget :
|
|
1310
|
+
view.Decoration.replace({ widget: new PreparedFoldWidget(preparePlaceholder(tr.state, e.value)) });
|
|
1311
|
+
folded = folded.update({ add: [widget.range(e.value.from, e.value.to)] });
|
|
1312
|
+
}
|
|
1313
|
+
else if (e.is(unfoldEffect)) {
|
|
1303
1314
|
folded = folded.update({ filter: (from, to) => e.value.from != from || e.value.to != to,
|
|
1304
1315
|
filterFrom: e.value.from, filterTo: e.value.to });
|
|
1316
|
+
}
|
|
1305
1317
|
}
|
|
1306
1318
|
// Clear folded ranges that cover the selection head
|
|
1307
1319
|
if (tr.selection) {
|
|
@@ -1478,6 +1490,7 @@ const foldKeymap = [
|
|
|
1478
1490
|
];
|
|
1479
1491
|
const defaultConfig = {
|
|
1480
1492
|
placeholderDOM: null,
|
|
1493
|
+
preparePlaceholder: null,
|
|
1481
1494
|
placeholderText: "…"
|
|
1482
1495
|
};
|
|
1483
1496
|
const foldConfig = state.Facet.define({
|
|
@@ -1492,27 +1505,36 @@ function codeFolding(config) {
|
|
|
1492
1505
|
result.push(foldConfig.of(config));
|
|
1493
1506
|
return result;
|
|
1494
1507
|
}
|
|
1508
|
+
function widgetToDOM(view, prepared) {
|
|
1509
|
+
let { state } = view, conf = state.facet(foldConfig);
|
|
1510
|
+
let onclick = (event) => {
|
|
1511
|
+
let line = view.lineBlockAt(view.posAtDOM(event.target));
|
|
1512
|
+
let folded = findFold(view.state, line.from, line.to);
|
|
1513
|
+
if (folded)
|
|
1514
|
+
view.dispatch({ effects: unfoldEffect.of(folded) });
|
|
1515
|
+
event.preventDefault();
|
|
1516
|
+
};
|
|
1517
|
+
if (conf.placeholderDOM)
|
|
1518
|
+
return conf.placeholderDOM(view, onclick, prepared);
|
|
1519
|
+
let element = document.createElement("span");
|
|
1520
|
+
element.textContent = conf.placeholderText;
|
|
1521
|
+
element.setAttribute("aria-label", state.phrase("folded code"));
|
|
1522
|
+
element.title = state.phrase("unfold");
|
|
1523
|
+
element.className = "cm-foldPlaceholder";
|
|
1524
|
+
element.onclick = onclick;
|
|
1525
|
+
return element;
|
|
1526
|
+
}
|
|
1495
1527
|
const foldWidget = view.Decoration.replace({ widget: new class extends view.WidgetType {
|
|
1496
|
-
toDOM(view) {
|
|
1497
|
-
let { state } = view, conf = state.facet(foldConfig);
|
|
1498
|
-
let onclick = (event) => {
|
|
1499
|
-
let line = view.lineBlockAt(view.posAtDOM(event.target));
|
|
1500
|
-
let folded = findFold(view.state, line.from, line.to);
|
|
1501
|
-
if (folded)
|
|
1502
|
-
view.dispatch({ effects: unfoldEffect.of(folded) });
|
|
1503
|
-
event.preventDefault();
|
|
1504
|
-
};
|
|
1505
|
-
if (conf.placeholderDOM)
|
|
1506
|
-
return conf.placeholderDOM(view, onclick);
|
|
1507
|
-
let element = document.createElement("span");
|
|
1508
|
-
element.textContent = conf.placeholderText;
|
|
1509
|
-
element.setAttribute("aria-label", state.phrase("folded code"));
|
|
1510
|
-
element.title = state.phrase("unfold");
|
|
1511
|
-
element.className = "cm-foldPlaceholder";
|
|
1512
|
-
element.onclick = onclick;
|
|
1513
|
-
return element;
|
|
1514
|
-
}
|
|
1528
|
+
toDOM(view) { return widgetToDOM(view, null); }
|
|
1515
1529
|
} });
|
|
1530
|
+
class PreparedFoldWidget extends view.WidgetType {
|
|
1531
|
+
constructor(value) {
|
|
1532
|
+
super();
|
|
1533
|
+
this.value = value;
|
|
1534
|
+
}
|
|
1535
|
+
eq(other) { return this.value == other.value; }
|
|
1536
|
+
toDOM(view) { return widgetToDOM(view, this.value); }
|
|
1537
|
+
}
|
|
1516
1538
|
const foldGutterDefaults = {
|
|
1517
1539
|
openText: "⌄",
|
|
1518
1540
|
closedText: "›",
|
|
@@ -2200,7 +2222,7 @@ class StreamLanguage extends Language {
|
|
|
2200
2222
|
state = this.streamParser.startState(cx.unit);
|
|
2201
2223
|
statePos = 0;
|
|
2202
2224
|
}
|
|
2203
|
-
if (pos - statePos > 10000 /*
|
|
2225
|
+
if (pos - statePos > 10000 /* MaxIndentScanDist */)
|
|
2204
2226
|
return null;
|
|
2205
2227
|
while (statePos < pos) {
|
|
2206
2228
|
let line = cx.state.doc.lineAt(statePos), end = Math.min(pos, line.to);
|
|
@@ -2282,7 +2304,7 @@ class Parse {
|
|
|
2282
2304
|
this.chunks.push(tree.children[i]);
|
|
2283
2305
|
this.chunkPos.push(tree.positions[i]);
|
|
2284
2306
|
}
|
|
2285
|
-
if (context && this.parsedPos < context.viewport.from - 100000 /*
|
|
2307
|
+
if (context && this.parsedPos < context.viewport.from - 100000 /* MaxDistanceBeforeViewport */) {
|
|
2286
2308
|
this.state = this.lang.streamParser.startState(getIndentUnit(context.state));
|
|
2287
2309
|
context.skipUntilInView(this.parsedPos, context.viewport.from);
|
|
2288
2310
|
this.parsedPos = context.viewport.from;
|
|
@@ -2292,7 +2314,7 @@ class Parse {
|
|
|
2292
2314
|
advance() {
|
|
2293
2315
|
let context = ParseContext.get();
|
|
2294
2316
|
let parseEnd = this.stoppedAt == null ? this.to : Math.min(this.to, this.stoppedAt);
|
|
2295
|
-
let end = Math.min(parseEnd, this.chunkStart + 2048 /*
|
|
2317
|
+
let end = Math.min(parseEnd, this.chunkStart + 2048 /* ChunkSize */);
|
|
2296
2318
|
if (context)
|
|
2297
2319
|
end = Math.min(end, context.viewport.to);
|
|
2298
2320
|
while (this.parsedPos < end)
|
|
@@ -2376,7 +2398,7 @@ class Parse {
|
|
|
2376
2398
|
let token = readToken(streamParser.token, stream, this.state);
|
|
2377
2399
|
if (token)
|
|
2378
2400
|
offset = this.emitToken(this.lang.tokenTable.resolve(token), this.parsedPos + stream.start, this.parsedPos + stream.pos, 4, offset);
|
|
2379
|
-
if (stream.start > 10000 /*
|
|
2401
|
+
if (stream.start > 10000 /* MaxLineLength */)
|
|
2380
2402
|
break;
|
|
2381
2403
|
}
|
|
2382
2404
|
}
|
|
@@ -2392,7 +2414,7 @@ class Parse {
|
|
|
2392
2414
|
length: this.parsedPos - this.chunkStart,
|
|
2393
2415
|
nodeSet,
|
|
2394
2416
|
topID: 0,
|
|
2395
|
-
maxBufferLength: 2048 /*
|
|
2417
|
+
maxBufferLength: 2048 /* ChunkSize */,
|
|
2396
2418
|
reused: this.chunkReused
|
|
2397
2419
|
});
|
|
2398
2420
|
tree = new common.Tree(tree.type, tree.children, tree.positions, tree.length, [[this.lang.stateAfter, this.lang.streamParser.copyState(this.state)]]);
|
|
@@ -2482,7 +2504,7 @@ function createTokenType(extra, tagStr) {
|
|
|
2482
2504
|
return type.id;
|
|
2483
2505
|
}
|
|
2484
2506
|
function docID(data) {
|
|
2485
|
-
let type = common.NodeType.define({ id: typeArray.length, name: "Document", props: [languageDataProp.add(() => data)] });
|
|
2507
|
+
let type = common.NodeType.define({ id: typeArray.length, name: "Document", props: [languageDataProp.add(() => data)], top: true });
|
|
2486
2508
|
typeArray.push(type);
|
|
2487
2509
|
return type;
|
|
2488
2510
|
}
|