@codemirror/language 6.3.2 → 6.5.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,21 @@
1
+ ## 6.5.0 (2023-02-07)
2
+
3
+ ### Bug fixes
4
+
5
+ Make indentation for stream languages more reliable by having `StringStream.indentation` return overridden indentations from the indent context.
6
+
7
+ ### New features
8
+
9
+ The `toggleFold` command folds or unfolds depending on whether there's an existing folded range on the current line.
10
+
11
+ `indentUnit` now accepts any (repeated) whitespace character, not just spaces and tabs.
12
+
13
+ ## 6.4.0 (2023-01-12)
14
+
15
+ ### New features
16
+
17
+ The `bracketMatchingHandle` node prop can now be used to limit bracket matching behavior for larger nodes to a single subnode (for example the tag name of an HTML tag).
18
+
1
19
  ## 6.3.2 (2022-12-16)
2
20
 
3
21
  ### Bug fixes
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (C) 2018-2021 by Marijn Haverbeke <marijnh@gmail.com> and others
3
+ Copyright (C) 2018-2021 by Marijn Haverbeke <marijn@haverbeke.berlin> and others
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/dist/index.cjs CHANGED
@@ -229,13 +229,13 @@ function syntaxParserRunning(view) {
229
229
  }
230
230
  // Lezer-style Input object for a Text document.
