diff --git a/spec/config-spec.coffee b/spec/config-spec.coffee index 666c76b3d..0c9251054 100644 --- a/spec/config-spec.coffee +++ b/spec/config-spec.coffee @@ -448,6 +448,32 @@ describe "Config", -> expect(atom.config.get('foo.bar')).toBe 'quux' expect(atom.config.get('foo.baz')).toBe 'bar' + 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', 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.omg')).toBe 'ok' + + describe 'when the default value is a complex value', -> + beforeEach -> + 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", -> + atom.config.onDidChange 'foo.bar', noChangeSpy = jasmine.createSpy() + + 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.omg')).toBe 'another' + describe "when the config file changes to omit a setting with a default", -> it "resets the setting back to the default", -> fs.writeFileSync(atom.config.configFilePath, "foo: { baz: 'new'}") diff --git a/src/config.coffee b/src/config.coffee index 96be654be..56d3efa9d 100644 --- a/src/config.coffee +++ b/src/config.coffee @@ -533,11 +533,7 @@ class Config try userConfig = CSON.readFileSync(@configFilePath) - @settings = {} # Reset to the defaults - if isPlainObject(userConfig) - @setRecursive(null, userConfig) - else - @emitter.emit 'did-change' + @setAll(userConfig) @configFileHasErrors = false catch error @configFileHasErrors = true @@ -566,16 +562,16 @@ class Config oldValue = _.clone(@get(keyPath)) _.setValueForKeyPath(@settings, keyPath, value) newValue = @get(keyPath) - @emitter.emit 'did-change', {oldValue, newValue, keyPath} if newValue isnt oldValue + @emitter.emit 'did-change', {oldValue, newValue, keyPath} unless _.isEqual(newValue, oldValue) setRawDefault: (keyPath, value) -> oldValue = _.clone(@get(keyPath)) _.setValueForKeyPath(@defaultSettings, keyPath, value) newValue = @get(keyPath) - @emitter.emit 'did-change', {oldValue, newValue, keyPath} if newValue isnt oldValue + @emitter.emit 'did-change', {oldValue, newValue, keyPath} unless _.isEqual(newValue, oldValue) setRecursive: (keyPath, value) -> - if value? and isPlainObject(value) + if isPlainObject(value) keys = if keyPath? then keyPath.split('.') else [] for key, childValue of value continue unless value.hasOwnProperty(key) @@ -587,7 +583,24 @@ class Config catch e console.warn("'#{keyPath}' could not be set. Attempted value: #{JSON.stringify(value)}; Schema: #{JSON.stringify(@getSchema(keyPath))}") - return + setAll: (newSettings) -> + unless isPlainObject(newSettings) + @settings = {} + @emitter.emit 'did-change' + return + + unsetUnspecifiedValues = (keyPath, value) => + if isPlainObject(value) + keys = if keyPath? then keyPath.split('.') else [] + for key, childValue of value + continue unless value.hasOwnProperty(key) + unsetUnspecifiedValues(keys.concat([key]).join('.'), childValue) + else + @setRawValue(keyPath, undefined) unless _.valueForKeyPath(newSettings, keyPath)? + return + + @setRecursive(null, newSettings) + unsetUnspecifiedValues(null, @settings) setDefaults: (keyPath, defaults) -> if defaults? and isPlainObject(defaults)