Merge remote-tracking branch 'origin/dev' into better-anchors

This commit is contained in:
Nathan Sobo
2013-02-02 16:47:09 -07:00
98 changed files with 2051 additions and 740 deletions

11
.atom/config.json Normal file
View File

@@ -0,0 +1,11 @@
{
"editor": {
"fontSize": 16
},
"core": {
"themes": [
"atom-dark-ui",
"atom-dark-syntax"
]
}
}

1
.atom/themes/README.md Normal file
View File

@@ -0,0 +1 @@
All themes in this directory will be automatically loaded

8
.atom/user.css Normal file
View File

@@ -0,0 +1,8 @@
/* User styles */
.tree-view {
}
.editor {
}

View File

@@ -15,6 +15,8 @@
styleguides
* Include thoughtfully worded [Jasmine](http://pivotal.github.com/jasmine/)
specs
* Style new elements in both the light and dark default themes when
appropriate
* New packages go in `src/packages/`
* Add 3rd-party packages by submoduling in `vendor/packages/`
* Commit messages are in the present tense

View File

@@ -21,7 +21,7 @@ Requirements
Atom is installed! Type `atom [path]` from the commmand line or find it in `/Applications/Atom.app`
## Your ~/.atom Directory
A basic ~/.atom directory is installed when you run `rake install`. Take a look at ~/.atom/atom.coffee for more information.
A basic ~/.atom directory is installed when you run `rake install`. Take a look at ~/.atom/user.coffee for more information.
## Basic Keyboard shortcuts
Atom doesn't have much in the way of menus yet. Use these keyboard shortcuts to
@@ -53,7 +53,7 @@ Most default OS X keybindings also work.
## Init Script
Atom will require `~/.atom/atom.coffee` whenever a window is opened or reloaded if it is present in your
Atom will require `~/.atom/user.coffee` whenever a window is opened or reloaded if it is present in your
home directory. This is a rudimentary jumping off point for your own customizations.
## Command Panel

View File

@@ -76,14 +76,26 @@ task "create-dot-atom" do
dot_atom_template_path = ATOM_SRC_PATH + "/.atom"
replace_dot_atom = false
next if File.exists?(DOT_ATOM_PATH)
if File.exists?(DOT_ATOM_PATH)
user_config = "#{DOT_ATOM_PATH}/user.coffee"
old_user_config = "#{DOT_ATOM_PATH}/atom.coffee"
if File.exists?(old_user_config)
`mv #{old_user_config} #{user_config}`
puts "\033[32mRenamed #{old_user_config} to #{user_config}\033[0m"
end
next
end
`rm -rf "#{DOT_ATOM_PATH}"`
`mkdir "#{DOT_ATOM_PATH}"`
`cp "#{dot_atom_template_path}/atom.coffee" "#{DOT_ATOM_PATH}"`
`cp "#{dot_atom_template_path}/packages" "#{DOT_ATOM_PATH}"`
`cp "#{dot_atom_template_path}/user.coffee" "#{DOT_ATOM_PATH}"`
`cp "#{dot_atom_template_path}/user.css" "#{DOT_ATOM_PATH}"`
`cp -r "#{dot_atom_template_path}/packages" "#{DOT_ATOM_PATH}"`
`cp -r "#{ATOM_SRC_PATH}/themes" "#{DOT_ATOM_PATH}"`
`cp "#{ATOM_SRC_PATH}/vendor/themes/IR_Black.tmTheme" "#{DOT_ATOM_PATH}/themes"`
end
desc "Clone default bundles into vendor/bundles directory"

View File

@@ -9,8 +9,8 @@ gutter.
You can change the background color using the following CSS:
```css
.editor.focused .line.cursor-line,
.editor.focused .line-number.cursor-line {
.editor.is-focused .line.cursor-line,
.editor.is-focused .line-number.cursor-line {
background-color: green;
}
```
@@ -18,7 +18,7 @@ You can change the background color using the following CSS:
You can change the line number foreground color using the following CSS:
```css
.editor.focused .line-number.cursor-line {
.editor.is-focused .line-number.cursor-line {
color: blue;
}
```

View File

@@ -26,17 +26,20 @@ describe "the `atom` global", ->
describe "keymap loading", ->
describe "when package.json does not contain a 'keymaps' manifest", ->
it "loads all keymaps in the directory", ->
it "loads all the .cson/.json files in the keymaps directory", ->
element1 = $$ -> @div class: 'test-1'
element2 = $$ -> @div class: 'test-2'
element3 = $$ -> @div class: 'test-3'
expect(keymap.bindingsForElement(element1)['ctrl-z']).toBeUndefined()
expect(keymap.bindingsForElement(element2)['ctrl-z']).toBeUndefined()
expect(keymap.bindingsForElement(element3)['ctrl-z']).toBeUndefined()
atom.loadPackage("package-with-module")
expect(keymap.bindingsForElement(element1)['ctrl-z']).toBe "test-1"
expect(keymap.bindingsForElement(element2)['ctrl-z']).toBe "test-2"
expect(keymap.bindingsForElement(element3)['ctrl-z']).toBeUndefined()
describe "when package.json contains a 'keymaps' manifest", ->
it "loads only the keymaps specified by the manifest, in the specified order", ->

View File

@@ -111,11 +111,11 @@ describe "Editor", ->
editor.isFocused = false
editor.hiddenInput.focus()
expect(editor.isFocused).toBeTruthy()
expect(editor).toHaveClass('focused')
expect(editor).toHaveClass('is-focused')
editor.hiddenInput.focusout()
expect(editor.isFocused).toBeFalsy()
expect(editor).not.toHaveClass('focused')
expect(editor).not.toHaveClass('is-focused')
describe "when the activeEditSession's file is modified on disk", ->
it "triggers an alert", ->
@@ -520,9 +520,8 @@ describe "Editor", ->
beforeEach ->
expect(editor.css('font-family')).not.toBe 'Courier'
it "sets the initial font family based on the value from config", ->
expect($("head style.font-family")).toExist()
expect($("head style.font-family").text()).toMatch "{font-family: #{config.get('editor.fontFamily')}}"
it "when there is no config in fontFamily don't set it", ->
expect($("head style.font-family")).not.toExist()
describe "when the font family changes", ->
it "updates the font family on new and existing editors", ->
@@ -544,7 +543,7 @@ describe "Editor", ->
lineHeightBefore = editor.lineHeight
charWidthBefore = editor.charWidth
config.set("editor.fontFamily", "Courier")
config.set("editor.fontFamily", "Inconsolata")
editor.setCursorScreenPosition [5, 6]
expect(editor.charWidth).not.toBe charWidthBefore
expect(editor.getCursorView().position()).toEqual { top: 5 * editor.lineHeight, left: 6 * editor.charWidth }
@@ -553,6 +552,7 @@ describe "Editor", ->
describe "font size", ->
beforeEach ->
expect(editor.css('font-size')).not.toBe "20px"
expect(editor.css('font-size')).not.toBe "10px"
it "sets the initial font size based on the value from config", ->
expect($("head style.font-size")).toExist()
@@ -615,6 +615,23 @@ describe "Editor", ->
config.set("editor.fontSize", 10)
expect(editor.renderedLines.find(".line").length).toBeGreaterThan originalLineCount
describe "when the editor is detached", ->
it "updates the font-size correctly and recalculates the dimensions by placing the rendered lines on the DOM", ->
rootView.attachToDom()
rootView.height(200)
rootView.width(200)
newEditor = editor.splitRight()
newEditorParent = newEditor.parent()
newEditor.detach()
config.set("editor.fontSize", 10)
newEditorParent.append(newEditor)
expect(newEditor.lineHeight).toBe editor.lineHeight
expect(newEditor.charWidth).toBe editor.charWidth
expect(newEditor.getCursorView().position()).toEqual editor.getCursorView().position()
expect(newEditor.verticalScrollbarContent.height()).toBe editor.verticalScrollbarContent.height()
describe "mouse events", ->
beforeEach ->
editor.attachToDom()

View File

@@ -23,8 +23,7 @@ describe "the `syntax` global", ->
expect(syntax.grammarForFilePath("/tmp/.git/config").name).toBe "Git Config"
it "uses plain text if no grammar can be found", ->
filePath = require.resolve("this-is-not-a-real-file")
expect(syntax.grammarForFilePath(filePath).name).toBe "Plain Text"
expect(syntax.grammarForFilePath("this-is-not-a-real-file").name).toBe "Plain Text"
describe ".getProperty(scopeDescriptor)", ->
it "returns the property with the most specific scope selector", ->

View File

@@ -42,7 +42,7 @@ describe "TextMateTheme", ->
selector: ".invalid.deprecated"
properties:
'color': "#D2A8A1"
# 'font-style': 'italic'
'font-style': 'italic'
'text-decoration': 'underline'
expect(rulesets[13]).toEqual

View File

@@ -13,6 +13,14 @@ describe "Window", ->
atom.setRootViewStateForPath(rootView.project.getPath(), null)
$(window).off 'beforeunload'
describe "window is loaded", ->
it "has .is-focused on the body tag", ->
expect($("body").hasClass("is-focused")).toBe true
it "doesn't have .is-focused on the window blur", ->
$(window).blur()
expect($("body").hasClass("is-focused")).toBe false
describe ".close()", ->
it "is triggered by the 'core:close' event", ->
spyOn window, 'close'

View File

@@ -0,0 +1,2 @@
".test-3":
"ctrl-z": "test-3"

View File

@@ -85,7 +85,7 @@ jasmine.unspy = (object, methodName) ->
throw new Error("Not a spy") unless object[methodName].originalValue?
object[methodName] = object[methodName].originalValue
jasmine.getEnv().defaultTimeoutInterval = 500
jasmine.getEnv().defaultTimeoutInterval = 1000
window.keyIdentifierForKey = (key) ->
if key.length > 1 # named key

View File

@@ -0,0 +1,60 @@
CSON = require 'cson'
describe "CSON", ->
describe "@stringify(object)", ->
describe "when the object is undefined", ->
it "throws an exception", ->
expect(-> CSON.stringify()).toThrow()
describe "when the object is a function", ->
it "throws an exception", ->
expect(-> CSON.stringify(-> 'function')).toThrow()
describe "when the object contains a function", ->
it "throws an exception", ->
expect(-> CSON.stringify(a: -> 'function')).toThrow()
describe "when formatting an undefined key", ->
it "does not include the key in the formatted CSON", ->
expect(CSON.stringify(b: 1, c: undefined)).toBe "'b': 1"
describe "when formatting an empty object", ->
it "returns the empty string", ->
expect(CSON.stringify({})).toBe ""
describe "when formatting a string", ->
it "returns formatted CSON", ->
expect(CSON.stringify(a: 'b')).toBe "'a': 'b'"
it "escapes single quotes", ->
expect(CSON.stringify(a: "'b'")).toBe "'a': '\\\'b\\\''"
it "doesn't escape double quotes", ->
expect(CSON.stringify(a: '"b"')).toBe "'a': '\"b\"'"
describe "when formatting a boolean", ->
it "returns formatted CSON", ->
expect(CSON.stringify(a: true)).toBe "'a': true"
expect(CSON.stringify(a: false)).toBe "'a': false"
describe "when formatting a number", ->
it "returns formatted CSON", ->
expect(CSON.stringify(a: 14)).toBe "'a': 14"
expect(CSON.stringify(a: 1.23)).toBe "'a': 1.23"
describe "when formatting null", ->
it "returns formatted CSON", ->
expect(CSON.stringify(a: null)).toBe "'a': null"
describe "when formatting an array", ->
describe "when the array is empty", ->
it "puts the array on a single line", ->
expect(CSON.stringify([])).toBe "[]"
it "returns formatted CSON", ->
expect(CSON.stringify(a: ['b'])).toBe "'a': [\n 'b'\n]"
expect(CSON.stringify(a: ['b', 4])).toBe "'a': [\n 'b'\n 4\n]"
describe "when formatting an object", ->
it "returns formatted CSON", ->
expect(CSON.stringify(a: {b: 'c'})).toBe "'a':\n 'b': 'c'"

View File

@@ -128,3 +128,8 @@ describe "fs", ->
describe ".md5ForPath(path)", ->
it "returns the MD5 hash of the file at the given path", ->
expect(fs.md5ForPath(require.resolve('fixtures/sample.js'))).toBe 'dd38087d0d7e3e4802a6d3f9b9745f2b'
describe ".list(path, extensions)", ->
it "returns the paths with the specified extensions", ->
path = require.resolve('fixtures/css.css')
expect(fs.list(require.resolve('fixtures'), ['.css'])).toEqual [path]

View File

@@ -26,15 +26,12 @@ class AtomPackage extends Package
@metadata = fs.readObject(metadataPath)
loadKeymaps: ->
for keymapPath in @getKeymapPaths()
keymap.load(keymapPath)
getKeymapPaths: ->
if keymaps = @metadata?.keymaps
keymaps.map (relativePath) =>
keymaps = keymaps.map (relativePath) =>
fs.resolve(@keymapsDirPath, relativePath, ['cson', 'json', ''])
keymap.load(keymapPath) for keymapPath in keymaps
else
fs.list(@keymapsDirPath)
keymap.loadDirectory(@keymapsDirPath)
loadStylesheets: ->
for stylesheetPath in @getStylesheetPaths()

View File

@@ -3,9 +3,16 @@ Theme = require 'theme'
module.exports =
class AtomTheme extends Theme
loadStylesheet: (stylesheetPath)->
@stylesheets[stylesheetPath] = fs.read(stylesheetPath)
load: ->
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)
if /\.css$/.test(@path)
@loadStylesheet @path
else
json = fs.read(fs.join(@path, "package.json"))
for stylesheetName in JSON.parse(json).stylesheets
stylesheetPath = fs.join(@path, stylesheetName)
@loadStylesheet stylesheetPath
super

View File

@@ -50,15 +50,21 @@ _.extend atom,
.filter (name) -> not _.contains(disabledPackages, name)
loadThemes: ->
themeNames = config.get("core.themes") ? ['Atom - Dark', 'IR_Black']
themeNames = config.get("core.themes") ? ['atom-dark-ui', 'atom-dark-syntax']
themeNames = [themeNames] unless _.isArray(themeNames)
@loadTheme(themeName) for themeName in themeNames
@loadUserStylesheet()
loadTheme: (name) ->
@loadedThemes.push Theme.load(name)
loadUserStylesheet: ->
userStylesheetPath = fs.join(config.configDirPath, 'user.css')
if fs.isFile(userStylesheetPath)
applyStylesheet(userStylesheetPath, fs.read(userStylesheetPath), 'userTheme')
getAtomThemeStylesheets: ->
themeNames = config.get("core.themes") ? ['Atom - Dark', 'IR_Black']
themeNames = config.get("core.themes") ? ['atom-dark-ui', 'atom-dark-syntax']
themeNames = [themeNames] unless _.isArray(themeNames)
open: (args...) ->

View File

@@ -4,7 +4,7 @@ EventEmitter = require 'event-emitter'
configDirPath = fs.absolute("~/.atom")
configJsonPath = fs.join(configDirPath, "config.json")
userInitScriptPath = fs.join(configDirPath, "atom.coffee")
userInitScriptPath = fs.join(configDirPath, "user.coffee")
bundledPackagesDirPath = fs.join(resourcePath, "src/packages")
bundledThemesDirPath = fs.join(resourcePath, "themes")
vendoredPackagesDirPath = fs.join(resourcePath, "vendor/packages")

