Merge branch 'config'

This commit is contained in:
Nathan Sobo
2012-12-31 12:43:25 -06:00
48 changed files with 1891 additions and 318 deletions

View File

@@ -1 +0,0 @@
Put TextMate bundles in this directory

0
.atom/packages/Readme.md Normal file
View File

View File

@@ -0,0 +1,810 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>name</key>
<string>IR_Black</string>
<key>settings</key>
<array>
<dict>
<key>settings</key>
<dict>
<key>background</key>
<string>#000000</string>
<key>caret</key>
<string>#FFFFFF</string>
<key>foreground</key>
<string>#EDEDED</string>
<key>invisibles</key>
<string>#CAE2FB3D</string>
<key>lineHighlight</key>
<string>#FFFFFF24</string>
<key>selection</key>
<string>#333333</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Comment</string>
<key>scope</key>
<string>comment</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#7C7C7C</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Entity</string>
<key>scope</key>
<string>entity</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#FFD2A7</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Keyword</string>
<key>scope</key>
<string>keyword</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#96CBFE</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Keyword.control</string>
<key>scope</key>
<string>keyword.control</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#96CBFE</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Keyword.Operator</string>
<key>scope</key>
<string>keyword.operator</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#EDEDED</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Class</string>
<key>scope</key>
<string>entity.name.type</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string>underline</string>
<key>foreground</key>
<string>#FFFFB6</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Support</string>
<key>scope</key>
<string>support</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#FFFFB6</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Storage</string>
<key>scope</key>
<string>storage</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#CFCB90</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Storage.modifier</string>
<key>scope</key>
<string>storage.modifier</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#96CBFE</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Constant</string>
<key>scope</key>
<string>constant</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#99CC99</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>String</string>
<key>scope</key>
<string>string</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string>bold</string>
<key>foreground</key>
<string>#A8FF60</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Number</string>
<key>scope</key>
<string>constant.numeric</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string>bold</string>
<key>foreground</key>
<string>#FF73FD</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Punctuation</string>
<key>scope</key>
<string>punctuation</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Variable</string>
<key>scope</key>
<string>variable</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#C6C5FE</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Invalid Deprecated</string>
<key>scope</key>
<string>invalid.deprecated</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string>italic underline</string>
<key>foreground</key>
<string>#FD5FF1</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Invalid Illegal</string>
<key>scope</key>
<string>invalid.illegal</string>
<key>settings</key>
<dict>
<key>background</key>
<string>#562D56BF</string>
<key>foreground</key>
<string>#FD5FF1</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>-----------------------------------</string>
<key>settings</key>
<dict/>
</dict>
<dict>
<key>name</key>
<string>♦ Embedded Source (Bright)</string>
<key>scope</key>
<string>text source</string>
<key>settings</key>
<dict>
<key>background</key>
<string>#B1B3BA08</string>
<key>fontStyle</key>
<string></string>
</dict>
</dict>
<dict>
<key>name</key>
<string>♦ Entity inherited-class</string>
<key>scope</key>
<string>entity.other.inherited-class</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string>italic</string>
<key>foreground</key>
<string>#9B5C2E</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>♦ String embedded-variable</string>
<key>scope</key>
<string>source string source</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#EDEDED</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>♦ String punctuation</string>
<key>scope</key>
<string>source string source punctuation.section.embedded</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#00A0A0</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>♦ String constant</string>
<key>scope</key>
<string>string constant</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#00A0A0</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>♦ String.regexp</string>
<key>scope</key>
<string>string.regexp</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#E9C062</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>♦ String.regexp.«special»</string>
<key>scope</key>
<string>string.regexp constant.character.escape, string.regexp source.ruby.embedded, string.regexp string.regexp.arbitrary-repitition</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#FF8000</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>♦ String.regexp.group</string>
<key>scope</key>
<string>string.regexp.group</string>
<key>settings</key>
<dict>
<key>background</key>
<string>#FFFFFF0F</string>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#C6A24F</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>♦ String.regexp.character-class</string>
<key>scope</key>
<string>string.regexp.character-class</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#B18A3D</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>♦ String variable</string>
<key>scope</key>
<string>string variable</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#8A9A95</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>♦ Support.function</string>
<key>scope</key>
<string>support.function</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#DAD085</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>♦ Support.constant</string>
<key>scope</key>
<string>support.constant</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#FFD2A7</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>c C/C++ Preprocessor Line</string>
<key>scope</key>
<string>meta.preprocessor.c</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#8996A8</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>c C/C++ Preprocessor Directive</string>
<key>scope</key>
<string>meta.preprocessor.c keyword</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#AFC4DB</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>j Cast</string>
<key>scope</key>
<string>meta.cast</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string>italic</string>
<key>foreground</key>
<string>#676767</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>✘ Doctype/XML Processing</string>
<key>scope</key>
<string>meta.sgml.html meta.doctype, meta.sgml.html meta.doctype entity, meta.sgml.html meta.doctype string, meta.xml-processing, meta.xml-processing entity, meta.xml-processing string</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#494949</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>✘ Meta.tag.«all»</string>
<key>scope</key>
<string>meta.tag, meta.tag entity</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string>bold</string>
<key>foreground</key>
<string>#96CBFE</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>✘ Meta.tag.inline</string>
<key>scope</key>
<string>source entity.name.tag, source entity.other.attribute-name, meta.tag.inline, meta.tag.inline entity</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#96CBFE</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>✘ Meta.tag.attribute-name</string>
<key>scope</key>
<string>entity.other.attribute-name</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#FFD7B1</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>✘ Namespaces</string>
<key>scope</key>
<string>entity.name.tag.namespace, entity.other.attribute-name.namespace</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#E18964</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>§ css tag-name</string>
<key>scope</key>
<string>meta.selector.css entity.name.tag</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string>underline</string>
<key>foreground</key>
<string>#96CBFE</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>§ css:pseudo-class</string>
<key>scope</key>
<string>meta.selector.css entity.other.attribute-name.tag.pseudo-class</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#8F9D6A</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>§ css#id</string>
<key>scope</key>
<string>meta.selector.css entity.other.attribute-name.id</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#8B98AB</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>§ css.class</string>
<key>scope</key>
<string>meta.selector.css entity.other.attribute-name.class</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#62B1FE</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>§ css property-name:</string>
<key>scope</key>
<string>support.type.property-name.css</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#EDEDED</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>§ css property-value;</string>
<key>scope</key>
<string>meta.property-group support.constant.property-value.css, meta.property-value support.constant.property-value.css</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#F9EE98</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>§ css @at-rule</string>
<key>scope</key>
<string>meta.preprocessor.at-rule keyword.control.at-rule</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#8693A5</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>§ css additional-constants</string>
<key>scope</key>
<string>meta.property-value support.constant.named-color.css, meta.property-value constant</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#87C38A</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>§ css constructor.argument</string>
<key>scope</key>
<string>meta.constructor.argument.css</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#8F9D6A</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>⎇ diff.header</string>
<key>scope</key>
<string>meta.diff, meta.diff.header</string>
<key>settings</key>
<dict>
<key>background</key>
<string>#0E2231</string>
<key>fontStyle</key>
<string>italic</string>
<key>foreground</key>
<string>#F8F8F8</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>⎇ diff.deleted</string>
<key>scope</key>
<string>markup.deleted</string>
<key>settings</key>
<dict>
<key>background</key>
<string>#420E09</string>
<key>foreground</key>
<string>#F8F8F8</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>⎇ diff.changed</string>
<key>scope</key>
<string>markup.changed</string>
<key>settings</key>
<dict>
<key>background</key>
<string>#4A410D</string>
<key>foreground</key>
<string>#F8F8F8</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>⎇ diff.inserted</string>
<key>scope</key>
<string>markup.inserted</string>
<key>settings</key>
<dict>
<key>background</key>
<string>#253B22</string>
<key>foreground</key>
<string>#F8F8F8</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>--------------------------------</string>
<key>settings</key>
<dict/>
</dict>
<dict>
<key>name</key>
<string>Markup: Italic</string>
<key>scope</key>
<string>markup.italic</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string>italic</string>
<key>foreground</key>
<string>#E9C062</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Markup: Bold</string>
<key>scope</key>
<string>markup.bold</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string>bold</string>
<key>foreground</key>
<string>#E9C062</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Markup: Underline</string>
<key>scope</key>
<string>markup.underline</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string>underline</string>
<key>foreground</key>
<string>#E18964</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Markup: Quote</string>
<key>scope</key>
<string>markup.quote</string>
<key>settings</key>
<dict>
<key>background</key>
<string>#FEE09C12</string>
<key>fontStyle</key>
<string>italic</string>
<key>foreground</key>
<string>#E1D4B9</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Markup: Heading</string>
<key>scope</key>
<string>markup.heading, markup.heading entity</string>
<key>settings</key>
<dict>
<key>background</key>
<string>#632D04</string>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#FEDCC5</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Markup: List</string>
<key>scope</key>
<string>markup.list</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#E1D4B9</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Markup: Raw</string>
<key>scope</key>
<string>markup.raw</string>
<key>settings</key>
<dict>
<key>background</key>
<string>#B1B3BA08</string>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#578BB3</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Markup: Comment</string>
<key>scope</key>
<string>markup comment</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string>italic</string>
<key>foreground</key>
<string>#F67B37</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Markup: Separator</string>
<key>scope</key>
<string>meta.separator</string>
<key>settings</key>
<dict>
<key>background</key>
<string>#242424</string>
<key>foreground</key>
<string>#60A633</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Log Entry</string>
<key>scope</key>
<string>meta.line.entry.logfile, meta.line.exit.logfile</string>
<key>settings</key>
<dict>
<key>background</key>
<string>#EEEEEE29</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Log Entry Error</string>
<key>scope</key>
<string>meta.line.error.logfile</string>
<key>settings</key>
<dict>
<key>background</key>
<string>#751012</string>
</dict>
</dict>
</array>
<key>uuid</key>
<string>D039AEA9-9DD2-4237-A963-E84494B0B3FB</string>
</dict>
</plist>

