From dc2a4539862decbbfdb550bac76d61e4d47128e0 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Tue, 16 Dec 2014 15:27:39 -0800 Subject: [PATCH] Revert "Merge pull request #4631 from atom/mb-new-config-api" This reverts commit 5147fb6a8b5a0afd5add48430a4d68999e0bee30, reversing changes made to 9bbbb5808452a49f173d51bdaf1b14cd21b02067. --- spec/config-spec.coffee | 355 +++++++------------------ spec/package-manager-spec.coffee | 12 +- spec/text-editor-component-spec.coffee | 32 +-- spec/text-editor-spec.coffee | 12 +- src/config.coffee | 279 ++++++++----------- src/cursor.coffee | 4 +- src/display-buffer.coffee | 18 +- src/language-mode.coffee | 2 +- src/text-editor-component.coffee | 6 +- src/text-editor.coffee | 12 +- src/tokenized-buffer.coffee | 4 +- src/workspace.coffee | 2 +- 12 files changed, 259 insertions(+), 479 deletions(-) diff --git a/spec/config-spec.coffee b/spec/config-spec.coffee index b3db03d0b..324db9d8a 100644 --- a/spec/config-spec.coffee +++ b/spec/config-spec.coffee @@ -2,7 +2,6 @@ path = require 'path' temp = require 'temp' CSON = require 'season' fs = require 'fs-plus' -Grim = require 'grim' describe "Config", -> dotAtomPath = null @@ -35,36 +34,6 @@ describe "Config", -> atom.config.setDefaults("bar", baz: 7) expect(atom.config.get("bar.baz")).toEqual {a: 3} - describe "when a 'sources' option is specified", -> - it "only retrieves values from the specified sources", -> - atom.config.set("x.y", 1, scopeSelector: ".foo", source: "a") - atom.config.set("x.y", 2, scopeSelector: ".foo", source: "b") - atom.config.set("x.y", 3, scopeSelector: ".foo", source: "c") - atom.config.setSchema("x.y", type: "integer", default: 4) - - expect(atom.config.get("x.y", sources: ["a"], scope: [".foo"])).toBe 1 - expect(atom.config.get("x.y", sources: ["b"], scope: [".foo"])).toBe 2 - expect(atom.config.get("x.y", sources: ["c"], scope: [".foo"])).toBe 3 - # Schema defaults never match a specific source. We could potentially add a special "schema" source. - expect(atom.config.get("x.y", sources: ["x"], scope: [".foo"])).toBeUndefined() - - expect(atom.config.get(null, sources: ['a'], scope: [".foo"]).x.y).toBe 1 - - describe "when an 'excludeSources' option is specified", -> - it "only retrieves values from the specified sources", -> - atom.config.set("x.y", 0) - atom.config.set("x.y", 1, scopeSelector: ".foo", source: "a") - atom.config.set("x.y", 2, scopeSelector: ".foo", source: "b") - atom.config.set("x.y", 3, scopeSelector: ".foo", source: "c") - atom.config.setSchema("x.y", type: "integer", default: 4) - - expect(atom.config.get("x.y", excludeSources: ["a"], scope: [".foo"])).toBe 3 - expect(atom.config.get("x.y", excludeSources: ["c"], scope: [".foo"])).toBe 2 - expect(atom.config.get("x.y", excludeSources: ["b", "c"], scope: [".foo"])).toBe 1 - expect(atom.config.get("x.y", excludeSources: ["b", "c", "a"], scope: [".foo"])).toBe 0 - expect(atom.config.get("x.y", excludeSources: ["b", "c", "a", atom.config.getUserConfigPath()], scope: [".foo"])).toBe 4 - expect(atom.config.get("x.y", excludeSources: [atom.config.getUserConfigPath()])).toBe 4 - describe ".set(keyPath, value)", -> it "allows a key path's value to be written", -> expect(atom.config.set("foo.bar.baz", 42)).toBe true @@ -80,11 +49,8 @@ describe "Config", -> expect(atom.config.save).toHaveBeenCalled() expect(observeHandler).toHaveBeenCalledWith 42 - it "does not allow a 'source' option without a 'scopeSelector'", -> - expect(-> atom.config.set("foo", 1, source: [".source.ruby"])).toThrow() - describe "when the value equals the default value", -> - it "does not store the value in the user's config", -> + it "does not store the value", -> atom.config.setDefaults "foo", same: 1 changes: 1 @@ -100,84 +66,60 @@ describe "Config", -> atom.config.set('foo.null', undefined) atom.config.set('foo.undefined', null) atom.config.set('foo.sameObject', {b: 2, a: 1}) + expect(atom.config.settings.foo).toEqual {changes: 2} - expect(atom.config.get("foo.same", sources: [atom.config.getUserConfigPath()])).toBeUndefined() - - expect(atom.config.get("foo.changes", sources: [atom.config.getUserConfigPath()])).toBe 2 atom.config.set('foo.changes', 1) - expect(atom.config.get("foo.changes", sources: [atom.config.getUserConfigPath()])).toBeUndefined() + expect(atom.config.settings.foo).toEqual {} describe ".getDefault(keyPath)", -> it "returns a clone of the default value", -> atom.config.setDefaults("foo", same: 1, changes: 1) - - spyOn(Grim, 'deprecate') expect(atom.config.getDefault('foo.same')).toBe 1 expect(atom.config.getDefault('foo.changes')).toBe 1 - expect(Grim.deprecate.callCount).toBe 2 atom.config.set('foo.same', 2) atom.config.set('foo.changes', 3) - expect(atom.config.getDefault('foo.same')).toBe 1 expect(atom.config.getDefault('foo.changes')).toBe 1 - expect(Grim.deprecate.callCount).toBe 4 initialDefaultValue = [1, 2, 3] atom.config.setDefaults("foo", bar: initialDefaultValue) expect(atom.config.getDefault('foo.bar')).toEqual initialDefaultValue expect(atom.config.getDefault('foo.bar')).not.toBe initialDefaultValue - expect(Grim.deprecate.callCount).toBe 6 describe "when scoped settings are used", -> it "returns the global default when no scoped default set", -> atom.config.setDefaults("foo", bar: baz: 10) - - spyOn(Grim, 'deprecate') expect(atom.config.getDefault('.source.coffee', 'foo.bar.baz')).toBe 10 - expect(Grim.deprecate).toHaveBeenCalled() - it "returns the scoped settings not including the user's config file", -> + it "returns the scoped default when a scoped default is set", -> atom.config.setDefaults("foo", bar: baz: 10) atom.config.addScopedSettings("default", ".source.coffee", foo: bar: baz: 42) - - spyOn(Grim, 'deprecate') expect(atom.config.getDefault('.source.coffee', 'foo.bar.baz')).toBe 42 - expect(Grim.deprecate.callCount).toBe 1 - atom.config.set('foo.bar.baz', 55, scopeSelector: '.source.coffee') + atom.config.set('.source.coffee', 'foo.bar.baz', 55) expect(atom.config.getDefault('.source.coffee', 'foo.bar.baz')).toBe 42 - expect(Grim.deprecate.callCount).toBe 2 describe ".isDefault(keyPath)", -> it "returns true when the value of the key path is its default value", -> atom.config.setDefaults("foo", same: 1, changes: 1) - - spyOn(Grim, 'deprecate') expect(atom.config.isDefault('foo.same')).toBe true expect(atom.config.isDefault('foo.changes')).toBe true - expect(Grim.deprecate.callCount).toBe 2 atom.config.set('foo.same', 2) atom.config.set('foo.changes', 3) - expect(atom.config.isDefault('foo.same')).toBe false expect(atom.config.isDefault('foo.changes')).toBe false - expect(Grim.deprecate.callCount).toBe 4 describe "when scoped settings are used", -> it "returns false when a scoped setting was set by the user", -> - spyOn(Grim, 'deprecate') expect(atom.config.isDefault('.source.coffee', 'foo.bar.baz')).toBe true - expect(Grim.deprecate.callCount).toBe 1 atom.config.addScopedSettings("default", ".source.coffee", foo: bar: baz: 42) expect(atom.config.isDefault('.source.coffee', 'foo.bar.baz')).toBe true - expect(Grim.deprecate.callCount).toBe 2 - atom.config.set('foo.bar.baz', 55, scopeSelector: '.source.coffee') + atom.config.set('.source.coffee', 'foo.bar.baz', 55) expect(atom.config.isDefault('.source.coffee', 'foo.bar.baz')).toBe false - expect(Grim.deprecate.callCount).toBe 3 describe ".setDefaults(keyPath)", -> it "sets a default when the setting's key contains an escaped dot", -> @@ -208,17 +150,17 @@ describe "Config", -> atom.config.toggle('foo.a') expect(atom.config.get('foo.a')).toBe false - describe ".unset(keyPath, {scope})", -> + describe ".restoreDefault(keyPath)", -> it "sets the value of the key path to its default", -> atom.config.setDefaults('a', b: 3) atom.config.set('a.b', 4) expect(atom.config.get('a.b')).toBe 4 - atom.config.unset('a.b') + atom.config.restoreDefault('a.b') expect(atom.config.get('a.b')).toBe 3 atom.config.set('a.c', 5) expect(atom.config.get('a.c')).toBe 5 - atom.config.unset('a.c') + atom.config.restoreDefault('a.c') expect(atom.config.get('a.c')).toBeUndefined() it "calls ::save()", -> @@ -226,64 +168,43 @@ describe "Config", -> atom.config.set('a.b', 4) atom.config.save.reset() - atom.config.unset('a.c') + atom.config.restoreDefault('a.c') expect(atom.config.save.callCount).toBe 1 - it "throws when called with a source but no scope", -> - expect(-> atom.config.unset("a.b", source: "the-source")).toThrow() - describe "when scoped settings are used", -> it "restores the global default when no scoped default set", -> atom.config.setDefaults("foo", bar: baz: 10) - atom.config.set('foo.bar.baz', 55, scopeSelector: '.source.coffee') - expect(atom.config.get('foo.bar.baz', scope: ['.source.coffee'])).toBe 55 + atom.config.set('.source.coffee', 'foo.bar.baz', 55) + expect(atom.config.get(['.source.coffee'], 'foo.bar.baz')).toBe 55 - atom.config.unset('foo.bar.baz', scopeSelector: '.source.coffee') - expect(atom.config.get('foo.bar.baz', scope: ['.source.coffee'])).toBe 10 + atom.config.restoreDefault('.source.coffee', 'foo.bar.baz') + expect(atom.config.get(['.source.coffee'], 'foo.bar.baz')).toBe 10 it "restores the scoped default when a scoped default is set", -> atom.config.setDefaults("foo", bar: baz: 10) atom.config.addScopedSettings("default", ".source.coffee", foo: bar: baz: 42) - atom.config.set('foo.bar.baz', 55, scopeSelector: '.source.coffee') - atom.config.set('foo.bar.ok', 100, scopeSelector: '.source.coffee') - expect(atom.config.get('foo.bar.baz', scope: ['.source.coffee'])).toBe 55 + atom.config.set('.source.coffee', 'foo.bar.baz', 55) + atom.config.set('.source.coffee', 'foo.bar.ok', 100) + expect(atom.config.get(['.source.coffee'], 'foo.bar.baz')).toBe 55 - atom.config.unset('foo.bar.baz', scopeSelector: '.source.coffee') - expect(atom.config.get('foo.bar.baz', scope: ['.source.coffee'])).toBe 42 - expect(atom.config.get('foo.bar.ok', scope: ['.source.coffee'])).toBe 100 + atom.config.restoreDefault('.source.coffee', 'foo.bar.baz') + expect(atom.config.get(['.source.coffee'], 'foo.bar.baz')).toBe 42 + expect(atom.config.get(['.source.coffee'], 'foo.bar.ok')).toBe 100 it "calls ::save()", -> atom.config.setDefaults("foo", bar: baz: 10) atom.config.addScopedSettings("default", ".source.coffee", foo: bar: baz: 42) - atom.config.set('foo.bar.baz', 55, scopeSelector: '.source.coffee') + atom.config.set('.source.coffee', 'foo.bar.baz', 55) atom.config.save.reset() - atom.config.unset('foo.bar.baz', scopeSelector: '.source.coffee') + atom.config.restoreDefault('.source.coffee', 'foo.bar.baz') expect(atom.config.save.callCount).toBe 1 - it "allows removing settings for a specific source and scope selector", -> - atom.config.set('foo.bar', 55, scopeSelector: '.source.coffee', source: "source-a") - atom.config.set('foo.bar', 65, scopeSelector: '.source.coffee', source: "source-b") - expect(atom.config.get('foo.bar', scope: ['.source.coffee'])).toBe 65 - - atom.config.unset('foo.bar', source: "source-b", scopeSelector: ".source.coffee") - expect(atom.config.get('foo.bar', scope: ['.source.coffee', '.string'])).toBe 55 - - it "allows removing all settings for a specific source", -> - atom.config.set('foo.bar', 55, scopeSelector: '.source.coffee', source: "source-a") - atom.config.set('foo.bar', 65, scopeSelector: '.source.coffee', source: "source-b") - atom.config.set('foo.baz', 65, scopeSelector: '.source.coffee', source: "source-b") - expect(atom.config.get('foo.bar', scope: ['.source.coffee'])).toBe 65 - - atom.config.unset(null, source: "source-b", scopeSelector: ".source.coffee") - expect(atom.config.get('foo.bar', scope: ['.source.coffee', '.string'])).toBe 55 - expect(atom.config.get('foo.baz', scope: ['.source.coffee', '.string'])).toBe undefined - it "does not call ::save or add a scoped property when no value has been set", -> # see https://github.com/atom/atom/issues/4175 atom.config.setDefaults("foo", bar: baz: 10) - atom.config.unset('foo.bar.baz', scopeSelector: '.source.coffee') - expect(atom.config.get('foo.bar.baz', scope: ['.source.coffee'])).toBe 10 + atom.config.restoreDefault('.source.coffee', 'foo.bar.baz') + expect(atom.config.get(['.source.coffee'], 'foo.bar.baz')).toBe 10 expect(atom.config.save).not.toHaveBeenCalled() @@ -295,14 +216,14 @@ describe "Config", -> jasmine.unspy atom.config, 'save' atom.config.setDefaults("foo", bar: baz: 10) - atom.config.set('foo.bar.baz', 55, scopeSelector: '.source.coffee') - atom.config.set('foo.bar.zfoo', 20, scopeSelector: '.source.coffee') + atom.config.set('.source.coffee', 'foo.bar.baz', 55) + atom.config.set('.source.coffee', 'foo.bar.zfoo', 20) CSON.writeFileSync.reset() - expect(atom.config.get('foo.bar.baz', scope: ['.source.coffee'])).toBe 55 + expect(atom.config.get(['.source.coffee'], 'foo.bar.baz')).toBe 55 - atom.config.unset('foo.bar.baz', scopeSelector: '.source.coffee') - expect(atom.config.get('foo.bar.baz', scope: ['.source.coffee'])).toBe 10 - expect(atom.config.get('foo.bar.zfoo', scope: ['.source.coffee'])).toBe 20 + atom.config.restoreDefault('.source.coffee', 'foo.bar.baz') + expect(atom.config.get(['.source.coffee'], 'foo.bar.baz')).toBe 10 + expect(atom.config.get(['.source.coffee'], 'foo.bar.zfoo')).toBe 20 expect(CSON.writeFileSync).toHaveBeenCalled() properties = CSON.writeFileSync.mostRecentCall.args[1] expect(properties['.coffee.source']).toEqual @@ -311,29 +232,19 @@ describe "Config", -> zfoo: 20 CSON.writeFileSync.reset() - atom.config.unset('foo.bar.zfoo', scopeSelector: '.source.coffee') + atom.config.restoreDefault('.source.coffee', 'foo.bar.zfoo') expect(CSON.writeFileSync).toHaveBeenCalled() properties = CSON.writeFileSync.mostRecentCall.args[1] expect(properties['.coffee.source']).toBeUndefined() it "does not call ::save when the value is already at the default", -> atom.config.setDefaults("foo", bar: baz: 10) - atom.config.set('foo.bar.baz', 55) + atom.config.set('.source.coffee', 'foo.bar.baz', 55) atom.config.save.reset() - atom.config.unset('foo.bar.ok', scopeSelector: '.source.coffee') + atom.config.restoreDefault('.source.coffee', 'foo.bar.ok') expect(atom.config.save).not.toHaveBeenCalled() - expect(atom.config.get('foo.bar.baz', scope: ['.source.coffee'])).toBe 55 - - it "deprecates passing a scope selector as the first argument", -> - atom.config.setDefaults("foo", bar: baz: 10) - atom.config.set('foo.bar.baz', 55, scopeSelector: '.source.coffee') - - spyOn(Grim, 'deprecate') - atom.config.unset('.source.coffee', 'foo.bar.baz') - expect(Grim.deprecate).toHaveBeenCalled() - - expect(atom.config.get('foo.bar.baz', scope: ['.source.coffee'])).toBe 10 + expect(atom.config.get(['.source.coffee'], 'foo.bar.baz')).toBe 55 describe ".getSettings()", -> it "returns all settings including defaults", -> @@ -421,7 +332,7 @@ describe "Config", -> CSON.writeFileSync.reset() atom.config.save() - expect(CSON.writeFileSync.argsForCall[0][0]).toBe path.join(atom.config.configDirPath, "atom.config.json") + expect(CSON.writeFileSync.argsForCall[0][0]).toBe(path.join(atom.config.configDirPath, "atom.config.json")) writtenConfig = CSON.writeFileSync.argsForCall[0][1] expect(writtenConfig).toEqual global: atom.config.settings @@ -436,15 +347,15 @@ describe "Config", -> CSON.writeFileSync.reset() atom.config.save() - expect(CSON.writeFileSync.argsForCall[0][0]).toBe path.join(atom.config.configDirPath, "atom.config.cson") + expect(CSON.writeFileSync.argsForCall[0][0]).toBe(path.join(atom.config.configDirPath, "atom.config.cson")) writtenConfig = CSON.writeFileSync.argsForCall[0][1] expect(writtenConfig).toEqual global: atom.config.settings describe "when scoped settings are defined", -> it 'writes out explicitly set config settings', -> - atom.config.set('foo.bar', 'ruby', scopeSelector: '.source.ruby') - atom.config.set('foo.omg', 'wow', scopeSelector: '.source.ruby') - atom.config.set('foo.bar', 'coffee', scopeSelector: '.source.coffee') + atom.config.set('.source.ruby', 'foo.bar', 'ruby') + atom.config.set('.source.ruby', 'foo.omg', 'wow') + atom.config.set('.source.coffee', 'foo.bar', 'coffee') CSON.writeFileSync.reset() atom.config.save() @@ -529,7 +440,7 @@ describe "Config", -> beforeEach -> observeHandler = jasmine.createSpy("observeHandler") atom.config.set("foo.bar.baz", "value 1") - observeSubscription = atom.config.observe("foo.bar.baz", observeHandler) + observeSubscription = atom.config.observe "foo.bar.baz", observeHandler it "fires the given callback with the current value at the keypath", -> expect(observeHandler).toHaveBeenCalledWith("value 1") @@ -571,31 +482,6 @@ describe "Config", -> atom.config.set('foo.bar.baz', "value 10") expect(bazCatHandler).not.toHaveBeenCalled() - describe "observing scoped settings", -> - otherHandler = null - - beforeEach -> - observeSubscription.dispose() - otherHandler = jasmine.createSpy('otherHandler') - - it "allows settings to be observed in a specific scope", -> - atom.config.observe("foo.bar.baz", scope: [".some.scope"], observeHandler) - atom.config.observe("foo.bar.baz", scope: [".another.scope"], otherHandler) - - atom.config.set('foo.bar.baz', "value 2", scopeSelector: ".some") - expect(observeHandler).toHaveBeenCalledWith("value 2") - expect(otherHandler).not.toHaveBeenCalledWith("value 2") - - it "deprecates using a scope descriptor as the first argument", -> - spyOn(Grim, 'deprecate') - atom.config.observe([".some.scope"], "foo.bar.baz", observeHandler) - atom.config.observe([".another.scope"], "foo.bar.baz", otherHandler) - expect(Grim.deprecate).toHaveBeenCalled() - - atom.config.set('foo.bar.baz', "value 2", scopeSelector: ".some") - expect(observeHandler).toHaveBeenCalledWith("value 2") - expect(otherHandler).not.toHaveBeenCalledWith("value 2") - describe ".initializeConfigDirectory()", -> beforeEach -> if fs.existsSync(dotAtomPath) @@ -628,15 +514,6 @@ describe "Config", -> atom.config.configDirPath = dotAtomPath atom.config.configFilePath = path.join(atom.config.configDirPath, "atom.config.cson") expect(fs.existsSync(atom.config.configDirPath)).toBeFalsy() - atom.config.setSchema 'foo', - type: 'object' - properties: - bar: - type: 'string' - default: 'def' - int: - type: 'integer' - default: 12 afterEach -> fs.removeSync(dotAtomPath) @@ -656,7 +533,7 @@ describe "Config", -> it "updates the config data based on the file contents", -> expect(atom.config.get("foo.bar")).toBe 'baz' - expect(atom.config.get("foo.bar", scope: ['.source.ruby'])).toBe 'more-specific' + expect(atom.config.get(['.source.ruby'], "foo.bar")).toBe 'more-specific' describe "when the config file contains valid cson", -> beforeEach -> @@ -694,42 +571,43 @@ describe "Config", -> expect(fs.existsSync(atom.config.configFilePath)).toBe true expect(CSON.readFileSync(atom.config.configFilePath)).toEqual {} - describe "when the config file contains values that do not adhere to the schema", -> - warnSpy = null + describe "when a schema is specified", -> beforeEach -> - warnSpy = spyOn console, 'warn' - fs.writeFileSync atom.config.configFilePath, """ - foo: - bar: 'baz' - int: 'bad value' - """ - atom.config.loadUserConfig() + schema = + type: 'object' + properties: + bar: + type: 'string' + default: 'def' + int: + type: 'integer' + default: 12 - it "updates the only the settings that have values matching the schema", -> - expect(atom.config.get("foo.bar")).toBe 'baz' - expect(atom.config.get("foo.int")).toBe 12 + atom.config.setSchema('foo', schema) - expect(warnSpy).toHaveBeenCalled() - expect(warnSpy.mostRecentCall.args[0]).toContain "foo.int" + describe "when the config file contains values that do not adhere to the schema", -> + warnSpy = null + beforeEach -> + warnSpy = spyOn console, 'warn' + fs.writeFileSync atom.config.configFilePath, """ + foo: + bar: 'baz' + int: 'bad value' + """ + atom.config.loadUserConfig() + + it "updates the only the settings that have values matching the schema", -> + expect(atom.config.get("foo.bar")).toBe 'baz' + expect(atom.config.get("foo.int")).toBe 12 + + expect(warnSpy).toHaveBeenCalled() + expect(warnSpy.mostRecentCall.args[0]).toContain "'foo.int' could not be set" describe ".observeUserConfig()", -> updatedHandler = null beforeEach -> - atom.config.setSchema 'foo', - type: 'object' - properties: - bar: - type: 'string' - default: 'def' - baz: - type: 'string' - scoped: - type: 'boolean' - int: - type: 'integer' - default: 12 - + atom.config.setDefaults('foo', bar: 'def') atom.config.configDirPath = dotAtomPath atom.config.configFilePath = path.join(atom.config.configDirPath, "atom.config.cson") expect(fs.existsSync(atom.config.configDirPath)).toBeFalsy() @@ -762,38 +640,32 @@ describe "Config", -> it "does not fire a change event for paths that did not change", -> atom.config.onDidChange 'foo.bar', noChangeSpy = jasmine.createSpy() - fs.writeFileSync(atom.config.configFilePath, "foo: { bar: 'baz', baz: 'ok'}") + fs.writeFileSync(atom.config.configFilePath, "foo: { bar: 'baz', omg: 'ok'}") waitsFor 'update event', -> updatedHandler.callCount > 0 runs -> expect(noChangeSpy).not.toHaveBeenCalled() expect(atom.config.get('foo.bar')).toBe 'baz' - expect(atom.config.get('foo.baz')).toBe 'ok' + expect(atom.config.get('foo.omg')).toBe 'ok' describe 'when the default value is a complex value', -> beforeEach -> - atom.config.setSchema 'foo.bar', - type: 'array' - items: - type: 'string' fs.writeFileSync(atom.config.configFilePath, "foo: { bar: ['baz', 'ok']}") waitsFor 'update event', -> updatedHandler.callCount > 0 runs -> updatedHandler.reset() it "does not fire a change event for paths that did not change", -> - noChangeSpy = jasmine.createSpy() - atom.config.onDidChange('foo.bar', noChangeSpy) + atom.config.onDidChange 'foo.bar', noChangeSpy = jasmine.createSpy() - fs.writeFileSync(atom.config.configFilePath, "foo: { bar: ['baz', 'ok'], baz: 'another'}") + fs.writeFileSync(atom.config.configFilePath, "foo: { bar: ['baz', 'ok'], omg: 'another'}") waitsFor 'update event', -> updatedHandler.callCount > 0 runs -> expect(noChangeSpy).not.toHaveBeenCalled() expect(atom.config.get('foo.bar')).toEqual ['baz', 'ok'] - expect(atom.config.get('foo.baz')).toBe 'another' + expect(atom.config.get('foo.omg')).toBe 'another' describe 'when scoped settings are used', -> it "fires a change event for scoped settings that are removed", -> - scopedSpy = jasmine.createSpy() - atom.config.onDidChange('foo.scoped', scope: ['.source.ruby'], scopedSpy) + atom.config.onDidChange ['.source.ruby'], 'foo.scoped', scopedSpy = jasmine.createSpy() fs.writeFileSync atom.config.configFilePath, """ global: @@ -803,11 +675,10 @@ describe "Config", -> waitsFor 'update event', -> updatedHandler.callCount > 0 runs -> expect(scopedSpy).toHaveBeenCalled() - expect(atom.config.get('foo.scoped', scope: ['.source.ruby'])).toBe false + expect(atom.config.get(['.source.ruby'], 'foo.scoped')).toBe false it "does not fire a change event for paths that did not change", -> - noChangeSpy = jasmine.createSpy() - atom.config.onDidChange('foo.scoped', scope: ['.source.ruby'], noChangeSpy) + atom.config.onDidChange ['.source.ruby'], 'foo.scoped', noChangeSpy = jasmine.createSpy() fs.writeFileSync atom.config.configFilePath, """ global: @@ -820,8 +691,8 @@ describe "Config", -> waitsFor 'update event', -> updatedHandler.callCount > 0 runs -> expect(noChangeSpy).not.toHaveBeenCalled() - expect(atom.config.get('foo.bar', scope: ['.source.ruby'])).toBe 'baz' - expect(atom.config.get('foo.scoped', scope: ['.source.ruby'])).toBe true + expect(atom.config.get(['.source.ruby'], 'foo.bar')).toBe 'baz' + expect(atom.config.get(['.source.ruby'], 'foo.scoped')).toBe true describe "when the config file changes to omit a setting with a default", -> it "resets the setting back to the default", -> @@ -1224,8 +1095,8 @@ describe "Config", -> it 'it respects the scoped defaults', -> expect(atom.config.get('foo.bar.str')).toBe 'ok' - expect(atom.config.get('foo.bar.str', scope: ['.source.js'])).toBe 'omg' - expect(atom.config.get('foo.bar.str', scope: ['.source.coffee'])).toBe 'ok' + expect(atom.config.get(['.source.js'], 'foo.bar.str')).toBe 'omg' + expect(atom.config.get(['.source.coffee'], 'foo.bar.str')).toBe 'ok' describe "scoped settings", -> describe ".get(scopeDescriptor, keyPath)", -> @@ -1234,29 +1105,29 @@ describe "Config", -> atom.config.addScopedSettings("config", ".source .string.quoted.double", foo: bar: baz: 22) atom.config.addScopedSettings("config", ".source", foo: bar: baz: 11) - expect(atom.config.get("foo.bar.baz", scope: [".source.coffee", ".string.quoted.double.coffee"])).toBe 42 - expect(atom.config.get("foo.bar.baz", scope: [".source.js", ".string.quoted.double.js"])).toBe 22 - expect(atom.config.get("foo.bar.baz", scope: [".source.js", ".variable.assignment.js"])).toBe 11 - expect(atom.config.get("foo.bar.baz", scope: [".text"])).toBeUndefined() + expect(atom.config.get([".source.coffee", ".string.quoted.double.coffee"], "foo.bar.baz")).toBe 42 + expect(atom.config.get([".source.js", ".string.quoted.double.js"], "foo.bar.baz")).toBe 22 + expect(atom.config.get([".source.js", ".variable.assignment.js"], "foo.bar.baz")).toBe 11 + expect(atom.config.get([".text"], "foo.bar.baz")).toBeUndefined() it "favors the most recently added properties in the event of a specificity tie", -> atom.config.addScopedSettings("config", ".source.coffee .string.quoted.single", foo: bar: baz: 42) atom.config.addScopedSettings("config", ".source.coffee .string.quoted.double", foo: bar: baz: 22) - expect(atom.config.get("foo.bar.baz", scope: [".source.coffee", ".string.quoted.single"])).toBe 42 - expect(atom.config.get("foo.bar.baz", scope: [".source.coffee", ".string.quoted.single.double"])).toBe 22 + expect(atom.config.get([".source.coffee", ".string.quoted.single"], "foo.bar.baz")).toBe 42 + expect(atom.config.get([".source.coffee", ".string.quoted.single.double"], "foo.bar.baz")).toBe 22 describe 'when there are global defaults', -> it 'falls back to the global when there is no scoped property specified', -> atom.config.setDefaults("foo", hasDefault: 'ok') - expect(atom.config.get("foo.hasDefault", scope: [".source.coffee", ".string.quoted.single"])).toBe 'ok' + expect(atom.config.get([".source.coffee", ".string.quoted.single"], "foo.hasDefault")).toBe 'ok' describe 'setting priority', -> describe 'when package settings are added after user settings', -> it "returns the user's setting because the user's setting has higher priority", -> - atom.config.set("foo.bar.baz", 100, scopeSelector: ".source.coffee") + atom.config.set(".source.coffee", "foo.bar.baz", 100) atom.config.addScopedSettings("some-package", ".source.coffee", foo: bar: baz: 1) - expect(atom.config.get("foo.bar.baz", scope: [".source.coffee"])).toBe 100 + expect(atom.config.get([".source.coffee"], "foo.bar.baz")).toBe 100 describe ".set(scope, keyPath, value)", -> it "sets the value and overrides the others", -> @@ -1264,10 +1135,10 @@ describe "Config", -> atom.config.addScopedSettings("config", ".source .string.quoted.double", foo: bar: baz: 22) atom.config.addScopedSettings("config", ".source", foo: bar: baz: 11) - expect(atom.config.get("foo.bar.baz", scope: [".source.coffee", ".string.quoted.double.coffee"])).toBe 42 + expect(atom.config.get([".source.coffee", ".string.quoted.double.coffee"], "foo.bar.baz")).toBe 42 - expect(atom.config.set("foo.bar.baz", 100, scopeSelector: ".source.coffee .string.quoted.double.coffee")).toBe true - expect(atom.config.get("foo.bar.baz", scope: [".source.coffee", ".string.quoted.double.coffee"])).toBe 100 + expect(atom.config.set(".source.coffee .string.quoted.double.coffee", "foo.bar.baz", 100)).toBe true + expect(atom.config.get([".source.coffee", ".string.quoted.double.coffee"], "foo.bar.baz")).toBe 100 describe ".removeScopedSettingsForName(name)", -> it "allows properties to be removed by name", -> @@ -1275,13 +1146,12 @@ describe "Config", -> disposable2 = atom.config.addScopedSettings("b", ".source .string.quoted.double", foo: bar: baz: 22) disposable2.dispose() - expect(atom.config.get("foo.bar.baz", scope: [".source.js", ".string.quoted.double.js"])).toBeUndefined() - expect(atom.config.get("foo.bar.baz", scope: [".source.coffee", ".string.quoted.double.coffee"])).toBe 42 + expect(atom.config.get([".source.js", ".string.quoted.double.js"], "foo.bar.baz")).toBeUndefined() + expect(atom.config.get([".source.coffee", ".string.quoted.double.coffee"], "foo.bar.baz")).toBe 42 describe ".observe(scopeDescriptor, keyPath)", -> it 'calls the supplied callback when the value at the descriptor/keypath changes', -> - changeSpy = jasmine.createSpy() - atom.config.observe("foo.bar.baz", scope: [".source.coffee", ".string.quoted.double.coffee"], changeSpy) + atom.config.observe [".source.coffee", ".string.quoted.double.coffee"], "foo.bar.baz", changeSpy = jasmine.createSpy() expect(changeSpy).toHaveBeenCalledWith(undefined) changeSpy.reset() @@ -1312,38 +1182,7 @@ describe "Config", -> describe ".onDidChange(scopeDescriptor, keyPath)", -> it 'calls the supplied callback when the value at the descriptor/keypath changes', -> keyPath = "foo.bar.baz" - changeSpy = jasmine.createSpy('onDidChange callback') - atom.config.onDidChange keyPath, scope: [".source.coffee", ".string.quoted.double.coffee"], changeSpy - - atom.config.set("foo.bar.baz", 12) - expect(changeSpy).toHaveBeenCalledWith({oldValue: undefined, newValue: 12, keyPath}) - changeSpy.reset() - - disposable1 = atom.config.addScopedSettings("a", ".source .string.quoted.double", foo: bar: baz: 22) - expect(changeSpy).toHaveBeenCalledWith({oldValue: 12, newValue: 22, keyPath}) - changeSpy.reset() - - disposable2 = atom.config.addScopedSettings("b", ".source.coffee .string.quoted.double.coffee", foo: bar: baz: 42) - expect(changeSpy).toHaveBeenCalledWith({oldValue: 22, newValue: 42, keyPath}) - changeSpy.reset() - - disposable2.dispose() - expect(changeSpy).toHaveBeenCalledWith({oldValue: 42, newValue: 22, keyPath}) - changeSpy.reset() - - disposable1.dispose() - expect(changeSpy).toHaveBeenCalledWith({oldValue: 22, newValue: 12, keyPath}) - changeSpy.reset() - - atom.config.set("foo.bar.baz", undefined) - expect(changeSpy).toHaveBeenCalledWith({oldValue: 12, newValue: undefined, keyPath}) - changeSpy.reset() - - it 'deprecates using a scope descriptor as an optional first argument', -> - keyPath = "foo.bar.baz" - spyOn(Grim, 'deprecate') atom.config.onDidChange [".source.coffee", ".string.quoted.double.coffee"], keyPath, changeSpy = jasmine.createSpy() - expect(Grim.deprecate).toHaveBeenCalled() atom.config.set("foo.bar.baz", 12) expect(changeSpy).toHaveBeenCalledWith({oldValue: undefined, newValue: 12, keyPath}) diff --git a/spec/package-manager-spec.coffee b/spec/package-manager-spec.coffee index bac6270f8..0cc55e32d 100644 --- a/spec/package-manager-spec.coffee +++ b/spec/package-manager-spec.coffee @@ -367,7 +367,7 @@ describe "PackageManager", -> atom.packages.activatePackage("package-with-scoped-properties") runs -> - expect(atom.config.get 'editor.increaseIndentPattern', scope: ['.source.omg']).toBe '^a' + expect(atom.config.get ['.source.omg'], 'editor.increaseIndentPattern').toBe '^a' describe "converted textmate packages", -> it "loads the package's grammars", -> @@ -380,13 +380,13 @@ describe "PackageManager", -> expect(atom.grammars.selectGrammar("file.rb").name).toBe "Ruby" it "loads the translated scoped properties", -> - expect(atom.config.get('editor.commentStart', scope: ['.source.ruby'])).toBeUndefined() + expect(atom.config.get(['.source.ruby'], 'editor.commentStart')).toBeUndefined() waitsForPromise -> atom.packages.activatePackage('language-ruby') runs -> - expect(atom.config.get('editor.commentStart', scope: ['.source.ruby'])).toBe '# ' + expect(atom.config.get(['.source.ruby'], 'editor.commentStart')).toBe '# ' describe "::deactivatePackage(id)", -> afterEach -> @@ -493,9 +493,9 @@ describe "PackageManager", -> atom.packages.activatePackage("package-with-scoped-properties") runs -> - expect(atom.config.get 'editor.increaseIndentPattern', scope: ['.source.omg']).toBe '^a' + expect(atom.config.get ['.source.omg'], 'editor.increaseIndentPattern').toBe '^a' atom.packages.deactivatePackage("package-with-scoped-properties") - expect(atom.config.get 'editor.increaseIndentPattern', scope: ['.source.omg']).toBeUndefined() + expect(atom.config.get ['.source.omg'], 'editor.increaseIndentPattern').toBeUndefined() describe "textmate packages", -> it "removes the package's grammars", -> @@ -515,7 +515,7 @@ describe "PackageManager", -> runs -> atom.packages.deactivatePackage('language-ruby') - expect(atom.config.get('editor.commentStart', scope: ['.source.ruby'])).toBeUndefined() + expect(atom.config.get(['.source.ruby'], 'editor.commentStart')).toBeUndefined() describe "::activate()", -> packageActivator = null diff --git a/spec/text-editor-component-spec.coffee b/spec/text-editor-component-spec.coffee index 6506db4d7..bfc343c03 100644 --- a/spec/text-editor-component-spec.coffee +++ b/spec/text-editor-component-spec.coffee @@ -2593,9 +2593,9 @@ describe "TextEditorComponent", -> describe 'soft wrap settings', -> beforeEach -> - atom.config.set 'editor.softWrap', true, scopeSelector: '.source.coffee' - atom.config.set 'editor.preferredLineLength', 17, scopeSelector: '.source.coffee' - atom.config.set 'editor.softWrapAtPreferredLineLength', true, scopeSelector: '.source.coffee' + atom.config.set '.source.coffee', 'editor.softWrap', true + atom.config.set '.source.coffee', 'editor.preferredLineLength', 17 + atom.config.set '.source.coffee', 'editor.softWrapAtPreferredLineLength', true editor.setEditorWidthInChars(20) coffeeEditor.setEditorWidthInChars(20) @@ -2605,18 +2605,18 @@ describe "TextEditorComponent", -> expect(coffeeEditor.lineTextForScreenRow(3)).toEqual ' return items ' it 'updates the wrapped lines when editor.preferredLineLength changes', -> - atom.config.set 'editor.preferredLineLength', 20, scopeSelector: '.source.coffee' + atom.config.set '.source.coffee', 'editor.preferredLineLength', 20 expect(coffeeEditor.lineTextForScreenRow(2)).toEqual ' return items if ' it 'updates the wrapped lines when editor.softWrapAtPreferredLineLength changes', -> - atom.config.set 'editor.softWrapAtPreferredLineLength', false, scopeSelector: '.source.coffee' + atom.config.set '.source.coffee', 'editor.softWrapAtPreferredLineLength', false expect(coffeeEditor.lineTextForScreenRow(2)).toEqual ' return items if ' it 'updates the wrapped lines when editor.softWrap changes', -> - atom.config.set 'editor.softWrap', false, scopeSelector: '.source.coffee' + atom.config.set '.source.coffee', 'editor.softWrap', false expect(coffeeEditor.lineTextForScreenRow(2)).toEqual ' return items if items.length <= 1' - atom.config.set 'editor.softWrap', true, scopeSelector: '.source.coffee' + atom.config.set '.source.coffee', 'editor.softWrap', true expect(coffeeEditor.lineTextForScreenRow(3)).toEqual ' return items ' it 'updates the wrapped lines when the grammar changes', -> @@ -2644,11 +2644,11 @@ describe "TextEditorComponent", -> tab: 'F' cr: 'E' - atom.config.set 'editor.showInvisibles', true, scopeSelector: '.source.js' - atom.config.set 'editor.invisibles', jsInvisibles, scopeSelector: '.source.js' + atom.config.set '.source.js', 'editor.showInvisibles', true + atom.config.set '.source.js', 'editor.invisibles', jsInvisibles - atom.config.set 'editor.showInvisibles', false, scopeSelector: '.source.coffee' - atom.config.set 'editor.invisibles', coffeeInvisibles, scopeSelector: '.source.coffee' + atom.config.set '.source.coffee', 'editor.showInvisibles', false + atom.config.set '.source.coffee', 'editor.invisibles', coffeeInvisibles editor.setText " a line with tabs\tand spaces \n" nextAnimationFrame() @@ -2664,7 +2664,7 @@ describe "TextEditorComponent", -> it "re-renders the invisibles when the invisible settings change", -> jsGrammar = editor.getGrammar() editor.setGrammar(coffeeEditor.getGrammar()) - atom.config.set 'editor.showInvisibles', true, scopeSelector: '.source.coffee' + atom.config.set '.source.coffee', 'editor.showInvisibles', true nextAnimationFrame() expect(component.lineNodeForScreenRow(0).textContent).toBe "#{coffeeInvisibles.space}a line with tabs#{coffeeInvisibles.tab}and spaces#{coffeeInvisibles.space}#{coffeeInvisibles.eol}" @@ -2673,7 +2673,7 @@ describe "TextEditorComponent", -> space: 'E' tab: 'W' cr: 'I' - atom.config.set 'editor.invisibles', newInvisibles, scopeSelector: '.source.coffee' + atom.config.set '.source.coffee', 'editor.invisibles', newInvisibles nextAnimationFrame() expect(component.lineNodeForScreenRow(0).textContent).toBe "#{newInvisibles.space}a line with tabs#{newInvisibles.tab}and spaces#{newInvisibles.space}#{newInvisibles.eol}" @@ -2683,8 +2683,8 @@ describe "TextEditorComponent", -> describe 'editor.showIndentGuide', -> beforeEach -> - atom.config.set 'editor.showIndentGuide', true, scopeSelector: '.source.js' - atom.config.set 'editor.showIndentGuide', false, scopeSelector: '.source.coffee' + atom.config.set '.source.js', 'editor.showIndentGuide', true + atom.config.set '.source.coffee', 'editor.showIndentGuide', false it "has an 'indent-guide' class when scoped editor.showIndentGuide is true, but not when scoped editor.showIndentGuide is false", -> line1LeafNodes = getLeafNodes(component.lineNodeForScreenRow(1)) @@ -2705,7 +2705,7 @@ describe "TextEditorComponent", -> expect(line1LeafNodes[0].classList.contains('indent-guide')).toBe true expect(line1LeafNodes[1].classList.contains('indent-guide')).toBe false - atom.config.set 'editor.showIndentGuide', false, scopeSelector: '.source.js' + atom.config.set '.source.js', 'editor.showIndentGuide', false line1LeafNodes = getLeafNodes(component.lineNodeForScreenRow(1)) expect(line1LeafNodes[0].textContent).toBe ' ' diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index c70991f38..b84b3b944 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -1327,7 +1327,7 @@ describe "TextEditor", -> coffeeEditor.selectWordsContainingCursors() expect(coffeeEditor.getSelectedBufferRange()).toEqual [[0, 6], [0, 15]] - atom.config.set 'editor.nonWordCharacters', 'qusort', scopeSelector: '.source.coffee' + atom.config.set '.source.coffee', 'editor.nonWordCharacters', 'qusort' coffeeEditor.setCursorBufferPosition [0, 9] coffeeEditor.selectWordsContainingCursors() @@ -3276,7 +3276,7 @@ describe "TextEditor", -> atom.packages.unloadPackages() it 'returns correct values based on the scope of the set grammars', -> - atom.config.set 'editor.tabLength', 6, scopeSelector: '.source.coffee' + atom.config.set '.source.coffee', 'editor.tabLength', 6 expect(editor.getTabLength()).toBe 2 expect(coffeeEditor.getTabLength()).toBe 6 @@ -3298,12 +3298,12 @@ describe "TextEditor", -> expect(editor.getTabLength()).toBe 2 expect(editor.tokenizedLineForScreenRow(5).tokens[0].firstNonWhitespaceIndex).toBe 2 - atom.config.set 'editor.tabLength', 6, scopeSelector: '.source.js' + atom.config.set '.source.js', 'editor.tabLength', 6 expect(editor.getTabLength()).toBe 6 expect(editor.tokenizedLineForScreenRow(5).tokens[0].firstNonWhitespaceIndex).toBe 6 it 'updates the tab length when the grammar changes', -> - atom.config.set 'editor.tabLength', 6, scopeSelector: '.source.coffee' + atom.config.set '.source.coffee', 'editor.tabLength', 6 expect(editor.getTabLength()).toBe 2 expect(editor.tokenizedLineForScreenRow(5).tokens[0].firstNonWhitespaceIndex).toBe 2 @@ -3473,8 +3473,8 @@ describe "TextEditor", -> atom.project.open('coffee.coffee', autoIndent: false).then (o) -> coffeeEditor = o runs -> - atom.config.set('editor.autoIndent', true, scopeSelector: '.source.js') - atom.config.set('editor.autoIndent', false, scopeSelector: '.source.coffee') + atom.config.set('.source.js', 'editor.autoIndent', true) + atom.config.set('.source.coffee', 'editor.autoIndent', false) afterEach: -> atom.packages.deactivatePackages() diff --git a/src/config.coffee b/src/config.coffee index cb9dc60b4..dcad15b56 100644 --- a/src/config.coffee +++ b/src/config.coffee @@ -314,11 +314,10 @@ class Config @settings = {} @scopedSettingsStore = new ScopedPropertyStore @usersScopedSettings = new CompositeDisposable + @usersScopedSettingPriority = {priority: 1000} @configFileHasErrors = false @configFilePath = fs.resolve(@configDirPath, 'config', ['json', 'cson']) @configFilePath ?= path.join(@configDirPath, 'config.cson') - @prioritiesBySource = {} - @prioritiesBySource[@getUserConfigPath()] = 1000 ### Section: Config Subscription @@ -338,36 +337,32 @@ class Config # # do stuff with value # ``` # + # * `scopeDescriptor` (optional) {ScopeDescriptor} describing a path from + # the root of the syntax tree to a token. Get one by calling + # {editor.getLastCursor().getScopeDescriptor()}. See {::get} for examples. + # See [the scopes docs](https://atom.io/docs/latest/advanced/scopes-and-scope-descriptors) + # for more information. # * `keyPath` {String} name of the key to observe - # * `options` {Object} - # * `scopeDescriptor` (optional) {ScopeDescriptor} describing a path from - # the root of the syntax tree to a token. Get one by calling - # {editor.getLastCursor().getScopeDescriptor()}. See {::get} for examples. - # See [the scopes docs](https://atom.io/docs/latest/advanced/scopes-and-scope-descriptors) - # for more information. # * `callback` {Function} to call when the value of the key changes. # * `value` the new value of the key # # Returns a {Disposable} with the following keys on which you can call # `.dispose()` to unsubscribe. - observe: -> - if arguments.length is 2 - [keyPath, callback] = arguments - else if arguments.length is 3 and (_.isArray(arguments[0]) or arguments[0] instanceof ScopeDescriptor) - Grim.deprecate """ - Passing a scope descriptor as the first argument to Config::observe is deprecated. - Pass a `scope` in an options hash as the third argument instead. - """ - [scopeDescriptor, keyPath, callback] = arguments - else if arguments.length is 3 and (_.isString(arguments[0]) and _.isObject(arguments[1])) - [keyPath, options, callback] = arguments - scopeDescriptor = options.scope - if options.callNow? - Grim.deprecate """ - Config::observe no longer takes a `callNow` option. Use ::onDidChange instead. - Note that ::onDidChange passes its callback different arguments. - See https://atom.io/docs/api/latest/Config - """ + observe: (scopeDescriptor, keyPath, options, callback) -> + args = Array::slice.call(arguments) + if args.length is 2 + # observe(keyPath, callback) + [keyPath, callback, scopeDescriptor, options] = args + else if args.length is 3 and (Array.isArray(scopeDescriptor) or scopeDescriptor instanceof ScopeDescriptor) + # observe(scopeDescriptor, keyPath, callback) + [scopeDescriptor, keyPath, callback, options] = args + else if args.length is 3 and _.isString(scopeDescriptor) and _.isObject(keyPath) + # observe(keyPath, options, callback) # Deprecated! + [keyPath, options, callback, scopeDescriptor] = args + + message = "" + message = "`callNow` was set to false. Use ::onDidChange instead. Note that ::onDidChange calls back with different arguments." if options.callNow == false + Grim.deprecate "Config::observe no longer supports options; see https://atom.io/docs/api/latest/Config. #{message}" else console.error 'An unsupported form of Config::observe is being used. See https://atom.io/docs/api/latest/Config for details' return @@ -380,14 +375,13 @@ class Config # Essential: Add a listener for changes to a given key path. If `keyPath` is # not specified, your callback will be called on changes to any key. # + # * `scopeDescriptor` (optional) {ScopeDescriptor} describing a path from + # the root of the syntax tree to a token. Get one by calling + # {editor.getLastCursor().getScopeDescriptor()}. See {::get} for examples. + # See [the scopes docs](https://atom.io/docs/latest/advanced/scopes-and-scope-descriptors) + # for more information. # * `keyPath` (optional) {String} name of the key to observe. Must be # specified if `scopeDescriptor` is specified. - # * `optional` (optional) {Object} - # * `scopeDescriptor` (optional) {ScopeDescriptor} describing a path from - # the root of the syntax tree to a token. Get one by calling - # {editor.getLastCursor().getScopeDescriptor()}. See {::get} for examples. - # See [the scopes docs](https://atom.io/docs/latest/advanced/scopes-and-scope-descriptors) - # for more information. # * `callback` {Function} to call when the value of the key changes. # * `event` {Object} # * `newValue` the new value of the key @@ -396,20 +390,12 @@ class Config # # Returns a {Disposable} with the following keys on which you can call # `.dispose()` to unsubscribe. - onDidChange: -> + onDidChange: (scopeDescriptor, keyPath, callback) -> + args = Array::slice.call(arguments) if arguments.length is 1 - [callback] = arguments + [callback, scopeDescriptor, keyPath] = args else if arguments.length is 2 - [keyPath, callback] = arguments - else if _.isArray(arguments[0]) or arguments[0] instanceof ScopeDescriptor - Grim.deprecate """ - Passing a scope descriptor as the first argument to Config::onDidChange is deprecated. - Pass a `scope` in an options hash as the third argument instead. - """ - [scopeDescriptor, keyPath, callback] = arguments - else - [keyPath, options, callback] = arguments - scopeDescriptor = options.scope + [keyPath, callback, scopeDescriptor] = args if scopeDescriptor? @onDidChangeScopedKeyPath(scopeDescriptor, keyPath, callback) @@ -460,40 +446,24 @@ class Config # atom.config.get(scopeDescriptor, 'editor.tabLength') # => 2 # ``` # + # * `scopeDescriptor` (optional) {ScopeDescriptor} describing a path from + # the root of the syntax tree to a token. Get one by calling + # {editor.getLastCursor().getScopeDescriptor()} + # See [the scopes docs](https://atom.io/docs/latest/advanced/scopes-and-scope-descriptors) + # for more information. # * `keyPath` The {String} name of the key to retrieve. - # * `options` (optional) {Object} - # * `sources` (optional) {Array} of {String} source names. If provided, only - # values that were associated with these sources during {::set} will be used. - # * `excludeSources` (optional) {Array} of {String} source names. If provided, - # values that were associated with these sources during {::set} will not - # be used. - # * `scopeDescriptor` (optional) {ScopeDescriptor} describing a path from - # the root of the syntax tree to a token. Get one by calling - # {editor.getLastCursor().getScopeDescriptor()} - # See [the scopes docs](https://atom.io/docs/latest/advanced/scopes-and-scope-descriptors) - # for more information. # # Returns the value from Atom's default settings, the user's configuration # file in the type specified by the configuration schema. - get: -> - if arguments.length > 1 - if typeof arguments[0] is 'string' or not arguments[0]? - [keyPath, options] = arguments - {scope} = options - else - Grim.deprecate """ - Passing a scope descriptor as the first argument to Config::get is deprecated. - Pass a `scope` in an options hash as the final argument instead. - """ - [scope, keyPath] = arguments + get: (scopeDescriptor, keyPath) -> + if arguments.length == 1 + # cannot assign to keyPath for the sake of v8 optimization + globalKeyPath = scopeDescriptor + @getRawValue(globalKeyPath) else - [keyPath] = arguments - - if scope? - value = @getRawScopedValue(scope, keyPath, options) - value ? @getRawValue(keyPath, options) - else - @getRawValue(keyPath, options) + value = @getRawScopedValue(scopeDescriptor, keyPath) + value ?= @getRawValue(keyPath) + value # Essential: Sets the value for a configuration setting. # @@ -524,95 +494,63 @@ class Config # atom.config.get(['source.js'], 'editor.tabLength') # => 4 # ``` # + # * `scopeSelector` (optional) {String}. eg. '.source.ruby' + # See [the scopes docs](https://atom.io/docs/latest/advanced/scopes-and-scope-descriptors) + # for more information. # * `keyPath` The {String} name of the key. # * `value` The value of the setting. Passing `undefined` will revert the # setting to the default value. - # * `options` (optional) {Object} - # * `scopeSelector` (optional) {String}. eg. '.source.ruby' - # See [the scopes docs](https://atom.io/docs/latest/advanced/scopes-and-scope-descriptors) - # for more information. - # * `source` (optional) {String} The name of a file with which the setting - # is associated. Defaults to the user's config file. # # Returns a {Boolean} # * `true` if the value was set. # * `false` if the value was not able to be coerced to the type specified in the setting's schema. - set: -> - if arguments[0][0] is '.' - Grim.deprecate """ - Passing a scope selector as the first argument to Config::set is deprecated. - Pass a `scopeSelector` in an options hash as the final argument instead. - """ - [scopeSelector, keyPath, value] = arguments - else - [keyPath, value, options] = arguments - scopeSelector = options?.scopeSelector - source = options?.source + set: (scopeSelector, keyPath, value) -> + if arguments.length < 3 + value = keyPath + keyPath = scopeSelector + scopeSelector = undefined - if source and not scopeSelector - throw new Error("::set with a 'source' and no 'sourceSelector' is not yet implemented!") - - source ?= @getUserConfigPath() - - unless value is undefined + unless value == undefined try value = @makeValueConformToSchema(keyPath, value) catch e return false if scopeSelector? - @setRawScopedValue(source, scopeSelector, keyPath, value) + @setRawScopedValue(scopeSelector, keyPath, value) else @setRawValue(keyPath, value) @save() unless @configFileHasErrors true - # Essential: Restore the setting at `keyPath` to its default value. + # Extended: Restore the global setting at `keyPath` to its default value. # + # * `scopeSelector` (optional) {String}. eg. '.source.ruby' + # See [the scopes docs](https://atom.io/docs/latest/advanced/scopes-and-scope-descriptors) + # for more information. # * `keyPath` The {String} name of the key. - # * `options` (optional) {Object} - # * `scopeSelector` (optional) {String}. See {::set} - # * `source` (optional) {String}. See {::set} - unset: (keyPath, options) -> - if typeof options is 'string' - Grim.deprecate """ - Passing a scope selector as the first argument to Config::unset is deprecated. - Pass a `scopeSelector` in an options hash as the second argument instead. - """ - scopeSelector = keyPath - keyPath = options - else - {scopeSelector, source} = options ? {} - - if source and not scopeSelector - throw new Error("::unset with a 'source' and no 'sourceSelector' is not yet implemented!") - - source ?= @getUserConfigPath() - - if scopeSelector? - if keyPath? - settings = @scopedSettingsStore.propertiesForSourceAndSelector(source, scopeSelector) - if _.valueForKeyPath(settings, keyPath)? - @scopedSettingsStore.removePropertiesForSourceAndSelector(source, scopeSelector) - _.setValueForKeyPath(settings, keyPath, undefined) - settings = withoutEmptyObjects(settings) - @addScopedSettings(source, scopeSelector, settings, priority: @usersScopedSettingPriority) if settings? - @save() unless @configFileHasErrors - else - @scopedSettingsStore.removePropertiesForSource(source) - else - @set(keyPath, _.valueForKeyPath(@defaultSettings, keyPath)) - - # Deprecated: Restore the global setting at `keyPath` to its default value. # # Returns the new value. restoreDefault: (scopeSelector, keyPath) -> - Grim.deprecate("Use ::unset instead.") - @unset(scopeSelector, keyPath) - @get(keyPath) + if arguments.length == 1 + keyPath = scopeSelector + scopeSelector = null - # Deprecated: Get the global default value of the key path. _Please note_ that in most + if scopeSelector? + settings = @scopedSettingsStore.propertiesForSourceAndSelector('user-config', scopeSelector) + if _.valueForKeyPath(settings, keyPath)? + @scopedSettingsStore.removePropertiesForSourceAndSelector('user-config', scopeSelector) + _.setValueForKeyPath(settings, keyPath, undefined) + settings = withoutEmptyObjects(settings) + @addScopedSettings('user-config', scopeSelector, settings, @usersScopedSettingPriority) if settings? + @save() unless @configFileHasErrors + @getDefault(scopeSelector, keyPath) + else + @set(keyPath, _.valueForKeyPath(@defaultSettings, keyPath)) + @get(keyPath) + + # Extended: Get the global default value of the key path. _Please note_ that in most # cases calling this is not necessary! {::get} returns the default value when # a custom value is not specified. # @@ -620,30 +558,35 @@ class Config # * `keyPath` The {String} name of the key. # # Returns the default value. - getDefault: -> - Grim.deprecate("Use `::get(keyPath, {scope, excludeSources: [atom.config.getUserConfigPath()]})` instead") - if arguments.length is 1 - [keyPath] = arguments - else - [scopeSelector, keyPath] = arguments - scope = [scopeSelector] - @get(keyPath, {scope, excludeSources: [@getUserConfigPath()]}) + getDefault: (scopeSelector, keyPath) -> + if arguments.length == 1 + keyPath = scopeSelector + scopeSelector = null - # Deprecated: Is the value at `keyPath` its default value? + if scopeSelector? + defaultValue = @scopedSettingsStore.getPropertyValue(scopeSelector, keyPath, excludeSources: ['user-config']) + defaultValue ?= _.valueForKeyPath(@defaultSettings, keyPath) + else + defaultValue = _.valueForKeyPath(@defaultSettings, keyPath) + _.deepClone(defaultValue) + + # Extended: Is the value at `keyPath` its default value? # # * `scopeSelector` (optional) {String}. eg. '.source.ruby' # * `keyPath` The {String} name of the key. # # Returns a {Boolean}, `true` if the current value is the default, `false` # otherwise. - isDefault: -> - Grim.deprecate("Use `not ::get(keyPath, {scope, sources: [atom.config.getUserConfigPath()]})?` instead") - if arguments.length is 1 - [keyPath] = arguments + isDefault: (scopeSelector, keyPath) -> + if arguments.length == 1 + keyPath = scopeSelector + scopeSelector = null + + if scopeSelector? + settings = @scopedSettingsStore.propertiesForSourceAndSelector('user-config', scopeSelector) + not _.valueForKeyPath(settings, keyPath)? else - [scopeSelector, keyPath] = arguments - scope = [scopeSelector] - not @get(keyPath, {scope, sources: [@getUserConfigPath()]})? + not _.valueForKeyPath(@settings, keyPath)? # Extended: Retrieve the schema for a specific key path. The schema will tell # you what type the keyPath expects, and other metadata about the config @@ -796,7 +739,7 @@ class Config save: -> allSettings = global: @settings - allSettings = _.extend allSettings, @scopedSettingsStore.propertiesForSource(@getUserConfigPath()) + allSettings = _.extend allSettings, @scopedSettingsStore.propertiesForSource('user-config') CSON.writeFileSync(@configFilePath, allSettings) ### @@ -841,11 +784,9 @@ class Config catch e console.warn("'#{keyPath}' could not be set. Attempted value: #{JSON.stringify(value)}; Schema: #{JSON.stringify(@getSchema(keyPath))}") - getRawValue: (keyPath, options) -> - unless options?.excludeSources?.indexOf(@getUserConfigPath()) >= 0 - value = _.valueForKeyPath(@settings, keyPath) - unless options?.sources?.length > 0 - defaultValue = _.valueForKeyPath(@defaultSettings, keyPath) + getRawValue: (keyPath) -> + value = _.valueForKeyPath(@settings, keyPath) + defaultValue = _.valueForKeyPath(@defaultSettings, keyPath) if value? value = _.deepClone(value) @@ -944,7 +885,7 @@ class Config resetUserScopedSettings: (newScopedSettings) -> @usersScopedSettings?.dispose() @usersScopedSettings = new CompositeDisposable - @usersScopedSettings.add @scopedSettingsStore.addProperties(@getUserConfigPath(), newScopedSettings, priority: @prioritiesBySource[@getUserConfigPath()]) + @usersScopedSettings.add @scopedSettingsStore.addProperties('user-config', newScopedSettings, @usersScopedSettingPriority) @emitter.emit 'did-change' addScopedSettings: (source, selector, value, options) -> @@ -956,7 +897,7 @@ class Config disposable.dispose() @emitter.emit 'did-change' - setRawScopedValue: (source, selector, keyPath, value) -> + setRawScopedValue: (selector, keyPath, value) -> if keyPath? newValue = {} _.setValueForKeyPath(newValue, keyPath, value) @@ -964,29 +905,29 @@ class Config settingsBySelector = {} settingsBySelector[selector] = value - @usersScopedSettings.add @scopedSettingsStore.addProperties(source, settingsBySelector, priority: @prioritiesBySource[source]) + @usersScopedSettings.add @scopedSettingsStore.addProperties('user-config', settingsBySelector, @usersScopedSettingPriority) @emitter.emit 'did-change' - getRawScopedValue: (scopeDescriptor, keyPath, options) -> + getRawScopedValue: (scopeDescriptor, keyPath) -> scopeDescriptor = ScopeDescriptor.fromObject(scopeDescriptor) - @scopedSettingsStore.getPropertyValue(scopeDescriptor.getScopeChain(), keyPath, options) + @scopedSettingsStore.getPropertyValue(scopeDescriptor.getScopeChain(), keyPath) - observeScopedKeyPath: (scope, keyPath, callback) -> - oldValue = @get(keyPath, {scope}) + observeScopedKeyPath: (scopeDescriptor, keyPath, callback) -> + oldValue = @get(scopeDescriptor, keyPath) callback(oldValue) didChange = => - newValue = @get(keyPath, {scope}) + newValue = @get(scopeDescriptor, keyPath) callback(newValue) unless _.isEqual(oldValue, newValue) oldValue = newValue @emitter.on 'did-change', didChange - onDidChangeScopedKeyPath: (scope, keyPath, callback) -> - oldValue = @get(keyPath, {scope}) + onDidChangeScopedKeyPath: (scopeDescriptor, keyPath, callback) -> + oldValue = @get(scopeDescriptor, keyPath) didChange = => - newValue = @get(keyPath, {scope}) + newValue = @get(scopeDescriptor, keyPath) callback({oldValue, newValue, keyPath}) unless _.isEqual(oldValue, newValue) oldValue = newValue diff --git a/src/cursor.coffee b/src/cursor.coffee index 421ddc014..5bbd0e0e6 100644 --- a/src/cursor.coffee +++ b/src/cursor.coffee @@ -202,7 +202,7 @@ class Cursor extends Model [before, after] = @editor.getTextInBufferRange(range) return false if /\s/.test(before) or /\s/.test(after) - nonWordCharacters = atom.config.get('editor.nonWordCharacters', scope: @getScopeDescriptor()).split('') + nonWordCharacters = atom.config.get(@getScopeDescriptor(), 'editor.nonWordCharacters').split('') _.contains(nonWordCharacters, before) isnt _.contains(nonWordCharacters, after) # Public: Returns whether this cursor is between a word's start and end. @@ -636,7 +636,7 @@ class Cursor extends Model # Returns a {RegExp}. wordRegExp: ({includeNonWordCharacters}={}) -> includeNonWordCharacters ?= true - nonWordCharacters = atom.config.get('editor.nonWordCharacters', scope: @getScopeDescriptor()) + nonWordCharacters = atom.config.get(@getScopeDescriptor(), 'editor.nonWordCharacters') segments = ["^[\t ]*$"] segments.push("[^\\s#{_.escapeRegExp(nonWordCharacters)}]+") if includeNonWordCharacters diff --git a/src/display-buffer.coffee b/src/display-buffer.coffee index 8b2940000..edda951fb 100644 --- a/src/display-buffer.coffee +++ b/src/display-buffer.coffee @@ -67,24 +67,24 @@ class DisplayBuffer extends Model oldConfigSettings = @configSettings @configSettings = - scrollPastEnd: atom.config.get('editor.scrollPastEnd', scope: scopeDescriptor) - softWrap: atom.config.get('editor.softWrap', scope: scopeDescriptor) - softWrapAtPreferredLineLength: atom.config.get('editor.softWrapAtPreferredLineLength', scope: scopeDescriptor) - preferredLineLength: atom.config.get('editor.preferredLineLength', scope: scopeDescriptor) + scrollPastEnd: atom.config.get(scopeDescriptor, 'editor.scrollPastEnd') + softWrap: atom.config.get(scopeDescriptor, 'editor.softWrap') + softWrapAtPreferredLineLength: atom.config.get(scopeDescriptor, 'editor.softWrapAtPreferredLineLength') + preferredLineLength: atom.config.get(scopeDescriptor, 'editor.preferredLineLength') - subscriptions.add atom.config.onDidChange 'editor.softWrap', scope: scopeDescriptor, ({newValue}) => + subscriptions.add atom.config.onDidChange scopeDescriptor, 'editor.softWrap', ({newValue}) => @configSettings.softWrap = newValue @updateWrappedScreenLines() - subscriptions.add atom.config.onDidChange 'editor.softWrapAtPreferredLineLength', scope: scopeDescriptor, ({newValue}) => + subscriptions.add atom.config.onDidChange scopeDescriptor, 'editor.softWrapAtPreferredLineLength', ({newValue}) => @configSettings.softWrapAtPreferredLineLength = newValue @updateWrappedScreenLines() if @isSoftWrapped() - subscriptions.add atom.config.onDidChange 'editor.preferredLineLength', scope: scopeDescriptor, ({newValue}) => + subscriptions.add atom.config.onDidChange scopeDescriptor, 'editor.preferredLineLength', ({newValue}) => @configSettings.preferredLineLength = newValue - @updateWrappedScreenLines() if @isSoftWrapped() and atom.config.get('editor.softWrapAtPreferredLineLength', scope: scopeDescriptor) + @updateWrappedScreenLines() if @isSoftWrapped() and atom.config.get(scopeDescriptor, 'editor.softWrapAtPreferredLineLength') - subscriptions.add atom.config.observe 'editor.scrollPastEnd', scope: scopeDescriptor, (value) => + subscriptions.add atom.config.observe scopeDescriptor, 'editor.scrollPastEnd', (value) => @configSettings.scrollPastEnd = value @updateWrappedScreenLines() if oldConfigSettings? and not _.isEqual(oldConfigSettings, @configSettings) diff --git a/src/language-mode.coffee b/src/language-mode.coffee index 17aad9777..bb600ca34 100644 --- a/src/language-mode.coffee +++ b/src/language-mode.coffee @@ -316,7 +316,7 @@ class LanguageMode @editor.setIndentationForBufferRow(bufferRow, desiredIndentLevel) getRegexForProperty: (scopeDescriptor, property) -> - if pattern = atom.config.get(property, scope: scopeDescriptor) + if pattern = atom.config.get(scopeDescriptor, property) new OnigRegExp(pattern) increaseIndentRegexForScopeDescriptor: (scopeDescriptor) -> diff --git a/src/text-editor-component.coffee b/src/text-editor-component.coffee index 9bd484f6b..51c4447b6 100644 --- a/src/text-editor-component.coffee +++ b/src/text-editor-component.coffee @@ -462,9 +462,9 @@ TextEditorComponent = React.createClass scopeDescriptor = editor.getRootScopeDescriptor() - subscriptions.add atom.config.observe 'editor.showIndentGuide', scope: scopeDescriptor, @setShowIndentGuide - subscriptions.add atom.config.observe 'editor.showLineNumbers', scope: scopeDescriptor, @setShowLineNumbers - subscriptions.add atom.config.observe 'editor.scrollSensitivity', scope: scopeDescriptor, @setScrollSensitivity + subscriptions.add atom.config.observe scopeDescriptor, 'editor.showIndentGuide', @setShowIndentGuide + subscriptions.add atom.config.observe scopeDescriptor, 'editor.showLineNumbers', @setShowLineNumbers + subscriptions.add atom.config.observe scopeDescriptor, 'editor.scrollSensitivity', @setScrollSensitivity focused: -> if @isMounted() diff --git a/src/text-editor.coffee b/src/text-editor.coffee index 1263936e0..29f50fd0f 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -168,8 +168,8 @@ class TextEditor extends Model scopeDescriptor = @getRootScopeDescriptor() - subscriptions.add atom.config.onDidChange 'editor.showInvisibles', scope: scopeDescriptor, => @updateInvisibles() - subscriptions.add atom.config.onDidChange 'editor.invisibles', scope: scopeDescriptor, => @updateInvisibles() + subscriptions.add atom.config.onDidChange scopeDescriptor, 'editor.showInvisibles', => @updateInvisibles() + subscriptions.add atom.config.onDidChange scopeDescriptor, 'editor.invisibles', => @updateInvisibles() getViewClass: -> require './text-editor-view' @@ -2812,17 +2812,17 @@ class TextEditor extends Model ### shouldAutoIndent: -> - atom.config.get("editor.autoIndent", scope: @getRootScopeDescriptor()) + atom.config.get(@getRootScopeDescriptor(), "editor.autoIndent") shouldAutoIndentOnPaste: -> - atom.config.get("editor.autoIndentOnPaste", scope: @getRootScopeDescriptor()) + atom.config.get(@getRootScopeDescriptor(), "editor.autoIndentOnPaste") shouldShowInvisibles: -> - not @mini and atom.config.get('editor.showInvisibles', scope: @getRootScopeDescriptor()) + not @mini and atom.config.get(@getRootScopeDescriptor(), 'editor.showInvisibles') updateInvisibles: -> if @shouldShowInvisibles() - @displayBuffer.setInvisibles(atom.config.get('editor.invisibles', scope: @getRootScopeDescriptor())) + @displayBuffer.setInvisibles(atom.config.get(@getRootScopeDescriptor(), 'editor.invisibles')) else @displayBuffer.setInvisibles(null) diff --git a/src/tokenized-buffer.coffee b/src/tokenized-buffer.coffee index 5557ea9ac..8b7ba7a01 100644 --- a/src/tokenized-buffer.coffee +++ b/src/tokenized-buffer.coffee @@ -84,10 +84,10 @@ class TokenizedBuffer extends Model @currentGrammarScore = score ? grammar.getScore(@buffer.getPath(), @buffer.getText()) @subscribe @grammar.onDidUpdate => @retokenizeLines() - @configSettings = tabLength: atom.config.get('editor.tabLength', scope: @rootScopeDescriptor) + @configSettings = tabLength: atom.config.get(@rootScopeDescriptor, 'editor.tabLength') @grammarTabLengthSubscription?.dispose() - @grammarTabLengthSubscription = atom.config.onDidChange 'editor.tabLength', scope: @rootScopeDescriptor, ({newValue}) => + @grammarTabLengthSubscription = atom.config.onDidChange @rootScopeDescriptor, 'editor.tabLength', ({newValue}) => @configSettings.tabLength = newValue @retokenizeLines() @subscribe @grammarTabLengthSubscription diff --git a/src/workspace.coffee b/src/workspace.coffee index 30a38cbf3..98630f7c2 100644 --- a/src/workspace.coffee +++ b/src/workspace.coffee @@ -645,7 +645,7 @@ class Workspace extends Model # Restore to a default editor font size. resetFontSize: -> - atom.config.unset("editor.fontSize") + atom.config.restoreDefault("editor.fontSize") # Removes the item's uri from the list of potential items to reopen. itemOpened: (item) ->