@codemirror/language 0.17.4 → 0.18.2

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/dist/index.js CHANGED
@@ -3,37 +3,52 @@ import { Text, countColumn } from '@codemirror/text';
3
3
  import { Facet, EditorState, StateEffect, StateField, Transaction } from '@codemirror/state';
4
4
  import { ViewPlugin } from '@codemirror/view';
5
5
 
6
- /// Node prop stored in a grammar's top syntax node to provide the
7
- /// facet that stores language data for that language.
8
- const languageDataProp = new NodeProp();
9
- /// Helper function to define a facet (to be added to the top syntax
10
- /// node(s) for a language via
11
- /// [`languageDataProp`](#language.languageDataProp)), that will be
12
- /// used to associate language data with the language. You
13
- /// probably only need this when subclassing
14
- /// [`Language`](#language.Language).
6
+ /**
7
+ Node prop stored in a grammar's top syntax node to provide the
8
+ facet that stores language data for that language.
9
+ */
10
+ const languageDataProp = /*@__PURE__*/new NodeProp();
11
+ /**
12
+ Helper function to define a facet (to be added to the top syntax
13
+ node(s) for a language via
14
+ [`languageDataProp`](https://codemirror.net/6/docs/ref/#language.languageDataProp)), that will be
15
+ used to associate language data with the language. You
16
+ probably only need this when subclassing
17
+ [`Language`](https://codemirror.net/6/docs/ref/#language.Language).
18
+ */
15
19
  function defineLanguageFacet(baseData) {
16
20
  return Facet.define({
17
21
  combine: baseData ? values => values.concat(baseData) : undefined
18
22
  });
19
23
  }
20
- /// A language object manages parsing and per-language
21
- /// [metadata](#state.EditorState.languageDataAt). Parse data is
22
- /// managed as a [Lezer](https://lezer.codemirror.net) tree. You'll
23
- /// want to subclass this class for custom parsers, or use the
24
- /// [`LezerLanguage`](#language.LezerLanguage) or
25
- /// [`StreamLanguage`](#stream-parser.StreamLanguage) abstractions for
26
- /// [Lezer](https://lezer.codemirror.net/) or stream parsers.
24
+ /**
25
+ A language object manages parsing and per-language
26
+ [metadata](https://codemirror.net/6/docs/ref/#state.EditorState.languageDataAt). Parse data is
27
+ managed as a [Lezer](https://lezer.codemirror.net) tree. You'll
28
+ want to subclass this class for custom parsers, or use the
29
+ [`LezerLanguage`](https://codemirror.net/6/docs/ref/#language.LezerLanguage) or
30
+ [`StreamLanguage`](https://codemirror.net/6/docs/ref/#stream-parser.StreamLanguage) abstractions for
31
+ [Lezer](https://lezer.codemirror.net/) or stream parsers.
32
+ */
27
33
  class Language {
28
- /// Construct a language object. You usually don't need to invoke
29
- /// this directly. But when you do, make sure you use
30
- /// [`defineLanguageFacet`](#language.defineLanguageFacet) to create
31
- /// the first argument.
34
+ /**
35
+ Construct a language object. You usually don't need to invoke
36
+ this directly. But when you do, make sure you use
37
+ [`defineLanguageFacet`](https://codemirror.net/6/docs/ref/#language.defineLanguageFacet) to create
38
+ the first argument.
39
+ */
32
40
  constructor(
33
- /// The [language data](#state.EditorState.languageDataAt) data
34
- /// facet used for this language.
35
- data, parser, extraExtensions = []) {
41
+ /**
42
+ The [language data](https://codemirror.net/6/docs/ref/#state.EditorState.languageDataAt) data
43
+ facet used for this language.
44
+ */
45
+ data, parser,
46
+ /**
47
+ The node type of the top node of trees produced by this parser.
48
+ */
49
+ topNode, extraExtensions = []) {
36
50
  this.data = data;
51
+ this.topNode = topNode;
37
52
  // Kludge to define EditorState.tree as a debugging helper,
38
53
  // without the EditorState package actually knowing about
39
54
  // languages and lezer trees.
@@ -45,13 +60,17 @@ class Language {
45
60
  EditorState.languageData.of((state, pos) => state.facet(languageDataFacetAt(state, pos)))
46
61
  ].concat(extraExtensions);
47
62
  }
48
- /// Query whether this language is active at the given position.
63
+ /**
64
+ Query whether this language is active at the given position.
65
+ */
49
66
  isActiveAt(state, pos) {
50
67
  return languageDataFacetAt(state, pos) == this.data;
51
68
  }
52
- /// Find the document regions that were parsed using this language.
53
- /// The returned regions will _include_ any nested languages rooted
54
- /// in this language, when those exist.
69
+ /**
70
+ Find the document regions that were parsed using this language.
71
+ The returned regions will _include_ any nested languages rooted
72
+ in this language, when those exist.
73
+ */
55
74
  findRegions(state) {
56
75
  let lang = state.facet(language);
57
76
  if ((lang === null || lang === void 0 ? void 0 : lang.data) == this.data)
@@ -70,20 +89,26 @@ class Language {
70
89
  });
71
90
  return result;
72
91
  }
73
- /// Indicates whether this language allows nested languages. The
74
- /// default implementation returns true.
92
+ /**
93
+ Indicates whether this language allows nested languages. The
94
+ default implementation returns true.
95
+ */
75
96
  get allowsNesting() { return true; }
