@codemirror/language 6.5.0 → 6.7.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 CHANGED
@@ -1,3 +1,15 @@
1
+ ## 6.7.0 (2023-05-19)
2
+
3
+ ### New features
4
+
5
+ Export `DocInput` class for feeding editor documents to a Lezer parser.
6
+
7
+ ## 6.6.0 (2023-02-13)
8
+
9
+ ### New features
10
+
11
+ 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.
12
+
1
13
  ## 6.5.0 (2023-02-07)
2
14
 
3
15
  ### Bug fixes
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 sublanguages. 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) => state.facet(languageDataFacetAt(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 languageDataFacetAt(state, pos, side) == this.data;
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 languageDataFacetAt(state, pos, side) {
130
- let topLang = state.facet(language);
131
- if (!topLang)
132
- return null;
133
- let facet = topLang.data;
134
- if (topLang.allowsNesting) {
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 facet;
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
@@ -227,8 +244,15 @@ function syntaxParserRunning(view) {
227
244
  var _a;
228
245
  return ((_a = view.plugin(parseWorker)) === null || _a === void 0 ? void 0 : _a.isWorking()) || false;
229
246
  }
230
- // Lezer-style Input object for a Text document.
247
+ /**
248
+ Lezer-style
249
+ [`Input`](https://lezer.codemirror.net/docs/ref#common.Input)
250
+ object for a [`Text`](https://codemirror.net/6/docs/ref/#state.Text) object.
251
+ */
231
252
  class DocInput {
253
+ /**
254
+ Create an input object for the given document.
255
+ */
232
256
  constructor(doc) {
233
257
  this.doc = doc;
234
258
  this.cursorPos = 0;
@@ -2463,6 +2487,7 @@ function docID(data) {
2463
2487
  return type;
2464
2488
  }
2465
2489
 
2490
+ exports.DocInput = DocInput;
2466
2491
  exports.HighlightStyle = HighlightStyle;
2467
2492
  exports.IndentContext = IndentContext;
2468
2493
  exports.LRLanguage = LRLanguage;
@@ -2506,6 +2531,7 @@ exports.indentUnit = indentUnit;
2506
2531
  exports.language = language;
2507
2532
  exports.languageDataProp = languageDataProp;
2508
2533
  exports.matchBrackets = matchBrackets;
2534
+ exports.sublanguageProp = sublanguageProp;
2509
2535
  exports.syntaxHighlighting = syntaxHighlighting;
2510
2536
  exports.syntaxParserRunning = syntaxParserRunning;
2511
2537
  exports.syntaxTree = syntaxTree;
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
- import { NodeProp, Parser, Tree, TreeFragment, SyntaxNode, NodeType } from '@lezer/common';
1
+ import { NodeProp, SyntaxNode, Parser, Tree, Input, 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, Extension, EditorState, StateField, Range } from '@codemirror/state';
4
+ import { Facet, EditorState, Extension, Text, 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 sublanguages. 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
@@ -174,6 +212,26 @@ is no language parser enabled.
174
212
  */
175
213
  declare function syntaxParserRunning(view: EditorView): boolean;
176
214
  /**
215
+ Lezer-style
216
+ [`Input`](https://lezer.codemirror.net/docs/ref#common.Input)
217
+ object for a [`Text`](https://codemirror.net/6/docs/ref/#state.Text) object.
218
+ */
219
+ declare class DocInput implements Input {
220
+ readonly doc: Text;
221
+ private cursor;
222
+ private cursorPos;
223
+ private string;
224
+ /**
225
+ Create an input object for the given document.
226
+ */
227
+ constructor(doc: Text);
228
+ get length(): number;
229
+ private syncTo;
230
+ chunk(pos: number): string;
231
+ get lineChunks(): boolean;
232
+ read(from: number, to: number): string;
233
+ }
234
+ /**
177
235
  A parse context provided to parsers working on the editor content.
178
236
  */
179
237
  declare class ParseContext {
@@ -626,7 +684,7 @@ declare function foldable(state: EditorState, lineStart: number, lineEnd: number
626
684
  from: number;
627
685
  to: number;
628
686
  } | null;
629
- declare type DocRange = {
687
+ type DocRange = {
630
688
  from: number;
631
689
  to: number;
632
690
  };
@@ -714,7 +772,7 @@ interface FoldConfig {
714
772
  Create an extension that configures code folding.
715
773
  */
716
774
  declare function codeFolding(config?: FoldConfig): Extension;
717
- declare type Handlers = {
775
+ type Handlers = {
718
776
  [event: string]: (view: EditorView, line: BlockInfo, event: Event) => boolean;
719
777
  };
720
778
  interface FoldGutterConfig {
@@ -1119,4 +1177,4 @@ declare class StreamLanguage<State> extends Language {
1119
1177
  get allowsNesting(): boolean;
1120
1178
  }
1121
1179
 
1122
- 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, toggleFold, unfoldAll, unfoldCode, unfoldEffect };
1180
+ export { Config, DocInput, HighlightStyle, IndentContext, LRLanguage, Language, LanguageDescription, LanguageSupport, MatchResult, ParseContext, StreamLanguage, StreamParser, StringStream, Sublanguage, TagStyle, TreeIndentContext, bracketMatching, bracketMatchingHandle, codeFolding, continuedIndent, defaultHighlightStyle, defineLanguageFacet, delimitedIndent, ensureSyntaxTree, flatIndent, foldAll, foldCode, foldEffect, foldGutter, foldInside, foldKeymap, foldNodeProp, foldService, foldState, foldable, foldedRanges, forceParsing, getIndentUnit, getIndentation, highlightingFor, indentNodeProp, indentOnInput, indentRange, indentService, indentString, indentUnit, language, languageDataProp, matchBrackets, sublanguageProp, syntaxHighlighting, syntaxParserRunning, syntaxTree, syntaxTreeAvailable, toggleFold, unfoldAll, unfoldCode, unfoldEffect };
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 sublanguages. 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) => state.facet(languageDataFacetAt(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 languageDataFacetAt(state, pos, side) == this.data;
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 languageDataFacetAt(state, pos, side) {
126
- let topLang = state.facet(language);
127
- if (!topLang)
128
- return null;
129
- let facet = topLang.data;
130
- if (topLang.allowsNesting) {
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 facet;
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
@@ -223,8 +240,15 @@ function syntaxParserRunning(view) {
223
240
  var _a;
224
241
  return ((_a = view.plugin(parseWorker)) === null || _a === void 0 ? void 0 : _a.isWorking()) || false;
225
242
  }
226
- // Lezer-style Input object for a Text document.
243
+ /**
244
+ Lezer-style
245
+ [`Input`](https://lezer.codemirror.net/docs/ref#common.Input)
246
+ object for a [`Text`](https://codemirror.net/6/docs/ref/#state.Text) object.
247
+ */
227
248
  class DocInput {
249
+ /**
250
+ Create an input object for the given document.
251
+ */
228
252
  constructor(doc) {
229
253
  this.doc = doc;
230
254
  this.cursorPos = 0;
@@ -2459,4 +2483,4 @@ function docID(data) {
2459
2483
  return type;
2460
2484
  }
2461
2485
 
2462
- 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, toggleFold, unfoldAll, unfoldCode, unfoldEffect };
2486
+ export { DocInput, HighlightStyle, IndentContext, LRLanguage, Language, LanguageDescription, LanguageSupport, ParseContext, StreamLanguage, StringStream, TreeIndentContext, bracketMatching, bracketMatchingHandle, codeFolding, continuedIndent, defaultHighlightStyle, defineLanguageFacet, delimitedIndent, ensureSyntaxTree, flatIndent, foldAll, foldCode, foldEffect, foldGutter, foldInside, foldKeymap, foldNodeProp, foldService, foldState, foldable, foldedRanges, forceParsing, getIndentUnit, getIndentation, highlightingFor, indentNodeProp, indentOnInput, indentRange, indentService, indentString, indentUnit, language, languageDataProp, matchBrackets, sublanguageProp, syntaxHighlighting, syntaxParserRunning, syntaxTree, syntaxTreeAvailable, toggleFold, unfoldAll, unfoldCode, unfoldEffect };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codemirror/language",
3
- "version": "6.5.0",
3
+ "version": "6.7.0",
4
4
  "description": "Language support infrastructure for the CodeMirror code editor",
5
5
  "scripts": {
6
6
  "test": "cm-runtests",