View File

@@ -18,7 +18,7 @@ class EditSession
if fs.exists(state.buffer)
session = project.buildEditSessionForPath(state.buffer)
else
console.warn "Could not build edit session for path '#{state.buffer}' because that file no longer exists"
console.warn "Could not build edit session for path '#{state.buffer}' because that file no longer exists" if state.buffer
session = project.buildEditSessionForPath(null)
session.setScrollTop(state.scrollTop)
session.setScrollLeft(state.scrollLeft)

View File

@@ -14,7 +14,6 @@ _ = require 'underscore'
module.exports =
class Editor extends View
@configDefaults:
fontFamily: "Inconsolata, Monaco, Courier"
fontSize: 20
showInvisibles: false
autosave: false
@@ -352,11 +351,11 @@ class Editor extends View
@hiddenInput.on 'focus', =>
@rootView()?.editorFocused(this)
@isFocused = true
@addClass 'focused'
@addClass 'is-focused'
@hiddenInput.on 'focusout', =>
@isFocused = false
@removeClass 'focused'
@removeClass 'is-focused'
@autosave() if config.get "editor.autosave"
@underlayer.on 'click', (e) =>
@@ -697,6 +696,7 @@ class Editor extends View
parseInt(@css("font-size"))
setFontFamily: (fontFamily) ->
return if fontFamily == undefined
headTag = $("head")
styleTag = headTag.find("style.font-family")
if styleTag.length == 0
@@ -804,6 +804,10 @@ class Editor extends View
@overlayer.append(view)
calculateDimensions: ->
if not @isOnDom()
detachedEditorParent = _.last(@parents()) ? this
$(document.body).append(detachedEditorParent)
fragment = $('<pre class="line" style="position: absolute; visibility: hidden;"><span>x</span></div>')
@renderedLines.append(fragment)
@@ -815,6 +819,8 @@ class Editor extends View
@height(@lineHeight) if @mini
fragment.remove()
$(detachedEditorParent).detach()
updateLayerDimensions: ->
@gutter.calculateWidth()

View File

@@ -1,4 +1,3 @@
$ = require 'jquery'
_ = require 'underscore'
Subscriber = require 'subscriber'
GitRepository = require 'git-repository'
@@ -6,9 +5,9 @@ GitRepository = require 'git-repository'
module.exports =
class Git
@open: (path) ->
@open: (path, options) ->
try
new Git(path)
new Git(path, options)
catch e
null
@@ -24,9 +23,12 @@ class Git
working_dir_typechange: 1 << 10
ignore: 1 << 14
constructor: (path) ->
constructor: (path, options={}) ->
@repo = new GitRepository(path)
@subscribe $(window), 'focus', => @refreshIndex()
refreshIndexOnFocus = options.refreshIndexOnFocus ? true
if refreshIndexOnFocus
$ = require 'jquery'
@subscribe $(window), 'focus', => @refreshIndex()
getRepo: ->
unless @repo?

View File

@@ -35,7 +35,7 @@ class Keymap
@loadDirectory(fs.join(config.configDirPath, 'keymaps'))
loadDirectory: (directoryPath) ->
@load(filePath) for filePath in fs.list(directoryPath)
@load(filePath) for filePath in fs.list(directoryPath, ['.cson', '.json'])
load: (path) ->
@add(fs.readObject(path))

View File

@@ -1,4 +1,4 @@
Task = require 'Task'
Task = require 'task'
module.exports =
class LoadTextMatePackagesTask extends Task

View File

@@ -44,17 +44,17 @@ class TextMateTheme extends Theme
'color': @translateColor(foreground)
@rulesets.push
selector: '.editor.focused .cursor'
selector: '.editor.is-focused .cursor'
properties:
'border-color': @translateColor(caret)
@rulesets.push
selector: '.editor.focused .selection .region'
selector: '.editor.is-focused .selection .region'
properties:
'background-color': @translateColor(selection)
@rulesets.push
selector: '.editor.focused .line-number.cursor-line-no-selection, .editor.focused .line.cursor-line'
selector: '.editor.is-focused .line-number.cursor-line-no-selection, .editor.is-focused .line.cursor-line'
properties:
'background-color': @translateColor(lineHighlight)
@@ -75,8 +75,8 @@ class TextMateTheme extends Theme
if fontStyle
fontStyles = fontStyle.split(/\s+/)
# properties['font-weight'] = 'bold' if _.contains(fontStyles, 'bold')
# properties['font-style'] = 'italic' if _.contains(fontStyles, 'italic')
properties['font-weight'] = 'bold' if _.contains(fontStyles, 'bold')
properties['font-style'] = 'italic' if _.contains(fontStyles, 'italic')
properties['text-decoration'] = 'underline' if _.contains(fontStyles, 'underline')
properties['color'] = @translateColor(foreground) if foreground

View File

@@ -11,7 +11,7 @@ class Theme
if fs.exists(name)
path = name
else
path = fs.resolve(config.themeDirPaths..., name, ['', '.tmTheme'])
path = fs.resolve(config.themeDirPaths..., name, ['', '.tmTheme', '.css'])
throw new Error("No theme exists named '#{name}'") unless path

View File

@@ -28,6 +28,7 @@ windowAdditions =
$(window).on 'core:close', => @close()
$(window).command 'window:close', => @close()
$(window).on 'focus blur', => $("body").toggleClass("is-focused")
# This method is intended only to be run when starting a normal application
# Note: RootView assigns itself on window on initialization so that

View File

@@ -6,9 +6,8 @@ describe "CommandLogger", ->
beforeEach ->
rootView = new RootView(require.resolve('fixtures/sample.js'))
atom.loadPackage('command-logger').getInstance()
commandLogger = atom.loadPackage('command-logger')
editor = rootView.getActiveEditor()
commandLogger = CommandLogger.instance
afterEach ->
rootView.deactivate()
@@ -44,9 +43,11 @@ describe "CommandLogger", ->
describe "when an event is ignored", ->
it "does not create a node for that event", ->
commandLogger.ignoredEvents.push 'editor:delete-line'
commandLoggerView = commandLogger.getInstance()
commandLoggerView.ignoredEvents.push 'editor:delete-line'
editor.trigger 'editor:delete-line'
nodes = commandLogger.createNodes()
commandLoggerView.eventLog = commandLogger.eventLog
nodes = commandLoggerView.createNodes()
for node in nodes
continue unless node.name is 'Editor'
for child in node.children

View File

@@ -34,6 +34,7 @@ class CommandLoggerView extends ScrollView
super
@command 'core:cancel', => @detach()
@on 'blur', => @detach() unless document.activeElement is this[0]
toggle: (@eventLog={}) ->
if @hasParent()
@@ -143,10 +144,10 @@ class CommandLoggerView extends ScrollView
.append('div')
.style('width', "#{w}px")
.style('height', "#{h}px")
.append('svg:svg')
.append('svg')
.attr('width', w)
.attr('height', h)
.append('svg:g')
.append('g')
.attr('transform', 'translate(.5,.5)')
nodes = treemap.nodes(root).filter((d) -> not d.children)
@@ -154,17 +155,17 @@ class CommandLoggerView extends ScrollView
cell = svg.selectAll('g')
.data(nodes)
.enter()
.append('svg:g')
.append('g')
.attr('class', 'node')
.attr('transform', (d) -> "translate(#{d.x},#{d.y})")
.on('click', (d) -> if node is d.parent then zoom(root) else zoom(d.parent))
cell.append('svg:rect')
cell.append('rect')
.attr('width', (d) -> d.dx - 1)
.attr('height', (d) -> d.dy - 1)
.style('fill', (d) -> color(d.parent.name))
cell.append('svg:foreignObject')
cell.append('foreignObject')
.attr('width', (d) -> d.dx - 1)
.attr('height', (d) -> d.dy - 1)
.attr('class', 'foreign-object')
@@ -180,8 +181,11 @@ class CommandLoggerView extends ScrollView
@focus()
detach: ->
super()
return if @detaching
@detaching = true
super
@rootView.focus()
@detaching = false
serialize: ->
eventLog: @eventLog

View File

@@ -438,13 +438,13 @@ describe "CommandPanel", ->
expect(previewList.getSelectedOperation()).toBe previewList.getOperations()[0]
describe "when core:confirm is triggered on the preview list", ->
it "opens the operation's buffer, selects and scrolls to the search result, and focuses the active editor", ->
it "opens the operation's buffer, selects and scrolls to the search result, and refocuses the preview list", ->
rootView.height(200)
rootView.attachToDom()
waitsForPromise -> commandPanel.execute('X x/apply/') # use apply because it is at the end of the file
runs ->
spyOn(rootView, 'focus')
spyOn(previewList, 'focus')
executeHandler = jasmine.createSpy('executeHandler')
commandPanel.on 'core:confirm', executeHandler
@@ -458,13 +458,13 @@ describe "CommandPanel", ->
expect(editSession.getSelectedBufferRange()).toEqual operation.getBufferRange()
expect(editSession.getSelectedBufferRange()).toEqual operation.getBufferRange()
expect(editor.isScreenRowVisible(editor.getCursorScreenRow())).toBeTruthy()
expect(rootView.focus).toHaveBeenCalled()
expect(previewList.focus).toHaveBeenCalled()
expect(executeHandler).not.toHaveBeenCalled()
describe "when an operation in the preview list is clicked", ->
it "opens the operation's buffer, selects the search result, and focuses the active editor", ->
spyOn(rootView, 'focus')
it "opens the operation's buffer, selects the search result, and refocuses the preview list", ->
spyOn(previewList, 'focus')
operation = previewList.getOperations()[4]
previewList.find('li.operation:eq(4) span').mousedown()
@@ -473,4 +473,4 @@ describe "CommandPanel", ->
editSession = rootView.getActiveEditSession()
expect(editSession.buffer.getPath()).toBe project.resolve(operation.getPath())
expect(editSession.getSelectedBufferRange()).toEqual operation.getBufferRange()
expect(rootView.focus).toHaveBeenCalled()
expect(previewList.focus).toHaveBeenCalled()

View File

@@ -83,7 +83,7 @@ class PreviewList extends ScrollView
editSession = @rootView.open(operation.getPath())
bufferRange = operation.execute(editSession)
editSession.setSelectedBufferRange(bufferRange, autoscroll: true) if bufferRange
@rootView.focus()
@focus()
false
getPathCount: ->

View File

@@ -0,0 +1,16 @@
DeferredAtomPackage = require 'deferred-atom-package'
Stats = require './src/stats'
module.exports =
class EditorStats extends DeferredAtomPackage
loadEvents: ['editor-stats:toggle']
instanceClass: 'editor-stats/src/editor-stats-view'
stats: new Stats
activate: (rootView) ->
super
rootView.on 'keydown', => @stats.track()
rootView.on 'mouseup', => @stats.track()
onLoadEvent: (event, instance) -> instance.toggle(@stats)

View File

@@ -0,0 +1,2 @@
'body':
'meta-alt-s': 'editor-stats:toggle'

View File

@@ -0,0 +1,46 @@
$ = require 'jquery'
RootView = require 'root-view'
EditorStats = require 'editor-stats/src/editor-stats-view'
describe "EditorStats", ->
[rootView, editorStats, time] = []
simulateKeyUp = (key) ->
e = $.Event "keydown", keyCode: key.charCodeAt(0)
rootView.trigger(e)
simulateClick = ->
e = $.Event "mouseup"
rootView.trigger(e)
beforeEach ->
rootView = new RootView(require.resolve('fixtures/sample.js'))
date = new Date()
mins = date.getMinutes()
hours = date.getHours()
mins = if mins == 60 then '01' else mins + 1
time = "#{hours}:#{mins}"
editorStatsPackage = atom.loadPackage('editor-stats')
editorStatsPackage.getInstance()
editorStats = editorStatsPackage.stats
editorStats.clear()
afterEach ->
rootView.deactivate()
describe "when a keyup event is triggered", ->
it "records the number of times a keyup is triggered", ->
simulateKeyUp('a')
expect(editorStats.eventLog[time]).toBe 1
simulateKeyUp('b')
expect(editorStats.eventLog[time]).toBe 2
describe "when a mouseup event is triggered", ->
it "records the number of times a mouseup is triggered", ->
simulateClick()
expect(editorStats.eventLog[time]).toBe 1
simulateClick()
expect(editorStats.eventLog[time]).toBe 2

View File

@@ -0,0 +1,103 @@
ScrollView = require 'scroll-view'
d3 = require 'd3.v3'
_ = require 'underscore'
$ = require 'jquery'
module.exports =
class EditorStatsView extends ScrollView
@activate: (rootView, state) ->
@instance = new EditorStatsView(rootView)
@content: (rootView) ->
@div class: 'editor-stats-wrapper', tabindex: -1, =>
@div class: 'editor-stats', outlet: 'editorStats'
pt: 15
pl: 10
pb: 3
pr: 25
initialize: (@rootView) ->
super
resizer = =>
return unless @isOnDom()
@draw()
@update()
@subscribe $(window), 'resize', _.debounce(resizer, 300)
draw: ->
@editorStats.empty()
@x ?= d3.scale.ordinal().domain d3.range(@stats.hours * 60)
@y ?= d3.scale.linear()
w = @rootView.vertical.width()
h = @height()
data = d3.entries @stats.eventLog
max = d3.max data, (d) -> d.value
@x.rangeBands [0, w - @pl - @pr], 0.2
@y.domain([0, max]).range [h - @pt - @pb, 0]
@xaxis ?= d3.svg.axis().scale(@x).orient('top')
.tickSize(-h + @pt + @pb)
.tickFormat (d) =>
d = new Date(@stats.startDate.getTime() + (d * 6e4))
mins = d.getMinutes()
mins = "0#{mins}" if mins <= 9
"#{d.getHours()}:#{mins}"
vis = d3.select(@editorStats.get(0)).append('svg')
.attr('width', w)
.attr('height', h)
.append('g')
.attr('transform', "translate(#{@pl},#{@pt})")
vis.append('g')
.attr('class', 'x axis')
.call(@xaxis)
.selectAll('g')
.classed('minor', (d, i) -> i % 5 == 0 && i % 15 != 0)
.style 'display', (d, i) ->
if i % 15 == 0 || i % 5 == 0 || i == data.length - 1
'block'
else
'none'
@bars = vis.selectAll('rect.bar')
.data(data)
.enter().append('rect')
.attr('x', (d, i) => @x i)
.attr('height', (d, i) => h - @y(d.value) - @pt - @pb)
.attr('y', (d) => @y(d.value))
.attr('width', @x.rangeBand())
.attr('class', 'bar')
clearInterval(@updateInterval)
updater = => @update() if @isOnDom()
setTimeout(updater, 100)
@updateInterval = setInterval(updater, 5000)
update: ->
newData = d3.entries @stats.eventLog
max = d3.max newData, (d) -> d.value
@y.domain [0, max]
h = @height()
@bars.data(newData).transition()
.attr('height', (d, i) => h - @y(d.value) - @pt - @pb)
.attr('y', (d, i) => @y(d.value))
@bars.classed('max', (d, i) -> d.value == max)
toggle: (@stats) ->
if @hasParent()
@detach()
else
@attach()
attach: ->
@rootView.vertical.append(@)
@draw()
detach: ->
super()
clearInterval(@updateInterval)
@rootView.focus()

