mirror of
https://github.com/atom/atom.git
synced 2026-02-14 16:45:14 -05:00
Merge branch 'config'
This commit is contained in:
17
src/app/atom-package.coffee
Normal file
17
src/app/atom-package.coffee
Normal file
@@ -0,0 +1,17 @@
|
||||
Package = require 'package'
|
||||
fs = require 'fs'
|
||||
|
||||
module.exports =
|
||||
class AtomPackage extends Package
|
||||
constructor: ->
|
||||
super
|
||||
@module = require(@path)
|
||||
@module.name = @name
|
||||
|
||||
load: ->
|
||||
try
|
||||
rootView.activatePackage(@module)
|
||||
extensionKeymapPath = require.resolve(fs.join(@name, "src/keymap"), verifyExistence: false)
|
||||
require extensionKeymapPath if fs.exists(extensionKeymapPath)
|
||||
catch e
|
||||
console.error "Failed to load package named '#{name}'", e.stack
|
||||
11
src/app/atom-theme.coffee
Normal file
11
src/app/atom-theme.coffee
Normal file
@@ -0,0 +1,11 @@
|
||||
fs = require 'fs'
|
||||
Theme = require 'theme'
|
||||
|
||||
module.exports =
|
||||
class AtomTheme extends Theme
|
||||
constructor: (@path) ->
|
||||
super
|
||||
json = fs.read(fs.join(path, "package.json"))
|
||||
for stylesheetName in JSON.parse(json).stylesheets
|
||||
stylesheetPath = fs.join(@path, stylesheetName)
|
||||
@stylesheets[stylesheetPath] = fs.read(stylesheetPath)
|
||||
@@ -1,5 +1,8 @@
|
||||
TextMateBundle = require("text-mate-bundle")
|
||||
fs = require 'fs'
|
||||
_ = require 'underscore'
|
||||
Package = require 'package'
|
||||
TextMatePackage = require 'text-mate-package'
|
||||
|
||||
messageIdCounter = 1
|
||||
originalSendMessageToBrowserProcess = atom.sendMessageToBrowserProcess
|
||||
@@ -9,18 +12,25 @@ _.extend atom,
|
||||
|
||||
pendingBrowserProcessCallbacks: {}
|
||||
|
||||
getAvailablePackages: ->
|
||||
allPackageNames = []
|
||||
for packageDirPath in config.packageDirPaths
|
||||
packageNames = fs.list(packageDirPath)
|
||||
.filter((packagePath) -> fs.isDirectory(packagePath))
|
||||
.map((packagePath) -> fs.base(packagePath))
|
||||
allPackageNames.push(packageNames...)
|
||||
_.unique(allPackageNames)
|
||||
|
||||
getAvailableTextMateBundles: ->
|
||||
@getAvailablePackages().filter (packageName) => TextMatePackage.testName(packageName)
|
||||
|
||||
loadPackages: (packageNames=@getAvailablePackages()) ->
|
||||
disabledPackages = config.get("core.disabledPackages") ? []
|
||||
for packageName in packageNames
|
||||
@loadPackage(packageName) unless _.contains(disabledPackages, packageName)
|
||||
|
||||
loadPackage: (name) ->
|
||||
try
|
||||
packagePath = require.resolve(name, verifyExistence: false)
|
||||
throw new Error("No package found named '#{name}'") unless packagePath
|
||||
packagePath = fs.directory(packagePath)
|
||||
extension = require(packagePath)
|
||||
extension.name = name
|
||||
rootView.activateExtension(extension)
|
||||
extensionKeymapPath = require.resolve(fs.join(name, "src/keymap"), verifyExistence: false)
|
||||
require extensionKeymapPath if fs.exists(extensionKeymapPath)
|
||||
catch e
|
||||
console.error "Failed to load package named '#{name}'", e.stack
|
||||
Package.forName(name).load()
|
||||
|
||||
open: (args...) ->
|
||||
@sendMessageToBrowserProcess('open', args)
|
||||
@@ -85,4 +95,3 @@ _.extend atom,
|
||||
if name is 'reply'
|
||||
[messageId, callbackIndex] = data.shift()
|
||||
@pendingBrowserProcessCallbacks[messageId]?[callbackIndex]?(data...)
|
||||
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
fs = require 'fs'
|
||||
_ = require 'underscore'
|
||||
EventEmitter = require 'event-emitter'
|
||||
{$$} = require 'space-pen'
|
||||
jQuery = require 'jquery'
|
||||
Specificity = require 'specificity'
|
||||
Theme = require 'theme'
|
||||
|
||||
configDirPath = fs.absolute("~/.atom")
|
||||
configJsonPath = fs.join(configDirPath, "config.json")
|
||||
userInitScriptPath = fs.join(configDirPath, "atom.coffee")
|
||||
bundledThemesDirPath = fs.join(resourcePath, "themes")
|
||||
bundledPackagesDirPath = fs.join(resourcePath, "src/packages")
|
||||
userThemesDirPath = fs.join(configDirPath, "themes")
|
||||
userPackagesDirPath = fs.join(configDirPath, "packages")
|
||||
|
||||
require.paths.unshift userPackagesDirPath
|
||||
@@ -13,46 +19,31 @@ require.paths.unshift userPackagesDirPath
|
||||
module.exports =
|
||||
class Config
|
||||
configDirPath: configDirPath
|
||||
themeDirPaths: [userThemesDirPath, bundledThemesDirPath]
|
||||
packageDirPaths: [userPackagesDirPath, bundledPackagesDirPath]
|
||||
settings: null
|
||||
|
||||
constructor: ->
|
||||
@settings =
|
||||
core: _.clone(require('root-view').configDefaults)
|
||||
editor: _.clone(require('editor').configDefaults)
|
||||
|
||||
load: ->
|
||||
@settings = {}
|
||||
@loadUserConfig()
|
||||
@assignDefaults()
|
||||
@loadPackages()
|
||||
@requireUserInitScript()
|
||||
atom.loadPackages()
|
||||
Theme.load(config.get("core.theme") ? 'IR_Black')
|
||||
|
||||
loadUserConfig: ->
|
||||
if fs.exists(configJsonPath)
|
||||
userConfig = JSON.parse(fs.read(configJsonPath))
|
||||
_.extend(@settings, userConfig)
|
||||
|
||||
assignDefaults: ->
|
||||
@settings ?= {}
|
||||
@setDefaults "core", require('root-view').configDefaults
|
||||
@setDefaults "editor", require('editor').configDefaults
|
||||
|
||||
getAvailablePackages: ->
|
||||
availablePackages =
|
||||
fs.list(bundledPackagesDirPath)
|
||||
.concat(fs.list(userPackagesDirPath)).map (path) -> fs.base(path)
|
||||
_.unique(availablePackages)
|
||||
|
||||
loadPackages: ->
|
||||
disabledPackages = config.get("core.disabledPackages") ? []
|
||||
for packageName in @getAvailablePackages()
|
||||
unless _.contains disabledPackages, packageName
|
||||
atom.loadPackage(packageName)
|
||||
|
||||
get: (keyPath) ->
|
||||
keys = @keysForKeyPath(keyPath)
|
||||
value = @settings
|
||||
for key in keys
|
||||
break unless value = value[key]
|
||||
value
|
||||
_.valueForKeyPath(@settings, keyPath)
|
||||
|
||||
set: (keyPath, value) ->
|
||||
keys = @keysForKeyPath(keyPath)
|
||||
keys = keyPath.split('.')
|
||||
hash = @settings
|
||||
while keys.length > 1
|
||||
key = keys.shift()
|
||||
@@ -64,7 +55,7 @@ class Config
|
||||
value
|
||||
|
||||
setDefaults: (keyPath, defaults) ->
|
||||
keys = @keysForKeyPath(keyPath)
|
||||
keys = keyPath.split('.')
|
||||
hash = @settings
|
||||
for key in keys
|
||||
hash[key] ?= {}
|
||||
@@ -73,12 +64,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)
|
||||
|
||||
@@ -3,7 +3,6 @@ _ = require 'underscore'
|
||||
fs = require 'fs'
|
||||
|
||||
BindingSet = require 'binding-set'
|
||||
Specificity = require 'specificity'
|
||||
|
||||
module.exports =
|
||||
class Keymap
|
||||
|
||||
@@ -67,14 +67,14 @@ class LanguageMode
|
||||
|
||||
toggleLineCommentsForBufferRows: (start, end) ->
|
||||
scopes = @editSession.scopesForBufferPosition([start, 0])
|
||||
return unless commentStartString = TextMateBundle.lineCommentStartStringForScope(scopes[0])
|
||||
return unless commentStartString = syntax.getProperty(scopes, "editor.commentStart")
|
||||
|
||||
buffer = @editSession.buffer
|
||||
commentStartRegexString = _.escapeRegExp(commentStartString).replace(/(\s+)$/, '($1)?')
|
||||
commentStartRegex = new OnigRegExp("^(\\s*)(#{commentStartRegexString})")
|
||||
shouldUncomment = commentStartRegex.test(buffer.lineForRow(start))
|
||||
|
||||
if commentEndString = TextMateBundle.lineCommentEndStringForScope(scopes[0])
|
||||
if commentEndString = syntax.getProperty(scopes, "editor.commentEnd")
|
||||
if shouldUncomment
|
||||
commentEndRegexString = _.escapeRegExp(commentEndString).replace(/^(\s+)/, '($1)?')
|
||||
commentEndRegex = new OnigRegExp("(#{commentEndRegexString})(\\s*)$")
|
||||
@@ -119,7 +119,7 @@ class LanguageMode
|
||||
continue if @editSession.isBufferRowBlank(row)
|
||||
indentation = @editSession.indentationForBufferRow(row)
|
||||
if indentation <= startIndentLevel
|
||||
includeRowInFold = indentation == startIndentLevel and TextMateBundle.foldEndRegexForScope(@grammar, scopes[0]).search(@editSession.lineForBufferRow(row))
|
||||
includeRowInFold = indentation == startIndentLevel and @foldEndRegexForScopes(scopes).search(@editSession.lineForBufferRow(row))
|
||||
foldEndRow = row if includeRowInFold
|
||||
break
|
||||
|
||||
@@ -130,7 +130,7 @@ class LanguageMode
|
||||
suggestedIndentForBufferRow: (bufferRow) ->
|
||||
currentIndentLevel = @editSession.indentationForBufferRow(bufferRow)
|
||||
scopes = @editSession.scopesForBufferPosition([bufferRow, 0])
|
||||
return currentIndentLevel unless increaseIndentPattern = TextMateBundle.indentRegexForScope(scopes[0])
|
||||
return currentIndentLevel unless increaseIndentRegex = @increaseIndentRegexForScopes(scopes)
|
||||
|
||||
currentLine = @buffer.lineForRow(bufferRow)
|
||||
precedingRow = @buffer.previousNonBlankRow(bufferRow)
|
||||
@@ -139,10 +139,10 @@ class LanguageMode
|
||||
precedingLine = @buffer.lineForRow(precedingRow)
|
||||
|
||||
desiredIndentLevel = @editSession.indentationForBufferRow(precedingRow)
|
||||
desiredIndentLevel += 1 if increaseIndentPattern.test(precedingLine)
|
||||
desiredIndentLevel += 1 if increaseIndentRegex.test(precedingLine)
|
||||
|
||||
return desiredIndentLevel unless decreaseIndentPattern = TextMateBundle.outdentRegexForScope(scopes[0])
|
||||
desiredIndentLevel -= 1 if decreaseIndentPattern.test(currentLine)
|
||||
return desiredIndentLevel unless decreaseIndentRegex = @decreaseIndentRegexForScopes(scopes)
|
||||
desiredIndentLevel -= 1 if decreaseIndentRegex.test(currentLine)
|
||||
|
||||
Math.max(desiredIndentLevel, currentIndentLevel)
|
||||
|
||||
@@ -159,32 +159,44 @@ class LanguageMode
|
||||
|
||||
precedingLine = @editSession.lineForBufferRow(precedingRow)
|
||||
scopes = @editSession.scopesForBufferPosition([precedingRow, Infinity])
|
||||
increaseIndentPattern = TextMateBundle.indentRegexForScope(scopes[0])
|
||||
return unless increaseIndentPattern
|
||||
increaseIndentRegex = @increaseIndentRegexForScopes(scopes)
|
||||
return unless increaseIndentRegex
|
||||
|
||||
currentIndentLevel = @editSession.indentationForBufferRow(bufferRow)
|
||||
desiredIndentLevel = @editSession.indentationForBufferRow(precedingRow)
|
||||
desiredIndentLevel += 1 if increaseIndentPattern.test(precedingLine)
|
||||
desiredIndentLevel += 1 if increaseIndentRegex.test(precedingLine)
|
||||
if desiredIndentLevel > currentIndentLevel
|
||||
@editSession.setIndentationForBufferRow(bufferRow, desiredIndentLevel)
|
||||
|
||||
autoDecreaseIndentForBufferRow: (bufferRow) ->
|
||||
scopes = @editSession.scopesForBufferPosition([bufferRow, 0])
|
||||
increaseIndentPattern = TextMateBundle.indentRegexForScope(scopes[0])
|
||||
decreaseIndentPattern = TextMateBundle.outdentRegexForScope(scopes[0])
|
||||
return unless increaseIndentPattern and decreaseIndentPattern
|
||||
increaseIndentRegex = @increaseIndentRegexForScopes(scopes)
|
||||
decreaseIndentRegex = @decreaseIndentRegexForScopes(scopes)
|
||||
return unless increaseIndentRegex and decreaseIndentRegex
|
||||
|
||||
line = @buffer.lineForRow(bufferRow)
|
||||
return unless decreaseIndentPattern.test(line)
|
||||
return unless decreaseIndentRegex.test(line)
|
||||
|
||||
currentIndentLevel = @editSession.indentationForBufferRow(bufferRow)
|
||||
precedingRow = @buffer.previousNonBlankRow(bufferRow)
|
||||
precedingLine = @buffer.lineForRow(precedingRow)
|
||||
|
||||
desiredIndentLevel = @editSession.indentationForBufferRow(precedingRow)
|
||||
desiredIndentLevel -= 1 unless increaseIndentPattern.test(precedingLine)
|
||||
desiredIndentLevel -= 1 unless increaseIndentRegex.test(precedingLine)
|
||||
if desiredIndentLevel < currentIndentLevel
|
||||
@editSession.setIndentationForBufferRow(bufferRow, desiredIndentLevel)
|
||||
|
||||
tokenizeLine: (line, stack, firstLine) ->
|
||||
{tokens, stack} = @grammar.tokenizeLine(line, stack, firstLine)
|
||||
|
||||
increaseIndentRegexForScopes: (scopes) ->
|
||||
if increaseIndentPattern = syntax.getProperty(scopes, 'editor.increaseIndentPattern')
|
||||
new OnigRegExp(increaseIndentPattern)
|
||||
|
||||
decreaseIndentRegexForScopes: (scopes) ->
|
||||
if decreaseIndentPattern = syntax.getProperty(scopes, 'editor.decreaseIndentPattern')
|
||||
new OnigRegExp(decreaseIndentPattern)
|
||||
|
||||
foldEndRegexForScopes: (scopes) ->
|
||||
if foldEndPattern = syntax.getProperty(scopes, 'editor.foldEndPattern')
|
||||
new OnigRegExp(foldEndPattern)
|
||||
|
||||
21
src/app/package.coffee
Normal file
21
src/app/package.coffee
Normal file
@@ -0,0 +1,21 @@
|
||||
fs = require 'fs'
|
||||
|
||||
module.exports =
|
||||
class Package
|
||||
@forName: (name) ->
|
||||
AtomPackage = require 'atom-package'
|
||||
TextMatePackage = require 'text-mate-package'
|
||||
|
||||
if TextMatePackage.testName(name)
|
||||
new TextMatePackage(name)
|
||||
else
|
||||
new AtomPackage(name)
|
||||
|
||||
constructor: (@name) ->
|
||||
@path = require.resolve(@name, verifyExistence: false)
|
||||
throw new Error("No package found named '#{@name}'") unless @path
|
||||
@path = fs.directory(@path) unless fs.isDirectory(@path)
|
||||
|
||||
load: ->
|
||||
for { selector, properties } in @getScopedProperties()
|
||||
syntax.addProperties(selector, properties)
|
||||
@@ -10,7 +10,6 @@ Project = require 'project'
|
||||
Pane = require 'pane'
|
||||
PaneColumn = require 'pane-column'
|
||||
PaneRow = require 'pane-row'
|
||||
TextMateTheme = require 'text-mate-theme'
|
||||
|
||||
module.exports =
|
||||
class RootView extends View
|
||||
@@ -24,25 +23,23 @@ class RootView extends View
|
||||
@div id: 'vertical', outlet: 'vertical', =>
|
||||
@div id: 'panes', outlet: 'panes'
|
||||
|
||||
@deserialize: ({ projectPath, panesViewState, extensionStates }) ->
|
||||
rootView = new RootView(projectPath, extensionStates: extensionStates, suppressOpen: true)
|
||||
@deserialize: ({ projectPath, panesViewState, packageStates }) ->
|
||||
rootView = new RootView(projectPath, packageStates: packageStates, suppressOpen: true)
|
||||
rootView.setRootPane(rootView.deserializeView(panesViewState)) if panesViewState
|
||||
rootView
|
||||
|
||||
extensions: null
|
||||
extensionStates: null
|
||||
packageModules: null
|
||||
packageStates: null
|
||||
title: null
|
||||
|
||||
initialize: (pathToOpen, { @extensionStates, suppressOpen } = {}) ->
|
||||
initialize: (pathToOpen, { @packageStates, suppressOpen } = {}) ->
|
||||
window.rootView = this
|
||||
@extensionStates ?= {}
|
||||
@extensions = {}
|
||||
@packageStates ?= {}
|
||||
@packageModules = {}
|
||||
@project = new Project(pathToOpen)
|
||||
|
||||
config.load()
|
||||
|
||||
TextMateTheme.activate(config.get("core.theme") ? 'IR_Black')
|
||||
|
||||
@handleEvents()
|
||||
|
||||
if pathToOpen
|
||||
@@ -53,7 +50,7 @@ class RootView extends View
|
||||
serialize: ->
|
||||
projectPath: @project?.getPath()
|
||||
panesViewState: @panes.children().view()?.serialize()
|
||||
extensionStates: @serializeExtensions()
|
||||
packageStates: @serializePackages()
|
||||
|
||||
handleFocus: (e) ->
|
||||
if @getActiveEditor()
|
||||
@@ -99,14 +96,14 @@ class RootView extends View
|
||||
afterAttach: (onDom) ->
|
||||
@focus() if onDom
|
||||
|
||||
serializeExtensions: ->
|
||||
extensionStates = {}
|
||||
for name, extension of @extensions
|
||||
serializePackages: ->
|
||||
packageStates = {}
|
||||
for name, packageModule of @packageModules
|
||||
try
|
||||
extensionStates[name] = extension.serialize?()
|
||||
packageStates[name] = packageModule.serialize?()
|
||||
catch e
|
||||
console?.error("Exception serializing '#{name}' extension\n", e.stack)
|
||||
extensionStates
|
||||
console?.error("Exception serializing '#{name}' package's module\n", e.stack)
|
||||
packageStates
|
||||
|
||||
deserializeView: (viewState) ->
|
||||
switch viewState.viewClass
|
||||
@@ -115,18 +112,18 @@ class RootView extends View
|
||||
when 'PaneColumn' then PaneColumn.deserialize(viewState, this)
|
||||
when 'Editor' then Editor.deserialize(viewState, this)
|
||||
|
||||
activateExtension: (extension, config) ->
|
||||
throw new Error("Trying to activate an extension with no name attribute") unless extension.name?
|
||||
@extensions[extension.name] = extension
|
||||
extension.activate(this, @extensionStates[extension.name], config)
|
||||
activatePackage: (packageModule) ->
|
||||
throw new Error("Trying to activate a package module with no name attribute") unless packageModule.name?
|
||||
@packageModules[packageModule.name] = packageModule
|
||||
packageModule.activate(this, @packageStates[packageModule.name])
|
||||
|
||||
deactivateExtension: (extension) ->
|
||||
extension.deactivate?()
|
||||
delete @extensions[extension.name]
|
||||
deactivatePackage: (packageModule) ->
|
||||
packageModule.deactivate?()
|
||||
delete @packageModules[packageModule.name]
|
||||
|
||||
deactivate: ->
|
||||
atom.setRootViewStateForPath(@project.getPath(), @serialize())
|
||||
@deactivateExtension(extension) for name, extension of @extensions
|
||||
@deactivatePackage(packageModule) for name, packageModule of @packageModules
|
||||
@remove()
|
||||
|
||||
open: (path, options = {}) ->
|
||||
|
||||
70
src/app/syntax.coffee
Normal file
70
src/app/syntax.coffee
Normal file
@@ -0,0 +1,70 @@
|
||||
_ = require 'underscore'
|
||||
jQuery = require 'jquery'
|
||||
Specificity = require 'specificity'
|
||||
{$$} = require 'space-pen'
|
||||
|
||||
module.exports =
|
||||
class Syntax
|
||||
constructor: ->
|
||||
@globalProperties = {}
|
||||
@scopedPropertiesIndex = 0
|
||||
@scopedProperties = []
|
||||
@propertiesBySelector = {}
|
||||
|
||||
addProperties: (args...) ->
|
||||
selector = args.shift() if args.length > 1
|
||||
properties = args.shift()
|
||||
|
||||
if selector
|
||||
@scopedProperties.unshift(
|
||||
selector: selector,
|
||||
properties: properties,
|
||||
specificity: Specificity(selector),
|
||||
index: @scopedPropertiesIndex++
|
||||
)
|
||||
else
|
||||
_.extend(@globalProperties, properties)
|
||||
|
||||
getProperty: (scope, keyPath) ->
|
||||
for object in @propertiesForScope(scope, keyPath)
|
||||
value = _.valueForKeyPath(object, keyPath)
|
||||
return value if value?
|
||||
undefined
|
||||
|
||||
propertiesForScope: (scope, keyPath) ->
|
||||
matchingProperties = []
|
||||
candidates = @scopedProperties.filter ({properties}) -> _.valueForKeyPath(properties, keyPath)?
|
||||
if candidates.length
|
||||
element = @buildScopeElement(scope)
|
||||
while element
|
||||
matchingProperties.push(@matchingPropertiesForElement(element, candidates)...)
|
||||
element = element.parentNode
|
||||
matchingProperties.concat([@globalProperties])
|
||||
|
||||
matchingPropertiesForElement: (element, candidates) ->
|
||||
matchingScopedProperties = candidates.filter ({selector}) ->
|
||||
jQuery.find.matchesSelector(element, selector)
|
||||
matchingScopedProperties.sort (a, b) ->
|
||||
if a.specificity == b.specificity
|
||||
b.index - a.index
|
||||
else
|
||||
b.specificity - a.specificity
|
||||
_.pluck matchingScopedProperties, 'properties'
|
||||
|
||||
buildScopeElement: (scope) ->
|
||||
scope = new Array(scope...)
|
||||
element = $$ ->
|
||||
elementsForRemainingScopes = =>
|
||||
classString = scope.shift()
|
||||
classes = classString.replace(/^\./, '').replace(/\./g, ' ')
|
||||
if scope.length
|
||||
@div class: classes, elementsForRemainingScopes
|
||||
else
|
||||
@div class: classes
|
||||
elementsForRemainingScopes()
|
||||
|
||||
deepestChild = element.find(":not(:has(*))")
|
||||
if deepestChild.length
|
||||
deepestChild[0]
|
||||
else
|
||||
element[0]
|
||||
@@ -10,18 +10,10 @@ class TextMateBundle
|
||||
@grammarsByFileType: {}
|
||||
@grammarsByScopeName: {}
|
||||
@preferencesByScopeSelector: {}
|
||||
@bundles: []
|
||||
@grammars: []
|
||||
|
||||
@loadAll: ->
|
||||
localBundlePath = fs.join(config.configDirPath, "bundles")
|
||||
localBundles = fs.list(localBundlePath) if fs.exists(localBundlePath)
|
||||
|
||||
for bundlePath in localBundles ? []
|
||||
@registerBundle(new TextMateBundle(bundlePath))
|
||||
|
||||
@registerBundle: (bundle)->
|
||||
@bundles.push(bundle)
|
||||
@load: (name)->
|
||||
bundle = new TextMateBundle(require.resolve(name))
|
||||
|
||||
for scopeSelector, preferences of bundle.getPreferencesByScopeSelector()
|
||||
if @preferencesByScopeSelector[scopeSelector]?
|
||||
@@ -35,6 +27,8 @@ class TextMateBundle
|
||||
@grammarsByFileType[fileType] = grammar
|
||||
@grammarsByScopeName[grammar.scopeName] = grammar
|
||||
|
||||
bundle
|
||||
|
||||
@grammarForFilePath: (filePath) ->
|
||||
return @grammarsByFileType["txt"] unless filePath
|
||||
|
||||
@@ -59,34 +53,6 @@ class TextMateBundle
|
||||
@grammarForScopeName: (scopeName) ->
|
||||
@grammarsByScopeName[scopeName]
|
||||
|
||||
@getPreferenceInScope: (scopeSelector, preferenceName) ->
|
||||
@preferencesByScopeSelector[scopeSelector]?[preferenceName]
|
||||
|
||||
@getPreferenceValueInScope: (scope, preferenceName, valueName) ->
|
||||
values = @getPreferenceInScope(scope, preferenceName)
|
||||
(_.find values, ({name}) -> name is valueName)?['value']
|
||||
|
||||
@lineCommentStartStringForScope: (scope) ->
|
||||
@getPreferenceValueInScope(scope, 'shellVariables', 'TM_COMMENT_START')
|
||||
|
||||
@lineCommentEndStringForScope: (scope) ->
|
||||
@getPreferenceValueInScope(scope, 'shellVariables', 'TM_COMMENT_END')
|
||||
|
||||
@indentRegexForScope: (scope) ->
|
||||
if source = @getPreferenceInScope(scope, 'increaseIndentPattern')
|
||||
new OnigRegExp(source)
|
||||
|
||||
@outdentRegexForScope: (scope) ->
|
||||
if source = @getPreferenceInScope(scope, 'decreaseIndentPattern')
|
||||
new OnigRegExp(source)
|
||||
|
||||
@foldEndRegexForScope: (grammar, scope) ->
|
||||
marker = @getPreferenceInScope(scope, 'foldingStopMarker')
|
||||
if marker
|
||||
new OnigRegExp(marker)
|
||||
else
|
||||
new OnigRegExp(grammar.foldingStopMarker)
|
||||
|
||||
grammars: null
|
||||
|
||||
constructor: (@path) ->
|
||||
|
||||
74
src/app/text-mate-package.coffee
Normal file
74
src/app/text-mate-package.coffee
Normal file
@@ -0,0 +1,74 @@
|
||||
Package = require 'package'
|
||||
TextMateBundle = require 'text-mate-bundle'
|
||||
fs = require 'fs'
|
||||
plist = require 'plist'
|
||||
_ = require 'underscore'
|
||||
|
||||
module.exports =
|
||||
class TextMatePackage extends Package
|
||||
@testName: (packageName) ->
|
||||
/(\.|_|-)tmbundle$/.test(packageName)
|
||||
|
||||
@cssSelectorFromScopeSelector: (scopeSelector) ->
|
||||
scopeSelector.split(', ').map((commaFragment) ->
|
||||
commaFragment.split(' ').map((spaceFragment) ->
|
||||
spaceFragment.split('.').map((dotFragment) ->
|
||||
'.' + dotFragment.replace(/\+/g, '\\+')
|
||||
).join('')
|
||||
).join(' ')
|
||||
).join(', ')
|
||||
|
||||
load: ->
|
||||
@bundle = TextMateBundle.load(@name)
|
||||
@grammars = @bundle.grammars
|
||||
super
|
||||
|
||||
constructor: ->
|
||||
super
|
||||
@preferencesPath = fs.join(@path, "Preferences")
|
||||
@syntaxesPath = fs.join(@path, "Syntaxes")
|
||||
|
||||
getScopedProperties: ->
|
||||
scopedProperties = []
|
||||
|
||||
for grammar in @grammars
|
||||
if properties = @propertiesFromTextMateSettings(grammar)
|
||||
selector = @cssSelectorFromScopeSelector(grammar.scopeName)
|
||||
scopedProperties.push({selector, properties})
|
||||
|
||||
for {scope, settings} in @getTextMatePreferenceObjects()
|
||||
if properties = @propertiesFromTextMateSettings(settings)
|
||||
selector = @cssSelectorFromScopeSelector(scope) if scope?
|
||||
scopedProperties.push({selector, properties})
|
||||
|
||||
scopedProperties
|
||||
|
||||
getTextMatePreferenceObjects: ->
|
||||
preferenceObjects = []
|
||||
if fs.exists(@preferencesPath)
|
||||
for preferencePath in fs.list(@preferencesPath)
|
||||
plist.parseString fs.read(preferencePath), (e, data) =>
|
||||
if e
|
||||
console.warn "Failed to parse preference at path '#{preferencePath}'", e.stack
|
||||
else
|
||||
preferenceObjects.push(data[0])
|
||||
preferenceObjects
|
||||
|
||||
propertiesFromTextMateSettings: (textMateSettings) ->
|
||||
if textMateSettings.shellVariables
|
||||
shellVariables = {}
|
||||
for {name, value} in textMateSettings.shellVariables
|
||||
shellVariables[name] = value
|
||||
textMateSettings.shellVariables = shellVariables
|
||||
|
||||
editorProperties = _.compactObject(
|
||||
commentStart: _.valueForKeyPath(textMateSettings, 'shellVariables.TM_COMMENT_START')
|
||||
commentEnd: _.valueForKeyPath(textMateSettings, 'shellVariables.TM_COMMENT_END')
|
||||
increaseIndentPattern: textMateSettings.increaseIndentPattern
|
||||
decreaseIndentPattern: textMateSettings.decreaseIndentPattern
|
||||
foldEndPattern: textMateSettings.foldingStopMarker
|
||||
)
|
||||
{ editor: editorProperties } if _.size(editorProperties) > 0
|
||||
|
||||
cssSelectorFromScopeSelector: (scopeSelector) ->
|
||||
@constructor.cssSelectorFromScopeSelector(scopeSelector)
|
||||
@@ -1,46 +1,16 @@
|
||||
_ = require 'underscore'
|
||||
fs = require 'fs'
|
||||
plist = require 'plist'
|
||||
Theme = require 'theme'
|
||||
|
||||
module.exports =
|
||||
class TextMateTheme
|
||||
@themesByName: {}
|
||||
|
||||
@loadAll: ->
|
||||
for themePath in fs.list(require.resolve("themes"))
|
||||
@registerTheme(TextMateTheme.load(themePath))
|
||||
|
||||
@load: (path) ->
|
||||
plistString = fs.read(require.resolve(path))
|
||||
theme = null
|
||||
plist.parseString plistString, (err, data) ->
|
||||
throw new Error("Error loading theme at '#{path}': #{err}") if err
|
||||
theme = new TextMateTheme(data[0])
|
||||
theme
|
||||
|
||||
@registerTheme: (theme) ->
|
||||
@themesByName[theme.name] = theme
|
||||
|
||||
@getNames: ->
|
||||
_.keys(@themesByName)
|
||||
|
||||
@getTheme: (name) ->
|
||||
@themesByName[name]
|
||||
|
||||
@activate: (name) ->
|
||||
if theme = @getTheme(name)
|
||||
theme.activate()
|
||||
else
|
||||
throw new Error("No theme with name '#{name}'")
|
||||
|
||||
constructor: ({@name, settings}) ->
|
||||
class TextMateTheme extends Theme
|
||||
constructor: (@path, {settings}) ->
|
||||
super
|
||||
@rulesets = []
|
||||
globalSettings = settings[0]
|
||||
@buildGlobalSettingsRulesets(settings[0])
|
||||
@buildScopeSelectorRulesets(settings[1..])
|
||||
|
||||
activate: ->
|
||||
applyStylesheet(@name, @getStylesheet())
|
||||
@stylesheets[@path] = @getStylesheet()
|
||||
|
||||
getStylesheet: ->
|
||||
lines = []
|
||||
|
||||
56
src/app/theme.coffee
Normal file
56
src/app/theme.coffee
Normal file
@@ -0,0 +1,56 @@
|
||||
fs = require("fs")
|
||||
plist = require 'plist'
|
||||
_ = require 'underscore'
|
||||
|
||||
module.exports =
|
||||
class Theme
|
||||
@stylesheets: null
|
||||
|
||||
@load: (names) ->
|
||||
if typeof(names) == "string"
|
||||
[@loadTheme(names)]
|
||||
else
|
||||
names.map (name) => @loadTheme(name)
|
||||
|
||||
@loadTheme: (name) ->
|
||||
if fs.exists(name)
|
||||
path = name
|
||||
else
|
||||
path = fs.resolve(config.themeDirPaths..., name)
|
||||
path ?= fs.resolve(config.themeDirPaths..., name + ".tmTheme")
|
||||
|
||||
if @isTextMateTheme(path)
|
||||
theme = @loadTextMateTheme(path)
|
||||
else
|
||||
theme = @loadAtomTheme(path)
|
||||
|
||||
throw new Error("Cannot activate theme named '#{name}' located at '#{path}'") unless theme
|
||||
theme.activate()
|
||||
theme
|
||||
|
||||
@loadTextMateTheme: (path) ->
|
||||
TextMateTheme = require("text-mate-theme")
|
||||
plistString = fs.read(path)
|
||||
theme = null
|
||||
plist.parseString plistString, (err, data) ->
|
||||
throw new Error("Error loading theme at '#{path}': #{err}") if err
|
||||
theme = new TextMateTheme(path, data[0])
|
||||
theme
|
||||
|
||||
@loadAtomTheme: (path) ->
|
||||
AtomTheme = require('atom-theme')
|
||||
new AtomTheme(path)
|
||||
|
||||
@isTextMateTheme: (path) ->
|
||||
/\.(tmTheme|plist)$/.test(path)
|
||||
|
||||
constructor: (@path) ->
|
||||
@stylesheets = {}
|
||||
|
||||
activate: ->
|
||||
for stylesheetPath, stylesheetContent of @stylesheets
|
||||
applyStylesheet(stylesheetPath, stylesheetContent)
|
||||
|
||||
deactivate: ->
|
||||
for stylesheetPath, stylesheetContent of @stylesheets
|
||||
window.removeStylesheet(stylesheetPath)
|
||||
@@ -9,6 +9,7 @@ _ = require 'underscore'
|
||||
$ = require 'jquery'
|
||||
{CoffeeScript} = require 'coffee-script'
|
||||
Config = require 'config'
|
||||
Syntax = require 'syntax'
|
||||
RootView = require 'root-view'
|
||||
Pasteboard = require 'pasteboard'
|
||||
require 'jquery-extensions'
|
||||
@@ -25,8 +26,7 @@ windowAdditions =
|
||||
# in all environments: spec, benchmark, and application
|
||||
startup: ->
|
||||
@config = new Config
|
||||
TextMateBundle.loadAll()
|
||||
TextMateTheme.loadAll()
|
||||
@syntax = new Syntax
|
||||
@setUpKeymap()
|
||||
@pasteboard = new Pasteboard
|
||||
|
||||
@@ -65,9 +65,14 @@ windowAdditions =
|
||||
|
||||
requireStylesheet: (path) ->
|
||||
unless fullPath = require.resolve(path)
|
||||
throw new Error("requireStylesheet could not find a file at path '#{path}'")
|
||||
throw new Error("Could not find a file at path '#{path}'")
|
||||
window.applyStylesheet(fullPath, fs.read(fullPath))
|
||||
|
||||
removeStylesheet: (path) ->
|
||||
unless fullPath = require.resolve(path)
|
||||
throw new Error("Could not find a file at path '#{path}'")
|
||||
$("head style[id='#{fullPath}']").remove()
|
||||
|
||||
applyStylesheet: (id, text) ->
|
||||
unless $("head style[id='#{id}']").length
|
||||
$('head').append "<style id='#{id}'>#{text}</style>"
|
||||
|
||||
Reference in New Issue
Block a user