@codemirror/language 6.4.0 → 6.6.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 +18 -0
- package/LICENSE +1 -1
- package/dist/index.cjs +97 -27
- package/dist/index.d.ts +53 -8
- package/dist/index.js +96 -28
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,21 @@
|
|
|
1
|
+
## 6.6.0 (2023-02-13)
|
|
2
|
+
|
|
3
|
+
### New features
|
|
4
|
+
|
|
5
|
+
Syntax-driven language data queries now support sublanguages, which make it possible to return different data for specific parts of the tree produced by a single language.
|
|
6
|
+
|
|
7
|
+
## 6.5.0 (2023-02-07)
|
|
8
|
+
|
|
9
|
+
### Bug fixes
|
|
10
|
+
|
|
11
|
+
Make indentation for stream languages more reliable by having `StringStream.indentation` return overridden indentations from the indent context.
|
|
12
|
+
|
|
13
|
+
### New features
|
|
14
|
+
|
|
15
|
+
The `toggleFold` command folds or unfolds depending on whether there's an existing folded range on the current line.
|
|
16
|
+
|
|
17
|
+
`indentUnit` now accepts any (repeated) whitespace character, not just spaces and tabs.
|
|
18
|
+
|
|
1
19
|
## 6.4.0 (2023-01-12)
|
|
2
20
|
|
|
3
21
|
### New features
|
package/LICENSE
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
MIT License
|
|
2
2
|
|
|
3
|
-
Copyright (C) 2018-2021 by Marijn Haverbeke <
|
|
3
|
+
Copyright (C) 2018-2021 by Marijn Haverbeke <marijn@haverbeke.berlin> and others
|
|
4
4
|
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
package/dist/index.cjs
CHANGED
|
@@ -28,6 +28,11 @@ function defineLanguageFacet(baseData) {
|
|
|
28
28
|
});
|
|
29
29
|
}
|
|
30
30
|
/**
|
|
31
|
+
Syntax node prop used to register sublangauges. Should be added to
|
|
32
|
+
the top level node type for the language.
|
|
33
|
+
*/
|
|
34
|
+
const sublanguageProp = new common.NodeProp();
|
|
35
|
+
/**
|
|
31
36
|
A language object manages parsing and per-language
|
|
32
37
|
[metadata](https://codemirror.net/6/docs/ref/#state.EditorState.languageDataAt). Parse data is
|
|
33
38
|
managed as a [Lezer](https://lezer.codemirror.net) tree. The class
|
|
@@ -64,14 +69,28 @@ class Language {
|
|
|
64
69
|
this.parser = parser;
|
|
65
70
|
this.extension = [
|
|
66
71
|
language.of(this),
|
|
67
|
-
state.EditorState.languageData.of((state, pos, side) =>
|
|
72
|
+
state.EditorState.languageData.of((state, pos, side) => {
|
|
73
|
+
let top = topNodeAt(state, pos, side), data = top.type.prop(languageDataProp);
|
|
74
|
+
if (!data)
|
|
75
|
+
return [];
|
|
76
|
+
let base = state.facet(data), sub = top.type.prop(sublanguageProp);
|
|
77
|
+
if (sub) {
|
|
78
|
+
let innerNode = top.resolve(pos - top.from, side);
|
|
79
|
+
for (let sublang of sub)
|
|
80
|
+
if (sublang.test(innerNode, state)) {
|
|
81
|
+
let data = state.facet(sublang.facet);
|
|
82
|
+
return sublang.type == "replace" ? data : data.concat(base);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return base;
|
|
86
|
+
})
|
|
68
87
|
].concat(extraExtensions);
|
|
69
88
|
}
|
|
70
89
|
/**
|
|
71
90
|
Query whether this language is active at the given position.
|
|
72
91
|
*/
|
|
73
92
|
isActiveAt(state, pos, side = -1) {
|
|
74
|
-
return
|
|
93
|
+
return topNodeAt(state, pos, side).type.prop(languageDataProp) == this.data;
|
|
75
94
|
}
|
|
76
95
|
/**
|
|
77
96
|
Find the document regions that were parsed using this language.
|
|
@@ -126,16 +145,14 @@ class Language {
|
|
|
126
145
|
@internal
|
|
127
146
|
*/
|
|
128
147
|
Language.setState = state.StateEffect.define();
|
|
129
|
-
function
|
|
130
|
-
let topLang = state.facet(language);
|
|
131
|
-
if (!topLang)
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
for (let node = syntaxTree(state).topNode; node; node = node.enter(pos, side, common.IterMode.ExcludeBuffers))
|
|
136
|
-
facet = node.type.prop(languageDataProp) || facet;
|
|
148
|
+
function topNodeAt(state, pos, side) {
|
|
149
|
+
let topLang = state.facet(language), tree = syntaxTree(state).topNode;
|
|
150
|
+
if (!topLang || topLang.allowsNesting) {
|
|
151
|
+
for (let node = tree; node; node = node.enter(pos, side, common.IterMode.ExcludeBuffers))
|
|
152
|
+
if (node.type.isTop)
|
|
153
|
+
tree = node;
|
|
137
154
|
}
|
|
138
|
-
return
|
|
155
|
+
return tree;
|
|
139
156
|
}
|
|
140
157
|
/**
|
|
141
158
|
A subclass of [`Language`](https://codemirror.net/6/docs/ref/#language.Language) for use with Lezer
|
|
@@ -229,13 +246,13 @@ function syntaxParserRunning(view) {
|
|
|
229
246
|
}
|
|
230
247
|
// Lezer-style Input object for a Text document.
|
|
231
248
|
class DocInput {
|
|
232
|
-
constructor(doc
|
|
249
|
+
constructor(doc) {
|
|
233
250
|
this.doc = doc;
|
|
234
|
-
this.length = length;
|
|
235
251
|
this.cursorPos = 0;
|
|
236
252
|
this.string = "";
|
|
237
253
|
this.cursor = doc.iter();
|
|
238
254
|
}
|
|
255
|
+
get length() { return this.doc.length; }
|
|
239
256
|
syncTo(pos) {
|
|
240
257
|
this.string = this.cursor.next(pos - this.cursorPos).value;
|
|
241
258
|
this.cursorPos = pos + this.string.length;
|
|
@@ -780,17 +797,18 @@ service.
|
|
|
780
797
|
*/
|
|
781
798
|
const indentService = state.Facet.define();
|
|
782
799
|
/**
|
|
783
|
-
Facet for overriding the unit by which indentation happens.
|
|
784
|
-
|
|
785
|
-
|
|
800
|
+
Facet for overriding the unit by which indentation happens. Should
|
|
801
|
+
be a string consisting either entirely of the same whitespace
|
|
802
|
+
character. When not set, this defaults to 2 spaces.
|
|
786
803
|
*/
|
|
787
804
|
const indentUnit = state.Facet.define({
|
|
788
805
|
combine: values => {
|
|
789
806
|
if (!values.length)
|
|
790
807
|
return " ";
|
|
791
|
-
|
|
808
|
+
let unit = values[0];
|
|
809
|
+
if (!unit || /\S/.test(unit) || Array.from(unit).some(e => e != unit[0]))
|
|
792
810
|
throw new Error("Invalid indent unit: " + JSON.stringify(values[0]));
|
|
793
|
-
return
|
|
811
|
+
return unit;
|
|
794
812
|
}
|
|
795
813
|
});
|
|
796
814
|
/**
|
|
@@ -810,14 +828,16 @@ Will use tabs for as much of the columns as possible when the
|
|
|
810
828
|
tabs.
|
|
811
829
|
*/
|
|
812
830
|
function indentString(state, cols) {
|
|
813
|
-
let result = "", ts = state.tabSize;
|
|
814
|
-
if (
|
|
831
|
+
let result = "", ts = state.tabSize, ch = state.facet(indentUnit)[0];
|
|
832
|
+
if (ch == "\t") {
|
|
815
833
|
while (cols >= ts) {
|
|
816
834
|
result += "\t";
|
|
817
835
|
cols -= ts;
|
|
818
836
|
}
|
|
837
|
+
ch = " ";
|
|
838
|
+
}
|
|
819
839
|
for (let i = 0; i < cols; i++)
|
|
820
|
-
result +=
|
|
840
|
+
result += ch;
|
|
821
841
|
return result;
|
|
822
842
|
}
|
|
823
843
|
/**
|
|
@@ -1400,6 +1420,41 @@ const unfoldAll = view => {
|
|
|
1400
1420
|
view.dispatch({ effects });
|
|
1401
1421
|
return true;
|
|
1402
1422
|
};
|
|
1423
|
+
// Find the foldable region containing the given line, if one exists
|
|
1424
|
+
function foldableContainer(view, lineBlock) {
|
|
1425
|
+
// Look backwards through line blocks until we find a foldable region that
|
|
1426
|
+
// intersects with the line
|
|
1427
|
+
for (let line = lineBlock;;) {
|
|
1428
|
+
let foldableRegion = foldable(view.state, line.from, line.to);
|
|
1429
|
+
if (foldableRegion && foldableRegion.to > lineBlock.from)
|
|
1430
|
+
return foldableRegion;
|
|
1431
|
+
if (!line.from)
|
|
1432
|
+
return null;
|
|
1433
|
+
line = view.lineBlockAt(line.from - 1);
|
|
1434
|
+
}
|
|
1435
|
+
}
|
|
1436
|
+
/**
|
|
1437
|
+
Toggle folding at cursors. Unfolds if there is an existing fold
|
|
1438
|
+
starting in that line, tries to find a foldable range around it
|
|
1439
|
+
otherwise.
|
|
1440
|
+
*/
|
|
1441
|
+
const toggleFold = (view) => {
|
|
1442
|
+
let effects = [];
|
|
1443
|
+
for (let line of selectedLines(view)) {
|
|
1444
|
+
let folded = findFold(view.state, line.from, line.to);
|
|
1445
|
+
if (folded) {
|
|
1446
|
+
effects.push(unfoldEffect.of(folded), announceFold(view, folded, false));
|
|
1447
|
+
}
|
|
1448
|
+
else {
|
|
1449
|
+
let foldRange = foldableContainer(view, line);
|
|
1450
|
+
if (foldRange)
|
|
1451
|
+
effects.push(foldEffect.of(foldRange), announceFold(view, foldRange));
|
|
1452
|
+
}
|
|
1453
|
+
}
|
|
1454
|
+
if (effects.length > 0)
|
|
1455
|
+
view.dispatch({ effects: maybeEnable(view.state, effects) });
|
|
1456
|
+
return !!effects.length;
|
|
1457
|
+
};
|
|
1403
1458
|
/**
|
|
1404
1459
|
Default fold-related key bindings.
|
|
1405
1460
|
|
|
@@ -1923,10 +1978,11 @@ class StringStream {
|
|
|
1923
1978
|
/**
|
|
1924
1979
|
The current indent unit size.
|
|
1925
1980
|
*/
|
|
1926
|
-
indentUnit) {
|
|
1981
|
+
indentUnit, overrideIndent) {
|
|
1927
1982
|
this.string = string;
|
|
1928
1983
|
this.tabSize = tabSize;
|
|
1929
1984
|
this.indentUnit = indentUnit;
|
|
1985
|
+
this.overrideIndent = overrideIndent;
|
|
1930
1986
|
/**
|
|
1931
1987
|
The current position on the line.
|
|
1932
1988
|
*/
|
|
@@ -2027,7 +2083,8 @@ class StringStream {
|
|
|
2027
2083
|
Get the indentation column of the current line.
|
|
2028
2084
|
*/
|
|
2029
2085
|
indentation() {
|
|
2030
|
-
|
|
2086
|
+
var _a;
|
|
2087
|
+
return (_a = this.overrideIndent) !== null && _a !== void 0 ? _a : countCol(this.string, null, this.tabSize);
|
|
2031
2088
|
}
|
|
2032
2089
|
/**
|
|
2033
2090
|
Match the input against the given string or regular expression
|
|
@@ -2089,6 +2146,7 @@ function defaultCopyState(state) {
|
|
|
2089
2146
|
}
|
|
2090
2147
|
return newState;
|
|
2091
2148
|
}
|
|
2149
|
+
const IndentedFrom = new WeakMap();
|
|
2092
2150
|
/**
|
|
2093
2151
|
A [language](https://codemirror.net/6/docs/ref/#language.Language) class based on a CodeMirror
|
|
2094
2152
|
5-style [streaming parser](https://codemirror.net/6/docs/ref/#language.StreamParser).
|
|
@@ -2119,7 +2177,14 @@ class StreamLanguage extends Language {
|
|
|
2119
2177
|
at = at.parent;
|
|
2120
2178
|
if (!at)
|
|
2121
2179
|
return null;
|
|
2122
|
-
let
|
|
2180
|
+
let from = undefined;
|
|
2181
|
+
let { overrideIndentation } = cx.options;
|
|
2182
|
+
if (overrideIndentation) {
|
|
2183
|
+
from = IndentedFrom.get(cx.state);
|
|
2184
|
+
if (from != null && from < pos - 1e4)
|
|
2185
|
+
from = undefined;
|
|
2186
|
+
}
|
|
2187
|
+
let start = findState(this, tree, 0, at.from, from !== null && from !== void 0 ? from : pos), statePos, state;
|
|
2123
2188
|
if (start) {
|
|
2124
2189
|
state = start.state;
|
|
2125
2190
|
statePos = start.pos + 1;
|
|
@@ -2133,7 +2198,8 @@ class StreamLanguage extends Language {
|
|
|
2133
2198
|
while (statePos < pos) {
|
|
2134
2199
|
let line = cx.state.doc.lineAt(statePos), end = Math.min(pos, line.to);
|
|
2135
2200
|
if (line.length) {
|
|
2136
|
-
let
|
|
2201
|
+
let indentation = overrideIndentation ? overrideIndentation(line.from) : -1;
|
|
2202
|
+
let stream = new StringStream(line.text, cx.state.tabSize, cx.unit, indentation < 0 ? undefined : indentation);
|
|
2137
2203
|
while (stream.pos < end - line.from)
|
|
2138
2204
|
readToken(this.streamParser.token, stream, state);
|
|
2139
2205
|
}
|
|
@@ -2144,8 +2210,10 @@ class StreamLanguage extends Language {
|
|
|
2144
2210
|
break;
|
|
2145
2211
|
statePos = line.to + 1;
|
|
2146
2212
|
}
|
|
2147
|
-
let
|
|
2148
|
-
|
|
2213
|
+
let line = cx.lineAt(pos);
|
|
2214
|
+
if (overrideIndentation && from == null)
|
|
2215
|
+
IndentedFrom.set(cx.state, line.from);
|
|
2216
|
+
return this.streamParser.indent(state, /^\s*(.*)/.exec(line.text)[1], cx);
|
|
2149
2217
|
}
|
|
2150
2218
|
get allowsNesting() { return false; }
|
|
2151
2219
|
}
|
|
@@ -2455,10 +2523,12 @@ exports.indentUnit = indentUnit;
|
|
|
2455
2523
|
exports.language = language;
|
|
2456
2524
|
exports.languageDataProp = languageDataProp;
|
|
2457
2525
|
exports.matchBrackets = matchBrackets;
|
|
2526
|
+
exports.sublanguageProp = sublanguageProp;
|
|
2458
2527
|
exports.syntaxHighlighting = syntaxHighlighting;
|
|
2459
2528
|
exports.syntaxParserRunning = syntaxParserRunning;
|
|
2460
2529
|
exports.syntaxTree = syntaxTree;
|
|
2461
2530
|
exports.syntaxTreeAvailable = syntaxTreeAvailable;
|
|
2531
|
+
exports.toggleFold = toggleFold;
|
|
2462
2532
|
exports.unfoldAll = unfoldAll;
|
|
2463
2533
|
exports.unfoldCode = unfoldCode;
|
|
2464
2534
|
exports.unfoldEffect = unfoldEffect;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { NodeProp, Parser, Tree, TreeFragment,
|
|
1
|
+
import { NodeProp, SyntaxNode, Parser, Tree, TreeFragment, NodeType } from '@lezer/common';
|
|
2
2
|
import { LRParser, ParserConfig } from '@lezer/lr';
|
|
3
3
|
import * as _codemirror_state from '@codemirror/state';
|
|
4
|
-
import { Facet,
|
|
4
|
+
import { Facet, EditorState, Extension, StateField, Range } from '@codemirror/state';
|
|
5
5
|
import { EditorView, DecorationSet, Command, KeyBinding, ViewUpdate, BlockInfo, Decoration } from '@codemirror/view';
|
|
6
6
|
import { Highlighter, Tag } from '@lezer/highlight';
|
|
7
7
|
import { StyleModule, StyleSpec } from 'style-mod';
|
|
@@ -31,6 +31,44 @@ declare function defineLanguageFacet(baseData?: {
|
|
|
31
31
|
[name: string]: any;
|
|
32
32
|
}[]>;
|
|
33
33
|
/**
|
|
34
|
+
Some languages need to return different [language
|
|
35
|
+
data](https://codemirror.net/6/docs/ref/#state.EditorState.languageDataAt) for some parts of their
|
|
36
|
+
tree. Sublanguages, registered by adding a [node
|
|
37
|
+
prop](https://codemirror.net/6/docs/ref/#language.sublanguageProp) to the language's top syntax
|
|
38
|
+
node, provide a mechanism to do this.
|
|
39
|
+
|
|
40
|
+
(Note that when using nested parsing, where nested syntax is
|
|
41
|
+
parsed by a different parser and has its own top node type, you
|
|
42
|
+
don't need a sublanguage.)
|
|
43
|
+
*/
|
|
44
|
+
interface Sublanguage {
|
|
45
|
+
/**
|
|
46
|
+
Determines whether the data provided by this sublanguage should
|
|
47
|
+
completely replace the regular data or be added to it (with
|
|
48
|
+
higher-precedence). The default is `"extend"`.
|
|
49
|
+
*/
|
|
50
|
+
type?: "replace" | "extend";
|
|
51
|
+
/**
|
|
52
|
+
A predicate that returns whether the node at the queried
|
|
53
|
+
position is part of the sublanguage.
|
|
54
|
+
*/
|
|
55
|
+
test: (node: SyntaxNode, state: EditorState) => boolean;
|
|
56
|
+
/**
|
|
57
|
+
The language data facet that holds the sublanguage's data.
|
|
58
|
+
You'll want to use
|
|
59
|
+
[`defineLanguageFacet`](https://codemirror.net/6/docs/ref/#language.defineLanguageFacet) to create
|
|
60
|
+
this.
|
|
61
|
+
*/
|
|
62
|
+
facet: Facet<{
|
|
63
|
+
[name: string]: any;
|
|
64
|
+
}>;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
Syntax node prop used to register sublangauges. Should be added to
|
|
68
|
+
the top level node type for the language.
|
|
69
|
+
*/
|
|
70
|
+
declare const sublanguageProp: NodeProp<Sublanguage[]>;
|
|
71
|
+
/**
|
|
34
72
|
A language object manages parsing and per-language
|
|
35
73
|
[metadata](https://codemirror.net/6/docs/ref/#state.EditorState.languageDataAt). Parse data is
|
|
36
74
|
managed as a [Lezer](https://lezer.codemirror.net) tree. The class
|
|
@@ -370,9 +408,9 @@ service.
|
|
|
370
408
|
*/
|
|
371
409
|
declare const indentService: Facet<(context: IndentContext, pos: number) => number | null | undefined, readonly ((context: IndentContext, pos: number) => number | null | undefined)[]>;
|
|
372
410
|
/**
|
|
373
|
-
Facet for overriding the unit by which indentation happens.
|
|
374
|
-
|
|
375
|
-
|
|
411
|
+
Facet for overriding the unit by which indentation happens. Should
|
|
412
|
+
be a string consisting either entirely of the same whitespace
|
|
413
|
+
character. When not set, this defaults to 2 spaces.
|
|
376
414
|
*/
|
|
377
415
|
declare const indentUnit: Facet<string, string>;
|
|
378
416
|
/**
|
|
@@ -450,7 +488,7 @@ declare class IndentContext {
|
|
|
450
488
|
simulateBreak?: number;
|
|
451
489
|
/**
|
|
452
490
|
When `simulateBreak` is given, this can be used to make the
|
|
453
|
-
|
|
491
|
+
simulated break behave like a double line break.
|
|
454
492
|
*/
|
|
455
493
|
simulateDoubleBreak?: boolean;
|
|
456
494
|
});
|
|
@@ -678,6 +716,12 @@ Unfold all folded code.
|
|
|
678
716
|
*/
|
|
679
717
|
declare const unfoldAll: Command;
|
|
680
718
|
/**
|
|
719
|
+
Toggle folding at cursors. Unfolds if there is an existing fold
|
|
720
|
+
starting in that line, tries to find a foldable range around it
|
|
721
|
+
otherwise.
|
|
722
|
+
*/
|
|
723
|
+
declare const toggleFold: Command;
|
|
724
|
+
/**
|
|
681
725
|
Default fold-related key bindings.
|
|
682
726
|
|
|
683
727
|
- Ctrl-Shift-[ (Cmd-Alt-[ on macOS): [`foldCode`](https://codemirror.net/6/docs/ref/#language.foldCode).
|
|
@@ -943,6 +987,7 @@ declare class StringStream {
|
|
|
943
987
|
The current indent unit size.
|
|
944
988
|
*/
|
|
945
989
|
indentUnit: number;
|
|
990
|
+
private overrideIndent?;
|
|
946
991
|
/**
|
|
947
992
|
The current position on the line.
|
|
948
993
|
*/
|
|
@@ -964,7 +1009,7 @@ declare class StringStream {
|
|
|
964
1009
|
/**
|
|
965
1010
|
The current indent unit size.
|
|
966
1011
|
*/
|
|
967
|
-
indentUnit: number);
|
|
1012
|
+
indentUnit: number, overrideIndent?: number | undefined);
|
|
968
1013
|
/**
|
|
969
1014
|
True if we are at the end of the line.
|
|
970
1015
|
*/
|
|
@@ -1112,4 +1157,4 @@ declare class StreamLanguage<State> extends Language {
|
|
|
1112
1157
|
get allowsNesting(): boolean;
|
|
1113
1158
|
}
|
|
1114
1159
|
|
|
1115
|
-
export { Config, HighlightStyle, IndentContext, LRLanguage, Language, LanguageDescription, LanguageSupport, MatchResult, ParseContext, StreamLanguage, StreamParser, StringStream, 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, syntaxHighlighting, syntaxParserRunning, syntaxTree, syntaxTreeAvailable, unfoldAll, unfoldCode, unfoldEffect };
|
|
1160
|
+
export { Config, 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 };
|
package/dist/index.js
CHANGED
|
@@ -24,6 +24,11 @@ function defineLanguageFacet(baseData) {
|
|
|
24
24
|
});
|
|
25
25
|
}
|
|
26
26
|
/**
|
|
27
|
+
Syntax node prop used to register sublangauges. Should be added to
|
|
28
|
+
the top level node type for the language.
|
|
29
|
+
*/
|
|
30
|
+
const sublanguageProp = /*@__PURE__*/new NodeProp();
|
|
31
|
+
/**
|
|
27
32
|
A language object manages parsing and per-language
|
|
28
33
|
[metadata](https://codemirror.net/6/docs/ref/#state.EditorState.languageDataAt). Parse data is
|
|
29
34
|
managed as a [Lezer](https://lezer.codemirror.net) tree. The class
|
|
@@ -60,14 +65,28 @@ class Language {
|
|
|
60
65
|
this.parser = parser;
|
|
61
66
|
this.extension = [
|
|
62
67
|
language.of(this),
|
|
63
|
-
EditorState.languageData.of((state, pos, side) =>
|
|
68
|
+
EditorState.languageData.of((state, pos, side) => {
|
|
69
|
+
let top = topNodeAt(state, pos, side), data = top.type.prop(languageDataProp);
|
|
70
|
+
if (!data)
|
|
71
|
+
return [];
|
|
72
|
+
let base = state.facet(data), sub = top.type.prop(sublanguageProp);
|
|
73
|
+
if (sub) {
|
|
74
|
+
let innerNode = top.resolve(pos - top.from, side);
|
|
75
|
+
for (let sublang of sub)
|
|
76
|
+
if (sublang.test(innerNode, state)) {
|
|
77
|
+
let data = state.facet(sublang.facet);
|
|
78
|
+
return sublang.type == "replace" ? data : data.concat(base);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return base;
|
|
82
|
+
})
|
|
64
83
|
].concat(extraExtensions);
|
|
65
84
|
}
|
|
66
85
|
/**
|
|
67
86
|
Query whether this language is active at the given position.
|
|
68
87
|
*/
|
|
69
88
|
isActiveAt(state, pos, side = -1) {
|
|
70
|
-
return
|
|
89
|
+
return topNodeAt(state, pos, side).type.prop(languageDataProp) == this.data;
|
|
71
90
|
}
|
|
72
91
|
/**
|
|
73
92
|
Find the document regions that were parsed using this language.
|
|
@@ -122,16 +141,14 @@ class Language {
|
|
|
122
141
|
@internal
|
|
123
142
|
*/
|
|
124
143
|
Language.setState = /*@__PURE__*/StateEffect.define();
|
|
125
|
-
function
|
|
126
|
-
let topLang = state.facet(language);
|
|
127
|
-
if (!topLang)
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
for (let node = syntaxTree(state).topNode; node; node = node.enter(pos, side, IterMode.ExcludeBuffers))
|
|
132
|
-
facet = node.type.prop(languageDataProp) || facet;
|
|
144
|
+
function topNodeAt(state, pos, side) {
|
|
145
|
+
let topLang = state.facet(language), tree = syntaxTree(state).topNode;
|
|
146
|
+
if (!topLang || topLang.allowsNesting) {
|
|
147
|
+
for (let node = tree; node; node = node.enter(pos, side, IterMode.ExcludeBuffers))
|
|
148
|
+
if (node.type.isTop)
|
|
149
|
+
tree = node;
|
|
133
150
|
}
|
|
134
|
-
return
|
|
151
|
+
return tree;
|
|
135
152
|
}
|
|
136
153
|
/**
|
|
137
154
|
A subclass of [`Language`](https://codemirror.net/6/docs/ref/#language.Language) for use with Lezer
|
|
@@ -225,13 +242,13 @@ function syntaxParserRunning(view) {
|
|
|
225
242
|
}
|
|
226
243
|
// Lezer-style Input object for a Text document.
|
|
227
244
|
class DocInput {
|
|
228
|
-
constructor(doc
|
|
245
|
+
constructor(doc) {
|
|
229
246
|
this.doc = doc;
|
|
230
|
-
this.length = length;
|
|
231
247
|
this.cursorPos = 0;
|
|
232
248
|
this.string = "";
|
|
233
249
|
this.cursor = doc.iter();
|
|
234
250
|
}
|
|
251
|
+
get length() { return this.doc.length; }
|
|
235
252
|
syncTo(pos) {
|
|
236
253
|
this.string = this.cursor.next(pos - this.cursorPos).value;
|
|
237
254
|
this.cursorPos = pos + this.string.length;
|
|
@@ -776,17 +793,18 @@ service.
|
|
|
776
793
|
*/
|
|
777
794
|
const indentService = /*@__PURE__*/Facet.define();
|
|
778
795
|
/**
|
|
779
|
-
Facet for overriding the unit by which indentation happens.
|
|
780
|
-
|
|
781
|
-
|
|
796
|
+
Facet for overriding the unit by which indentation happens. Should
|
|
797
|
+
be a string consisting either entirely of the same whitespace
|
|
798
|
+
character. When not set, this defaults to 2 spaces.
|
|
782
799
|
*/
|
|
783
800
|
const indentUnit = /*@__PURE__*/Facet.define({
|
|
784
801
|
combine: values => {
|
|
785
802
|
if (!values.length)
|
|
786
803
|
return " ";
|
|
787
|
-
|
|
804
|
+
let unit = values[0];
|
|
805
|
+
if (!unit || /\S/.test(unit) || Array.from(unit).some(e => e != unit[0]))
|
|
788
806
|
throw new Error("Invalid indent unit: " + JSON.stringify(values[0]));
|
|
789
|
-
return
|
|
807
|
+
return unit;
|
|
790
808
|
}
|
|
791
809
|
});
|
|
792
810
|
/**
|
|
@@ -806,14 +824,16 @@ Will use tabs for as much of the columns as possible when the
|
|
|
806
824
|
tabs.
|
|
807
825
|
*/
|
|
808
826
|
function indentString(state, cols) {
|
|
809
|
-
let result = "", ts = state.tabSize;
|
|
810
|
-
if (
|
|
827
|
+
let result = "", ts = state.tabSize, ch = state.facet(indentUnit)[0];
|
|
828
|
+
if (ch == "\t") {
|
|
811
829
|
while (cols >= ts) {
|
|
812
830
|
result += "\t";
|
|
813
831
|
cols -= ts;
|
|
814
832
|
}
|
|
833
|
+
ch = " ";
|
|
834
|
+
}
|
|
815
835
|
for (let i = 0; i < cols; i++)
|
|
816
|
-
result +=
|
|
836
|
+
result += ch;
|
|
817
837
|
return result;
|
|
818
838
|
}
|
|
819
839
|
/**
|
|
@@ -1396,6 +1416,41 @@ const unfoldAll = view => {
|
|
|
1396
1416
|
view.dispatch({ effects });
|
|
1397
1417
|
return true;
|
|
1398
1418
|
};
|
|
1419
|
+
// Find the foldable region containing the given line, if one exists
|
|
1420
|
+
function foldableContainer(view, lineBlock) {
|
|
1421
|
+
// Look backwards through line blocks until we find a foldable region that
|
|
1422
|
+
// intersects with the line
|
|
1423
|
+
for (let line = lineBlock;;) {
|
|
1424
|
+
let foldableRegion = foldable(view.state, line.from, line.to);
|
|
1425
|
+
if (foldableRegion && foldableRegion.to > lineBlock.from)
|
|
1426
|
+
return foldableRegion;
|
|
1427
|
+
if (!line.from)
|
|
1428
|
+
return null;
|
|
1429
|
+
line = view.lineBlockAt(line.from - 1);
|
|
1430
|
+
}
|
|
1431
|
+
}
|
|
1432
|
+
/**
|
|
1433
|
+
Toggle folding at cursors. Unfolds if there is an existing fold
|
|
1434
|
+
starting in that line, tries to find a foldable range around it
|
|
1435
|
+
otherwise.
|
|
1436
|
+
*/
|
|
1437
|
+
const toggleFold = (view) => {
|
|
1438
|
+
let effects = [];
|
|
1439
|
+
for (let line of selectedLines(view)) {
|
|
1440
|
+
let folded = findFold(view.state, line.from, line.to);
|
|
1441
|
+
if (folded) {
|
|
1442
|
+
effects.push(unfoldEffect.of(folded), announceFold(view, folded, false));
|
|
1443
|
+
}
|
|
1444
|
+
else {
|
|
1445
|
+
let foldRange = foldableContainer(view, line);
|
|
1446
|
+
if (foldRange)
|
|
1447
|
+
effects.push(foldEffect.of(foldRange), announceFold(view, foldRange));
|
|
1448
|
+
}
|
|
1449
|
+
}
|
|
1450
|
+
if (effects.length > 0)
|
|
1451
|
+
view.dispatch({ effects: maybeEnable(view.state, effects) });
|
|
1452
|
+
return !!effects.length;
|
|
1453
|
+
};
|
|
1399
1454
|
/**
|
|
1400
1455
|
Default fold-related key bindings.
|
|
1401
1456
|
|
|
@@ -1919,10 +1974,11 @@ class StringStream {
|
|
|
1919
1974
|
/**
|
|
1920
1975
|
The current indent unit size.
|
|
1921
1976
|
*/
|
|
1922
|
-
indentUnit) {
|
|
1977
|
+
indentUnit, overrideIndent) {
|
|
1923
1978
|
this.string = string;
|
|
1924
1979
|
this.tabSize = tabSize;
|
|
1925
1980
|
this.indentUnit = indentUnit;
|
|
1981
|
+
this.overrideIndent = overrideIndent;
|
|
1926
1982
|
/**
|
|
1927
1983
|
The current position on the line.
|
|
1928
1984
|
*/
|
|
@@ -2023,7 +2079,8 @@ class StringStream {
|
|
|
2023
2079
|
Get the indentation column of the current line.
|
|
2024
2080
|
*/
|
|
2025
2081
|
indentation() {
|
|
2026
|
-
|
|
2082
|
+
var _a;
|
|
2083
|
+
return (_a = this.overrideIndent) !== null && _a !== void 0 ? _a : countCol(this.string, null, this.tabSize);
|
|
2027
2084
|
}
|
|
2028
2085
|
/**
|
|
2029
2086
|
Match the input against the given string or regular expression
|
|
@@ -2085,6 +2142,7 @@ function defaultCopyState(state) {
|
|
|
2085
2142
|
}
|
|
2086
2143
|
return newState;
|
|
2087
2144
|
}
|
|
2145
|
+
const IndentedFrom = /*@__PURE__*/new WeakMap();
|
|
2088
2146
|
/**
|
|
2089
2147
|
A [language](https://codemirror.net/6/docs/ref/#language.Language) class based on a CodeMirror
|
|
2090
2148
|
5-style [streaming parser](https://codemirror.net/6/docs/ref/#language.StreamParser).
|
|
@@ -2115,7 +2173,14 @@ class StreamLanguage extends Language {
|
|
|
2115
2173
|
at = at.parent;
|
|
2116
2174
|
if (!at)
|
|
2117
2175
|
return null;
|
|
2118
|
-
let
|
|
2176
|
+
let from = undefined;
|
|
2177
|
+
let { overrideIndentation } = cx.options;
|
|
2178
|
+
if (overrideIndentation) {
|
|
2179
|
+
from = IndentedFrom.get(cx.state);
|
|
2180
|
+
if (from != null && from < pos - 1e4)
|
|
2181
|
+
from = undefined;
|
|
2182
|
+
}
|
|
2183
|
+
let start = findState(this, tree, 0, at.from, from !== null && from !== void 0 ? from : pos), statePos, state;
|
|
2119
2184
|
if (start) {
|
|
2120
2185
|
state = start.state;
|
|
2121
2186
|
statePos = start.pos + 1;
|
|
@@ -2129,7 +2194,8 @@ class StreamLanguage extends Language {
|
|
|
2129
2194
|
while (statePos < pos) {
|
|
2130
2195
|
let line = cx.state.doc.lineAt(statePos), end = Math.min(pos, line.to);
|
|
2131
2196
|
if (line.length) {
|
|
2132
|
-
let
|
|
2197
|
+
let indentation = overrideIndentation ? overrideIndentation(line.from) : -1;
|
|
2198
|
+
let stream = new StringStream(line.text, cx.state.tabSize, cx.unit, indentation < 0 ? undefined : indentation);
|
|
2133
2199
|
while (stream.pos < end - line.from)
|
|
2134
2200
|
readToken(this.streamParser.token, stream, state);
|
|
2135
2201
|
}
|
|
@@ -2140,8 +2206,10 @@ class StreamLanguage extends Language {
|
|
|
2140
2206
|
break;
|
|
2141
2207
|
statePos = line.to + 1;
|
|
2142
2208
|
}
|
|
2143
|
-
let
|
|
2144
|
-
|
|
2209
|
+
let line = cx.lineAt(pos);
|
|
2210
|
+
if (overrideIndentation && from == null)
|
|
2211
|
+
IndentedFrom.set(cx.state, line.from);
|
|
2212
|
+
return this.streamParser.indent(state, /^\s*(.*)/.exec(line.text)[1], cx);
|
|
2145
2213
|
}
|
|
2146
2214
|
get allowsNesting() { return false; }
|
|
2147
2215
|
}
|
|
@@ -2408,4 +2476,4 @@ function docID(data) {
|
|
|
2408
2476
|
return type;
|
|
2409
2477
|
}
|
|
2410
2478
|
|
|
2411
|
-
export { 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, syntaxHighlighting, syntaxParserRunning, syntaxTree, syntaxTreeAvailable, unfoldAll, unfoldCode, unfoldEffect };
|
|
2479
|
+
export { 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 };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@codemirror/language",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.6.0",
|
|
4
4
|
"description": "Language support infrastructure for the CodeMirror code editor",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"test": "cm-runtests",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
],
|
|
13
13
|
"author": {
|
|
14
14
|
"name": "Marijn Haverbeke",
|
|
15
|
-
"email": "
|
|
15
|
+
"email": "marijn@haverbeke.berlin",
|
|
16
16
|
"url": "http://marijnhaverbeke.nl"
|
|
17
17
|
},
|
|
18
18
|
"type": "module",
|