View File

@@ -0,0 +1,29 @@
module.exports =
class Stats
startDate: new Date
hours: 6
eventLog: []
constructor: ->
date = new Date(@startDate)
future = new Date(date.getTime() + (36e5 * @hours))
@eventLog[@time(date)] = 0
while date < future
@eventLog[@time(date)] = 0
clear: ->
@eventLog = []
track: ->
date = new Date
times = @time date
@eventLog[times] ?= 0
@eventLog[times] += 1
@eventLog.shift() if @eventLog.length > (@hours * 60)
time: (date) ->
date.setTime(date.getTime() + 6e4)
hour = date.getHours()
minute = date.getMinutes()
"#{hour}:#{minute}"

View File

@@ -0,0 +1,45 @@
.editor-stats-wrapper {
padding: 5px;
box-sizing: border-box;
border-top: 1px solid rgba(255, 255, 255, 0.05);
z-index: 9999;
}
.editor-stats {
height: 50px;
width: 100%;
background: #1d1f21;
border: 1px solid rgba(0, 0, 0, 0.3);
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
border-right: 1px solid rgba(255, 255, 255, 0.1);
}
.editor-stats rect.bar {
fill: rgba(255, 255, 255, 0.2);
shape-rendering: crispedges;
}
.editor-stats rect.bar.max {
fill: rgba(0, 163, 255, 1);
}
.editor-stats text {
font-size: 10px;
fill: rgba(255, 255, 255, 0.2);
font-family: Courier;
}
.editor-stats .minor text {
display: none;
}
.editor-stats line {
stroke: #ccc;
stroke-opacity: 0.05;
stroke-width: 1px;
shape-rendering: crispedges;
}
.editor-stats path.domain {
fill: none;
}

View File

