mirror of
https://github.com/atom/atom.git
synced 2026-01-22 21:38:10 -05:00
Merge branch 'master' into privilege-escalation
Conflicts: src/text-buffer.coffee
This commit is contained in:
@@ -71,27 +71,3 @@ will only attempt to call deserialize if the two versions match, and otherwise
|
||||
return undefined. We plan on implementing a migration system in the future, but
|
||||
this at least protects you from improperly deserializing old state. If you find
|
||||
yourself in dire need of the migration system, let us know.
|
||||
|
||||
### Deferred Package Deserializers
|
||||
|
||||
If your package defers loading on startup with an `activationEvents` property in
|
||||
its `package.cson`, your deserializers won't be loaded until your package is
|
||||
activated. If you want to deserialize an object from your package on startup,
|
||||
this could be a problem.
|
||||
|
||||
The solution is to also supply a `deferredDeserializers` array in your
|
||||
`package.cson` with the names of all your deserializers. When Atom attempts to
|
||||
deserialize some state whose `deserializer` matches one of these names, it will
|
||||
load your package first so it can register any necessary deserializers before
|
||||
proceeding.
|
||||
|
||||
For example, the markdown preview package doesn't fully load until a preview is
|
||||
triggered. But if you refresh a window with a preview pane, it loads the
|
||||
markdown package early so Atom can deserialize the view correctly.
|
||||
|
||||
```coffee-script
|
||||
# markdown-preview/package.cson
|
||||
'activationEvents': 'markdown-preview:toggle': '.editor'
|
||||
'deferredDeserializers': ['MarkdownPreviewView']
|
||||
...
|
||||
```
|
||||
|
||||
@@ -68,6 +68,8 @@
|
||||
'cmd-=': 'window:increase-font-size'
|
||||
'cmd-+': 'window:increase-font-size'
|
||||
'cmd--': 'window:decrease-font-size'
|
||||
'cmd-_': 'window:decrease-font-size'
|
||||
'cmd-0': 'window:reset-font-size'
|
||||
|
||||
'cmd-k up': 'pane:split-up' # Atom Specific
|
||||
'cmd-k down': 'pane:split-down' # Atom Specific
|
||||
@@ -122,7 +124,6 @@
|
||||
'alt-cmd-z': 'editor:checkout-head-revision'
|
||||
'cmd-<': 'editor:scroll-to-cursor'
|
||||
'alt-cmd-ctrl-f': 'editor:fold-selection'
|
||||
'cmd-=': 'editor:auto-indent'
|
||||
|
||||
# Sublime Parity
|
||||
'cmd-enter': 'editor:newline-below'
|
||||
|
||||
@@ -40,6 +40,8 @@
|
||||
'ctrl-=': 'window:increase-font-size'
|
||||
'ctrl-+': 'window:increase-font-size'
|
||||
'ctrl--': 'window:decrease-font-size'
|
||||
'ctrl-_': 'window:decrease-font-size'
|
||||
'ctrl-0': 'window:reset-font-size'
|
||||
|
||||
'ctrl-k up': 'pane:split-up' # Atom Specific
|
||||
'ctrl-k down': 'pane:split-down' # Atom Specific
|
||||
@@ -69,7 +71,6 @@
|
||||
'alt-ctrl-z': 'editor:checkout-head-revision'
|
||||
'ctrl-<': 'editor:scroll-to-cursor'
|
||||
'alt-ctrl-f': 'editor:fold-selection'
|
||||
'ctrl-=': 'editor:auto-indent'
|
||||
|
||||
# Sublime Parity
|
||||
'ctrl-enter': 'editor:newline-below'
|
||||
|
||||
30
package.json
30
package.json
@@ -63,12 +63,12 @@
|
||||
"base16-tomorrow-dark-theme": "0.11.0",
|
||||
"solarized-dark-syntax": "0.9.0",
|
||||
"solarized-light-syntax": "0.5.0",
|
||||
"archive-view": "0.21.0",
|
||||
"archive-view": "0.22.0",
|
||||
"autocomplete": "0.22.0",
|
||||
"autoflow": "0.13.0",
|
||||
"autosave": "0.10.0",
|
||||
"background-tips": "0.6.0",
|
||||
"bookmarks": "0.18.0",
|
||||
"autoflow": "0.14.0",
|
||||
"autosave": "0.11.0",
|
||||
"background-tips": "0.7.0",
|
||||
"bookmarks": "0.19.0",
|
||||
"bracket-matcher": "0.20.0",
|
||||
"command-logger": "0.11.0",
|
||||
"command-palette": "0.16.0",
|
||||
@@ -76,23 +76,23 @@
|
||||
"editor-stats": "0.13.0",
|
||||
"exception-reporting": "0.13.0",
|
||||
"feedback": "0.23.0",
|
||||
"find-and-replace": "0.81.0",
|
||||
"find-and-replace": "0.82.0",
|
||||
"fuzzy-finder": "0.34.0",
|
||||
"gists": "0.17.0",
|
||||
"git-diff": "0.24.0",
|
||||
"github-sign-in": "0.18.0",
|
||||
"github-sign-in": "0.19.0",
|
||||
"go-to-line": "0.16.0",
|
||||
"grammar-selector": "0.19.0",
|
||||
"image-view": "0.19.0",
|
||||
"keybinding-resolver": "0.9.0",
|
||||
"keybinding-resolver": "0.10.0",
|
||||
"link": "0.17.0",
|
||||
"markdown-preview": "0.25.1",
|
||||
"markdown-preview": "0.28.0",
|
||||
"metrics": "0.26.0",
|
||||
"package-generator": "0.26.0",
|
||||
"release-notes": "0.18.0",
|
||||
"release-notes": "0.20.0",
|
||||
"settings-view": "0.71.0",
|
||||
"snippets": "0.27.0",
|
||||
"spell-check": "0.23.0",
|
||||
"spell-check": "0.24.0",
|
||||
"status-bar": "0.32.0",
|
||||
"styleguide": "0.23.0",
|
||||
"symbols-view": "0.33.0",
|
||||
@@ -101,10 +101,10 @@
|
||||
"timecop": "0.13.0",
|
||||
"to-the-hubs": "0.19.0",
|
||||
"tree-view": "0.69.0",
|
||||
"update-package-dependencies": "0.2.0",
|
||||
"visual-bell": "0.6.0",
|
||||
"update-package-dependencies": "0.3.0",
|
||||
"visual-bell": "0.7.0",
|
||||
"welcome": "0.4.0",
|
||||
"whitespace": "0.11.0",
|
||||
"whitespace": "0.12.0",
|
||||
"wrap-guide": "0.14.0",
|
||||
"language-c": "0.4.0",
|
||||
"language-clojure": "0.1.0",
|
||||
@@ -136,7 +136,7 @@
|
||||
"language-sql": "0.3.0",
|
||||
"language-text": "0.3.0",
|
||||
"language-todo": "0.3.0",
|
||||
"language-toml": "0.7.0",
|
||||
"language-toml": "0.8.0",
|
||||
"language-xml": "0.3.0",
|
||||
"language-yaml": "0.2.0"
|
||||
},
|
||||
|
||||
@@ -1,34 +1,49 @@
|
||||
{View, $, $$} = require '../src/space-pen-extensions'
|
||||
path = require 'path'
|
||||
_ = require 'underscore-plus'
|
||||
{convertStackTrace} = require 'coffeestack'
|
||||
{View, $, $$} = require '../src/space-pen-extensions'
|
||||
|
||||
sourceMaps = {}
|
||||
formatStackTrace = (stackTrace) ->
|
||||
formatStackTrace = (message='', stackTrace) ->
|
||||
return stackTrace unless stackTrace
|
||||
|
||||
jasminePattern = /^\s*at\s+.*\(?.*\/jasmine(-[^\/]*)?\.js:\d+:\d+\)?\s*$/
|
||||
firstJasmineLinePattern = /^\s*at \/.*\/jasmine(-[^\/]*)?\.js:\d+:\d+\)?\s*$/
|
||||
convertedLines = []
|
||||
for line in stackTrace.split('\n')
|
||||
convertedLines.push(line) unless jasminePattern.test(line)
|
||||
break if firstJasmineLinePattern.test(line)
|
||||
|
||||
convertStackTrace(convertedLines.join('\n'), sourceMaps)
|
||||
stackTrace = convertStackTrace(convertedLines.join('\n'), sourceMaps)
|
||||
lines = stackTrace.split('\n')
|
||||
|
||||
# Remove first line of stack when it is the same as the error message
|
||||
errorMatch = lines[0]?.match(/^Error: (.*)/)
|
||||
lines.shift() if message.trim() is errorMatch?[1]?.trim()
|
||||
|
||||
# Remove prefix of lines matching: at [object Object].<anonymous> (path:1:2)
|
||||
for line, index in lines
|
||||
prefixMatch = line.match(/at \[object Object\]\.<anonymous> \(([^\)]+)\)/)
|
||||
lines[index] = "at #{prefixMatch[1]}" if prefixMatch
|
||||
|
||||
lines = lines.map (line) -> line.trim()
|
||||
lines.join('\n')
|
||||
|
||||
module.exports =
|
||||
class AtomReporter extends View
|
||||
@content: ->
|
||||
@div id: 'HTMLReporter', class: 'jasmine_reporter', =>
|
||||
@div outlet: 'specPopup', class: "spec-popup"
|
||||
@div class: 'spec-reporter', =>
|
||||
@div outlet: "suites"
|
||||
@div outlet: 'coreArea', =>
|
||||
@div outlet: 'coreHeader', class: 'symbolHeader'
|
||||
@ul outlet: 'coreSummary', class: 'symbolSummary list-unstyled'
|
||||
@div outlet: 'bundledArea', =>
|
||||
@div outlet: 'bundledHeader', class: 'symbolHeader'
|
||||
@ul outlet: 'bundledSummary', class: 'symbolSummary list-unstyled'
|
||||
@div outlet: 'userArea', =>
|
||||
@div outlet: 'userHeader', class: 'symbolHeader'
|
||||
@ul outlet: 'userSummary', class: 'symbolSummary list-unstyled'
|
||||
@div outlet: "status", class: 'status', =>
|
||||
@div outlet: 'coreArea', class: 'symbol-area', =>
|
||||
@div outlet: 'coreHeader', class: 'symbol-header'
|
||||
@ul outlet: 'coreSummary', class: 'symbol-summary list-unstyled'
|
||||
@div outlet: 'bundledArea', class: 'symbol-area', =>
|
||||
@div outlet: 'bundledHeader', class: 'symbol-header'
|
||||
@ul outlet: 'bundledSummary', class: 'symbol-summary list-unstyled'
|
||||
@div outlet: 'userArea', class: 'symbol-area', =>
|
||||
@div outlet: 'userHeader', class: 'symbol-header'
|
||||
@ul outlet: 'userSummary', class: 'symbol-summary list-unstyled'
|
||||
@div outlet: "status", class: 'status alert alert-info', =>
|
||||
@div outlet: "time", class: 'time'
|
||||
@div outlet: "specCount", class: 'spec-count'
|
||||
@div outlet: "message", class: 'message'
|
||||
@@ -45,7 +60,7 @@ class AtomReporter extends View
|
||||
|
||||
reportRunnerStarting: (runner) ->
|
||||
@handleEvents()
|
||||
@startedAt = new Date()
|
||||
@startedAt = Date.now()
|
||||
specs = runner.specs()
|
||||
@totalSpecCount = specs.length
|
||||
@addSpecs(specs)
|
||||
@@ -53,57 +68,29 @@ class AtomReporter extends View
|
||||
|
||||
reportRunnerResults: (runner) ->
|
||||
@updateSpecCounts()
|
||||
if @failedCount == 0
|
||||
@message.text "Success!"
|
||||
@status.addClass('alert-success').removeClass('alert-info') if @failedCount is 0
|
||||
if @failedCount is 1
|
||||
@message.text "#{@failedCount} failure"
|
||||
else
|
||||
@message.text "Game Over"
|
||||
@message.text "#{@failedCount} failures"
|
||||
|
||||
reportSuiteResults: (suite) ->
|
||||
|
||||
reportSpecResults: (spec) ->
|
||||
@completeSpecCount++
|
||||
spec.endedAt = new Date().getTime()
|
||||
spec.endedAt = Date.now()
|
||||
@specComplete(spec)
|
||||
@updateStatusView(spec)
|
||||
|
||||
reportSpecStarting: (spec) ->
|
||||
@specStarted(spec)
|
||||
|
||||
specFilter: (spec) ->
|
||||
globalFocusPriority = jasmine.getEnv().focusPriority
|
||||
parent = spec.parentSuite ? spec.suite
|
||||
|
||||
if !globalFocusPriority
|
||||
true
|
||||
else if spec.focusPriority >= globalFocusPriority
|
||||
true
|
||||
else if not parent
|
||||
false
|
||||
else
|
||||
@specFilter(parent)
|
||||
|
||||
handleEvents: ->
|
||||
$(document).on "mouseover", ".spec-summary", ({currentTarget}) =>
|
||||
element = $(currentTarget)
|
||||
description = element.data("description")
|
||||
return unless description
|
||||
|
||||
clearTimeout @timeoutId if @timeoutId?
|
||||
@specPopup.show()
|
||||
spec = _.find(window.timedSpecs, ({fullName}) -> description is fullName)
|
||||
description = "#{description} #{spec.time}ms" if spec
|
||||
@specPopup.text description
|
||||
{left, top} = element.offset()
|
||||
left += 20
|
||||
top += 20
|
||||
@specPopup.offset({left, top})
|
||||
@timeoutId = setTimeout((=> @specPopup.hide()), 3000)
|
||||
|
||||
$(document).on "click", ".spec-toggle", ({currentTarget}) =>
|
||||
element = $(currentTarget)
|
||||
specFailures = element.parent().find('.spec-failures')
|
||||
specFailures.toggle()
|
||||
if specFailures.is(":visible") then element.text "\uf03d" else element.html "\uf03f"
|
||||
element.toggleClass('folded')
|
||||
false
|
||||
|
||||
updateSpecCounts: ->
|
||||
@@ -115,7 +102,7 @@ class AtomReporter extends View
|
||||
|
||||
updateStatusView: (spec) ->
|
||||
if @failedCount > 0
|
||||
@status.addClass('failed') unless @status.hasClass('failed')
|
||||
@status.addClass('alert-danger').removeClass('alert-info')
|
||||
|
||||
@updateSpecCounts()
|
||||
|
||||
@@ -123,7 +110,7 @@ class AtomReporter extends View
|
||||
rootSuite = rootSuite.parentSuite while rootSuite.parentSuite
|
||||
@message.text rootSuite.description
|
||||
|
||||
time = "#{Math.round((spec.endedAt - @startedAt.getTime()) / 10)}"
|
||||
time = "#{Math.round((spec.endedAt - @startedAt) / 10)}"
|
||||
time = "0#{time}" if time.length < 3
|
||||
@time[0].textContent = "#{time[0...-2]}.#{time[-2..]}s"
|
||||
|
||||
@@ -145,15 +132,22 @@ class AtomReporter extends View
|
||||
@userSummary.append symbol
|
||||
|
||||
if coreSpecs > 0
|
||||
@coreHeader.text("Core Specs (#{coreSpecs}):")
|
||||
@coreHeader.text("Core Specs (#{coreSpecs})")
|
||||
else
|
||||
@coreArea.hide()
|
||||
if bundledPackageSpecs > 0
|
||||
@bundledHeader.text("Bundled Package Specs (#{bundledPackageSpecs}):")
|
||||
@bundledHeader.text("Bundled Package Specs (#{bundledPackageSpecs})")
|
||||
else
|
||||
@bundledArea.hide()
|
||||
if userPackageSpecs > 0
|
||||
@userHeader.text("User Package Specs (#{userPackageSpecs}):")
|
||||
if coreSpecs is 0 and bundledPackageSpecs is 0
|
||||
# Package specs being run, show a more descriptive label
|
||||
{specDirectory} = specs[0]
|
||||
packageFolderName = path.basename(path.dirname(specDirectory))
|
||||
packageName = _.undasherize(_.uncamelcase(packageFolderName))
|
||||
@userHeader.text("#{packageName} Specs")
|
||||
else
|
||||
@userHeader.text("User Package Specs (#{userPackageSpecs})")
|
||||
else
|
||||
@userArea.hide()
|
||||
|
||||
@@ -163,7 +157,7 @@ class AtomReporter extends View
|
||||
specComplete: (spec) ->
|
||||
specSummaryElement = $("#spec-summary-#{spec.id}")
|
||||
specSummaryElement.removeClass('pending')
|
||||
specSummaryElement.data("description", spec.getFullName())
|
||||
specSummaryElement.setTooltip(title: spec.getFullName(), container: '.spec-reporter')
|
||||
|
||||
results = spec.results()
|
||||
if results.skipped
|
||||
@@ -184,11 +178,9 @@ class SuiteResultView extends View
|
||||
@div class: 'suite', =>
|
||||
@div outlet: 'description', class: 'description'
|
||||
|
||||
suite: null
|
||||
|
||||
initialize: (@suite) ->
|
||||
@attr('id', "suite-view-#{@suite.id}")
|
||||
@description.html @suite.description
|
||||
@description.text(@suite.description)
|
||||
|
||||
attach: ->
|
||||
(@parentSuiteView() or $('.results')).append this
|
||||
@@ -205,20 +197,22 @@ class SuiteResultView extends View
|
||||
class SpecResultView extends View
|
||||
@content: ->
|
||||
@div class: 'spec', =>
|
||||
@div "\uf03d", class: 'spec-toggle'
|
||||
@div class: 'spec-toggle'
|
||||
@div outlet: 'description', class: 'description'
|
||||
@div outlet: 'specFailures', class: 'spec-failures'
|
||||
spec: null
|
||||
|
||||
initialize: (@spec) ->
|
||||
@addClass("spec-view-#{@spec.id}")
|
||||
@description.text @spec.description
|
||||
|
||||
description = @spec.description
|
||||
description = "it #{description}" if description.indexOf('it ') isnt 0
|
||||
@description.text(description)
|
||||
|
||||
for result in @spec.results().getItems() when not result.passed()
|
||||
stackTrace = formatStackTrace(result.trace.stack)
|
||||
stackTrace = formatStackTrace(result.message, result.trace.stack)
|
||||
@specFailures.append $$ ->
|
||||
@div result.message, class: 'resultMessage fail'
|
||||
@div stackTrace, class: 'stackTrace' if stackTrace
|
||||
@div result.message, class: 'result-message fail'
|
||||
@pre stackTrace, class: 'stack-trace padded' if stackTrace
|
||||
|
||||
attach: ->
|
||||
@parentSuiteView().append this
|
||||
|
||||
@@ -10,25 +10,14 @@ describe "the `atom` global", ->
|
||||
|
||||
describe "package lifecycle methods", ->
|
||||
describe ".loadPackage(name)", ->
|
||||
describe "when the package has deferred deserializers", ->
|
||||
it "requires the package's main module if one of its deferred deserializers is referenced", ->
|
||||
pack = atom.packages.loadPackage('package-with-activation-events')
|
||||
spyOn(pack, 'activateStylesheets').andCallThrough()
|
||||
expect(pack.mainModule).toBeNull()
|
||||
object = atom.deserializers.deserialize({deserializer: 'Foo', data: 5})
|
||||
expect(pack.mainModule).toBeDefined()
|
||||
expect(object.constructor.name).toBe 'Foo'
|
||||
expect(object.data).toBe 5
|
||||
expect(pack.activateStylesheets).toHaveBeenCalled()
|
||||
it "continues if the package has an invalid package.json", ->
|
||||
spyOn(console, 'warn')
|
||||
atom.config.set("core.disabledPackages", [])
|
||||
expect(-> atom.packages.loadPackage("package-with-broken-package-json")).not.toThrow()
|
||||
|
||||
it "continues if the package has an invalid package.json", ->
|
||||
spyOn(console, 'warn')
|
||||
atom.config.set("core.disabledPackages", [])
|
||||
expect(-> atom.packages.loadPackage("package-with-broken-package-json")).not.toThrow()
|
||||
|
||||
it "continues if the package has an invalid keymap", ->
|
||||
atom.config.set("core.disabledPackages", [])
|
||||
expect(-> atom.packages.loadPackage("package-with-broken-keymap")).not.toThrow()
|
||||
it "continues if the package has an invalid keymap", ->
|
||||
atom.config.set("core.disabledPackages", [])
|
||||
expect(-> atom.packages.loadPackage("package-with-broken-keymap")).not.toThrow()
|
||||
|
||||
describe ".unloadPackage(name)", ->
|
||||
describe "when the package is active", ->
|
||||
@@ -355,12 +344,18 @@ describe "the `atom` global", ->
|
||||
|
||||
it "absorbs exceptions that are thrown by the package module's serialize methods", ->
|
||||
spyOn(console, 'error')
|
||||
atom.packages.activatePackage('package-with-serialize-error', immediate: true)
|
||||
atom.packages.activatePackage('package-with-serialization', immediate: true)
|
||||
atom.packages.deactivatePackages()
|
||||
expect(atom.packages.packageStates['package-with-serialize-error']).toBeUndefined()
|
||||
expect(atom.packages.packageStates['package-with-serialization']).toEqual someNumber: 1
|
||||
expect(console.error).toHaveBeenCalled()
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('package-with-serialize-error')
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('package-with-serialization')
|
||||
|
||||
runs ->
|
||||
atom.packages.deactivatePackages()
|
||||
expect(atom.packages.packageStates['package-with-serialize-error']).toBeUndefined()
|
||||
expect(atom.packages.packageStates['package-with-serialization']).toEqual someNumber: 1
|
||||
expect(console.error).toHaveBeenCalled()
|
||||
|
||||
it "removes the package's grammars", ->
|
||||
waitsForPromise ->
|
||||
@@ -405,15 +400,22 @@ describe "the `atom` global", ->
|
||||
describe "textmate packages", ->
|
||||
it "removes the package's grammars", ->
|
||||
expect(atom.syntax.selectGrammar("file.rb").name).toBe "Null Grammar"
|
||||
atom.packages.activatePackage('language-ruby', sync: true)
|
||||
expect(atom.syntax.selectGrammar("file.rb").name).toBe "Ruby"
|
||||
atom.packages.deactivatePackage('language-ruby')
|
||||
expect(atom.syntax.selectGrammar("file.rb").name).toBe "Null Grammar"
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-ruby')
|
||||
|
||||
runs ->
|
||||
expect(atom.syntax.selectGrammar("file.rb").name).toBe "Ruby"
|
||||
atom.packages.deactivatePackage('language-ruby')
|
||||
expect(atom.syntax.selectGrammar("file.rb").name).toBe "Null Grammar"
|
||||
|
||||
it "removes the package's scoped properties", ->
|
||||
atom.packages.activatePackage('language-ruby', sync: true)
|
||||
atom.packages.deactivatePackage('language-ruby')
|
||||
expect(atom.syntax.getProperty(['.source.ruby'], 'editor.commentStart')).toBeUndefined()
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-ruby')
|
||||
|
||||
runs ->
|
||||
atom.packages.deactivatePackage('language-ruby')
|
||||
expect(atom.syntax.getProperty(['.source.ruby'], 'editor.commentStart')).toBeUndefined()
|
||||
|
||||
describe ".activate()", ->
|
||||
packageActivator = null
|
||||
|
||||
@@ -63,6 +63,19 @@ describe "Config", ->
|
||||
atom.config.toggle('foo.a')
|
||||
expect(atom.config.get('foo.a')).toBe false
|
||||
|
||||
describe ".restoreDefault(keyPath)", ->
|
||||
it "sets the value of the key path to its default", ->
|
||||
atom.config.setDefaults('a', b: 3)
|
||||
atom.config.set('a.b', 4)
|
||||
expect(atom.config.get('a.b')).toBe 4
|
||||
atom.config.restoreDefault('a.b')
|
||||
expect(atom.config.get('a.b')).toBe 3
|
||||
|
||||
atom.config.set('a.c', 5)
|
||||
expect(atom.config.get('a.c')).toBe 5
|
||||
atom.config.restoreDefault('a.c')
|
||||
expect(atom.config.get('a.c')).toBeUndefined()
|
||||
|
||||
describe ".pushAtKeyPath(keyPath, value)", ->
|
||||
it "pushes the given value to the array at the key path and updates observers", ->
|
||||
atom.config.set("foo.bar.baz", ["a"])
|
||||
|
||||
@@ -5,12 +5,15 @@ describe "DisplayBuffer", ->
|
||||
[displayBuffer, buffer, changeHandler, tabLength] = []
|
||||
beforeEach ->
|
||||
tabLength = 2
|
||||
atom.packages.activatePackage('language-javascript', sync: true)
|
||||
|
||||
buffer = atom.project.bufferForPathSync('sample.js')
|
||||
displayBuffer = new DisplayBuffer({buffer, tabLength})
|
||||
changeHandler = jasmine.createSpy 'changeHandler'
|
||||
displayBuffer.on 'changed', changeHandler
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-javascript')
|
||||
|
||||
afterEach ->
|
||||
displayBuffer.destroy()
|
||||
buffer.release()
|
||||
|
||||
@@ -16,11 +16,13 @@ describe "Editor", ->
|
||||
|
||||
describe "with default options", ->
|
||||
beforeEach ->
|
||||
atom.packages.activatePackage('language-javascript', sync: true)
|
||||
editor = atom.project.openSync('sample.js', autoIndent: false)
|
||||
buffer = editor.buffer
|
||||
lineLengths = buffer.getLines().map (line) -> line.length
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-javascript')
|
||||
|
||||
describe "when the editor is deserialized", ->
|
||||
it "restores selections and folds based on markers in the buffer", ->
|
||||
editor.setSelectedBufferRange([[1, 2], [3, 4]])
|
||||
@@ -2733,19 +2735,26 @@ describe "Editor", ->
|
||||
|
||||
describe "when the editor's grammar has an injection selector", ->
|
||||
beforeEach ->
|
||||
atom.packages.activatePackage('language-text', sync: true)
|
||||
atom.packages.activatePackage('language-javascript', sync: true)
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-text')
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-javascript')
|
||||
|
||||
it "includes the grammar's patterns when the selector matches the current scope in other grammars", ->
|
||||
atom.packages.activatePackage('language-hyperlink', sync: true)
|
||||
grammar = atom.syntax.selectGrammar("text.js")
|
||||
{tokens} = grammar.tokenizeLine("var i; // http://github.com")
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-hyperlink')
|
||||
|
||||
expect(tokens[0].value).toBe "var"
|
||||
expect(tokens[0].scopes).toEqual ["source.js", "storage.modifier.js"]
|
||||
runs ->
|
||||
grammar = atom.syntax.selectGrammar("text.js")
|
||||
{tokens} = grammar.tokenizeLine("var i; // http://github.com")
|
||||
|
||||
expect(tokens[6].value).toBe "http://github.com"
|
||||
expect(tokens[6].scopes).toEqual ["source.js", "comment.line.double-slash.js", "markup.underline.link.http.hyperlink"]
|
||||
expect(tokens[0].value).toBe "var"
|
||||
expect(tokens[0].scopes).toEqual ["source.js", "storage.modifier.js"]
|
||||
|
||||
expect(tokens[6].value).toBe "http://github.com"
|
||||
expect(tokens[6].scopes).toEqual ["source.js", "comment.line.double-slash.js", "markup.underline.link.http.hyperlink"]
|
||||
|
||||
describe "when the grammar is added", ->
|
||||
it "retokenizes existing buffers that contain tokens that match the injection selector", ->
|
||||
@@ -2756,11 +2765,13 @@ describe "Editor", ->
|
||||
expect(tokens[1].value).toBe " http://github.com"
|
||||
expect(tokens[1].scopes).toEqual ["source.js", "comment.line.double-slash.js"]
|
||||
|
||||
atom.packages.activatePackage('language-hyperlink', sync: true)
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-hyperlink')
|
||||
|
||||
{tokens} = editor.lineForScreenRow(0)
|
||||
expect(tokens[2].value).toBe "http://github.com"
|
||||
expect(tokens[2].scopes).toEqual ["source.js", "comment.line.double-slash.js", "markup.underline.link.http.hyperlink"]
|
||||
runs ->
|
||||
{tokens} = editor.lineForScreenRow(0)
|
||||
expect(tokens[2].value).toBe "http://github.com"
|
||||
expect(tokens[2].scopes).toEqual ["source.js", "comment.line.double-slash.js", "markup.underline.link.http.hyperlink"]
|
||||
|
||||
describe "when the grammar is updated", ->
|
||||
it "retokenizes existing buffers that contain tokens that match the injection selector", ->
|
||||
@@ -2771,14 +2782,17 @@ describe "Editor", ->
|
||||
expect(tokens[1].value).toBe " SELECT * FROM OCTOCATS"
|
||||
expect(tokens[1].scopes).toEqual ["source.js", "comment.line.double-slash.js"]
|
||||
|
||||
atom.packages.activatePackage('package-with-injection-selector', sync: true)
|
||||
|
||||
atom.packages.activatePackage('package-with-injection-selector')
|
||||
|
||||
{tokens} = editor.lineForScreenRow(0)
|
||||
expect(tokens[1].value).toBe " SELECT * FROM OCTOCATS"
|
||||
expect(tokens[1].scopes).toEqual ["source.js", "comment.line.double-slash.js"]
|
||||
|
||||
atom.packages.activatePackage('language-sql', sync: true)
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-sql')
|
||||
|
||||
{tokens} = editor.lineForScreenRow(0)
|
||||
expect(tokens[2].value).toBe "SELECT"
|
||||
expect(tokens[2].scopes).toEqual ["source.js", "comment.line.double-slash.js", "keyword.other.DML.sql"]
|
||||
runs ->
|
||||
{tokens} = editor.lineForScreenRow(0)
|
||||
expect(tokens[2].value).toBe "SELECT"
|
||||
expect(tokens[2].scopes).toEqual ["source.js", "comment.line.double-slash.js", "keyword.other.DML.sql"]
|
||||
|
||||
@@ -10,8 +10,6 @@ describe "EditorView", ->
|
||||
[buffer, editorView, editor, cachedLineHeight, cachedCharWidth] = []
|
||||
|
||||
beforeEach ->
|
||||
atom.packages.activatePackage('language-text', sync: true)
|
||||
atom.packages.activatePackage('language-javascript', sync: true)
|
||||
editor = atom.project.openSync('sample.js')
|
||||
buffer = editor.buffer
|
||||
editorView = new EditorView(editor)
|
||||
@@ -26,6 +24,12 @@ describe "EditorView", ->
|
||||
@width(getCharWidth() * widthInChars) if widthInChars
|
||||
$('#jasmine-content').append(this)
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-text', sync: true)
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-javascript', sync: true)
|
||||
|
||||
getLineHeight = ->
|
||||
return cachedLineHeight if cachedLineHeight?
|
||||
calcDimensions()
|
||||
@@ -2532,6 +2536,52 @@ describe "EditorView", ->
|
||||
editorView.trigger 'editor:move-line-up'
|
||||
expect(editor.getCursorBufferPosition()).toEqual [0,2]
|
||||
|
||||
describe "when the line above is folded", ->
|
||||
it "moves the line around the fold", ->
|
||||
editor.foldBufferRow(1)
|
||||
editor.setCursorBufferPosition([10, 0])
|
||||
editorView.trigger 'editor:move-line-up'
|
||||
|
||||
expect(editor.getCursorBufferPosition()).toEqual [1, 0]
|
||||
expect(buffer.lineForRow(1)).toBe ''
|
||||
expect(buffer.lineForRow(2)).toBe ' var sort = function(items) {'
|
||||
expect(editor.isFoldedAtBufferRow(1)).toBe false
|
||||
expect(editor.isFoldedAtBufferRow(2)).toBe true
|
||||
|
||||
describe "when the line being moved is folded", ->
|
||||
it "moves the fold around the fold above it", ->
|
||||
editor.setCursorBufferPosition([0, 0])
|
||||
editor.insertText """
|
||||
var a = function() {
|
||||
b = 3;
|
||||
};
|
||||
|
||||
"""
|
||||
editor.foldBufferRow(0)
|
||||
editor.foldBufferRow(3)
|
||||
editor.setCursorBufferPosition([3, 0])
|
||||
editorView.trigger 'editor:move-line-up'
|
||||
|
||||
expect(editor.getCursorBufferPosition()).toEqual [0, 0]
|
||||
expect(buffer.lineForRow(0)).toBe 'var quicksort = function () {'
|
||||
expect(buffer.lineForRow(13)).toBe 'var a = function() {'
|
||||
editor.logScreenLines()
|
||||
expect(editor.isFoldedAtBufferRow(0)).toBe true
|
||||
expect(editor.isFoldedAtBufferRow(13)).toBe true
|
||||
|
||||
describe "when the line above is empty and the line above that is folded", ->
|
||||
it "moves the line to the empty line", ->
|
||||
editor.foldBufferRow(2)
|
||||
editor.setCursorBufferPosition([11, 0])
|
||||
editorView.trigger 'editor:move-line-up'
|
||||
|
||||
expect(editor.getCursorBufferPosition()).toEqual [10, 0]
|
||||
expect(buffer.lineForRow(9)).toBe ' };'
|
||||
expect(buffer.lineForRow(10)).toBe ' return sort(Array.apply(this, arguments));'
|
||||
expect(buffer.lineForRow(11)).toBe ''
|
||||
expect(editor.isFoldedAtBufferRow(2)).toBe true
|
||||
expect(editor.isFoldedAtBufferRow(10)).toBe false
|
||||
|
||||
describe "where there is a selection", ->
|
||||
describe "when the selection falls inside the line", ->
|
||||
it "maintains the selection", ->
|
||||
@@ -2631,6 +2681,54 @@ describe "EditorView", ->
|
||||
editorView.trigger 'editor:move-line-down'
|
||||
expect(editor.getCursorBufferPosition()).toEqual [1, 2]
|
||||
|
||||
describe "when the line below is folded", ->
|
||||
it "moves the line around the fold", ->
|
||||
editor.setCursorBufferPosition([0, 0])
|
||||
editor.foldBufferRow(1)
|
||||
editorView.trigger 'editor:move-line-down'
|
||||
|
||||
expect(editor.getCursorBufferPosition()).toEqual [9, 0]
|
||||
expect(buffer.lineForRow(0)).toBe ' var sort = function(items) {'
|
||||
expect(buffer.lineForRow(9)).toBe 'var quicksort = function () {'
|
||||
expect(editor.isFoldedAtBufferRow(0)).toBe true
|
||||
expect(editor.isFoldedAtBufferRow(9)).toBe false
|
||||
|
||||
describe "when the line being moved is folded", ->
|
||||
it "moves the fold around the fold below it", ->
|
||||
editor.setCursorBufferPosition([0, 0])
|
||||
editor.insertText """
|
||||
var a = function() {
|
||||
b = 3;
|
||||
};
|
||||
|
||||
"""
|
||||
editor.foldBufferRow(0)
|
||||
editor.foldBufferRow(3)
|
||||
editor.setCursorBufferPosition([0, 0])
|
||||
editorView.trigger 'editor:move-line-down'
|
||||
|
||||
expect(editor.getCursorBufferPosition()).toEqual [13, 0]
|
||||
expect(buffer.lineForRow(0)).toBe 'var quicksort = function () {'
|
||||
expect(buffer.lineForRow(13)).toBe 'var a = function() {'
|
||||
expect(editor.isFoldedAtBufferRow(0)).toBe true
|
||||
expect(editor.isFoldedAtBufferRow(13)).toBe true
|
||||
|
||||
describe "when the line below is empty and the line below that is folded", ->
|
||||
it "moves the line to the empty line", ->
|
||||
editor.setCursorBufferPosition([0, Infinity])
|
||||
editor.insertText('\n')
|
||||
editor.setCursorBufferPosition([0, 0])
|
||||
editor.foldBufferRow(2)
|
||||
editorView.trigger 'editor:move-line-down'
|
||||
|
||||
expect(editor.getCursorBufferPosition()).toEqual [1, 0]
|
||||
expect(buffer.lineForRow(0)).toBe ''
|
||||
expect(buffer.lineForRow(1)).toBe 'var quicksort = function () {'
|
||||
expect(buffer.lineForRow(2)).toBe ' var sort = function(items) {'
|
||||
expect(editor.isFoldedAtBufferRow(0)).toBe false
|
||||
expect(editor.isFoldedAtBufferRow(1)).toBe false
|
||||
expect(editor.isFoldedAtBufferRow(2)).toBe true
|
||||
|
||||
describe "when the cursor is on the last line", ->
|
||||
it "does not move the line", ->
|
||||
editor.moveCursorToBottom()
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
'activationEvents': ['activation-event']
|
||||
'deferredDeserializers': ['Foo']
|
||||
|
||||
@@ -1,5 +1 @@
|
||||
# This package loads async, otherwise it would log errors when it
|
||||
# is automatically serialized when workspaceView is deactivatated
|
||||
|
||||
'main': 'index.coffee'
|
||||
'activationEvents': ['activation-event']
|
||||
|
||||
@@ -6,10 +6,12 @@ describe "LanguageMode", ->
|
||||
|
||||
describe "javascript", ->
|
||||
beforeEach ->
|
||||
atom.packages.activatePackage('language-javascript', sync: true)
|
||||
editor = atom.project.openSync('sample.js', autoIndent: false)
|
||||
{buffer, languageMode} = editor
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-javascript')
|
||||
|
||||
describe ".minIndentLevelForRowRange(startRow, endRow)", ->
|
||||
it "returns the minimum indent level for the given row range", ->
|
||||
expect(languageMode.minIndentLevelForRowRange(4, 7)).toBe 2
|
||||
@@ -100,10 +102,12 @@ describe "LanguageMode", ->
|
||||
|
||||
describe "coffeescript", ->
|
||||
beforeEach ->
|
||||
atom.packages.activatePackage('language-coffee-script', sync: true)
|
||||
editor = atom.project.openSync('coffee.coffee', autoIndent: false)
|
||||
{buffer, languageMode} = editor
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-coffee-script')
|
||||
|
||||
describe ".toggleLineCommentsForBufferRows(start, end)", ->
|
||||
it "comments/uncomments lines in the given range", ->
|
||||
languageMode.toggleLineCommentsForBufferRows(4, 6)
|
||||
@@ -147,10 +151,12 @@ describe "LanguageMode", ->
|
||||
|
||||
describe "css", ->
|
||||
beforeEach ->
|
||||
atom.packages.activatePackage('language-css', sync: true)
|
||||
editor = atom.project.openSync('css.css', autoIndent: false)
|
||||
{buffer, languageMode} = editor
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-css')
|
||||
|
||||
describe ".toggleLineCommentsForBufferRows(start, end)", ->
|
||||
it "comments/uncomments lines in the given range", ->
|
||||
languageMode.toggleLineCommentsForBufferRows(0, 1)
|
||||
@@ -188,11 +194,15 @@ describe "LanguageMode", ->
|
||||
|
||||
describe "less", ->
|
||||
beforeEach ->
|
||||
atom.packages.activatePackage('language-less', sync: true)
|
||||
atom.packages.activatePackage('language-css', sync: true)
|
||||
editor = atom.project.openSync('sample.less', autoIndent: false)
|
||||
{buffer, languageMode} = editor
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-less')
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-css')
|
||||
|
||||
describe "when commenting lines", ->
|
||||
it "only uses the `commentEnd` pattern if it comes from the same grammar as the `commentStart`", ->
|
||||
languageMode.toggleLineCommentsForBufferRows(0, 0)
|
||||
@@ -200,10 +210,12 @@ describe "LanguageMode", ->
|
||||
|
||||
describe "folding", ->
|
||||
beforeEach ->
|
||||
atom.packages.activatePackage('language-javascript', sync: true)
|
||||
editor = atom.project.openSync('sample.js', autoIndent: false)
|
||||
{buffer, languageMode} = editor
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-javascript')
|
||||
|
||||
it "maintains cursor buffer position when a folding/unfolding", ->
|
||||
editor.setCursorBufferPosition([5,5])
|
||||
languageMode.foldAll()
|
||||
@@ -298,10 +310,12 @@ describe "LanguageMode", ->
|
||||
|
||||
describe "folding with comments", ->
|
||||
beforeEach ->
|
||||
atom.packages.activatePackage('language-javascript', sync: true)
|
||||
editor = atom.project.openSync('sample-with-comments.js', autoIndent: false)
|
||||
{buffer, languageMode} = editor
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-javascript')
|
||||
|
||||
describe ".unfoldAll()", ->
|
||||
it "unfolds every folded line", ->
|
||||
initialScreenLineCount = editor.getScreenLineCount()
|
||||
@@ -362,10 +376,12 @@ describe "LanguageMode", ->
|
||||
|
||||
describe "css", ->
|
||||
beforeEach ->
|
||||
atom.packages.activatePackage('language-source', sync: true)
|
||||
atom.packages.activatePackage('language-css', sync: true)
|
||||
editor = atom.project.openSync('css.css', autoIndent: true)
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-source')
|
||||
atom.packages.activatePackage('language-css')
|
||||
|
||||
describe "suggestedIndentForBufferRow", ->
|
||||
it "does not return negative values (regression)", ->
|
||||
editor.setText('.test {\npadding: 0;\n}')
|
||||
|
||||
@@ -159,6 +159,16 @@ addCustomMatchers = (spec) ->
|
||||
@message = -> return "Expected path '" + @actual + "'" + notText + " to exist."
|
||||
fs.existsSync(@actual)
|
||||
|
||||
toHaveFocus: ->
|
||||
notText = this.isNot and " not" or ""
|
||||
if not document.hasFocus()
|
||||
console.error "Specs will fail because the Dev Tools have focus. To fix this close the Dev Tools or click the spec runner."
|
||||
|
||||
@message = -> return "Expected element '" + @actual + "' or its descendants" + notText + " to have focus."
|
||||
element = @actual
|
||||
element = element.get(0) if element.jquery
|
||||
element.webkitMatchesSelector(":focus") or element.querySelector(":focus")
|
||||
|
||||
window.keyIdentifierForKey = (key) ->
|
||||
if key.length > 1 # named key
|
||||
key
|
||||
|
||||
@@ -4,10 +4,18 @@ temp = require 'temp'
|
||||
|
||||
describe "the `syntax` global", ->
|
||||
beforeEach ->
|
||||
atom.packages.activatePackage('language-text', sync: true)
|
||||
atom.packages.activatePackage('language-javascript', sync: true)
|
||||
atom.packages.activatePackage('language-coffee-script', sync: true)
|
||||
atom.packages.activatePackage('language-ruby', sync: true)
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-text')
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-javascript')
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-coffee-script')
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-ruby')
|
||||
|
||||
describe "serialization", ->
|
||||
it "remembers grammar overrides by path", ->
|
||||
@@ -20,29 +28,33 @@ describe "the `syntax` global", ->
|
||||
|
||||
describe ".selectGrammar(filePath)", ->
|
||||
it "can use the filePath to load the correct grammar based on the grammar's filetype", ->
|
||||
atom.packages.activatePackage('language-git', sync: true)
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-git')
|
||||
|
||||
expect(atom.syntax.selectGrammar("file.js").name).toBe "JavaScript" # based on extension (.js)
|
||||
expect(atom.syntax.selectGrammar(path.join(temp.dir, '.git', 'config')).name).toBe "Git Config" # based on end of the path (.git/config)
|
||||
expect(atom.syntax.selectGrammar("Rakefile").name).toBe "Ruby" # based on the file's basename (Rakefile)
|
||||
expect(atom.syntax.selectGrammar("curb").name).toBe "Null Grammar"
|
||||
expect(atom.syntax.selectGrammar("/hu.git/config").name).toBe "Null Grammar"
|
||||
runs ->
|
||||
expect(atom.syntax.selectGrammar("file.js").name).toBe "JavaScript" # based on extension (.js)
|
||||
expect(atom.syntax.selectGrammar(path.join(temp.dir, '.git', 'config')).name).toBe "Git Config" # based on end of the path (.git/config)
|
||||
expect(atom.syntax.selectGrammar("Rakefile").name).toBe "Ruby" # based on the file's basename (Rakefile)
|
||||
expect(atom.syntax.selectGrammar("curb").name).toBe "Null Grammar"
|
||||
expect(atom.syntax.selectGrammar("/hu.git/config").name).toBe "Null Grammar"
|
||||
|
||||
it "uses the filePath's shebang line if the grammar cannot be determined by the extension or basename", ->
|
||||
filePath = require.resolve("./fixtures/shebang")
|
||||
expect(atom.syntax.selectGrammar(filePath).name).toBe "Ruby"
|
||||
|
||||
it "uses the number of newlines in the first line regex to determine the number of lines to test against", ->
|
||||
atom.packages.activatePackage('language-property-list', sync: true)
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-property-list')
|
||||
|
||||
fileContent = "first-line\n<html>"
|
||||
expect(atom.syntax.selectGrammar("dummy.coffee", fileContent).name).toBe "CoffeeScript"
|
||||
runs ->
|
||||
fileContent = "first-line\n<html>"
|
||||
expect(atom.syntax.selectGrammar("dummy.coffee", fileContent).name).toBe "CoffeeScript"
|
||||
|
||||
fileContent = '<?xml version="1.0" encoding="UTF-8"?>'
|
||||
expect(atom.syntax.selectGrammar("grammar.tmLanguage", fileContent).name).toBe "Null Grammar"
|
||||
fileContent = '<?xml version="1.0" encoding="UTF-8"?>'
|
||||
expect(atom.syntax.selectGrammar("grammar.tmLanguage", fileContent).name).toBe "Null Grammar"
|
||||
|
||||
fileContent += '\n<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">'
|
||||
expect(atom.syntax.selectGrammar("grammar.tmLanguage", fileContent).name).toBe "Property List (XML)"
|
||||
fileContent += '\n<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">'
|
||||
expect(atom.syntax.selectGrammar("grammar.tmLanguage", fileContent).name).toBe "Property List (XML)"
|
||||
|
||||
it "doesn't read the file when the file contents are specified", ->
|
||||
filePath = require.resolve("./fixtures/shebang")
|
||||
|
||||
@@ -571,6 +571,23 @@ describe 'TextBuffer', ->
|
||||
saveBuffer.reload()
|
||||
expect(events).toEqual ['will-reload', 'reloaded']
|
||||
|
||||
it "no longer reports being in conflict", ->
|
||||
saveBuffer.setText('a')
|
||||
saveBuffer.save()
|
||||
saveBuffer.setText('ab')
|
||||
|
||||
fs.writeFileSync(saveBuffer.getPath(), 'c')
|
||||
conflictHandler = jasmine.createSpy('conflictHandler')
|
||||
saveBuffer.on 'contents-conflicted', conflictHandler
|
||||
|
||||
waitsFor ->
|
||||
conflictHandler.callCount > 0
|
||||
|
||||
runs ->
|
||||
expect(saveBuffer.isInConflict()).toBe true
|
||||
saveBuffer.save()
|
||||
expect(saveBuffer.isInConflict()).toBe false
|
||||
|
||||
describe "when the buffer has no path", ->
|
||||
it "throws an exception", ->
|
||||
saveBuffer = atom.project.bufferForPathSync(null)
|
||||
|
||||
@@ -5,11 +5,13 @@ describe "TokenizedBuffer", ->
|
||||
[tokenizedBuffer, buffer, changeHandler] = []
|
||||
|
||||
beforeEach ->
|
||||
atom.packages.activatePackage('language-javascript', sync: true)
|
||||
# enable async tokenization
|
||||
TokenizedBuffer.prototype.chunkSize = 5
|
||||
jasmine.unspy(TokenizedBuffer.prototype, 'tokenizeInBackground')
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-javascript')
|
||||
|
||||
startTokenizing = (tokenizedBuffer) ->
|
||||
tokenizedBuffer.setVisible(true)
|
||||
|
||||
@@ -311,10 +313,13 @@ describe "TokenizedBuffer", ->
|
||||
|
||||
describe "when the buffer contains hard-tabs", ->
|
||||
beforeEach ->
|
||||
atom.packages.activatePackage('language-coffee-script', sync: true)
|
||||
buffer = atom.project.bufferForPathSync('sample-with-tabs.coffee')
|
||||
tokenizedBuffer = new TokenizedBuffer({buffer})
|
||||
startTokenizing(tokenizedBuffer)
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-coffee-script')
|
||||
|
||||
runs ->
|
||||
buffer = atom.project.bufferForPathSync('sample-with-tabs.coffee')
|
||||
tokenizedBuffer = new TokenizedBuffer({buffer})
|
||||
startTokenizing(tokenizedBuffer)
|
||||
|
||||
afterEach ->
|
||||
tokenizedBuffer.destroy()
|
||||
@@ -341,14 +346,17 @@ describe "TokenizedBuffer", ->
|
||||
|
||||
describe "when the buffer contains surrogate pairs", ->
|
||||
beforeEach ->
|
||||
atom.packages.activatePackage('language-javascript', sync: true)
|
||||
buffer = atom.project.bufferForPathSync 'sample-with-pairs.js'
|
||||
buffer.setText """
|
||||
'abc\uD835\uDF97def'
|
||||
//\uD835\uDF97xyz
|
||||
"""
|
||||
tokenizedBuffer = new TokenizedBuffer({buffer})
|
||||
fullyTokenize(tokenizedBuffer)
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-javascript')
|
||||
|
||||
runs ->
|
||||
buffer = atom.project.bufferForPathSync 'sample-with-pairs.js'
|
||||
buffer.setText """
|
||||
'abc\uD835\uDF97def'
|
||||
//\uD835\uDF97xyz
|
||||
"""
|
||||
tokenizedBuffer = new TokenizedBuffer({buffer})
|
||||
fullyTokenize(tokenizedBuffer)
|
||||
|
||||
afterEach ->
|
||||
tokenizedBuffer.destroy()
|
||||
@@ -379,22 +387,30 @@ describe "TokenizedBuffer", ->
|
||||
|
||||
describe "when the grammar is updated because a grammar it includes is activated", ->
|
||||
it "retokenizes the buffer", ->
|
||||
atom.packages.activatePackage('language-ruby-on-rails', sync: true)
|
||||
atom.packages.activatePackage('language-ruby', sync: true)
|
||||
|
||||
buffer = atom.project.bufferForPathSync()
|
||||
buffer.setText "<div class='name'><%= User.find(2).full_name %></div>"
|
||||
tokenizedBuffer = new TokenizedBuffer({buffer})
|
||||
tokenizedBuffer.setGrammar(atom.syntax.selectGrammar('test.erb'))
|
||||
fullyTokenize(tokenizedBuffer)
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-ruby-on-rails')
|
||||
|
||||
{tokens} = tokenizedBuffer.lineForScreenRow(0)
|
||||
expect(tokens[0]).toEqual value: "<div class='name'>", scopes: ["text.html.ruby"]
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-ruby')
|
||||
|
||||
atom.packages.activatePackage('language-html', sync: true)
|
||||
fullyTokenize(tokenizedBuffer)
|
||||
{tokens} = tokenizedBuffer.lineForScreenRow(0)
|
||||
expect(tokens[0]).toEqual value: '<', scopes: ["text.html.ruby","meta.tag.block.any.html","punctuation.definition.tag.begin.html"]
|
||||
runs ->
|
||||
buffer = atom.project.bufferForPathSync()
|
||||
buffer.setText "<div class='name'><%= User.find(2).full_name %></div>"
|
||||
tokenizedBuffer = new TokenizedBuffer({buffer})
|
||||
tokenizedBuffer.setGrammar(atom.syntax.selectGrammar('test.erb'))
|
||||
fullyTokenize(tokenizedBuffer)
|
||||
|
||||
{tokens} = tokenizedBuffer.lineForScreenRow(0)
|
||||
expect(tokens[0]).toEqual value: "<div class='name'>", scopes: ["text.html.ruby"]
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-html')
|
||||
|
||||
runs ->
|
||||
fullyTokenize(tokenizedBuffer)
|
||||
{tokens} = tokenizedBuffer.lineForScreenRow(0)
|
||||
expect(tokens[0]).toEqual value: '<', scopes: ["text.html.ruby","meta.tag.block.any.html","punctuation.definition.tag.begin.html"]
|
||||
|
||||
describe ".tokenForPosition(position)", ->
|
||||
afterEach ->
|
||||
|
||||
@@ -7,49 +7,125 @@ describe "Workspace", ->
|
||||
atom.project.setPath(atom.project.resolve('dir'))
|
||||
workspace = new Workspace
|
||||
|
||||
describe "::open(uri)", ->
|
||||
describe "::open(uri, options)", ->
|
||||
beforeEach ->
|
||||
spyOn(workspace.activePane, 'activate')
|
||||
|
||||
describe "when called without a uri", ->
|
||||
it "adds and activates an empty editor on the active pane", ->
|
||||
editor = null
|
||||
waitsForPromise ->
|
||||
workspace.open().then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
expect(editor.getPath()).toBeUndefined()
|
||||
expect(workspace.activePane.items).toEqual [editor]
|
||||
expect(workspace.activePaneItem).toBe editor
|
||||
expect(workspace.activePane.activate).toHaveBeenCalled()
|
||||
|
||||
describe "when called with a uri", ->
|
||||
describe "when the active pane already has an editor for the given uri", ->
|
||||
it "activates the existing editor on the active pane", ->
|
||||
editor1 = workspace.openSync('a')
|
||||
editor2 = workspace.openSync('b')
|
||||
spyOn(workspace.activePane, 'activate').andCallThrough()
|
||||
|
||||
describe "when the 'searchAllPanes' option is false (default)", ->
|
||||
describe "when called without a uri", ->
|
||||
it "adds and activates an empty editor on the active pane", ->
|
||||
editor = null
|
||||
waitsForPromise ->
|
||||
workspace.open('a').then (o) -> editor = o
|
||||
workspace.open().then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
expect(editor).toBe editor1
|
||||
expect(workspace.activePaneItem).toBe editor
|
||||
expect(workspace.activePane.activate).toHaveBeenCalled()
|
||||
|
||||
describe "when the active pane does not have an editor for the given uri", ->
|
||||
it "adds and activates a new editor for the given path on the active pane", ->
|
||||
editor = null
|
||||
waitsForPromise ->
|
||||
workspace.open('a').then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
expect(editor.getUri()).toBe 'a'
|
||||
expect(workspace.activePaneItem).toBe editor
|
||||
expect(editor.getPath()).toBeUndefined()
|
||||
expect(workspace.activePane.items).toEqual [editor]
|
||||
expect(workspace.activePaneItem).toBe editor
|
||||
expect(workspace.activePane.activate).toHaveBeenCalled()
|
||||
|
||||
describe "when called with a uri", ->
|
||||
describe "when the active pane already has an editor for the given uri", ->
|
||||
it "activates the existing editor on the active pane", ->
|
||||
editor1 = workspace.openSync('a')
|
||||
editor2 = workspace.openSync('b')
|
||||
|
||||
editor = null
|
||||
waitsForPromise ->
|
||||
workspace.open('a').then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
expect(editor).toBe editor1
|
||||
expect(workspace.activePaneItem).toBe editor
|
||||
expect(workspace.activePane.activate).toHaveBeenCalled()
|
||||
|
||||
describe "when the active pane does not have an editor for the given uri", ->
|
||||
it "adds and activates a new editor for the given path on the active pane", ->
|
||||
editor = null
|
||||
waitsForPromise ->
|
||||
workspace.open('a').then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
expect(editor.getUri()).toBe 'a'
|
||||
expect(workspace.activePaneItem).toBe editor
|
||||
expect(workspace.activePane.items).toEqual [editor]
|
||||
expect(workspace.activePane.activate).toHaveBeenCalled()
|
||||
|
||||
describe "when the 'searchAllPanes' option is true", ->
|
||||
describe "when an editor for the given uri is already open on an inactive pane", ->
|
||||
it "activates the existing editor on the inactive pane, then activates that pane", ->
|
||||
editor1 = workspace.openSync('a')
|
||||
pane1 = workspace.activePane
|
||||
pane2 = workspace.activePane.splitRight()
|
||||
editor2 = workspace.openSync('b')
|
||||
expect(workspace.activePaneItem).toBe editor2
|
||||
|
||||
waitsForPromise ->
|
||||
workspace.open('a', searchAllPanes: true)
|
||||
|
||||
runs ->
|
||||
expect(workspace.activePane).toBe pane1
|
||||
expect(workspace.activePaneItem).toBe editor1
|
||||
|
||||
describe "when no editor for the given uri is open in any pane", ->
|
||||
it "opens an editor for the given uri in the active pane", ->
|
||||
editor = null
|
||||
waitsForPromise ->
|
||||
workspace.open('a', searchAllPanes: true).then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
expect(workspace.activePaneItem).toBe editor
|
||||
|
||||
describe "when the 'split' option is set", ->
|
||||
describe "when the 'split' option is 'left'", ->
|
||||
it "opens the editor in the leftmost pane of the current pane axis", ->
|
||||
pane1 = workspace.activePane
|
||||
pane2 = pane1.splitRight()
|
||||
expect(workspace.activePane).toBe pane2
|
||||
|
||||
editor = null
|
||||
waitsForPromise ->
|
||||
workspace.open('a', split: 'left').then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
expect(workspace.activePane).toBe pane1
|
||||
expect(pane1.items).toEqual [editor]
|
||||
expect(pane2.items).toEqual []
|
||||
|
||||
# Focus right pane and reopen the file on the left
|
||||
waitsForPromise ->
|
||||
pane2.focus()
|
||||
workspace.open('a', split: 'left').then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
expect(workspace.activePane).toBe pane1
|
||||
expect(pane1.items).toEqual [editor]
|
||||
expect(pane2.items).toEqual []
|
||||
|
||||
describe "when the 'split' option is 'right'", ->
|
||||
it "opens the editor in the rightmost pane of the current pane axis", ->
|
||||
editor = null
|
||||
pane1 = workspace.activePane
|
||||
pane2 = null
|
||||
waitsForPromise ->
|
||||
workspace.open('a', split: 'right').then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
pane2 = workspace.getPanes().filter((p) -> p != pane1)[0]
|
||||
expect(workspace.activePane).toBe pane2
|
||||
expect(pane1.items).toEqual []
|
||||
expect(pane2.items).toEqual [editor]
|
||||
|
||||
# Focus right pane and reopen the file on the right
|
||||
waitsForPromise ->
|
||||
pane1.focus()
|
||||
workspace.open('a', split: 'right').then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
expect(workspace.activePane).toBe pane2
|
||||
expect(pane1.items).toEqual []
|
||||
expect(pane2.items).toEqual [editor]
|
||||
|
||||
describe "::openSync(uri, options)", ->
|
||||
[activePane, initialItemCount] = []
|
||||
|
||||
@@ -92,61 +168,6 @@ describe "Workspace", ->
|
||||
workspace.openSync('b', activatePane: false)
|
||||
expect(activePane.activate).not.toHaveBeenCalled()
|
||||
|
||||
describe "::openSingletonSync(uri, options)", ->
|
||||
describe "when an editor for the given uri is already open on the active pane", ->
|
||||
it "activates the existing editor", ->
|
||||
editor1 = workspace.openSync('a')
|
||||
editor2 = workspace.openSync('b')
|
||||
expect(workspace.activePaneItem).toBe editor2
|
||||
workspace.openSingletonSync('a')
|
||||
expect(workspace.activePaneItem).toBe editor1
|
||||
|
||||
describe "when an editor for the given uri is already open on an inactive pane", ->
|
||||
it "activates the existing editor on the inactive pane, then activates that pane", ->
|
||||
editor1 = workspace.openSync('a')
|
||||
pane1 = workspace.activePane
|
||||
pane2 = workspace.activePane.splitRight()
|
||||
editor2 = workspace.openSync('b')
|
||||
expect(workspace.activePaneItem).toBe editor2
|
||||
workspace.openSingletonSync('a')
|
||||
expect(workspace.activePane).toBe pane1
|
||||
expect(workspace.activePaneItem).toBe editor1
|
||||
|
||||
describe "when no editor for the given uri is open in any pane", ->
|
||||
it "opens an editor for the given uri in the active pane", ->
|
||||
editor1 = workspace.openSingletonSync('a')
|
||||
expect(workspace.activePaneItem).toBe editor1
|
||||
|
||||
describe "when the 'split' option is 'left'", ->
|
||||
it "opens the editor in the leftmost pane of the current pane axis", ->
|
||||
pane1 = workspace.activePane
|
||||
pane2 = pane1.splitRight()
|
||||
expect(workspace.activePane).toBe pane2
|
||||
editor1 = workspace.openSingletonSync('a', split: 'left')
|
||||
expect(workspace.activePane).toBe pane1
|
||||
expect(pane1.items).toEqual [editor1]
|
||||
expect(pane2.items).toEqual []
|
||||
|
||||
describe "when the 'split' option is 'right'", ->
|
||||
describe "when the active pane is in a horizontal pane axis", ->
|
||||
it "activates the editor on the rightmost pane of the current pane axis", ->
|
||||
pane1 = workspace.activePane
|
||||
pane2 = pane1.splitRight()
|
||||
pane1.activate()
|
||||
editor1 = workspace.openSingletonSync('a', split: 'right')
|
||||
expect(workspace.activePane).toBe pane2
|
||||
expect(pane2.items).toEqual [editor1]
|
||||
expect(pane1.items).toEqual []
|
||||
|
||||
describe "when the active pane is not in a horizontal pane axis", ->
|
||||
it "splits the current pane to the right, then activates the editor on the right pane", ->
|
||||
pane1 = workspace.activePane
|
||||
editor1 = workspace.openSingletonSync('a', split: 'right')
|
||||
pane2 = workspace.activePane
|
||||
expect(workspace.paneContainer.root.children).toEqual [pane1, pane2]
|
||||
expect(pane2.items).toEqual [editor1]
|
||||
expect(pane1.items).toEqual []
|
||||
|
||||
describe "::reopenItemSync()", ->
|
||||
it "opens the uri associated with the last closed pane that isn't currently open", ->
|
||||
pane = workspace.activePane
|
||||
|
||||
@@ -43,11 +43,7 @@ class AtomPackage extends Package
|
||||
@loadStylesheets()
|
||||
@loadGrammars()
|
||||
@loadScopedProperties()
|
||||
|
||||
if @metadata.activationEvents?
|
||||
@registerDeferredDeserializers()
|
||||
else
|
||||
@requireMainModule()
|
||||
@requireMainModule() unless @metadata.activationEvents?
|
||||
|
||||
catch e
|
||||
console.warn "Failed to load package named '#{@name}'", e.stack ? e
|
||||
@@ -73,21 +69,6 @@ class AtomPackage extends Package
|
||||
|
||||
@activationDeferred.promise
|
||||
|
||||
# Deprecated
|
||||
activateSync: ({immediate}={}) ->
|
||||
@activateResources()
|
||||
if @metadata.activationEvents? and not immediate
|
||||
@subscribeToActivationEvents()
|
||||
else
|
||||
try
|
||||
@activateConfig()
|
||||
@activateStylesheets()
|
||||
if @requireMainModule()
|
||||
@mainModule.activate(atom.packages.getPackageState(@name) ? {})
|
||||
@mainActivated = true
|
||||
catch e
|
||||
console.warn "Failed to activate package named '#{@name}'", e.stack
|
||||
|
||||
activateNow: ->
|
||||
try
|
||||
@activateConfig()
|
||||
@@ -228,12 +209,6 @@ class AtomPackage extends Package
|
||||
path.join(@path, 'index')
|
||||
@mainModulePath = fs.resolveExtension(mainModulePath, ["", _.keys(require.extensions)...])
|
||||
|
||||
registerDeferredDeserializers: ->
|
||||
for deserializerName in @metadata.deferredDeserializers ? []
|
||||
atom.deserializers.addDeferred deserializerName, =>
|
||||
@activateStylesheets()
|
||||
@requireMainModule()
|
||||
|
||||
subscribeToActivationEvents: ->
|
||||
return unless @metadata.activationEvents?
|
||||
if _.isArray(@metadata.activationEvents)
|
||||
|
||||
@@ -150,6 +150,14 @@ class Config
|
||||
toggle: (keyPath) ->
|
||||
@set(keyPath, !@get(keyPath))
|
||||
|
||||
# Public: Restore the key path to its default value.
|
||||
#
|
||||
# keyPath - The {String} name of the key.
|
||||
#
|
||||
# Returns the new value.
|
||||
restoreDefault: (keyPath) ->
|
||||
@set(keyPath, _.valueForKeyPath(@defaultSettings, keyPath))
|
||||
|
||||
# Public: Push the value to the array at the key path.
|
||||
#
|
||||
# keyPath - The {String} key path.
|
||||
|
||||
@@ -16,7 +16,6 @@ module.exports =
|
||||
class DeserializerManager
|
||||
constructor: ->
|
||||
@deserializers = {}
|
||||
@deferredDeserializers = {}
|
||||
|
||||
# Public: Register the given class(es) as deserializers.
|
||||
#
|
||||
@@ -24,13 +23,6 @@ class DeserializerManager
|
||||
add: (classes...) ->
|
||||
@deserializers[klass.name] = klass for klass in classes
|
||||
|
||||
# Public: Add a deferred deserializer for the given class name.
|
||||
#
|
||||
# name - The {String} name of the deserializer.
|
||||
# fn - The {Function} that creates the deserializer.
|
||||
addDeferred: (name, fn) ->
|
||||
@deferredDeserializers[name] = fn
|
||||
|
||||
# Public: Remove the given class(es) as deserializers.
|
||||
#
|
||||
# classes - One or more classes to remove.
|
||||
@@ -59,8 +51,4 @@ class DeserializerManager
|
||||
return unless state?
|
||||
|
||||
name = state.get?('deserializer') ? state.deserializer
|
||||
if @deferredDeserializers[name]
|
||||
@deferredDeserializers[name]()
|
||||
delete @deferredDeserializers[name]
|
||||
|
||||
@deserializers[name]
|
||||
|
||||
@@ -26,6 +26,7 @@ module.exports =
|
||||
class EditorView extends View
|
||||
@characterWidthCache: {}
|
||||
@configDefaults:
|
||||
fontFamily: ''
|
||||
fontSize: 20
|
||||
showInvisibles: false
|
||||
showIndentGuide: false
|
||||
|
||||
@@ -621,7 +621,7 @@ class Editor extends Model
|
||||
largestFoldStartingAtScreenRow: (screenRow) ->
|
||||
@displayBuffer.largestFoldStartingAtScreenRow(screenRow)
|
||||
|
||||
# Public: Moves the selected line up one row.
|
||||
# Public: Moves the selected lines up one screen row.
|
||||
moveLineUp: ->
|
||||
selection = @getSelectedBufferRange()
|
||||
return if selection.start.row is 0
|
||||
@@ -633,29 +633,47 @@ class Editor extends Model
|
||||
rows = [selection.start.row..selection.end.row]
|
||||
if selection.start.row isnt selection.end.row and selection.end.column is 0
|
||||
rows.pop() unless @isFoldedAtBufferRow(selection.end.row)
|
||||
|
||||
# Move line around the fold that is directly above the selection
|
||||
precedingScreenRow = @screenPositionForBufferPosition([selection.start.row]).translate([-1])
|
||||
precedingBufferRow = @bufferPositionForScreenPosition(precedingScreenRow).row
|
||||
if fold = @largestFoldContainingBufferRow(precedingBufferRow)
|
||||
insertDelta = fold.getBufferRange().getRowCount()
|
||||
else
|
||||
insertDelta = 1
|
||||
|
||||
for row in rows
|
||||
screenRow = @screenPositionForBufferPosition([row]).row
|
||||
if @isFoldedAtScreenRow(screenRow)
|
||||
bufferRange = @bufferRangeForScreenRange([[screenRow], [screenRow + 1]])
|
||||
if fold = @displayBuffer.largestFoldStartingAtBufferRow(row)
|
||||
bufferRange = fold.getBufferRange()
|
||||
startRow = bufferRange.start.row
|
||||
endRow = bufferRange.end.row - 1
|
||||
foldedRows.push(endRow - 1)
|
||||
endRow = bufferRange.end.row
|
||||
foldedRows.push(startRow - insertDelta)
|
||||
else
|
||||
startRow = row
|
||||
endRow = row
|
||||
|
||||
insertPosition = Point.fromObject([startRow - insertDelta])
|
||||
endPosition = Point.min([endRow + 1], @buffer.getEofPosition())
|
||||
lines = @buffer.getTextInRange([[startRow], endPosition])
|
||||
if endPosition.row is lastRow and endPosition.column > 0 and not @buffer.lineEndingForRow(endPosition.row)
|
||||
lines = "#{lines}\n"
|
||||
|
||||
@buffer.deleteRows(startRow, endRow)
|
||||
@buffer.insert([startRow - 1], lines)
|
||||
|
||||
@foldBufferRow(foldedRow) for foldedRow in foldedRows
|
||||
# Make sure the inserted text doesn't go into an existing fold
|
||||
if fold = @displayBuffer.largestFoldStartingAtBufferRow(insertPosition.row)
|
||||
@destroyFoldsContainingBufferRow(insertPosition.row)
|
||||
foldedRows.push(insertPosition.row + endRow - startRow + fold.getBufferRange().getRowCount())
|
||||
|
||||
@setSelectedBufferRange(selection.translate([-1]), preserveFolds: true)
|
||||
@buffer.insert(insertPosition, lines)
|
||||
|
||||
# Public: Moves the selected line down one row.
|
||||
# Restore folds that existed before the lines were moved
|
||||
for foldedRow in foldedRows when 0 <= foldedRow <= @getLastBufferRow()
|
||||
@foldBufferRow(foldedRow)
|
||||
|
||||
@setSelectedBufferRange(selection.translate([-insertDelta]), preserveFolds: true)
|
||||
|
||||
# Public: Moves the selected lines down one screen row.
|
||||
moveLineDown: ->
|
||||
selection = @getSelectedBufferRange()
|
||||
lastRow = @buffer.getLastRow()
|
||||
@@ -667,13 +685,21 @@ class Editor extends Model
|
||||
rows = [selection.end.row..selection.start.row]
|
||||
if selection.start.row isnt selection.end.row and selection.end.column is 0
|
||||
rows.shift() unless @isFoldedAtBufferRow(selection.end.row)
|
||||
|
||||
# Move line around the fold that is directly below the selection
|
||||
followingScreenRow = @screenPositionForBufferPosition([selection.end.row]).translate([1])
|
||||
followingBufferRow = @bufferPositionForScreenPosition(followingScreenRow).row
|
||||
if fold = @largestFoldContainingBufferRow(followingBufferRow)
|
||||
insertDelta = fold.getBufferRange().getRowCount()
|
||||
else
|
||||
insertDelta = 1
|
||||
|
||||
for row in rows
|
||||
screenRow = @screenPositionForBufferPosition([row]).row
|
||||
if @isFoldedAtScreenRow(screenRow)
|
||||
bufferRange = @bufferRangeForScreenRange([[screenRow], [screenRow + 1]])
|
||||
if fold = @displayBuffer.largestFoldStartingAtBufferRow(row)
|
||||
bufferRange = fold.getBufferRange()
|
||||
startRow = bufferRange.start.row
|
||||
endRow = bufferRange.end.row - 1
|
||||
foldedRows.push(endRow + 1)
|
||||
endRow = bufferRange.end.row
|
||||
foldedRows.push(endRow + insertDelta)
|
||||
else
|
||||
startRow = row
|
||||
endRow = row
|
||||
@@ -684,14 +710,23 @@ class Editor extends Model
|
||||
endPosition = [endRow + 1]
|
||||
lines = @buffer.getTextInRange([[startRow], endPosition])
|
||||
@buffer.deleteRows(startRow, endRow)
|
||||
insertPosition = Point.min([startRow + 1], @buffer.getEofPosition())
|
||||
|
||||
insertPosition = Point.min([startRow + insertDelta], @buffer.getEofPosition())
|
||||
if insertPosition.row is @buffer.getLastRow() and insertPosition.column > 0
|
||||
lines = "\n#{lines}"
|
||||
|
||||
# Make sure the inserted text doesn't go into an existing fold
|
||||
if fold = @displayBuffer.largestFoldStartingAtBufferRow(insertPosition.row)
|
||||
@destroyFoldsContainingBufferRow(insertPosition.row)
|
||||
foldedRows.push(insertPosition.row + fold.getBufferRange().getRowCount())
|
||||
|
||||
@buffer.insert(insertPosition, lines)
|
||||
|
||||
@foldBufferRow(foldedRow) for foldedRow in foldedRows
|
||||
# Restore folds that existed before the lines were moved
|
||||
for foldedRow in foldedRows when 0 <= foldedRow <= @getLastBufferRow()
|
||||
@foldBufferRow(foldedRow)
|
||||
|
||||
@setSelectedBufferRange(selection.translate([1]), preserveFolds: true)
|
||||
@setSelectedBufferRange(selection.translate([insertDelta]), preserveFolds: true)
|
||||
|
||||
# Public: Duplicates the current line.
|
||||
#
|
||||
|
||||
@@ -11,9 +11,8 @@ fs = require 'fs-plus'
|
||||
# An instance of this class is always available as the `atom.menu` global.
|
||||
module.exports =
|
||||
class MenuManager
|
||||
pendingUpdateOperation: null
|
||||
|
||||
constructor: ({@resourcePath}) ->
|
||||
@pendingUpdateOperation = null
|
||||
@template = []
|
||||
atom.keymap.on 'bundled-keymaps-loaded', => @loadPlatformItems()
|
||||
|
||||
@@ -32,7 +31,8 @@ class MenuManager
|
||||
# items - An {Array} of menu item {Object}s containing the keys:
|
||||
# :label - The {String} menu label.
|
||||
# :submenu - An optional {Array} of sub menu items.
|
||||
# :command - An option {String} command to trigger when the item is clicked.
|
||||
# :command - An optional {String} command to trigger when the item is
|
||||
# clicked.
|
||||
#
|
||||
# Returns nothing.
|
||||
add: (items) ->
|
||||
@@ -48,14 +48,21 @@ class MenuManager
|
||||
includeSelector: (selector) ->
|
||||
return true if document.body.webkitMatchesSelector(selector)
|
||||
|
||||
# Simulate an .editor element attached to a body element that has the same
|
||||
# classes as the current body element.
|
||||
# Simulate an .editor element attached to a .workspace element attached to
|
||||
# a body element that has the same classes as the current body element.
|
||||
unless @testEditor?
|
||||
testBody = document.createElement('body')
|
||||
testBody.classList.add(@classesForElement(document.body)...)
|
||||
|
||||
testWorkspace = document.createElement('body')
|
||||
workspaceClasses = @classesForElement(document.body.querySelector('.workspace')) ? ['.workspace']
|
||||
testWorkspace.classList.add(workspaceClasses...)
|
||||
|
||||
testBody.appendChild(testWorkspace)
|
||||
|
||||
@testEditor = document.createElement('div')
|
||||
@testEditor.classList.add('editor')
|
||||
testBody = document.createElement('body')
|
||||
testBody.classList.add(document.body.classList.toString().split(' ')...)
|
||||
testBody.appendChild(@testEditor)
|
||||
testWorkspace.appendChild(@testEditor)
|
||||
|
||||
@testEditor.webkitMatchesSelector(selector)
|
||||
|
||||
@@ -109,3 +116,7 @@ class MenuManager
|
||||
label.replace(/\&/g, '')
|
||||
else
|
||||
label
|
||||
|
||||
# Get an {Array} of {String} classes for the given element.
|
||||
classesForElement: (element) ->
|
||||
element?.classList.toString().split(' ') ? []
|
||||
|
||||
@@ -81,26 +81,15 @@ class PackageManager
|
||||
@observeDisabledPackages()
|
||||
|
||||
# Activate a single package by name
|
||||
activatePackage: (name, options={}) ->
|
||||
if options.sync? or options.immediate?
|
||||
return @activatePackageSync(name, options)
|
||||
|
||||
activatePackage: (name) ->
|
||||
if pack = @getActivePackage(name)
|
||||
Q(pack)
|
||||
else
|
||||
pack = @loadPackage(name)
|
||||
pack.activate(options).then =>
|
||||
pack.activate().then =>
|
||||
@activePackages[pack.name] = pack
|
||||
pack
|
||||
|
||||
# Deprecated
|
||||
activatePackageSync: (name, options) ->
|
||||
return pack if pack = @getActivePackage(name)
|
||||
if pack = @loadPackage(name)
|
||||
@activePackages[pack.name] = pack
|
||||
pack.activateSync(options)
|
||||
pack
|
||||
|
||||
# Deactivate all packages
|
||||
deactivatePackages: ->
|
||||
@deactivatePackage(pack.name) for pack in @getLoadedPackages()
|
||||
|
||||
@@ -27,7 +27,7 @@ class PaneView extends View
|
||||
'destroyItem', 'destroyItems', 'destroyActiveItem', 'destroyInactiveItems',
|
||||
'saveActiveItem', 'saveActiveItemAs', 'saveItem', 'saveItemAs', 'saveItems',
|
||||
'itemForUri', 'activateItemForUri', 'promptToSaveItem', 'copyActiveItem', 'isActive',
|
||||
'activate', toProperty: 'model'
|
||||
'activate', 'getActiveItem', toProperty: 'model'
|
||||
|
||||
previousActiveItem: null
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
{Model, Sequence} = require 'theorist'
|
||||
Serializable = require 'serializable'
|
||||
PaneAxis = require './pane-axis'
|
||||
Editor = require './editor'
|
||||
PaneView = null
|
||||
|
||||
# Public: A container for multiple items, one of which is *active* at a given
|
||||
@@ -85,6 +86,17 @@ class Pane extends Model
|
||||
getItems: ->
|
||||
@items.slice()
|
||||
|
||||
# Public: Get the active pane item in this pane.
|
||||
#
|
||||
# Returns a pane item.
|
||||
getActiveItem: ->
|
||||
@activeItem
|
||||
|
||||
# Public: Returns an {Editor} if the pane item is an {Editor}, or null
|
||||
# otherwise.
|
||||
getActiveEditor: ->
|
||||
@activeItem if @activeItem instanceof Editor
|
||||
|
||||
# Public: Returns the item at the specified index.
|
||||
itemAtIndex: (index) ->
|
||||
@items[index]
|
||||
@@ -105,15 +117,15 @@ class Pane extends Model
|
||||
else
|
||||
@activateItemAtIndex(@items.length - 1)
|
||||
|
||||
# Public: Returns the index of the current active item.
|
||||
# Returns the index of the current active item.
|
||||
getActiveItemIndex: ->
|
||||
@items.indexOf(@activeItem)
|
||||
|
||||
# Public: Makes the item at the given index active.
|
||||
# Makes the item at the given index active.
|
||||
activateItemAtIndex: (index) ->
|
||||
@activateItem(@itemAtIndex(index))
|
||||
|
||||
# Public: Makes the given item active, adding the item if necessary.
|
||||
# Makes the given item active, adding the item if necessary.
|
||||
activateItem: (item) ->
|
||||
if item?
|
||||
@addItem(item)
|
||||
|
||||
@@ -137,9 +137,8 @@ class Project extends Model
|
||||
#
|
||||
# Returns a promise that resolves to an {Editor}.
|
||||
open: (filePath, options={}) ->
|
||||
filePath = @resolve(filePath)
|
||||
resource = null
|
||||
_.find @openers, (opener) -> resource = opener(filePath, options)
|
||||
filePath = @resolve(filePath) ? ''
|
||||
resource = opener(filePath, options) for opener in @openers when !resource
|
||||
|
||||
if resource
|
||||
Q(resource)
|
||||
@@ -149,11 +148,10 @@ class Project extends Model
|
||||
|
||||
# Only be used in specs
|
||||
openSync: (filePath, options={}) ->
|
||||
filePath = @resolve(filePath)
|
||||
for opener in @openers
|
||||
return resource if resource = opener(filePath, options)
|
||||
filePath = @resolve(filePath) ? ''
|
||||
resource = opener(filePath, options) for opener in @openers when !resource
|
||||
|
||||
@buildEditorForBuffer(@bufferForPathSync(filePath), options)
|
||||
resource or @buildEditorForBuffer(@bufferForPathSync(filePath), options)
|
||||
|
||||
# Public: Retrieves all {Editor}s for all open files.
|
||||
#
|
||||
|
||||
@@ -165,14 +165,14 @@ class TextBuffer extends TextBufferCore
|
||||
|
||||
# Sets the path for the file.
|
||||
#
|
||||
# path - A {String} representing the new file path
|
||||
setPath: (path) ->
|
||||
return if path == @getPath()
|
||||
# filePath - A {String} representing the new file path
|
||||
setPath: (filePath) ->
|
||||
return if filePath == @getPath()
|
||||
|
||||
@file?.off()
|
||||
|
||||
if path
|
||||
@file = new File(path)
|
||||
if filePath
|
||||
@file = new File(filePath)
|
||||
@subscribeToFile()
|
||||
else
|
||||
@file = null
|
||||
@@ -188,14 +188,15 @@ class TextBuffer extends TextBufferCore
|
||||
|
||||
# Saves the buffer at a specific path.
|
||||
#
|
||||
# path - The path to save at.
|
||||
saveAs: (path) ->
|
||||
unless path then throw new Error("Can't save buffer with no file path")
|
||||
# filePath - The path to save at.
|
||||
saveAs: (filePath) ->
|
||||
unless filePath then throw new Error("Can't save buffer with no file path")
|
||||
|
||||
@emit 'will-be-saved', this
|
||||
@setPath(path)
|
||||
@setPath(filePath)
|
||||
@file.write(@getText())
|
||||
@cachedDiskContents = @getText()
|
||||
@conflict = false
|
||||
@emitModifiedStatusChanged(false)
|
||||
@emit 'saved', this
|
||||
|
||||
@@ -212,7 +213,10 @@ class TextBuffer extends TextBufferCore
|
||||
else
|
||||
not @isEmpty()
|
||||
|
||||
# Identifies if a buffer is in a git conflict with `HEAD`.
|
||||
# Is the buffer's text in conflict with the text on disk?
|
||||
#
|
||||
# This occurs when the buffer's file changes on disk while the buffer has
|
||||
# unsaved changes.
|
||||
#
|
||||
# Returns a {Boolean}.
|
||||
isInConflict: -> @conflict
|
||||
|
||||
@@ -117,6 +117,7 @@ class WorkspaceView extends View
|
||||
@command 'window:run-package-specs', => ipc.sendChannel('run-package-specs', path.join(atom.project.getPath(), 'spec'))
|
||||
@command 'window:increase-font-size', => @increaseFontSize()
|
||||
@command 'window:decrease-font-size', => @decreaseFontSize()
|
||||
@command 'window:reset-font-size', => @model.resetFontSize()
|
||||
|
||||
@command 'window:focus-next-pane', => @focusNextPane()
|
||||
@command 'window:focus-previous-pane', => @focusPreviousPane()
|
||||
@@ -229,9 +230,13 @@ class WorkspaceView extends View
|
||||
@horizontal.append(element)
|
||||
|
||||
# Public: Returns the currently focused {PaneView}.
|
||||
getActivePane: ->
|
||||
getActivePaneView: ->
|
||||
@panes.getActivePane()
|
||||
|
||||
# Deprecated: Returns the currently focused {PaneView}.
|
||||
getActivePane: ->
|
||||
@getActivePaneView()
|
||||
|
||||
# Public: Returns the currently focused item from within the focused {PaneView}
|
||||
getActivePaneItem: ->
|
||||
@model.activePaneItem
|
||||
|
||||
@@ -52,27 +52,43 @@ class Workspace extends Model
|
||||
#
|
||||
# filePath - A {String} file path.
|
||||
# options - An options {Object} (default: {}).
|
||||
# :initialLine - The buffer line number to open to.
|
||||
# :initialLine - A {Number} indicating which line number to open to.
|
||||
# :split - A {String} ('left' or 'right') that opens the filePath in a new
|
||||
# pane or an existing one if it exists.
|
||||
# :changeFocus - A {Boolean} that allows the filePath to be opened without
|
||||
# changing focus.
|
||||
# :searchAllPanes - A {Boolean} that will open existing editors from any pane
|
||||
# if the filePath is already open (default: false)
|
||||
#
|
||||
# Returns a promise that resolves to the {Editor} for the file URI.
|
||||
open: (filePath, options={}) ->
|
||||
changeFocus = options.changeFocus ? true
|
||||
filePath = atom.project.resolve(filePath)
|
||||
initialLine = options.initialLine
|
||||
activePane = @activePane
|
||||
searchAllPanes = options.searchAllPanes
|
||||
split = options.split
|
||||
uri = atom.project.relativize(filePath)
|
||||
|
||||
editor = activePane.itemForUri(atom.project.relativize(filePath)) if activePane and filePath
|
||||
promise = atom.project.open(filePath, {initialLine}) if not editor
|
||||
pane = switch split
|
||||
when 'left'
|
||||
@activePane.findLeftmostSibling()
|
||||
when 'right'
|
||||
@activePane.findOrCreateRightmostSibling()
|
||||
else
|
||||
if searchAllPanes
|
||||
@paneContainer.paneForUri(uri) ? @activePane
|
||||
else
|
||||
@activePane
|
||||
|
||||
Q(editor ? promise)
|
||||
Q(pane.itemForUri(uri) ? atom.project.open(filePath, options))
|
||||
.then (editor) =>
|
||||
if not activePane
|
||||
activePane = new Pane(items: [editor])
|
||||
@paneContainer.root = activePane
|
||||
if not pane
|
||||
pane = new Pane(items: [editor])
|
||||
@paneContainer.root = pane
|
||||
|
||||
@itemOpened(editor)
|
||||
activePane.activateItem(editor)
|
||||
activePane.activate() if changeFocus
|
||||
pane.activateItem(editor)
|
||||
pane.activate() if changeFocus
|
||||
@emit "uri-opened"
|
||||
editor
|
||||
.catch (error) ->
|
||||
@@ -95,8 +111,7 @@ class Workspace extends Model
|
||||
@activePane.activate() if activatePane
|
||||
editor
|
||||
|
||||
# Public: Synchronously open an editor for the given URI or activate an existing
|
||||
# editor in any pane if one already exists.
|
||||
# Deprecated
|
||||
openSingletonSync: (uri, options={}) ->
|
||||
{initialLine, split} = options
|
||||
# TODO: Remove deprecated changeFocus option
|
||||
@@ -140,6 +155,11 @@ class Workspace extends Model
|
||||
destroyActivePane: ->
|
||||
@activePane?.destroy()
|
||||
|
||||
# Public: Returns an {Editor} if the active pane item is an {Editor},
|
||||
# or null otherwise.
|
||||
getActiveEditor: ->
|
||||
@activePane?.getActiveEditor()
|
||||
|
||||
increaseFontSize: ->
|
||||
atom.config.set("editor.fontSize", atom.config.get("editor.fontSize") + 1)
|
||||
|
||||
@@ -147,6 +167,9 @@ class Workspace extends Model
|
||||
fontSize = atom.config.get("editor.fontSize")
|
||||
atom.config.set("editor.fontSize", fontSize - 1) if fontSize > 1
|
||||
|
||||
resetFontSize: ->
|
||||
atom.config.restoreDefault("editor.fontSize")
|
||||
|
||||
# Removes the item's uri from the list of potential items to reopen.
|
||||
itemOpened: (item) ->
|
||||
if uri = item.getUri?()
|
||||
|
||||
@@ -1,171 +1,164 @@
|
||||
@import "octicon-mixins.less";
|
||||
@import "octicon-mixins";
|
||||
|
||||
@font-face { .octicon-font(); }
|
||||
#jasmine_content {
|
||||
position: fixed;
|
||||
right: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: #ddd;
|
||||
background-color: #fff;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.spec-popup {
|
||||
position: absolute;
|
||||
background-color: #ddd;
|
||||
border: 2px solid black;
|
||||
padding: 5px;
|
||||
font-size: 13px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.list-unstyled {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
#HTMLReporter { font-size: 11px; font-family: Monaco, Consolas, monospace; line-height: 1.6em; color: #333333; }
|
||||
#HTMLReporter #jasmine_content { position: fixed; right: 100%; }
|
||||
|
||||
#HTMLReporter .symbolHeader {
|
||||
background-color: #222;
|
||||
color: #c2c2c2;
|
||||
font-size: 12px;
|
||||
margin: 0;
|
||||
padding: 5px 2px 2px 2px;
|
||||
}
|
||||
|
||||
#HTMLReporter .symbolSummary {
|
||||
background-color: #222;
|
||||
overflow: hidden;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#HTMLReporter .symbolSummary li {
|
||||
float: left;
|
||||
line-height: 10px;
|
||||
height: 10px;
|
||||
width: 10px;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
#HTMLReporter .symbolSummary li.passed { color: #63AD75 }
|
||||
#HTMLReporter .symbolSummary li.failed { color: #FF3F05 }
|
||||
#HTMLReporter .symbolSummary li.skipped { color: #444 }
|
||||
#HTMLReporter .symbolSummary li.pending { color: #111 }
|
||||
|
||||
#HTMLReporter .symbolSummary li:before { content: "\02022"; }
|
||||
|
||||
#HTMLReporter .symbolSummary li:hover {
|
||||
color: white;
|
||||
}
|
||||
|
||||
#HTMLReporter .status {
|
||||
font-size: 20px;
|
||||
color: #222;
|
||||
background-color: #E5FFC0;
|
||||
line-height: 2em;
|
||||
padding: 2px;
|
||||
border: 2px solid #222;
|
||||
border-left: 0;
|
||||
border-right: 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#HTMLReporter .status.failed {
|
||||
color: white;
|
||||
background-color: rgba(204,51,63,1.0);
|
||||
}
|
||||
|
||||
#HTMLReporter .status .spec-count {
|
||||
float: left;
|
||||
}
|
||||
|
||||
#HTMLReporter .status .message {
|
||||
}
|
||||
|
||||
#HTMLReporter .status .time {
|
||||
float: right;
|
||||
}
|
||||
|
||||
#HTMLReporter .results .suite + .suite, #HTMLReporter .results .spec + .spec {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
#HTMLReporter .results .suite, #HTMLReporter .results .spec {
|
||||
border: 2px solid #222;
|
||||
border-radius: 7px 0 0 0;
|
||||
border-right: none;
|
||||
border-bottom: none;
|
||||
padding: 5px;
|
||||
padding-right: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
#HTMLReporter .results .suite:first-child {
|
||||
border-radius: 0;
|
||||
border: 2px solid #6A4A3C;
|
||||
border-top: 0;
|
||||
border-left: 0;
|
||||
border-right: 0;
|
||||
}
|
||||
|
||||
#HTMLReporter .results .suite {
|
||||
border: 2px solid #6A4A3C;
|
||||
border-radius: 7px 0 0 0;
|
||||
border-right: none;
|
||||
border-bottom: none;
|
||||
padding: 5px;
|
||||
padding-right: 0;
|
||||
padding-bottom: 0;
|
||||
background-color:rgba(204,51,63,0.33);
|
||||
}
|
||||
|
||||
#HTMLReporter .results .spec {
|
||||
padding: 10px;
|
||||
background-color:rgba(204,51,63,1.0);
|
||||
}
|
||||
|
||||
#HTMLReporter .results .suite > .suite, #HTMLReporter .results .suite > .spec {
|
||||
margin-left: 5px
|
||||
}
|
||||
|
||||
#HTMLReporter .results .description {
|
||||
color: white;
|
||||
font-size: 15px;
|
||||
padding-bottom: 10px
|
||||
}
|
||||
|
||||
#HTMLReporter .results .spec .spec-toggle {
|
||||
font-family: Octicons Regular;
|
||||
color: white;
|
||||
font-size: 20px;
|
||||
float: right;
|
||||
cursor: pointer;
|
||||
text-shadow: 3px 3px #222;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
#HTMLReporter .results .spec .spec-toggle:hover {
|
||||
text-shadow: none;
|
||||
padding-top: 3px;
|
||||
}
|
||||
|
||||
#HTMLReporter .results .spec:hover .spec-toggle {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
#HTMLReporter .resultMessage {
|
||||
padding-top: 5px;
|
||||
color: #fff;
|
||||
font-size: 15px
|
||||
}
|
||||
|
||||
#HTMLReporter .stackTrace {
|
||||
font-size: 12px;
|
||||
padding: 5px;
|
||||
margin: 5px 0 0 0;
|
||||
border-radius: 2px;
|
||||
line-height: 18px;
|
||||
color: #666666;
|
||||
border: 1px solid #ddd;
|
||||
background: white;
|
||||
white-space: pre;
|
||||
overflow: auto;
|
||||
.spec-reporter {
|
||||
font-size: 11px;
|
||||
line-height: 1.6em;
|
||||
color: #333;
|
||||
|
||||
.list-unstyled {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.symbol-header {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.symbol-area {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.symbol-summary {
|
||||
overflow: hidden;
|
||||
margin: 0;
|
||||
|
||||
li {
|
||||
font-family: Monaco, Consolas, monospace;
|
||||
float: left;
|
||||
line-height: 10px;
|
||||
height: 10px;
|
||||
width: 10px;
|
||||
font-size: 10px;
|
||||
|
||||
&.passed {
|
||||
color: #5cb85c;
|
||||
}
|
||||
|
||||
&.failed {
|
||||
color: #d9534f;
|
||||
}
|
||||
|
||||
&.skipped {
|
||||
color: #f0ad4e;
|
||||
}
|
||||
|
||||
&.pending {
|
||||
color: #eee;
|
||||
}
|
||||
|
||||
&:before {
|
||||
content: "\02022";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.status {
|
||||
font-size: 20px;
|
||||
line-height: 2em;
|
||||
padding: 5px;
|
||||
border-radius: 0;
|
||||
text-align: center;
|
||||
|
||||
.spec-count {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.time {
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
|
||||
.results {
|
||||
padding: 10px;
|
||||
|
||||
.description {
|
||||
font-size: 16px;
|
||||
padding: 5px 0 5px 0;
|
||||
}
|
||||
|
||||
> .suite {
|
||||
> .description {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.spec {
|
||||
margin-top: 5px;
|
||||
padding: 0 10px 10px 10px;
|
||||
border-left: 3px solid #d9534f;
|
||||
|
||||
.spec-toggle {
|
||||
.octicon(fold);
|
||||
float: right;
|
||||
cursor: pointer;
|
||||
opacity: 0;
|
||||
color: #999;
|
||||
|
||||
&.folded {
|
||||
.octicon(unfold);
|
||||
}
|
||||
}
|
||||
|
||||
.spec-toggle:hover {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
&:hover .spec-toggle {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.suite > .suite,
|
||||
.suite > .spec {
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.result-message {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
color: #d9534f;
|
||||
padding: 5px 0 5px 0;
|
||||
}
|
||||
|
||||
.stack-trace {
|
||||
font-size: 12px;
|
||||
margin: 5px 0 0 0;
|
||||
border-radius: 2px;
|
||||
line-height: 18px;
|
||||
color: #666;
|
||||
border: 1px solid #ddd;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.tooltip {
|
||||
.tooltip-inner {
|
||||
border: 1px solid #ccc;
|
||||
background: #fff;
|
||||
color: #666;
|
||||
max-width: 400px;
|
||||
}
|
||||
|
||||
&.in {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.tooltip-arrow {
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
2
vendor/apm
vendored
2
vendor/apm
vendored
Submodule vendor/apm updated: ce140e6628...0ed2a1ef75
Reference in New Issue
Block a user