mirror of
https://github.com/atom/atom.git
synced 2026-02-05 20:25:04 -05:00
189 lines
6.1 KiB
CoffeeScript
189 lines
6.1 KiB
CoffeeScript
fsUtils = require 'fs-utils'
|
|
_ = require 'underscore'
|
|
EventEmitter = require 'event-emitter'
|
|
CSON = require 'cson'
|
|
fs = require 'fs'
|
|
async = require 'async'
|
|
pathWatcher = require 'pathwatcher'
|
|
|
|
configDirPath = fsUtils.absolute("~/.atom")
|
|
bundledPackagesDirPath = fsUtils.join(resourcePath, "src/packages")
|
|
bundledThemesDirPath = fsUtils.join(resourcePath, "themes")
|
|
vendoredPackagesDirPath = fsUtils.join(resourcePath, "vendor/packages")
|
|
vendoredThemesDirPath = fsUtils.join(resourcePath, "vendor/themes")
|
|
userThemesDirPath = fsUtils.join(configDirPath, "themes")
|
|
userPackagesDirPath = fsUtils.join(configDirPath, "packages")
|
|
|
|
# Public: Handles all of Atom's configuration details.
|
|
#
|
|
# This includes loading and setting default options, as well as reading from the
|
|
# user's configuration file.
|
|
module.exports =
|
|
class Config
|
|
configDirPath: configDirPath
|
|
themeDirPaths: [userThemesDirPath, bundledThemesDirPath, vendoredThemesDirPath]
|
|
packageDirPaths: [userPackagesDirPath, vendoredPackagesDirPath, bundledPackagesDirPath]
|
|
userPackagesDirPath: userPackagesDirPath
|
|
lessSearchPaths: [fsUtils.join(resourcePath, 'static'), fsUtils.join(resourcePath, 'vendor')]
|
|
defaultSettings: null
|
|
settings: null
|
|
configFileHasErrors: null
|
|
|
|
### Internal ###
|
|
|
|
constructor: ->
|
|
@defaultSettings =
|
|
core: _.clone(require('root-view').configDefaults)
|
|
editor: _.clone(require('editor').configDefaults)
|
|
@settings = {}
|
|
@configFilePath = fsUtils.resolve(configDirPath, 'config', ['json', 'cson'])
|
|
@configFilePath ?= fsUtils.join(configDirPath, 'config.cson')
|
|
|
|
initializeConfigDirectory: (done) ->
|
|
return if fsUtils.exists(@configDirPath)
|
|
|
|
fsUtils.makeDirectory(@configDirPath)
|
|
|
|
|
|
queue = async.queue ({sourcePath, destinationPath}, callback) =>
|
|
fsUtils.copy(sourcePath, destinationPath, callback)
|
|
queue.drain = done
|
|
|
|
templateConfigDirPath = fsUtils.resolve(window.resourcePath, 'dot-atom')
|
|
onConfigDirFile = (sourcePath) =>
|
|
relativePath = sourcePath.substring(templateConfigDirPath.length + 1)
|
|
destinationPath = fsUtils.join(@configDirPath, relativePath)
|
|
queue.push({sourcePath, destinationPath})
|
|
fsUtils.traverseTree(templateConfigDirPath, onConfigDirFile, (path) -> true)
|
|
|
|
configThemeDirPath = fsUtils.join(@configDirPath, 'themes')
|
|
onThemeDirFile = (sourcePath) ->
|
|
relativePath = sourcePath.substring(bundledThemesDirPath.length + 1)
|
|
destinationPath = fsUtils.join(configThemeDirPath, relativePath)
|
|
queue.push({sourcePath, destinationPath})
|
|
fsUtils.traverseTree(bundledThemesDirPath, onThemeDirFile, (path) -> true)
|
|
|
|
load: ->
|
|
@initializeConfigDirectory()
|
|
@loadUserConfig()
|
|
@observeUserConfig()
|
|
|
|
loadUserConfig: ->
|
|
if fsUtils.exists(@configFilePath)
|
|
try
|
|
userConfig = CSON.readObject(@configFilePath)
|
|
_.extend(@settings, userConfig)
|
|
@configFileHasErrors = false
|
|
@trigger 'updated'
|
|
catch e
|
|
@configFileHasErrors = true
|
|
console.error "Failed to load user config '#{@configFilePath}'", e.message
|
|
console.error e.stack
|
|
|
|
observeUserConfig: ->
|
|
@watchSubscription ?= pathWatcher.watch @configFilePath, (eventType) =>
|
|
@loadUserConfig() if eventType is 'change' and @watchSubscription?
|
|
|
|
unobserveUserConfig: ->
|
|
@watchSubscription?.close()
|
|
@watchSubscription = null
|
|
|
|
setDefaults: (keyPath, defaults) ->
|
|
keys = keyPath.split('.')
|
|
hash = @defaultSettings
|
|
for key in keys
|
|
hash[key] ?= {}
|
|
hash = hash[key]
|
|
|
|
_.extend hash, defaults
|
|
@update()
|
|
|
|
### Public ###
|
|
|
|
# Retrieves the setting for the given key.
|
|
#
|
|
# keyPath - The {String} name of the key to retrieve
|
|
#
|
|
# Returns the value from Atom's default settings, the user's configuration file,
|
|
# or `null` if the key doesn't exist in either.
|
|
get: (keyPath) ->
|
|
_.valueForKeyPath(@settings, keyPath) ?
|
|
_.valueForKeyPath(@defaultSettings, keyPath)
|
|
|
|
|
|
# Retrieves the setting for the given key as an integer.
|
|
#
|
|
# keyPath - The {String} name of the key to retrieve
|
|
#
|
|
# Returns the value from Atom's default settings, the user's configuration file,
|
|
# or `NaN` if the key doesn't exist in either.
|
|
getInt: (keyPath, defaultValueWhenFalsy) ->
|
|
parseInt(@get(keyPath))
|
|
|
|
# Retrieves the setting for the given key as a positive integer.
|
|
#
|
|
# keyPath - The {String} name of the key to retrieve
|
|
# defaultValue - The integer {Number} to fall back to if the value isn't
|
|
# positive
|
|
#
|
|
# Returns the value from Atom's default settings, the user's configuration file,
|
|
# or `defaultValue` if the key value isn't greater than zero.
|
|
getPositiveInt: (keyPath, defaultValue) ->
|
|
Math.max(@getInt(keyPath), 0) or defaultValue
|
|
|
|
# Sets the value for a configuration setting.
|
|
#
|
|
# This value is stored in Atom's internal configuration file.
|
|
#
|
|
# keyPath - The {String} name of the key
|
|
# value - The value of the setting
|
|
#
|
|
# Returns the `value`.
|
|
set: (keyPath, value) ->
|
|
_.setValueForKeyPath(@settings, keyPath, value)
|
|
@update()
|
|
value
|
|
|
|
# Establishes an event listener for a given key.
|
|
#
|
|
# Whenever the value of the key is changed, a callback is fired.
|
|
#
|
|
# keyPath - The {String} name of the key to watch
|
|
# callback - The {Function} that fires when the. It is given a single argument, `value`,
|
|
# which is the new value of `keyPath`.
|
|
observe: (keyPath, callback) ->
|
|
value = @get(keyPath)
|
|
previousValue = _.clone(value)
|
|
updateCallback = =>
|
|
value = @get(keyPath)
|
|
unless _.isEqual(value, previousValue)
|
|
previousValue = _.clone(value)
|
|
callback(value)
|
|
|
|
subscription = { cancel: => @off 'updated', updateCallback }
|
|
@on 'updated', updateCallback
|
|
callback(value)
|
|
subscription
|
|
|
|
### Internal ###
|
|
|
|
setDefaults: (keyPath, defaults) ->
|
|
keys = keyPath.split('.')
|
|
hash = @defaultSettings
|
|
for key in keys
|
|
hash[key] ?= {}
|
|
hash = hash[key]
|
|
|
|
_.extend hash, defaults
|
|
@update()
|
|
|
|
update: ->
|
|
return if @configFileHasErrors
|
|
@save()
|
|
@trigger 'updated'
|
|
|
|
save: ->
|
|
CSON.writeObject(@configFilePath, @settings)
|
|
|
|
_.extend Config.prototype, EventEmitter
|