View File

@@ -60,6 +60,20 @@ end
desc "Creates .atom file if non exists"
task "create-dot-atom" do
# Migration: If there is still a bundle path, rename it to packages
if File.exists?(DOT_ATOM_PATH) and File.exists?(File.join(DOT_ATOM_PATH, "bundles"))
if File.exists?(File.join(DOT_ATOM_PATH, "packages"))
`mv #{File.join(DOT_ATOM_PATH, "bundles", "*")} #{File.join(DOT_ATOM_PATH, "packages")}`
$stderr.puts "WARNING: Bundles from ~/.atom/bundles were moved to ~/.atom/packages"
else
`mv #{File.join(DOT_ATOM_PATH, "bundles")} #{File.join(DOT_ATOM_PATH, "packages")}`
$stderr.puts "WARNING: ~/.atom/bundles was moved to ~/.atom/packages"
end
end
# Migration: remove files that are no longer needed
`rm -rf #{File.join(DOT_ATOM_PATH, 'default-config.coffee')}`
dot_atom_template_path = ATOM_SRC_PATH + "/.atom"
replace_dot_atom = false
next if File.exists?(DOT_ATOM_PATH)
@@ -67,12 +81,8 @@ task "create-dot-atom" do
`rm -rf "#{DOT_ATOM_PATH}"`
`mkdir "#{DOT_ATOM_PATH}"`
`cp "#{dot_atom_template_path}/atom.coffee" "#{DOT_ATOM_PATH}"`
`cp "#{dot_atom_template_path}/bundles" "#{DOT_ATOM_PATH}"`
for path in Dir.entries(dot_atom_template_path)
next if ["..", ".", "atom.coffee", "bundles"].include? path
`ln -s "#{dot_atom_template_path}/#{path}" "#{DOT_ATOM_PATH}"`
end
`cp "#{dot_atom_template_path}/packages" "#{DOT_ATOM_PATH}"`
`cp -r "#{dot_atom_template_path}/themes" "#{DOT_ATOM_PATH}"`
end
desc "Clone default bundles into .atom directory"
@@ -96,7 +106,7 @@ task "clone-default-bundles" => "create-dot-atom" do
for bundle_url, sha in bundles
bundle_dir = bundle_url[/([^\/]+?)(\.git)?$/, 1]
dest_path = File.join(DOT_ATOM_PATH, "bundles", bundle_dir)
dest_path = File.join(DOT_ATOM_PATH, "packages", bundle_dir)
if File.exists? dest_path
`cd #{dest_path} && git fetch --quiet`
else
@@ -110,6 +120,8 @@ end
desc "Clean build Atom via `xcodebuild`"
task :clean do
output = `xcodebuild clean`
`rm -rf #{application_path()}`
`rm -rf #{BUILD_DIR}`
end
desc "Run Atom"
@@ -135,7 +147,7 @@ task :benchmark do
end
task :nof do
system %{find . -name *spec.coffee | grep -v atom-build | xargs sed -E -i "" "s/f+(it|describe) +(['\\"])/\\1 \\2/g"}
system %{find . -name *spec.coffee | grep -v #{BUILD_DIR} | xargs sed -E -i "" "s/f+(it|describe) +(['\\"])/\\1 \\2/g"}
end
task :tags do

View File

@@ -11,12 +11,14 @@ TextMateTheme = require 'text-mate-theme'
require 'window'
requireStylesheet "jasmine.css"
# Load TextMate bundles, which specs rely on (but not other packages)
atom.loadPackages(atom.getAvailableTextMateBundles())
beforeEach ->
# don't load user configuration
# reset config after each benchmark; don't load or save from/to `config.json`
window.config = new Config()
spyOn(config, 'load')
spyOn(config, 'save')
config.assignDefaults()
keymap = new Keymap
keymap.bindDefaultKeys()

View File

@@ -78,58 +78,6 @@ ConfigObserver = require 'config-observer'
_.extend MyClass.prototype, ConfigObserver
```
## Scoped Config Settings (Not Yet Implemented)
Users and extension authors can provide language-specific behavior by employing
*scoped configuration keys*. By associating key values with a specific scope,
you can make Atom behave differently in different contexts. For example, if you
want Atom to auto-indent pasted text in some languages but not others, you can
give the `autoIndentPastedText` key a different value under a scope selector:
```coffeescript
# in config.cson
editor:
autoIndentPastedText: true
scopes:
".source.coffee":
editor:
autoIndentPastedText: false
```
Scope selectors are placed under the `scope` key at the top-level of the
configuration file. The values you specify for keys under a selector will
override global values in that specific scope. Any basic CSS 3 selector is
permitted, but you should leave out element names to make your keys accessible
outside the view layer.
### Reading Scoped Config Settings
Use the `config.inScope` method to the read keys with the most specific selector
match:
```coffeescript
scope = [".source.coffee", ".meta.class.instance.constructor"]
config.inScope(scope).get "editor.lineComment"
```
Pass `.inScope` an array of scope descriptors, which describes a specific
element. This is frequently useful when you get the nested scopes for a position
in the buffer based on its syntax. You can also pass an actual DOM element
to use its nesting within the DOM as fodder for the scope selectors (†).
```coffeescript
config.inScope(fuzzyFinder.miniEditor).get("editor.fontSize")
```
`observeConfig` can take a scope as its first argument:
```
@observeConfig scope, "editor.autoIndentPastedText", -> # ...
```
†: Matching DOM elements fits cleanly into this scheme, but I can't think of a
use for it currently. Let's keep it in the back of our minds though.
# Themes (Not Yet Implemented)
## Selecting A Theme
@@ -162,7 +110,7 @@ folder, which can contain multiple stylesheets along with an optional
package.json:
```json
{
"stylesheets": ["core", "editor", "tree-view"]
"stylesheets": ["core.css", "editor.less", "tree-view.css"]
}
```

View File

@@ -29,4 +29,4 @@ for COFFEE_FILE in $COFFEE_FILES; do
done;
# Copy non-coffee files into bundle
rsync --archive --recursive --exclude="src/**/*.coffee" src static vendor spec benchmark themes "$RESOUCES_PATH"
rsync --archive --recursive --exclude="src/**/*.coffee" src static vendor spec benchmark "$RESOUCES_PATH"

View File

@@ -6,9 +6,9 @@ describe "the `atom` global", ->
beforeEach ->
rootView = new RootView
extension = require "package-with-extension"
extension = require "package-with-module"
it "requires and activates the package's main module if it exists", ->
spyOn(rootView, 'activateExtension').andCallThrough()
atom.loadPackage("package-with-extension")
expect(rootView.activateExtension).toHaveBeenCalledWith(extension)
spyOn(rootView, 'activatePackage').andCallThrough()
atom.loadPackage("package-with-module")
expect(rootView.activatePackage).toHaveBeenCalledWith(extension)

View File

@@ -262,19 +262,19 @@ describe "LanguageMode", ->
expect(buffer.lineForRow(0)).toBe "/*body {"
expect(buffer.lineForRow(1)).toBe " font-size: 1234px;*/"
expect(buffer.lineForRow(2)).toBe " width: 110%;"
expect(buffer.lineForRow(3)).toBe "}"
expect(buffer.lineForRow(3)).toBe " font-weight: bold !important;"
languageMode.toggleLineCommentsForBufferRows(2, 2)
expect(buffer.lineForRow(0)).toBe "/*body {"
expect(buffer.lineForRow(1)).toBe " font-size: 1234px;*/"
expect(buffer.lineForRow(2)).toBe "/* width: 110%;*/"
expect(buffer.lineForRow(3)).toBe "}"
expect(buffer.lineForRow(3)).toBe " font-weight: bold !important;"
languageMode.toggleLineCommentsForBufferRows(0, 1)
expect(buffer.lineForRow(0)).toBe "body {"
expect(buffer.lineForRow(1)).toBe " font-size: 1234px;"
expect(buffer.lineForRow(2)).toBe "/* width: 110%;*/"
expect(buffer.lineForRow(3)).toBe "}"
expect(buffer.lineForRow(3)).toBe " font-weight: bold !important;"
it "uncomments lines with leading whitespace", ->
buffer.replaceLines(2, 2, " /*width: 110%;*/")

View File

@@ -125,24 +125,24 @@ describe "RootView", ->
expect(rootView.getTitle()).toBe 'untitled'
describe ".serialize()", ->
it "absorbs exceptions that are thrown by extension serialize methods", ->
it "absorbs exceptions that are thrown by the package module's serialize methods", ->
spyOn(console, 'error')
rootView.activateExtension(
rootView.activatePackage(
name: "bad-egg"
activate: ->
serialize: -> throw new Error("I'm broken")
)
rootView.activateExtension(
rootView.activatePackage(
name: "good-egg"
activate: ->
serialize: -> "I still get called"
)
data = rootView.serialize()
expect(data.extensionStates['good-egg']).toBe "I still get called"
expect(data.extensionStates['bad-egg']).toBeUndefined()
expect(data.packageStates['good-egg']).toBe "I still get called"
expect(data.packageStates['bad-egg']).toBeUndefined()
expect(console.error).toHaveBeenCalled()
describe "focus", ->
@@ -393,54 +393,49 @@ describe "RootView", ->
rootView.focusNextPane()
expect(view1.focus).toHaveBeenCalled()
describe "extensions", ->
extension = null
describe "packages", ->
packageModule = null
beforeEach ->
extension =
name: 'extension'
packageModule =
name: 'package'
deactivate: ->
activate: jasmine.createSpy("activate")
serialize: -> "it worked"
describe ".activateExtension(extension)", ->
it "calls activate on the extension", ->
rootView.activateExtension(extension)
expect(extension.activate).toHaveBeenCalledWith(rootView, undefined, undefined)
describe ".activatePackage(packageModule)", ->
it "calls activate on the package module", ->
rootView.activatePackage(packageModule)
expect(packageModule.activate).toHaveBeenCalledWith(rootView, undefined)
it "calls activate on the extension with its previous state", ->
rootView.activateExtension(extension)
extension.activate.reset()
it "calls activate on the package module with its previous state", ->
rootView.activatePackage(packageModule)
packageModule.activate.reset()
newRootView = RootView.deserialize(rootView.serialize())
newRootView.activateExtension(extension)
expect(extension.activate).toHaveBeenCalledWith(newRootView, "it worked", undefined)
newRootView.activatePackage(packageModule)
expect(packageModule.activate).toHaveBeenCalledWith(newRootView, "it worked")
newRootView.remove()
it "calls activate on the extension with the config data", ->
config = {}
rootView.activateExtension(extension, config)
expect(extension.activate).toHaveBeenCalledWith(rootView, undefined, config)
it "throws an exception if the package module has no 'name' property", ->
expect(-> rootView.activatePackage({ activate: -> })).toThrow()
it "throws an exception if the extension has no 'name' property", ->
expect(-> rootView.activateExtension({ activate: -> })).toThrow()
describe ".deactivatePackage(packageModule)", ->
it "deactivates and removes the package module from the package module map", ->
rootView.activatePackage(packageModule)
expect(rootView.packageModules[packageModule.name]).toBeTruthy()
spyOn(packageModule, "deactivate").andCallThrough()
rootView.deactivatePackage(packageModule)
expect(packageModule.deactivate).toHaveBeenCalled()
expect(rootView.packageModules[packageModule.name]).toBeFalsy()
describe ".deactivateExtension(extension)", ->
it "deactivates and removes the extension from the extension list", ->
rootView.activateExtension(extension)
expect(rootView.extensions[extension.name]).toBeTruthy()
spyOn(extension, "deactivate").andCallThrough()
rootView.deactivateExtension(extension)
expect(extension.deactivate).toHaveBeenCalled()
expect(rootView.extensions[extension.name]).toBeFalsy()
it "is called when the rootView is deactivated to deactivate all extensions", ->
rootView.activateExtension(extension)
spyOn(rootView, "deactivateExtension").andCallThrough()
spyOn(extension, "deactivate").andCallThrough()
it "is called when the rootView is deactivated to deactivate all packages", ->
rootView.activatePackage(packageModule)
spyOn(rootView, "deactivatePackage").andCallThrough()
spyOn(packageModule, "deactivate").andCallThrough()
rootView.deactivate()
expect(rootView.deactivateExtension).toHaveBeenCalled()
expect(extension.deactivate).toHaveBeenCalled()
expect(rootView.deactivatePackage).toHaveBeenCalled()
expect(packageModule.deactivate).toHaveBeenCalled()
describe "keymap wiring", ->
commandHandler = null

View File

@@ -0,0 +1,19 @@
describe "the `syntax` global", ->
describe ".getProperty(scopeDescriptor)", ->
it "returns the property with the most specific scope selector", ->
syntax.addProperties(".source.coffee .string.quoted.double.coffee", foo: bar: baz: 42)
syntax.addProperties(".source .string.quoted.double", foo: bar: baz: 22)
syntax.addProperties(".source", foo: bar: baz: 11)
syntax.addProperties(foo: bar: baz: 1)
expect(syntax.getProperty([".source.coffee", ".string.quoted.double.coffee"], "foo.bar.baz")).toBe 42
expect(syntax.getProperty([".source.js", ".string.quoted.double.js"], "foo.bar.baz")).toBe 22
expect(syntax.getProperty([".source.js", ".variable.assignment.js"], "foo.bar.baz")).toBe 11
expect(syntax.getProperty([".text"], "foo.bar.baz")).toBe 1
it "favors the most recently added properties in the event of a specificity tie", ->
syntax.addProperties(".source.coffee .string.quoted.single", foo: bar: baz: 42)
syntax.addProperties(".source.coffee .string.quoted.double", foo: bar: baz: 22)
expect(syntax.getProperty([".source.coffee", ".string.quoted.single"], "foo.bar.baz")).toBe 42
expect(syntax.getProperty([".source.coffee", ".string.quoted.single.double"], "foo.bar.baz")).toBe 22

View File

@@ -2,14 +2,6 @@ fs = require('fs')
TextMateBundle = require 'text-mate-bundle'
describe "TextMateBundle", ->
describe ".getPreferenceInScope(scope, preferenceName)", ->
it "returns the preference by the given name in the given scope or undefined if there isn't one", ->
expect(TextMateBundle.getPreferenceInScope('source.coffee', 'decreaseIndentPattern')).toBe '^\\s*(\\}|\\]|else|catch|finally)$'
expect(TextMateBundle.getPreferenceInScope('source.coffee', 'shellVariables')).toBeDefined()
it "returns the preference by the given name in the given scope for a scope registered via a comma-separated list of scopes", ->
expect(TextMateBundle.getPreferenceInScope('source.objc++', 'shellVariables')).toBeDefined()
describe ".getPreferencesByScopeSelector()", ->
it "logs warning, but does not raise errors if a preference can't be parsed", ->
bundlePath = fs.join(require.resolve('fixtures'), "test.tmbundle")

View File

@@ -1,29 +1,17 @@
fs = require 'fs'
plist = require 'plist'
TextMateTheme = require 'text-mate-theme'
Theme = require 'theme'
describe "TextMateTheme", ->
theme = null
[theme, themePath] = []
beforeEach ->
theme = TextMateTheme.getTheme('Twilight')
themePath = require.resolve(fs.join('fixtures', 'test.tmTheme'))
[theme] = Theme.load(themePath)
describe "@getNames()", ->
it "returns an array of available theme names", ->
names = TextMateTheme.getNames()
expect(names).toContain("Twilight")
expect(names).toContain("Blackboard")
describe "@activate(name)", ->
it "activates a theme by name", ->
spyOn theme, 'activate'
TextMateTheme.activate('Twilight')
expect(theme.activate).toHaveBeenCalled()
describe ".activate()", ->
it "applies the theme's stylesheet to the current window", ->
spyOn window, 'applyStylesheet'
theme.activate()
expect(window.applyStylesheet).toHaveBeenCalledWith(theme.name, theme.getStylesheet())
afterEach ->
theme.deactivate()
describe ".getRulesets()", ->
rulesets = null

View File

@@ -0,0 +1,48 @@
$ = require 'jquery'
fs = require 'fs'
Theme = require 'theme'
describe "@load(name)", ->
themes = null
beforeEach ->
$("#jasmine-content").append $("<div class='editor'></div>")
afterEach ->
theme.deactivate() for theme in themes
describe "TextMateTheme", ->
it "applies the theme's stylesheet to the current window", ->
expect($(".editor").css("background-color")).not.toBe("rgb(20, 20, 20)")
themePath = require.resolve(fs.join('fixtures', 'test.tmTheme'))
themes = Theme.load(themePath)
expect($(".editor").css("background-color")).toBe("rgb(20, 20, 20)")
describe "AtomTheme", ->
it "Loads and applies css from package.json in the correct order", ->
expect($(".editor").css("padding-top")).not.toBe("101px")
expect($(".editor").css("padding-right")).not.toBe("102px")
expect($(".editor").css("padding-bottom")).not.toBe("103px")
themePath = require.resolve(fs.join('fixtures', 'test-atom-theme'))
themes = Theme.load(themePath)
expect($(".editor").css("padding-top")).toBe("101px")
expect($(".editor").css("padding-right")).toBe("102px")
expect($(".editor").css("padding-bottom")).toBe("103px")
describe "when name is an array of themes", ->
it "loads all themes in order", ->
firstThemePath = require.resolve(fs.join('fixtures', 'test.tmTheme'))
secondThemePath = require.resolve(fs.join('fixtures', 'test-atom-theme'))
expect($(".editor").css("padding-top")).not.toBe("101px")
expect($(".editor").css("padding-right")).not.toBe("102px")
expect($(".editor").css("padding-bottom")).not.toBe("103px")
expect($(".editor").css("color")).not.toBe("rgb(0, 255, 0)")
themes = Theme.load([firstThemePath, secondThemePath])
expect($(".editor").css("padding-top")).toBe("101px")
expect($(".editor").css("padding-right")).toBe("102px")
expect($(".editor").css("padding-bottom")).toBe("103px")
expect($(".editor").css("color")).toBe("rgb(255, 0, 0)")

View File

@@ -48,6 +48,16 @@ describe "Window", ->
requireStylesheet('atom.css')
expect($('head style').length).toBe lengthBefore + 1
describe ".disableStyleSheet(path)", ->
it "removes styling applied by given stylesheet path", ->
cssPath = require.resolve(fs.join("fixtures", "css.css"))
expect($(document.body).css('font-weight')).not.toBe("bold")
requireStylesheet(cssPath)
expect($(document.body).css('font-weight')).toBe("bold")
removeStylesheet(cssPath)
expect($(document.body).css('font-weight')).not.toBe("bold")
describe "before the window is unloaded", ->
it "saves the serialized state of the root view to the atom object so it can be rehydrated after reload", ->
expect(atom.getRootViewStateForPath(window.rootView.project.getPath())).toBeUndefined()

View File

@@ -1,4 +1,5 @@
body {
font-size: 1234px;
width: 110%;
font-weight: bold !important;
}

View File

@@ -0,0 +1,7 @@
.editor {
padding-top: 101px;
padding-right: 101px;
padding-bottom: 101px;
color: red;
}

View File

@@ -0,0 +1,5 @@
.editor {
/* padding-top: 103px;
padding-right: 103px;*/
padding-bottom: 103px;
}

View File

@@ -0,0 +1,3 @@
{
"stylesheets": ["first.css", "second.css", "last.css"]
}

View File

@@ -0,0 +1,5 @@
.editor {
/* padding-top: 102px;*/
padding-right: 102px;
padding-bottom: 102px;
}

514
spec/fixtures/test.tmTheme vendored Normal file
View File

@@ -0,0 +1,514 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>author</key>
<string>Michael Sheets</string>
<key>name</key>
<string>Twilight</string>
<key>settings</key>
<array>
<dict>
<key>settings</key>
<dict>
<key>background</key>
<string>#141414</string>
<key>caret</key>
<string>#A7A7A7</string>
<key>foreground</key>
<string>#F8F8F8</string>
<key>invisibles</key>
<string>#FFFFFF40</string>
<key>lineHighlight</key>
<string>#FFFFFF08</string>
<key>selection</key>
<string>#DDF0FF33</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Comment</string>
<key>scope</key>
<string>comment</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string>italic</string>
<key>foreground</key>
<string>#5F5A60</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Constant</string>
<key>scope</key>
<string>constant</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#CF6A4C</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Entity</string>
<key>scope</key>
<string>entity</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#9B703F</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Keyword</string>
<key>scope</key>
<string>keyword</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#CDA869</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Storage</string>
<key>scope</key>
<string>storage</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#F9EE98</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>String</string>
<key>scope</key>
<string>string</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#8F9D6A</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Support</string>
<key>scope</key>
<string>support</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#9B859D</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Variable</string>
<key>scope</key>
<string>variable</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#7587A6</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Invalid Deprecated</string>
<key>scope</key>
<string>invalid.deprecated</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string>italic underline</string>
<key>foreground</key>
<string>#D2A8A1</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Invalid Illegal</string>
<key>scope</key>
<string>invalid.illegal</string>
<key>settings</key>
<dict>
<key>background</key>
<string>#562D56BF</string>
<key>foreground</key>
<string>#F8F8F8</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>-----------------------------------</string>
<key>settings</key>
<dict/>
</dict>
<dict>
<key>name</key>
<string>♦ Embedded Source</string>
<key>scope</key>
<string>text source</string>
<key>settings</key>
<dict>
<key>background</key>
<string>#B0B3BA14</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>♦ Embedded Source (Bright)</string>
<key>scope</key>
<string>text.html.ruby source</string>
<key>settings</key>
<dict>
<key>background</key>
<string>#B1B3BA21</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>♦ Entity inherited-class</string>
<key>scope</key>
<string>entity.other.inherited-class</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string>italic</string>
<key>foreground</key>
<string>#9B5C2E</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>♦ String embedded-source</string>
<key>scope</key>
<string>string source</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#DAEFA3</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>♦ String constant</string>
<key>scope</key>
<string>string constant</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#DDF2A4</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>♦ String.regexp</string>
<key>scope</key>
<string>string.regexp</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#E9C062</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>♦ String.regexp.«special»</string>
<key>scope</key>
<string>string.regexp constant.character.escape, string.regexp source.ruby.embedded, string.regexp string.regexp.arbitrary-repitition</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#CF7D34</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>♦ String variable</string>
<key>scope</key>
<string>string variable</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#8A9A95</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>♦ Support.function</string>
<key>scope</key>
<string>support.function</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#DAD085</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>♦ Support.constant</string>
<key>scope</key>
<string>support.constant</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#CF6A4C</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>c C/C++ Preprocessor Line</string>
<key>scope</key>
<string>meta.preprocessor.c</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#8996A8</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>c C/C++ Preprocessor Directive</string>
<key>scope</key>
<string>meta.preprocessor.c keyword</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#AFC4DB</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>✘ Doctype/XML Processing</string>
<key>scope</key>
<string>meta.tag.sgml.doctype, meta.tag.sgml.doctype entity, meta.tag.sgml.doctype string, meta.tag.preprocessor.xml, meta.tag.preprocessor.xml entity, meta.tag.preprocessor.xml string</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#494949</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>✘ Meta.tag.«all»</string>
<key>scope</key>
<string>declaration.tag, declaration.tag entity, meta.tag, meta.tag entity</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#AC885B</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>✘ Meta.tag.inline</string>
<key>scope</key>
<string>declaration.tag.inline, declaration.tag.inline entity, source entity.name.tag, source entity.other.attribute-name, meta.tag.inline, meta.tag.inline entity</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#E0C589</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>§ css tag-name</string>
<key>scope</key>
<string>meta.selector.css entity.name.tag</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#CDA869</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>§ css:pseudo-class</string>
<key>scope</key>
<string>meta.selector.css entity.other.attribute-name.tag.pseudo-class</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#8F9D6A</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>§ css#id</string>
<key>scope</key>
<string>meta.selector.css entity.other.attribute-name.id</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#8B98AB</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>§ css.class</string>
<key>scope</key>
<string>meta.selector.css entity.other.attribute-name.class</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#9B703F</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>§ css property-name:</string>
<key>scope</key>
<string>support.type.property-name.css</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#C5AF75</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>§ css property-value;</string>
<key>scope</key>
<string>meta.property-group support.constant.property-value.css, meta.property-value support.constant.property-value.css</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#F9EE98</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>§ css @at-rule</string>
<key>scope</key>
<string>meta.preprocessor.at-rule keyword.control.at-rule</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#8693A5</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>§ css additional-constants</string>
<key>scope</key>
<string>meta.property-value support.constant.named-color.css, meta.property-value constant</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#CA7840</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>§ css constructor.argument</string>
<key>scope</key>
<string>meta.constructor.argument.css</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#8F9D6A</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>⎇ diff.header</string>
<key>scope</key>
<string>meta.diff, meta.diff.header, meta.separator</string>
<key>settings</key>
<dict>
<key>background</key>
<string>#0E2231</string>
<key>fontStyle</key>
<string>italic</string>
<key>foreground</key>
<string>#F8F8F8</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>⎇ diff.deleted</string>
<key>scope</key>
<string>markup.deleted</string>
<key>settings</key>
<dict>
<key>background</key>
<string>#420E09</string>
<key>foreground</key>
<string>#F8F8F8</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>⎇ diff.changed</string>
<key>scope</key>
<string>markup.changed</string>
<key>settings</key>
<dict>
<key>background</key>
<string>#4A410D</string>
<key>foreground</key>
<string>#F8F8F8</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>⎇ diff.inserted</string>
<key>scope</key>
<string>markup.inserted</string>
<key>settings</key>
<dict>
<key>background</key>
<string>#253B22</string>
<key>foreground</key>
<string>#F8F8F8</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Markup: List</string>
<key>scope</key>
<string>markup.list</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#F9EE98</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Markup: Heading</string>
<key>scope</key>
<string>markup.heading</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#CF6A4C</string>
</dict>
</dict>
</array>
<key>uuid</key>
<string>766026CB-703D-4610-B070-8DE07D967C5F</string>
</dict>
</plist>

View File

@@ -19,15 +19,17 @@ requireStylesheet "jasmine.css"
require.paths.unshift(require.resolve('fixtures/packages'))
# Load TextMate bundles, which specs rely on (but not other packages)
atom.loadPackages(atom.getAvailableTextMateBundles())
beforeEach ->
window.fixturesProject = new Project(require.resolve('fixtures'))
window.resetTimeouts()
# don't load or save user configuration
# reset config after each spec; don't load or save from/to `config.json`
window.config = new Config()
spyOn(config, 'load')
spyOn(config, 'save')
config.assignDefaults()
config.set "editor.fontSize", 16
# make editor display updates synchronous

View File

@@ -121,7 +121,7 @@ describe 'Child Processes', ->
cmd = "for i in {1..20000}; do echo $RANDOM; done"
options =
stdout: (data) -> output.push(data)
stderr: (data) -> console.log data.length
stderr: (data) ->
ChildProcess.exec(cmd, options)

View 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
View 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)

View File

@@ -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...)

View File

@@ -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)

View File

@@ -3,7 +3,6 @@ _ = require 'underscore'
fs = require 'fs'
BindingSet = require 'binding-set'
Specificity = require 'specificity'
module.exports =
class Keymap

View File

@@ -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
View 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)

View File

@@ -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
View 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]

View File

@@ -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) ->

View 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)

View File

@@ -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
View 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)

View File

@@ -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>"

View File

@@ -36,7 +36,7 @@ describe "CommandPanel", ->
rootView.deactivate()
rootView2.attachToDom()
commandPanel = rootView2.activateExtension(CommandPanel)
commandPanel = rootView2.activatePackage(CommandPanel)
expect(rootView2.find('.command-panel')).toExist()
expect(commandPanel.miniEditor.getText()).toBe 'abc'
expect(commandPanel.miniEditor.isFocused).toBeTruthy()
@@ -49,7 +49,7 @@ describe "CommandPanel", ->
rootView3 = RootView.deserialize(rootView2.serialize())
rootView2.deactivate()
rootView3.attachToDom()
commandPanel = rootView3.activateExtension(CommandPanel)
commandPanel = rootView3.activatePackage(CommandPanel)
expect(commandPanel.miniEditor.isFocused).toBeFalsy()
rootView3.deactivate()
@@ -71,7 +71,7 @@ describe "CommandPanel", ->
rootView.deactivate()
rootView2.attachToDom()
commandPanel = rootView2.activateExtension(CommandPanel)
commandPanel = rootView2.activatePackage(CommandPanel)
expect(commandPanel.history.length).toBe(2)
expect(commandPanel.history[0]).toBe('/test2')
expect(commandPanel.history[1]).toBe('/test3')

View File

@@ -8,7 +8,7 @@ describe "EventPalette", ->
beforeEach ->
rootView = new RootView(require.resolve('fixtures/sample.js'))
rootView.activateExtension(EventPalette)
atom.loadPackage("event-palette")
palette = EventPalette.instance
rootView.attachToDom().focus()
rootView.trigger 'event-palette:toggle'

View File

@@ -10,7 +10,7 @@ describe 'FuzzyFinder', ->
beforeEach ->
rootView = new RootView(require.resolve('fixtures/sample.js'))
rootView.enableKeymap()
rootView.activateExtension(FuzzyFinder)
atom.loadPackage("fuzzy-finder")
finder = FuzzyFinder.instance
afterEach ->

View File

@@ -73,7 +73,8 @@ class FuzzyFinder extends SelectList
else
@setLoading("Indexing...")
@rootView.project.getFilePaths().done (paths) =>
ignoredNames = config.get("fuzzy-finder.ignoredNames")
ignoredNames = config.get("fuzzyFinder.ignoredNames") or []
ignoredNames = ignoredNames.concat(config.get("core.ignoredNames") or [])
@projectPaths = paths
if ignoredNames
@projectPaths = @projectPaths.filter (path) ->

View File

@@ -7,7 +7,7 @@ describe "MarkdownPreview", ->
beforeEach ->
rootView = new RootView(require.resolve('fixtures/markdown'))
rootView.activateExtension(MarkdownPreview)
atom.loadPackage("markdown-preview")
markdownPreview = MarkdownPreview.instance
rootView.attachToDom()

View File

@@ -7,7 +7,7 @@ describe "OutlineView", ->
beforeEach ->
rootView = new RootView(require.resolve('fixtures'))
rootView.activateExtension(OutlineView)
atom.loadPackage("outline-view")
outlineView = OutlineView.instance
rootView.attachToDom()
setArraySpy = spyOn(outlineView, 'setArray').andCallThrough()

View File

@@ -11,7 +11,7 @@ describe "Tabs", ->
rootView = new RootView(require.resolve('fixtures/sample.js'))
rootView.open('sample.txt')
rootView.simulateDomAttachment()
rootView.activateExtension(Tabs)
atom.loadPackage("tabs")
editor = rootView.getActiveEditor()
tabs = rootView.find('.tabs').view()

View File

@@ -13,7 +13,7 @@ describe "TreeView", ->
rootView = new RootView(require.resolve('fixtures/tree-view'))
project = rootView.project
rootView.activateExtension(TreeView)
atom.loadPackage("tree-view")
treeView = rootView.find(".tree-view").view()
treeView.root = treeView.find('> li:first').view()
sampleJs = treeView.find('.file:contains(tree-view.js)')
@@ -51,7 +51,7 @@ describe "TreeView", ->
rootView.deactivate()
rootView = new RootView
rootView.activateExtension(TreeView)
rootView.activatePackage(TreeView)
treeView = rootView.find(".tree-view").view()
it "does not create a root node", ->
@@ -74,7 +74,7 @@ describe "TreeView", ->
describe "when the prototypes deactivate method is called", ->
it "calls the deactivate on tree view instance", ->
spyOn(treeView, "deactivate").andCallThrough()
rootView.deactivateExtension(TreeView)
rootView.deactivatePackage(TreeView)
expect(treeView.deactivate).toHaveBeenCalled()
describe "serialization", ->
@@ -89,7 +89,7 @@ describe "TreeView", ->
newRootView = RootView.deserialize(rootView.serialize())
rootView.deactivate() # Deactivates previous TreeView
newRootView.activateExtension(TreeView)
newRootView.activatePackage(TreeView)
newTreeView = newRootView.find(".tree-view").view()
@@ -106,7 +106,7 @@ describe "TreeView", ->
rootView.deactivate() # Deactivates previous TreeView
newRootView.attachToDom()
newRootView.activateExtension(TreeView)
newRootView.activatePackage(TreeView)
newTreeView = newRootView.find(".tree-view").view()
expect(newTreeView).toMatchSelector ':focus'
@@ -589,7 +589,7 @@ describe "TreeView", ->
rootView = new RootView(rootDirPath)
project = rootView.project
rootView.activateExtension(TreeView)
rootView.activatePackage(TreeView)
treeView = rootView.find(".tree-view").view()
dirView = treeView.root.entries.find('.directory:contains(test-dir)').view()
dirView.expand()

View File

@@ -124,6 +124,13 @@ module.exports =
md5ForPath: (path) ->
$native.md5ForPath(path)
resolve: (paths...) ->
to = paths.pop()
for from in paths
path = @join(from, to)
return path if @exists(path)
undefined
isCompressedExtension: (ext) ->
_.contains([
'.gz'

View File

@@ -85,3 +85,16 @@ _.mixin
endsWith: (string, suffix) ->
string.indexOf(suffix, string.length - suffix.length) isnt -1
valueForKeyPath: (object, keyPath) ->
keys = keyPath.split('.')
for key in keys
object = object[key]
return unless object?
object
compactObject: (object) ->
newObject = {}
for key, value of object
newObject[key] = value if value?
newObject