@@ -1,8 +1,8 @@
DeferredAtomPackage = require 'deferred-atom-package'
LoadPathsTask = require './src/load-paths-task'
module.exports =
class FuzzyFinder extends DeferredAtomPackage
loadEvents: [
'fuzzy-finder:toggle-file-finder'
'fuzzy-finder:toggle-buffer-finder'
@@ -11,7 +11,18 @@ class FuzzyFinder extends DeferredAtomPackage
instanceClass: 'fuzzy-finder/src/fuzzy-finder-view'
activate: (rootView) ->
super
if rootView.project.getPath()?
callback = (paths) => @projectPaths = paths
new LoadPathsTask(rootView, callback).start()
onLoadEvent: (event, instance) ->
if @projectPaths? and not @instance.projectPaths?
@instance.projectPaths = @projectPaths
@instance.reloadProjectPaths = false
switch event.type
when 'fuzzy-finder:toggle-file-finder'
instance.toggleFileFinder()

View File

@@ -1,5 +1,6 @@
RootView = require 'root-view'
FuzzyFinder = require 'fuzzy-finder/src/fuzzy-finder-view'
LoadPathsTask = require 'fuzzy-finder/src/load-paths-task'
$ = require 'jquery'
{$$} = require 'space-pen'
fs = require 'fs'
@@ -48,14 +49,13 @@ describe 'FuzzyFinder', ->
expect(finder.find(".loading")).toBeVisible()
expect(finder.find(".loading")).toHaveText "Indexing..."
waitsForPromise ->
rootView.project.getFilePaths().done (foundPaths) -> paths = foundPaths
waitsFor ->
finder.list.children('li').length > 0
waitsFor "all project paths to load", 5000, ->
if finder.projectPaths?.length > 0
paths = finder.projectPaths
true
runs ->
expect(finder.list.children('li').length).toBe paths.length, finder.maxResults
expect(finder.list.children('li').length).toBe paths.length
for path in paths
expect(finder.list.find("li:contains(#{fs.base(path)})")).toExist()
expect(finder.list.children().first()).toHaveClass 'selected'
@@ -222,15 +222,15 @@ describe 'FuzzyFinder', ->
describe "cached file paths", ->
it "caches file paths after first time", ->
spyOn(rootView.project, "getFilePaths").andCallThrough()
spyOn(LoadPathsTask.prototype, "start").andCallThrough()
rootView.trigger 'fuzzy-finder:toggle-file-finder'
waitsFor ->
finder.list.children('li').length > 0
runs ->
expect(rootView.project.getFilePaths).toHaveBeenCalled()
rootView.project.getFilePaths.reset()
expect(finder.loadPathsTask.start).toHaveBeenCalled()
finder.loadPathsTask.start.reset()
rootView.trigger 'fuzzy-finder:toggle-file-finder'
rootView.trigger 'fuzzy-finder:toggle-file-finder'
@@ -238,45 +238,44 @@ describe 'FuzzyFinder', ->
finder.list.children('li').length > 0
runs ->
expect(rootView.project.getFilePaths).not.toHaveBeenCalled()
expect(finder.loadPathsTask.start).not.toHaveBeenCalled()
it "doesn't cache buffer paths", ->
spyOn(rootView.project, "getFilePaths").andCallThrough()
spyOn(rootView, "getOpenBufferPaths").andCallThrough()
rootView.trigger 'fuzzy-finder:toggle-buffer-finder'
waitsFor ->
finder.list.children('li').length > 0
runs ->
expect(rootView.project.getFilePaths).not.toHaveBeenCalled()
rootView.project.getFilePaths.reset()
expect(rootView.getOpenBufferPaths).toHaveBeenCalled()
rootView.getOpenBufferPaths.reset()
rootView.trigger 'fuzzy-finder:toggle-buffer-finder'
rootView.trigger 'fuzzy-finder:toggle-buffer-finder'
rootView.trigger 'fuzzy-finder:toggle-file-finder'
waitsFor ->
finder.list.children('li').length > 0
runs ->
expect(rootView.project.getFilePaths).toHaveBeenCalled()
expect(rootView.getOpenBufferPaths).toHaveBeenCalled()
it "busts the cache when the window gains focus", ->
spyOn(rootView.project, "getFilePaths").andCallThrough()
spyOn(LoadPathsTask.prototype, "start").andCallThrough()
rootView.trigger 'fuzzy-finder:toggle-file-finder'
waitsFor ->
finder.list.children('li').length > 0
runs ->
expect(rootView.project.getFilePaths).toHaveBeenCalled()
rootView.project.getFilePaths.reset()
expect(finder.loadPathsTask.start).toHaveBeenCalled()
finder.loadPathsTask.start.reset()
$(window).trigger 'focus'
rootView.trigger 'fuzzy-finder:toggle-file-finder'
rootView.trigger 'fuzzy-finder:toggle-file-finder'
expect(rootView.project.getFilePaths).toHaveBeenCalled()
expect(finder.loadPathsTask.start).toHaveBeenCalled()
describe "path ignoring", ->
it "ignores paths that match entries in config.fuzzyFinder.ignoredNames", ->
spyOn(rootView.project, "getFilePaths").andCallThrough()
config.set("fuzzyFinder.ignoredNames", ["tree-view.js"])
rootView.trigger 'fuzzy-finder:toggle-file-finder'
finder.maxItems = Infinity
@@ -293,7 +292,6 @@ describe 'FuzzyFinder', ->
beforeEach ->
editor = rootView.getActiveEditor()
rootView.attachToDom()
spyOn(rootView.project, "getFilePaths").andCallThrough()
it "opens the fuzzy finder window when there are multiple matches", ->
editor.setText("sample")

View File

@@ -3,6 +3,7 @@ SelectList = require 'select-list'
_ = require 'underscore'
$ = require 'jquery'
fs = require 'fs'
LoadPathsTask = require 'fuzzy-finder/src/load-paths-task'
module.exports =
class FuzzyFinderView extends SelectList
@@ -126,16 +127,9 @@ class FuzzyFinderView extends SelectList
@setLoading("Indexing...")
if @reloadProjectPaths
@rootView.project.getFilePaths().done (paths) =>
ignoredNames = config.get("fuzzyFinder.ignoredNames") or []
ignoredNames = ignoredNames.concat(config.get("core.ignoredNames") or [])
@loadPathsTask?.terminate()
callback = (paths) =>
@projectPaths = paths
if ignoredNames
@projectPaths = @projectPaths.filter (path) ->
for segment in path.split("/")
return false if _.contains(ignoredNames, segment)
return true
@reloadProjectPaths = false
listedItems =
if options.filter?
@@ -146,6 +140,8 @@ class FuzzyFinderView extends SelectList
@setArray(listedItems)
options.done(listedItems) if options.done?
@loadPathsTask = new LoadPathsTask(@rootView, callback)
@loadPathsTask.start()
populateOpenBufferPaths: ->
@paths = @rootView.getOpenBufferPaths().map (path) =>

View File

@@ -0,0 +1,20 @@
fs = require 'fs'
_ = require 'underscore'
Git = require 'git'
module.exports =
loadPaths: (rootPath, ignoredNames, ignoreGitIgnoredFiles) ->
paths = []
repo = Git.open(rootPath, refreshIndexOnFocus: false) if ignoreGitIgnoredFiles
isIgnored = (path) ->
for segment in path.split('/')
return true if _.contains(ignoredNames, segment)
return true if repo?.isPathIgnored(fs.join(rootPath, path))
false
onFile = (path) ->
paths.push(path) unless isIgnored(path)
onDirectory = (path) ->
not isIgnored(path)
fs.traverseTree(rootPath, onFile, onDirectory)
repo?.destroy()
callTaskMethod('pathsLoaded', paths)

View File

@@ -0,0 +1,17 @@
Task = require 'task'
module.exports =
class LoadPathsTask extends Task
constructor: (@rootView, @callback)->
super('fuzzy-finder/src/load-paths-handler')
started: ->
ignoredNames = config.get("fuzzyFinder.ignoredNames") ? []
ignoredNames = ignoredNames.concat(config.get("core.ignoredNames") ? [])
ignoreGitIgnoredFiles = config.get("core.hideGitIgnoredFiles")
rootPath = @rootView.project.getPath()
@callWorkerMethod('loadPaths', rootPath, ignoredNames, ignoreGitIgnoredFiles)
pathsLoaded: (paths) ->
@terminate()
@callback(paths)

View File

@@ -277,6 +277,7 @@ describe "Snippets extension", ->
it "terminates the worker when loading completes", ->
jasmine.unspy(LoadSnippetsTask.prototype, 'loadAtomSnippets')
spyOn(console, "warn")
spyOn(Worker.prototype, 'terminate').andCallThrough()
snippets.loaded = false
snippets.loadAll()
@@ -284,6 +285,8 @@ describe "Snippets extension", ->
waitsFor "all snippets to load", 5000, -> snippets.loaded
runs ->
expect(console.warn).toHaveBeenCalled()
expect(console.warn.argsForCall[0]).toMatch /Error reading snippets file '.*?\/spec\/fixtures\/packages\/package-with-snippets\/snippets\/junk-file'/
expect(Worker.prototype.terminate).toHaveBeenCalled()
expect(Worker.prototype.terminate.calls.length).toBe 1

View File

@@ -1,4 +1,4 @@
Task = require 'Task'
Task = require 'task'
TextMatePackage = require 'text-mate-package'
module.exports =

View File

@@ -770,6 +770,9 @@ describe "TreeView", ->
treeView.trigger "tree-view:move"
moveDialog = rootView.find(".tree-view-dialog").view()
afterEach ->
waits 50 # The move specs cause too many false positives because of their async nature, so wait a little bit before we cleanup
it "opens a move dialog with the file's current path (excluding extension) populated", ->
extension = fs.extension(filePath)
fileNameWithoutExtension = fs.base(filePath, extension)

79
src/stdlib/cson.coffee Normal file
View File

@@ -0,0 +1,79 @@
_ = require 'underscore'
module.exports =
stringifyIndent: (level=0) -> _.multiplyString(' ', Math.max(level, 0))
stringifyString: (string) ->
string = JSON.stringify(string)
string = string[1...-1] # Remove surrounding double quotes
string = string.replace(/\\"/g, '"') # Unescape escaped double quotes
string = string.replace(/'/g, '\\\'') # Escape single quotes
"'#{string}'" # Wrap in single quotes
stringifyBoolean: (boolean) -> "#{boolean}"
stringifyNumber: (number) -> "#{number}"
stringifyNull: -> 'null'
stringifyArray: (array, indentLevel=0) ->
return '[]' if array.length is 0
cson = '[\n'
for value in array
cson += @stringifyIndent(indentLevel + 2)
if _.isString(value)
cson += @stringifyString(value)
else if _.isBoolean(value)
cson += @stringifyBoolean(value)
else if _.isNumber(value)
cson += @stringifyNumber(value)
else if _.isNull(value)
cson += @stringifyNull(value)
else if _.isArray(value)
cson += @stringifyArray(value, indentLevel + 2)
else if _.isObject(value)
cson += @stringifyObject(value, indentLevel + 2)
else
throw new Error("Unrecognized type for array value: #{value}")
cson += '\n'
"#{cson}#{@stringifyIndent(indentLevel)}]"
stringifyObject: (object, indentLevel=0) ->
cson = ''
prefix = ''
for key, value of object
continue if value is undefined
if _.isFunction(value)
throw new Error("Function specified as value to key: #{key}")
cson += "#{prefix}#{@stringifyIndent(indentLevel)}'#{key}':"
if _.isString(value)
cson += " #{@stringifyString(value)}"
else if _.isBoolean(value)
cson += " #{@stringifyBoolean(value)}"
else if _.isNumber(value)
cson += " #{@stringifyNumber(value)}"
else if _.isNull(value)
cson += " #{@stringifyNull(value)}"
else if _.isArray(value)
cson += " #{@stringifyArray(value, indentLevel)}"
else if _.isObject(value)
cson += "\n#{@stringifyObject(value, indentLevel + 2)}"
else
throw new Error("Unrecognized value type for key: #{key} with value: #{value}")
prefix = '\n'
cson
stringify: (object) ->
throw new Error("Cannot stringify undefined object") if object is undefined
throw new Error("Cannot stringify function: #{object}") if _.isFunction(object)
return @stringifyString(object) if _.isString(object)
return @stringifyBoolean(object) if _.isBoolean(object)
return @stringifyNumber(object) if _.isNumber(object)
return @stringifyNull(object) if _.isNull(object)
return @stringifyArray(object) if _.isArray(object)
return @stringifyObject(object) if _.isObject(object)
throw new Error("Unrecognized type to stringify: #{object}")

View File

@@ -59,11 +59,16 @@ module.exports =
# Returns an array with all the names of files contained
# in the directory path.
list: (rootPath) ->
list: (rootPath, extensions) ->
paths = []
onPath = (path) =>
paths.push(@join(rootPath, path))
false
if extensions
onPath = (path) =>
paths.push(@join(rootPath, path)) if _.contains(extensions, @extension(path))
false
else
onPath = (path) =>
paths.push(@join(rootPath, path))
false
@traverseTree(rootPath, onPath, onPath)
paths

View File

@@ -25,6 +25,9 @@ $.fn.pageUp = ->
$.fn.pageDown = ->
@scrollTop(@scrollTop() + @height())
$.fn.isOnDom = ->
@closest(document.body).length is 1
$.fn.containsElement = (element) ->
(element[0].compareDocumentPosition(this[0]) & 8) == 8

View File

@@ -56,7 +56,6 @@
overflow-x: hidden;
}
.editor .underlayer, .editor .lines, .editor .overlayer {
width: 100%;
height: 100%;
@@ -83,11 +82,11 @@
.editor .cursor {
position: absolute;
border-left: 2px solid;
border-left: 1px solid;
}
.editor:not(.focused) .cursor,
.editor.focused .cursor.blink-off {
.editor:not(.is-focused) .cursor,
.editor.is-focused .cursor.blink-off {
visibility: hidden;
}

View File

@@ -1,170 +1,80 @@
.jasmine_reporter {
font-family: "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif;
font-size: 16px;
}
body { background-color: #eeeeee; padding: 0; overflow-y: scroll; }
body {
background: #eee;
}
#HTMLReporter { font-size: 11px; font-family: Monaco, "Lucida Console", monospace; line-height: 14px; color: #333333; }
#HTMLReporter a { text-decoration: none; }
#HTMLReporter a:hover { text-decoration: underline; }
#HTMLReporter p, #HTMLReporter h1, #HTMLReporter h2, #HTMLReporter h3, #HTMLReporter h4, #HTMLReporter h5, #HTMLReporter h6 { margin: 0; line-height: 14px; }
#HTMLReporter .banner, #HTMLReporter .symbolSummary, #HTMLReporter .summary, #HTMLReporter .resultMessage, #HTMLReporter .specDetail .description, #HTMLReporter .alert .bar, #HTMLReporter .stackTrace { padding-left: 9px; padding-right: 9px; }
#HTMLReporter #jasmine_content { position: fixed; right: 100%; }
#HTMLReporter .version { color: #aaaaaa; }
#HTMLReporter .banner { margin-top: 14px; }
#HTMLReporter .duration { color: #aaaaaa; float: right; }
#HTMLReporter .symbolSummary { overflow: hidden; *zoom: 1; margin: 14px 0; }
#HTMLReporter .symbolSummary li { display: block; float: left; height: 7px; width: 14px; margin-bottom: 7px; font-size: 16px; }
#HTMLReporter .symbolSummary li.passed { font-size: 14px; }
#HTMLReporter .symbolSummary li.passed:before { color: #5e7d00; content: "\02022"; }
#HTMLReporter .symbolSummary li.failed { line-height: 9px; }
#HTMLReporter .symbolSummary li.failed:before { color: #b03911; content: "x"; font-weight: bold; margin-left: -1px; }
#HTMLReporter .symbolSummary li.skipped { font-size: 14px; }
#HTMLReporter .symbolSummary li.skipped:before { color: #bababa; content: "\02022"; }
#HTMLReporter .symbolSummary li.pending { line-height: 11px; }
#HTMLReporter .symbolSummary li.pending:before { color: #aaaaaa; content: "-"; }
#HTMLReporter .exceptions { color: #fff; float: right; margin-top: 5px; margin-right: 5px; }
#HTMLReporter .bar { line-height: 28px; font-size: 14px; display: block; color: #eee; }
#HTMLReporter .runningAlert { background-color: #666666; }
#HTMLReporter .skippedAlert { background-color: #aaaaaa; }
#HTMLReporter .skippedAlert:first-child { background-color: #333333; }
#HTMLReporter .passingAlert { background-color: #a6b779; }
#HTMLReporter .passingAlert:first-child { background-color: #5e7d00; }
#HTMLReporter .failingAlert { background-color: #cf867e; }
#HTMLReporter .failingAlert:first-child { background-color: #b03911; }
#HTMLReporter .results { margin-top: 5px }
#HTMLReporter #details { display: none; }
#HTMLReporter .resultsMenu, #HTMLReporter .resultsMenu a { background-color: #fff; color: #333333; }
#HTMLReporter.showDetails .summaryMenuItem { font-weight: normal; text-decoration: inherit; }
#HTMLReporter.showDetails .detailsMenuItem { font-weight: bold; }
#HTMLReporter.showDetails .summary { display: none; }
#HTMLReporter.showDetails #details { display: block; }
#HTMLReporter .summaryMenuItem { font-weight: bold; }
#HTMLReporter .summary { margin-top: 14px; }
#HTMLReporter .summary .suite .suite, #HTMLReporter .summary .specSummary { margin-left: 14px; }
#HTMLReporter .summary .specSummary.passed a { color: #5e7d00; }
#HTMLReporter .summary .specSummary.failed a { color: #b03911; }
#HTMLReporter .description + .suite { margin-top: 0; }
#HTMLReporter .suite { margin-top: 14px; }
#HTMLReporter .suite a { color: #333333; }
#HTMLReporter #details .specDetail { margin-bottom: 28px; }
#HTMLReporter #details .specDetail .description { display: block; color: white; background-color: #b03911; font-size: 14px; padding: 3px 9px }
#HTMLReporter .resultMessage { padding-top: 5px; color: #333333; }
#HTMLReporter .resultMessage span.result { display: block; }
#HTMLReporter .stackTrace { margin: 5px 0 0 0; max-height: 500px; overflow: auto; line-height: 18px; color: #666666; border: 1px solid #ddd; background: white; white-space: pre; }
.jasmine_reporter a:visited, .jasmine_reporter a {
color: #303;
}
.jasmine_reporter a:hover, .jasmine_reporter a:active {
color: blue;
}
.run_spec {
float:right;
padding-right: 5px;
font-size: .8em;
text-decoration: none;
}
.jasmine_reporter {
margin: 0 5px;
}
.banner {
color: #303;
background-color: #fef;
padding: 5px;
}
.logo {
float: left;
font-size: 1.1em;
padding-left: 5px;
}
.logo .version {
font-size: .6em;
padding-left: 1em;
}
.runner.running {
background-color: yellow;
}
.options {
text-align: right;
font-size: .8em;
}
.suite {
border: 1px outset gray;
margin: 5px 0;
padding-left: 1em;
}
.suite .suite {
margin: 5px;
}
.suite.passed {
background-color: #dfd;
}
.suite.failed {
background-color: #fdd;
}
.spec {
margin: 5px;
padding-left: 1em;
clear: both;
}
.spec.failed, .spec.passed, .spec.skipped {
padding-bottom: 5px;
border: 1px solid gray;
}
.spec.failed {
background-color: #fbb;
border-color: red;
}
.spec.passed {
background-color: #bfb;
border-color: green;
}
.spec.skipped {
background-color: #bbb;
}
.messages {
border-left: 1px dashed gray;
padding-left: 1em;
padding-right: 1em;
}
.passed {
background-color: #cfc;
display: none;
}
.failed {
background-color: #fbb;
}
.skipped {
color: #777;
background-color: #eee;
display: none;
}
/*.resultMessage {*/
/*white-space: pre;*/
/*}*/
.resultMessage span.result {
display: block;
line-height: 2em;
color: black;
}
.resultMessage .mismatch {
color: black;
}
.stackTrace {
white-space: pre;
font-size: .8em;
margin-left: 10px;
max-height: 5em;
overflow: auto;
border: 1px inset red;
padding: 1em;
background: #eef;
}
.finished-at {
padding-left: 1em;
font-size: .6em;
}
.show-passed .passed,
.show-skipped .skipped {
display: block;
}
#jasmine_content {
position:fixed;
right: 100%;
}
.runner {
border: 1px solid gray;
display: block;
margin: 5px 0;
padding: 2px 0 2px 10px;
}
#TrivialReporter { padding: 8px 13px; position: absolute; top: 0; bottom: 0; left: 0; right: 0; overflow-y: scroll; background-color: white; font-family: "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif; /*.resultMessage {*/ /*white-space: pre;*/ /*}*/ }
#TrivialReporter a:visited, #TrivialReporter a { color: #303; }
#TrivialReporter a:hover, #TrivialReporter a:active { color: blue; }
#TrivialReporter .run_spec { float: right; padding-right: 5px; font-size: .8em; text-decoration: none; }
#TrivialReporter .banner { color: #303; background-color: #fef; padding: 5px; }
#TrivialReporter .logo { float: left; font-size: 1.1em; padding-left: 5px; }
#TrivialReporter .logo .version { font-size: .6em; padding-left: 1em; }
#TrivialReporter .runner.running { background-color: yellow; }
#TrivialReporter .options { text-align: right; font-size: .8em; }
#TrivialReporter .suite { border: 1px outset gray; margin: 5px 0; padding-left: 1em; }
#TrivialReporter .suite .suite { margin: 5px; }
#TrivialReporter .suite.passed { background-color: #dfd; }
#TrivialReporter .suite.failed { background-color: #fdd; }
#TrivialReporter .spec { margin: 5px; padding-left: 1em; clear: both; }
#TrivialReporter .spec.failed, #TrivialReporter .spec.passed, #TrivialReporter .spec.skipped { padding-bottom: 5px; border: 1px solid gray; }
#TrivialReporter .spec.failed { background-color: #fbb; border-color: red; }
#TrivialReporter .spec.passed { background-color: #bfb; border-color: green; }
#TrivialReporter .spec.skipped { background-color: #bbb; }
#TrivialReporter .messages { border-left: 1px dashed gray; padding-left: 1em; padding-right: 1em; }
#TrivialReporter .passed { background-color: #cfc; display: none; }
#TrivialReporter .failed { background-color: #fbb; }
#TrivialReporter .skipped { color: #777; background-color: #eee; display: none; }
#TrivialReporter .resultMessage span.result { display: block; line-height: 2em; color: black; }
#TrivialReporter .resultMessage .mismatch { color: black; }
#TrivialReporter .stackTrace { white-space: pre; font-size: .8em; margin-left: 10px; max-height: 5em; overflow: auto; border: 1px inset red; padding: 1em; background: #eef; }
#TrivialReporter .finished-at { padding-left: 1em; font-size: .6em; }
#TrivialReporter.show-passed .passed, #TrivialReporter.show-skipped .skipped { display: block; }
#TrivialReporter #jasmine_content { position: fixed; right: 100%; }
#TrivialReporter .runner { border: 1px solid gray; display: block; margin: 5px 0; padding: 2px 0 2px 10px; }

View File

@@ -1,3 +0,0 @@
.wrap-guide {
background: rgba(150, 150, 150, .30);
}

View File

@@ -1,3 +0,0 @@
.wrap-guide {
background: rgba(150, 150, 150, .30);
}

269
themes/atom-dark-syntax.css Normal file
View File

@@ -0,0 +1,269 @@
.editor, .editor .gutter {
background-color: #1d1f21;
color: #c5c8c6;
}
.editor.is-focused .cursor {
border-color: #FFFFFF;
}
.editor.is-focused .selection .region {
background-color: #333333;
}
.editor.is-focused .line-number.cursor-line-no-selection, .editor.is-focused .line.cursor-line {
background-color: rgba(255, 255, 255, 0.14);
}
.comment {
color: #7C7C7C;
}
.entity {
color: #FFD2A7;
}
.keyword {
color: #96CBFE;
}
.keyword.control {
color: #96CBFE;
}
.keyword.operator {
color: #EDEDED;
}
.entity.name.type {
text-decoration: underline;
color: #FFFFB6;
}
.support {
color: #FFFFB6;
}
.storage {
color: #CFCB90;
}
.storage.modifier {
color: #96CBFE;
}
.constant {
color: #99CC99;
}
.string {
color: #A8FF60;
}
.constant.numeric {
color: #FF73FD;
}
.punctuation {
}
.variable {
color: #C6C5FE;
}
.invalid.deprecated {
text-decoration: underline;
color: #FD5FF1;
}
.invalid.illegal {
color: #FD5FF1;
background-color: rgba(86, 45, 86, 0.75);
}
.text .source {
background-color: rgba(177, 179, 186, 0.03);
}
.entity.other.inherited-class {
color: #9B5C2E;
}
.source .string .source {
color: #EDEDED;
}
.source .string .source .punctuation.section.embedded {
color: #00A0A0;
}
.string .constant {
color: #00A0A0;
}
.string.regexp {
color: #E9C062;
}
.string.regexp .constant.character.escape, .string.regexp .source.ruby.embedded, .string.regexp .string.regexp.arbitrary-repitition {
color: #FF8000;
}
.string.regexp.group {
color: #C6A24F;
background-color: rgba(255, 255, 255, 0.06);
}
.string.regexp.character-class {
color: #B18A3D;
}
.string .variable {
color: #8A9A95;
}
.support.function {
color: #DAD085;
}
.support.constant {
color: #FFD2A7;
}
.meta.preprocessor.c {
color: #8996A8;
}
.meta.preprocessor.c .keyword {
color: #AFC4DB;
}
.meta.cast {
color: #676767;
}
.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 {
color: #494949;
}
.meta.tag, .meta.tag .entity {
color: #96CBFE;
}
.source .entity.name.tag, .source .entity.other.attribute-name, .meta.tag.inline, .meta.tag.inline .entity {
color: #96CBFE;
}
.entity.other.attribute-name {
color: #FFD7B1;
}
.entity.name.tag.namespace, .entity.other.attribute-name.namespace {
color: #E18964;
}
.meta.selector.css .entity.name.tag {
text-decoration: underline;
color: #96CBFE;
}
.meta.selector.css .entity.other.attribute-name.tag.pseudo-class {
color: #8F9D6A;
}
.meta.selector.css .entity.other.attribute-name.id {
color: #8B98AB;
}
.meta.selector.css .entity.other.attribute-name.class {
color: #62B1FE;
}
.support.type.property-name.css {
color: #EDEDED;
}
.meta.property-group .support.constant.property-value.css, .meta.property-value .support.constant.property-value.css {
color: #F9EE98;
}
.meta.preprocessor.at-rule .keyword.control.at-rule {
color: #8693A5;
}
.meta.property-value .support.constant.named-color.css, .meta.property-value .constant {
color: #87C38A;
}
.meta.constructor.argument.css {
color: #8F9D6A;
}
.meta.diff, .meta.diff.header {
color: #F8F8F8;
background-color: #0E2231;
}
.markup.deleted {
color: #F8F8F8;
background-color: #420E09;
}
.markup.changed {
color: #F8F8F8;
background-color: #4A410D;
}
.markup.inserted {
color: #F8F8F8;
background-color: #253B22;
}
.markup.italic {
color: #E9C062;
}
.markup.bold {
color: #E9C062;
}
.markup.underline {
text-decoration: underline;
color: #E18964;
}
.markup.quote {
color: #E1D4B9;
background-color: rgba(254, 224, 156, 0.07);
}
.markup.heading, .markup.heading .entity {
color: #FEDCC5;
background-color: #632D04;
}
.markup.list {
color: #E1D4B9;
}
.markup.raw {
color: #578BB3;
background-color: rgba(177, 179, 186, 0.03);
}
.markup .comment {
color: #F67B37;
}
.meta.separator {
color: #60A633;
background-color: #242424;
}
.meta.line.entry.logfile, .meta.line.exit.logfile {
background-color: rgba(238, 238, 238, 0.16);
}
.meta.line.error.logfile {
background-color: #751012;
}

View File

@@ -4,23 +4,16 @@ html, body,
background-color: #333333;
}
#root-view #panes:before {
display: block;
content: "\f208";
font-family: 'Octicons Regular';
color: #303030;
-webkit-font-smoothing: antialiased;
font-size: 100vmin;
line-height: 100vmin;
text-align: center;
}
#root-view #panes .row > * + * {
border-left: 5px solid #515151;
-webkit-box-shadow:
-2px 0 rgba(0, 0, 0, 0.3),
-1px 0 rgba(255, 255, 255, 0.2);
}
#root-view #panes .column > * + * {
border-top: 5px solid #515151;
-webkit-box-shadow:
0 -2px rgba(0, 0, 0, 0.3),
0 -1px rgba(255, 255, 255, 0.2);
}
.error {

View File

@@ -1,18 +1,21 @@
.command-panel {
background-color: #303030;
border: 1px solid #252525;
color: #ededed;
color: #dedede;
padding: 5px;
}
.command-panel .preview-list {
max-height: 300px;
overflow: auto;
margin-bottom: 3px;
margin: 0 1px 5px 10px;
position: relative;
background-color: #000000;
color: #ededed;
background-color: #1e1e1e;
color: #C5C8C6;
cursor: default;
border: 1px solid rgba(0, 0, 0, 0.5);
border-bottom: 1px solid rgba(180, 180, 180, 0.2);
border-right: 1px solid rgba(180, 180, 180, 0.2);
}
.command-panel .preview-count {
@@ -32,7 +35,7 @@
.command-panel .preview-list .path {
padding-left: 5px;
color: #00a693;
color: #fff;
}
.command-panel .preview-list .path:before {
@@ -73,6 +76,7 @@
background-color: rgba(255, 255, 255, .2);
-webkit-border-radius: 2px;
padding: 1px;
color: yellow;
}
.command-panel .prompt-and-editor {

View File

@@ -1,5 +1,6 @@
.editor {
font-family: Inconsolata, Monaco, Courier;
line-height: 1.3;
}
.editor.mini {
@@ -17,7 +18,7 @@
}
.editor .gutter .line-number {
padding-right: 1.3em;
padding-right: .5em;
min-width: 35px;
box-sizing: border-box;
text-align: right;
@@ -52,16 +53,28 @@
opacity: 1;
}
.editor .fold-marker:before {
content: '\f060';
-webkit-transform: rotate(90deg);
.editor .gutter .line-number:after {
font-size: 0.8em;
content: '\f078';
font-family: 'Octicons Regular';
display: inline-block;
margin-left: .3em;
margin-top: .1em;
line-height: .8em;
-webkit-font-smoothing: antialiased;
color: #fba0e3;
visibility: hidden;
}
.editor .gutter .line-number.fold:after {
visibility: visible;
}
.editor .fold-marker:after {
content: '\2026';
opacity: .8;
color: #fba0e3;
padding-left: .2em;
}
.editor .line.cursor-line .fold-marker {
opacity: 1;
}
.editor .invisible {

View File

@@ -2,10 +2,11 @@
background: #333333;
border-bottom: 4px solid #424242;
font: caption;
box-shadow: inset 0 -1px 0 #2e2e2e;
box-shadow: inset 0 -1px 0 #2e2e2e, 0 1px 0 #191919;
margin-bottom: 1px;
}
.tab {
.is-focused .tab {
cursor: default;
padding: 2px 21px 2px 9px;
background-image: -webkit-linear-gradient(#444, #3d3d3d);
@@ -15,6 +16,42 @@
box-shadow: inset 0 0 5px #383838, 0 1px 0 #585858, inset -1px 0 0 #4a4a4a, inset 1px 0 0 #4a4a4a;
}
.is-focused .tab:first-child {
box-shadow: inset 0 0 5px #383838, 0 1px 0 #585858, inset -1px 0 0 #4a4a4a;
}
.is-focused .tab.active,
.is-focused .tab.active:hover {
border-top: 1px solid #4a4a4a;
box-shadow: inset -1px 0 0 #595959, inset 1px 0 0 #595959;
border-bottom-color: #424242;
background-image: -webkit-linear-gradient(#555555, #424242);
}
.tab {
cursor: default;
padding: 2px 21px 2px 9px;
background-color: #555;
background-image: none;
border-top: 1px solid #383838;
border-right: 1px solid #2e2e2e;
border-bottom: 1px solid #2e2e2e;
box-shadow: inset 0 0 5px #555, 0 1px 0 #585858, inset -1px 0 0 #4a4a4a, inset 1px 0 0 #4a4a4a;
}
.tab:first-child {
box-shadow: inset 0 0 5px #555, 0 1px 0 #585858, inset -1px 0 0 #4a4a4a;
}
.tab.active,
.tab.active:hover {
border-top: 1px solid #4a4a4a;
box-shadow: inset -1px 0 0 #595959, inset 1px 0 0 #595959;
border-bottom-color: #424242;
background-image: none;
background-color: #424242;
}
.tab,
.tab .close-icon {
color: #aaa;
@@ -24,9 +61,9 @@
border-color: #aaa;
}
.tab.active,
.tab.active:hover,
.tab.active .close-icon {
.is-focused .tab.active,
.is-focused .tab.active:hover,
.is-focused .tab.active .close-icon {
color: #e6e6e6;
}
@@ -48,23 +85,11 @@
content: "";
}
.tab:first-child {
box-shadow: inset 0 0 5px #383838, 0 1px 0 #585858, inset -1px 0 0 #4a4a4a;
}
.tab.active:first-child,
.tab.active:first-child:hover {
.is-focused .tab.active:first-child,
.is-focused .tab.active:first-child:hover {
box-shadow: inset -1px 0 0 #595959;
}
.tab.active,
.tab.active:hover {
border-top: 1px solid #4a4a4a;
box-shadow: inset -1px 0 0 #595959, inset 1px 0 0 #595959;
border-bottom-color: #424242;
background-image: -webkit-linear-gradient(#555555, #424242);
}
.tab.active:before,
.tab.active:after {
position: absolute;
@@ -75,6 +100,19 @@
z-index: 3;
border: 1px solid #595959;
}
.is-focused .tab.active:before {
border-bottom-right-radius: 4px;
border-width: 0 1px 1px 0;
box-shadow: 2px 2px 0 #424242;
left: -4px;
}
.is-focused .tab.active:after {
right: -4px;
border-bottom-left-radius: 4px;
border-width: 0 0 1px 1px;
box-shadow: -2px 2px 0 #424242;
}
.tab.active:before {
border-bottom-right-radius: 4px;
border-width: 0 1px 1px 0;
@@ -87,7 +125,7 @@
border-width: 0 0 1px 1px;
box-shadow: -2px 2px 0 #424242;
}
.tab.active:first-child:before {
.is-focused .tab.active:first-child:before {
display: none;
}

View File

@@ -1,6 +1,11 @@
.tree-view {
.is-focused .tree-view {
background: #1e1e1e;
border-right: 2px solid #191919;
border-right: 1px solid #191919;
}
.tree-view {
background: #2e2e2e;
border-right: 1px solid #191919;
}
.tree-view .entry {
@@ -20,10 +25,15 @@
color: #d2d2d2;
}
.tree-view .selected > .highlight {
.is-focused .tree-view .selected > .highlight {
background-image: -webkit-linear-gradient(#4e4e4e, #434343);
}
.tree-view .selected > .highlight {
background-image: none;
background-color: #6e6e6e;
}
.tree-view:focus .selected > .highlight {
background-image: -webkit-linear-gradient(#7e7e7e, #737373);
}

View File

@@ -0,0 +1,3 @@
.wrap-guide {
background: rgba(150, 150, 150, 0.1);
}

View File

@@ -0,0 +1,168 @@
.editor, .editor .gutter {
background-color: #FFFFFF;
color: #555;
}
.editor.is-focused .cursor {
border-color: #000;
}
.editor.is-focused .selection .region {
background-color: #afc4da;
}
.editor.is-focused .line-number.cursor-line-no-selection, .editor.is-focused .line.cursor-line {
background-color: rgba(255, 255, 134, 0.34);
}
.editor .comment {
color: #999988;
font-style: italic;
}
.editor .string {
color: #D14;
}
.editor .constant.numeric {
color: #D14;
}
.editor .constant.language {
color: #606aa1;
}
.editor .constant.character, .editor .constant.other {
color: #606aa1;
}
.editor .constant.symbol {
color: #990073;
}
.editor .variable {
color: #008080;
}
/* Keywords */
.editor .keyword {
color: #222;
font-weight: bold;
}
.editor .keyword.unit {
color: #445588;
}
.editor .keyword.special-method {
color: #0086B3;
}
.editor .storage {
color: #222;
}
.editor .storage.type {
color: #222;
}
.editor .entity.name.class {
text-decoration: underline;
color: #606aa1;
}
.editor .entity.other.inherited-class {
text-decoration: underline;
color: #606aa1;
}
.editor .entity.name.function {
color: #900;
}
.editor .variable.parameter {
color: #606aa1;
}
.editor .entity.name.tag {
color: #008080;
}
.editor .entity.other.attribute-name {
color: #458;
font-weight: bold;
}
.editor .support.function {
color: #458;
}
.editor .support.constant {
color: #458;
}
.editor .support.type {
color: #458;
}
.editor .support.class {
color: #008080;
}
.editor .invalid {
color: #F8F8F0;
background-color: #00A8C6;
}
.editor .invalid.deprecated {
color: #F8F8F0;
background-color: #8FBE00;
}
.editor .meta.structure.dictionary.json > .string.quoted.double.json,
.editor .meta.structure.dictionary.json > .string.quoted.double.json .punctuation.string {
color: #000080;
}
.editor .meta.structure.dictionary.value.json > .string.quoted.double.json {
color: #d14;
}
.editor .meta.diff, .editor .meta.diff.header {
color: #75715E;
}
.editor .meta.function span {
color: #990000;
font-weight: bold;
}
.editor .markup.deleted {
color: #00A8C6;
}
.editor .markup.inserted {
color: #A6E22E;
}
.editor .markup.changed {
color: #E6DB74;
}
.editor .constant.numeric.line-number.find-in-files .- .match {
color: rgba(143, 190, 0, 0.63);
}
.editor .entity.name.filename.find-in-files {
color: #E6DB74;
}
/* CSS Styles */
.editor .css.support.property-name {
font-weight: bold;
color: #333;
}
.editor .css.constant {
color: #099;
}

View File

@@ -5,11 +5,15 @@ html, body,
}
#root-view #panes .row > * + * {
border-left: 1px solid #989898;
-webkit-box-shadow:
-2px 0 rgba(0, 0, 0, 0.3),
-1px 0 rgba(255, 255, 255, 0.2);
}
#root-view #panes .column > * + * {
border-top: 1px solid #989898;
-webkit-box-shadow:
0 -2px rgba(0, 0, 0, 0.3),
0 -1px rgba(255, 255, 255, 0.2);
}
.error {

View File

@@ -1,5 +1,6 @@
.editor {
font-family: Inconsolata, Monaco, Courier;
line-height: 1.3;
}
.editor.mini {
@@ -20,7 +21,7 @@
}
.editor .gutter .line-number {
padding-right: 1.3em;
padding-right: .5em;
min-width: 35px;
box-sizing: border-box;
text-align: right;
@@ -55,16 +56,28 @@
opacity: 1;
}
.editor .fold-marker:before {
content: '\f060';
-webkit-transform: rotate(90deg);
.editor .gutter .line-number:after {
font-size: 0.8em;
content: '\f078';
font-family: 'Octicons Regular';
display: inline-block;
margin-left: .3em;
margin-top: .1em;
line-height: .8em;
-webkit-font-smoothing: antialiased;
color: #fba0e3;
visibility: hidden;
}
.editor .gutter .line-number.fold:after {
visibility: visible;
}
.editor .fold-marker:after {
content: '\2026';
opacity: .8;
color: #fba0e3;
padding-left: .2em;
}
.editor .line.cursor-line .fold-marker {
opacity: 1;
}
.editor .invisible {

View File

@@ -2,13 +2,26 @@
background: #e3e3e3;
border-bottom: 4px solid #e5e5e5;
font: caption;
box-shadow: inset 0 -1px 0 #959595;
box-shadow: inset 0 -1px 0 #959595, 0 1px 0 #989898;
margin-bottom: 1px;
}
.is-focused .tab {
cursor: default;
padding: 2px 21px 2px 9px;
background-image: -webkit-linear-gradient(#e0e0e0, #bfbfbf);
border-top: none;
border-right: 1px solid #959595;
border-bottom: 1px solid #959595;
box-shadow: inset 0 0 5px #eee, 0 1px 0 #eee, inset -1px 0 0 #e0e0e0, inset 1px 0 0 #e0e0e0;
color: #323232;
}
.tab {
cursor: default;
padding: 2px 21px 2px 9px;
background-image: -webkit-linear-gradient(#e0e0e0, #bfbfbf);
background-image: none;
background-color: #e0e0e0);
border-top: none;
border-right: 1px solid #959595;
border-bottom: 1px solid #959595;

View File

@@ -1,8 +1,13 @@
.tree-view {
.is-focused .tree-view {
background: #dde3e8;
border-right: 1px solid #989898;
}
.tree-view {
background: #f3f3f3;
border-right: 1px solid #c5c5c5;
}
.tree-view .entry {
text-shadow: 0 1px 0 #fff;
}
@@ -20,7 +25,7 @@
color: #262626;
}
.tree-view .selected > .highlight {
.is-focused .tree-view .selected > .highlight {
box-sizing: border-box;
border-top: 1px solid #97a4a7;
border-bottom: 1px solid #97a4a7;
@@ -28,12 +33,27 @@
background-image: -webkit-linear-gradient(#cad5d8, #bcccce);
}
.tree-view:focus .selected > .highlight {
.tree-view .selected > .highlight {
box-sizing: border-box;
border-top: 1px solid #97a4a7;
border-bottom: 1px solid #97a4a7;
background-image: none;
background-color: #DFDFDF;
}
.is-focused .tree-view:focus .selected > .highlight {
border-top: 1px solid #3D4552;
border-bottom: 1px solid #3D4552;
background-image: -webkit-linear-gradient(#7e868d, #69717b);
}
.tree-view:focus .selected > .highlight {
border-top: 1px solid #3D4552;
border-bottom: 1px solid #3D4552;
background-image: none;
background-color: #69717b;
}
.tree-view:focus .directory.selected > .header > .name,
.tree-view:focus .selected > .name,
.tree-view:focus .directory.selected > .header > .name:before,
@@ -50,10 +70,14 @@
color: #262626;
}
.tree-view .name:before {
.is-focused .tree-view .name:before {
color: #7e8692;
}
.tree-view .name:before {
color: #7e7e7e;
}
.tree-view .entry:hover,
.tree-view .directory .header:hover .name,
.tree-view .directory .header:hover .disclosure-arrow {

View File

@@ -0,0 +1,3 @@
.wrap-guide {
background: rgba(150, 150, 150, 0.3);
}

View File

@@ -1,10 +1,6 @@
jasmine.AtomReporter = function(doc) {
this.document = doc || document;
this.suiteDivs = {};
this.logRunningSpecs = false;
};
jasmine.AtomReporterHelpers = {};
jasmine.AtomReporter.prototype.createDom = function(type, attrs, childrenVarArgs) {
jasmine.AtomReporterHelpers.createDom = function(type, attrs, childrenVarArgs) {
var el = document.createElement(type);
for (var i = 2; i < arguments.length; i++) {
@@ -13,7 +9,9 @@ jasmine.AtomReporter.prototype.createDom = function(type, attrs, childrenVarArgs
if (typeof child === 'string') {
el.appendChild(document.createTextNode(child));
} else {
if (child) { el.appendChild(child); }
if (child) {
el.appendChild(child);
}
}
}
@@ -28,117 +26,344 @@ jasmine.AtomReporter.prototype.createDom = function(type, attrs, childrenVarArgs
return el;
};
jasmine.AtomReporter.prototype.reportRunnerStarting = function(runner) {
var showPassed, showSkipped;
this.outerDiv = this.createDom('div', { className: 'jasmine_reporter' },
this.createDom('div', { className: 'banner' },
this.createDom('div', { className: 'logo' },
this.createDom('span', { className: 'title' }, "Jasmine"),
this.createDom('span', { className: 'version' }, runner.env.versionString())),
this.createDom('div', { className: 'options' },
"Show ",
showPassed = this.createDom('input', { id: "__jasmine_AtomReporter_showPassed__", type: 'checkbox' }),
this.createDom('label', { "for": "__jasmine_AtomReporter_showPassed__" }, " passed "),
showSkipped = this.createDom('input', { id: "__jasmine_AtomReporter_showSkipped__", type: 'checkbox' }),
this.createDom('label', { "for": "__jasmine_AtomReporter_showSkipped__" }, " skipped")
)
),
this.runnerDiv = this.createDom('div', { className: 'runner running' },
this.createDom('a', { className: 'run_spec', href: '?' }, "run all"),
this.runnerMessageSpan = this.createDom('span', {}, "Running..."),
this.finishedAtSpan = this.createDom('span', { className: 'finished-at' }, ""))
);
this.document.body.appendChild(this.outerDiv);
var suites = runner.suites();
for (var i = 0; i < suites.length; i++) {
var suite = suites[i];
var suiteDiv = this.createDom('div', { className: 'suite' },
this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, "run"),
this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, suite.description));
this.suiteDivs[suite.id] = suiteDiv;
var parentDiv = this.outerDiv;
if (suite.parentSuite) {
parentDiv = this.suiteDivs[suite.parentSuite.id];
}
parentDiv.appendChild(suiteDiv);
}
this.startedAt = new Date();
var self = this;
showPassed.onclick = function(evt) {
if (showPassed.checked) {
self.outerDiv.className += ' show-passed';
} else {
self.outerDiv.className = self.outerDiv.className.replace(/ show-passed/, '');
}
};
showSkipped.onclick = function(evt) {
if (showSkipped.checked) {
self.outerDiv.className += ' show-skipped';
} else {
self.outerDiv.className = self.outerDiv.className.replace(/ show-skipped/, '');
}
};
};
jasmine.AtomReporter.prototype.reportRunnerResults = function(runner) {
var results = runner.results();
var className = (results.failedCount > 0) ? "runner failed" : "runner passed";
this.runnerDiv.setAttribute("class", className);
//do it twice for IE
this.runnerDiv.setAttribute("className", className);
var specs = runner.specs();
var specCount = 0;
for (var i = 0; i < specs.length; i++) {
if (this.specFilter(specs[i])) {
specCount++;
}
}
var message = "" + specCount + " spec" + (specCount == 1 ? "" : "s" ) + ", " + results.failedCount + " failure" + ((results.failedCount == 1) ? "" : "s");
message += " in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s";
this.runnerMessageSpan.replaceChild(this.createDom('a', { className: 'description', href: '?'}, message), this.runnerMessageSpan.firstChild);
this.finishedAtSpan.appendChild(document.createTextNode("Finished at " + new Date().toString()));
};
jasmine.AtomReporter.prototype.reportSuiteResults = function(suite) {
var results = suite.results();
var status = results.passed() ? 'passed' : 'failed';
if (results.totalCount === 0) { // todo: change this to check results.skipped
status = 'skipped';
}
this.suiteDivs[suite.id].className += " " + status;
};
jasmine.AtomReporter.prototype.reportSpecStarting = function(spec) {
if (this.logRunningSpecs) {
this.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...');
}
};
jasmine.AtomReporter.prototype.reportSpecResults = function(spec) {
var results = spec.results();
jasmine.AtomReporterHelpers.getSpecStatus = function(child) {
var results = child.results();
var status = results.passed() ? 'passed' : 'failed';
if (results.skipped) {
status = 'skipped';
}
var specDiv = this.createDom('div', { className: 'spec ' + status },
this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(spec.getFullName()) }, "run"),
return status;
};
jasmine.AtomReporterHelpers.appendToSummary = function(child, childElement) {
var parentDiv = this.dom.summary;
var parentSuite = (typeof child.parentSuite == 'undefined') ? 'suite' : 'parentSuite';
var parent = child[parentSuite];
if (parent) {
if (typeof this.views.suites[parent.id] == 'undefined') {
this.views.suites[parent.id] = new jasmine.AtomReporter.SuiteView(parent, this.dom, this.views);
}
parentDiv = this.views.suites[parent.id].element;
}
parentDiv.appendChild(childElement);
};
jasmine.AtomReporterHelpers.addHelpers = function(ctor) {
for(var fn in jasmine.AtomReporterHelpers) {
ctor.prototype[fn] = jasmine.AtomReporterHelpers[fn];
}
};
jasmine.AtomReporter = function(_doc) {
var self = this;
var doc = _doc || window.document;
var reporterView;
var dom = {};
// Jasmine Reporter Public Interface
self.logRunningSpecs = false;
self.reportRunnerStarting = function(runner) {
var specs = runner.specs() || [];
if (specs.length == 0) {
return;
}
createReporterDom();
doc.body.appendChild(dom.reporter);
reporterView = new jasmine.AtomReporter.ReporterView(dom);
reporterView.addSpecs(specs, self.specFilter);
};
self.reportRunnerResults = function(runner) {
reporterView && reporterView.complete();
};
self.reportSuiteResults = function(suite) {
reporterView.suiteComplete(suite);
};
self.reportSpecStarting = function(spec) {
if (self.logRunningSpecs) {
self.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...');
}
reporterView.specStarted(spec);
};
self.reportSpecResults = function(spec) {
reporterView.specComplete(spec);
};
self.log = function() {
var console = jasmine.getGlobal().console;
if (console && console.log) {
if (console.log.apply) {
console.log.apply(console, arguments);
} else {
console.log(arguments); // ie fix: console.log.apply doesn't exist on ie
}
}
};
self.specFilter = function(spec) {
return self.fSpecFilter(spec);
};
return self;
function createReporterDom() {
dom.reporter = self.createDom('div', { id: 'HTMLReporter', className: 'jasmine_reporter' },
dom.banner = self.createDom('div', { className: 'banner' },
self.createDom('span', { className: 'title' }, "Atom "),
self.createDom('span', { className: 'version' }, "0.0.0")),
dom.symbolSummary = self.createDom('ul', {className: 'symbolSummary'}),
dom.alert = self.createDom('div', {className: 'alert'}),
dom.results = self.createDom('div', {className: 'results'},
dom.summary = self.createDom('div', { className: 'summary' }),
dom.details = self.createDom('div', { id: 'details' }))
);
}
function searchWithCatch() {
var params = jasmine.AtomReporter.parameters(window.document);
var removed = false;
var i = 0;
while (!removed && i < params.length) {
if (params[i].match(/catch=/)) {
params.splice(i, 1);
removed = true;
}
i++;
}
if (jasmine.CATCH_EXCEPTIONS) {
params.push("catch=false");
}
return params.join("&");
}
};
jasmine.AtomReporter.parameters = function(doc) {
var paramStr = doc.location.search.substring(1);
var params = [];
if (paramStr.length > 0) {
params = paramStr.split('&');
}
return params;
}
jasmine.AtomReporter.sectionLink = function(sectionName) {
var link = '?';
var params = [];
if (sectionName) {
params.push('spec=' + encodeURIComponent(sectionName));
}
if (!jasmine.CATCH_EXCEPTIONS) {
params.push("catch=false");
}
if (params.length > 0) {
link += params.join("&");
}
return link;
};
jasmine.AtomReporterHelpers.addHelpers(jasmine.AtomReporter);
jasmine.AtomReporter.ReporterView = function(dom) {
this.startedAt = new Date();
this.runningSpecCount = 0;
this.completeSpecCount = 0;
this.passedCount = 0;
this.failedCount = 0;
this.skippedCount = 0;
this.createResultsMenu = function() {
this.resultsMenu = this.createDom('span', {className: 'resultsMenu bar'},
this.summaryMenuItem = this.createDom('span', {className: 'summaryMenuItem'}, '0 specs'),
' | ',
this.detailsMenuItem = this.createDom('span', {className: 'detailsMenuItem'}, '0 failing'),
this.currentSpecMenuItem = this.createDom('div', {className: 'currentSpecMenuItem'}, '')
);
};
this.addSpecs = function(specs, specFilter) {
this.totalSpecCount = specs.length;
this.views = {
specs: {},
suites: {}
};
for (var i = 0; i < specs.length; i++) {
var spec = specs[i];
this.views.specs[spec.id] = new jasmine.AtomReporter.SpecView(spec, dom, this.views);
if (specFilter(spec)) {
this.runningSpecCount++;
}
}
};
this.specStarted = function(spec) {
if (this.currentSpecMenuItem) {
this.currentSpecMenuItem.innerHTML = spec.getFullName()
}
}
this.specComplete = function(spec) {
this.completeSpecCount++;
if (isUndefined(this.views.specs[spec.id])) {
this.views.specs[spec.id] = new jasmine.AtomReporter.SpecView(spec, dom);
}
var specView = this.views.specs[spec.id];
switch (specView.status()) {
case 'passed':
this.passedCount++;
break;
case 'failed':
this.failedCount++;
break;
case 'skipped':
this.skippedCount++;
break;
}
specView.refresh(spec);
this.refresh();
};
this.suiteComplete = function(suite) {
var suiteView = this.views.suites[suite.id];
if (isUndefined(suiteView)) {
return;
}
suiteView.refresh();
};
this.refresh = function() {
if (isUndefined(this.resultsMenu)) {
this.createResultsMenu();
dom.alert.appendChild(this.resultsMenu);
}
// summary info
this.summaryMenuItem.innerHTML = "" + specPluralizedFor(this.runningSpecCount);
this.detailsMenuItem.innerHTML = "" + this.failedCount + " failing";
};
this.complete = function() {
dom.alert.removeChild(this.resultsMenu);
var skippedSpecs = this.skippedCount == 0 ? "" : " (" + this.skippedCount + " specs skipped)"
if (this.failedCount === 0) {
dom.alert.appendChild(this.createDom('span', {className: 'passingAlert bar'}, this.passedCount + "/" + specPluralizedFor(this.totalSpecCount - this.skippedCount) + " passed" + skippedSpecs));
} else {
dom.alert.appendChild(this.createDom('span', {className: 'failingAlert bar'}, specPluralizedFor(this.failedCount) + " failed" + skippedSpecs));
showDetails();
}
dom.banner.appendChild(this.createDom('span', {className: 'duration'}, "finished in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s"));
};
return this;
function showDetails() {
if (dom.reporter.className.search(/showDetails/) === -1) {
dom.reporter.className += " showDetails";
}
}
function isUndefined(obj) {
return typeof obj === 'undefined';
}
function isDefined(obj) {
return !isUndefined(obj);
}
function specPluralizedFor(count) {
var str = count + " spec";
if (count > 1) {
str += "s"
}
return str;
}
};
jasmine.AtomReporterHelpers.addHelpers(jasmine.AtomReporter.ReporterView);
jasmine.AtomReporter.SpecView = function(spec, dom, views) {
this.spec = spec;
this.dom = dom;
this.views = views;
this.symbol = this.createDom('li', { className: 'pending' });
this.dom.symbolSummary.appendChild(this.symbol);
this.summary = this.createDom('div', { className: 'specSummary' },
this.createDom('a', {
className: 'description',
href: jasmine.AtomReporter.sectionLink(this.spec.getFullName()),
title: this.spec.getFullName()
}, this.spec.description)
);
this.detail = this.createDom('div', { className: 'specDetail' },
this.createDom('a', {
className: 'description',
href: '?spec=' + encodeURIComponent(spec.getFullName()),
title: spec.getFullName()
}, spec.description));
href: '?spec=' + encodeURIComponent(this.spec.getFullName()),
title: this.spec.getFullName()
}, this.spec.getFullName())
);
};
jasmine.AtomReporter.SpecView.prototype.status = function() {
return this.getSpecStatus(this.spec);
};
var resultItems = results.getItems();
jasmine.AtomReporter.SpecView.prototype.refresh = function() {
this.symbol.className = this.status();
switch (this.status()) {
case 'skipped':
case 'passed':
break;
case 'failed':
this.appendSummaryToSuiteDiv();
this.appendFailureDetail();
break;
}
};
jasmine.AtomReporter.SpecView.prototype.appendSummaryToSuiteDiv = function() {
this.summary.className += ' ' + this.status();
this.appendToSummary(this.spec, this.summary);
};
jasmine.AtomReporter.SpecView.prototype.appendFailureDetail = function() {
this.detail.className += ' ' + this.status();
var resultItems = this.spec.results().getItems();
var messagesDiv = this.createDom('div', { className: 'messages' });
for (var i = 0; i < resultItems.length; i++) {
var result = resultItems[i];
@@ -154,37 +379,29 @@ jasmine.AtomReporter.prototype.reportSpecResults = function(spec) {
}
if (messagesDiv.childNodes.length > 0) {
specDiv.appendChild(messagesDiv);
}
this.suiteDivs[spec.suite.id].appendChild(specDiv);
};
jasmine.AtomReporter.prototype.log = function() {
var console = jasmine.getGlobal().console;
if (console && console.log) {
if (console.log.apply) {
console.log.apply(console, arguments);
} else {
console.log(arguments); // ie fix: console.log.apply doesn't exist on ie
}
this.detail.appendChild(messagesDiv);
this.dom.details.appendChild(this.detail);
}
};
jasmine.AtomReporter.prototype.getLocation = function() {
return this.document.location;
jasmine.AtomReporterHelpers.addHelpers(jasmine.AtomReporter.SpecView);jasmine.AtomReporter.SuiteView = function(suite, dom, views) {
this.suite = suite;
this.dom = dom;
this.views = views;
this.element = this.createDom('div', { className: 'suite' },
this.createDom('a', { className: 'description', href: jasmine.AtomReporter.sectionLink(this.suite.getFullName()) }, this.suite.description)
);
this.appendToSummary(this.suite, this.element);
};
jasmine.AtomReporter.prototype.specFilter = function(spec) {
var paramMap = {};
var params = this.getLocation().search.substring(1).split('&');
for (var i = 0; i < params.length; i++) {
var p = params[i].split('=');
paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]);
}
if (!paramMap.spec) {
return true;
}
return spec.getFullName().indexOf(paramMap.spec) === 0;
jasmine.AtomReporter.SuiteView.prototype.status = function() {
return this.getSpecStatus(this.suite);
};
jasmine.AtomReporter.SuiteView.prototype.refresh = function() {
this.element.className += " " + this.status();
};
jasmine.AtomReporterHelpers.addHelpers(jasmine.AtomReporter.SuiteView);

View File

@@ -31,7 +31,9 @@ jasmine.ConsoleReporter.prototype.reportSpecResults = function(spec) {
for (var i = 0; i < resultItems.length; i++) {
var result = resultItems[i];
if (this.logErrors && result.type == 'expect' && result.passed && !result.passed()) {
console.log("ERROR: " + spec.getFullName())
message = spec.getFullName()
console.log("\n\n" + message)
console.log((new Array(message.length + 1)).join('-'))
if (result.trace.stack) {
console.log(result.trace.stack)
}
@@ -43,9 +45,5 @@ jasmine.ConsoleReporter.prototype.reportSpecResults = function(spec) {
};
jasmine.ConsoleReporter.prototype.specFilter = function(spec) {
if (!jasmine.getEnv().focusPriority) {
return true;
}
return fSpecFilter(spec);
return true;
};

View File

@@ -36,28 +36,12 @@ var fffit = function(description, specDefinitions) {
fit(description, specDefinitions, 3);
};
var fSpecFilter = function(specOrSuite) {
jasmine.AtomReporter.prototype.fSpecFilter = function(specOrSuite) {
globalFocusPriority = jasmine.getEnv().focusPriority;
if (!globalFocusPriority) return true;
if (specOrSuite.focusPriority >= globalFocusPriority) return true;
var parent = specOrSuite.parentSuite || specOrSuite.suite;
if (!parent) return false;
return fSpecFilter(parent);
}
jasmine.AtomReporter.prototype.specFilter = function(spec) {
var paramMap = {};
var params = this.getLocation().search.substring(1).split('&');
for (var i = 0; i < params.length; i++) {
var p = params[i].split('=');
paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]);
}
if (!paramMap.spec && !jasmine.getEnv().focusPriority) {
return true;
}
return (spec.getFullName().indexOf(paramMap.spec) === 0) || fSpecFilter(spec);
};
return this.fSpecFilter(parent);
};

View File

@@ -8,9 +8,6 @@ module.exports.runSpecSuite = (specSuite, logErrors=true) ->
$ = require 'jquery'
TimeReporter = require 'time-reporter'
$('body').append $$ ->
@div id: 'jasmine-content'
reporter = if atom.exitWhenDone
new jasmine.ConsoleReporter(document, logErrors)
else
@@ -22,4 +19,8 @@ module.exports.runSpecSuite = (specSuite, logErrors=true) ->
jasmineEnv.addReporter(new TimeReporter())
jasmineEnv.specFilter = (spec) -> reporter.specFilter(spec)
$('body').append $$ ->
@div id: 'jasmine-content'
jasmineEnv.execute()

583
vendor/jasmine.js vendored
View File

@@ -1,8 +1,10 @@
// Modified line 1769
// - if (self.blocks[self.index].abort) {
// + if (self.blocks[self.index] && self.blocks[self.index].abort) {
// Modified line
// - var isCommonJS = typeof window == "undefined" && typeof exports == "object";
// +
//
// Modified method jasmine.WaitsForBlock.prototype.execute
var isCommonJS = typeof window == "undefined";
var isCommonJS = typeof window == "undefined" && typeof exports == "object";
/**
* Top level namespace for Jasmine, a lightweight JavaScript BDD/spec/testing framework.
@@ -38,11 +40,23 @@ jasmine.VERBOSE = false;
*/
jasmine.DEFAULT_UPDATE_INTERVAL = 250;
/**
* Maximum levels of nesting that will be included when an object is pretty-printed
*/
jasmine.MAX_PRETTY_PRINT_DEPTH = 40;
/**
* Default timeout interval in milliseconds for waitsFor() blocks.
*/
jasmine.DEFAULT_TIMEOUT_INTERVAL = 5000;
/**
* By default exceptions thrown in the context of a test are caught by jasmine so that it can run the remaining tests in the suite.
* Set to false to let the exception bubble up in the browser.
*
*/
jasmine.CATCH_EXCEPTIONS = true;
jasmine.getGlobal = function() {
function getGlobal() {
return window;
@@ -200,6 +214,21 @@ jasmine.any = function(clazz) {
return new jasmine.Matchers.Any(clazz);
};
/**
* Returns a matchable subset of a JSON object. For use in expectations when you don't care about all of the
* attributes on the object.
*
* @example
* // don't care about any other attributes than foo.
* expect(mySpy).toHaveBeenCalledWith(jasmine.objectContaining({foo: "bar"});
*
* @param sample {Object} sample
* @returns matchable object for the sample
*/
jasmine.objectContaining = function (sample) {
return new jasmine.Matchers.ObjectContaining(sample);
};
/**
* Jasmine Spies are test doubles that can act as stubs, spies, fakes or when used in an expecation, mocks.
*
@@ -452,7 +481,7 @@ jasmine.log = function() {
* @see jasmine.createSpy
* @param obj
* @param methodName
* @returns a Jasmine spy that can be chained with all spy methods
* @return {jasmine.Spy} a Jasmine spy that can be chained with all spy methods
*/
var spyOn = function(obj, methodName) {
return jasmine.getEnv().currentSpec.spyOn(obj, methodName);
@@ -497,6 +526,7 @@ if (isCommonJS) exports.xit = xit;
* jasmine.Matchers functions.
*
* @param {Object} actual Actual value to test against and expected value
* @return {jasmine.Matchers}
*/
var expect = function(actual) {
return jasmine.getEnv().currentSpec.expect(actual);
@@ -856,6 +886,25 @@ jasmine.Env.prototype.xit = function(desc, func) {
};
};
jasmine.Env.prototype.compareRegExps_ = function(a, b, mismatchKeys, mismatchValues) {
if (a.source != b.source)
mismatchValues.push("expected pattern /" + b.source + "/ is not equal to the pattern /" + a.source + "/");
if (a.ignoreCase != b.ignoreCase)
mismatchValues.push("expected modifier i was" + (b.ignoreCase ? " " : " not ") + "set and does not equal the origin modifier");
if (a.global != b.global)
mismatchValues.push("expected modifier g was" + (b.global ? " " : " not ") + "set and does not equal the origin modifier");
if (a.multiline != b.multiline)
mismatchValues.push("expected modifier m was" + (b.multiline ? " " : " not ") + "set and does not equal the origin modifier");
if (a.sticky != b.sticky)
mismatchValues.push("expected modifier y was" + (b.sticky ? " " : " not ") + "set and does not equal the origin modifier");
return (mismatchValues.length === 0);
};
jasmine.Env.prototype.compareObjects_ = function(a, b, mismatchKeys, mismatchValues) {
if (a.__Jasmine_been_here_before__ === b && b.__Jasmine_been_here_before__ === a) {
return true;
@@ -918,11 +967,19 @@ jasmine.Env.prototype.equals_ = function(a, b, mismatchKeys, mismatchValues) {
return a.getTime() == b.getTime();
}
if (a instanceof jasmine.Matchers.Any) {
if (a.jasmineMatches) {
return a.jasmineMatches(b);
}
if (b.jasmineMatches) {
return b.jasmineMatches(a);
}
if (a instanceof jasmine.Matchers.ObjectContaining) {
return a.matches(b);
}
if (b instanceof jasmine.Matchers.Any) {
if (b instanceof jasmine.Matchers.ObjectContaining) {
return b.matches(a);
}
@@ -934,6 +991,10 @@ jasmine.Env.prototype.equals_ = function(a, b, mismatchKeys, mismatchValues) {
return (a == b);
}
if (a instanceof RegExp && b instanceof RegExp) {
return this.compareRegExps_(a, b, mismatchKeys, mismatchValues);
}
if (typeof a === "object" && typeof b === "object") {
return this.compareObjects_(a, b, mismatchKeys, mismatchValues);
}
@@ -1001,10 +1062,15 @@ jasmine.Block = function(env, func, spec) {
};
jasmine.Block.prototype.execute = function(onComplete) {
try {
if (!jasmine.CATCH_EXCEPTIONS) {
this.func.apply(this.spec);
} catch (e) {
this.spec.fail(e);
}
else {
try {
this.func.apply(this.spec);
} catch (e) {
this.spec.fail(e);
}
}
onComplete();
};
@@ -1216,7 +1282,7 @@ jasmine.Matchers.prototype.toEqual = function(expected) {
/**
* toNotEqual: compares the actual to the expected using the ! of jasmine.Matchers.toEqual
* @param expected
* @deprecated as of 1.0. Use not.toNotEqual() instead.
* @deprecated as of 1.0. Use not.toEqual() instead.
*/
jasmine.Matchers.prototype.toNotEqual = function(expected) {
return !this.env.equals_(this.actual, expected);
@@ -1262,6 +1328,17 @@ jasmine.Matchers.prototype.toBeNull = function() {
return (this.actual === null);
};
/**
* Matcher that compares the actual to NaN.
*/
jasmine.Matchers.prototype.toBeNaN = function() {
this.message = function() {
return [ "Expected " + jasmine.pp(this.actual) + " to be NaN." ];
};
return (this.actual !== this.actual);
};
/**
* Matcher that boolean not-nots the actual.
*/
@@ -1339,18 +1416,14 @@ jasmine.Matchers.prototype.toHaveBeenCalledWith = function() {
throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
}
this.message = function() {
var invertedMessage = "Expected spy " + this.actual.identity + " not to have been called with " + jasmine.pp(expectedArgs) + " but it was.";
var positiveMessage = "";
if (this.actual.callCount === 0) {
// todo: what should the failure message for .not.toHaveBeenCalledWith() be? is this right? test better. [xw]
return [
"Expected spy " + this.actual.identity + " to have been called with " + jasmine.pp(expectedArgs) + " but it was never called.",
"Expected spy " + this.actual.identity + " not to have been called with " + jasmine.pp(expectedArgs) + " but it was."
];
positiveMessage = "Expected spy " + this.actual.identity + " to have been called with " + jasmine.pp(expectedArgs) + " but it was never called.";
} else {
return [
"Expected spy " + this.actual.identity + " to have been called with " + jasmine.pp(expectedArgs) + " but was called with " + jasmine.pp(this.actual.argsForCall),
"Expected spy " + this.actual.identity + " not to have been called with " + jasmine.pp(expectedArgs) + " but was called with " + jasmine.pp(this.actual.argsForCall)
];
positiveMessage = "Expected spy " + this.actual.identity + " to have been called with " + jasmine.pp(expectedArgs) + " but actual calls were " + jasmine.pp(this.actual.argsForCall).replace(/^\[ | \]$/g, '')
}
return [positiveMessage, invertedMessage];
};
return this.env.contains_(this.actual.argsForCall, expectedArgs);
@@ -1389,7 +1462,7 @@ jasmine.Matchers.prototype.toContain = function(expected) {
* Matcher that checks that the expected item is NOT an element in the actual Array.
*
* @param {Object} expected
* @deprecated as of 1.0. Use not.toNotContain() instead.
* @deprecated as of 1.0. Use not.toContain() instead.
*/
jasmine.Matchers.prototype.toNotContain = function(expected) {
return !this.env.contains_(this.actual, expected);
@@ -1408,22 +1481,19 @@ jasmine.Matchers.prototype.toBeGreaterThan = function(expected) {
* up to a given level of decimal precision (default 2).
*
* @param {Number} expected
* @param {Number} precision
* @param {Number} precision, as number of decimal places
*/
jasmine.Matchers.prototype.toBeCloseTo = function(expected, precision) {
if (!(precision === 0)) {
precision = precision || 2;
}
var multiplier = Math.pow(10, precision);
var actual = Math.round(this.actual * multiplier);
expected = Math.round(expected * multiplier);
return expected == actual;
return Math.abs(expected - this.actual) < (Math.pow(10, -precision) / 2);
};
/**
* Matcher that checks that the expected exception was thrown by the actual.
*
* @param {String} expected
* @param {String} [expected]
*/
jasmine.Matchers.prototype.toThrow = function(expected) {
var result = false;
@@ -1457,7 +1527,7 @@ jasmine.Matchers.Any = function(expectedClass) {
this.expectedClass = expectedClass;
};
jasmine.Matchers.Any.prototype.matches = function(other) {
jasmine.Matchers.Any.prototype.jasmineMatches = function(other) {
if (this.expectedClass == String) {
return typeof other == 'string' || other instanceof String;
}
@@ -1477,10 +1547,222 @@ jasmine.Matchers.Any.prototype.matches = function(other) {
return other instanceof this.expectedClass;
};
jasmine.Matchers.Any.prototype.toString = function() {
jasmine.Matchers.Any.prototype.jasmineToString = function() {
return '<jasmine.any(' + this.expectedClass + ')>';
};
jasmine.Matchers.ObjectContaining = function (sample) {
this.sample = sample;
};
jasmine.Matchers.ObjectContaining.prototype.jasmineMatches = function(other, mismatchKeys, mismatchValues) {
mismatchKeys = mismatchKeys || [];
mismatchValues = mismatchValues || [];
var env = jasmine.getEnv();
var hasKey = function(obj, keyName) {
return obj != null && obj[keyName] !== jasmine.undefined;
};
for (var property in this.sample) {
if (!hasKey(other, property) && hasKey(this.sample, property)) {
mismatchKeys.push("expected has key '" + property + "', but missing from actual.");
}
else if (!env.equals_(this.sample[property], other[property], mismatchKeys, mismatchValues)) {
mismatchValues.push("'" + property + "' was '" + (other[property] ? jasmine.util.htmlEscape(other[property].toString()) : other[property]) + "' in expected, but was '" + (this.sample[property] ? jasmine.util.htmlEscape(this.sample[property].toString()) : this.sample[property]) + "' in actual.");
}
}
return (mismatchKeys.length === 0 && mismatchValues.length === 0);
};
jasmine.Matchers.ObjectContaining.prototype.jasmineToString = function () {
return "<jasmine.objectContaining(" + jasmine.pp(this.sample) + ")>";
};
// Mock setTimeout, clearTimeout
// Contributed by Pivotal Computer Systems, www.pivotalsf.com
jasmine.FakeTimer = function() {
this.reset();
var self = this;
self.setTimeout = function(funcToCall, millis) {
self.timeoutsMade++;
self.scheduleFunction(self.timeoutsMade, funcToCall, millis, false);
return self.timeoutsMade;
};
self.setInterval = function(funcToCall, millis) {
self.timeoutsMade++;
self.scheduleFunction(self.timeoutsMade, funcToCall, millis, true);
return self.timeoutsMade;
};
self.clearTimeout = function(timeoutKey) {
self.scheduledFunctions[timeoutKey] = jasmine.undefined;
};
self.clearInterval = function(timeoutKey) {
self.scheduledFunctions[timeoutKey] = jasmine.undefined;
};
};
jasmine.FakeTimer.prototype.reset = function() {
this.timeoutsMade = 0;
this.scheduledFunctions = {};
this.nowMillis = 0;
};
jasmine.FakeTimer.prototype.tick = function(millis) {
var oldMillis = this.nowMillis;
var newMillis = oldMillis + millis;
this.runFunctionsWithinRange(oldMillis, newMillis);
this.nowMillis = newMillis;
};
jasmine.FakeTimer.prototype.runFunctionsWithinRange = function(oldMillis, nowMillis) {
var scheduledFunc;
var funcsToRun = [];
for (var timeoutKey in this.scheduledFunctions) {
scheduledFunc = this.scheduledFunctions[timeoutKey];
if (scheduledFunc != jasmine.undefined &&
scheduledFunc.runAtMillis >= oldMillis &&
scheduledFunc.runAtMillis <= nowMillis) {
funcsToRun.push(scheduledFunc);
this.scheduledFunctions[timeoutKey] = jasmine.undefined;
}
}
if (funcsToRun.length > 0) {
funcsToRun.sort(function(a, b) {
return a.runAtMillis - b.runAtMillis;
});
for (var i = 0; i < funcsToRun.length; ++i) {
try {
var funcToRun = funcsToRun[i];
this.nowMillis = funcToRun.runAtMillis;
funcToRun.funcToCall();
if (funcToRun.recurring) {
this.scheduleFunction(funcToRun.timeoutKey,
funcToRun.funcToCall,
funcToRun.millis,
true);
}
} catch(e) {
}
}
this.runFunctionsWithinRange(oldMillis, nowMillis);
}
};
jasmine.FakeTimer.prototype.scheduleFunction = function(timeoutKey, funcToCall, millis, recurring) {
this.scheduledFunctions[timeoutKey] = {
runAtMillis: this.nowMillis + millis,
funcToCall: funcToCall,
recurring: recurring,
timeoutKey: timeoutKey,
millis: millis
};
};
/**
* @namespace
*/
jasmine.Clock = {
defaultFakeTimer: new jasmine.FakeTimer(),
reset: function() {
jasmine.Clock.assertInstalled();
jasmine.Clock.defaultFakeTimer.reset();
},
tick: function(millis) {
jasmine.Clock.assertInstalled();
jasmine.Clock.defaultFakeTimer.tick(millis);
},
runFunctionsWithinRange: function(oldMillis, nowMillis) {
jasmine.Clock.defaultFakeTimer.runFunctionsWithinRange(oldMillis, nowMillis);
},
scheduleFunction: function(timeoutKey, funcToCall, millis, recurring) {
jasmine.Clock.defaultFakeTimer.scheduleFunction(timeoutKey, funcToCall, millis, recurring);
},
useMock: function() {
if (!jasmine.Clock.isInstalled()) {
var spec = jasmine.getEnv().currentSpec;
spec.after(jasmine.Clock.uninstallMock);
jasmine.Clock.installMock();
}
},
installMock: function() {
jasmine.Clock.installed = jasmine.Clock.defaultFakeTimer;
},
uninstallMock: function() {
jasmine.Clock.assertInstalled();
jasmine.Clock.installed = jasmine.Clock.real;
},
real: {
setTimeout: jasmine.getGlobal().setTimeout,
clearTimeout: jasmine.getGlobal().clearTimeout,
setInterval: jasmine.getGlobal().setInterval,
clearInterval: jasmine.getGlobal().clearInterval
},
assertInstalled: function() {
if (!jasmine.Clock.isInstalled()) {
throw new Error("Mock clock is not installed, use jasmine.Clock.useMock()");
}
},
isInstalled: function() {
return jasmine.Clock.installed == jasmine.Clock.defaultFakeTimer;
},
installed: null
};
jasmine.Clock.installed = jasmine.Clock.real;
//else for IE support
jasmine.getGlobal().setTimeout = function(funcToCall, millis) {
if (jasmine.Clock.installed.setTimeout.apply) {
return jasmine.Clock.installed.setTimeout.apply(this, arguments);
} else {
return jasmine.Clock.installed.setTimeout(funcToCall, millis);
}
};
jasmine.getGlobal().setInterval = function(funcToCall, millis) {
if (jasmine.Clock.installed.setInterval.apply) {
return jasmine.Clock.installed.setInterval.apply(this, arguments);
} else {
return jasmine.Clock.installed.setInterval(funcToCall, millis);
}
};
jasmine.getGlobal().clearTimeout = function(timeoutKey) {
if (jasmine.Clock.installed.clearTimeout.apply) {
return jasmine.Clock.installed.clearTimeout.apply(this, arguments);
} else {
return jasmine.Clock.installed.clearTimeout(timeoutKey);
}
};
jasmine.getGlobal().clearInterval = function(timeoutKey) {
if (jasmine.Clock.installed.clearTimeout.apply) {
return jasmine.Clock.installed.clearInterval.apply(this, arguments);
} else {
return jasmine.Clock.installed.clearInterval(timeoutKey);
}
};
/**
* @constructor
*/
@@ -1609,10 +1891,6 @@ jasmine.PrettyPrinter = function() {
* @param value
*/
jasmine.PrettyPrinter.prototype.format = function(value) {
if (this.ppNestLevel_ > 40) {
throw new Error('jasmine.PrettyPrinter: format() nested too deeply!');
}
this.ppNestLevel_++;
try {
if (value === jasmine.undefined) {
@@ -1621,8 +1899,8 @@ jasmine.PrettyPrinter.prototype.format = function(value) {
this.emitScalar('null');
} else if (value === jasmine.getGlobal()) {
this.emitScalar('<global>');
} else if (value instanceof jasmine.Matchers.Any) {
this.emitScalar(value.toString());
} else if (value.jasmineToString) {
this.emitScalar(value.jasmineToString());
} else if (typeof value === 'string') {
this.emitString(value);
} else if (jasmine.isSpy(value)) {
@@ -1655,6 +1933,7 @@ jasmine.PrettyPrinter.prototype.format = function(value) {
jasmine.PrettyPrinter.prototype.iterateObject = function(obj, fn) {
for (var property in obj) {
if (!obj.hasOwnProperty(property)) continue;
if (property == '__Jasmine_been_here_before__') continue;
fn(property, obj.__lookupGetter__ ? (obj.__lookupGetter__(property) !== jasmine.undefined &&
obj.__lookupGetter__(property) !== null) : false);
@@ -1682,6 +1961,11 @@ jasmine.StringPrettyPrinter.prototype.emitString = function(value) {
};
jasmine.StringPrettyPrinter.prototype.emitArray = function(array) {
if (this.ppNestLevel_ > jasmine.MAX_PRETTY_PRINT_DEPTH) {
this.append("Array");
return;
}
this.append('[ ');
for (var i = 0; i < array.length; i++) {
if (i > 0) {
@@ -1693,6 +1977,11 @@ jasmine.StringPrettyPrinter.prototype.emitArray = function(array) {
};
jasmine.StringPrettyPrinter.prototype.emitObject = function(obj) {
if (this.ppNestLevel_ > jasmine.MAX_PRETTY_PRINT_DEPTH) {
this.append("Object");
return;
}
var self = this;
this.append('{ ');
var first = true;
@@ -1721,6 +2010,10 @@ jasmine.StringPrettyPrinter.prototype.append = function(value) {
};
jasmine.Queue = function(env) {
this.env = env;
// parallel to blocks. each true value in this array means the block will
// get executed even if we abort
this.ensured = [];
this.blocks = [];
this.running = false;
this.index = 0;
@@ -1728,15 +2021,30 @@ jasmine.Queue = function(env) {
this.abort = false;
};
jasmine.Queue.prototype.addBefore = function(block) {
jasmine.Queue.prototype.addBefore = function(block, ensure) {
if (ensure === jasmine.undefined) {
ensure = false;
}
this.blocks.unshift(block);
this.ensured.unshift(ensure);
};
jasmine.Queue.prototype.add = function(block) {
jasmine.Queue.prototype.add = function(block, ensure) {
if (ensure === jasmine.undefined) {
ensure = false;
}
this.blocks.push(block);
this.ensured.push(ensure);
};
jasmine.Queue.prototype.insertNext = function(block) {
jasmine.Queue.prototype.insertNext = function(block, ensure) {
if (ensure === jasmine.undefined) {
ensure = false;
}
this.ensured.splice((this.index + this.offset + 1), 0, ensure);
this.blocks.splice((this.index + this.offset + 1), 0, block);
this.offset++;
};
@@ -1760,7 +2068,7 @@ jasmine.Queue.prototype.next_ = function() {
while (goAgain) {
goAgain = false;
if (self.index < self.blocks.length && !this.abort) {
if (self.index < self.blocks.length && !(this.abort && !this.ensured[self.index])) {
var calledSynchronously = true;
var completedSynchronously = false;
@@ -2051,7 +2359,7 @@ jasmine.Spec.prototype.finish = function(onComplete) {
jasmine.Spec.prototype.after = function(doAfter) {
if (this.queue.isRunning()) {
this.queue.add(new jasmine.Block(this.env, doAfter, this));
this.queue.add(new jasmine.Block(this.env, doAfter, this), true);
} else {
this.afterCallbacks.unshift(doAfter);
}
@@ -2089,15 +2397,15 @@ jasmine.Spec.prototype.addBeforesAndAftersToQueue = function() {
this.queue.addBefore(new jasmine.Block(this.env, runner.before_[i], this));
}
for (i = 0; i < this.afterCallbacks.length; i++) {
this.queue.add(new jasmine.Block(this.env, this.afterCallbacks[i], this));
this.queue.add(new jasmine.Block(this.env, this.afterCallbacks[i], this), true);
}
for (suite = this.suite; suite; suite = suite.parentSuite) {
for (i = 0; i < suite.after_.length; i++) {
this.queue.add(new jasmine.Block(this.env, suite.after_[i], this));
this.queue.add(new jasmine.Block(this.env, suite.after_[i], this), true);
}
}
for (i = 0; i < runner.after_.length; i++) {
this.queue.add(new jasmine.Block(this.env, runner.after_[i], this));
this.queue.add(new jasmine.Block(this.env, runner.after_[i], this), true);
}
};
@@ -2351,192 +2659,9 @@ jasmine.WaitsForBlock.MultiCompletion.prototype.buildCompletionFunction = functi
};
};
// Mock setTimeout, clearTimeout
// Contributed by Pivotal Computer Systems, www.pivotalsf.com
jasmine.FakeTimer = function() {
this.reset();
var self = this;
self.setTimeout = function(funcToCall, millis) {
self.timeoutsMade++;
self.scheduleFunction(self.timeoutsMade, funcToCall, millis, false);
return self.timeoutsMade;
};
self.setInterval = function(funcToCall, millis) {
self.timeoutsMade++;
self.scheduleFunction(self.timeoutsMade, funcToCall, millis, true);
return self.timeoutsMade;
};
self.clearTimeout = function(timeoutKey) {
self.scheduledFunctions[timeoutKey] = jasmine.undefined;
};
self.clearInterval = function(timeoutKey) {
self.scheduledFunctions[timeoutKey] = jasmine.undefined;
};
};
jasmine.FakeTimer.prototype.reset = function() {
this.timeoutsMade = 0;
this.scheduledFunctions = {};
this.nowMillis = 0;
};
jasmine.FakeTimer.prototype.tick = function(millis) {
var oldMillis = this.nowMillis;
var newMillis = oldMillis + millis;
this.runFunctionsWithinRange(oldMillis, newMillis);
this.nowMillis = newMillis;
};
jasmine.FakeTimer.prototype.runFunctionsWithinRange = function(oldMillis, nowMillis) {
var scheduledFunc;
var funcsToRun = [];
for (var timeoutKey in this.scheduledFunctions) {
scheduledFunc = this.scheduledFunctions[timeoutKey];
if (scheduledFunc != jasmine.undefined &&
scheduledFunc.runAtMillis >= oldMillis &&
scheduledFunc.runAtMillis <= nowMillis) {
funcsToRun.push(scheduledFunc);
this.scheduledFunctions[timeoutKey] = jasmine.undefined;
}
}
if (funcsToRun.length > 0) {
funcsToRun.sort(function(a, b) {
return a.runAtMillis - b.runAtMillis;
});
for (var i = 0; i < funcsToRun.length; ++i) {
try {
var funcToRun = funcsToRun[i];
this.nowMillis = funcToRun.runAtMillis;
funcToRun.funcToCall();
if (funcToRun.recurring) {
this.scheduleFunction(funcToRun.timeoutKey,
funcToRun.funcToCall,
funcToRun.millis,
true);
}
} catch(e) {
}
}
this.runFunctionsWithinRange(oldMillis, nowMillis);
}
};
jasmine.FakeTimer.prototype.scheduleFunction = function(timeoutKey, funcToCall, millis, recurring) {
this.scheduledFunctions[timeoutKey] = {
runAtMillis: this.nowMillis + millis,
funcToCall: funcToCall,
recurring: recurring,
timeoutKey: timeoutKey,
millis: millis
};
};
/**
* @namespace
*/
jasmine.Clock = {
defaultFakeTimer: new jasmine.FakeTimer(),
reset: function() {
jasmine.Clock.assertInstalled();
jasmine.Clock.defaultFakeTimer.reset();
},
tick: function(millis) {
jasmine.Clock.assertInstalled();
jasmine.Clock.defaultFakeTimer.tick(millis);
},
runFunctionsWithinRange: function(oldMillis, nowMillis) {
jasmine.Clock.defaultFakeTimer.runFunctionsWithinRange(oldMillis, nowMillis);
},
scheduleFunction: function(timeoutKey, funcToCall, millis, recurring) {
jasmine.Clock.defaultFakeTimer.scheduleFunction(timeoutKey, funcToCall, millis, recurring);
},
useMock: function() {
if (!jasmine.Clock.isInstalled()) {
var spec = jasmine.getEnv().currentSpec;
spec.after(jasmine.Clock.uninstallMock);
jasmine.Clock.installMock();
}
},
installMock: function() {
jasmine.Clock.installed = jasmine.Clock.defaultFakeTimer;
},
uninstallMock: function() {
jasmine.Clock.assertInstalled();
jasmine.Clock.installed = jasmine.Clock.real;
},
real: {
setTimeout: jasmine.getGlobal().setTimeout,
clearTimeout: jasmine.getGlobal().clearTimeout,
setInterval: jasmine.getGlobal().setInterval,
clearInterval: jasmine.getGlobal().clearInterval
},
assertInstalled: function() {
if (!jasmine.Clock.isInstalled()) {
throw new Error("Mock clock is not installed, use jasmine.Clock.useMock()");
}
},
isInstalled: function() {
return jasmine.Clock.installed == jasmine.Clock.defaultFakeTimer;
},
installed: null
};
jasmine.Clock.installed = jasmine.Clock.real;
//else for IE support
jasmine.getGlobal().setTimeout = function(funcToCall, millis) {
if (jasmine.Clock.installed.setTimeout.apply) {
return jasmine.Clock.installed.setTimeout.apply(this, arguments);
} else {
return jasmine.Clock.installed.setTimeout(funcToCall, millis);
}
};
jasmine.getGlobal().setInterval = function(funcToCall, millis) {
if (jasmine.Clock.installed.setInterval.apply) {
return jasmine.Clock.installed.setInterval.apply(this, arguments);
} else {
return jasmine.Clock.installed.setInterval(funcToCall, millis);
}
};
jasmine.getGlobal().clearTimeout = function(timeoutKey) {
if (jasmine.Clock.installed.clearTimeout.apply) {
return jasmine.Clock.installed.clearTimeout.apply(this, arguments);
} else {
return jasmine.Clock.installed.clearTimeout(timeoutKey);
}
};
jasmine.getGlobal().clearInterval = function(timeoutKey) {
if (jasmine.Clock.installed.clearTimeout.apply) {
return jasmine.Clock.installed.clearInterval.apply(this, arguments);
} else {
return jasmine.Clock.installed.clearInterval(timeoutKey);
}
};
jasmine.version_= {
"major": 1,
"minor": 1,
"build": 0,
"revision": 1315677058
"minor": 3,
"build": 1,
"revision": 1354556913
};