231
231
  class DocInput {
232
- constructor(doc, length = doc.length) {
232
+ constructor(doc) {
233
233
  this.doc = doc;
234
- this.length = length;
235
234
  this.cursorPos = 0;
236
235
  this.string = "";
237
236
  this.cursor = doc.iter();
238
237
  }
238
+ get length() { return this.doc.length; }
239
239
  syncTo(pos) {
240
240
  this.string = this.cursor.next(pos - this.cursorPos).value;
241
241
  this.cursorPos = pos + this.string.length;
@@ -780,17 +780,18 @@ service.
780
780
  */
781
781
  const indentService = state.Facet.define();
782
782
  /**
783
- Facet for overriding the unit by which indentation happens.
784
- Should be a string consisting either entirely of spaces or
785
- entirely of tabs. When not set, this defaults to 2 spaces.
783
+ Facet for overriding the unit by which indentation happens. Should
784
+ be a string consisting either entirely of the same whitespace
785
+ character. When not set, this defaults to 2 spaces.
786
786
  */
787
787
  const indentUnit = state.Facet.define({
788
788
  combine: values => {
789
789
  if (!values.length)
790
790
  return " ";
791
- if (!/^(?: +|\t+)$/.test(values[0]))
791
+ let unit = values[0];
792
+ if (!unit || /\S/.test(unit) || Array.from(unit).some(e => e != unit[0]))
792
793
  throw new Error("Invalid indent unit: " + JSON.stringify(values[0]));
793
- return values[0];
794
+ return unit;
794
795
  }
795
796
  });
796
797
  /**
@@ -810,14 +811,16 @@ Will use tabs for as much of the columns as possible when the
810
811
  tabs.
811
812
  */
812
813
  function indentString(state, cols) {
813
- let result = "", ts = state.tabSize;
814
- if (state.facet(indentUnit).charCodeAt(0) == 9)
814
+ let result = "", ts = state.tabSize, ch = state.facet(indentUnit)[0];
815
+ if (ch == "\t") {
815
816
  while (cols >= ts) {
816
817
  result += "\t";
817
818
  cols -= ts;
818
819
  }
820
+ ch = " ";
821
+ }
819
822
  for (let i = 0; i < cols; i++)
820
- result += " ";
823
+ result += ch;
821
824
  return result;
822
825
  }
823
826
  /**
@@ -1400,6 +1403,41 @@ const unfoldAll = view => {
1400
1403
  view.dispatch({ effects });
1401
1404
  return true;
1402
1405
  };
1406
+ // Find the foldable region containing the given line, if one exists
1407
+ function foldableContainer(view, lineBlock) {
1408
+ // Look backwards through line blocks until we find a foldable region that
1409
+ // intersects with the line
1410
+ for (let line = lineBlock;;) {
1411
+ let foldableRegion = foldable(view.state, line.from, line.to);
1412
+ if (foldableRegion && foldableRegion.to > lineBlock.from)
1413
+ return foldableRegion;
1414
+ if (!line.from)
1415
+ return null;
1416
+ line = view.lineBlockAt(line.from - 1);
1417
+ }
1418
+ }
1419
+ /**
1420
+ Toggle folding at cursors. Unfolds if there is an existing fold
1421
+ starting in that line, tries to find a foldable range around it
1422
+ otherwise.
1423
+ */
1424
+ const toggleFold = (view) => {
1425
+ let effects = [];
1426
+ for (let line of selectedLines(view)) {
1427
+ let folded = findFold(view.state, line.from, line.to);
1428
+ if (folded) {
1429
+ effects.push(unfoldEffect.of(folded), announceFold(view, folded, false));
1430
+ }
1431
+ else {
1432
+ let foldRange = foldableContainer(view, line);
1433
+ if (foldRange)
1434
+ effects.push(foldEffect.of(foldRange), announceFold(view, foldRange));
1435
+ }
1436
+ }
1437
+ if (effects.length > 0)
1438
+ view.dispatch({ effects: maybeEnable(view.state, effects) });
1439
+ return !!effects.length;
1440
+ };
1403
1441
  /**
1404
1442
  Default fold-related key bindings.
1405
1443
 
@@ -1787,6 +1825,15 @@ highlighting style is used to indicate this.
1787
1825
  function bracketMatching(config = {}) {
1788
1826
  return [bracketMatchingConfig.of(config), bracketMatchingUnique];
1789
1827
  }
1828
+ /**
1829
+ When larger syntax nodes, such as HTML tags, are marked as
1830
+ opening/closing, it can be a bit messy to treat the whole node as
1831
+ a matchable bracket. This node prop allows you to define, for such
1832
+ a node, a ‘handle’—the part of the node that is highlighted, and
1833
+ that the cursor must be on to activate highlighting in the first
1834
+ place.
1835
+ */
1836
+ const bracketMatchingHandle = new common.NodeProp();
1790
1837
  function matchingNodes(node, dir, brackets) {
1791
1838
  let byProp = node.prop(dir < 0 ? common.NodeProp.openedBy : common.NodeProp.closedBy);
1792
1839
  if (byProp)
@@ -1798,6 +1845,10 @@ function matchingNodes(node, dir, brackets) {
1798
1845
  }
1799
1846
  return null;
1800
1847
  }
1848
+ function findHandle(node) {
1849
+ let hasHandle = node.type.prop(bracketMatchingHandle);
1850
+ return hasHandle ? hasHandle(node.node) : node;
1851
+ }
1801
1852
  /**
1802
1853
  Find the matching bracket for the token at `pos`, scanning
1803
1854
  direction `dir`. Only the `brackets` and `maxScanDistance`
@@ -1809,30 +1860,36 @@ function matchBrackets(state, pos, dir, config = {}) {
1809
1860
  let tree = syntaxTree(state), node = tree.resolveInner(pos, dir);
1810
1861
  for (let cur = node; cur; cur = cur.parent) {
1811
1862
  let matches = matchingNodes(cur.type, dir, brackets);
1812
- if (matches && cur.from < cur.to)
1813
- return matchMarkedBrackets(state, pos, dir, cur, matches, brackets);
1863
+ if (matches && cur.from < cur.to) {
1864
+ let handle = findHandle(cur);
1865
+ if (handle && (dir > 0 ? pos >= handle.from && pos < handle.to : pos > handle.from && pos <= handle.to))
1866
+ return matchMarkedBrackets(state, pos, dir, cur, handle, matches, brackets);
1867
+ }
1814
1868
  }
1815
1869
  return matchPlainBrackets(state, pos, dir, tree, node.type, maxScanDistance, brackets);
1816
1870
  }
1817
- function matchMarkedBrackets(_state, _pos, dir, token, matching, brackets) {
1818
- let parent = token.parent, firstToken = { from: token.from, to: token.to };
1871
+ function matchMarkedBrackets(_state, _pos, dir, token, handle, matching, brackets) {
1872
+ let parent = token.parent, firstToken = { from: handle.from, to: handle.to };
1819
1873
  let depth = 0, cursor = parent === null || parent === void 0 ? void 0 : parent.cursor();
1820
1874
  if (cursor && (dir < 0 ? cursor.childBefore(token.from) : cursor.childAfter(token.to)))
1821
1875
  do {
1822
1876
  if (dir < 0 ? cursor.to <= token.from : cursor.from >= token.to) {
1823
1877
  if (depth == 0 && matching.indexOf(cursor.type.name) > -1 && cursor.from < cursor.to) {
1824
- return { start: firstToken, end: { from: cursor.from, to: cursor.to }, matched: true };
1878
+ let endHandle = findHandle(cursor);
1879
+ return { start: firstToken, end: endHandle ? { from: endHandle.from, to: endHandle.to } : undefined, matched: true };
1825
1880
  }
1826
1881
  else if (matchingNodes(cursor.type, dir, brackets)) {
1827
1882
  depth++;
1828
1883
  }
1829
1884
  else if (matchingNodes(cursor.type, -dir, brackets)) {
1830
- if (depth == 0)
1885
+ if (depth == 0) {
1886
+ let endHandle = findHandle(cursor);
1831
1887
  return {
1832
1888
  start: firstToken,
1833
- end: cursor.from == cursor.to ? undefined : { from: cursor.from, to: cursor.to },
1889
+ end: endHandle && endHandle.from < endHandle.to ? { from: endHandle.from, to: endHandle.to } : undefined,
1834
1890
  matched: false
1835
1891
  };
1892
+ }
1836
1893
  depth--;
1837
1894
  }
1838
1895
  }
@@ -1904,10 +1961,11 @@ class StringStream {
1904
1961
  /**
1905
1962
  The current indent unit size.
1906
1963
  */
1907
- indentUnit) {
1964
+ indentUnit, overrideIndent) {
1908
1965
  this.string = string;
1909
1966
  this.tabSize = tabSize;
1910
1967
  this.indentUnit = indentUnit;
1968
+ this.overrideIndent = overrideIndent;
1911
1969
  /**
1912
1970
  The current position on the line.
1913
1971
  */
@@ -2008,7 +2066,8 @@ class StringStream {
2008
2066
  Get the indentation column of the current line.
2009
2067
  */
2010
2068
  indentation() {
2011
- return countCol(this.string, null, this.tabSize);
2069
+ var _a;
2070
+ return (_a = this.overrideIndent) !== null && _a !== void 0 ? _a : countCol(this.string, null, this.tabSize);
2012
2071
  }
2013
2072
  /**
2014
2073
  Match the input against the given string or regular expression
@@ -2070,6 +2129,7 @@ function defaultCopyState(state) {
2070
2129
  }
2071
2130
  return newState;
2072
2131
  }
2132
+ const IndentedFrom = new WeakMap();
2073
2133
  /**
2074
2134
  A [language](https://codemirror.net/6/docs/ref/#language.Language) class based on a CodeMirror
2075
2135
  5-style [streaming parser](https://codemirror.net/6/docs/ref/#language.StreamParser).
@@ -2100,7 +2160,14 @@ class StreamLanguage extends Language {
2100
2160
  at = at.parent;
2101
2161
  if (!at)
2102
2162
  return null;
2103
- let start = findState(this, tree, 0, at.from, pos), statePos, state;
2163
+ let from = undefined;
2164
+ let { overrideIndentation } = cx.options;
2165
+ if (overrideIndentation) {
2166
+ from = IndentedFrom.get(cx.state);
2167
+ if (from != null && from < pos - 1e4)
2168
+ from = undefined;
2169
+ }
2170
+ let start = findState(this, tree, 0, at.from, from !== null && from !== void 0 ? from : pos), statePos, state;
2104
2171
  if (start) {
2105
2172
  state = start.state;
2106
2173
  statePos = start.pos + 1;
@@ -2114,7 +2181,8 @@ class StreamLanguage extends Language {
2114
2181
  while (statePos < pos) {
2115
2182
  let line = cx.state.doc.lineAt(statePos), end = Math.min(pos, line.to);
2116
2183
  if (line.length) {
2117
- let stream = new StringStream(line.text, cx.state.tabSize, cx.unit);
2184
+ let indentation = overrideIndentation ? overrideIndentation(line.from) : -1;
2185
+ let stream = new StringStream(line.text, cx.state.tabSize, cx.unit, indentation < 0 ? undefined : indentation);
2118
2186
  while (stream.pos < end - line.from)
2119
2187
  readToken(this.streamParser.token, stream, state);
2120
2188
  }
@@ -2125,8 +2193,10 @@ class StreamLanguage extends Language {
2125
2193
  break;
2126
2194
  statePos = line.to + 1;
2127
2195
  }
2128
- let { text } = cx.lineAt(pos);
2129
- return this.streamParser.indent(state, /^\s*(.*)/.exec(text)[1], cx);
2196
+ let line = cx.lineAt(pos);
2197
+ if (overrideIndentation && from == null)
2198
+ IndentedFrom.set(cx.state, line.from);
2199
+ return this.streamParser.indent(state, /^\s*(.*)/.exec(line.text)[1], cx);
2130
2200
  }
2131
2201
  get allowsNesting() { return false; }
2132
2202
  }
@@ -2404,6 +2474,7 @@ exports.StreamLanguage = StreamLanguage;
2404
2474
  exports.StringStream = StringStream;
2405
2475
  exports.TreeIndentContext = TreeIndentContext;
2406
2476
  exports.bracketMatching = bracketMatching;
2477
+ exports.bracketMatchingHandle = bracketMatchingHandle;
2407
2478
  exports.codeFolding = codeFolding;
2408
2479
  exports.continuedIndent = continuedIndent;
2409
2480
  exports.defaultHighlightStyle = defaultHighlightStyle;
@@ -2439,6 +2510,7 @@ exports.syntaxHighlighting = syntaxHighlighting;
2439
2510
  exports.syntaxParserRunning = syntaxParserRunning;
2440
2511
  exports.syntaxTree = syntaxTree;
2441
2512
  exports.syntaxTreeAvailable = syntaxTreeAvailable;
2513
+ exports.toggleFold = toggleFold;
2442
2514
  exports.unfoldAll = unfoldAll;
2443
2515
  exports.unfoldCode = unfoldCode;
2444
2516
  exports.unfoldEffect = unfoldEffect;
package/dist/index.d.ts CHANGED
@@ -370,9 +370,9 @@ service.
370
370
  */
371
371
  declare const indentService: Facet<(context: IndentContext, pos: number) => number | null | undefined, readonly ((context: IndentContext, pos: number) => number | null | undefined)[]>;
372
372
  /**
373
- Facet for overriding the unit by which indentation happens.
374
- Should be a string consisting either entirely of spaces or
375
- entirely of tabs. When not set, this defaults to 2 spaces.
373
+ Facet for overriding the unit by which indentation happens. Should
374
+ be a string consisting either entirely of the same whitespace
375
+ character. When not set, this defaults to 2 spaces.
376
376
  */
377
377
  declare const indentUnit: Facet<string, string>;
378
378
  /**
@@ -450,7 +450,7 @@ declare class IndentContext {
450
450
  simulateBreak?: number;
451
451
  /**
452
452
  When `simulateBreak` is given, this can be used to make the
453
- simulate break behave like a double line break.
453
+ simulated break behave like a double line break.
454
454
  */
455
455
  simulateDoubleBreak?: boolean;
456
456
  });
@@ -678,6 +678,12 @@ Unfold all folded code.
678
678
  */
679
679
  declare const unfoldAll: Command;
680
680
  /**
681
+ Toggle folding at cursors. Unfolds if there is an existing fold
682
+ starting in that line, tries to find a foldable range around it
683
+ otherwise.
684
+ */
685
+ declare const toggleFold: Command;
686
+ /**
681
687
  Default fold-related key bindings.
682
688
 
683
689
  - Ctrl-Shift-[ (Cmd-Alt-[ on macOS): [`foldCode`](https://codemirror.net/6/docs/ref/#language.foldCode).
@@ -889,6 +895,15 @@ highlighting style is used to indicate this.
889
895
  */
890
896
  declare function bracketMatching(config?: Config): Extension;
891
897
  /**
898
+ When larger syntax nodes, such as HTML tags, are marked as
899
+ opening/closing, it can be a bit messy to treat the whole node as
900
+ a matchable bracket. This node prop allows you to define, for such
901
+ a node, a ‘handle’—the part of the node that is highlighted, and
902
+ that the cursor must be on to activate highlighting in the first
903
+ place.
904
+ */
905
+ declare const bracketMatchingHandle: NodeProp<(node: SyntaxNode) => SyntaxNode | null>;
906
+ /**
892
907
  The result returned from `matchBrackets`.
893
908
  */
894
909
  interface MatchResult {
@@ -934,6 +949,7 @@ declare class StringStream {
934
949
  The current indent unit size.
935
950
  */
936
951
  indentUnit: number;
952
+ private overrideIndent?;
937
953
  /**
938
954
  The current position on the line.
939
955
  */
@@ -955,7 +971,7 @@ declare class StringStream {
955
971
  /**
956
972
  The current indent unit size.
957
973
  */
958
- indentUnit: number);
974
+ indentUnit: number, overrideIndent?: number | undefined);
959
975
  /**
960
976
  True if we are at the end of the line.
961
977
  */
@@ -1103,4 +1119,4 @@ declare class StreamLanguage<State> extends Language {
1103
1119
  get allowsNesting(): boolean;
1104
1120
  }
1105
1121
 
1106
- export { Config, HighlightStyle, IndentContext, LRLanguage, Language, LanguageDescription, LanguageSupport, MatchResult, ParseContext, StreamLanguage, StreamParser, StringStream, TagStyle, TreeIndentContext, bracketMatching, codeFolding, continuedIndent, defaultHighlightStyle, defineLanguageFacet, delimitedIndent, ensureSyntaxTree, flatIndent, foldAll, foldCode, foldEffect, foldGutter, foldInside, foldKeymap, foldNodeProp, foldService, foldState, foldable, foldedRanges, forceParsing, getIndentUnit, getIndentation, highlightingFor, indentNodeProp, indentOnInput, indentRange, indentService, indentString, indentUnit, language, languageDataProp, matchBrackets, syntaxHighlighting, syntaxParserRunning, syntaxTree, syntaxTreeAvailable, unfoldAll, unfoldCode, unfoldEffect };
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 };
package/dist/index.js CHANGED
@@ -225,13 +225,13 @@ function syntaxParserRunning(view) {
225
225
  }
226
226
  // Lezer-style Input object for a Text document.
227
227
  class DocInput {
228
- constructor(doc, length = doc.length) {
228
+ constructor(doc) {
229
229
  this.doc = doc;
230
- this.length = length;
231
230
  this.cursorPos = 0;
232
231
  this.string = "";
233
232
  this.cursor = doc.iter();
234
233
  }
234
+ get length() { return this.doc.length; }
235
235
  syncTo(pos) {
236
236
  this.string = this.cursor.next(pos - this.cursorPos).value;
237
237
  this.cursorPos = pos + this.string.length;
@@ -776,17 +776,18 @@ service.
776
776
  */
777
777
  const indentService = /*@__PURE__*/Facet.define();
778
778
  /**
779
- Facet for overriding the unit by which indentation happens.
780
- Should be a string consisting either entirely of spaces or
781
- entirely of tabs. When not set, this defaults to 2 spaces.
779
+ Facet for overriding the unit by which indentation happens. Should
780
+ be a string consisting either entirely of the same whitespace
781
+ character. When not set, this defaults to 2 spaces.
782
782
  */
783
783
  const indentUnit = /*@__PURE__*/Facet.define({
784
784
  combine: values => {
785
785
  if (!values.length)
786
786
  return " ";
787
- if (!/^(?: +|\t+)$/.test(values[0]))
787
+ let unit = values[0];
788
+ if (!unit || /\S/.test(unit) || Array.from(unit).some(e => e != unit[0]))
788
789
  throw new Error("Invalid indent unit: " + JSON.stringify(values[0]));
789
- return values[0];
790
+ return unit;
790
791
  }
791
792
  });
792
793
  /**
@@ -806,14 +807,16 @@ Will use tabs for as much of the columns as possible when the
806
807
  tabs.
807
808
  */
808
809
  function indentString(state, cols) {
809
- let result = "", ts = state.tabSize;
810
- if (state.facet(indentUnit).charCodeAt(0) == 9)
810
+ let result = "", ts = state.tabSize, ch = state.facet(indentUnit)[0];
811
+ if (ch == "\t") {
811
812
  while (cols >= ts) {
812
813
  result += "\t";
813
814
  cols -= ts;
814
815
  }
816
+ ch = " ";
817
+ }
815
818
  for (let i = 0; i < cols; i++)
816
- result += " ";
819
+ result += ch;
817
820
  return result;
818
821
  }
819
822
  /**
@@ -1396,6 +1399,41 @@ const unfoldAll = view => {
1396
1399
  view.dispatch({ effects });
1397
1400
  return true;
1398
1401
  };
1402
+ // Find the foldable region containing the given line, if one exists
1403
+ function foldableContainer(view, lineBlock) {
1404
+ // Look backwards through line blocks until we find a foldable region that
1405
+ // intersects with the line
1406
+ for (let line = lineBlock;;) {
1407
+ let foldableRegion = foldable(view.state, line.from, line.to);
1408
+ if (foldableRegion && foldableRegion.to > lineBlock.from)
1409
+ return foldableRegion;
1410
+ if (!line.from)
1411
+ return null;
1412
+ line = view.lineBlockAt(line.from - 1);
1413
+ }
1414
+ }
1415
+ /**
1416
+ Toggle folding at cursors. Unfolds if there is an existing fold
1417
+ starting in that line, tries to find a foldable range around it
1418
+ otherwise.
1419
+ */
1420
+ const toggleFold = (view) => {
1421
+ let effects = [];
1422
+ for (let line of selectedLines(view)) {
1423
+ let folded = findFold(view.state, line.from, line.to);
1424
+ if (folded) {
1425
+ effects.push(unfoldEffect.of(folded), announceFold(view, folded, false));
1426
+ }
1427
+ else {
1428
+ let foldRange = foldableContainer(view, line);
1429
+ if (foldRange)
1430
+ effects.push(foldEffect.of(foldRange), announceFold(view, foldRange));
1431
+ }
1432
+ }
1433
+ if (effects.length > 0)
1434
+ view.dispatch({ effects: maybeEnable(view.state, effects) });
1435
+ return !!effects.length;
1436
+ };
1399
1437
  /**
1400
1438
  Default fold-related key bindings.
1401
1439
 
@@ -1783,6 +1821,15 @@ highlighting style is used to indicate this.
1783
1821
  function bracketMatching(config = {}) {
1784
1822
  return [bracketMatchingConfig.of(config), bracketMatchingUnique];
1785
1823
  }
1824
+ /**
1825
+ When larger syntax nodes, such as HTML tags, are marked as
1826
+ opening/closing, it can be a bit messy to treat the whole node as
1827
+ a matchable bracket. This node prop allows you to define, for such
1828
+ a node, a ‘handle’—the part of the node that is highlighted, and
1829
+ that the cursor must be on to activate highlighting in the first
1830
+ place.
1831
+ */
1832
+ const bracketMatchingHandle = /*@__PURE__*/new NodeProp();
1786
1833
  function matchingNodes(node, dir, brackets) {
1787
1834
  let byProp = node.prop(dir < 0 ? NodeProp.openedBy : NodeProp.closedBy);
1788
1835
  if (byProp)
@@ -1794,6 +1841,10 @@ function matchingNodes(node, dir, brackets) {
1794
1841
  }
1795
1842
  return null;
1796
1843
  }
1844
+ function findHandle(node) {
1845
+ let hasHandle = node.type.prop(bracketMatchingHandle);
1846
+ return hasHandle ? hasHandle(node.node) : node;
1847
+ }
1797
1848
  /**
1798
1849
  Find the matching bracket for the token at `pos`, scanning
1799
1850
  direction `dir`. Only the `brackets` and `maxScanDistance`
@@ -1805,30 +1856,36 @@ function matchBrackets(state, pos, dir, config = {}) {
1805
1856
  let tree = syntaxTree(state), node = tree.resolveInner(pos, dir);
1806
1857
  for (let cur = node; cur; cur = cur.parent) {
1807
1858
  let matches = matchingNodes(cur.type, dir, brackets);
1808
- if (matches && cur.from < cur.to)
1809
- return matchMarkedBrackets(state, pos, dir, cur, matches, brackets);
1859
+ if (matches && cur.from < cur.to) {
1860
+ let handle = findHandle(cur);
1861
+ if (handle && (dir > 0 ? pos >= handle.from && pos < handle.to : pos > handle.from && pos <= handle.to))
1862
+ return matchMarkedBrackets(state, pos, dir, cur, handle, matches, brackets);
1863
+ }
1810
1864
  }
1811
1865
  return matchPlainBrackets(state, pos, dir, tree, node.type, maxScanDistance, brackets);
1812
1866
  }
1813
- function matchMarkedBrackets(_state, _pos, dir, token, matching, brackets) {
1814
- let parent = token.parent, firstToken = { from: token.from, to: token.to };
1867
+ function matchMarkedBrackets(_state, _pos, dir, token, handle, matching, brackets) {
1868
+ let parent = token.parent, firstToken = { from: handle.from, to: handle.to };
1815
1869
  let depth = 0, cursor = parent === null || parent === void 0 ? void 0 : parent.cursor();
1816
1870
  if (cursor && (dir < 0 ? cursor.childBefore(token.from) : cursor.childAfter(token.to)))
1817
1871
  do {
1818
1872
  if (dir < 0 ? cursor.to <= token.from : cursor.from >= token.to) {
1819
1873
  if (depth == 0 && matching.indexOf(cursor.type.name) > -1 && cursor.from < cursor.to) {
1820
- return { start: firstToken, end: { from: cursor.from, to: cursor.to }, matched: true };
1874
+ let endHandle = findHandle(cursor);
1875
+ return { start: firstToken, end: endHandle ? { from: endHandle.from, to: endHandle.to } : undefined, matched: true };
1821
1876
  }
1822
1877
  else if (matchingNodes(cursor.type, dir, brackets)) {
1823
1878
  depth++;
1824
1879
  }
1825
1880
  else if (matchingNodes(cursor.type, -dir, brackets)) {
1826
- if (depth == 0)
1881
+ if (depth == 0) {
1882
+ let endHandle = findHandle(cursor);
1827
1883
  return {
1828
1884
  start: firstToken,
1829
- end: cursor.from == cursor.to ? undefined : { from: cursor.from, to: cursor.to },
1885
+ end: endHandle && endHandle.from < endHandle.to ? { from: endHandle.from, to: endHandle.to } : undefined,
1830
1886
  matched: false
1831
1887
  };
1888
+ }
1832
1889
  depth--;
1833
1890
  }
1834
1891
  }
@@ -1900,10 +1957,11 @@ class StringStream {
1900
1957
  /**
1901
1958
  The current indent unit size.
1902
1959
  */
1903
- indentUnit) {
1960
+ indentUnit, overrideIndent) {
1904
1961
  this.string = string;
1905
1962
  this.tabSize = tabSize;
1906
1963
  this.indentUnit = indentUnit;
1964
+ this.overrideIndent = overrideIndent;
1907
1965
  /**
1908
1966
  The current position on the line.
1909
1967
  */
@@ -2004,7 +2062,8 @@ class StringStream {
2004
2062
  Get the indentation column of the current line.
2005
2063
  */
2006
2064
  indentation() {
2007
- return countCol(this.string, null, this.tabSize);
2065
+ var _a;
2066
+ return (_a = this.overrideIndent) !== null && _a !== void 0 ? _a : countCol(this.string, null, this.tabSize);
2008
2067
  }
2009
2068
  /**
2010
2069
  Match the input against the given string or regular expression
@@ -2066,6 +2125,7 @@ function defaultCopyState(state) {
2066
2125
  }
2067
2126
  return newState;
2068
2127
  }
2128
+ const IndentedFrom = /*@__PURE__*/new WeakMap();
2069
2129
  /**
2070
2130
  A [language](https://codemirror.net/6/docs/ref/#language.Language) class based on a CodeMirror
2071
2131
  5-style [streaming parser](https://codemirror.net/6/docs/ref/#language.StreamParser).
@@ -2096,7 +2156,14 @@ class StreamLanguage extends Language {
2096
2156
  at = at.parent;
2097
2157
  if (!at)
2098
2158
  return null;
2099
- let start = findState(this, tree, 0, at.from, pos), statePos, state;
2159
+ let from = undefined;
2160
+ let { overrideIndentation } = cx.options;
2161
+ if (overrideIndentation) {
2162
+ from = IndentedFrom.get(cx.state);
2163
+ if (from != null && from < pos - 1e4)
2164
+ from = undefined;
2165
+ }
2166
+ let start = findState(this, tree, 0, at.from, from !== null && from !== void 0 ? from : pos), statePos, state;
2100
2167
  if (start) {
2101
2168
  state = start.state;
2102
2169
  statePos = start.pos + 1;
@@ -2110,7 +2177,8 @@ class StreamLanguage extends Language {
2110
2177
  while (statePos < pos) {
2111
2178
  let line = cx.state.doc.lineAt(statePos), end = Math.min(pos, line.to);
2112
2179
  if (line.length) {
2113
- let stream = new StringStream(line.text, cx.state.tabSize, cx.unit);
2180
+ let indentation = overrideIndentation ? overrideIndentation(line.from) : -1;
2181
+ let stream = new StringStream(line.text, cx.state.tabSize, cx.unit, indentation < 0 ? undefined : indentation);
2114
2182
  while (stream.pos < end - line.from)
2115
2183
  readToken(this.streamParser.token, stream, state);
2116
2184
  }
@@ -2121,8 +2189,10 @@ class StreamLanguage extends Language {
2121
2189
  break;
2122
2190
  statePos = line.to + 1;
2123
2191
  }
2124
- let { text } = cx.lineAt(pos);
2125
- return this.streamParser.indent(state, /^\s*(.*)/.exec(text)[1], cx);
2192
+ let line = cx.lineAt(pos);
2193
+ if (overrideIndentation && from == null)
2194
+ IndentedFrom.set(cx.state, line.from);
2195
+ return this.streamParser.indent(state, /^\s*(.*)/.exec(line.text)[1], cx);
2126
2196
  }
2127
2197
  get allowsNesting() { return false; }
2128
2198
  }
@@ -2389,4 +2459,4 @@ function docID(data) {
2389
2459
  return type;
2390
2460
  }
2391
2461
 
2392
- export { HighlightStyle, IndentContext, LRLanguage, Language, LanguageDescription, LanguageSupport, ParseContext, StreamLanguage, StringStream, TreeIndentContext, bracketMatching, codeFolding, continuedIndent, defaultHighlightStyle, defineLanguageFacet, delimitedIndent, ensureSyntaxTree, flatIndent, foldAll, foldCode, foldEffect, foldGutter, foldInside, foldKeymap, foldNodeProp, foldService, foldState, foldable, foldedRanges, forceParsing, getIndentUnit, getIndentation, highlightingFor, indentNodeProp, indentOnInput, indentRange, indentService, indentString, indentUnit, language, languageDataProp, matchBrackets, syntaxHighlighting, syntaxParserRunning, syntaxTree, syntaxTreeAvailable, unfoldAll, unfoldCode, unfoldEffect };
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 };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codemirror/language",
3
- "version": "6.3.2",
3
+ "version": "6.5.0",
4
4
  "description": "Language support infrastructure for the CodeMirror code editor",
5
5
  "scripts": {
6
6
  "test": "cm-runtests",
@@ -12,7 +12,7 @@
12
12
  ],
13
13
  "author": {
14
14
  "name": "Marijn Haverbeke",
15
- "email": "marijnh@gmail.com",
15
+ "email": "marijn@haverbeke.berlin",
16
16
  "url": "http://marijnhaverbeke.nl"
17
17
  },
18
18
  "type": "module",