@codemirror/language 6.2.1 → 6.3.1

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