mirror of
https://github.com/atom/atom.git
synced 2026-01-24 06:18:03 -05:00
Implement scoped config settings
You can pass a scope stack when calling `config.get`, which will prefer settings under the most specific matching scope selector for the given scope stack.
This commit is contained in:
@@ -1,19 +1,32 @@
|
||||
describe "Config", ->
|
||||
describe ".get(keyPath) and .set(keyPath, value)", ->
|
||||
it "allows a key path's value to be read and written", ->
|
||||
expect(config.set("foo.bar.baz", 42)).toBe 42
|
||||
expect(config.get("foo.bar.baz")).toBe 42
|
||||
expect(config.get("bogus.key.path")).toBeUndefined()
|
||||
describe ".get([scope], keyPath) and .set([scope], keyPath, value)", ->
|
||||
describe "when called without a scope argument", ->
|
||||
it "allows a key path's value to be read and written", ->
|
||||
expect(config.set("foo.bar.baz", 42)).toBe 42
|
||||
expect(config.get("foo.bar.baz")).toBe 42
|
||||
expect(config.get("bogus.key.path")).toBeUndefined()
|
||||
|
||||
it "updates observers and saves when a key path is set", ->
|
||||
observeHandler = jasmine.createSpy "observeHandler"
|
||||
config.observe "foo.bar.baz", observeHandler
|
||||
observeHandler.reset()
|
||||
it "updates observers and saves when a key path is set", ->
|
||||
observeHandler = jasmine.createSpy "observeHandler"
|
||||
config.observe "foo.bar.baz", observeHandler
|
||||
observeHandler.reset()
|
||||
|
||||
config.set("foo.bar.baz", 42)
|
||||
config.set("foo.bar.baz", 42)
|
||||
|
||||
expect(config.save).toHaveBeenCalled()
|
||||
expect(observeHandler).toHaveBeenCalledWith 42
|
||||
expect(config.save).toHaveBeenCalled()
|
||||
expect(observeHandler).toHaveBeenCalledWith 42
|
||||
|
||||
describe "when called with a scope argument", ->
|
||||
it "returns the config value for the most specific selector", ->
|
||||
expect(config.set(".source.coffee .string.quoted.double.coffee", "foo.bar.baz", 42)).toBe 42
|
||||
config.set(".source .string.quoted.double", "foo.bar.baz", 22)
|
||||
config.set(".source", "foo.bar.baz", 11)
|
||||
config.set("foo.bar.baz", 1)
|
||||
|
||||
expect(config.get([".source.coffee", ".string.quoted.double.coffee"], "foo.bar.baz")).toBe 42
|
||||
expect(config.get([".source.js", ".string.quoted.double.js"], "foo.bar.baz")).toBe 22
|
||||
expect(config.get([".source.js", ".variable.assignment.js"], "foo.bar.baz")).toBe 11
|
||||
expect(config.get([".text"], "foo.bar.baz")).toBe 1
|
||||
|
||||
describe ".setDefaults(keyPath, defaults)", ->
|
||||
it "assigns any previously-unassigned keys to the object at the key path", ->
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
fs = require 'fs'
|
||||
_ = require 'underscore'
|
||||
EventEmitter = require 'event-emitter'
|
||||
{$$} = require 'space-pen'
|
||||
jQuery = require 'jquery'
|
||||
Specificity = require 'specificity'
|
||||
|
||||
configDirPath = fs.absolute("~/.atom")
|
||||
configJsonPath = fs.join(configDirPath, "config.json")
|
||||
@@ -31,15 +34,33 @@ class Config
|
||||
userConfig = JSON.parse(fs.read(configJsonPath))
|
||||
_.extend(@settings, userConfig)
|
||||
|
||||
get: (keyPath) ->
|
||||
get: (args...) ->
|
||||
scopeStack = args.shift() if args.length > 1
|
||||
keyPath = args.shift()
|
||||
keys = @keysForKeyPath(keyPath)
|
||||
value = @settings
|
||||
for key in keys
|
||||
break unless value = value[key]
|
||||
value
|
||||
|
||||
set: (keyPath, value) ->
|
||||
settingsToSearch = []
|
||||
settingsToSearch.push(@settingsForScopeChain(scopeStack)...) if scopeStack
|
||||
settingsToSearch.push(@settings)
|
||||
|
||||
for settings in settingsToSearch
|
||||
value = settings
|
||||
for key in keys
|
||||
value = value[key]
|
||||
break unless value?
|
||||
return value if value?
|
||||
undefined
|
||||
|
||||
set: (args...) ->
|
||||
scope = args.shift() if args.length > 2
|
||||
keyPath = args.shift()
|
||||
value = args.shift()
|
||||
|
||||
keys = @keysForKeyPath(keyPath)
|
||||
if scope
|
||||
keys.unshift(scope)
|
||||
keys.unshift('scopes')
|
||||
|
||||
hash = @settings
|
||||
while keys.length > 1
|
||||
key = keys.shift()
|
||||
@@ -60,12 +81,6 @@ class Config
|
||||
_.defaults hash, defaults
|
||||
@update()
|
||||
|
||||
keysForKeyPath: (keyPath) ->
|
||||
if typeof keyPath is 'string'
|
||||
keyPath.split(".")
|
||||
else
|
||||
new Array(keyPath...)
|
||||
|
||||
observe: (keyPath, callback) ->
|
||||
value = @get(keyPath)
|
||||
previousValue = _.clone(value)
|
||||
@@ -87,6 +102,46 @@ class Config
|
||||
save: ->
|
||||
fs.write(configJsonPath, JSON.stringify(@settings, undefined, 2) + "\n")
|
||||
|
||||
keysForKeyPath: (keyPath) ->
|
||||
if typeof keyPath is 'string'
|
||||
keyPath.split(".")
|
||||
else
|
||||
new Array(keyPath...)
|
||||
|
||||
settingsForScopeChain: (scopeStack) ->
|
||||
return [] unless @settings.scopes?
|
||||
|
||||
matchingScopeSelectors = []
|
||||
node = @buildDomNodeFromScopeChain(scopeStack)
|
||||
while node
|
||||
scopeSelectorsForNode = []
|
||||
for scopeSelector of @settings.scopes
|
||||
if jQuery.find.matchesSelector(node, scopeSelector)
|
||||
scopeSelectorsForNode.push(scopeSelector)
|
||||
scopeSelectorsForNode.sort (a, b) -> Specificity(b) - Specificity(a)
|
||||
matchingScopeSelectors.push(scopeSelectorsForNode...)
|
||||
node = node.parentNode
|
||||
|
||||
matchingScopeSelectors.map (scopeSelector) => @settings.scopes[scopeSelector]
|
||||
|
||||
buildDomNodeFromScopeChain: (scopeStack) ->
|
||||
scopeStack = new Array(scopeStack...)
|
||||
element = $$ ->
|
||||
elementsForRemainingScopes = =>
|
||||
classString = scopeStack.shift()
|
||||
classes = classString.replace(/^\./, '').replace(/\./g, ' ')
|
||||
if scopeStack.length
|
||||
@div class: classes, elementsForRemainingScopes
|
||||
else
|
||||
@div class: classes
|
||||
elementsForRemainingScopes()
|
||||
|
||||
deepestChild = element.find(":not(:has(*))")
|
||||
if deepestChild.length
|
||||
deepestChild[0]
|
||||
else
|
||||
element[0]
|
||||
|
||||
requireUserInitScript: ->
|
||||
try
|
||||
require userInitScriptPath if fs.exists(userInitScriptPath)
|
||||
|
||||
Reference in New Issue
Block a user