76
- /// Use this language to parse the given string into a tree.
97
+ /**
98
+ Use this language to parse the given string into a tree.
99
+ */
77
100
  parseString(code) {
78
101
  let doc = Text.of(code.split("\n"));
79
- let parse = this.parser.startParse(new DocInput(doc), 0, new EditorParseContext(this.parser, EditorState.create({ doc }), [], Tree.empty, { from: 0, to: code.length }, []));
102
+ let parse = this.parser.startParse(new DocInput(doc), 0, new EditorParseContext(this.parser, EditorState.create({ doc }), [], Tree.empty, { from: 0, to: code.length }, [], null));
80
103
  let tree;
81
104
  while (!(tree = parse.advance())) { }
82
105
  return tree;
83
106
  }
84
107
  }
85
- /// @internal
86
- Language.setState = StateEffect.define();
108
+ /**
109
+ @internal
110
+ */
111
+ Language.setState = /*@__PURE__*/StateEffect.define();
87
112
  function languageDataFacetAt(state, pos) {
88
113
  let topLang = state.facet(language);
89
114
  if (!topLang)
@@ -100,38 +125,48 @@ function languageDataFacetAt(state, pos) {
100
125
  }
101
126
  return topLang.data;
102
127
  }
103
- /// A subclass of [`Language`](#language.Language) for use with
104
- /// [Lezer](https://lezer.codemirror.net/docs/ref#lezer.Parser)
105
- /// parsers.
128
+ /**
129
+ A subclass of [`Language`](https://codemirror.net/6/docs/ref/#language.Language) for use with
130
+ [Lezer](https://lezer.codemirror.net/docs/ref#lezer.Parser)
131
+ parsers.
132
+ */
106
133
  class LezerLanguage extends Language {
107
134
  constructor(data, parser) {
108
- super(data, parser);
135
+ super(data, parser, parser.topNode);
109
136
  this.parser = parser;
110
137
  }
111
- /// Define a language from a parser.
138
+ /**
139
+ Define a language from a parser.
140
+ */
112
141
  static define(spec) {
113
142
  let data = defineLanguageFacet(spec.languageData);
114
143
  return new LezerLanguage(data, spec.parser.configure({
115
144
  props: [languageDataProp.add(type => type.isTop ? data : undefined)]
116
145
  }));
117
146
  }
118
- /// Create a new instance of this language with a reconfigured
119
- /// version of its parser.
147
+ /**
148
+ Create a new instance of this language with a reconfigured
149
+ version of its parser.
150
+ */
120
151
  configure(options) {
121
152
  return new LezerLanguage(this.data, this.parser.configure(options));
122
153
  }
123
154
  get allowsNesting() { return this.parser.hasNested; }
124
155
  }
125
- /// Get the syntax tree for a state, which is the current (possibly
126
- /// incomplete) parse tree of active [language](#language.Language),
127
- /// or the empty tree if there is no language available.
156
+ /**
157
+ Get the syntax tree for a state, which is the current (possibly
158
+ incomplete) parse tree of active [language](https://codemirror.net/6/docs/ref/#language.Language),
159
+ or the empty tree if there is no language available.
160
+ */
128
161
  function syntaxTree(state) {
129
162
  let field = state.field(Language.state, false);
130
163
  return field ? field.tree : Tree.empty;
131
164
  }
