@codemirror/language 6.2.0 → 6.3.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 +62 -40
- package/dist/index.d.ts +37 -13
- package/dist/index.js +63 -41
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,19 @@
|
|
|
1
|
+
## 6.3.0 (2022-10-24)
|
|
2
|
+
|
|
3
|
+
### New features
|
|
4
|
+
|
|
5
|
+
`HighlightStyle` objects now have a `specs` property holding the tag styles that were used to define them.
|
|
6
|
+
|
|
7
|
+
`Language` objects now have a `name` field holding the language name.
|
|
8
|
+
|
|
9
|
+
## 6.2.1 (2022-07-21)
|
|
10
|
+
|
|
11
|
+
### Bug fixes
|
|
12
|
+
|
|
13
|
+
Fix a bug where `bracketMatching` would incorrectly match nested brackets in syntax trees that put multiple pairs of brackets in the same parent node.
|
|
14
|
+
|
|
15
|
+
Fix a bug that could cause `indentRange` to loop infinitely.
|
|
16
|
+
|
|
1
17
|
## 6.2.0 (2022-06-30)
|
|
2
18
|
|
|
3
19
|
### Bug fixes
|
package/dist/index.cjs
CHANGED
|
@@ -49,8 +49,13 @@ class Language {
|
|
|
49
49
|
The [language data](https://codemirror.net/6/docs/ref/#state.EditorState.languageDataAt) facet
|
|
50
50
|
used for this language.
|
|
51
51
|
*/
|
|
52
|
-
data, parser, extraExtensions = []
|
|
52
|
+
data, parser, extraExtensions = [],
|
|
53
|
+
/**
|
|
54
|
+
A language name.
|
|
55
|
+
*/
|
|
56
|
+
name = "") {
|
|
53
57
|
this.data = data;
|
|
58
|
+
this.name = name;
|
|
54
59
|
// Kludge to define EditorState.tree as a debugging helper,
|
|
55
60
|
// without the EditorState package actually knowing about
|
|
56
61
|
// languages and lezer trees.
|
|
@@ -138,8 +143,8 @@ A subclass of [`Language`](https://codemirror.net/6/docs/ref/#language.Language)
|
|
|
138
143
|
parsers.
|
|
139
144
|
*/
|
|
140
145
|
class LRLanguage extends Language {
|
|
141
|
-
constructor(data, parser) {
|
|
142
|
-
super(data, parser);
|
|
146
|
+
constructor(data, parser, name) {
|
|
147
|
+
super(data, parser, [], name);
|
|
143
148
|
this.parser = parser;
|
|
144
149
|
}
|
|
145
150
|
/**
|
|
@@ -149,14 +154,14 @@ class LRLanguage extends Language {
|
|
|
149
154
|
let data = defineLanguageFacet(spec.languageData);
|
|
150
155
|
return new LRLanguage(data, spec.parser.configure({
|
|
151
156
|
props: [languageDataProp.add(type => type.isTop ? data : undefined)]
|
|
152
|
-
}));
|
|
157
|
+
}), spec.name);
|
|
153
158
|
}
|
|
154
159
|
/**
|
|
155
160
|
Create a new instance of this language with a reconfigured
|
|
156
|
-
version of its parser.
|
|
161
|
+
version of its parser and optionally a new name.
|
|
157
162
|
*/
|
|
158
|
-
configure(options) {
|
|
159
|
-
return new LRLanguage(this.data, this.parser.configure(options));
|
|
163
|
+
configure(options, name) {
|
|
164
|
+
return new LRLanguage(this.data, this.parser.configure(options), name || this.name);
|
|
160
165
|
}
|
|
161
166
|
get allowsNesting() { return this.parser.hasWrappers(); }
|
|
162
167
|
}
|
|
@@ -503,14 +508,14 @@ class LanguageState {
|
|
|
503
508
|
// state updates with parse work beyond the viewport.
|
|
504
509
|
let upto = this.context.treeLen == tr.startState.doc.length ? undefined
|
|
505
510
|
: Math.max(tr.changes.mapPos(this.context.treeLen), newCx.viewport.to);
|
|
506
|
-
if (!newCx.work(20 /* Apply */, upto))
|
|
511
|
+
if (!newCx.work(20 /* Work.Apply */, upto))
|
|
507
512
|
newCx.takeTree();
|
|
508
513
|
return new LanguageState(newCx);
|
|
509
514
|
}
|
|
510
515
|
static init(state) {
|
|
511
|
-
let vpTo = Math.min(3000 /* InitViewport */, state.doc.length);
|
|
516
|
+
let vpTo = Math.min(3000 /* Work.InitViewport */, state.doc.length);
|
|
512
517
|
let parseState = ParseContext.create(state.facet(language).parser, state, { from: 0, to: vpTo });
|
|
513
|
-
if (!parseState.work(20 /* Apply */, vpTo))
|
|
518
|
+
if (!parseState.work(20 /* Work.Apply */, vpTo))
|
|
514
519
|
parseState.takeTree();
|
|
515
520
|
return new LanguageState(parseState);
|
|
516
521
|
}
|
|
@@ -527,14 +532,14 @@ Language.state = state.StateField.define({
|
|
|
527
532
|
}
|
|
528
533
|
});
|
|
529
534
|
let requestIdle = (callback) => {
|
|
530
|
-
let timeout = setTimeout(() => callback(), 500 /* MaxPause */);
|
|
535
|
+
let timeout = setTimeout(() => callback(), 500 /* Work.MaxPause */);
|
|
531
536
|
return () => clearTimeout(timeout);
|
|
532
537
|
};
|
|
533
538
|
if (typeof requestIdleCallback != "undefined")
|
|
534
539
|
requestIdle = (callback) => {
|
|
535
540
|
let idle = -1, timeout = setTimeout(() => {
|
|
536
|
-
idle = requestIdleCallback(callback, { timeout: 500 /* MaxPause */ - 100 /* MinPause */ });
|
|
537
|
-
}, 100 /* MinPause */);
|
|
541
|
+
idle = requestIdleCallback(callback, { timeout: 500 /* Work.MaxPause */ - 100 /* Work.MinPause */ });
|
|
542
|
+
}, 100 /* Work.MinPause */);
|
|
538
543
|
return () => idle < 0 ? clearTimeout(timeout) : cancelIdleCallback(idle);
|
|
539
544
|
};
|
|
540
545
|
const isInputPending = typeof navigator != "undefined" && ((_a = navigator.scheduling) === null || _a === void 0 ? void 0 : _a.isInputPending)
|
|
@@ -557,7 +562,7 @@ const parseWorker = view.ViewPlugin.fromClass(class ParseWorker {
|
|
|
557
562
|
this.scheduleWork();
|
|
558
563
|
if (update.docChanged) {
|
|
559
564
|
if (this.view.hasFocus)
|
|
560
|
-
this.chunkBudget += 50 /* ChangeBonus */;
|
|
565
|
+
this.chunkBudget += 50 /* Work.ChangeBonus */;
|
|
561
566
|
this.scheduleWork();
|
|
562
567
|
}
|
|
563
568
|
this.checkAsyncSchedule(cx);
|
|
@@ -573,19 +578,19 @@ const parseWorker = view.ViewPlugin.fromClass(class ParseWorker {
|
|
|
573
578
|
this.working = null;
|
|
574
579
|
let now = Date.now();
|
|
575
580
|
if (this.chunkEnd < now && (this.chunkEnd < 0 || this.view.hasFocus)) { // Start a new chunk
|
|
576
|
-
this.chunkEnd = now + 30000 /* ChunkTime */;
|
|
577
|
-
this.chunkBudget = 3000 /* ChunkBudget */;
|
|
581
|
+
this.chunkEnd = now + 30000 /* Work.ChunkTime */;
|
|
582
|
+
this.chunkBudget = 3000 /* Work.ChunkBudget */;
|
|
578
583
|
}
|
|
579
584
|
if (this.chunkBudget <= 0)
|
|
580
585
|
return; // No more budget
|
|
581
586
|
let { state, viewport: { to: vpTo } } = this.view, field = state.field(Language.state);
|
|
582
|
-
if (field.tree == field.context.tree && field.context.isDone(vpTo + 100000 /* MaxParseAhead */))
|
|
587
|
+
if (field.tree == field.context.tree && field.context.isDone(vpTo + 100000 /* Work.MaxParseAhead */))
|
|
583
588
|
return;
|
|
584
|
-
let endTime = Date.now() + Math.min(this.chunkBudget, 100 /* Slice */, deadline && !isInputPending ? Math.max(25 /* MinSlice */, deadline.timeRemaining() - 5) : 1e9);
|
|
589
|
+
let endTime = Date.now() + Math.min(this.chunkBudget, 100 /* Work.Slice */, deadline && !isInputPending ? Math.max(25 /* Work.MinSlice */, deadline.timeRemaining() - 5) : 1e9);
|
|
585
590
|
let viewportFirst = field.context.treeLen < vpTo && state.doc.length > vpTo + 1000;
|
|
586
591
|
let done = field.context.work(() => {
|
|
587
592
|
return isInputPending && isInputPending() || Date.now() > endTime;
|
|
588
|
-
}, vpTo + (viewportFirst ? 0 : 100000 /* MaxParseAhead */));
|
|
593
|
+
}, vpTo + (viewportFirst ? 0 : 100000 /* Work.MaxParseAhead */));
|
|
589
594
|
this.chunkBudget -= Date.now() - now;
|
|
590
595
|
if (done || this.chunkBudget <= 0) {
|
|
591
596
|
field.context.takeTree();
|
|
@@ -623,7 +628,14 @@ current language on a state.
|
|
|
623
628
|
*/
|
|
624
629
|
const language = state.Facet.define({
|
|
625
630
|
combine(languages) { return languages.length ? languages[0] : null; },
|
|
626
|
-
enables: [
|
|
631
|
+
enables: language => [
|
|
632
|
+
Language.state,
|
|
633
|
+
parseWorker,
|
|
634
|
+
view.EditorView.contentAttributes.compute([language], state => {
|
|
635
|
+
let lang = state.facet(language);
|
|
636
|
+
return lang && lang.name ? { "data-language": lang.name } : {};
|
|
637
|
+
})
|
|
638
|
+
]
|
|
627
639
|
});
|
|
628
640
|
/**
|
|
629
641
|
This class bundles a [language](https://codemirror.net/6/docs/ref/#language.Language) with an
|
|
@@ -753,8 +765,10 @@ class LanguageDescription {
|
|
|
753
765
|
|
|
754
766
|
/**
|
|
755
767
|
Facet that defines a way to provide a function that computes the
|
|
756
|
-
appropriate indentation depth
|
|
757
|
-
`
|
|
768
|
+
appropriate indentation depth, as a column number (see
|
|
769
|
+
[`indentString`](https://codemirror.net/6/docs/ref/#language.indentString)), at the start of a given
|
|
770
|
+
line, or `null` to indicate no appropriate indentation could be
|
|
771
|
+
determined.
|
|
758
772
|
*/
|
|
759
773
|
const indentService = state.Facet.define();
|
|
760
774
|
/**
|
|
@@ -799,12 +813,13 @@ function indentString(state, cols) {
|
|
|
799
813
|
return result;
|
|
800
814
|
}
|
|
801
815
|
/**
|
|
802
|
-
Get the indentation at the given position.
|
|
803
|
-
[indent services](https://codemirror.net/6/docs/ref/#language.indentService)
|
|
804
|
-
and if none of those return an indentation,
|
|
805
|
-
syntax tree for the [indent node
|
|
806
|
-
and use that if found. Returns a
|
|
807
|
-
be determined, and null
|
|
816
|
+
Get the indentation, as a column number, at the given position.
|
|
817
|
+
Will first consult any [indent services](https://codemirror.net/6/docs/ref/#language.indentService)
|
|
818
|
+
that are registered, and if none of those return an indentation,
|
|
819
|
+
this will check the syntax tree for the [indent node
|
|
820
|
+
prop](https://codemirror.net/6/docs/ref/#language.indentNodeProp) and use that if found. Returns a
|
|
821
|
+
number when an indentation could be determined, and null
|
|
822
|
+
otherwise.
|
|
808
823
|
*/
|
|
809
824
|
function getIndentation(context, pos) {
|
|
810
825
|
if (context instanceof state.EditorState)
|
|
@@ -827,6 +842,7 @@ function indentRange(state, from, to) {
|
|
|
827
842
|
let changes = [];
|
|
828
843
|
for (let pos = from; pos <= to;) {
|
|
829
844
|
let line = state.doc.lineAt(pos);
|
|
845
|
+
pos = line.to + 1;
|
|
830
846
|
let indent = getIndentation(context, line.from);
|
|
831
847
|
if (indent == null)
|
|
832
848
|
continue;
|
|
@@ -838,7 +854,6 @@ function indentRange(state, from, to) {
|
|
|
838
854
|
updated[line.from] = indent;
|
|
839
855
|
changes.push({ from: line.from, to: line.from + cur.length, insert: norm });
|
|
840
856
|
}
|
|
841
|
-
pos = line.to + 1;
|
|
842
857
|
}
|
|
843
858
|
return state.changes(changes);
|
|
844
859
|
}
|
|
@@ -939,8 +954,9 @@ class IndentContext {
|
|
|
939
954
|
/**
|
|
940
955
|
A syntax tree node prop used to associate indentation strategies
|
|
941
956
|
with node types. Such a strategy is a function from an indentation
|
|
942
|
-
context to a column number
|
|
943
|
-
|
|
957
|
+
context to a column number (see also
|
|
958
|
+
[`indentString`](https://codemirror.net/6/docs/ref/#language.indentString)) or null, where null
|
|
959
|
+
indicates that no definitive indentation can be determined.
|
|
944
960
|
*/
|
|
945
961
|
const indentNodeProp = new common.NodeProp();
|
|
946
962
|
// Compute the indentation for a given position from the syntax tree.
|
|
@@ -1531,7 +1547,12 @@ A highlight style associates CSS styles with higlighting
|
|
|
1531
1547
|
[tags](https://lezer.codemirror.net/docs/ref#highlight.Tag).
|
|
1532
1548
|
*/
|
|
1533
1549
|
class HighlightStyle {
|
|
1534
|
-
constructor(
|
|
1550
|
+
constructor(
|
|
1551
|
+
/**
|
|
1552
|
+
The tag styles used to create this highlight style.
|
|
1553
|
+
*/
|
|
1554
|
+
specs, options) {
|
|
1555
|
+
this.specs = specs;
|
|
1535
1556
|
let modSpec;
|
|
1536
1557
|
function def(spec) {
|
|
1537
1558
|
let cls = styleMod.StyleModule.newName();
|
|
@@ -1542,7 +1563,7 @@ class HighlightStyle {
|
|
|
1542
1563
|
const scopeOpt = options.scope;
|
|
1543
1564
|
this.scope = scopeOpt instanceof Language ? (type) => type.prop(languageDataProp) == scopeOpt.data
|
|
1544
1565
|
: scopeOpt ? (type) => type == scopeOpt : undefined;
|
|
1545
|
-
this.style = highlight.tagHighlighter(
|
|
1566
|
+
this.style = highlight.tagHighlighter(specs.map(style => ({
|
|
1546
1567
|
tag: style.tag,
|
|
1547
1568
|
class: style.class || def(Object.assign({}, style, { tag: null }))
|
|
1548
1569
|
})), {
|
|
@@ -1798,13 +1819,13 @@ function matchMarkedBrackets(_state, _pos, dir, token, matching, brackets) {
|
|
|
1798
1819
|
depth++;
|
|
1799
1820
|
}
|
|
1800
1821
|
else if (matchingNodes(cursor.type, -dir, brackets)) {
|
|
1801
|
-
depth--;
|
|
1802
1822
|
if (depth == 0)
|
|
1803
1823
|
return {
|
|
1804
1824
|
start: firstToken,
|
|
1805
1825
|
end: cursor.from == cursor.to ? undefined : { from: cursor.from, to: cursor.to },
|
|
1806
1826
|
matched: false
|
|
1807
1827
|
};
|
|
1828
|
+
depth--;
|
|
1808
1829
|
}
|
|
1809
1830
|
}
|
|
1810
1831
|
} while (dir < 0 ? cursor.prevSibling() : cursor.nextSibling());
|
|
@@ -2021,6 +2042,7 @@ class StringStream {
|
|
|
2021
2042
|
|
|
2022
2043
|
function fullParser(spec) {
|
|
2023
2044
|
return {
|
|
2045
|
+
name: spec.name || "",
|
|
2024
2046
|
token: spec.token,
|
|
2025
2047
|
blankLine: spec.blankLine || (() => { }),
|
|
2026
2048
|
startState: spec.startState || (() => true),
|
|
@@ -2053,7 +2075,7 @@ class StreamLanguage extends Language {
|
|
|
2053
2075
|
return new Parse(self, input, fragments, ranges);
|
|
2054
2076
|
}
|
|
2055
2077
|
};
|
|
2056
|
-
super(data, impl, [indentService.of((cx, pos) => this.getIndent(cx, pos))]);
|
|
2078
|
+
super(data, impl, [indentService.of((cx, pos) => this.getIndent(cx, pos))], parser.name);
|
|
2057
2079
|
this.topNode = docID(data);
|
|
2058
2080
|
self = this;
|
|
2059
2081
|
this.streamParser = p;
|
|
@@ -2079,7 +2101,7 @@ class StreamLanguage extends Language {
|
|
|
2079
2101
|
state = this.streamParser.startState(cx.unit);
|
|
2080
2102
|
statePos = 0;
|
|
2081
2103
|
}
|
|
2082
|
-
if (pos - statePos > 10000 /* MaxIndentScanDist */)
|
|
2104
|
+
if (pos - statePos > 10000 /* C.MaxIndentScanDist */)
|
|
2083
2105
|
return null;
|
|
2084
2106
|
while (statePos < pos) {
|
|
2085
2107
|
let line = cx.state.doc.lineAt(statePos), end = Math.min(pos, line.to);
|
|
@@ -2158,7 +2180,7 @@ class Parse {
|
|
|
2158
2180
|
this.chunks.push(tree.children[i]);
|
|
2159
2181
|
this.chunkPos.push(tree.positions[i]);
|
|
2160
2182
|
}
|
|
2161
|
-
if (context && this.parsedPos < context.viewport.from - 100000 /* MaxDistanceBeforeViewport */) {
|
|
2183
|
+
if (context && this.parsedPos < context.viewport.from - 100000 /* C.MaxDistanceBeforeViewport */) {
|
|
2162
2184
|
this.state = this.lang.streamParser.startState(getIndentUnit(context.state));
|
|
2163
2185
|
context.skipUntilInView(this.parsedPos, context.viewport.from);
|
|
2164
2186
|
this.parsedPos = context.viewport.from;
|
|
@@ -2168,7 +2190,7 @@ class Parse {
|
|
|
2168
2190
|
advance() {
|
|
2169
2191
|
let context = ParseContext.get();
|
|
2170
2192
|
let parseEnd = this.stoppedAt == null ? this.to : Math.min(this.to, this.stoppedAt);
|
|
2171
|
-
let end = Math.min(parseEnd, this.chunkStart + 2048 /* ChunkSize */);
|
|
2193
|
+
let end = Math.min(parseEnd, this.chunkStart + 2048 /* C.ChunkSize */);
|
|
2172
2194
|
if (context)
|
|
2173
2195
|
end = Math.min(end, context.viewport.to);
|
|
2174
2196
|
while (this.parsedPos < end)
|
|
@@ -2252,7 +2274,7 @@ class Parse {
|
|
|
2252
2274
|
let token = readToken(streamParser.token, stream, this.state);
|
|
2253
2275
|
if (token)
|
|
2254
2276
|
offset = this.emitToken(this.lang.tokenTable.resolve(token), this.parsedPos + stream.start, this.parsedPos + stream.pos, 4, offset);
|
|
2255
|
-
if (stream.start > 10000 /* MaxLineLength */)
|
|
2277
|
+
if (stream.start > 10000 /* C.MaxLineLength */)
|
|
2256
2278
|
break;
|
|
2257
2279
|
}
|
|
2258
2280
|
}
|
|
@@ -2268,7 +2290,7 @@ class Parse {
|
|
|
2268
2290
|
length: this.parsedPos - this.chunkStart,
|
|
2269
2291
|
nodeSet,
|
|
2270
2292
|
topID: 0,
|
|
2271
|
-
maxBufferLength: 2048 /* ChunkSize */,
|
|
2293
|
+
maxBufferLength: 2048 /* C.ChunkSize */,
|
|
2272
2294
|
reused: this.chunkReused
|
|
2273
2295
|
});
|
|
2274
2296
|
tree = new common.Tree(tree.type, tree.children, tree.positions, tree.length, [[this.lang.stateAfter, this.lang.streamParser.copyState(this.state)]]);
|
package/dist/index.d.ts
CHANGED
|
@@ -48,6 +48,10 @@ declare class Language {
|
|
|
48
48
|
[name: string]: any;
|
|
49
49
|
}>;
|
|
50
50
|
/**
|
|
51
|
+
A language name.
|
|
52
|
+
*/
|
|
53
|
+
readonly name: string;
|
|
54
|
+
/**
|
|
51
55
|
The extension value to install this as the document language.
|
|
52
56
|
*/
|
|
53
57
|
readonly extension: Extension;
|
|
@@ -70,7 +74,11 @@ declare class Language {
|
|
|
70
74
|
*/
|
|
71
75
|
data: Facet<{
|
|
72
76
|
[name: string]: any;
|
|
73
|
-
}>, parser: Parser, extraExtensions?: Extension[]
|
|
77
|
+
}>, parser: Parser, extraExtensions?: Extension[],
|
|
78
|
+
/**
|
|
79
|
+
A language name.
|
|
80
|
+
*/
|
|
81
|
+
name?: string);
|
|
74
82
|
/**
|
|
75
83
|
Query whether this language is active at the given position.
|
|
76
84
|
*/
|
|
@@ -102,6 +110,10 @@ declare class LRLanguage extends Language {
|
|
|
102
110
|
Define a language from a parser.
|
|
103
111
|
*/
|
|
104
112
|
static define(spec: {
|
|
113
|
+
/**
|
|
114
|
+
The [name](https://codemirror.net/6/docs/ref/#Language.name) of the language.
|
|
115
|
+
*/
|
|
116
|
+
name?: string;
|
|
105
117
|
/**
|
|
106
118
|
The parser to use. Should already have added editor-relevant
|
|
107
119
|
node props (and optionally things like dialect and top rule)
|
|
@@ -118,9 +130,9 @@ declare class LRLanguage extends Language {
|
|
|
118
130
|
}): LRLanguage;
|
|
119
131
|
/**
|
|
120
132
|
Create a new instance of this language with a reconfigured
|
|
121
|
-
version of its parser.
|
|
133
|
+
version of its parser and optionally a new name.
|
|
122
134
|
*/
|
|
123
|
-
configure(options: ParserConfig): LRLanguage;
|
|
135
|
+
configure(options: ParserConfig, name?: string): LRLanguage;
|
|
124
136
|
get allowsNesting(): boolean;
|
|
125
137
|
}
|
|
126
138
|
/**
|
|
@@ -349,8 +361,10 @@ declare class LanguageDescription {
|
|
|
349
361
|
|
|
350
362
|
/**
|
|
351
363
|
Facet that defines a way to provide a function that computes the
|
|
352
|
-
appropriate indentation depth
|
|
353
|
-
`
|
|
364
|
+
appropriate indentation depth, as a column number (see
|
|
365
|
+
[`indentString`](https://codemirror.net/6/docs/ref/#language.indentString)), at the start of a given
|
|
366
|
+
line, or `null` to indicate no appropriate indentation could be
|
|
367
|
+
determined.
|
|
354
368
|
*/
|
|
355
369
|
declare const indentService: Facet<(context: IndentContext, pos: number) => number | null, readonly ((context: IndentContext, pos: number) => number | null)[]>;
|
|
356
370
|
/**
|
|
@@ -374,12 +388,13 @@ tabs.
|
|
|
374
388
|
*/
|
|
375
389
|
declare function indentString(state: EditorState, cols: number): string;
|
|
376
390
|
/**
|
|
377
|
-
Get the indentation at the given position.
|
|
378
|
-
[indent services](https://codemirror.net/6/docs/ref/#language.indentService)
|
|
379
|
-
and if none of those return an indentation,
|
|
380
|
-
syntax tree for the [indent node
|
|
381
|
-
and use that if found. Returns a
|
|
382
|
-
be determined, and null
|
|
391
|
+
Get the indentation, as a column number, at the given position.
|
|
392
|
+
Will first consult any [indent services](https://codemirror.net/6/docs/ref/#language.indentService)
|
|
393
|
+
that are registered, and if none of those return an indentation,
|
|
394
|
+
this will check the syntax tree for the [indent node
|
|
395
|
+
prop](https://codemirror.net/6/docs/ref/#language.indentNodeProp) and use that if found. Returns a
|
|
396
|
+
number when an indentation could be determined, and null
|
|
397
|
+
otherwise.
|
|
383
398
|
*/
|
|
384
399
|
declare function getIndentation(context: IndentContext | EditorState, pos: number): number | null;
|
|
385
400
|
/**
|
|
@@ -477,8 +492,9 @@ declare class IndentContext {
|
|
|
477
492
|
/**
|
|
478
493
|
A syntax tree node prop used to associate indentation strategies
|
|
479
494
|
with node types. Such a strategy is a function from an indentation
|
|
480
|
-
context to a column number
|
|
481
|
-
|
|
495
|
+
context to a column number (see also
|
|
496
|
+
[`indentString`](https://codemirror.net/6/docs/ref/#language.indentString)) or null, where null
|
|
497
|
+
indicates that no definitive indentation can be determined.
|
|
482
498
|
*/
|
|
483
499
|
declare const indentNodeProp: NodeProp<(context: TreeIndentContext) => number | null>;
|
|
484
500
|
/**
|
|
@@ -732,6 +748,10 @@ A highlight style associates CSS styles with higlighting
|
|
|
732
748
|
[tags](https://lezer.codemirror.net/docs/ref#highlight.Tag).
|
|
733
749
|
*/
|
|
734
750
|
declare class HighlightStyle implements Highlighter {
|
|
751
|
+
/**
|
|
752
|
+
The tag styles used to create this highlight style.
|
|
753
|
+
*/
|
|
754
|
+
readonly specs: readonly TagStyle[];
|
|
735
755
|
/**
|
|
736
756
|
A style module holding the CSS rules for this highlight style.
|
|
737
757
|
When using
|
|
@@ -1013,6 +1033,10 @@ copyable) object with state, in which it can store information
|
|
|
1013
1033
|
about the current context.
|
|
1014
1034
|
*/
|
|
1015
1035
|
interface StreamParser<State> {
|
|
1036
|
+
/**
|
|
1037
|
+
A name for this language.
|
|
1038
|
+
*/
|
|
1039
|
+
name?: string;
|
|
1016
1040
|
/**
|
|
1017
1041
|
Produce a start state for the parser.
|
|
1018
1042
|
*/
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
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
|
-
import { ViewPlugin, logException,
|
|
3
|
+
import { ViewPlugin, logException, EditorView, Decoration, WidgetType, gutter, GutterMarker } from '@codemirror/view';
|
|
4
4
|
import { tags, tagHighlighter, highlightTree, styleTags } from '@lezer/highlight';
|
|
5
5
|
import { StyleModule } from 'style-mod';
|
|
6
6
|
|
|
@@ -45,8 +45,13 @@ class Language {
|
|
|
45
45
|
The [language data](https://codemirror.net/6/docs/ref/#state.EditorState.languageDataAt) facet
|
|
46
46
|
used for this language.
|
|
47
47
|
*/
|
|
48
|
-
data, parser, extraExtensions = []
|
|
48
|
+
data, parser, extraExtensions = [],
|
|
49
|
+
/**
|
|
50
|
+
A language name.
|
|
51
|
+
*/
|
|
52
|
+
name = "") {
|
|
49
53
|
this.data = data;
|
|
54
|
+
this.name = name;
|
|
50
55
|
// Kludge to define EditorState.tree as a debugging helper,
|
|
51
56
|
// without the EditorState package actually knowing about
|
|
52
57
|
// languages and lezer trees.
|
|
@@ -134,8 +139,8 @@ A subclass of [`Language`](https://codemirror.net/6/docs/ref/#language.Language)
|
|
|
134
139
|
parsers.
|
|
135
140
|
*/
|
|
136
141
|
class LRLanguage extends Language {
|
|
137
|
-
constructor(data, parser) {
|
|
138
|
-
super(data, parser);
|
|
142
|
+
constructor(data, parser, name) {
|
|
143
|
+
super(data, parser, [], name);
|
|
139
144
|
this.parser = parser;
|
|
140
145
|
}
|
|
141
146
|
/**
|
|
@@ -145,14 +150,14 @@ class LRLanguage extends Language {
|
|
|
145
150
|
let data = defineLanguageFacet(spec.languageData);
|
|
146
151
|
return new LRLanguage(data, spec.parser.configure({
|
|
147
152
|
props: [languageDataProp.add(type => type.isTop ? data : undefined)]
|
|
148
|
-
}));
|
|
153
|
+
}), spec.name);
|
|
149
154
|
}
|
|
150
155
|
/**
|
|
151
156
|
Create a new instance of this language with a reconfigured
|
|
152
|
-
version of its parser.
|
|
157
|
+
version of its parser and optionally a new name.
|
|
153
158
|
*/
|
|
154
|
-
configure(options) {
|
|
155
|
-
return new LRLanguage(this.data, this.parser.configure(options));
|
|
159
|
+
configure(options, name) {
|
|
160
|
+
return new LRLanguage(this.data, this.parser.configure(options), name || this.name);
|
|
156
161
|
}
|
|
157
162
|
get allowsNesting() { return this.parser.hasWrappers(); }
|
|
158
163
|
}
|
|
@@ -499,14 +504,14 @@ class LanguageState {
|
|
|
499
504
|
// state updates with parse work beyond the viewport.
|
|
500
505
|
let upto = this.context.treeLen == tr.startState.doc.length ? undefined
|
|
501
506
|
: Math.max(tr.changes.mapPos(this.context.treeLen), newCx.viewport.to);
|
|
502
|
-
if (!newCx.work(20 /* Apply */, upto))
|
|
507
|
+
if (!newCx.work(20 /* Work.Apply */, upto))
|
|
503
508
|
newCx.takeTree();
|
|
504
509
|
return new LanguageState(newCx);
|
|
505
510
|
}
|
|
506
511
|
static init(state) {
|
|
507
|
-
let vpTo = Math.min(3000 /* InitViewport */, state.doc.length);
|
|
512
|
+
let vpTo = Math.min(3000 /* Work.InitViewport */, state.doc.length);
|
|
508
513
|
let parseState = ParseContext.create(state.facet(language).parser, state, { from: 0, to: vpTo });
|
|
509
|
-
if (!parseState.work(20 /* Apply */, vpTo))
|
|
514
|
+
if (!parseState.work(20 /* Work.Apply */, vpTo))
|
|
510
515
|
parseState.takeTree();
|
|
511
516
|
return new LanguageState(parseState);
|
|
512
517
|
}
|
|
@@ -523,14 +528,14 @@ Language.state = /*@__PURE__*/StateField.define({
|
|
|
523
528
|
}
|
|
524
529
|
});
|
|
525
530
|
let requestIdle = (callback) => {
|
|
526
|
-
let timeout = setTimeout(() => callback(), 500 /* MaxPause */);
|
|
531
|
+
let timeout = setTimeout(() => callback(), 500 /* Work.MaxPause */);
|
|
527
532
|
return () => clearTimeout(timeout);
|
|
528
533
|
};
|
|
529
534
|
if (typeof requestIdleCallback != "undefined")
|
|
530
535
|
requestIdle = (callback) => {
|
|
531
536
|
let idle = -1, timeout = setTimeout(() => {
|
|
532
|
-
idle = requestIdleCallback(callback, { timeout: 500 /* MaxPause */ - 100 /* MinPause */ });
|
|
533
|
-
}, 100 /* MinPause */);
|
|
537
|
+
idle = requestIdleCallback(callback, { timeout: 500 /* Work.MaxPause */ - 100 /* Work.MinPause */ });
|
|
538
|
+
}, 100 /* Work.MinPause */);
|
|
534
539
|
return () => idle < 0 ? clearTimeout(timeout) : cancelIdleCallback(idle);
|
|
535
540
|
};
|
|
536
541
|
const isInputPending = typeof navigator != "undefined" && ((_a = navigator.scheduling) === null || _a === void 0 ? void 0 : _a.isInputPending)
|
|
@@ -553,7 +558,7 @@ const parseWorker = /*@__PURE__*/ViewPlugin.fromClass(class ParseWorker {
|
|
|
553
558
|
this.scheduleWork();
|
|
554
559
|
if (update.docChanged) {
|
|
555
560
|
if (this.view.hasFocus)
|
|
556
|
-
this.chunkBudget += 50 /* ChangeBonus */;
|
|
561
|
+
this.chunkBudget += 50 /* Work.ChangeBonus */;
|
|
557
562
|
this.scheduleWork();
|
|
558
563
|
}
|
|
559
564
|
this.checkAsyncSchedule(cx);
|
|
@@ -569,19 +574,19 @@ const parseWorker = /*@__PURE__*/ViewPlugin.fromClass(class ParseWorker {
|
|
|
569
574
|
this.working = null;
|
|
570
575
|
let now = Date.now();
|
|
571
576
|
if (this.chunkEnd < now && (this.chunkEnd < 0 || this.view.hasFocus)) { // Start a new chunk
|
|
572
|
-
this.chunkEnd = now + 30000 /* ChunkTime */;
|
|
573
|
-
this.chunkBudget = 3000 /* ChunkBudget */;
|
|
577
|
+
this.chunkEnd = now + 30000 /* Work.ChunkTime */;
|
|
578
|
+
this.chunkBudget = 3000 /* Work.ChunkBudget */;
|
|
574
579
|
}
|
|
575
580
|
if (this.chunkBudget <= 0)
|
|
576
581
|
return; // No more budget
|
|
577
582
|
let { state, viewport: { to: vpTo } } = this.view, field = state.field(Language.state);
|
|
578
|
-
if (field.tree == field.context.tree && field.context.isDone(vpTo + 100000 /* MaxParseAhead */))
|
|
583
|
+
if (field.tree == field.context.tree && field.context.isDone(vpTo + 100000 /* Work.MaxParseAhead */))
|
|
579
584
|
return;
|
|
580
|
-
let endTime = Date.now() + Math.min(this.chunkBudget, 100 /* Slice */, deadline && !isInputPending ? Math.max(25 /* MinSlice */, deadline.timeRemaining() - 5) : 1e9);
|
|
585
|
+
let endTime = Date.now() + Math.min(this.chunkBudget, 100 /* Work.Slice */, deadline && !isInputPending ? Math.max(25 /* Work.MinSlice */, deadline.timeRemaining() - 5) : 1e9);
|
|
581
586
|
let viewportFirst = field.context.treeLen < vpTo && state.doc.length > vpTo + 1000;
|
|
582
587
|
let done = field.context.work(() => {
|
|
583
588
|
return isInputPending && isInputPending() || Date.now() > endTime;
|
|
584
|
-
}, vpTo + (viewportFirst ? 0 : 100000 /* MaxParseAhead */));
|
|
589
|
+
}, vpTo + (viewportFirst ? 0 : 100000 /* Work.MaxParseAhead */));
|
|
585
590
|
this.chunkBudget -= Date.now() - now;
|
|
586
591
|
if (done || this.chunkBudget <= 0) {
|
|
587
592
|
field.context.takeTree();
|
|
@@ -619,7 +624,14 @@ current language on a state.
|
|
|
619
624
|
*/
|
|
620
625
|
const language = /*@__PURE__*/Facet.define({
|
|
621
626
|
combine(languages) { return languages.length ? languages[0] : null; },
|
|
622
|
-
enables: [
|
|
627
|
+
enables: language => [
|
|
628
|
+
Language.state,
|
|
629
|
+
parseWorker,
|
|
630
|
+
EditorView.contentAttributes.compute([language], state => {
|
|
631
|
+
let lang = state.facet(language);
|
|
632
|
+
return lang && lang.name ? { "data-language": lang.name } : {};
|
|
633
|
+
})
|
|
634
|
+
]
|
|
623
635
|
});
|
|
624
636
|
/**
|
|
625
637
|
This class bundles a [language](https://codemirror.net/6/docs/ref/#language.Language) with an
|
|
@@ -749,8 +761,10 @@ class LanguageDescription {
|
|
|
749
761
|
|
|
750
762
|
/**
|
|
751
763
|
Facet that defines a way to provide a function that computes the
|
|
752
|
-
appropriate indentation depth
|
|
753
|
-
`
|
|
764
|
+
appropriate indentation depth, as a column number (see
|
|
765
|
+
[`indentString`](https://codemirror.net/6/docs/ref/#language.indentString)), at the start of a given
|
|
766
|
+
line, or `null` to indicate no appropriate indentation could be
|
|
767
|
+
determined.
|
|
754
768
|
*/
|
|
755
769
|
const indentService = /*@__PURE__*/Facet.define();
|
|
756
770
|
/**
|
|
@@ -795,12 +809,13 @@ function indentString(state, cols) {
|
|
|
795
809
|
return result;
|
|
796
810
|
}
|
|
797
811
|
/**
|
|
798
|
-
Get the indentation at the given position.
|
|
799
|
-
[indent services](https://codemirror.net/6/docs/ref/#language.indentService)
|
|
800
|
-
and if none of those return an indentation,
|
|
801
|
-
syntax tree for the [indent node
|
|
802
|
-
and use that if found. Returns a
|
|
803
|
-
be determined, and null
|
|
812
|
+
Get the indentation, as a column number, at the given position.
|
|
813
|
+
Will first consult any [indent services](https://codemirror.net/6/docs/ref/#language.indentService)
|
|
814
|
+
that are registered, and if none of those return an indentation,
|
|
815
|
+
this will check the syntax tree for the [indent node
|
|
816
|
+
prop](https://codemirror.net/6/docs/ref/#language.indentNodeProp) and use that if found. Returns a
|
|
817
|
+
number when an indentation could be determined, and null
|
|
818
|
+
otherwise.
|
|
804
819
|
*/
|
|
805
820
|
function getIndentation(context, pos) {
|
|
806
821
|
if (context instanceof EditorState)
|
|
@@ -823,6 +838,7 @@ function indentRange(state, from, to) {
|
|
|
823
838
|
let changes = [];
|
|
824
839
|
for (let pos = from; pos <= to;) {
|
|
825
840
|
let line = state.doc.lineAt(pos);
|
|
841
|
+
pos = line.to + 1;
|
|
826
842
|
let indent = getIndentation(context, line.from);
|
|
827
843
|
if (indent == null)
|
|
828
844
|
continue;
|
|
@@ -834,7 +850,6 @@ function indentRange(state, from, to) {
|
|
|
834
850
|
updated[line.from] = indent;
|
|
835
851
|
changes.push({ from: line.from, to: line.from + cur.length, insert: norm });
|
|
836
852
|
}
|
|
837
|
-
pos = line.to + 1;
|
|
838
853
|
}
|
|
839
854
|
return state.changes(changes);
|
|
840
855
|
}
|
|
@@ -935,8 +950,9 @@ class IndentContext {
|
|
|
935
950
|
/**
|
|
936
951
|
A syntax tree node prop used to associate indentation strategies
|
|
937
952
|
with node types. Such a strategy is a function from an indentation
|
|
938
|
-
context to a column number
|
|
939
|
-
|
|
953
|
+
context to a column number (see also
|
|
954
|
+
[`indentString`](https://codemirror.net/6/docs/ref/#language.indentString)) or null, where null
|
|
955
|
+
indicates that no definitive indentation can be determined.
|
|
940
956
|
*/
|
|
941
957
|
const indentNodeProp = /*@__PURE__*/new NodeProp();
|
|
942
958
|
// Compute the indentation for a given position from the syntax tree.
|
|
@@ -1527,7 +1543,12 @@ A highlight style associates CSS styles with higlighting
|
|
|
1527
1543
|
[tags](https://lezer.codemirror.net/docs/ref#highlight.Tag).
|
|
1528
1544
|
*/
|
|
1529
1545
|
class HighlightStyle {
|
|
1530
|
-
constructor(
|
|
1546
|
+
constructor(
|
|
1547
|
+
/**
|
|
1548
|
+
The tag styles used to create this highlight style.
|
|
1549
|
+
*/
|
|
1550
|
+
specs, options) {
|
|
1551
|
+
this.specs = specs;
|
|
1531
1552
|
let modSpec;
|
|
1532
1553
|
function def(spec) {
|
|
1533
1554
|
let cls = StyleModule.newName();
|
|
@@ -1538,7 +1559,7 @@ class HighlightStyle {
|
|
|
1538
1559
|
const scopeOpt = options.scope;
|
|
1539
1560
|
this.scope = scopeOpt instanceof Language ? (type) => type.prop(languageDataProp) == scopeOpt.data
|
|
1540
1561
|
: scopeOpt ? (type) => type == scopeOpt : undefined;
|
|
1541
|
-
this.style = tagHighlighter(
|
|
1562
|
+
this.style = tagHighlighter(specs.map(style => ({
|
|
1542
1563
|
tag: style.tag,
|
|
1543
1564
|
class: style.class || def(Object.assign({}, style, { tag: null }))
|
|
1544
1565
|
})), {
|
|
@@ -1794,13 +1815,13 @@ function matchMarkedBrackets(_state, _pos, dir, token, matching, brackets) {
|
|
|
1794
1815
|
depth++;
|
|
1795
1816
|
}
|
|
1796
1817
|
else if (matchingNodes(cursor.type, -dir, brackets)) {
|
|
1797
|
-
depth--;
|
|
1798
1818
|
if (depth == 0)
|
|
1799
1819
|
return {
|
|
1800
1820
|
start: firstToken,
|
|
1801
1821
|
end: cursor.from == cursor.to ? undefined : { from: cursor.from, to: cursor.to },
|
|
1802
1822
|
matched: false
|
|
1803
1823
|
};
|
|
1824
|
+
depth--;
|
|
1804
1825
|
}
|
|
1805
1826
|
}
|
|
1806
1827
|
} while (dir < 0 ? cursor.prevSibling() : cursor.nextSibling());
|
|
@@ -2017,6 +2038,7 @@ class StringStream {
|
|
|
2017
2038
|
|
|
2018
2039
|
function fullParser(spec) {
|
|
2019
2040
|
return {
|
|
2041
|
+
name: spec.name || "",
|
|
2020
2042
|
token: spec.token,
|
|
2021
2043
|
blankLine: spec.blankLine || (() => { }),
|
|
2022
2044
|
startState: spec.startState || (() => true),
|
|
@@ -2049,7 +2071,7 @@ class StreamLanguage extends Language {
|
|
|
2049
2071
|
return new Parse(self, input, fragments, ranges);
|
|
2050
2072
|
}
|
|
2051
2073
|
};
|
|
2052
|
-
super(data, impl, [indentService.of((cx, pos) => this.getIndent(cx, pos))]);
|
|
2074
|
+
super(data, impl, [indentService.of((cx, pos) => this.getIndent(cx, pos))], parser.name);
|
|
2053
2075
|
this.topNode = docID(data);
|
|
2054
2076
|
self = this;
|
|
2055
2077
|
this.streamParser = p;
|
|
@@ -2075,7 +2097,7 @@ class StreamLanguage extends Language {
|
|
|
2075
2097
|
state = this.streamParser.startState(cx.unit);
|
|
2076
2098
|
statePos = 0;
|
|
2077
2099
|
}
|
|
2078
|
-
if (pos - statePos > 10000 /* MaxIndentScanDist */)
|
|
2100
|
+
if (pos - statePos > 10000 /* C.MaxIndentScanDist */)
|
|
2079
2101
|
return null;
|
|
2080
2102
|
while (statePos < pos) {
|
|
2081
2103
|
let line = cx.state.doc.lineAt(statePos), end = Math.min(pos, line.to);
|
|
@@ -2154,7 +2176,7 @@ class Parse {
|
|
|
2154
2176
|
this.chunks.push(tree.children[i]);
|
|
2155
2177
|
this.chunkPos.push(tree.positions[i]);
|
|
2156
2178
|
}
|
|
2157
|
-
if (context && this.parsedPos < context.viewport.from - 100000 /* MaxDistanceBeforeViewport */) {
|
|
2179
|
+
if (context && this.parsedPos < context.viewport.from - 100000 /* C.MaxDistanceBeforeViewport */) {
|
|
2158
2180
|
this.state = this.lang.streamParser.startState(getIndentUnit(context.state));
|
|
2159
2181
|
context.skipUntilInView(this.parsedPos, context.viewport.from);
|
|
2160
2182
|
this.parsedPos = context.viewport.from;
|
|
@@ -2164,7 +2186,7 @@ class Parse {
|
|
|
2164
2186
|
advance() {
|
|
2165
2187
|
let context = ParseContext.get();
|
|
2166
2188
|
let parseEnd = this.stoppedAt == null ? this.to : Math.min(this.to, this.stoppedAt);
|
|
2167
|
-
let end = Math.min(parseEnd, this.chunkStart + 2048 /* ChunkSize */);
|
|
2189
|
+
let end = Math.min(parseEnd, this.chunkStart + 2048 /* C.ChunkSize */);
|
|
2168
2190
|
if (context)
|
|
2169
2191
|
end = Math.min(end, context.viewport.to);
|
|
2170
2192
|
while (this.parsedPos < end)
|
|
@@ -2248,7 +2270,7 @@ class Parse {
|
|
|
2248
2270
|
let token = readToken(streamParser.token, stream, this.state);
|
|
2249
2271
|
if (token)
|
|
2250
2272
|
offset = this.emitToken(this.lang.tokenTable.resolve(token), this.parsedPos + stream.start, this.parsedPos + stream.pos, 4, offset);
|
|
2251
|
-
if (stream.start > 10000 /* MaxLineLength */)
|
|
2273
|
+
if (stream.start > 10000 /* C.MaxLineLength */)
|
|
2252
2274
|
break;
|
|
2253
2275
|
}
|
|
2254
2276
|
}
|
|
@@ -2264,7 +2286,7 @@ class Parse {
|
|
|
2264
2286
|
length: this.parsedPos - this.chunkStart,
|
|
2265
2287
|
nodeSet,
|
|
2266
2288
|
topID: 0,
|
|
2267
|
-
maxBufferLength: 2048 /* ChunkSize */,
|
|
2289
|
+
maxBufferLength: 2048 /* C.ChunkSize */,
|
|
2268
2290
|
reused: this.chunkReused
|
|
2269
2291
|
});
|
|
2270
2292
|
tree = new Tree(tree.type, tree.children, tree.positions, tree.length, [[this.lang.stateAfter, this.lang.streamParser.copyState(this.state)]]);
|