Repository: atom/atom
File: src/grammar-registry.js (JavaScript)

Code before:
  }

  // Extended: Read a grammar synchronously but don't add it to the registry.
  //
  // * `grammarPath` A {String} absolute file path to a grammar file.
  //
  // Returns a {Grammar}.
  readGrammarSync (grammarPath) {
    return this.createGrammar(grammarPath, CSON.readFileSync(grammarPath) || {})
  }

  createGrammar (grammarPath, params) {
    if (params.type === 'tree-sitter') {
      return new TreeSitterGrammar(this, grammarPath, params)
    } else {
      if (typeof params.scopeName !== 'string' || params.scopeName.length === 0) {
        throw new Error(`Grammar missing required scopeName property: ${grammarPath}`)
      }
      return this.textmateRegistry.createGrammar(grammarPath, params)
    }
  }

  // Extended: Get all the grammars in this registry.
  //
  // Returns a non-empty {Array} of {Grammar} instances.
  getGrammars (params = {includeTreeSitter: false}) {
    let tmGrammars = this.textmateRegistry.getGrammars()
    if (!params.includeTreeSitter) return tmGrammars

    let tsGrammars = Object.values(this.treeSitterGrammarsById)
    return tsGrammars.concat(tmGrammars)
  }

  scopeForId (id) {
    return this.textmateRegistry.scopeForId(id)
  }

  treeSitterGrammarForLanguageString (languageString) {
    let longestMatchLength = 0
    let grammarWithLongestMatch = null
    for (const id in this.treeSitterGrammarsById) {
      const grammar = this.treeSitterGrammarsById[id]
      if (grammar.injectionRegex) {
        const match = languageString.match(grammar.injectionRegex)
        if (match) {
          const {length} = match[0]
          if (length > longestMatchLength) {
            grammarWithLongestMatch = grammar
            longestMatchLength = length
          }
        }

Review comment (refactor):
Turned into options object so we can add / change settings later without breaking changes

Maybe add TM-TS duplicate removal here? It would be slightly easier, and allow it to be used by all packages instead of making them do it themselves

Code after:
      return new Disposable(() => this.removeGrammar(grammar));
    } else {
      return this.textmateRegistry.addGrammar(grammar);
    }
  }

  removeGrammar(grammar) {
    if (grammar instanceof TreeSitterGrammar) {
      delete this.treeSitterGrammarsById[grammar.scopeName];
    } else {
      return this.textmateRegistry.removeGrammar(grammar);
    }
  }

  removeGrammarForScopeName(scopeName) {
    return this.textmateRegistry.removeGrammarForScopeName(scopeName);
  }

  // Extended: Read a grammar asynchronously and add it to the registry.
  //
  // * `grammarPath` A {String} absolute file path to a grammar file.
  // * `callback` A {Function} to call when loaded with the following arguments:
  //   * `error` An {Error}, may be null.
  //   * `grammar` A {Grammar} or null if an error occured.
  loadGrammar(grammarPath, callback) {
    this.readGrammar(grammarPath, (error, grammar) => {
      if (error) return callback(error);
      this.addGrammar(grammar);
      callback(null, grammar);
    });
  }

  // Extended: Read a grammar synchronously and add it to this registry.
  //
  // * `grammarPath` A {String} absolute file path to a grammar file.
  //
  // Returns a {Grammar}.
  loadGrammarSync(grammarPath) {
    const grammar = this.readGrammarSync(grammarPath);
    this.addGrammar(grammar);
    return grammar;
  }

  // Extended: Read a grammar asynchronously but don't add it to the registry.
  //
  // * `grammarPath` A {String} absolute file path to a grammar file.
  // * `callback` A {Function} to call when read with the following arguments:
  //   * `error` An {Error}, may be null.
  //   * `grammar` A {Grammar} or null if an error occured.
  //
  // Returns undefined.