132
- /// Try to get a parse tree that spans at least up to `upto`. The
133
- /// method will do at most `timeout` milliseconds of work to parse
134
- /// up to that point if the tree isn't already available.
165
+ /**
166
+ Try to get a parse tree that spans at least up to `upto`. The
167
+ method will do at most `timeout` milliseconds of work to parse
168
+ up to that point if the tree isn't already available.
169
+ */
135
170
  function ensureSyntaxTree(state, upto, timeout = 50) {
136
171
  var _a;
137
172
  let parse = (_a = state.field(Language.state, false)) === null || _a === void 0 ? void 0 : _a.context;
@@ -174,7 +209,7 @@ class DocInput {
174
209
  let stringStart = this.cursorPos - this.string.length;
175
210
  if (pos < stringStart || pos >= this.cursorPos)
176
211
  stringStart = this.syncTo(pos);
177
- return this.cursor.lineBreak ? "" : this.string.slice(pos - stringStart);
212
+ return this.cursor.lineBreak ? "" : this.string.slice(pos - stringStart, Math.min(this.length - stringStart, this.string.length));
178
213
  }
179
214
  read(from, to) {
180
215
  let stringStart = this.cursorPos - this.string.length;
@@ -187,36 +222,61 @@ class DocInput {
187
222
  return new DocInput(this.doc, at);
188
223
  }
189
224
  }
190
- /// A parse context provided to parsers working on the editor content.
225
+ /**
226
+ A parse context provided to parsers working on the editor content.
227
+ */
191
228
  class EditorParseContext {
192
- /// @internal
229
+ /**
230
+ @internal
231
+ */
193
232
  constructor(parser,
194
- /// The current editor state.
233
+ /**
234
+ The current editor state.
235
+ */
195
236
  state,
196
- /// Tree fragments that can be reused by incremental re-parses.
237
+ /**
238
+ Tree fragments that can be reused by incremental re-parses.
239
+ */
197
240
  fragments = [],
198
- /// @internal
241
+ /**
242
+ @internal
243
+ */
199
244
  tree,
200
- /// The current editor viewport (or some overapproximation
201
- /// thereof). Intended to be used for opportunistically avoiding
202
- /// work (in which case
203
- /// [`skipUntilInView`](#language.EditorParseContext.skipUntilInView)
204
- /// should be called to make sure the parser is restarted when the
205
- /// skipped region becomes visible).
245
+ /**
246
+ The current editor viewport (or some overapproximation
247
+ thereof). Intended to be used for opportunistically avoiding
248
+ work (in which case
249
+ [`skipUntilInView`](https://codemirror.net/6/docs/ref/#language.EditorParseContext.skipUntilInView)
250
+ should be called to make sure the parser is restarted when the
251
+ skipped region becomes visible).
252
+ */
206
253
  viewport,
207
- /// @internal
208
- skipped) {
254
+ /**
255
+ @internal
256
+ */
257
+ skipped,
258
+ /**
259
+ This is where skipping parsers can register a promise that,
260
+ when resolved, will schedule a new parse. It is cleared when
261
+ the parse worker picks up the promise. @internal
262
+ */
263
+ scheduleOn) {
209
264
  this.parser = parser;
210
265
  this.state = state;
211
266
  this.fragments = fragments;
212
267
  this.tree = tree;
213
268
  this.viewport = viewport;
214
269
  this.skipped = skipped;
270
+ this.scheduleOn = scheduleOn;
215
271
  this.parse = null;
216
- /// @internal
272
+ /**
273
+ @internal
274
+ */
217
275
  this.tempSkipped = [];
218
276
  }
219
- /// @internal
277
+ /**
278
+ @internal
279
+ */
220
280
  work(time, upto) {
221
281
  if (this.tree != Tree.empty && (upto == null ? this.tree.length == this.state.doc.length : this.tree.length >= upto)) {
222
282
  this.takeTree();
@@ -241,7 +301,9 @@ class EditorParseContext {
241
301
  return false;
242
302
  }
243
303
  }
244
- /// @internal
304
+ /**
305
+ @internal
306
+ */
245
307
  takeTree() {
246
308
  if (this.parse && this.parse.pos > this.tree.length) {
247
309
  this.tree = this.parse.forceFinish();
@@ -253,7 +315,9 @@ class EditorParseContext {
253
315
  fragments = cutFragments(fragments, r.from, r.to);
254
316
  return fragments;
255
317
  }
256
- /// @internal
318
+ /**
319
+ @internal
320
+ */
257
321
  changes(changes, newState) {
258
322
  let { fragments, tree, viewport, skipped } = this;
259
323
  this.takeTree();
@@ -272,9 +336,11 @@ class EditorParseContext {
272
336
  }
273
337
  }
274
338
  }
275
- return new EditorParseContext(this.parser, newState, fragments, tree, viewport, skipped);
339
+ return new EditorParseContext(this.parser, newState, fragments, tree, viewport, skipped, this.scheduleOn);
276
340
  }
277
- /// @internal
341
+ /**
342
+ @internal
343
+ */
278
344
  updateViewport(viewport) {
279
345
  this.viewport = viewport;
280
346
  let startLen = this.skipped.length;
@@ -287,40 +353,61 @@ class EditorParseContext {
287
353
  }
288
354
  return this.skipped.length < startLen;
289
355
  }
290
- /// @internal
356
+ /**
357
+ @internal
358
+ */
291
359
  reset() {
292
360
  if (this.parse) {
293
361
  this.takeTree();
294
362
  this.parse = null;
295
363
  }
296
364
  }
297
- /// Notify the parse scheduler that the given region was skipped
298
- /// because it wasn't in view, and the parse should be restarted
299
- /// when it comes into view.
365
+ /**
366
+ Notify the parse scheduler that the given region was skipped
367
+ because it wasn't in view, and the parse should be restarted
368
+ when it comes into view.
369
+ */
300
370
  skipUntilInView(from, to) {
301
371
  this.skipped.push({ from, to });
302
372
  }
303
- /// @internal
373
+ /**
374
+ Returns a parser intended to be used as placeholder when
375
+ asynchronously loading a nested parser. It'll skip its input and
376
+ mark it as not-really-parsed, so that the next update will parse
377
+ it again.
378
+
379
+ When `until` is given, a reparse will be scheduled when that
380
+ promise resolves.
381
+ */
382
+ static getSkippingParser(until) {
383
+ return {
384
+ startParse(input, startPos, context) {
385
+ return {
386
+ pos: startPos,
387
+ advance() {
388
+ let ecx = context;
389
+ ecx.tempSkipped.push({ from: startPos, to: input.length });
390
+ if (until)
391
+ ecx.scheduleOn = ecx.scheduleOn ? Promise.all([ecx.scheduleOn, until]) : until;
392
+ this.pos = input.length;
393
+ return new Tree(NodeType.none, [], [], input.length - startPos);
394
+ },
395
+ forceFinish() { return this.advance(); }
396
+ };
397
+ }
398
+ };
399
+ }
400
+ /**
401
+ @internal
402
+ */
304
403
  movedPast(pos) {
305
404
  return this.tree.length < pos && this.parse && this.parse.pos >= pos;
306
405
  }
307
406
  }
308
- /// A parser intended to be used as placeholder when asynchronously
309
- /// loading a nested parser. It'll skip its input and mark it as
310
- /// not-really-parsed, so that the next update will parse it again.
311
- EditorParseContext.skippingParser = {
312
- startParse(input, startPos, context) {
313
- return {
314
- pos: startPos,
315
- advance() {
316
- context.tempSkipped.push({ from: startPos, to: input.length });
317
- this.pos = input.length;
318
- return new Tree(NodeType.none, [], [], input.length - startPos);
319
- },
320
- forceFinish() { return this.advance(); }
321
- };
322
- }
323
- };
407
+ /**
408
+ FIXME backwards compatible shim, remove on next major @internal
409
+ */
410
+ EditorParseContext.skippingParser = /*@__PURE__*/EditorParseContext.getSkippingParser();
324
411
  function cutFragments(fragments, from, to) {
325
412
  return TreeFragment.applyChanges(fragments, [{ fromA: from, toA: to, fromB: from, toB: to }]);
326
413
  }
@@ -346,13 +433,13 @@ class LanguageState {
346
433
  return new LanguageState(newCx);
347
434
  }
348
435
  static init(state) {
349
- let parseState = new EditorParseContext(state.facet(language).parser, state, [], Tree.empty, { from: 0, to: state.doc.length }, []);
436
+ let parseState = new EditorParseContext(state.facet(language).parser, state, [], Tree.empty, { from: 0, to: state.doc.length }, [], null);
350
437
  if (!parseState.work(25 /* Apply */))
351
438
  parseState.takeTree();
352
439
  return new LanguageState(parseState);
353
440
  }
354
441
  }
355
- Language.state = StateField.define({
442
+ Language.state = /*@__PURE__*/StateField.define({
356
443
  create: LanguageState.init,
357
444
  update(value, tr) {
358
445
  for (let e of tr.effects)
@@ -366,7 +453,7 @@ Language.state = StateField.define({
366
453
  let requestIdle = typeof window != "undefined" && window.requestIdleCallback ||
367
454
  ((callback, { timeout }) => setTimeout(callback, timeout));
368
455
  let cancelIdle = typeof window != "undefined" && window.cancelIdleCallback || clearTimeout;
369
- const parseWorker = ViewPlugin.fromClass(class ParseWorker {
456
+ const parseWorker = /*@__PURE__*/ViewPlugin.fromClass(class ParseWorker {
370
457
  constructor(view) {
371
458
  this.view = view;
372
459
  this.working = -1;
@@ -378,8 +465,8 @@ const parseWorker = ViewPlugin.fromClass(class ParseWorker {
378
465
  this.scheduleWork();
379
466
  }
380
467
  update(update) {
468
+ let cx = this.view.state.field(Language.state).context;
381
469
  if (update.viewportChanged) {
382
- let cx = this.view.state.field(Language.state).context;
383
470
  if (cx.updateViewport(update.view.viewport))
384
471
  cx.reset();
385
472
  if (this.view.viewport.to > cx.tree.length)
@@ -390,12 +477,13 @@ const parseWorker = ViewPlugin.fromClass(class ParseWorker {
390
477
  this.chunkBudget += 50 /* ChangeBonus */;
391
478
  this.scheduleWork();
392
479
  }
480
+ this.checkAsyncSchedule(cx);
393
481
  }
394
482
  scheduleWork() {
395
483
  if (this.working > -1)
396
484
  return;
397
- let { state } = this.view, field = state.field(Language.state);
398
- if (field.tree.length >= state.doc.length)
485
+ let { state } = this.view, field = state.field(Language.state), frags = field.context.fragments;
486
+ if (field.tree.length >= state.doc.length && frags.length && frags[0].from == 0 && frags[0].to >= state.doc.length)
399
487
  return;
400
488
  this.working = requestIdle(this.work, { timeout: 500 /* Pause */ });
401
489
  }
@@ -420,6 +508,13 @@ const parseWorker = ViewPlugin.fromClass(class ParseWorker {
420
508
  }
421
509
  if (!done && this.chunkBudget > 0)
422
510
  this.scheduleWork();
511
+ this.checkAsyncSchedule(field.context);
512
+ }
513
+ checkAsyncSchedule(cx) {
514
+ if (cx.scheduleOn) {
515
+ cx.scheduleOn.then(() => this.scheduleWork());
516
+ cx.scheduleOn = null;
517
+ }
423
518
  }
424
519
  destroy() {
425
520
  if (this.working >= 0)
@@ -428,70 +523,98 @@ const parseWorker = ViewPlugin.fromClass(class ParseWorker {
428
523
  }, {
429
524
  eventHandlers: { focus() { this.scheduleWork(); } }
430
525
  });
431
- /// The facet used to associate a language with an editor state.
432
- const language = Facet.define({
526
+ /**
527
+ The facet used to associate a language with an editor state.
528
+ */
529
+ const language = /*@__PURE__*/Facet.define({
433
530
  combine(languages) { return languages.length ? languages[0] : null; },
434
531
  enables: [Language.state, parseWorker]
435
532
  });
436
- /// This class bundles a [language object](#language.Language) with an
437
- /// optional set of supporting extensions. Language packages are
438
- /// encouraged to export a function that optionally takes a
439
- /// configuration object and returns a `LanguageSupport` instance, as
440
- /// the main way for client code to use the package.
533
+ /**
534
+ This class bundles a [language object](https://codemirror.net/6/docs/ref/#language.Language) with an
535
+ optional set of supporting extensions. Language packages are
536
+ encouraged to export a function that optionally takes a
537
+ configuration object and returns a `LanguageSupport` instance, as
538
+ the main way for client code to use the package.
539
+ */
441
540
  class LanguageSupport {
442
- /// Create a support object.
541
+ /**
542
+ Create a support object.
543
+ */
443
544
  constructor(
444
- /// The language object.
545
+ /**
546
+ The language object.
547
+ */
445
548
  language,
446
- /// An optional set of supporting extensions. When nesting a
447
- /// language in another language, the outer language is encouraged
448
- /// to include the supporting extensions for its inner languages
449
- /// in its own set of support extensions.
549
+ /**
550
+ An optional set of supporting extensions. When nesting a
551
+ language in another language, the outer language is encouraged
552
+ to include the supporting extensions for its inner languages
553
+ in its own set of support extensions.
554
+ */
450
555
  support = []) {
451
556
  this.language = language;
452
557
  this.support = support;
453
558
  this.extension = [language, support];
454
559
  }
455
560
  }
456
- /// Language descriptions are used to store metadata about languages
457
- /// and to dynamically load them. Their main role is finding the
458
- /// appropriate language for a filename or dynamically loading nested
459
- /// parsers.
561
+ /**
562
+ Language descriptions are used to store metadata about languages
563
+ and to dynamically load them. Their main role is finding the
564
+ appropriate language for a filename or dynamically loading nested
565
+ parsers.
566
+ */
460
567
  class LanguageDescription {
461
568
  constructor(
462
- /// The name of this language.
569
+ /**
570
+ The name of this language.
571
+ */
463
572
  name,
464
- /// Alternative names for the mode (lowercased, includes `this.name`).
573
+ /**
574
+ Alternative names for the mode (lowercased, includes `this.name`).
575
+ */
465
576
  alias,
466
- /// File extensions associated with this language.
577
+ /**
578
+ File extensions associated with this language.
579
+ */
467
580
  extensions,
468
- /// Optional filename pattern that should be associated with this
469
- /// language.
581
+ /**
582
+ Optional filename pattern that should be associated with this
583
+ language.
584
+ */
470
585
  filename, loadFunc) {
471
586
  this.name = name;
472
587
  this.alias = alias;
473
588
  this.extensions = extensions;
474
589
  this.filename = filename;
475
590
  this.loadFunc = loadFunc;
476
- /// If the language has been loaded, this will hold its value.
591
+ /**
592
+ If the language has been loaded, this will hold its value.
593
+ */
477
594
  this.support = undefined;
478
595
  this.loading = null;
479
596
  }
480
- /// Start loading the the language. Will return a promise that
481
- /// resolves to a [`LanguageSupport`](#language.LanguageSupport)
482
- /// object when the language successfully loads.
597
+ /**
598
+ Start loading the the language. Will return a promise that
599
+ resolves to a [`LanguageSupport`](https://codemirror.net/6/docs/ref/#language.LanguageSupport)
600
+ object when the language successfully loads.
601
+ */
483
602
  load() {
484
603
  return this.loading || (this.loading = this.loadFunc().then(support => this.support = support, err => { this.loading = null; throw err; }));
485
604
  }
486
- /// Create a language description.
605
+ /**
606
+ Create a language description.
607
+ */
487
608
  static of(spec) {
488
609
  return new LanguageDescription(spec.name, (spec.alias || []).concat(spec.name).map(s => s.toLowerCase()), spec.extensions || [], spec.filename, spec.load);
489
610
  }
490
- /// Look for a language in the given array of descriptions that
491
- /// matches the filename. Will first match
492
- /// [`filename`](#language.LanguageDescription.filename) patterns,
493
- /// and then [extensions](#language.LanguageDescription.extensions),
494
- /// and return the first language that matches.
611
+ /**
612
+ Look for a language in the given array of descriptions that
613
+ matches the filename. Will first match
614
+ [`filename`](https://codemirror.net/6/docs/ref/#language.LanguageDescription.filename) patterns,
615
+ and then [extensions](https://codemirror.net/6/docs/ref/#language.LanguageDescription.extensions),
616
+ and return the first language that matches.
617
+ */
495
618
  static matchFilename(descs, filename) {
496
619
  for (let d of descs)
497
620
  if (d.filename && d.filename.test(filename))
@@ -503,11 +626,13 @@ class LanguageDescription {
503
626
  return d;
504
627
  return null;
505
628
  }
506
- /// Look for a language whose name or alias matches the the given
507
- /// name (case-insensitively). If `fuzzy` is true, and no direct
508
- /// matchs is found, this'll also search for a language whose name
509
- /// or alias occurs in the string (for names shorter than three
510
- /// characters, only when surrounded by non-word characters).
629
+ /**
630
+ Look for a language whose name or alias matches the the given
631
+ name (case-insensitively). If `fuzzy` is true, and no direct
632
+ matchs is found, this'll also search for a language whose name
633
+ or alias occurs in the string (for names shorter than three
634
+ characters, only when surrounded by non-word characters).
635
+ */
511
636
  static matchLanguageName(descs, name, fuzzy = true) {
512
637
  name = name.toLowerCase();
513
638
  for (let d of descs)
@@ -524,14 +649,18 @@ class LanguageDescription {
524
649
  }
525
650
  }
526
651
 
527
- /// Facet that defines a way to provide a function that computes the
528
- /// appropriate indentation depth at the start of a given line, or
529
- /// `null` to indicate no appropriate indentation could be determined.
530
- const indentService = Facet.define();
531
- /// Facet for overriding the unit by which indentation happens.
532
- /// Should be a string consisting either entirely of spaces or
533
- /// entirely of tabs. When not set, this defaults to 2 spaces.
534
- const indentUnit = Facet.define({
652
+ /**
653
+ Facet that defines a way to provide a function that computes the
654
+ appropriate indentation depth at the start of a given line, or
655
+ `null` to indicate no appropriate indentation could be determined.
656
+ */
657
+ const indentService = /*@__PURE__*/Facet.define();
658
+ /**
659
+ Facet for overriding the unit by which indentation happens.
660
+ Should be a string consisting either entirely of spaces or
661
+ entirely of tabs. When not set, this defaults to 2 spaces.
662
+ */
663
+ const indentUnit = /*@__PURE__*/Facet.define({
535
664
  combine: values => {
536
665
  if (!values.length)
537
666
  return " ";
@@ -540,18 +669,22 @@ const indentUnit = Facet.define({
540
669
  return values[0];
541
670
  }
542
671
  });
543
- /// Return the _column width_ of an indent unit in the state.
544
- /// Determined by the [`indentUnit`](#language.indentUnit)
545
- /// facet, and [`tabSize`](#state.EditorState^tabSize) when that
546
- /// contains tabs.
672
+ /**
673
+ Return the _column width_ of an indent unit in the state.
674
+ Determined by the [`indentUnit`](https://codemirror.net/6/docs/ref/#language.indentUnit)
675
+ facet, and [`tabSize`](https://codemirror.net/6/docs/ref/#state.EditorState^tabSize) when that
676
+ contains tabs.
677
+ */
547
678
  function getIndentUnit(state) {
548
679
  let unit = state.facet(indentUnit);
549
680
  return unit.charCodeAt(0) == 9 ? state.tabSize * unit.length : unit.length;
550
681
  }
551
- /// Create an indentation string that covers columns 0 to `cols`.
552
- /// Will use tabs for as much of the columns as possible when the
553
- /// [`indentUnit`](#language.indentUnit) facet contains
554
- /// tabs.
682
+ /**
683
+ Create an indentation string that covers columns 0 to `cols`.
684
+ Will use tabs for as much of the columns as possible when the
685
+ [`indentUnit`](https://codemirror.net/6/docs/ref/#language.indentUnit) facet contains
686
+ tabs.
687
+ */
555
688
  function indentString(state, cols) {
556
689
  let result = "", ts = state.tabSize;
557
690
  if (state.facet(indentUnit).charCodeAt(0) == 9)
@@ -563,12 +696,14 @@ function indentString(state, cols) {
563
696
  result += " ";
564
697
  return result;
565
698
  }
566
- /// Get the indentation at the given position. Will first consult any
567
- /// [indent services](#language.indentService) that are registered,
568
- /// and if none of those return an indentation, this will check the
569
- /// syntax tree for the [indent node prop](#language.indentNodeProp)
570
- /// and use that if found. Returns a number when an indentation could
571
- /// be determined, and null otherwise.
699
+ /**
700
+ Get the indentation at the given position. Will first consult any
701
+ [indent services](https://codemirror.net/6/docs/ref/#language.indentService) that are registered,
702
+ and if none of those return an indentation, this will check the
703
+ syntax tree for the [indent node prop](https://codemirror.net/6/docs/ref/#language.indentNodeProp)
704
+ and use that if found. Returns a number when an indentation could
705
+ be determined, and null otherwise.
706
+ */
572
707
  function getIndentation(context, pos) {
573
708
  if (context instanceof EditorState)
574
709
  context = new IndentContext(context);
@@ -580,23 +715,33 @@ function getIndentation(context, pos) {
580
715
  let tree = syntaxTree(context.state);
581
716
  return tree ? syntaxIndentation(context, tree, pos) : null;
582
717
  }
583
- /// Indentation contexts are used when calling [indentation
584
- /// services](#language.indentService). They provide helper utilities
585
- /// useful in indentation logic, and can selectively override the
586
- /// indentation reported for some lines.
718
+ /**
719
+ Indentation contexts are used when calling [indentation
720
+ services](https://codemirror.net/6/docs/ref/#language.indentService). They provide helper utilities
721
+ useful in indentation logic, and can selectively override the
722
+ indentation reported for some lines.
723
+ */
587
724
  class IndentContext {
588
- /// Create an indent context.
725
+ /**
726
+ Create an indent context.
727
+ */
589
728
  constructor(
590
- /// The editor state.
729
+ /**
730
+ The editor state.
731
+ */
591
732
  state,
592
- /// @internal
733
+ /**
734
+ @internal
735
+ */
593
736
  options = {}) {
594
737
  this.state = state;
595
738
  this.options = options;
596
739
  this.unit = getIndentUnit(state);
597
740
  }
598
- /// Get the text directly after `pos`, either the entire line
599
- /// or the next 100 characters, whichever is shorter.
741
+ /**
742
+ Get the text directly after `pos`, either the entire line
743
+ or the next 100 characters, whichever is shorter.
744
+ */
600
745
  textAfterPos(pos) {
601
746
  var _a, _b;
602
747
  let sim = (_a = this.options) === null || _a === void 0 ? void 0 : _a.simulateBreak;
@@ -604,7 +749,9 @@ class IndentContext {
604
749
  return "";
605
750
  return this.state.sliceDoc(pos, Math.min(pos + 100, sim != null && sim > pos ? sim : 1e9, this.state.doc.lineAt(pos).to));
606
751
  }
607
- /// Find the column for the given position.
752
+ /**
753
+ Find the column for the given position.
754
+ */
608
755
  column(pos) {
609
756
  var _a;
610
757
  let line = this.state.doc.lineAt(pos), text = line.text.slice(0, pos - line.from);
@@ -614,12 +761,16 @@ class IndentContext {
614
761
  result += override - this.countColumn(text, text.search(/\S/));
615
762
  return result;
616
763
  }
617
- /// find the column position (taking tabs into account) of the given
618
- /// position in the given string.
764
+ /**
765
+ find the column position (taking tabs into account) of the given
766
+ position in the given string.
767
+ */
619
768
  countColumn(line, pos) {
620
769
  return countColumn(pos < 0 ? line : line.slice(0, pos), 0, this.state.tabSize);
621
770
  }
622
- /// Find the indentation column of the given document line.
771
+ /**
772
+ Find the indentation column of the given document line.
773
+ */
623
774
  lineIndent(line) {
624
775
  var _a;
625
776
  let override = (_a = this.options) === null || _a === void 0 ? void 0 : _a.overrideIndentation;
@@ -631,11 +782,13 @@ class IndentContext {
631
782
  return this.countColumn(line.text, line.text.search(/\S/));
632
783
  }
633
784
  }
634
- /// A syntax tree node prop used to associate indentation strategies
635
- /// with node types. Such a strategy is a function from an indentation
636
- /// context to a column number or null, where null indicates that no
637
- /// definitive indentation can be determined.
638
- const indentNodeProp = new NodeProp();
785
+ /**
786
+ A syntax tree node prop used to associate indentation strategies
787
+ with node types. Such a strategy is a function from an indentation
788
+ context to a column number or null, where null indicates that no
789
+ definitive indentation can be determined.
790
+ */
791
+ const indentNodeProp = /*@__PURE__*/new NodeProp();
639
792
  // Compute the indentation for a given position from the syntax tree.
640
793
  function syntaxIndentation(cx, ast, pos) {
641
794
  let tree = ast.resolve(pos);
@@ -655,12 +808,7 @@ function syntaxIndentation(cx, ast, pos) {
655
808
  scanPos = scan.to + 1;
656
809
  }
657
810
  }
658
- for (; tree; tree = tree.parent) {
659
- let strategy = indentStrategy(tree);
660
- if (strategy)
661
- return strategy(new TreeIndentContext(cx, pos, tree));
662
- }
663
- return null;
811
+ return indentFrom(tree, pos, cx);
664
812
  }
665
813
  function ignoreClosed(cx) {
666
814
  var _a, _b;
@@ -677,31 +825,52 @@ function indentStrategy(tree) {
677
825
  }
678
826
  return tree.parent == null ? topIndent : null;
679
827
  }
828
+ function indentFrom(node, pos, base) {
829
+ for (; node; node = node.parent) {
830
+ let strategy = indentStrategy(node);
831
+ if (strategy)
832
+ return strategy(new TreeIndentContext(base, pos, node));
833
+ }
834
+ return null;
835
+ }
680
836
  function topIndent() { return 0; }
681
- /// Objects of this type provide context information and helper
682
- /// methods to indentation functions.
837
+ /**
838
+ Objects of this type provide context information and helper
839
+ methods to indentation functions.
840
+ */
683
841
  class TreeIndentContext extends IndentContext {
684
- /// @internal
842
+ /**
843
+ @internal
844
+ */
685
845
  constructor(base,
686
- /// The position at which indentation is being computed.
846
+ /**
847
+ The position at which indentation is being computed.
848
+ */
687
849
  pos,
688
- /// The syntax tree node to which the indentation strategy
689
- /// applies.
850
+ /**
851
+ The syntax tree node to which the indentation strategy
852
+ applies.
853
+ */
690
854
  node) {
691
855
  super(base.state, base.options);
856
+ this.base = base;
692
857
  this.pos = pos;
693
858
  this.node = node;
694
859
  }
695
- /// Get the text directly after `this.pos`, either the entire line
696
- /// or the next 100 characters, whichever is shorter.
860
+ /**
861
+ Get the text directly after `this.pos`, either the entire line
862
+ or the next 100 characters, whichever is shorter.
863
+ */
697
864
  get textAfter() {
698
865
  return this.textAfterPos(this.pos);
699
866
  }
700
- /// Get the indentation at the reference line for `this.node`, which
701
- /// is the line on which it starts, unless there is a node that is
702
- /// _not_ a parent of this node covering the start of that line. If
703
- /// so, the line at the start of that node is tried, again skipping
704
- /// on if it is covered by another such node.
867
+ /**
868
+ Get the indentation at the reference line for `this.node`, which
869
+ is the line on which it starts, unless there is a node that is
870
+ _not_ a parent of this node covering the start of that line. If
871
+ so, the line at the start of that node is tried, again skipping
872
+ on if it is covered by another such node.
873
+ */
705
874
  get baseIndent() {
706
875
  let line = this.state.doc.lineAt(this.node.from);
707
876
  // Skip line starts that are covered by a sibling (or cousin, etc)
@@ -715,6 +884,14 @@ class TreeIndentContext extends IndentContext {
715
884
  }
716
885
  return this.lineIndent(line);
717
886
  }
887
+ /**
888
+ Continue looking for indentations in the node's parent nodes,
889
+ and return the result of that.
890
+ */
891
+ continue() {
892
+ let parent = this.node.parent;
893
+ return parent ? indentFrom(parent, this.pos, this.base) : 0;
894
+ }
718
895
  }
719
896
  function isParent(parent, of) {
720
897
  for (let cur = of; cur; cur = cur.parent)
@@ -743,15 +920,17 @@ function bracketedAligned(context) {
743
920
  pos = next.to;
744
921
  }
745
922
  }
746
- /// An indentation strategy for delimited (usually bracketed) nodes.
747
- /// Will, by default, indent one unit more than the parent's base
748
- /// indent unless the line starts with a closing token. When `align`
749
- /// is true and there are non-skipped nodes on the node's opening
750
- /// line, the content of the node will be aligned with the end of the
751
- /// opening node, like this:
752
- ///
753
- /// foo(bar,
754
- /// baz)
923
+ /**
924
+ An indentation strategy for delimited (usually bracketed) nodes.
925
+ Will, by default, indent one unit more than the parent's base
926
+ indent unless the line starts with a closing token. When `align`
927
+ is true and there are non-skipped nodes on the node's opening
928
+ line, the content of the node will be aligned with the end of the
929
+ opening node, like this:
930
+
931
+ foo(bar,
932
+ baz)
933
+ */
755
934
  function delimitedIndent({ closing, align = true, units = 1 }) {
756
935
  return (context) => delimitedStrategy(context, align, units, closing);
757
936
  }
@@ -763,15 +942,19 @@ function delimitedStrategy(context, align, units, closing, closedAt) {
763
942
  return closed ? context.column(aligned.from) : context.column(aligned.to);
764
943
  return context.baseIndent + (closed ? 0 : context.unit * units);
765
944
  }
766
- /// An indentation strategy that aligns a node's content to its base
767
- /// indentation.
945
+ /**
946
+ An indentation strategy that aligns a node's content to its base
947
+ indentation.
948
+ */
768
949
  const flatIndent = (context) => context.baseIndent;
769
- /// Creates an indentation strategy that, by default, indents
770
- /// continued lines one unit more than the node's base indentation.
771
- /// You can provide `except` to prevent indentation of lines that
772
- /// match a pattern (for example `/^else\b/` in `if`/`else`
773
- /// constructs), and you can change the amount of units used with the
774
- /// `units` option.
950
+ /**
951
+ Creates an indentation strategy that, by default, indents
952
+ continued lines one unit more than the node's base indentation.
953
+ You can provide `except` to prevent indentation of lines that
954
+ match a pattern (for example `/^else\b/` in `if`/`else`
955
+ constructs), and you can change the amount of units used with the
956
+ `units` option.
957
+ */
775
958
  function continuedIndent({ except, units = 1 } = {}) {
776
959
  return (context) => {
777
960
  let matchExcept = except && except.test(context.textAfter);
@@ -779,17 +962,19 @@ function continuedIndent({ except, units = 1 } = {}) {
779
962
  };
780
963
  }
781
964
  const DontIndentBeyond = 200;
782
- /// Enables reindentation on input. When a language defines an
783
- /// `indentOnInput` field in its [language
784
- /// data](#state.EditorState.languageDataAt), which must hold a regular
785
- /// expression, the line at the cursor will be reindented whenever new
786
- /// text is typed and the input from the start of the line up to the
787
- /// cursor matches that regexp.
788
- ///
789
- /// To avoid unneccesary reindents, it is recommended to start the
790
- /// regexp with `^` (usually followed by `\s*`), and end it with `$`.
791
- /// For example, `/^\s*\}$/` will reindent when a closing brace is
792
- /// added at the start of a line.
965
+ /**
966
+ Enables reindentation on input. When a language defines an
967
+ `indentOnInput` field in its [language
968
+ data](https://codemirror.net/6/docs/ref/#state.EditorState.languageDataAt), which must hold a regular
969
+ expression, the line at the cursor will be reindented whenever new
970
+ text is typed and the input from the start of the line up to the
971
+ cursor matches that regexp.
972
+
973
+ To avoid unneccesary reindents, it is recommended to start the
974
+ regexp with `^` (usually followed by `\s*`), and end it with `$`.
975
+ For example, `/^\s*\}$/` will reindent when a closing brace is
976
+ added at the start of a line.
977
+ */
793
978
  function indentOnInput() {
794
979
  return EditorState.transactionFilter.of(tr => {
795
980
  if (!tr.docChanged || tr.annotation(Transaction.userEvent) != "input")
@@ -821,16 +1006,29 @@ function indentOnInput() {
821
1006
  });
822
1007
  }
823
1008
 
824
- /// A facet that registers a code folding service. When called with
825
- /// the extent of a line, such a function should return a foldable
826
- /// range that starts on that line (but continues beyond it), if one
827
- /// can be found.
828
- const foldService = Facet.define();
829
- /// This node prop is used to associate folding information with
830
- /// syntax node types. Given a syntax node, it should check whether
831
- /// that tree is foldable and return the range that can be collapsed
832
- /// when it is.
833
- const foldNodeProp = new NodeProp();
1009
+ /**
1010
+ A facet that registers a code folding service. When called with
1011
+ the extent of a line, such a function should return a foldable
1012
+ range that starts on that line (but continues beyond it), if one
1013
+ can be found.
1014
+ */
1015
+ const foldService = /*@__PURE__*/Facet.define();
1016
+ /**
1017
+ This node prop is used to associate folding information with
1018
+ syntax node types. Given a syntax node, it should check whether
1019
+ that tree is foldable and return the range that can be collapsed
1020
+ when it is.
1021
+ */
1022
+ const foldNodeProp = /*@__PURE__*/new NodeProp();
1023
+ /**
1024
+ [Fold](https://codemirror.net/6/docs/ref/#language.foldNodeProp) function that folds everything but
1025
+ the first and the last child of a syntax node. Useful for nodes
1026
+ that start and end with delimiters.
1027
+ */
1028
+ function foldInside(node) {
1029
+ let first = node.firstChild, last = node.lastChild;
1030
+ return first && first.to < last.from ? { from: first.to, to: last.type.isError ? node.to : last.from } : null;
1031
+ }
834
1032
  function syntaxFolding(state, start, end) {
835
1033
  let tree = syntaxTree(state);
836
1034
  if (tree.length == 0)
@@ -851,12 +1049,14 @@ function syntaxFolding(state, start, end) {
851
1049
  }
852
1050
  return found;
853
1051
  }
854
- /// Check whether the given line is foldable. First asks any fold
855
- /// services registered through
856
- /// [`foldService`](#language.foldService), and if none of them return
857
- /// a result, tries to query the [fold node
858
- /// prop](#language.foldNodeProp) of syntax nodes that cover the end
859
- /// of the line.
1052
+ /**
1053
+ Check whether the given line is foldable. First asks any fold
1054
+ services registered through
1055
+ [`foldService`](https://codemirror.net/6/docs/ref/#language.foldService), and if none of them return
1056
+ a result, tries to query the [fold node
1057
+ prop](https://codemirror.net/6/docs/ref/#language.foldNodeProp) of syntax nodes that cover the end
1058
+ of the line.
1059
+ */
860
1060
  function foldable(state, lineStart, lineEnd) {
861
1061
  for (let service of state.facet(foldService)) {
862
1062
  let result = service(state, lineStart, lineEnd);
@@ -866,4 +1066,4 @@ function foldable(state, lineStart, lineEnd) {
866
1066
  return syntaxFolding(state, lineStart, lineEnd);
867
1067
  }
868
1068
 
869
- export { EditorParseContext, IndentContext, Language, LanguageDescription, LanguageSupport, LezerLanguage, TreeIndentContext, continuedIndent, defineLanguageFacet, delimitedIndent, ensureSyntaxTree, flatIndent, foldNodeProp, foldService, foldable, getIndentUnit, getIndentation, indentNodeProp, indentOnInput, indentService, indentString, indentUnit, language, languageDataProp, syntaxTree };
1069
+ export { EditorParseContext, IndentContext, Language, LanguageDescription, LanguageSupport, LezerLanguage, TreeIndentContext, continuedIndent, defineLanguageFacet, delimitedIndent, ensureSyntaxTree, flatIndent, foldInside, foldNodeProp, foldService, foldable, getIndentUnit, getIndentation, indentNodeProp, indentOnInput, indentService, indentString, indentUnit, language, languageDataProp, syntaxTree };