/ src / tree-sitter-language-mode.js
tree-sitter-language-mode.js
   1  const Parser = require('tree-sitter');
   2  const { Point, Range, spliceArray } = require('text-buffer');
   3  const { Patch } = require('superstring');
   4  const { Emitter } = require('event-kit');
   5  const ScopeDescriptor = require('./scope-descriptor');
   6  const Token = require('./token');
   7  const TokenizedLine = require('./tokenized-line');
   8  const TextMateLanguageMode = require('./text-mate-language-mode');
   9  const { matcherForSelector } = require('./selectors');
  10  
  11  let nextId = 0;
  12  const MAX_RANGE = new Range(Point.ZERO, Point.INFINITY).freeze();
  13  const PARSER_POOL = [];
  14  const WORD_REGEX = /\w/;
  15  
  16  class TreeSitterLanguageMode {
  17    static _patchSyntaxNode() {
  18      if (!Parser.SyntaxNode.prototype.hasOwnProperty('range')) {
  19        Object.defineProperty(Parser.SyntaxNode.prototype, 'range', {
  20          get() {
  21            return rangeForNode(this);
  22          }
  23        });
  24      }
  25    }
  26  
  27    constructor({ buffer, grammar, config, grammars, syncTimeoutMicros }) {
  28      TreeSitterLanguageMode._patchSyntaxNode();
  29      this.id = nextId++;
  30      this.buffer = buffer;
  31      this.grammar = grammar;
  32      this.config = config;
  33      this.grammarRegistry = grammars;
  34      this.parser = new Parser();
  35      this.rootLanguageLayer = new LanguageLayer(this, grammar, 0);
  36      this.injectionsMarkerLayer = buffer.addMarkerLayer();
  37  
  38      if (syncTimeoutMicros != null) {
  39        this.syncTimeoutMicros = syncTimeoutMicros;
  40      }
  41  
  42      this.rootScopeDescriptor = new ScopeDescriptor({
  43        scopes: [this.grammar.scopeName]
  44      });
  45      this.emitter = new Emitter();
  46      this.isFoldableCache = [];
  47      this.hasQueuedParse = false;
  48  
  49      this.grammarForLanguageString = this.grammarForLanguageString.bind(this);
  50  
  51      this.rootLanguageLayer
  52        .update(null)
  53        .then(() => this.emitter.emit('did-tokenize'));
  54  
  55      // TODO: Remove this once TreeSitterLanguageMode implements its own auto-indentation system. This
  56      // is temporarily needed in order to delegate to the TextMateLanguageMode's auto-indent system.
  57      this.regexesByPattern = {};
  58    }
  59  
  60    async parseCompletePromise() {
  61      let done = false;
  62      while (!done) {
  63        if (this.rootLanguageLayer.currentParsePromise) {
  64          await this.rootLanguageLayer.currentParsePromises;
  65        } else {
  66          done = true;
  67          for (const marker of this.injectionsMarkerLayer.getMarkers()) {
  68            if (marker.languageLayer.currentParsePromise) {
  69              done = false;
  70              await marker.languageLayer.currentParsePromise;
  71              break;
  72            }
  73          }
  74        }
  75        await new Promise(resolve => setTimeout(resolve, 0));
  76      }
  77    }
  78  
  79    destroy() {
  80      this.injectionsMarkerLayer.destroy();
  81      this.rootLanguageLayer = null;
  82      this.parser = null;
  83    }
  84  
  85    getLanguageId() {
  86      return this.grammar.scopeName;
  87    }
  88  
  89    bufferDidChange({ oldRange, newRange, oldText, newText }) {
  90      const edit = this.rootLanguageLayer._treeEditForBufferChange(
  91        oldRange.start,
  92        oldRange.end,
  93        newRange.end,
  94        oldText,
  95        newText
  96      );
  97      this.rootLanguageLayer.handleTextChange(edit, oldText, newText);
  98      for (const marker of this.injectionsMarkerLayer.getMarkers()) {
  99        marker.languageLayer.handleTextChange(edit, oldText, newText);
 100      }
 101    }
 102  
 103    bufferDidFinishTransaction({ changes }) {
 104      for (let i = 0, { length } = changes; i < length; i++) {
 105        const { oldRange, newRange } = changes[i];
 106        spliceArray(
 107          this.isFoldableCache,
 108          newRange.start.row,
 109          oldRange.end.row - oldRange.start.row,
 110          { length: newRange.end.row - newRange.start.row }
 111        );
 112      }
 113      this.rootLanguageLayer.update(null);
 114    }
 115  
 116    parse(language, oldTree, ranges) {
 117      const parser = PARSER_POOL.pop() || new Parser();
 118      parser.setLanguage(language);
 119      const result = parser.parseTextBuffer(this.buffer.buffer, oldTree, {
 120        syncTimeoutMicros: this.syncTimeoutMicros,
 121        includedRanges: ranges
 122      });
 123  
 124      if (result.then) {
 125        return result.then(tree => {
 126          PARSER_POOL.push(parser);
 127          return tree;
 128        });
 129      } else {
 130        PARSER_POOL.push(parser);
 131        return result;
 132      }
 133    }
 134  
 135    get tree() {
 136      return this.rootLanguageLayer.tree;
 137    }
 138  
 139    updateForInjection(grammar) {
 140      this.rootLanguageLayer.updateInjections(grammar);
 141    }
 142  
 143    /*
 144    Section - Highlighting
 145    */
 146  
 147    buildHighlightIterator() {
 148      if (!this.rootLanguageLayer) return new NullHighlightIterator();
 149      return new HighlightIterator(this);
 150    }
 151  
 152    onDidTokenize(callback) {
 153      return this.emitter.on('did-tokenize', callback);
 154    }
 155  
 156    onDidChangeHighlighting(callback) {
 157      return this.emitter.on('did-change-highlighting', callback);
 158    }
 159  
 160    classNameForScopeId(scopeId) {
 161      return this.grammar.classNameForScopeId(scopeId);
 162    }
 163  
 164    /*
 165    Section - Commenting
 166    */
 167  
 168    commentStringsForPosition(position) {
 169      const range =
 170        this.firstNonWhitespaceRange(position.row) ||
 171        new Range(position, position);
 172      const { grammar } = this.getSyntaxNodeAndGrammarContainingRange(range);
 173      return grammar.commentStrings;
 174    }
 175  
 176    isRowCommented(row) {
 177      const range = this.firstNonWhitespaceRange(row);
 178      if (range) {
 179        const firstNode = this.getSyntaxNodeContainingRange(range);
 180        if (firstNode) return firstNode.type.includes('comment');
 181      }
 182      return false;
 183    }
 184  
 185    /*
 186    Section - Indentation
 187    */
 188  
 189    suggestedIndentForLineAtBufferRow(row, line, tabLength) {
 190      return this._suggestedIndentForLineWithScopeAtBufferRow(
 191        row,
 192        line,
 193        this.rootScopeDescriptor,
 194        tabLength
 195      );
 196    }
 197  
 198    suggestedIndentForBufferRow(row, tabLength, options) {
 199      return this._suggestedIndentForLineWithScopeAtBufferRow(
 200        row,
 201        this.buffer.lineForRow(row),
 202        this.rootScopeDescriptor,
 203        tabLength,
 204        options
 205      );
 206    }
 207  
 208    indentLevelForLine(line, tabLength) {
 209      let indentLength = 0;
 210      for (let i = 0, { length } = line; i < length; i++) {
 211        const char = line[i];
 212        if (char === '\t') {
 213          indentLength += tabLength - (indentLength % tabLength);
 214        } else if (char === ' ') {
 215          indentLength++;
 216        } else {
 217          break;
 218        }
 219      }
 220      return indentLength / tabLength;
 221    }
 222  
 223    /*
 224    Section - Folding
 225    */
 226  
 227    isFoldableAtRow(row) {
 228      if (this.isFoldableCache[row] != null) return this.isFoldableCache[row];
 229      const result =
 230        this.getFoldableRangeContainingPoint(Point(row, Infinity), 0, true) !=
 231        null;
 232      this.isFoldableCache[row] = result;
 233      return result;
 234    }
 235  
 236    getFoldableRanges() {
 237      return this.getFoldableRangesAtIndentLevel(null);
 238    }
 239  
 240    /**
 241     * TODO: Make this method generate folds for nested languages (currently,
 242     * folds are only generated for the root language layer).
 243     */
 244    getFoldableRangesAtIndentLevel(goalLevel) {
 245      let result = [];
 246      let stack = [{ node: this.tree.rootNode, level: 0 }];
 247      while (stack.length > 0) {
 248        const { node, level } = stack.pop();
 249  
 250        const range = this.getFoldableRangeForNode(node, this.grammar);
 251        if (range) {
 252          if (goalLevel == null || level === goalLevel) {
 253            let updatedExistingRange = false;
 254            for (let i = 0, { length } = result; i < length; i++) {
 255              if (
 256                result[i].start.row === range.start.row &&
 257                result[i].end.row === range.end.row
 258              ) {
 259                result[i] = range;
 260                updatedExistingRange = true;
 261                break;
 262              }
 263            }
 264            if (!updatedExistingRange) result.push(range);
 265          }
 266        }
 267  
 268        const parentStartRow = node.startPosition.row;
 269        const parentEndRow = node.endPosition.row;
 270        for (
 271          let children = node.namedChildren, i = 0, { length } = children;
 272          i < length;
 273          i++
 274        ) {
 275          const child = children[i];
 276          const { startPosition: childStart, endPosition: childEnd } = child;
 277          if (childEnd.row > childStart.row) {
 278            if (
 279              childStart.row === parentStartRow &&
 280              childEnd.row === parentEndRow
 281            ) {
 282              stack.push({ node: child, level: level });
 283            } else {
 284              const childLevel =
 285                range &&
 286                range.containsPoint(childStart) &&
 287                range.containsPoint(childEnd)
 288                  ? level + 1
 289                  : level;
 290              if (childLevel <= goalLevel || goalLevel == null) {
 291                stack.push({ node: child, level: childLevel });
 292              }
 293            }
 294          }
 295        }
 296      }
 297  
 298      return result.sort((a, b) => a.start.row - b.start.row);
 299    }
 300  
 301    getFoldableRangeContainingPoint(point, tabLength, existenceOnly = false) {
 302      if (!this.tree) return null;
 303  
 304      let smallestRange;
 305      this._forEachTreeWithRange(new Range(point, point), (tree, grammar) => {
 306        let node = tree.rootNode.descendantForPosition(
 307          this.buffer.clipPosition(point)
 308        );
 309        while (node) {
 310          if (existenceOnly && node.startPosition.row < point.row) return;
 311          if (node.endPosition.row > point.row) {
 312            const range = this.getFoldableRangeForNode(node, grammar);
 313            if (range && rangeIsSmaller(range, smallestRange)) {
 314              smallestRange = range;
 315              return;
 316            }
 317          }
 318          node = node.parent;
 319        }
 320      });
 321  
 322      return existenceOnly
 323        ? smallestRange && smallestRange.start.row === point.row
 324        : smallestRange;
 325    }
 326  
 327    _forEachTreeWithRange(range, callback) {
 328      if (this.rootLanguageLayer.tree) {
 329        callback(this.rootLanguageLayer.tree, this.rootLanguageLayer.grammar);
 330      }
 331  
 332      const injectionMarkers = this.injectionsMarkerLayer.findMarkers({
 333        intersectsRange: range
 334      });
 335  
 336      for (const injectionMarker of injectionMarkers) {
 337        const { tree, grammar } = injectionMarker.languageLayer;
 338        if (tree) callback(tree, grammar);
 339      }
 340    }
 341  
 342    getFoldableRangeForNode(node, grammar, existenceOnly) {
 343      const { children } = node;
 344      const childCount = children.length;
 345  
 346      for (var i = 0, { length } = grammar.folds; i < length; i++) {
 347        const foldSpec = grammar.folds[i];
 348  
 349        if (foldSpec.matchers && !hasMatchingFoldSpec(foldSpec.matchers, node))
 350          continue;
 351  
 352        let foldStart;
 353        const startEntry = foldSpec.start;
 354        if (startEntry) {
 355          let foldStartNode;
 356          if (startEntry.index != null) {
 357            foldStartNode = children[startEntry.index];
 358            if (
 359              !foldStartNode ||
 360              (startEntry.matchers &&
 361                !hasMatchingFoldSpec(startEntry.matchers, foldStartNode))
 362            )
 363              continue;
 364          } else {
 365            foldStartNode = children.find(child =>
 366              hasMatchingFoldSpec(startEntry.matchers, child)
 367            );
 368            if (!foldStartNode) continue;
 369          }
 370          foldStart = new Point(foldStartNode.endPosition.row, Infinity);
 371        } else {
 372          foldStart = new Point(node.startPosition.row, Infinity);
 373        }
 374  
 375        let foldEnd;
 376        const endEntry = foldSpec.end;
 377        if (endEntry) {
 378          let foldEndNode;
 379          if (endEntry.index != null) {
 380            const index =
 381              endEntry.index < 0 ? childCount + endEntry.index : endEntry.index;
 382            foldEndNode = children[index];
 383            if (
 384              !foldEndNode ||
 385              (endEntry.type && endEntry.type !== foldEndNode.type)
 386            )
 387              continue;
 388          } else {
 389            foldEndNode = children.find(child =>
 390              hasMatchingFoldSpec(endEntry.matchers, child)
 391            );
 392            if (!foldEndNode) continue;
 393          }
 394  
 395          if (foldEndNode.startPosition.row <= foldStart.row) continue;
 396  
 397          foldEnd = foldEndNode.startPosition;
 398          if (
 399            this.buffer.findInRangeSync(
 400              WORD_REGEX,
 401              new Range(foldEnd, new Point(foldEnd.row, Infinity))
 402            )
 403          ) {
 404            foldEnd = new Point(foldEnd.row - 1, Infinity);
 405          }
 406        } else {
 407          const { endPosition } = node;
 408          if (endPosition.column === 0) {
 409            foldEnd = Point(endPosition.row - 1, Infinity);
 410          } else if (childCount > 0) {
 411            foldEnd = endPosition;
 412          } else {
 413            foldEnd = Point(endPosition.row, 0);
 414          }
 415        }
 416  
 417        return existenceOnly ? true : new Range(foldStart, foldEnd);
 418      }
 419    }
 420  
 421    /*
 422    Section - Syntax Tree APIs
 423    */
 424  
 425    getSyntaxNodeContainingRange(range, where = _ => true) {
 426      return this.getSyntaxNodeAndGrammarContainingRange(range, where).node;
 427    }
 428  
 429    getSyntaxNodeAndGrammarContainingRange(range, where = _ => true) {
 430      const startIndex = this.buffer.characterIndexForPosition(range.start);
 431      const endIndex = this.buffer.characterIndexForPosition(range.end);
 432      const searchEndIndex = Math.max(0, endIndex - 1);
 433  
 434      let smallestNode = null;
 435      let smallestNodeGrammar = this.grammar;
 436      this._forEachTreeWithRange(range, (tree, grammar) => {
 437        let node = tree.rootNode.descendantForIndex(startIndex, searchEndIndex);
 438        while (node) {
 439          if (
 440            nodeContainsIndices(node, startIndex, endIndex) &&
 441            where(node, grammar)
 442          ) {
 443            if (nodeIsSmaller(node, smallestNode)) {
 444              smallestNode = node;
 445              smallestNodeGrammar = grammar;
 446            }
 447            break;
 448          }
 449          node = node.parent;
 450        }
 451      });
 452  
 453      return { node: smallestNode, grammar: smallestNodeGrammar };
 454    }
 455  
 456    getRangeForSyntaxNodeContainingRange(range, where) {
 457      const node = this.getSyntaxNodeContainingRange(range, where);
 458      return node && node.range;
 459    }
 460  
 461    getSyntaxNodeAtPosition(position, where) {
 462      return this.getSyntaxNodeContainingRange(
 463        new Range(position, position),
 464        where
 465      );
 466    }
 467  
 468    bufferRangeForScopeAtPosition(selector, position) {
 469      const nodeCursorAdapter = new NodeCursorAdaptor();
 470      if (typeof selector === 'string') {
 471        const match = matcherForSelector(selector);
 472        selector = (node, grammar) => {
 473          const rules = grammar.scopeMap.get([node.type], [0], node.named);
 474          nodeCursorAdapter.node = node;
 475          const scopeName = applyLeafRules(rules, nodeCursorAdapter);
 476          if (scopeName != null) {
 477            return match(scopeName);
 478          }
 479        };
 480      }
 481      if (selector === null) selector = undefined;
 482      const node = this.getSyntaxNodeAtPosition(position, selector);
 483      return node && node.range;
 484    }
 485  
 486    /*
 487    Section - Backward compatibility shims
 488    */
 489  
 490    tokenizedLineForRow(row) {
 491      const lineText = this.buffer.lineForRow(row);
 492      const tokens = [];
 493  
 494      const iterator = this.buildHighlightIterator();
 495      let start = { row, column: 0 };
 496      const scopes = iterator.seek(start, row);
 497      while (true) {
 498        const end = iterator.getPosition();
 499        if (end.row > row) {
 500          end.row = row;
 501          end.column = lineText.length;
 502        }
 503  
 504        if (end.column > start.column) {
 505          tokens.push(
 506            new Token({
 507              value: lineText.substring(start.column, end.column),
 508              scopes: scopes.map(s => this.grammar.scopeNameForScopeId(s))
 509            })
 510          );
 511        }
 512  
 513        if (end.column < lineText.length) {
 514          const closeScopeCount = iterator.getCloseScopeIds().length;
 515          for (let i = 0; i < closeScopeCount; i++) {
 516            scopes.pop();
 517          }
 518          scopes.push(...iterator.getOpenScopeIds());
 519          start = end;
 520          iterator.moveToSuccessor();
 521        } else {
 522          break;
 523        }
 524      }
 525  
 526      return new TokenizedLine({
 527        openScopes: [],
 528        text: lineText,
 529        tokens,
 530        tags: [],
 531        ruleStack: [],
 532        lineEnding: this.buffer.lineEndingForRow(row),
 533        tokenIterator: null,
 534        grammar: this.grammar
 535      });
 536    }
 537  
 538    syntaxTreeScopeDescriptorForPosition(point) {
 539      const nodes = [];
 540      point = this.buffer.clipPosition(Point.fromObject(point));
 541  
 542      // If the position is the end of a line, get node of left character instead of newline
 543      // This is to match TextMate behaviour, see https://github.com/atom/atom/issues/18463
 544      if (
 545        point.column > 0 &&
 546        point.column === this.buffer.lineLengthForRow(point.row)
 547      ) {
 548        point = point.copy();
 549        point.column--;
 550      }
 551  
 552      this._forEachTreeWithRange(new Range(point, point), tree => {
 553        let node = tree.rootNode.descendantForPosition(point);
 554        while (node) {
 555          nodes.push(node);
 556          node = node.parent;
 557        }
 558      });
 559  
 560      // The nodes are mostly already sorted from smallest to largest,
 561      // but for files with multiple syntax trees (e.g. ERB), each tree's
 562      // nodes are separate. Sort the nodes from largest to smallest.
 563      nodes.reverse();
 564      nodes.sort(
 565        (a, b) => a.startIndex - b.startIndex || b.endIndex - a.endIndex
 566      );
 567  
 568      const nodeTypes = nodes.map(node => node.type);
 569      nodeTypes.unshift(this.grammar.scopeName);
 570      return new ScopeDescriptor({ scopes: nodeTypes });
 571    }
 572  
 573    scopeDescriptorForPosition(point) {
 574      point = this.buffer.clipPosition(Point.fromObject(point));
 575  
 576      // If the position is the end of a line, get scope of left character instead of newline
 577      // This is to match TextMate behaviour, see https://github.com/atom/atom/issues/18463
 578      if (
 579        point.column > 0 &&
 580        point.column === this.buffer.lineLengthForRow(point.row)
 581      ) {
 582        point = point.copy();
 583        point.column--;
 584      }
 585  
 586      const iterator = this.buildHighlightIterator();
 587      const scopes = [];
 588      for (const scope of iterator.seek(point, point.row + 1)) {
 589        scopes.push(this.grammar.scopeNameForScopeId(scope));
 590      }
 591      if (point.isEqual(iterator.getPosition())) {
 592        for (const scope of iterator.getOpenScopeIds()) {
 593          scopes.push(this.grammar.scopeNameForScopeId(scope));
 594        }
 595      }
 596      if (scopes.length === 0 || scopes[0] !== this.grammar.scopeName) {
 597        scopes.unshift(this.grammar.scopeName);
 598      }
 599      return new ScopeDescriptor({ scopes });
 600    }
 601  
 602    tokenForPosition(point) {
 603      const node = this.getSyntaxNodeAtPosition(point);
 604      const scopes = this.scopeDescriptorForPosition(point).getScopesArray();
 605      return new Token({ value: node.text, scopes });
 606    }
 607  
 608    getGrammar() {
 609      return this.grammar;
 610    }
 611  
 612    /*
 613    Section - Private
 614    */
 615  
 616    firstNonWhitespaceRange(row) {
 617      return this.buffer.findInRangeSync(
 618        /\S/,
 619        new Range(new Point(row, 0), new Point(row, Infinity))
 620      );
 621    }
 622  
 623    grammarForLanguageString(languageString) {
 624      return this.grammarRegistry.treeSitterGrammarForLanguageString(
 625        languageString
 626      );
 627    }
 628  
 629    emitRangeUpdate(range) {
 630      const startRow = range.start.row;
 631      const endRow = range.end.row;
 632      for (let row = startRow; row < endRow; row++) {
 633        this.isFoldableCache[row] = undefined;
 634      }
 635      this.emitter.emit('did-change-highlighting', range);
 636    }
 637  }
 638  
 639  class LanguageLayer {
 640    constructor(languageMode, grammar, depth) {
 641      this.languageMode = languageMode;
 642      this.grammar = grammar;
 643      this.tree = null;
 644      this.currentParsePromise = null;
 645      this.patchSinceCurrentParseStarted = null;
 646      this.depth = depth;
 647    }
 648  
 649    buildHighlightIterator() {
 650      if (this.tree) {
 651        return new LayerHighlightIterator(this, this.tree.walk());
 652      } else {
 653        return new NullHighlightIterator();
 654      }
 655    }
 656  
 657    handleTextChange(edit, oldText, newText) {
 658      const { startPosition, oldEndPosition, newEndPosition } = edit;
 659  
 660      if (this.tree) {
 661        this.tree.edit(edit);
 662        if (this.editedRange) {
 663          if (startPosition.isLessThan(this.editedRange.start)) {
 664            this.editedRange.start = startPosition;
 665          }
 666          if (oldEndPosition.isLessThan(this.editedRange.end)) {
 667            this.editedRange.end = newEndPosition.traverse(
 668              this.editedRange.end.traversalFrom(oldEndPosition)
 669            );
 670          } else {
 671            this.editedRange.end = newEndPosition;
 672          }
 673        } else {
 674          this.editedRange = new Range(startPosition, newEndPosition);
 675        }
 676      }
 677  
 678      if (this.patchSinceCurrentParseStarted) {
 679        this.patchSinceCurrentParseStarted.splice(
 680          startPosition,
 681          oldEndPosition.traversalFrom(startPosition),
 682          newEndPosition.traversalFrom(startPosition),
 683          oldText,
 684          newText
 685        );
 686      }
 687    }
 688  
 689    destroy() {
 690      for (const marker of this.languageMode.injectionsMarkerLayer.getMarkers()) {
 691        if (marker.parentLanguageLayer === this) {
 692          marker.languageLayer.destroy();
 693          marker.destroy();
 694        }
 695      }
 696    }
 697  
 698    async update(nodeRangeSet) {
 699      if (!this.currentParsePromise) {
 700        while (
 701          !this.destroyed &&
 702          (!this.tree || this.tree.rootNode.hasChanges())
 703        ) {
 704          const params = { async: false };
 705          this.currentParsePromise = this._performUpdate(nodeRangeSet, params);
 706          if (!params.async) break;
 707          await this.currentParsePromise;
 708        }
 709        this.currentParsePromise = null;
 710      }
 711    }
 712  
 713    updateInjections(grammar) {
 714      if (grammar.injectionRegex) {
 715        if (!this.currentParsePromise)
 716          this.currentParsePromise = Promise.resolve();
 717        this.currentParsePromise = this.currentParsePromise.then(async () => {
 718          await this._populateInjections(MAX_RANGE, null);
 719          this.currentParsePromise = null;
 720        });
 721      }
 722    }
 723  
 724    async _performUpdate(nodeRangeSet, params) {
 725      let includedRanges = null;
 726      if (nodeRangeSet) {
 727        includedRanges = nodeRangeSet.getRanges(this.languageMode.buffer);
 728        if (includedRanges.length === 0) {
 729          this.tree = null;
 730          this.destroyed = true;
 731          return;
 732        }
 733      }
 734  
 735      let affectedRange = this.editedRange;
 736      this.editedRange = null;
 737  
 738      this.patchSinceCurrentParseStarted = new Patch();
 739      let tree = this.languageMode.parse(
 740        this.grammar.languageModule,
 741        this.tree,
 742        includedRanges
 743      );
 744      if (tree.then) {
 745        params.async = true;
 746        tree = await tree;
 747      }
 748  
 749      const changes = this.patchSinceCurrentParseStarted.getChanges();
 750      this.patchSinceCurrentParseStarted = null;
 751      for (const {
 752        oldStart,
 753        newStart,
 754        oldEnd,
 755        newEnd,
 756        oldText,
 757        newText
 758      } of changes) {
 759        const newExtent = Point.fromObject(newEnd).traversalFrom(newStart);
 760        tree.edit(
 761          this._treeEditForBufferChange(
 762            newStart,
 763            oldEnd,
 764            Point.fromObject(oldStart).traverse(newExtent),
 765            oldText,
 766            newText
 767          )
 768        );
 769      }
 770  
 771      if (this.tree) {
 772        const rangesWithSyntaxChanges = this.tree.getChangedRanges(tree);
 773        this.tree = tree;
 774  
 775        if (rangesWithSyntaxChanges.length > 0) {
 776          for (const range of rangesWithSyntaxChanges) {
 777            this.languageMode.emitRangeUpdate(rangeForNode(range));
 778          }
 779  
 780          const combinedRangeWithSyntaxChange = new Range(
 781            rangesWithSyntaxChanges[0].startPosition,
 782            last(rangesWithSyntaxChanges).endPosition
 783          );
 784  
 785          if (affectedRange) {
 786            this.languageMode.emitRangeUpdate(affectedRange);
 787            affectedRange = affectedRange.union(combinedRangeWithSyntaxChange);
 788          } else {
 789            affectedRange = combinedRangeWithSyntaxChange;
 790          }
 791        }
 792      } else {
 793        this.tree = tree;
 794        this.languageMode.emitRangeUpdate(rangeForNode(tree.rootNode));
 795        if (includedRanges) {
 796          affectedRange = new Range(
 797            includedRanges[0].startPosition,
 798            last(includedRanges).endPosition
 799          );
 800        } else {
 801          affectedRange = MAX_RANGE;
 802        }
 803      }
 804  
 805      if (affectedRange) {
 806        const injectionPromise = this._populateInjections(
 807          affectedRange,
 808          nodeRangeSet
 809        );
 810        if (injectionPromise) {
 811          params.async = true;
 812          return injectionPromise;
 813        }
 814      }
 815    }
 816  
 817    _populateInjections(range, nodeRangeSet) {
 818      const existingInjectionMarkers = this.languageMode.injectionsMarkerLayer
 819        .findMarkers({ intersectsRange: range })
 820        .filter(marker => marker.parentLanguageLayer === this);
 821  
 822      if (existingInjectionMarkers.length > 0) {
 823        range = range.union(
 824          new Range(
 825            existingInjectionMarkers[0].getRange().start,
 826            last(existingInjectionMarkers).getRange().end
 827          )
 828        );
 829      }
 830  
 831      const markersToUpdate = new Map();
 832      const nodes = this.tree.rootNode.descendantsOfType(
 833        Object.keys(this.grammar.injectionPointsByType),
 834        range.start,
 835        range.end
 836      );
 837  
 838      let existingInjectionMarkerIndex = 0;
 839      for (const node of nodes) {
 840        for (const injectionPoint of this.grammar.injectionPointsByType[
 841          node.type
 842        ]) {
 843          const languageName = injectionPoint.language(node);
 844          if (!languageName) continue;
 845  
 846          const grammar = this.languageMode.grammarForLanguageString(
 847            languageName
 848          );
 849          if (!grammar) continue;
 850  
 851          const contentNodes = injectionPoint.content(node);
 852          if (!contentNodes) continue;
 853  
 854          const injectionNodes = [].concat(contentNodes);
 855          if (!injectionNodes.length) continue;
 856  
 857          const injectionRange = rangeForNode(node);
 858  
 859          let marker;
 860          for (
 861            let i = existingInjectionMarkerIndex,
 862              n = existingInjectionMarkers.length;
 863            i < n;
 864            i++
 865          ) {
 866            const existingMarker = existingInjectionMarkers[i];
 867            const comparison = existingMarker.getRange().compare(injectionRange);
 868            if (comparison > 0) {
 869              break;
 870            } else if (comparison === 0) {
 871              existingInjectionMarkerIndex = i;
 872              if (existingMarker.languageLayer.grammar === grammar) {
 873                marker = existingMarker;
 874                break;
 875              }
 876            } else {
 877              existingInjectionMarkerIndex = i;
 878            }
 879          }
 880  
 881          if (!marker) {
 882            marker = this.languageMode.injectionsMarkerLayer.markRange(
 883              injectionRange
 884            );
 885            marker.languageLayer = new LanguageLayer(
 886              this.languageMode,
 887              grammar,
 888              this.depth + 1
 889            );
 890            marker.parentLanguageLayer = this;
 891          }
 892  
 893          markersToUpdate.set(
 894            marker,
 895            new NodeRangeSet(
 896              nodeRangeSet,
 897              injectionNodes,
 898              injectionPoint.newlinesBetween,
 899              injectionPoint.includeChildren
 900            )
 901          );
 902        }
 903      }
 904  
 905      for (const marker of existingInjectionMarkers) {
 906        if (!markersToUpdate.has(marker)) {
 907          marker.languageLayer.destroy();
 908          this.languageMode.emitRangeUpdate(marker.getRange());
 909          marker.destroy();
 910        }
 911      }
 912  
 913      if (markersToUpdate.size > 0) {
 914        const promises = [];
 915        for (const [marker, nodeRangeSet] of markersToUpdate) {
 916          promises.push(marker.languageLayer.update(nodeRangeSet));
 917        }
 918        return Promise.all(promises);
 919      }
 920    }
 921  
 922    _treeEditForBufferChange(start, oldEnd, newEnd, oldText, newText) {
 923      const startIndex = this.languageMode.buffer.characterIndexForPosition(
 924        start
 925      );
 926      return {
 927        startIndex,
 928        oldEndIndex: startIndex + oldText.length,
 929        newEndIndex: startIndex + newText.length,
 930        startPosition: start,
 931        oldEndPosition: oldEnd,
 932        newEndPosition: newEnd
 933      };
 934    }
 935  }
 936  
 937  class HighlightIterator {
 938    constructor(languageMode) {
 939      this.languageMode = languageMode;
 940      this.iterators = null;
 941    }
 942  
 943    seek(targetPosition, endRow) {
 944      const injectionMarkers = this.languageMode.injectionsMarkerLayer.findMarkers(
 945        {
 946          intersectsRange: new Range(targetPosition, new Point(endRow + 1, 0))
 947        }
 948      );
 949  
 950      const containingTags = [];
 951      const containingTagStartIndices = [];
 952      const targetIndex = this.languageMode.buffer.characterIndexForPosition(
 953        targetPosition
 954      );
 955  
 956      this.iterators = [];
 957      const iterator = this.languageMode.rootLanguageLayer.buildHighlightIterator();
 958      if (iterator.seek(targetIndex, containingTags, containingTagStartIndices)) {
 959        this.iterators.push(iterator);
 960      }
 961  
 962      // Populate the iterators array with all of the iterators whose syntax
 963      // trees span the given position.
 964      for (const marker of injectionMarkers) {
 965        const iterator = marker.languageLayer.buildHighlightIterator();
 966        if (
 967          iterator.seek(targetIndex, containingTags, containingTagStartIndices)
 968        ) {
 969          this.iterators.push(iterator);
 970        }
 971      }
 972  
 973      // Sort the iterators so that the last one in the array is the earliest
 974      // in the document, and represents the current position.
 975      this.iterators.sort((a, b) => b.compare(a));
 976      this.detectCoveredScope();
 977  
 978      return containingTags;
 979    }
 980  
 981    moveToSuccessor() {
 982      // Advance the earliest layer iterator to its next scope boundary.
 983      let leader = last(this.iterators);
 984  
 985      // Maintain the sorting of the iterators by their position in the document.
 986      if (leader.moveToSuccessor()) {
 987        const leaderIndex = this.iterators.length - 1;
 988        let i = leaderIndex;
 989        while (i > 0 && this.iterators[i - 1].compare(leader) < 0) i--;
 990        if (i < leaderIndex) {
 991          this.iterators.splice(i, 0, this.iterators.pop());
 992        }
 993      } else {
 994        // If the layer iterator was at the end of its syntax tree, then remove
 995        // it from the array.
 996        this.iterators.pop();
 997      }
 998  
 999      this.detectCoveredScope();
1000    }
1001  
1002    // Detect whether or not another more deeply-nested language layer has a
1003    // scope boundary at this same position. If so, the current language layer's
1004    // scope boundary should not be reported.
1005    detectCoveredScope() {
1006      const layerCount = this.iterators.length;
1007      if (layerCount > 1) {
1008        const first = this.iterators[layerCount - 1];
1009        const next = this.iterators[layerCount - 2];
1010        if (
1011          next.offset === first.offset &&
1012          next.atEnd === first.atEnd &&
1013          next.depth > first.depth &&
1014          !next.isAtInjectionBoundary()
1015        ) {
1016          this.currentScopeIsCovered = true;
1017          return;
1018        }
1019      }
1020      this.currentScopeIsCovered = false;
1021    }
1022  
1023    getPosition() {
1024      const iterator = last(this.iterators);
1025      if (iterator) {
1026        return iterator.getPosition();
1027      } else {
1028        return Point.INFINITY;
1029      }
1030    }
1031  
1032    getCloseScopeIds() {
1033      const iterator = last(this.iterators);
1034      if (iterator && !this.currentScopeIsCovered) {
1035        return iterator.getCloseScopeIds();
1036      }
1037      return [];
1038    }
1039  
1040    getOpenScopeIds() {
1041      const iterator = last(this.iterators);
1042      if (iterator && !this.currentScopeIsCovered) {
1043        return iterator.getOpenScopeIds();
1044      }
1045      return [];
1046    }
1047  
1048    logState() {
1049      const iterator = last(this.iterators);
1050      if (iterator && iterator.treeCursor) {
1051        console.log(
1052          iterator.getPosition(),
1053          iterator.treeCursor.nodeType,
1054          `depth=${iterator.languageLayer.depth}`,
1055          new Range(
1056            iterator.languageLayer.tree.rootNode.startPosition,
1057            iterator.languageLayer.tree.rootNode.endPosition
1058          ).toString()
1059        );
1060        if (this.currentScopeIsCovered) {
1061          console.log('covered');
1062        } else {
1063          console.log(
1064            'close',
1065            iterator.closeTags.map(id =>
1066              this.languageMode.grammar.scopeNameForScopeId(id)
1067            )
1068          );
1069          console.log(
1070            'open',
1071            iterator.openTags.map(id =>
1072              this.languageMode.grammar.scopeNameForScopeId(id)
1073            )
1074          );
1075        }
1076      }
1077    }
1078  }
1079  
1080  class LayerHighlightIterator {
1081    constructor(languageLayer, treeCursor) {
1082      this.languageLayer = languageLayer;
1083      this.depth = this.languageLayer.depth;
1084  
1085      // The iterator is always positioned at either the start or the end of some node
1086      // in the syntax tree.
1087      this.atEnd = false;
1088      this.treeCursor = treeCursor;
1089      this.offset = 0;
1090  
1091      // In order to determine which selectors match its current node, the iterator maintains
1092      // a list of the current node's ancestors. Because the selectors can use the `:nth-child`
1093      // pseudo-class, each node's child index is also stored.
1094      this.containingNodeTypes = [];
1095      this.containingNodeChildIndices = [];
1096      this.containingNodeEndIndices = [];
1097  
1098      // At any given position, the iterator exposes the list of class names that should be
1099      // *ended* at its current position and the list of class names that should be *started*
1100      // at its current position.
1101      this.closeTags = [];
1102      this.openTags = [];
1103    }
1104  
1105    seek(targetIndex, containingTags, containingTagStartIndices) {
1106      while (this.treeCursor.gotoParent()) {}
1107  
1108      this.atEnd = true;
1109      this.closeTags.length = 0;
1110      this.openTags.length = 0;
1111      this.containingNodeTypes.length = 0;
1112      this.containingNodeChildIndices.length = 0;
1113      this.containingNodeEndIndices.length = 0;
1114  
1115      const containingTagEndIndices = [];
1116  
1117      if (targetIndex >= this.treeCursor.endIndex) {
1118        return false;
1119      }
1120  
1121      let childIndex = -1;
1122      for (;;) {
1123        this.containingNodeTypes.push(this.treeCursor.nodeType);
1124        this.containingNodeChildIndices.push(childIndex);
1125        this.containingNodeEndIndices.push(this.treeCursor.endIndex);
1126  
1127        const scopeId = this._currentScopeId();
1128        if (scopeId) {
1129          if (this.treeCursor.startIndex < targetIndex) {
1130            insertContainingTag(
1131              scopeId,
1132              this.treeCursor.startIndex,
1133              containingTags,
1134              containingTagStartIndices
1135            );
1136            containingTagEndIndices.push(this.treeCursor.endIndex);
1137          } else {
1138            this.atEnd = false;
1139            this.openTags.push(scopeId);
1140            this._moveDown();
1141            break;
1142          }
1143        }
1144  
1145        childIndex = this.treeCursor.gotoFirstChildForIndex(targetIndex);
1146        if (childIndex === null) break;
1147        if (this.treeCursor.startIndex >= targetIndex) this.atEnd = false;
1148      }
1149  
1150      if (this.atEnd) {
1151        this.offset = this.treeCursor.endIndex;
1152        for (let i = 0, { length } = containingTags; i < length; i++) {
1153          if (containingTagEndIndices[i] === this.offset) {
1154            this.closeTags.push(containingTags[i]);
1155          }
1156        }
1157      } else {
1158        this.offset = this.treeCursor.startIndex;
1159      }
1160  
1161      return true;
1162    }
1163  
1164    moveToSuccessor() {
1165      this.closeTags.length = 0;
1166      this.openTags.length = 0;
1167  
1168      while (!this.closeTags.length && !this.openTags.length) {
1169        if (this.atEnd) {
1170          if (this._moveRight()) {
1171            const scopeId = this._currentScopeId();
1172            if (scopeId) this.openTags.push(scopeId);
1173            this.atEnd = false;
1174            this._moveDown();
1175          } else if (this._moveUp(true)) {
1176            this.atEnd = true;
1177          } else {
1178            return false;
1179          }
1180        } else if (!this._moveDown()) {
1181          const scopeId = this._currentScopeId();
1182          if (scopeId) this.closeTags.push(scopeId);
1183          this.atEnd = true;
1184          this._moveUp(false);
1185        }
1186      }
1187  
1188      if (this.atEnd) {
1189        this.offset = this.treeCursor.endIndex;
1190      } else {
1191        this.offset = this.treeCursor.startIndex;
1192      }
1193  
1194      return true;
1195    }
1196  
1197    getPosition() {
1198      if (this.atEnd) {
1199        return this.treeCursor.endPosition;
1200      } else {
1201        return this.treeCursor.startPosition;
1202      }
1203    }
1204  
1205    compare(other) {
1206      const result = this.offset - other.offset;
1207      if (result !== 0) return result;
1208      if (this.atEnd && !other.atEnd) return -1;
1209      if (other.atEnd && !this.atEnd) return 1;
1210      return this.languageLayer.depth - other.languageLayer.depth;
1211    }
1212  
1213    getCloseScopeIds() {
1214      return this.closeTags.slice();
1215    }
1216  
1217    getOpenScopeIds() {
1218      return this.openTags.slice();
1219    }
1220  
1221    isAtInjectionBoundary() {
1222      return this.containingNodeTypes.length === 1;
1223    }
1224  
1225    // Private methods
1226  
1227    _moveUp(atLastChild) {
1228      let result = false;
1229      const { endIndex } = this.treeCursor;
1230      let depth = this.containingNodeEndIndices.length;
1231  
1232      // The iterator should not move up until it has visited all of the children of this node.
1233      while (
1234        depth > 1 &&
1235        (atLastChild || this.containingNodeEndIndices[depth - 2] === endIndex)
1236      ) {
1237        atLastChild = false;
1238        result = true;
1239        this.treeCursor.gotoParent();
1240        this.containingNodeTypes.pop();
1241        this.containingNodeChildIndices.pop();
1242        this.containingNodeEndIndices.pop();
1243        --depth;
1244        const scopeId = this._currentScopeId();
1245        if (scopeId) this.closeTags.push(scopeId);
1246      }
1247      return result;
1248    }
1249  
1250    _moveDown() {
1251      let result = false;
1252      const { startIndex } = this.treeCursor;
1253  
1254      // Once the iterator has found a scope boundary, it needs to stay at the same
1255      // position, so it should not move down if the first child node starts later than the
1256      // current node.
1257      while (this.treeCursor.gotoFirstChild()) {
1258        if (
1259          (this.closeTags.length || this.openTags.length) &&
1260          this.treeCursor.startIndex > startIndex
1261        ) {
1262          this.treeCursor.gotoParent();
1263          break;
1264        }
1265  
1266        result = true;
1267        this.containingNodeTypes.push(this.treeCursor.nodeType);
1268        this.containingNodeChildIndices.push(0);
1269        this.containingNodeEndIndices.push(this.treeCursor.endIndex);
1270  
1271        const scopeId = this._currentScopeId();
1272        if (scopeId) this.openTags.push(scopeId);
1273      }
1274  
1275      return result;
1276    }
1277  
1278    _moveRight() {
1279      if (this.treeCursor.gotoNextSibling()) {
1280        const depth = this.containingNodeTypes.length;
1281        this.containingNodeTypes[depth - 1] = this.treeCursor.nodeType;
1282        this.containingNodeChildIndices[depth - 1]++;
1283        this.containingNodeEndIndices[depth - 1] = this.treeCursor.endIndex;
1284        return true;
1285      }
1286    }
1287  
1288    _currentScopeId() {
1289      const value = this.languageLayer.grammar.scopeMap.get(
1290        this.containingNodeTypes,
1291        this.containingNodeChildIndices,
1292        this.treeCursor.nodeIsNamed
1293      );
1294      const scopeName = applyLeafRules(value, this.treeCursor);
1295      if (scopeName) {
1296        return this.languageLayer.languageMode.grammar.idForScope(scopeName);
1297      }
1298    }
1299  }
1300  
1301  const applyLeafRules = (rules, cursor) => {
1302    if (!rules || typeof rules === 'string') return rules;
1303    if (Array.isArray(rules)) {
1304      for (let i = 0, { length } = rules; i !== length; ++i) {
1305        const result = applyLeafRules(rules[i], cursor);
1306        if (result) return result;
1307      }
1308      return undefined;
1309    }
1310    if (typeof rules === 'object') {
1311      if (rules.exact) {
1312        return cursor.nodeText === rules.exact
1313          ? applyLeafRules(rules.scopes, cursor)
1314          : undefined;
1315      }
1316      if (rules.match) {
1317        return rules.match.test(cursor.nodeText)
1318          ? applyLeafRules(rules.scopes, cursor)
1319          : undefined;
1320      }
1321    }
1322  };
1323  
1324  class NodeCursorAdaptor {
1325    get nodeText() {
1326      return this.node.text;
1327    }
1328  }
1329  
1330  class NullHighlightIterator {
1331    seek() {
1332      return [];
1333    }
1334    compare() {
1335      return 1;
1336    }
1337    moveToSuccessor() {}
1338    getPosition() {
1339      return Point.INFINITY;
1340    }
1341    getOpenScopeIds() {
1342      return [];
1343    }
1344    getCloseScopeIds() {
1345      return [];
1346    }
1347  }
1348  
1349  class NodeRangeSet {
1350    constructor(previous, nodes, newlinesBetween, includeChildren) {
1351      this.previous = previous;
1352      this.nodes = nodes;
1353      this.newlinesBetween = newlinesBetween;
1354      this.includeChildren = includeChildren;
1355    }
1356  
1357    getRanges(buffer) {
1358      const previousRanges = this.previous && this.previous.getRanges(buffer);
1359      const result = [];
1360  
1361      for (const node of this.nodes) {
1362        let position = node.startPosition;
1363        let index = node.startIndex;
1364  
1365        if (!this.includeChildren) {
1366          for (const child of node.children) {
1367            const nextIndex = child.startIndex;
1368            if (nextIndex > index) {
1369              this._pushRange(buffer, previousRanges, result, {
1370                startIndex: index,
1371                endIndex: nextIndex,
1372                startPosition: position,
1373                endPosition: child.startPosition
1374              });
1375            }
1376            position = child.endPosition;
1377            index = child.endIndex;
1378          }
1379        }
1380  
1381        if (node.endIndex > index) {
1382          this._pushRange(buffer, previousRanges, result, {
1383            startIndex: index,
1384            endIndex: node.endIndex,
1385            startPosition: position,
1386            endPosition: node.endPosition
1387          });
1388        }
1389      }
1390  
1391      return result;
1392    }
1393  
1394    _pushRange(buffer, previousRanges, newRanges, newRange) {
1395      if (!previousRanges) {
1396        if (this.newlinesBetween) {
1397          const { startIndex, startPosition } = newRange;
1398          this._ensureNewline(buffer, newRanges, startIndex, startPosition);
1399        }
1400        newRanges.push(newRange);
1401        return;
1402      }
1403  
1404      for (const previousRange of previousRanges) {
1405        if (previousRange.endIndex <= newRange.startIndex) continue;
1406        if (previousRange.startIndex >= newRange.endIndex) break;
1407        const startIndex = Math.max(
1408          previousRange.startIndex,
1409          newRange.startIndex
1410        );
1411        const endIndex = Math.min(previousRange.endIndex, newRange.endIndex);
1412        const startPosition = Point.max(
1413          previousRange.startPosition,
1414          newRange.startPosition
1415        );
1416        const endPosition = Point.min(
1417          previousRange.endPosition,
1418          newRange.endPosition
1419        );
1420        if (this.newlinesBetween) {
1421          this._ensureNewline(buffer, newRanges, startIndex, startPosition);
1422        }
1423        newRanges.push({ startIndex, endIndex, startPosition, endPosition });
1424      }
1425    }
1426  
1427    // For injection points with `newlinesBetween` enabled, ensure that a
1428    // newline is included between each disjoint range.
1429    _ensureNewline(buffer, newRanges, startIndex, startPosition) {
1430      const lastRange = newRanges[newRanges.length - 1];
1431      if (lastRange && lastRange.endPosition.row < startPosition.row) {
1432        newRanges.push({
1433          startPosition: new Point(
1434            startPosition.row - 1,
1435            buffer.lineLengthForRow(startPosition.row - 1)
1436          ),
1437          endPosition: new Point(startPosition.row, 0),
1438          startIndex: startIndex - startPosition.column - 1,
1439          endIndex: startIndex - startPosition.column
1440        });
1441      }
1442    }
1443  }
1444  
1445  function insertContainingTag(tag, index, tags, indices) {
1446    const i = indices.findIndex(existingIndex => existingIndex > index);
1447    if (i === -1) {
1448      tags.push(tag);
1449      indices.push(index);
1450    } else {
1451      tags.splice(i, 0, tag);
1452      indices.splice(i, 0, index);
1453    }
1454  }
1455  
1456  // Return true iff `mouse` is smaller than `house`. Only correct if
1457  // mouse and house overlap.
1458  //
1459  // * `mouse` {Range}
1460  // * `house` {Range}
1461  function rangeIsSmaller(mouse, house) {
1462    if (!house) return true;
1463    const mvec = vecFromRange(mouse);
1464    const hvec = vecFromRange(house);
1465    return Point.min(mvec, hvec) === mvec;
1466  }
1467  
1468  function vecFromRange({ start, end }) {
1469    return end.translate(start.negate());
1470  }
1471  
1472  function rangeForNode(node) {
1473    return new Range(node.startPosition, node.endPosition);
1474  }
1475  
1476  function nodeContainsIndices(node, start, end) {
1477    if (node.startIndex < start) return node.endIndex >= end;
1478    if (node.startIndex === start) return node.endIndex > end;
1479    return false;
1480  }
1481  
1482  function nodeIsSmaller(left, right) {
1483    if (!left) return false;
1484    if (!right) return true;
1485    return left.endIndex - left.startIndex < right.endIndex - right.startIndex;
1486  }
1487  
1488  function last(array) {
1489    return array[array.length - 1];
1490  }
1491  
1492  function hasMatchingFoldSpec(specs, node) {
1493    return specs.some(
1494      ({ type, named }) => type === node.type && named === node.isNamed
1495    );
1496  }
1497  
1498  // TODO: Remove this once TreeSitterLanguageMode implements its own auto-indent system.
1499  [
1500    '_suggestedIndentForLineWithScopeAtBufferRow',
1501    'suggestedIndentForEditedBufferRow',
1502    'increaseIndentRegexForScopeDescriptor',
1503    'decreaseIndentRegexForScopeDescriptor',
1504    'decreaseNextIndentRegexForScopeDescriptor',
1505    'regexForPattern',
1506    'getNonWordCharacters'
1507  ].forEach(methodName => {
1508    TreeSitterLanguageMode.prototype[methodName] =
1509      TextMateLanguageMode.prototype[methodName];
1510  });
1511  
1512  TreeSitterLanguageMode.LanguageLayer = LanguageLayer;
1513  TreeSitterLanguageMode.prototype.syncTimeoutMicros = 1000;
1514  
1515  module.exports = TreeSitterLanguageMode;