diff --git a/packages/language-clojure/grammars/ts/highlights.scm b/packages/language-clojure/grammars/ts/highlights.scm index b6c933b7a..b2a34546a 100644 --- a/packages/language-clojure/grammars/ts/highlights.scm +++ b/packages/language-clojure/grammars/ts/highlights.scm @@ -34,9 +34,12 @@ ((list_lit "(" @punctuation.section.expression.begin (#is-not? test.descendantOfNodeWithData "clojure.dismissTag") . - (sym_lit) @meta.definition.global @keyword.control (#eq? @meta.definition.global "ns") + (sym_lit) @meta.definition.global @keyword.control + (#eq? @meta.definition.global "ns") . - (sym_lit) @meta.definition.global @entity.global + ; We need to distinguish this `@meta.definition.global` from the one above or + ; else this query will fail. + (sym_lit) @meta.definition.global.__TEXT__ @entity.global ")" @punctuation.section.expression.end) @meta.namespace.clojure (#set! isNamespace true)) diff --git a/packages/language-clojure/package.json b/packages/language-clojure/package.json index f04efc261..73b882a4d 100644 --- a/packages/language-clojure/package.json +++ b/packages/language-clojure/package.json @@ -5,7 +5,7 @@ "main": "lib/main", "engines": { "atom": "*", - "node": "*" + "node": ">=12" }, "repository": "https://github.com/pulsar-edit/pulsar", "license": "MIT", diff --git a/src/scope-resolver.js b/src/scope-resolver.js index 308ab2e7c..9fdc94823 100644 --- a/src/scope-resolver.js +++ b/src/scope-resolver.js @@ -1,3 +1,4 @@ +const { CompositeDisposable } = require('event-kit'); const { Point } = require('text-buffer'); const ScopeDescriptor = require('./scope-descriptor'); @@ -69,17 +70,36 @@ function interpretPossibleKeyValuePair(rawValue, coerceValue = false) { // `onDidChange` handlers (which are costly when observing all config values). class ConfigCache { constructor(config) { + this.subscriptions = new CompositeDisposable(); this.cachesByGrammar = new Map(); this.config = config; - this.config.onDidChange(() => { - for (let cache of this.cachesByGrammar.values()) { - cache.clear(); - } - }); + this.subscriptions.add( + this.config.onDidChange(() => this.clearAll()), + atom.grammars.onDidAddGrammar(() => this.clearAll()), + atom.grammars.onDidUpdateGrammar(() => this.clearAll()) + ); } + + dispose() { + this.subscriptions.dispose(); + } + + clearAll() { + for (let cache of this.cachesByGrammar.values()) { + cache.clear(); + } + } + getCacheForGrammar(grammar) { let { scopeName } = grammar; + // We key on the scope name rather than the grammar instance. We need to be + // able to iterate over grammars, so we can't use a `WeakSet` here, and we + // have no lifecycle event to keep the map from getting stale. + // + // To prevent two different incarnations of the same grammar (after + // disabling and reenabling) from incorrectly sharing a cache, we clear all + // caches whenever grammars are added or updated. let cache = this.cachesByGrammar.get(scopeName); if (!cache) { cache = new Map();