merge dev, fix conflicts from package rewrite

This commit is contained in:
Justin Palmer
2013-02-09 20:17:29 -08:00
130 changed files with 1438 additions and 1161 deletions

Binary file not shown.

View File

@@ -0,0 +1,67 @@
RootView = require 'root-view'
AtomPackage = require 'atom-package'
fs = require 'fs'
describe "AtomPackage", ->
describe ".load()", ->
afterEach ->
rootView.deactivate()
describe "when the package metadata includes activation events", ->
[packageMainModule, pack] = []
beforeEach ->
new RootView(fixturesProject.getPath())
pack = new AtomPackage(fs.resolve(config.packageDirPaths..., 'package-with-activation-events'))
packageMainModule = require 'fixtures/packages/package-with-activation-events/main'
spyOn(packageMainModule, 'activate').andCallThrough()
pack.load()
it "defers activating the package until an activation event bubbles to the root view", ->
expect(packageMainModule.activate).not.toHaveBeenCalled()
rootView.trigger 'activation-event'
expect(packageMainModule.activate).toHaveBeenCalled()
it "triggers the activation event on all handlers registered during activation", ->
rootView.open('sample.js')
editor = rootView.getActiveEditor()
eventHandler = jasmine.createSpy("activation-event")
editor.command 'activation-event', eventHandler
editor.trigger 'activation-event'
expect(packageMainModule.activate.callCount).toBe 1
expect(packageMainModule.activationEventCallCount).toBe 1
expect(eventHandler.callCount).toBe 1
editor.trigger 'activation-event'
expect(packageMainModule.activationEventCallCount).toBe 2
expect(eventHandler.callCount).toBe 2
expect(packageMainModule.activate.callCount).toBe 1
describe "when the package does not specify a main module", ->
describe "when the package has an index.coffee", ->
it "uses index.coffee as the main module", ->
new RootView(fixturesProject.getPath())
pack = new AtomPackage(fs.resolve(config.packageDirPaths..., 'package-with-module'))
packageMainModule = require 'fixtures/packages/package-with-module'
spyOn(packageMainModule, 'activate').andCallThrough()
expect(packageMainModule.activate).not.toHaveBeenCalled()
pack.load()
expect(packageMainModule.activate).toHaveBeenCalled()
describe "when the package doesn't have an index.coffee", ->
it "does not throw an exception or log an error", ->
spyOn(console, "error")
spyOn(console, "warn")
new RootView(fixturesProject.getPath())
pack = new AtomPackage(fs.resolve(config.packageDirPaths..., 'package-with-keymaps-manifest'))
expect(-> pack.load()).not.toThrow()
expect(console.error).not.toHaveBeenCalled()
expect(console.warn).not.toHaveBeenCalled()
describe "when a package is activated", ->
it "loads config defaults based on the `configDefaults` key", ->
expect(config.get('package-with-module.numbers.one')).toBeUndefined()
atom.loadPackage("package-with-module")
expect(config.get('package-with-module.numbers.one')).toBe 1
expect(config.get('package-with-module.numbers.two')).toBe 2

View File

@@ -2,11 +2,16 @@ RootView = require 'root-view'
{$$} = require 'space-pen'
describe "the `atom` global", ->
beforeEach ->
new RootView
afterEach ->
rootView.deactivate()
describe ".loadPackage(name)", ->
[extension, stylesheetPath] = []
beforeEach ->
rootView = new RootView
extension = require "package-with-module"
stylesheetPath = require.resolve("fixtures/packages/package-with-module/stylesheets/styles.css")
@@ -14,9 +19,9 @@ describe "the `atom` global", ->
removeStylesheet(stylesheetPath)
it "requires and activates the package's main module if it exists", ->
spyOn(rootView, 'activatePackage').andCallThrough()
spyOn(atom, 'activateAtomPackage').andCallThrough()
atom.loadPackage("package-with-module")
expect(rootView.activatePackage).toHaveBeenCalled()
expect(atom.activateAtomPackage).toHaveBeenCalled()
it "logs warning instead of throwing an exception if a package fails to load", ->
config.set("core.disabledPackages", [])
@@ -70,6 +75,7 @@ describe "the `atom` global", ->
syntax.on 'grammars-loaded', eventHandler
disabledPackages = config.get("core.disabledPackages")
disabledPackages.push('textmate-package.tmbundle')
disabledPackages.push('package-with-snippets')
config.set "core.disabledPackages", disabledPackages
atom.loadPackages()
@@ -78,3 +84,61 @@ describe "the `atom` global", ->
runs ->
expect(Worker.prototype.terminate).toHaveBeenCalled()
expect(Worker.prototype.terminate.calls.length).toBe 1
describe "package lifecycle", ->
[pack, packageModule] = []
beforeEach ->
pack =
name: "package"
packageMain:
activate: jasmine.createSpy("activate")
deactivate: ->
serialize: -> "it worked"
packageModule = pack.packageMain
describe ".activateAtomPackage(package)", ->
it "calls activate on the package", ->
atom.activateAtomPackage(pack)
expect(packageModule.activate).toHaveBeenCalledWith(undefined)
it "calls activate on the package module with its previous state", ->
atom.activateAtomPackage(pack)
packageModule.activate.reset()
serializedState = rootView.serialize()
rootView.deactivate()
RootView.deserialize(serializedState)
atom.activateAtomPackage(pack)
expect(packageModule.activate).toHaveBeenCalledWith("it worked")
describe ".deactivateAtomPackages()", ->
it "deactivates and removes the package module from the package module map", ->
atom.activateAtomPackage(pack)
spyOn(packageModule, "deactivate").andCallThrough()
atom.deactivateAtomPackages()
expect(packageModule.deactivate).toHaveBeenCalled()
expect(rootView.packages.length).toBe 0
describe ".serializeAtomPackages()", ->
it "absorbs exceptions that are thrown by the package module's serialize methods", ->
spyOn(console, 'error')
atom.activateAtomPackage
name: "bad-egg"
packageMain:
activate: ->
serialize: -> throw new Error("I'm broken")
atom.activateAtomPackage
name: "good-egg"
packageMain:
activate: ->
serialize: -> "I still get called"
packageStates = atom.serializeAtomPackages()
expect(packageStates['good-egg']).toBe "I still get called"
expect(packageStates['bad-egg']).toBeUndefined()
expect(console.error).toHaveBeenCalled()

View File

@@ -19,192 +19,6 @@ describe "LanguageMode", ->
expect(jsEditSession.languageMode.grammar.name).toBe "JavaScript"
jsEditSession.destroy()
describe "bracket insertion", ->
beforeEach ->
editSession.buffer.setText("")
describe "when more than one character is inserted", ->
it "does not insert a matching bracket", ->
editSession.insertText("woah(")
expect(editSession.buffer.getText()).toBe "woah("
describe "when there is a word character after the cursor", ->
it "does not insert a matching bracket", ->
editSession.buffer.setText("ab")
editSession.setCursorBufferPosition([0, 1])
editSession.insertText("(")
expect(editSession.buffer.getText()).toBe "a(b"
describe "when there are multiple cursors", ->
it "inserts ) at each cursor", ->
editSession.buffer.setText("()\nab\n[]\n12")
editSession.setCursorBufferPosition([3, 1])
editSession.addCursorAtBufferPosition([2, 1])
editSession.addCursorAtBufferPosition([1, 1])
editSession.addCursorAtBufferPosition([0, 1])
editSession.insertText ')'
expect(editSession.buffer.getText()).toBe "())\na)b\n[)]\n1)2"
describe "when there is a non-word character after the cursor", ->
it "inserts a closing bracket after an opening bracket is inserted", ->
editSession.buffer.setText("}")
editSession.setCursorBufferPosition([0, 0])
editSession.insertText '{'
expect(buffer.lineForRow(0)).toBe "{}}"
expect(editSession.getCursorBufferPosition()).toEqual([0,1])
describe "when the cursor is at the end of the line", ->
it "inserts a closing bracket after an opening bracket is inserted", ->
editSession.buffer.setText("")
editSession.insertText '{'
expect(buffer.lineForRow(0)).toBe "{}"
expect(editSession.getCursorBufferPosition()).toEqual([0,1])
editSession.buffer.setText("")
editSession.insertText '('
expect(buffer.lineForRow(0)).toBe "()"
expect(editSession.getCursorBufferPosition()).toEqual([0,1])
editSession.buffer.setText("")
editSession.insertText '['
expect(buffer.lineForRow(0)).toBe "[]"
expect(editSession.getCursorBufferPosition()).toEqual([0,1])
editSession.buffer.setText("")
editSession.insertText '"'
expect(buffer.lineForRow(0)).toBe '""'
expect(editSession.getCursorBufferPosition()).toEqual([0,1])
editSession.buffer.setText("")
editSession.insertText "'"
expect(buffer.lineForRow(0)).toBe "''"
expect(editSession.getCursorBufferPosition()).toEqual([0,1])
describe "when the cursor is on a closing bracket and a closing bracket is inserted", ->
describe "when the closing bracket was there previously", ->
it "inserts a closing bracket", ->
editSession.insertText '()x'
editSession.setCursorBufferPosition([0, 1])
editSession.insertText ')'
expect(buffer.lineForRow(0)).toBe "())x"
expect(editSession.getCursorBufferPosition().column).toBe 2
describe "when the closing bracket was automatically inserted from inserting an opening bracket", ->
it "only moves cursor over the closing bracket one time", ->
editSession.insertText '('
expect(buffer.lineForRow(0)).toBe "()"
editSession.setCursorBufferPosition([0, 1])
editSession.insertText ')'
expect(buffer.lineForRow(0)).toBe "()"
expect(editSession.getCursorBufferPosition()).toEqual [0, 2]
editSession.setCursorBufferPosition([0, 1])
editSession.insertText ')'
expect(buffer.lineForRow(0)).toBe "())"
expect(editSession.getCursorBufferPosition()).toEqual [0, 2]
it "moves cursor over the closing bracket after other text is inserted", ->
editSession.insertText '('
editSession.insertText 'ok cool'
expect(buffer.lineForRow(0)).toBe "(ok cool)"
editSession.setCursorBufferPosition([0, 8])
editSession.insertText ')'
expect(buffer.lineForRow(0)).toBe "(ok cool)"
expect(editSession.getCursorBufferPosition()).toEqual [0, 9]
it "works with nested brackets", ->
editSession.insertText '('
editSession.insertText '1'
editSession.insertText '('
editSession.insertText '2'
expect(buffer.lineForRow(0)).toBe "(1(2))"
editSession.setCursorBufferPosition([0, 4])
editSession.insertText ')'
expect(buffer.lineForRow(0)).toBe "(1(2))"
expect(editSession.getCursorBufferPosition()).toEqual [0, 5]
editSession.insertText ')'
expect(buffer.lineForRow(0)).toBe "(1(2))"
expect(editSession.getCursorBufferPosition()).toEqual [0, 6]
it "works with mixed brackets", ->
editSession.insertText '('
editSession.insertText '}'
expect(buffer.lineForRow(0)).toBe "(})"
editSession.insertText ')'
expect(buffer.lineForRow(0)).toBe "(})"
expect(editSession.getCursorBufferPosition()).toEqual [0, 3]
it "closes brackets with the same begin/end character correctly", ->
editSession.insertText '"'
editSession.insertText 'ok'
expect(buffer.lineForRow(0)).toBe '"ok"'
expect(editSession.getCursorBufferPosition()).toEqual [0, 3]
editSession.insertText '"'
expect(buffer.lineForRow(0)).toBe '"ok"'
expect(editSession.getCursorBufferPosition()).toEqual [0, 4]
describe "when there is text selected on a single line", ->
it "wraps the selection with brackets", ->
editSession.insertText 'text'
editSession.moveCursorToBottom()
editSession.selectToTop()
editSession.selectAll()
editSession.insertText '('
expect('(text)').toBe buffer.getText()
expect(editSession.getSelectedBufferRange()).toEqual [[0, 1], [0, 5]]
expect(editSession.getSelection().isReversed()).toBeTruthy()
describe "when there is text selected on multiple lines", ->
it "wraps the selection with brackets", ->
editSession.insertText 'text\nabcd'
editSession.moveCursorToBottom()
editSession.selectToTop()
editSession.selectAll()
editSession.insertText '('
expect('(text\nabcd)').toBe buffer.getText()
expect(editSession.getSelectedBufferRange()).toEqual [[0, 1], [1, 4]]
expect(editSession.getSelection().isReversed()).toBeTruthy()
describe "when inserting a quote", ->
describe "when a word character is before the cursor", ->
it "does not automatically insert closing quote", ->
editSession.buffer.setText("abc")
editSession.setCursorBufferPosition([0, 3])
editSession.insertText '"'
expect(buffer.lineForRow(0)).toBe "abc\""
editSession.buffer.setText("abc")
editSession.setCursorBufferPosition([0, 3])
editSession.insertText '\''
expect(buffer.lineForRow(0)).toBe "abc\'"
describe "when a non word character is before the cursor", ->
it "automatically insert closing quote", ->
editSession.buffer.setText("ab@")
editSession.setCursorBufferPosition([0, 3])
editSession.insertText '"'
expect(buffer.lineForRow(0)).toBe "ab@\"\""
expect(editSession.getCursorBufferPosition()).toEqual [0, 4]
describe "when the cursor is on an empty line", ->
it "automatically insert closing quote", ->
editSession.buffer.setText("")
editSession.setCursorBufferPosition([0, 0])
editSession.insertText '"'
expect(buffer.lineForRow(0)).toBe "\"\""
expect(editSession.getCursorBufferPosition()).toEqual [0, 1]
describe "bracket deletion", ->
it "deletes the end bracket when it directly proceeds a begin bracket that is being backspaced", ->
buffer.setText("")
editSession.setCursorBufferPosition([0, 0])
editSession.insertText '{'
expect(buffer.lineForRow(0)).toBe "{}"
editSession.backspace()
expect(buffer.lineForRow(0)).toBe ""
describe "javascript", ->
beforeEach ->
editSession = fixturesProject.buildEditSessionForPath('sample.js', autoIndent: false)

View File

@@ -50,6 +50,14 @@ describe "RootView", ->
expect(rootView.getEditors()[0].getText()).toEqual ""
expect(rootView.getTitle()).toBe 'untitled'
describe ".deactivate()", ->
it "deactivates all packages", ->
pack = atom.loadPackage("package-with-module")
atom.activateAtomPackage(pack)
spyOn(pack.packageMain, "deactivate").andCallThrough()
rootView.deactivate()
expect(pack.packageMain.deactivate).toHaveBeenCalled()
describe "@deserialize()", ->
viewState = null
@@ -151,25 +159,6 @@ describe "RootView", ->
expect(rootView.find('.pane').length).toBe 1
expect(rootView.find('.pane').children().length).toBe 0
describe ".serialize()", ->
it "absorbs exceptions that are thrown by the package module's serialize methods", ->
spyOn(console, 'error')
rootView.activatePackage("bad-egg",
activate: ->
serialize: -> throw new Error("I'm broken")
)
rootView.activatePackage("good-egg"
activate: ->
serialize: -> "I still get called"
)
data = rootView.serialize()
expect(data.packageStates['good-egg']).toBe "I still get called"
expect(data.packageStates['bad-egg']).toBeUndefined()
expect(console.error).toHaveBeenCalled()
describe "focus", ->
describe "when there is an active editor", ->
it "hands off focus to the active editor", ->
@@ -418,54 +407,6 @@ describe "RootView", ->
rootView.focusNextPane()
expect(view1.focus).toHaveBeenCalled()
describe "packages", ->
packageModule = null
beforeEach ->
packageModule =
configDefaults: foo: { bar: 2, baz: 3 }
activate: jasmine.createSpy("activate")
deactivate: ->
serialize: -> "it worked"
describe ".activatePackage(name, packageModule)", ->
it "calls activate on the package module", ->
rootView.activatePackage('package', packageModule)
expect(packageModule.activate).toHaveBeenCalledWith(rootView, undefined)
it "calls activate on the package module with its previous state", ->
rootView.activatePackage('package', packageModule)
packageModule.activate.reset()
newRootView = RootView.deserialize(rootView.serialize())
newRootView.activatePackage('package', packageModule)
expect(packageModule.activate).toHaveBeenCalledWith(newRootView, "it worked")
newRootView.remove()
it "loads config defaults based on the `configDefaults` key", ->
expect(config.get('foo.bar')).toBeUndefined()
rootView.activatePackage('package', packageModule)
config.set("package.foo.bar", 1)
expect(config.get('package.foo.bar')).toBe 1
expect(config.get('package.foo.baz')).toBe 3
describe ".deactivatePackage(packageName)", ->
it "deactivates and removes the package module from the package module map", ->
rootView.activatePackage('package', packageModule)
expect(rootView.packageModules['package']).toBeTruthy()
spyOn(packageModule, "deactivate").andCallThrough()
rootView.deactivatePackage('package')
expect(packageModule.deactivate).toHaveBeenCalled()
expect(rootView.packageModules['package']).toBeFalsy()
it "is called when the rootView is deactivated to deactivate all packages", ->
rootView.activatePackage('package', packageModule)
spyOn(rootView, "deactivatePackage").andCallThrough()
spyOn(packageModule, "deactivate").andCallThrough()
rootView.deactivate()
expect(rootView.deactivatePackage).toHaveBeenCalled()
expect(packageModule.deactivate).toHaveBeenCalled()
describe "keymap wiring", ->
commandHandler = null
beforeEach ->

View File

@@ -1,4 +1,5 @@
TextMateGrammar = require 'text-mate-grammar'
TextMatePackage = require 'text-mate-package'
plist = require 'plist'
fs = require 'fs'
_ = require 'underscore'
@@ -257,3 +258,14 @@ describe "TextMateGrammar", ->
{tokens, ruleStack} = grammar.tokenizeLine("if(1){if(1){m()}}")
expect(tokens[5]).toEqual value: "if", scopes: ["source.c", "meta.block.c", "keyword.control.c"]
expect(tokens[10]).toEqual value: "m", scopes: ["source.c", "meta.block.c", "meta.block.c", "meta.function-call.c", "support.function.any-method.c"]
describe "when the grammar is CSON", ->
it "loads the grammar and correctly parses a keyword", ->
spyOn(syntax, 'addGrammar')
pack = new TextMatePackage(fixturesProject.resolve("packages/package-with-a-cson-grammar.tmbundle"))
pack.load()
grammar = pack.grammars[0]
expect(grammar).toBeTruthy()
expect(grammar.scopeName).toBe "source.alot"
{tokens} = grammar.tokenizeLine("this is alot of code")
expect(tokens[1]).toEqual value: "alot", scopes: ["source.alot", "keyword.alot"]

View File

@@ -0,0 +1,11 @@
'fileTypes': ['alot']
'name': 'Alot'
'scopeName': 'source.alot'
'patterns': [
{
'captures':
'0':
'name': 'keyword.alot'
'match': 'alot'
}
]

View File

@@ -0,0 +1,6 @@
module.exports =
activationEventCallCount: 0
activate: ->
rootView.getActiveEditor()?.command 'activation-event', =>
@activationEventCallCount++

View File

@@ -0,0 +1,2 @@
'activationEvents': ['activation-event']
'main': 'main'

View File

@@ -1,6 +1,8 @@
AtomPackage = require 'atom-package'
module.exports =
class MyPackage extends AtomPackage
configDefaults:
numbers: { one: 1, two: 2 }
activate: ->
@activateCalled = true
deactivate: ->

View File

@@ -17,12 +17,20 @@ fixturePackagesPath = require.resolve('fixtures/packages')
require.paths.unshift(fixturePackagesPath)
[bindingSetsToRestore, bindingSetsByFirstKeystrokeToRestore] = []
# Load TextMate bundles, which specs rely on (but not other packages)
atom.loadTextMatePackages()
# Specs rely on TextMate bundles (but not atom packages)
window.loadTextMatePackages = ->
TextMatePackage = require 'text-mate-package'
config.packageDirPaths.unshift(fixturePackagesPath)
window.textMatePackages = []
for path in atom.getPackagePaths() when TextMatePackage.testName(path)
window.textMatePackages.push atom.loadPackage(fs.base(path))
window.loadTextMatePackages()
beforeEach ->
window.fixturesProject = new Project(require.resolve('fixtures'))
window.resetTimeouts()
atom.atomPackageStates = {}
# used to reset keymap after each spec
bindingSetsToRestore = _.clone(keymap.bindingSets)
@@ -30,7 +38,6 @@ beforeEach ->
# reset config before each spec; don't load or save from/to `config.json`
window.config = new Config()
config.packageDirPaths.unshift(fixturePackagesPath)
spyOn(config, 'load')
spyOn(config, 'save')
config.set "editor.fontSize", 16

View File

@@ -1,42 +1,88 @@
Package = require 'package'
fs = require 'fs'
_ = require 'underscore'
$ = require 'jquery'
module.exports =
class AtomPackage extends Package
metadata: null
keymapsDirPath: null
autoloadStylesheets: true
packageMain: null
constructor: (@name) ->
super
@keymapsDirPath = fs.join(@path, 'keymaps')
load: ->
load: ({activateImmediately}={}) ->
try
@loadMetadata()
@loadKeymaps()
@loadStylesheets() if @autoloadStylesheets
rootView?.activatePackage(@name, this) unless @isDirectory
@loadStylesheets()
if @metadata.activationEvents and not activateImmediately
@subscribeToActivationEvents()
else
@activatePackageMain()
catch e
console.warn "Failed to load package named '#{@name}'", e.stack
this
disableEventHandlersOnBubblePath: (event) ->
bubblePathEventHandlers = []
disabledHandler = ->
element = $(event.target)
while element.length
if eventHandlers = element.data('events')?[event.type]
for eventHandler in eventHandlers
eventHandler.disabledHandler = eventHandler.handler
eventHandler.handler = disabledHandler
bubblePathEventHandlers.push(eventHandler)
element = element.parent()
bubblePathEventHandlers
restoreEventHandlersOnBubblePath: (eventHandlers) ->
for eventHandler in eventHandlers
eventHandler.handler = eventHandler.disabledHandler
delete eventHandler.disabledHandler
unsubscribeFromActivationEvents: (activateHandler) ->
if _.isArray(@metadata.activationEvents)
rootView.off(event, activateHandler) for event in @metadata.activationEvents
else
rootView.off(event, selector, activateHandler) for event, selector of @metadata.activationEvents
subscribeToActivationEvents: () ->
activateHandler = (event) =>
bubblePathEventHandlers = @disableEventHandlersOnBubblePath(event)
@activatePackageMain()
$(event.target).trigger(event)
@restoreEventHandlersOnBubblePath(bubblePathEventHandlers)
@unsubscribeFromActivationEvents(activateHandler)
if _.isArray(@metadata.activationEvents)
rootView.command(event, activateHandler) for event in @metadata.activationEvents
else
rootView.command(event, selector, activateHandler) for event, selector of @metadata.activationEvents
activatePackageMain: ->
mainPath = @path
mainPath = fs.join(mainPath, @metadata.main) if @metadata.main
mainPath = require.resolve(mainPath)
if fs.isFile(mainPath)
@packageMain = require(mainPath)
config.setDefaults(@name, @packageMain.configDefaults)
atom.activateAtomPackage(this)
loadMetadata: ->
if metadataPath = fs.resolveExtension(fs.join(@path, "package"), ['cson', 'json'])
if metadataPath = fs.resolveExtension(fs.join(@path, 'package'), ['cson', 'json'])
@metadata = fs.readObject(metadataPath)
@metadata ?= {}
loadKeymaps: ->
if keymaps = @metadata?.keymaps
keymaps = keymaps.map (relativePath) =>
fs.resolve(@keymapsDirPath, relativePath, ['cson', 'json', ''])
keymap.load(keymapPath) for keymapPath in keymaps
keymapsDirPath = fs.join(@path, 'keymaps')
if @metadata.keymaps
for path in @metadata.keymaps
keymapPath = fs.resolve(keymapsDirPath, path, ['cson', 'json', ''])
keymap.load(keymapPath)
else
keymap.loadDirectory(@keymapsDirPath)
keymap.loadDirectory(keymapsDirPath)
loadStylesheets: ->
for stylesheetPath in @getStylesheetPaths()
requireStylesheet(stylesheetPath)
getStylesheetPaths: ->
stylesheetDirPath = fs.join(@path, 'stylesheets')
fs.list(stylesheetDirPath)
for stylesheetPath in fs.list(stylesheetDirPath)
requireStylesheet(stylesheetPath)

View File

@@ -12,42 +12,58 @@ _.extend atom,
exitWhenDone: window.location.params.exitWhenDone
loadedThemes: []
pendingBrowserProcessCallbacks: {}
loadedPackages: []
activatedAtomPackages: []
atomPackageStates: {}
activateAtomPackage: (pack) ->
@activatedAtomPackages.push(pack)
pack.packageMain.activate(@atomPackageStates[pack.name])
deactivateAtomPackages: ->
pack.packageMain.deactivate?() for pack in @activatedAtomPackages
@activatedAtomPackages = []
serializeAtomPackages: ->
packageStates = {}
for pack in @activatedAtomPackages
try
packageStates[pack.name] = pack.packageMain.serialize?()
catch e
console?.error("Exception serializing '#{pack.name}' package's module\n", e.stack)
packageStates
loadPackage: (name, options) ->
packagePath = _.find @getPackagePaths(), (packagePath) -> fs.base(packagePath) == name
pack = Package.build(packagePath)
pack?.load(options)
loadPackages: ->
{packages, asyncTextMatePackages} = _.groupBy @getPackages(), (pack) ->
if pack instanceof TextMatePackage and pack.name isnt 'text.tmbundle'
'asyncTextMatePackages'
textMatePackages = []
for path in @getPackagePaths()
pack = Package.build(path)
@loadedPackages.push(pack)
if pack instanceof TextMatePackage and fs.base(pack.path) isnt 'text.tmbundle'
textMatePackages.push(pack)
else
'packages'
pack.load()
pack.load() for pack in packages
if asyncTextMatePackages.length
new LoadTextMatePackagesTask(asyncTextMatePackages).start()
new LoadTextMatePackagesTask(textMatePackages).start() if textMatePackages.length > 0
getPackages: ->
@packages ?= @getPackageNames().map((name) -> Package.build(name))
.filter((pack) -> pack?)
new Array(@packages...)
getLoadedPackages: ->
_.clone(@loadedPackages)
loadTextMatePackages: ->
pack.load() for pack in @getTextMatePackages()
getTextMatePackages: ->
@getPackages().filter (pack) -> pack instanceof TextMatePackage
loadPackage: (name) ->
Package.build(name)?.load()
getPackageNames: ->
getPackagePaths: ->
disabledPackages = config.get("core.disabledPackages") ? []
allPackageNames = []
packagePaths = []
for packageDirPath in config.packageDirPaths
packageNames = fs.list(packageDirPath)
.filter((packagePath) -> fs.isDirectory(packagePath))
.map((packagePath) -> fs.base(packagePath))
allPackageNames.push(packageNames...)
_.unique(allPackageNames)
.filter (name) -> not _.contains(disabledPackages, name)
for packagePath in fs.list(packageDirPath)
continue if not fs.isDirectory(packagePath)
continue if fs.base(packagePath) in disabledPackages
continue if packagePath in packagePaths
packagePaths.push(packagePath)
packagePaths
loadThemes: ->
themeNames = config.get("core.themes") ? ['atom-dark-ui', 'atom-dark-syntax']

View File

@@ -1,36 +0,0 @@
AtomPackage = require 'atom-package'
_ = require 'underscore'
module.exports =
class DeferredAtomPackage extends AtomPackage
constructor: ->
super
@autoloadStylesheets = false
activate: (@rootView, @state) ->
@instance = null
onLoadEvent = (e) => @onLoadEvent(e, @getInstance())
if _.isArray(@loadEvents)
for event in @loadEvents
@rootView.command(event, onLoadEvent)
else
for event, selector of @loadEvents
@rootView.command(event, selector, onLoadEvent)
this
deactivate: -> @instance?.deactivate?()
serialize: ->
if @instance
@instance.serialize?()
else
@state
getInstance: ->
unless @instance
@loadStylesheets()
InstanceClass = require @instanceClass
@instance = InstanceClass.activate(@rootView, @state)
@instance

View File

@@ -8,78 +8,10 @@ class LanguageMode
buffer = null
grammar = null
editSession = null
pairedCharacters:
'(': ')'
'[': ']'
'{': '}'
'"': '"'
"'": "'"
constructor: (@editSession) ->
@buffer = @editSession.buffer
@reloadGrammar()
@bracketMarkers = []
_.adviseBefore @editSession, 'insertText', (text) =>
return true if @editSession.hasMultipleCursors()
cursorBufferPosition = @editSession.getCursorBufferPosition()
previousCharacter = @editSession.getTextInBufferRange([cursorBufferPosition.add([0, -1]), cursorBufferPosition])
nextCharacter = @editSession.getTextInBufferRange([cursorBufferPosition, cursorBufferPosition.add([0,1])])
if @isOpeningBracket(text) and not @editSession.getSelection().isEmpty()
@wrapSelectionInBrackets(text)
return false
hasWordAfterCursor = /\w/.test(nextCharacter)
hasWordBeforeCursor = /\w/.test(previousCharacter)
autoCompleteOpeningBracket = @isOpeningBracket(text) and not hasWordAfterCursor and not (@isQuote(text) and hasWordBeforeCursor)
skipOverExistingClosingBracket = false
if @isClosingBracket(text) and nextCharacter == text
if bracketMarker = _.find(@bracketMarkers, (marker) => @editSession.getMarkerBufferRange(marker)?.end.isEqual(cursorBufferPosition))
skipOverExistingClosingBracket = true
if skipOverExistingClosingBracket
@editSession.destroyMarker(bracketMarker)
_.remove(@bracketMarkers, bracketMarker)
@editSession.moveCursorRight()
false
else if autoCompleteOpeningBracket
@editSession.insertText(text + @pairedCharacters[text])
@editSession.moveCursorLeft()
range = [cursorBufferPosition, cursorBufferPosition.add([0, text.length])]
@bracketMarkers.push @editSession.markBufferRange(range)
false
_.adviseBefore @editSession, 'backspace', =>
return if @editSession.hasMultipleCursors()
return unless @editSession.getSelection().isEmpty()
cursorBufferPosition = @editSession.getCursorBufferPosition()
previousCharacter = @editSession.getTextInBufferRange([cursorBufferPosition.add([0, -1]), cursorBufferPosition])
nextCharacter = @editSession.getTextInBufferRange([cursorBufferPosition, cursorBufferPosition.add([0,1])])
if @pairedCharacters[previousCharacter] is nextCharacter
@editSession.transact =>
@editSession.moveCursorLeft()
@editSession.delete()
@editSession.delete()
false
wrapSelectionInBrackets: (bracket) ->
pair = @pairedCharacters[bracket]
@editSession.mutateSelectedText (selection) =>
return if selection.isEmpty()
range = selection.getBufferRange()
options = reverse: selection.isReversed()
selection.insertText("#{bracket}#{selection.getText()}#{pair}")
selectionStart = range.start.add([0, 1])
if range.start.row is range.end.row
selectionEnd = range.end.add([0, 1])
else
selectionEnd = range.end
selection.setBufferRange([selectionStart, selectionEnd], options)
reloadGrammar: ->
path = @buffer.getPath()
@@ -92,23 +24,6 @@ class LanguageMode
throw new Error("No grammar found for path: #{path}") unless @grammar
previousGrammar isnt @grammar
isQuote: (string) ->
/'|"/.test(string)
isOpeningBracket: (string) ->
@pairedCharacters[string]?
isClosingBracket: (string) ->
@getInvertedPairedCharacters()[string]?
getInvertedPairedCharacters: ->
return @invertedPairedCharacters if @invertedPairedCharacters
@invertedPairedCharacters = {}
for open, close of @pairedCharacters
@invertedPairedCharacters[close] = open
@invertedPairedCharacters
toggleLineCommentsForBufferRows: (start, end) ->
scopes = @editSession.scopesForBufferPosition([start, 0])
return unless commentStartString = syntax.getProperty(scopes, "editor.commentStart")

View File

@@ -1,5 +1,5 @@
TextMatePackage = require 'text-mate-package'
module.exports =
loadPackage: (name) ->
callTaskMethod('packageLoaded', new TextMatePackage(name).readGrammars())
loadPackage: (path) ->
callTaskMethod('packageLoaded', new TextMatePackage(path).readGrammars())

View File

@@ -16,10 +16,10 @@ class LoadTextMatePackagesTask extends Task
return
@package = @packages.shift()
@loadPackage(@package.name)
@loadPackage(@package.path)
loadPackage: (name) ->
@callWorkerMethod('loadPackage', name)
loadPackage: (path) ->
@callWorkerMethod('loadPackage', path)
packageLoaded: (grammars) ->
@package.loadGrammars(grammars)

View File

@@ -2,34 +2,17 @@ fs = require 'fs'
module.exports =
class Package
@resolve: (name) ->
path = require.resolve(name, verifyExistence: false)
return path if path
throw new Error("No package found named '#{name}'")
@build: (name) ->
@build: (path) ->
TextMatePackage = require 'text-mate-package'
AtomPackage = require 'atom-package'
if TextMatePackage.testName(name)
new TextMatePackage(name)
if TextMatePackage.testName(path)
new TextMatePackage(path)
else
if fs.isDirectory(@resolve(name))
new AtomPackage(name)
else
try
PackageClass = require name
new PackageClass(name) if typeof PackageClass is 'function'
catch e
console.warn "Failed to load package named '#{name}'", e.stack
new AtomPackage(path)
name: null
path: null
isDirectory: false
module: null
constructor: (@name) ->
@path = Package.resolve(@name)
@isDirectory = fs.isDirectory(@path)
@path = fs.directory(@path) unless @isDirectory
activate: (rootView) ->
constructor: (@path) ->
@name = fs.base(@path)

View File

@@ -118,6 +118,10 @@ class Project
getEditSessions: ->
new Array(@editSessions...)
eachEditSession: (callback) ->
callback(editSession) for editSession in @getEditSessions()
@on 'edit-session-created', (editSession) -> callback(editSession)
removeEditSession: (editSession) ->
_.remove(@editSessions, editSession)
@@ -125,9 +129,12 @@ class Project
buffers = []
for editSession in @editSessions when not _.include(buffers, editSession.buffer)
buffers.push editSession.buffer
buffers
eachBuffer: (callback) ->
callback(buffer) for buffer in @getBuffers()
@on 'buffer-created', (buffer) -> callback(buffer)
bufferForPath: (filePath) ->
if filePath?
filePath = @resolve(filePath)

View File

@@ -29,19 +29,19 @@ class RootView extends View
else
projectOrPathToOpen = projectPath # This will migrate people over to the new project serialization scheme. It should be removed eventually.
rootView = new RootView(projectOrPathToOpen , packageStates: packageStates, suppressOpen: true)
atom.atomPackageStates = packageStates ? {}
rootView = new RootView(projectOrPathToOpen , suppressOpen: true)
rootView.setRootPane(rootView.deserializeView(panesViewState)) if panesViewState
rootView
packageModules: null
packageStates: null
packages: null
title: null
pathToOpenIsFile: false
initialize: (projectOrPathToOpen, { @packageStates, suppressOpen } = {}) ->
initialize: (projectOrPathToOpen, { suppressOpen } = {}) ->
window.rootView = this
@packageStates ?= {}
@packageModules = {}
@packages = []
@viewClasses = {
"Pane": Pane,
"PaneRow": PaneRow,
@@ -68,7 +68,7 @@ class RootView extends View
serialize: ->
projectState: @project?.serialize()
panesViewState: @panes.children().view()?.serialize()
packageStates: @serializePackages()
packageStates: atom.serializeAtomPackages()
handleFocus: (e) ->
if @getActiveEditor()
@@ -118,33 +118,15 @@ class RootView extends View
afterAttach: (onDom) ->
@focus() if onDom
serializePackages: ->
packageStates = {}
for name, packageModule of @packageModules
try
packageStates[name] = packageModule.serialize?()
catch e
console?.error("Exception serializing '#{name}' package's module\n", e.stack)
packageStates
registerViewClass: (viewClass) ->
@viewClasses[viewClass.name] = viewClass
deserializeView: (viewState) ->
@viewClasses[viewState.viewClass]?.deserialize(viewState, this)
activatePackage: (name, packageModule) ->
config.setDefaults(name, packageModule.configDefaults) if packageModule.configDefaults?
@packageModules[name] = packageModule
packageModule.activate(this, @packageStates[name])
deactivatePackage: (name) ->
@packageModules[name].deactivate?()
delete @packageModules[name]
deactivate: ->
atom.setRootViewStateForPath(@project.getPath(), @serialize())
@deactivatePackage(name) for name of @packageModules
atom.deactivateAtomPackages()
@remove()
open: (path, options = {}) ->
@@ -274,9 +256,11 @@ class RootView extends View
callback(editor) for editor in @getEditors()
@on 'editor:attached', (e, editor) -> callback(editor)
eachEditSession: (callback) ->
@project.eachEditSession(callback)
eachBuffer: (callback) ->
callback(buffer) for buffer in @project.getBuffers()
@project.on 'buffer-created', (buffer) -> callback(buffer)
@project.eachBuffer(callback)
indexOfPane: (pane) ->
index = -1

View File

@@ -9,9 +9,12 @@ module.exports =
class TextMateGrammar
@readFromPath: (path) ->
grammarContent = null
plist.parseString fs.read(path), (e, data) ->
throw new Error(e) if e
grammarContent = data[0]
if fs.extension(path) is '.cson'
grammarContent = fs.readObject(path)
else
plist.parseString fs.read(path), (e, data) ->
throw new Error(e) if e
grammarContent = data[0]
throw new Error("Failed to load grammar at path `#{path}`") unless grammarContent
grammarContent

View File

@@ -28,7 +28,7 @@ class TextMatePackage extends Package
try
@loadGrammars()
catch e
console.warn "Failed to load package named '#{@name}'", e.stack
console.warn "Failed to load package at '#{@path}'", e.stack
this
getGrammars: -> @grammars

View File

@@ -37,8 +37,8 @@ windowAdditions =
# Note: RootView assigns itself on window on initialization so that
# window.rootView is available when loading user configuration
attachRootView: (pathToOpen) ->
if rootViewState = atom.getRootViewStateForPath(pathToOpen)
RootView.deserialize(rootViewState)
if pathState = atom.getRootViewStateForPath(pathToOpen)
RootView.deserialize(pathState)
else
new RootView(pathToOpen)

View File

@@ -1,6 +0,0 @@
AtomPackage = require 'atom-package'
AutocompleteView = require './src/autocomplete-view'
module.exports =
class Autocomplete extends AtomPackage
activate: (rootView) -> AutocompleteView.activate(rootView)

View File

@@ -4,10 +4,6 @@ SelectList = require 'select-list'
module.exports =
class AutocompleteView extends SelectList
@activate: (rootView) ->
rootView.eachEditor (editor) ->
new AutocompleteView(editor) if editor.attached and not editor.mini
@viewClass: -> "autocomplete #{super} popover-list"
editor: null
@@ -21,7 +17,6 @@ class AutocompleteView extends SelectList
initialize: (@editor) ->
super
@handleEvents()
@setCurrentBuffer(@editor.getBuffer())

View File

@@ -0,0 +1,10 @@
AutocompleteView = require './autocomplete-view'
module.exports =
autoCompleteViews: []
activate: ->
rootView.eachEditor (editor) =>
if editor.attached and not editor.mini
@autoCompleteViews.push new AutocompleteView(editor)

View File

@@ -0,0 +1,3 @@
'main': 'lib/autocomplete'
'activationEvents':
'autocomplete:attach': '.editor'

View File

@@ -1,37 +1,33 @@
$ = require 'jquery'
Autocomplete = require 'autocomplete/src/autocomplete-view'
AutocompleteView = require 'autocomplete/lib/autocomplete-view'
Autocomplete = require 'autocomplete/lib/autocomplete'
Buffer = require 'buffer'
Editor = require 'editor'
RootView = require 'root-view'
describe "Autocomplete", ->
autocomplete = null
editor = null
miniEditor = null
beforeEach ->
editor = new Editor(editSession: fixturesProject.buildEditSessionForPath('sample.js'))
atom.loadPackage('autocomplete')
autocomplete = new Autocomplete(editor)
miniEditor = autocomplete.miniEditor
rootView = new RootView(require.resolve('fixtures/sample.js'))
rootView.simulateDomAttachment()
afterEach ->
editor?.remove()
rootView.deactivate()
describe "@activate(rootView)", ->
describe "@activate()", ->
it "activates autocomplete on all existing and future editors (but not on autocomplete's own mini editor)", ->
rootView = new RootView(require.resolve('fixtures/sample.js'))
rootView.simulateDomAttachment()
Autocomplete.activate(rootView)
spyOn(AutocompleteView.prototype, 'initialize').andCallThrough()
autocompletePackage = atom.loadPackage("autocomplete")
expect(AutocompleteView.prototype.initialize).not.toHaveBeenCalled()
leftEditor = rootView.getActiveEditor()
rightEditor = rootView.getActiveEditor().splitRight()
spyOn(Autocomplete.prototype, 'initialize')
leftEditor.trigger 'autocomplete:attach'
expect(leftEditor.find('.autocomplete')).toExist()
expect(rightEditor.find('.autocomplete')).not.toExist()
expect(AutocompleteView.prototype.initialize).toHaveBeenCalled()
autoCompleteView = leftEditor.find('.autocomplete').view()
autoCompleteView.trigger 'core:cancel'
expect(leftEditor.find('.autocomplete')).not.toExist()
@@ -39,9 +35,20 @@ describe "Autocomplete", ->
rightEditor.trigger 'autocomplete:attach'
expect(rightEditor.find('.autocomplete')).toExist()
expect(Autocomplete.prototype.initialize).not.toHaveBeenCalled()
describe "AutocompleteView", ->
autocomplete = null
editor = null
miniEditor = null
rootView.deactivate()
beforeEach ->
new RootView
editor = new Editor(editSession: fixturesProject.buildEditSessionForPath('sample.js'))
atom.loadPackage('autocomplete')
autocomplete = new AutocompleteView(editor)
miniEditor = autocomplete.miniEditor
afterEach ->
editor?.remove()
describe 'autocomplete:attach event', ->
it "shows autocomplete view and focuses its mini-editor", ->

View File

@@ -1,8 +1,5 @@
AtomPackage = require 'atom-package'
module.exports =
class Autoflow extends AtomPackage
activate: (rootView) ->
activate: ->
rootView.command 'autoflow:reflow-paragraph', '.editor', (e) =>
@reflowParagraph(e.currentTargetView())

View File

@@ -0,0 +1 @@
'main': 'autoflow'

View File

@@ -1,10 +1,15 @@
AtomPackage = require 'atom-package'
_ = require 'underscore'
{$$} = require 'space-pen'
Range = require 'range'
module.exports =
class BracketMatcher extends AtomPackage
pairedCharacters:
'(': ')'
'[': ']'
'{': '}'
'"': '"'
"'": "'"
startPairMatches:
'(': ')'
'[': ']'
@@ -17,8 +22,9 @@ class BracketMatcher extends AtomPackage
pairHighlighted: false
activate: (rootView) ->
activate: ->
rootView.eachEditor (editor) => @subscribeToEditor(editor) if editor.attached
rootView.eachEditSession (editSession) => @subscribeToEditSession(editSession)
subscribeToEditor: (editor) ->
editor.on 'cursor:moved.bracket-matcher', => @updateMatch(editor)
@@ -118,3 +124,84 @@ class BracketMatcher extends AtomPackage
underlayer.append(@createView(editor, matchPosition))
underlayer.append(@createView(editor, position))
@pairHighlighted = true
subscribeToEditSession: (editSession) ->
@bracketMarkers = []
_.adviseBefore editSession, 'insertText', (text) =>
return true if editSession.hasMultipleCursors()
cursorBufferPosition = editSession.getCursorBufferPosition()
previousCharacter = editSession.getTextInBufferRange([cursorBufferPosition.add([0, -1]), cursorBufferPosition])
nextCharacter = editSession.getTextInBufferRange([cursorBufferPosition, cursorBufferPosition.add([0,1])])
if @isOpeningBracket(text) and not editSession.getSelection().isEmpty()
@wrapSelectionInBrackets(editSession, text)
return false
hasWordAfterCursor = /\w/.test(nextCharacter)
hasWordBeforeCursor = /\w/.test(previousCharacter)
autoCompleteOpeningBracket = @isOpeningBracket(text) and not hasWordAfterCursor and not (@isQuote(text) and hasWordBeforeCursor)
skipOverExistingClosingBracket = false
if @isClosingBracket(text) and nextCharacter == text
if bracketMarker = _.find(@bracketMarkers, (marker) => editSession.getMarkerBufferRange(marker)?.end.isEqual(cursorBufferPosition))
skipOverExistingClosingBracket = true
if skipOverExistingClosingBracket
editSession.destroyMarker(bracketMarker)
_.remove(@bracketMarkers, bracketMarker)
editSession.moveCursorRight()
false
else if autoCompleteOpeningBracket
editSession.insertText(text + @pairedCharacters[text])
editSession.moveCursorLeft()
range = [cursorBufferPosition, cursorBufferPosition.add([0, text.length])]
@bracketMarkers.push editSession.markBufferRange(range)
false
_.adviseBefore editSession, 'backspace', =>
return if editSession.hasMultipleCursors()
return unless editSession.getSelection().isEmpty()
cursorBufferPosition = editSession.getCursorBufferPosition()
previousCharacter = editSession.getTextInBufferRange([cursorBufferPosition.add([0, -1]), cursorBufferPosition])
nextCharacter = editSession.getTextInBufferRange([cursorBufferPosition, cursorBufferPosition.add([0,1])])
if @pairedCharacters[previousCharacter] is nextCharacter
editSession.transact =>
editSession.moveCursorLeft()
editSession.delete()
editSession.delete()
false
wrapSelectionInBrackets: (editSession, bracket) ->
pair = @pairedCharacters[bracket]
editSession.mutateSelectedText (selection) =>
return if selection.isEmpty()
range = selection.getBufferRange()
options = reverse: selection.isReversed()
selection.insertText("#{bracket}#{selection.getText()}#{pair}")
selectionStart = range.start.add([0, 1])
if range.start.row is range.end.row
selectionEnd = range.end.add([0, 1])
else
selectionEnd = range.end
selection.setBufferRange([selectionStart, selectionEnd], options)
isQuote: (string) ->
/'|"/.test(string)
getInvertedPairedCharacters: ->
return @invertedPairedCharacters if @invertedPairedCharacters
@invertedPairedCharacters = {}
for open, close of @pairedCharacters
@invertedPairedCharacters[close] = open
@invertedPairedCharacters
isOpeningBracket: (string) ->
@pairedCharacters[string]?
isClosingBracket: (string) ->
@getInvertedPairedCharacters()[string]?

View File

@@ -0,0 +1 @@
'main': 'lib/bracket-matcher'

View File

@@ -1,63 +1,66 @@
RootView = require 'root-view'
describe "bracket matching", ->
[rootView, editor] = []
[editor, editSession, buffer] = []
beforeEach ->
rootView = new RootView(require.resolve('fixtures/sample.js'))
atom.loadPackage('bracket-matcher')
rootView.attachToDom()
editor = rootView.getActiveEditor()
editSession = editor.activeEditSession
buffer = editSession.buffer
afterEach ->
rootView.deactivate()
describe "when the cursor is before a starting pair", ->
it "highlights the starting pair and ending pair", ->
editor.moveCursorToEndOfLine()
editor.moveCursorLeft()
expect(editor.underlayer.find('.bracket-matcher').length).toBe 2
expect(editor.underlayer.find('.bracket-matcher:first').position()).toEqual editor.pixelPositionForBufferPosition([0,28])
expect(editor.underlayer.find('.bracket-matcher:last').position()).toEqual editor.pixelPositionForBufferPosition([12,0])
describe "when the cursor is after a starting pair", ->
it "highlights the starting pair and ending pair", ->
editor.moveCursorToEndOfLine()
expect(editor.underlayer.find('.bracket-matcher').length).toBe 2
expect(editor.underlayer.find('.bracket-matcher:first').position()).toEqual editor.pixelPositionForBufferPosition([0,28])
expect(editor.underlayer.find('.bracket-matcher:last').position()).toEqual editor.pixelPositionForBufferPosition([12,0])
describe "when the cursor is before an ending pair", ->
it "highlights the starting pair and ending pair", ->
editor.moveCursorToBottom()
editor.moveCursorLeft()
editor.moveCursorLeft()
expect(editor.underlayer.find('.bracket-matcher').length).toBe 2
expect(editor.underlayer.find('.bracket-matcher:last').position()).toEqual editor.pixelPositionForBufferPosition([12,0])
expect(editor.underlayer.find('.bracket-matcher:first').position()).toEqual editor.pixelPositionForBufferPosition([0,28])
describe "when the cursor is after an ending pair", ->
it "highlights the starting pair and ending pair", ->
editor.moveCursorToBottom()
editor.moveCursorLeft()
expect(editor.underlayer.find('.bracket-matcher').length).toBe 2
expect(editor.underlayer.find('.bracket-matcher:last').position()).toEqual editor.pixelPositionForBufferPosition([12,0])
expect(editor.underlayer.find('.bracket-matcher:first').position()).toEqual editor.pixelPositionForBufferPosition([0,28])
describe "when the cursor is moved off a pair", ->
it "removes the starting pair and ending pair highlights", ->
editor.moveCursorToEndOfLine()
expect(editor.underlayer.find('.bracket-matcher').length).toBe 2
editor.moveCursorToBeginningOfLine()
expect(editor.underlayer.find('.bracket-matcher').length).toBe 0
describe "pair balancing", ->
describe "when a second starting pair preceeds the first ending pair", ->
it "advances to the second ending pair", ->
editor.setCursorBufferPosition([8,42])
describe "matching bracket highlighting", ->
describe "when the cursor is before a starting pair", ->
it "highlights the starting pair and ending pair", ->
editor.moveCursorToEndOfLine()
editor.moveCursorLeft()
expect(editor.underlayer.find('.bracket-matcher').length).toBe 2
expect(editor.underlayer.find('.bracket-matcher:first').position()).toEqual editor.pixelPositionForBufferPosition([8,42])
expect(editor.underlayer.find('.bracket-matcher:last').position()).toEqual editor.pixelPositionForBufferPosition([8,54])
expect(editor.underlayer.find('.bracket-matcher:first').position()).toEqual editor.pixelPositionForBufferPosition([0,28])
expect(editor.underlayer.find('.bracket-matcher:last').position()).toEqual editor.pixelPositionForBufferPosition([12,0])
describe "when the cursor is after a starting pair", ->
it "highlights the starting pair and ending pair", ->
editor.moveCursorToEndOfLine()
expect(editor.underlayer.find('.bracket-matcher').length).toBe 2
expect(editor.underlayer.find('.bracket-matcher:first').position()).toEqual editor.pixelPositionForBufferPosition([0,28])
expect(editor.underlayer.find('.bracket-matcher:last').position()).toEqual editor.pixelPositionForBufferPosition([12,0])
describe "when the cursor is before an ending pair", ->
it "highlights the starting pair and ending pair", ->
editor.moveCursorToBottom()
editor.moveCursorLeft()
editor.moveCursorLeft()
expect(editor.underlayer.find('.bracket-matcher').length).toBe 2
expect(editor.underlayer.find('.bracket-matcher:last').position()).toEqual editor.pixelPositionForBufferPosition([12,0])
expect(editor.underlayer.find('.bracket-matcher:first').position()).toEqual editor.pixelPositionForBufferPosition([0,28])
describe "when the cursor is after an ending pair", ->
it "highlights the starting pair and ending pair", ->
editor.moveCursorToBottom()
editor.moveCursorLeft()
expect(editor.underlayer.find('.bracket-matcher').length).toBe 2
expect(editor.underlayer.find('.bracket-matcher:last').position()).toEqual editor.pixelPositionForBufferPosition([12,0])
expect(editor.underlayer.find('.bracket-matcher:first').position()).toEqual editor.pixelPositionForBufferPosition([0,28])
describe "when the cursor is moved off a pair", ->
it "removes the starting pair and ending pair highlights", ->
editor.moveCursorToEndOfLine()
expect(editor.underlayer.find('.bracket-matcher').length).toBe 2
editor.moveCursorToBeginningOfLine()
expect(editor.underlayer.find('.bracket-matcher').length).toBe 0
describe "pair balancing", ->
describe "when a second starting pair preceeds the first ending pair", ->
it "advances to the second ending pair", ->
editor.setCursorBufferPosition([8,42])
expect(editor.underlayer.find('.bracket-matcher').length).toBe 2
expect(editor.underlayer.find('.bracket-matcher:first').position()).toEqual editor.pixelPositionForBufferPosition([8,42])
expect(editor.underlayer.find('.bracket-matcher:last').position()).toEqual editor.pixelPositionForBufferPosition([8,54])
describe "when editor:go-to-matching-bracket is triggered", ->
describe "when the cursor is before the starting pair", ->
@@ -84,3 +87,189 @@ describe "bracket matching", ->
editor.setCursorBufferPosition([12, 1])
editor.trigger "editor:go-to-matching-bracket"
expect(editor.getCursorBufferPosition()).toEqual [0, 28]
describe "matching bracket insertion", ->
beforeEach ->
editSession.buffer.setText("")
describe "when more than one character is inserted", ->
it "does not insert a matching bracket", ->
editSession.insertText("woah(")
expect(editSession.buffer.getText()).toBe "woah("
describe "when there is a word character after the cursor", ->
it "does not insert a matching bracket", ->
editSession.buffer.setText("ab")
editSession.setCursorBufferPosition([0, 1])
editSession.insertText("(")
expect(editSession.buffer.getText()).toBe "a(b"
describe "when there are multiple cursors", ->
it "inserts ) at each cursor", ->
editSession.buffer.setText("()\nab\n[]\n12")
editSession.setCursorBufferPosition([3, 1])
editSession.addCursorAtBufferPosition([2, 1])
editSession.addCursorAtBufferPosition([1, 1])
editSession.addCursorAtBufferPosition([0, 1])
editSession.insertText ')'
expect(editSession.buffer.getText()).toBe "())\na)b\n[)]\n1)2"
describe "when there is a non-word character after the cursor", ->
it "inserts a closing bracket after an opening bracket is inserted", ->
editSession.buffer.setText("}")
editSession.setCursorBufferPosition([0, 0])
editSession.insertText '{'
expect(buffer.lineForRow(0)).toBe "{}}"
expect(editSession.getCursorBufferPosition()).toEqual([0,1])
describe "when the cursor is at the end of the line", ->
it "inserts a closing bracket after an opening bracket is inserted", ->
editSession.buffer.setText("")
editSession.insertText '{'
expect(buffer.lineForRow(0)).toBe "{}"
expect(editSession.getCursorBufferPosition()).toEqual([0,1])
editSession.buffer.setText("")
editSession.insertText '('
expect(buffer.lineForRow(0)).toBe "()"
expect(editSession.getCursorBufferPosition()).toEqual([0,1])
editSession.buffer.setText("")
editSession.insertText '['
expect(buffer.lineForRow(0)).toBe "[]"
expect(editSession.getCursorBufferPosition()).toEqual([0,1])
editSession.buffer.setText("")
editSession.insertText '"'
expect(buffer.lineForRow(0)).toBe '""'
expect(editSession.getCursorBufferPosition()).toEqual([0,1])
editSession.buffer.setText("")
editSession.insertText "'"
expect(buffer.lineForRow(0)).toBe "''"
expect(editSession.getCursorBufferPosition()).toEqual([0,1])
describe "when the cursor is on a closing bracket and a closing bracket is inserted", ->
describe "when the closing bracket was there previously", ->
it "inserts a closing bracket", ->
editSession.insertText '()x'
editSession.setCursorBufferPosition([0, 1])
editSession.insertText ')'
expect(buffer.lineForRow(0)).toBe "())x"
expect(editSession.getCursorBufferPosition().column).toBe 2
describe "when the closing bracket was automatically inserted from inserting an opening bracket", ->
it "only moves cursor over the closing bracket one time", ->
editSession.insertText '('
expect(buffer.lineForRow(0)).toBe "()"
editSession.setCursorBufferPosition([0, 1])
editSession.insertText ')'
expect(buffer.lineForRow(0)).toBe "()"
expect(editSession.getCursorBufferPosition()).toEqual [0, 2]
editSession.setCursorBufferPosition([0, 1])
editSession.insertText ')'
expect(buffer.lineForRow(0)).toBe "())"
expect(editSession.getCursorBufferPosition()).toEqual [0, 2]
it "moves cursor over the closing bracket after other text is inserted", ->
editSession.insertText '('
editSession.insertText 'ok cool'
expect(buffer.lineForRow(0)).toBe "(ok cool)"
editSession.setCursorBufferPosition([0, 8])
editSession.insertText ')'
expect(buffer.lineForRow(0)).toBe "(ok cool)"
expect(editSession.getCursorBufferPosition()).toEqual [0, 9]
it "works with nested brackets", ->
editSession.insertText '('
editSession.insertText '1'
editSession.insertText '('
editSession.insertText '2'
expect(buffer.lineForRow(0)).toBe "(1(2))"
editSession.setCursorBufferPosition([0, 4])
editSession.insertText ')'
expect(buffer.lineForRow(0)).toBe "(1(2))"
expect(editSession.getCursorBufferPosition()).toEqual [0, 5]
editSession.insertText ')'
expect(buffer.lineForRow(0)).toBe "(1(2))"
expect(editSession.getCursorBufferPosition()).toEqual [0, 6]
it "works with mixed brackets", ->
editSession.insertText '('
editSession.insertText '}'
expect(buffer.lineForRow(0)).toBe "(})"
editSession.insertText ')'
expect(buffer.lineForRow(0)).toBe "(})"
expect(editSession.getCursorBufferPosition()).toEqual [0, 3]
it "closes brackets with the same begin/end character correctly", ->
editSession.insertText '"'
editSession.insertText 'ok'
expect(buffer.lineForRow(0)).toBe '"ok"'
expect(editSession.getCursorBufferPosition()).toEqual [0, 3]
editSession.insertText '"'
expect(buffer.lineForRow(0)).toBe '"ok"'
expect(editSession.getCursorBufferPosition()).toEqual [0, 4]
describe "when there is text selected on a single line", ->
it "wraps the selection with brackets", ->
editSession.insertText 'text'
editSession.moveCursorToBottom()
editSession.selectToTop()
editSession.selectAll()
editSession.insertText '('
expect('(text)').toBe buffer.getText()
expect(editSession.getSelectedBufferRange()).toEqual [[0, 1], [0, 5]]
expect(editSession.getSelection().isReversed()).toBeTruthy()
describe "when there is text selected on multiple lines", ->
it "wraps the selection with brackets", ->
editSession.insertText 'text\nabcd'
editSession.moveCursorToBottom()
editSession.selectToTop()
editSession.selectAll()
editSession.insertText '('
expect('(text\nabcd)').toBe buffer.getText()
expect(editSession.getSelectedBufferRange()).toEqual [[0, 1], [1, 4]]
expect(editSession.getSelection().isReversed()).toBeTruthy()
describe "when inserting a quote", ->
describe "when a word character is before the cursor", ->
it "does not automatically insert closing quote", ->
editSession.buffer.setText("abc")
editSession.setCursorBufferPosition([0, 3])
editSession.insertText '"'
expect(buffer.lineForRow(0)).toBe "abc\""
editSession.buffer.setText("abc")
editSession.setCursorBufferPosition([0, 3])
editSession.insertText '\''
expect(buffer.lineForRow(0)).toBe "abc\'"
describe "when a non word character is before the cursor", ->
it "automatically insert closing quote", ->
editSession.buffer.setText("ab@")
editSession.setCursorBufferPosition([0, 3])
editSession.insertText '"'
expect(buffer.lineForRow(0)).toBe "ab@\"\""
expect(editSession.getCursorBufferPosition()).toEqual [0, 4]
describe "when the cursor is on an empty line", ->
it "automatically insert closing quote", ->
editSession.buffer.setText("")
editSession.setCursorBufferPosition([0, 0])
editSession.insertText '"'
expect(buffer.lineForRow(0)).toBe "\"\""
expect(editSession.getCursorBufferPosition()).toEqual [0, 1]
describe "matching bracket deletion", ->
it "deletes the end bracket when it directly proceeds a begin bracket that is being backspaced", ->
buffer.setText("")
editSession.setCursorBufferPosition([0, 0])
editSession.insertText '{'
expect(buffer.lineForRow(0)).toBe "{}"
editSession.backspace()
expect(buffer.lineForRow(0)).toBe ""

View File

@@ -4,18 +4,12 @@ _ = require 'underscore'
module.exports =
class CommandLoggerView extends ScrollView
@activate: (rootView, state) ->
@instance = new CommandLoggerView(rootView)
@content: (rootView) ->
@div class: 'command-logger', tabindex: -1, =>
@h1 class: 'category-header', outlet: 'categoryHeader'
@h1 class: 'category-summary', outlet: 'categorySummary'
@div class: 'tree-map', outlet: 'treeMap'
@serialize: ->
@instance.serialize()
eventLog: null
ignoredEvents: [
'core:backspace'
@@ -30,7 +24,7 @@ class CommandLoggerView extends ScrollView
'tree-view:directory-modified'
]
initialize: (@rootView) ->
initialize: ->
super
@command 'core:cancel', => @detach()
@@ -176,7 +170,7 @@ class CommandLoggerView extends ScrollView
d3.select('.command-logger').on('click', -> zoom(root))
attach: ->
@rootView.append(this)
rootView.append(this)
@addTreeMap()
@focus()
@@ -184,8 +178,5 @@ class CommandLoggerView extends ScrollView
return if @detaching
@detaching = true
super
@rootView.focus()
rootView.focus()
@detaching = false
serialize: ->
eventLog: @eventLog

View File

@@ -1,18 +1,14 @@
DeferredAtomPackage = require 'deferred-atom-package'
$ = require 'jquery'
module.exports =
class CommandLogger extends DeferredAtomPackage
loadEvents: ['command-logger:toggle']
instanceClass: 'command-logger/src/command-logger-view'
activate: (rootView, state={})->
super
eventLog: {}
commandLoggerView: null
originalTrigger: null
activate: (state={})->
@eventLog = state.eventLog ? {}
rootView.command 'command-logger:clear-data', => @eventLog = {}
rootView.command 'command-logger:toggle', => @createView().toggle(@eventLog)
registerTriggeredEvent = (eventName) =>
eventNameLog = @eventLog[eventName]
@@ -23,10 +19,22 @@ class CommandLogger extends DeferredAtomPackage
@eventLog[eventName] = eventNameLog
eventNameLog.count++
eventNameLog.lastRun = new Date().getTime()
originalTrigger = $.fn.trigger
trigger = $.fn.trigger
@originalTrigger = trigger
$.fn.trigger = (eventName) ->
eventName = eventName.type if eventName.type
registerTriggeredEvent(eventName) if $(this).events()[eventName]
originalTrigger.apply(this, arguments)
trigger.apply(this, arguments)
onLoadEvent: (event, instance) -> instance.toggle(@eventLog)
deactivate: ->
$.fn.trigger = @originalTrigger if @originalTrigger?
@commandLoggerView = null
@eventLog = {}
serialize: ->
{@eventLog}
createView: ->
unless @commandLoggerView
CommandLoggerView = require 'command-logger/lib/command-logger-view'
@commandLoggerView = new CommandLoggerView

View File

@@ -0,0 +1 @@
'main': 'lib/command-logger'

View File

@@ -1,12 +1,13 @@
RootView = require 'root-view'
CommandLogger = require 'command-logger/src/command-logger-view'
CommandLogger = require 'command-logger/lib/command-logger-view'
describe "CommandLogger", ->
[rootView, commandLogger, editor] = []
[commandLogger, editor] = []
beforeEach ->
rootView = new RootView(require.resolve('fixtures/sample.js'))
commandLogger = atom.loadPackage('command-logger')
new RootView(require.resolve('fixtures/sample.js'))
commandLogger = atom.loadPackage('command-logger').packageMain
commandLogger.eventLog = {}
editor = rootView.getActiveEditor()
afterEach ->
@@ -43,7 +44,7 @@ describe "CommandLogger", ->
describe "when an event is ignored", ->
it "does not create a node for that event", ->
commandLoggerView = commandLogger.getInstance()
commandLoggerView = commandLogger.createView()
commandLoggerView.ignoredEvents.push 'editor:delete-line'
editor.trigger 'editor:delete-line'
commandLoggerView.eventLog = commandLogger.eventLog

View File

@@ -1,10 +0,0 @@
DeferredAtomPackage = require 'deferred-atom-package'
module.exports =
class CommandPalette extends DeferredAtomPackage
loadEvents: ['command-palette:toggle']
instanceClass: 'command-palette/src/command-palette-view'
onLoadEvent: (event, instance) -> instance.attach()

View File

@@ -5,8 +5,8 @@ _ = require 'underscore'
module.exports =
class CommandPaletteView extends SelectList
@activate: (rootView) ->
@instance = new CommandPaletteView(rootView)
@activate: ->
new CommandPaletteView
@viewClass: ->
"#{super} command-palette overlay from-top"
@@ -16,12 +16,17 @@ class CommandPaletteView extends SelectList
previouslyFocusedElement: null
keyBindings: null
initialize: (@rootView) ->
@command 'command-palette:toggle', =>
@cancel()
false
initialize: ->
super
rootView.command 'command-palette:toggle', => @toggle()
toggle: ->
if @hasParent()
@cancel()
else
@attach()
attach: ->
super
@@ -34,7 +39,7 @@ class CommandPaletteView extends SelectList
events = _.sortBy events, (e) -> e.eventDescription
@setArray(events)
@appendTo(@rootView)
@appendTo(rootView)
@miniEditor.focus()
itemForElement: ({eventName, eventDescription}) ->

View File

@@ -0,0 +1,2 @@
'main': 'lib/command-palette-view'
'activationEvents': ['command-palette:toggle']

View File

@@ -1,17 +1,17 @@
RootView = require 'root-view'
CommandPalette = require 'command-palette/src/command-palette-view'
CommandPalette = require 'command-palette/lib/command-palette-view'
$ = require 'jquery'
_ = require 'underscore'
describe "CommandPalette", ->
[rootView, palette] = []
[palette] = []
beforeEach ->
rootView = new RootView(require.resolve('fixtures/sample.js'))
atom.loadPackage("command-palette").getInstance()
palette = CommandPalette.instance
atom.loadPackage("command-palette")
rootView.attachToDom().focus()
rootView.trigger 'command-palette:toggle'
palette = rootView.find('.command-palette').view()
afterEach ->
rootView.remove()

View File

@@ -1,33 +0,0 @@
DeferredAtomPackage = require 'deferred-atom-package'
module.exports =
class CommandPanel extends DeferredAtomPackage
loadEvents: [
'command-panel:toggle'
'command-panel:toggle-preview'
'command-panel:find-in-file'
'command-panel:find-in-project'
'command-panel:repeat-relative-address'
'command-panel:repeat-relative-address-in-reverse'
'command-panel:set-selection-as-regex-address'
]
instanceClass: 'command-panel/src/command-panel-view'
onLoadEvent: (event, instance) ->
switch event.type
when 'command-panel:toggle'
instance.toggle()
when 'command-panel:toggle-preview'
instance.togglePreview()
when 'command-panel:find-in-file'
instance.attach("/")
when 'command-panel:find-in-project'
instance.attach("Xx/")
when 'command-panel:repeat-relative-address'
instance.repeatRelativeAddress()
when 'command-panel:repeat-relative-address-in-reverse'
instance.repeatRelativeAddressInReverse()
when 'command-panel:set-selection-as-regex-address'
instance.setSelectionAsLastRelativeAddress()

View File

@@ -6,7 +6,7 @@ class CommandInterpreter
constructor: (@project) ->
eval: (string, activeEditSession) ->
@parser ?= PEG.buildParser(fs.read(require.resolve 'command-panel/commands.pegjs'))
@parser ?= PEG.buildParser(fs.read(require.resolve 'command-panel/lib/commands.pegjs'))
compositeCommand = @parser.parse(string)
@lastRelativeAddress = compositeCommand if compositeCommand.isRelativeAddress()
compositeCommand.execute(@project, activeEditSession)

View File

@@ -1,28 +1,15 @@
{View, $$, $$$} = require 'space-pen'
CommandInterpreter = require 'command-panel/src/command-interpreter'
RegexAddress = require 'command-panel/src/commands/regex-address'
CompositeCommand = require 'command-panel/src/commands/composite-command'
PreviewList = require 'command-panel/src/preview-list'
CommandInterpreter = require './command-interpreter'
RegexAddress = require './commands/regex-address'
CompositeCommand = require './commands/composite-command'
PreviewList = require './preview-list'
Editor = require 'editor'
{SyntaxError} = require('pegjs').parser
_ = require 'underscore'
module.exports =
class CommandPanelView extends View
@activate: (rootView, state) ->
if state?
@instance = @deserialize(state, rootView)
else
@instance = new CommandPanelView(rootView)
@deserialize: (state, rootView) ->
commandPanel = new CommandPanelView(rootView, state.history)
commandPanel.attach(state.text, focus: false) if state.visible
commandPanel.miniEditor.focus() if state.miniEditorFocused
commandPanel
@content: (rootView) ->
@content: ->
@div class: 'command-panel tool-panel', =>
@div outlet: 'previewCount', class: 'preview-count'
@subview 'previewList', new PreviewList(rootView)
@@ -36,38 +23,42 @@ class CommandPanelView extends View
historyIndex: 0
maxSerializedHistorySize: 100
initialize: (@rootView, @history) ->
@commandInterpreter = new CommandInterpreter(@rootView.project)
initialize: (state={}) ->
@commandInterpreter = new CommandInterpreter(rootView.project)
@history ?= []
@historyIndex = @history.length
@command 'tool-panel:unfocus', => @rootView.focus()
@command 'tool-panel:unfocus', => rootView.focus()
@command 'core:close', => @detach(); false
@command 'core:confirm', => @execute()
@command 'core:move-up', => @navigateBackwardInHistory()
@command 'core:move-down', => @navigateForwardInHistory()
rootView.command 'command-panel:toggle', => @toggle()
rootView.command 'command-panel:toggle-preview', => @togglePreview()
rootView.command 'command-panel:find-in-file', => @attach('/')
rootView.command 'command-panel:find-in-project', => @attach('Xx/')
rootView.command 'command-panel:repeat-relative-address', => @repeatRelativeAddress()
rootView.command 'command-panel:repeat-relative-address-in-reverse', => @repeatRelativeAddressInReverse()
rootView.command 'command-panel:set-selection-as-regex-address', => @setSelectionAsLastRelativeAddress()
@previewList.hide()
@previewCount.hide()
@errorMessages.hide()
@prompt.iconSize(@miniEditor.getFontSize())
@history = state.history ? []
@historyIndex = @history.length
serialize: ->
text: @miniEditor.getText()
visible: @hasParent()
miniEditorFocused: @miniEditor.isFocused
history: @history[-@maxSerializedHistorySize..]
deactivate: -> @destroy()
destroy: ->
@previewList.destroy()
toggle: ->
if @miniEditor.isFocused
@detach()
@rootView.focus()
rootView.focus()
else
@attach() unless @hasParent()
@miniEditor.focus()
@@ -77,7 +68,7 @@ class CommandPanelView extends View
@previewList.hide()
@previewCount.hide()
@detach()
@rootView.focus()
rootView.focus()
else
@attach() unless @hasParent()
if @previewList.hasOperations()
@@ -90,13 +81,13 @@ class CommandPanelView extends View
@errorMessages.hide()
focus = options.focus ? true
@rootView.vertical.append(this)
rootView.vertical.append(this)
@miniEditor.focus() if focus
@miniEditor.setText(text)
@miniEditor.setCursorBufferPosition([0, Infinity])
detach: ->
@rootView.focus()
rootView.focus()
@previewList.hide()
@previewCount.hide()
super
@@ -108,7 +99,7 @@ class CommandPanelView extends View
@errorMessages.empty()
try
@commandInterpreter.eval(command, @rootView.getActiveEditSession()).done ({operationsToPreview, errorMessages}) =>
@commandInterpreter.eval(command, rootView.getActiveEditSession()).done ({operationsToPreview, errorMessages}) =>
@history.push(command)
@historyIndex = @history.length
@@ -141,12 +132,12 @@ class CommandPanelView extends View
@miniEditor.setText(@history[@historyIndex] or '')
repeatRelativeAddress: ->
@commandInterpreter.repeatRelativeAddress(@rootView.getActiveEditSession())
@commandInterpreter.repeatRelativeAddress(rootView.getActiveEditSession())
repeatRelativeAddressInReverse: ->
@commandInterpreter.repeatRelativeAddressInReverse(@rootView.getActiveEditSession())
@commandInterpreter.repeatRelativeAddressInReverse(rootView.getActiveEditSession())
setSelectionAsLastRelativeAddress: ->
selection = @rootView.getActiveEditor().getSelectedText()
selection = rootView.getActiveEditor().getSelectedText()
regex = _.escapeRegExp(selection)
@commandInterpreter.lastRelativeAddress = new CompositeCommand([new RegexAddress(regex)])

View File

@@ -0,0 +1,17 @@
CommandPanelView = require './command-panel-view'
module.exports =
commandPanelView: null
activate: (@state) ->
@commandPanelView = new CommandPanelView(@state)
deactivate: ->
@commandPanelView?.destroy()
@commandPanelView = null
serialize: ->
if @commandPanelView?
@commandPanelView.serialize()
else
@state

View File

@@ -1,15 +1,15 @@
{
var CompositeCommand = require('command-panel/src/commands/composite-command')
var Substitution = require('command-panel/src/commands/substitution');
var ZeroAddress = require('command-panel/src/commands/zero-address');
var EofAddress = require('command-panel/src/commands/eof-address');
var LineAddress = require('command-panel/src/commands/line-address');
var AddressRange = require('command-panel/src/commands/address-range');
var DefaultAddressRange = require('command-panel/src/commands/default-address-range');
var CurrentSelectionAddress = require('command-panel/src/commands/current-selection-address')
var RegexAddress = require('command-panel/src/commands/regex-address')
var SelectAllMatches = require('command-panel/src/commands/select-all-matches')
var SelectAllMatchesInProject = require('command-panel/src/commands/select-all-matches-in-project')
var CompositeCommand = require('command-panel/lib/commands/composite-command')
var Substitution = require('command-panel/lib/commands/substitution');
var ZeroAddress = require('command-panel/lib/commands/zero-address');
var EofAddress = require('command-panel/lib/commands/eof-address');
var LineAddress = require('command-panel/lib/commands/line-address');
var AddressRange = require('command-panel/lib/commands/address-range');
var DefaultAddressRange = require('command-panel/lib/commands/default-address-range');
var CurrentSelectionAddress = require('command-panel/lib/commands/current-selection-address')
var RegexAddress = require('command-panel/lib/commands/regex-address')
var SelectAllMatches = require('command-panel/lib/commands/select-all-matches')
var SelectAllMatchesInProject = require('command-panel/lib/commands/select-all-matches-in-project')
}
start = _ commands:( selectAllMatchesInProject / textCommand ) {

View File

@@ -1,4 +1,4 @@
Address = require 'command-panel/src/commands/address'
Address = require 'command-panel/lib/commands/address'
Range = require 'range'
module.exports =

View File

@@ -1,5 +1,5 @@
Command = require 'command-panel/src/commands/command'
Operation = require 'command-panel/src/operation'
Command = require './command'
Operation = require 'command-panel/lib/operation'
$ = require 'jquery'
module.exports =

View File

@@ -1,5 +1,3 @@
_ = require 'underscore'
module.exports =
class Command
isAddress: -> false

View File

@@ -1,5 +1,4 @@
Address = require 'command-panel/src/commands/address'
Range = require 'range'
Address = require './address'
module.exports =
class CurrentSelectionAddress extends Address

View File

@@ -1,5 +1,4 @@
Address = require 'command-panel/src/commands/address'
Range = require 'range'
Address = require './address'
module.exports =
class DefaultAddressRange extends Address

View File

@@ -1,4 +1,4 @@
Address = require 'command-panel/src/commands/address'
Address = require './address'
Range = require 'range'
module.exports =

View File

@@ -1,4 +1,4 @@
Address = require 'command-panel/src/commands/address'
Address = require './address'
Range = require 'range'
module.exports =

View File

@@ -1,4 +1,4 @@
Address = require 'command-panel/src/commands/address'
Address = require './address'
Range = require 'range'
module.exports =

View File

@@ -1,5 +1,5 @@
Command = require 'command-panel/src/commands/command'
Operation = require 'command-panel/src/operation'
Command = require './command'
Operation = require 'command-panel/lib/operation'
$ = require 'jquery'
module.exports =

View File

@@ -1,5 +1,5 @@
Command = require 'command-panel/src/commands/command'
Operation = require 'command-panel/src/operation'
Command = require './command'
Operation = require 'command-panel/lib/operation'
$ = require 'jquery'
module.exports =

View File

@@ -1,5 +1,5 @@
Command = require 'command-panel/src/commands/command'
Operation = require 'command-panel/src/operation'
Command = require './command'
Operation = require 'command-panel/lib/operation'
$ = require 'jquery'
module.exports =

View File

@@ -1,4 +1,4 @@
Address = require 'command-panel/src/commands/address'
Address = require './address'
Range = require 'range'
module.exports =

View File

@@ -1,5 +1,3 @@
{$$$} = require 'space-pen'
module.exports =
class Operation
constructor: ({@project, @buffer, bufferRange, @newText, @preserveSelection, @errorMessage}) ->

View File

@@ -0,0 +1,10 @@
'main': 'lib/command-panel'
'activationEvents': [
'command-panel:toggle'
'command-panel:toggle-preview'
'command-panel:find-in-file'
'command-panel:find-in-project'
'command-panel:repeat-relative-address'
'command-panel:repeat-relative-address-in-reverse'
'command-panel:set-selection-as-regex-address'
]

View File

@@ -1,4 +1,4 @@
CommandInterpreter = require 'command-panel/src/command-interpreter'
CommandInterpreter = require 'command-panel/lib/command-interpreter'
Project = require 'project'
Buffer = require 'buffer'
EditSession = require 'edit-session'

View File

@@ -1,19 +1,19 @@
RootView = require 'root-view'
CommandPanelView = require 'command-panel/src/command-panel-view'
CommandPanelView = require 'command-panel/lib/command-panel-view'
_ = require 'underscore'
describe "CommandPanel", ->
[rootView, editor, buffer, commandPanel, project, CommandPanel] = []
[editor, buffer, commandPanel, project, CommandPanel] = []
beforeEach ->
rootView = new RootView
new RootView
rootView.open(require.resolve 'fixtures/sample.js')
rootView.enableKeymap()
project = rootView.project
editor = rootView.getActiveEditor()
buffer = editor.activeEditSession.buffer
CommandPanel = atom.loadPackage('command-panel')
commandPanel = CommandPanel.getInstance()
commandPanelMain = atom.loadPackage('command-panel', activateImmediately: true).packageMain
commandPanel = commandPanelMain.commandPanelView
commandPanel.history = []
commandPanel.historyIndex = 0
@@ -21,7 +21,7 @@ describe "CommandPanel", ->
rootView.deactivate()
describe "serialization", ->
it "preserves the command panel's mini-editor text, visibility, focus, and history across reloads", ->
it "preserves the command panel's history across reloads", ->
rootView.attachToDom()
rootView.trigger 'command-panel:toggle'
expect(commandPanel.miniEditor.isFocused).toBeTruthy()
@@ -31,29 +31,20 @@ describe "CommandPanel", ->
expect(commandPanel.historyIndex).toBe(1)
rootView.trigger 'command-panel:toggle'
expect(commandPanel.miniEditor.isFocused).toBeTruthy()
commandPanel.miniEditor.insertText 'abc'
rootView2 = RootView.deserialize(rootView.serialize())
rootView.deactivate()
rootView2.attachToDom()
commandPanel = rootView2.activatePackage('command-panel', CommandPanel).getInstance()
expect(rootView2.find('.command-panel')).toExist()
expect(commandPanel.miniEditor.getText()).toBe 'abc'
expect(commandPanel.miniEditor.isFocused).toBeTruthy()
rootViewState = rootView.serialize()
rootView.deactivate()
RootView.deserialize(rootViewState).attachToDom()
atom.loadPackage('command-panel')
expect(rootView.find('.command-panel')).not.toExist()
rootView.trigger 'command-panel:toggle'
expect(rootView.find('.command-panel')).toExist()
commandPanel = rootView.find('.command-panel').view()
expect(commandPanel.history.length).toBe(1)
expect(commandPanel.history[0]).toBe('/.')
expect(commandPanel.historyIndex).toBe(1)
rootView2.focus()
expect(commandPanel.miniEditor.isFocused).toBeFalsy()
rootView3 = RootView.deserialize(rootView2.serialize())
rootView2.deactivate()
rootView3.attachToDom()
commandPanel = rootView3.activatePackage('command-panel', CommandPanel).getInstance()
expect(commandPanel.miniEditor.isFocused).toBeFalsy()
rootView3.deactivate()
it "only retains the configured max serialized history size", ->
rootView.attachToDom()
@@ -67,18 +58,18 @@ describe "CommandPanel", ->
expect(commandPanel.history[2]).toBe('/test3')
expect(commandPanel.historyIndex).toBe(3)
rootView2 = RootView.deserialize(rootView.serialize())
rootViewState = rootView.serialize()
rootView.deactivate()
rootView2.attachToDom()
RootView.deserialize(rootViewState).attachToDom()
atom.loadPackage('command-panel')
rootView.trigger 'command-panel:toggle'
commandPanel = rootView2.activatePackage('command-panel', CommandPanel).getInstance()
commandPanel = rootView.find('.command-panel').view()
expect(commandPanel.history.length).toBe(2)
expect(commandPanel.history[0]).toBe('/test2')
expect(commandPanel.history[1]).toBe('/test3')
expect(commandPanel.historyIndex).toBe(2)
rootView2.deactivate()
describe "when core:close is triggered on the command panel", ->
it "detaches the command panel, focuses the RootView and does not bubble the core:close event", ->
commandPanel.attach()

View File

@@ -1,16 +0,0 @@
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

@@ -5,10 +5,10 @@ $ = require 'jquery'
module.exports =
class EditorStatsView extends ScrollView
@activate: (rootView, state) ->
@instance = new EditorStatsView(rootView)
@activate: ->
new EditorStatsView
@content: (rootView) ->
@content: ->
@div class: 'editor-stats-wrapper', tabindex: -1, =>
@div class: 'editor-stats', outlet: 'editorStats'
@@ -17,7 +17,7 @@ class EditorStatsView extends ScrollView
pb: 3
pr: 25
initialize: (@rootView) ->
initialize: ->
super
resizer = =>
@@ -30,7 +30,7 @@ class EditorStatsView extends ScrollView
@editorStats.empty()
@x ?= d3.scale.ordinal().domain d3.range(@stats.hours * 60)
@y ?= d3.scale.linear()
w = @rootView.vertical.width()
w = rootView.vertical.width()
h = @height()
data = d3.entries @stats.eventLog
max = d3.max data, (d) -> d.value
@@ -94,10 +94,10 @@ class EditorStatsView extends ScrollView
@attach()
attach: ->
@rootView.vertical.append(@)
rootView.vertical.append(this)
@draw()
detach: ->
super()
super
clearInterval(@updateInterval)
@rootView.focus()
rootView.focus()

View File

@@ -0,0 +1,19 @@
StatsTracker = require './stats-tracker'
module.exports =
stats: null
editorStatsView: null
activate: ->
@stats = new StatsTracker()
rootView.command 'editor-stats:toggle', => @createView().toggle(@stats)
deactivate: ->
@editorStatsView = null
@stats = null
createView: ->
unless @editorStatsView
EditorStatsView = require 'editor-stats/lib/editor-stats-view'
@editorStatsView = new EditorStatsView()
@editorStatsView

View File

@@ -1,5 +1,5 @@
module.exports =
class Stats
class StatsTracker
startDate: new Date
hours: 6
eventLog: []
@@ -12,6 +12,9 @@ class Stats
while date < future
@eventLog[@time(date)] = 0
rootView.on 'keydown', => @track()
rootView.on 'mouseup', => @track()
clear: ->
@eventLog = []

View File

@@ -0,0 +1 @@
'main': 'lib/editor-stats'

View File

@@ -1,9 +1,9 @@
$ = require 'jquery'
RootView = require 'root-view'
EditorStats = require 'editor-stats/src/editor-stats-view'
EditorStats = require 'editor-stats/lib/editor-stats-view'
describe "EditorStats", ->
[rootView, editorStats, time] = []
[editorStats, time] = []
simulateKeyUp = (key) ->
e = $.Event "keydown", keyCode: key.charCodeAt(0)
@@ -23,10 +23,7 @@ describe "EditorStats", ->
mins = if mins == 60 then '01' else mins + 1
time = "#{hours}:#{mins}"
editorStatsPackage = atom.loadPackage('editor-stats')
editorStatsPackage.getInstance()
editorStats = editorStatsPackage.stats
editorStats.clear()
editorStats = atom.loadPackage('editor-stats').packageMain.stats
afterEach ->
rootView.deactivate()

View File

@@ -0,0 +1,32 @@
module.exports =
class StatsTracker
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
rootView.on 'keydown', => @track()
rootView.on 'mouseup', => @track()
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

@@ -1,32 +0,0 @@
DeferredAtomPackage = require 'deferred-atom-package'
module.exports =
class FuzzyFinder extends DeferredAtomPackage
loadEvents: [
'fuzzy-finder:toggle-file-finder'
'fuzzy-finder:toggle-buffer-finder'
'fuzzy-finder:find-under-cursor'
]
instanceClass: 'fuzzy-finder/src/fuzzy-finder-view'
activate: (rootView) ->
super
if rootView.project.getPath()?
callback = (paths) => @projectPaths = paths
LoadPathsTask = require 'fuzzy-finder/src/load-paths-task'
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()
when 'fuzzy-finder:toggle-buffer-finder'
instance.toggleBufferFinder()
when 'fuzzy-finder:find-under-cursor'
instance.findUnderCursor()

View File

@@ -3,15 +3,12 @@ SelectList = require 'select-list'
_ = require 'underscore'
$ = require 'jquery'
fs = require 'fs'
LoadPathsTask = require 'fuzzy-finder/src/load-paths-task'
LoadPathsTask = require './load-paths-task'
module.exports =
class FuzzyFinderView extends SelectList
filenameRegex: /[\w\.\-\/\\]+/
@activate: (rootView) ->
@instance = new FuzzyFinderView(rootView)
@viewClass: ->
[super, 'fuzzy-finder', 'overlay', 'from-top'].join(' ')
@@ -20,7 +17,7 @@ class FuzzyFinderView extends SelectList
projectPaths: null
reloadProjectPaths: true
initialize: (@rootView) ->
initialize: ->
super
@subscribe $(window), 'focus', => @reloadProjectPaths = true
@@ -54,15 +51,15 @@ class FuzzyFinderView extends SelectList
@span " - #{folder}/", class: 'directory'
openPath: (path) ->
@rootView.open(path, {@allowActiveEditorChange}) if path
rootView.open(path, {@allowActiveEditorChange}) if path
splitOpenPath: (fn) ->
path = @getSelectedElement()
return unless path
editor = @rootView.getActiveEditor()
editor = rootView.getActiveEditor()
if editor
fn(editor, @rootView.project.buildEditSessionForPath(path))
fn(editor, rootView.project.buildEditSessionForPath(path))
else
@openPath(path)
@@ -79,7 +76,7 @@ class FuzzyFinderView extends SelectList
if @hasParent()
@cancel()
else
return unless @rootView.project.getPath()?
return unless rootView.project.getPath()?
@allowActiveEditorChange = false
@populateProjectPaths()
@attach()
@@ -96,9 +93,9 @@ class FuzzyFinderView extends SelectList
if @hasParent()
@cancel()
else
return unless @rootView.project.getPath()?
return unless rootView.project.getPath()?
@allowActiveEditorChange = false
editor = @rootView.getActiveEditor()
editor = rootView.getActiveEditor()
currentWord = editor.getWordUnderCursor(wordRegex: @filenameRegex)
if currentWord.length == 0
@@ -110,7 +107,7 @@ class FuzzyFinderView extends SelectList
@attach()
@setError("No files match '#{currentWord}'")
else if paths.length == 1
@rootView.open(paths[0])
rootView.open(paths[0])
else
@attach()
@miniEditor.setText(currentWord)
@@ -142,16 +139,21 @@ class FuzzyFinderView extends SelectList
@setArray(listedItems)
options.done(listedItems) if options.done?
@loadPathsTask = new LoadPathsTask(@rootView, callback)
@loadPathsTask = new LoadPathsTask(callback)
@loadPathsTask.start()
populateOpenBufferPaths: ->
@paths = @rootView.getOpenBufferPaths().map (path) =>
@rootView.project.relativize(path)
@paths = rootView.getOpenBufferPaths().map (path) =>
rootView.project.relativize(path)
@setArray(@paths)
detach: ->
super
@loadPathsTask?.terminate()
attach: ->
super
@rootView.append(this)
rootView.append(this)
@miniEditor.focus()

View File

@@ -0,0 +1,32 @@
module.exports =
projectPaths: null
fuzzyFinderView: null
activate: ->
rootView.command 'fuzzy-finder:toggle-file-finder', =>
@createView().toggleFileFinder()
rootView.command 'fuzzy-finder:toggle-buffer-finder', =>
@createView().toggleBufferFinder()
rootView.command 'fuzzy-finder:find-under-cursor', =>
@createView().findUnderCursor()
if rootView.project.getPath()?
LoadPathsTask = require 'fuzzy-finder/lib/load-paths-task'
@loadPathsTask = new LoadPathsTask((paths) => @projectPaths = paths)
@loadPathsTask.start()
deactivate: ->
@loadPathsTask?.terminate()
@fuzzyFinderView?.cancel()
@fuzzyFinderView = null
@projectPaths = null
@fuzzyFinderView = null
createView: ->
unless @fuzzyFinderView
FuzzyFinderView = require 'fuzzy-finder/lib/fuzzy-finder-view'
@fuzzyFinderView = new FuzzyFinderView()
if @projectPaths? and not @fuzzyFinderView.projectPaths?
@fuzzyFinderView.projectPaths = @projectPaths
@fuzzyFinderView.reloadProjectPaths = false
@fuzzyFinderView

View File

@@ -1,11 +1,13 @@
fs = require 'fs'
_ = require 'underscore'
Git = require 'git'
module.exports =
loadPaths: (rootPath, ignoredNames, excludeGitIgnoredPaths) ->
if excludeGitIgnoredPaths
Git = require 'git'
repo = Git.open(rootPath, refreshIndexOnFocus: false)
paths = []
repo = Git.open(rootPath, refreshIndexOnFocus: false) if excludeGitIgnoredPaths
isIgnored = (path) ->
for segment in path.split('/')
return true if _.contains(ignoredNames, segment)
@@ -15,5 +17,7 @@ module.exports =
onDirectory = (path) ->
not isIgnored(path)
fs.traverseTree(rootPath, onFile, onDirectory)
repo?.destroy()
callTaskMethod('pathsLoaded', paths)

View File

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

View File

@@ -0,0 +1 @@
'main': 'lib/fuzzy-finder'

View File

@@ -1,21 +1,20 @@
RootView = require 'root-view'
FuzzyFinder = require 'fuzzy-finder/src/fuzzy-finder-view'
LoadPathsTask = require 'fuzzy-finder/src/load-paths-task'
FuzzyFinder = require 'fuzzy-finder/lib/fuzzy-finder-view'
LoadPathsTask = require 'fuzzy-finder/lib/load-paths-task'
$ = require 'jquery'
{$$} = require 'space-pen'
fs = require 'fs'
describe 'FuzzyFinder', ->
[rootView, finder] = []
[finderView] = []
beforeEach ->
rootView = new RootView(require.resolve('fixtures/sample.js'))
rootView.enableKeymap()
atom.loadPackage("fuzzy-finder").getInstance()
finder = FuzzyFinder.instance
finderView = atom.loadPackage("fuzzy-finder").packageMain.createView()
afterEach ->
rootView.remove()
rootView.deactivate()
describe "file-finder behavior", ->
describe "toggling", ->
@@ -26,12 +25,13 @@ describe 'FuzzyFinder', ->
rootView.find('.editor').trigger 'editor:split-right'
[editor1, editor2] = rootView.find('.editor').map -> $(this).view()
expect(rootView.find('.fuzzy-finder')).not.toExist()
rootView.trigger 'fuzzy-finder:toggle-file-finder'
expect(rootView.find('.fuzzy-finder')).toExist()
expect(finder.miniEditor.isFocused).toBeTruthy()
expect(finderView.miniEditor.isFocused).toBeTruthy()
expect(editor1.isFocused).toBeFalsy()
expect(editor2.isFocused).toBeFalsy()
finder.miniEditor.insertText('this should not show up next time we toggle')
finderView.miniEditor.insertText('this should not show up next time we toggle')
rootView.trigger 'fuzzy-finder:toggle-file-finder'
expect(editor1.isFocused).toBeFalsy()
@@ -39,27 +39,27 @@ describe 'FuzzyFinder', ->
expect(rootView.find('.fuzzy-finder')).not.toExist()
rootView.trigger 'fuzzy-finder:toggle-file-finder'
expect(finder.miniEditor.getText()).toBe ''
expect(finderView.miniEditor.getText()).toBe ''
it "shows all relative file paths for the current project and selects the first", ->
rootView.attachToDom()
finder.maxItems = Infinity
finderView.maxItems = Infinity
rootView.trigger 'fuzzy-finder:toggle-file-finder'
paths = null
expect(finder.find(".loading")).toBeVisible()
expect(finder.find(".loading")).toHaveText "Indexing..."
expect(finderView.find(".loading")).toBeVisible()
expect(finderView.find(".loading")).toHaveText "Indexing..."
waitsFor "all project paths to load", 5000, ->
if finder.projectPaths?.length > 0
paths = finder.projectPaths
if finderView.projectPaths?.length > 0
paths = finderView.projectPaths
true
runs ->
expect(finder.list.children('li').length).toBe paths.length
expect(finderView.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'
expect(finder.find(".loading")).not.toBeVisible()
expect(finderView.list.find("li:contains(#{fs.base(path)})")).toExist()
expect(finderView.list.children().first()).toHaveClass 'selected'
expect(finderView.find(".loading")).not.toBeVisible()
describe "when root view's project has no path", ->
beforeEach ->
@@ -78,10 +78,10 @@ describe 'FuzzyFinder', ->
expect(rootView.getActiveEditor()).toBe editor2
rootView.trigger 'fuzzy-finder:toggle-file-finder'
finder.confirmed('dir/a')
finderView.confirmed('dir/a')
expectedPath = fixturesProject.resolve('dir/a')
expect(finder.hasParent()).toBeFalsy()
expect(finderView.hasParent()).toBeFalsy()
expect(editor1.getPath()).not.toBe expectedPath
expect(editor2.getPath()).toBe expectedPath
expect(editor2.isFocused).toBeTruthy()
@@ -91,12 +91,12 @@ describe 'FuzzyFinder', ->
rootView.attachToDom()
path = rootView.getActiveEditor().getPath()
rootView.trigger 'fuzzy-finder:toggle-file-finder'
finder.confirmed('dir/this/is/not/a/file.txt')
expect(finder.hasParent()).toBeTruthy()
finderView.confirmed('dir/this/is/not/a/file.txt')
expect(finderView.hasParent()).toBeTruthy()
expect(rootView.getActiveEditor().getPath()).toBe path
expect(finder.find('.error').text().length).toBeGreaterThan 0
expect(finderView.find('.error').text().length).toBeGreaterThan 0
advanceClock(2000)
expect(finder.find('.error').text().length).toBe 0
expect(finderView.find('.error').text().length).toBe 0
describe "buffer-finder behavior", ->
describe "toggling", ->
@@ -113,7 +113,7 @@ describe 'FuzzyFinder', ->
rootView.trigger 'fuzzy-finder:toggle-buffer-finder'
expect(rootView.find('.fuzzy-finder')).toExist()
expect(rootView.find('.fuzzy-finder input:focus')).toExist()
finder.miniEditor.insertText('this should not show up next time we toggle')
finderView.miniEditor.insertText('this should not show up next time we toggle')
rootView.trigger 'fuzzy-finder:toggle-buffer-finder'
expect(editor1.isFocused).toBeFalsy()
@@ -121,14 +121,14 @@ describe 'FuzzyFinder', ->
expect(rootView.find('.fuzzy-finder')).not.toExist()
rootView.trigger 'fuzzy-finder:toggle-buffer-finder'
expect(finder.miniEditor.getText()).toBe ''
expect(finderView.miniEditor.getText()).toBe ''
it "lists the paths of the current open buffers", ->
rootView.trigger 'fuzzy-finder:toggle-buffer-finder'
expect(finder.list.children('li').length).toBe 2
expect(finder.list.find("li:contains(sample.js)")).toExist()
expect(finder.list.find("li:contains(sample.txt)")).toExist()
expect(finder.list.children().first()).toHaveClass 'selected'
expect(finderView.list.children('li').length).toBe 2
expect(finderView.list.find("li:contains(sample.js)")).toExist()
expect(finderView.list.find("li:contains(sample.txt)")).toExist()
expect(finderView.list.children().first()).toHaveClass 'selected'
describe "when the active editor only contains edit sessions for anonymous buffers", ->
it "does not open", ->
@@ -162,9 +162,9 @@ describe 'FuzzyFinder', ->
describe "when there is an edit session for the confirmed path in the active editor", ->
it "switches the active editor to the edit session for the selected path", ->
expectedPath = fixturesProject.resolve('sample.txt')
finder.confirmed('sample.txt')
finderView.confirmed('sample.txt')
expect(finder.hasParent()).toBeFalsy()
expect(finderView.hasParent()).toBeFalsy()
expect(editor1.getPath()).not.toBe expectedPath
expect(editor2.getPath()).toBe expectedPath
expect(editor2.isFocused).toBeTruthy()
@@ -178,9 +178,9 @@ describe 'FuzzyFinder', ->
expect(rootView.getActiveEditor()).toBe editor1
expectedPath = fixturesProject.resolve('sample.txt')
finder.confirmed('sample.txt')
finderView.confirmed('sample.txt')
expect(finder.hasParent()).toBeFalsy()
expect(finderView.hasParent()).toBeFalsy()
expect(editor1.getPath()).not.toBe expectedPath
expect(editor2.getPath()).toBe expectedPath
expect(editor2.isFocused).toBeTruthy()
@@ -194,31 +194,31 @@ describe 'FuzzyFinder', ->
activeEditor.focus()
rootView.trigger 'fuzzy-finder:toggle-file-finder'
expect(finder.hasParent()).toBeTruthy()
expect(finderView.hasParent()).toBeTruthy()
expect(activeEditor.isFocused).toBeFalsy()
expect(finder.miniEditor.isFocused).toBeTruthy()
expect(finderView.miniEditor.isFocused).toBeTruthy()
finder.cancel()
finderView.cancel()
expect(finder.hasParent()).toBeFalsy()
expect(finderView.hasParent()).toBeFalsy()
expect(activeEditor.isFocused).toBeTruthy()
expect(finder.miniEditor.isFocused).toBeFalsy()
expect(finderView.miniEditor.isFocused).toBeFalsy()
describe "when no editors are open", ->
it "detaches the finder and surrenders focus to the body", ->
it "detaches the finder and focuses the previously focused element", ->
rootView.attachToDom()
rootView.getActiveEditor().destroyActiveEditSession()
rootView.trigger 'fuzzy-finder:toggle-file-finder'
expect(finder.hasParent()).toBeTruthy()
expect(finderView.hasParent()).toBeTruthy()
expect(rootView.isFocused).toBeFalsy()
expect(finder.miniEditor.isFocused).toBeTruthy()
expect(finderView.miniEditor.isFocused).toBeTruthy()
finder.cancel()
finderView.cancel()
expect(finder.hasParent()).toBeFalsy()
expect(document.activeElement).toBe $('body')[0]
expect(finder.miniEditor.isFocused).toBeFalsy()
expect(finderView.hasParent()).toBeFalsy()
expect($(document.activeElement).view()).toBe rootView
expect(finderView.miniEditor.isFocused).toBeFalsy()
describe "cached file paths", ->
it "caches file paths after first time", ->
@@ -226,26 +226,26 @@ describe 'FuzzyFinder', ->
rootView.trigger 'fuzzy-finder:toggle-file-finder'
waitsFor ->
finder.list.children('li').length > 0
finderView.list.children('li').length > 0
runs ->
expect(finder.loadPathsTask.start).toHaveBeenCalled()
finder.loadPathsTask.start.reset()
expect(finderView.loadPathsTask.start).toHaveBeenCalled()
finderView.loadPathsTask.start.reset()
rootView.trigger 'fuzzy-finder:toggle-file-finder'
rootView.trigger 'fuzzy-finder:toggle-file-finder'
waitsFor ->
finder.list.children('li').length > 0
finderView.list.children('li').length > 0
runs ->
expect(finder.loadPathsTask.start).not.toHaveBeenCalled()
expect(finderView.loadPathsTask.start).not.toHaveBeenCalled()
it "doesn't cache buffer paths", ->
spyOn(rootView, "getOpenBufferPaths").andCallThrough()
rootView.trigger 'fuzzy-finder:toggle-buffer-finder'
waitsFor ->
finder.list.children('li').length > 0
finderView.list.children('li').length > 0
runs ->
expect(rootView.getOpenBufferPaths).toHaveBeenCalled()
@@ -254,7 +254,7 @@ describe 'FuzzyFinder', ->
rootView.trigger 'fuzzy-finder:toggle-buffer-finder'
waitsFor ->
finder.list.children('li').length > 0
finderView.list.children('li').length > 0
runs ->
expect(rootView.getOpenBufferPaths).toHaveBeenCalled()
@@ -264,27 +264,27 @@ describe 'FuzzyFinder', ->
rootView.trigger 'fuzzy-finder:toggle-file-finder'
waitsFor ->
finder.list.children('li').length > 0
finderView.list.children('li').length > 0
runs ->
expect(finder.loadPathsTask.start).toHaveBeenCalled()
finder.loadPathsTask.start.reset()
expect(finderView.loadPathsTask.start).toHaveBeenCalled()
finderView.loadPathsTask.start.reset()
$(window).trigger 'focus'
rootView.trigger 'fuzzy-finder:toggle-file-finder'
rootView.trigger 'fuzzy-finder:toggle-file-finder'
expect(finder.loadPathsTask.start).toHaveBeenCalled()
expect(finderView.loadPathsTask.start).toHaveBeenCalled()
describe "path ignoring", ->
it "ignores paths that match entries in config.fuzzyFinder.ignoredNames", ->
config.set("fuzzyFinder.ignoredNames", ["tree-view.js"])
rootView.trigger 'fuzzy-finder:toggle-file-finder'
finder.maxItems = Infinity
finderView.maxItems = Infinity
waitsFor ->
finder.list.children('li').length > 0
finderView.list.children('li').length > 0
runs ->
expect(finder.list.find("li:contains(tree-view.js)")).not.toExist()
expect(finderView.list.find("li:contains(tree-view.js)")).not.toExist()
describe "fuzzy find by content under cursor", ->
editor = null
@@ -298,10 +298,10 @@ describe 'FuzzyFinder', ->
rootView.trigger 'fuzzy-finder:find-under-cursor'
waitsFor ->
finder.list.children('li').length > 0
finderView.list.children('li').length > 0
runs ->
expect(finder).toBeVisible()
expect(finderView).toBeVisible()
expect(rootView.find('.fuzzy-finder input:focus')).toExist()
it "opens a file directly when there is a single match", ->
@@ -316,7 +316,7 @@ describe 'FuzzyFinder', ->
openedPath != null
runs ->
expect(finder).not.toBeVisible()
expect(finderView).not.toBeVisible()
expect(openedPath).toBe "sample.txt"
it "displays error when the word under the cursor doesn't match any files", ->
@@ -326,10 +326,10 @@ describe 'FuzzyFinder', ->
rootView.trigger 'fuzzy-finder:find-under-cursor'
waitsFor ->
finder.is(':visible')
finderView.is(':visible')
runs ->
expect(finder.find('.error').text().length).toBeGreaterThan 0
expect(finderView.find('.error').text().length).toBeGreaterThan 0
it "displays error when there is no word under the cursor", ->
editor.setText("&&&&&&&&&&&&&&& sample")
@@ -338,10 +338,10 @@ describe 'FuzzyFinder', ->
rootView.trigger 'fuzzy-finder:find-under-cursor'
waitsFor ->
finder.is(':visible')
finderView.is(':visible')
runs ->
expect(finder.find('.error').text().length).toBeGreaterThan 0
expect(finderView.find('.error').text().length).toBeGreaterThan 0
describe "opening a path into a split", ->
@@ -354,7 +354,7 @@ describe 'FuzzyFinder', ->
spyOn(editor, "splitLeft").andCallThrough()
expect(rootView.find('.editor').length).toBe 1
rootView.trigger 'fuzzy-finder:toggle-buffer-finder'
finder.miniEditor.trigger 'editor:split-left'
finderView.miniEditor.trigger 'editor:split-left'
expect(rootView.find('.editor').length).toBe 2
expect(editor.splitLeft).toHaveBeenCalled()
expect(rootView.getActiveEditor()).not.toBe editor
@@ -365,7 +365,7 @@ describe 'FuzzyFinder', ->
spyOn(editor, "splitRight").andCallThrough()
expect(rootView.find('.editor').length).toBe 1
rootView.trigger 'fuzzy-finder:toggle-buffer-finder'
finder.miniEditor.trigger 'editor:split-right'
finderView.miniEditor.trigger 'editor:split-right'
expect(rootView.find('.editor').length).toBe 2
expect(editor.splitRight).toHaveBeenCalled()
expect(rootView.getActiveEditor()).not.toBe editor
@@ -376,7 +376,7 @@ describe 'FuzzyFinder', ->
spyOn(editor, "splitDown").andCallThrough()
expect(rootView.find('.editor').length).toBe 1
rootView.trigger 'fuzzy-finder:toggle-buffer-finder'
finder.miniEditor.trigger 'editor:split-down'
finderView.miniEditor.trigger 'editor:split-down'
expect(rootView.find('.editor').length).toBe 2
expect(editor.splitDown).toHaveBeenCalled()
expect(rootView.getActiveEditor()).not.toBe editor
@@ -387,8 +387,8 @@ describe 'FuzzyFinder', ->
spyOn(editor, "splitUp").andCallThrough()
expect(rootView.find('.editor').length).toBe 1
rootView.trigger 'fuzzy-finder:toggle-buffer-finder'
finder.miniEditor.trigger 'editor:split-up'
finderView.miniEditor.trigger 'editor:split-up'
expect(rootView.find('.editor').length).toBe 2
expect(editor.splitUp).toHaveBeenCalled()
expect(rootView.getActiveEditor()).not.toBe editor
expect(rootView.getActiveEditor().getPath()).toBe editor.getPath()
expect(rootView.getActiveEditor().getPath()).toBe editor.getPath()

View File

@@ -0,0 +1,62 @@
'name': 'GitHub Markdown'
'scopeName': 'source.gfm'
'fileTypes': [
'markdown'
'md'
'mkd'
'mkdown'
'ron'
]
'patterns': [
{
'match': '\\*\\*[^\\*]+\\*\\*'
'name': 'markup.bold.gfm'
}
{
'match': '__[^_]+__'
'name': 'markup.bold.gfm'
}
{
'match': '\\*[^\\*]+\\*'
'name': 'markup.italic.gfm'
}
{
'match': '_[^_]+_'
'name': 'markup.italic.gfm'
}
{
'match': '^#{1,6}\\s+.+$'
'name': 'markup.heading.gfm'
}
{
'match': '\\:[^\\:]+\\:'
'name': 'variable.emoji.gfm'
}
{
'begin': '^```.*$'
'beginCaptures':
'0': 'name': 'support.gfm'
'end': '^```$'
'endCaptures':
'0': 'name': 'support.gfm'
'patterns': [
'match': '.*'
'name': 'markup.raw.gfm'
]
}
{
'match': '`[^`]+`'
'name': 'markup.raw.gfm'
}
{
'match': '\\!?\\[([^\\]]*)\\]\\(([^\\)]+)\\)'
'captures':
'1': 'name': 'entity.gfm'
'2': 'name': 'markup.underline.gfm'
}
{
'match': '^\\s*([\\*\\+-])[ \\t]+'
'captures':
'1': 'name': 'constant.gfm'
}
]

View File

@@ -0,0 +1,106 @@
TextMatePackage = require 'text-mate-package'
describe "GitHub Flavored Markdown grammar", ->
grammar = null
beforeEach ->
spyOn(syntax, "addGrammar")
pack = new TextMatePackage(require.resolve("gfm.tmbundle"))
pack.load()
grammar = pack.grammars[0]
it "parses the grammar", ->
expect(grammar).toBeTruthy()
expect(grammar.scopeName).toBe "source.gfm"
it "tokenizes **bold** text", ->
{tokens} = grammar.tokenizeLine("****")
expect(tokens[0]).toEqual value: "****", scopes: ["source.gfm"]
{tokens} = grammar.tokenizeLine("this is **bold** text")
expect(tokens[0]).toEqual value: "this is ", scopes: ["source.gfm"]
expect(tokens[1]).toEqual value: "**bold**", scopes: ["source.gfm", "markup.bold.gfm"]
expect(tokens[2]).toEqual value: " text", scopes: ["source.gfm"]
it "tokenizes __bold__ text", ->
{tokens} = grammar.tokenizeLine("____")
expect(tokens[0]).toEqual value: "____", scopes: ["source.gfm"]
{tokens} = grammar.tokenizeLine("this is __bold__ text")
expect(tokens[0]).toEqual value: "this is ", scopes: ["source.gfm"]
expect(tokens[1]).toEqual value: "__bold__", scopes: ["source.gfm", "markup.bold.gfm"]
expect(tokens[2]).toEqual value: " text", scopes: ["source.gfm"]
it "tokenizes *italic* text", ->
{tokens} = grammar.tokenizeLine("**")
expect(tokens[0]).toEqual value: "**", scopes: ["source.gfm"]
{tokens} = grammar.tokenizeLine("this is *italic* text")
expect(tokens[0]).toEqual value: "this is ", scopes: ["source.gfm"]
expect(tokens[1]).toEqual value: "*italic*", scopes: ["source.gfm", "markup.italic.gfm"]
expect(tokens[2]).toEqual value: " text", scopes: ["source.gfm"]
it "tokenizes _italic_ text", ->
{tokens} = grammar.tokenizeLine("__")
expect(tokens[0]).toEqual value: "__", scopes: ["source.gfm"]
{tokens} = grammar.tokenizeLine("this is _italic_ text")
expect(tokens[0]).toEqual value: "this is ", scopes: ["source.gfm"]
expect(tokens[1]).toEqual value: "_italic_", scopes: ["source.gfm", "markup.italic.gfm"]
expect(tokens[2]).toEqual value: " text", scopes: ["source.gfm"]
it "tokenizes a ## Heading", ->
{tokens} = grammar.tokenizeLine("# Heading 1")
expect(tokens[0]).toEqual value: "# Heading 1", scopes: ["source.gfm", "markup.heading.gfm"]
{tokens} = grammar.tokenizeLine("### Heading 3")
expect(tokens[0]).toEqual value: "### Heading 3", scopes: ["source.gfm", "markup.heading.gfm"]
it "tokenizies an :emoji:", ->
{tokens} = grammar.tokenizeLine("this is :no_good:")
expect(tokens[0]).toEqual value: "this is ", scopes: ["source.gfm"]
expect(tokens[1]).toEqual value: ":no_good:", scopes: ["source.gfm", "variable.emoji.gfm"]
it "tokenizes a ``` code block```", ->
{tokens, ruleStack} = grammar.tokenizeLine("```coffeescript")
expect(tokens[0]).toEqual value: "```coffeescript", scopes: ["source.gfm", "support.gfm"]
{tokens, ruleStack} = grammar.tokenizeLine("-> 'hello'", ruleStack)
expect(tokens[0]).toEqual value: "-> 'hello'", scopes: ["source.gfm", "markup.raw.gfm"]
{tokens} = grammar.tokenizeLine("```", ruleStack)
expect(tokens[0]).toEqual value: "```", scopes: ["source.gfm", "support.gfm"]
it "tokenizes inline `code` blocks", ->
{tokens} = grammar.tokenizeLine("`this` is `code`")
expect(tokens[0]).toEqual value: "`this`", scopes: ["source.gfm", "markup.raw.gfm"]
expect(tokens[1]).toEqual value: " is ", scopes: ["source.gfm"]
expect(tokens[2]).toEqual value: "`code`", scopes: ["source.gfm", "markup.raw.gfm"]
it "tokenizes [links](links)", ->
{tokens} = grammar.tokenizeLine("please click [this link](website)")
expect(tokens[0]).toEqual value: "please click ", scopes: ["source.gfm"]
expect(tokens[1]).toEqual value: "[", scopes: ["source.gfm"]
expect(tokens[2]).toEqual value: "this link", scopes: ["source.gfm", "entity.gfm"]
expect(tokens[3]).toEqual value: "](", scopes: ["source.gfm"]
expect(tokens[4]).toEqual value: "website", scopes: ["source.gfm", "markup.underline.gfm"]
expect(tokens[5]).toEqual value: ")", scopes: ["source.gfm"]
it "tokenizes lists", ->
{tokens} = grammar.tokenizeLine("*Item 1")
expect(tokens[0]).toEqual value: "*Item 1", scopes: ["source.gfm"]
{tokens} = grammar.tokenizeLine(" * Item 1")
expect(tokens[0]).toEqual value: " ", scopes: ["source.gfm"]
expect(tokens[1]).toEqual value: "*", scopes: ["source.gfm", "constant.gfm"]
expect(tokens[2]).toEqual value: " ", scopes: ["source.gfm"]
expect(tokens[3]).toEqual value: "Item 1", scopes: ["source.gfm"]
{tokens} = grammar.tokenizeLine(" + Item 2")
expect(tokens[0]).toEqual value: " ", scopes: ["source.gfm"]
expect(tokens[1]).toEqual value: "+", scopes: ["source.gfm", "constant.gfm"]
expect(tokens[2]).toEqual value: " ", scopes: ["source.gfm"]
expect(tokens[3]).toEqual value: "Item 2", scopes: ["source.gfm"]
{tokens} = grammar.tokenizeLine(" - Item 3")
expect(tokens[0]).toEqual value: " ", scopes: ["source.gfm"]
expect(tokens[1]).toEqual value: "-", scopes: ["source.gfm", "constant.gfm"]
expect(tokens[2]).toEqual value: " ", scopes: ["source.gfm"]
expect(tokens[3]).toEqual value: "Item 3", scopes: ["source.gfm"]

View File

@@ -1,12 +0,0 @@
DeferredAtomPackage = require 'deferred-atom-package'
module.exports =
class GistsPackage extends DeferredAtomPackage
loadEvents:
'gist:create': '.editor'
instanceClass: 'gists/lib/gists'
onLoadEvent: (event, instance) ->
instance.createGist(event.currentTargetView())

View File

@@ -3,12 +3,15 @@ $ = require 'jquery'
module.exports =
class Gists
@activate: -> new Gists
@activate: (rootView) -> new Gists(rootView)
constructor: (@rootView) ->
constructor: ->
rootView.command 'gist:create', '.editor', => @createGist()
createGist: (editor) ->
editor = rootView.getActiveEditor()
return unless editor?
gist = { public: false, files: {} }
gist.files[editor.getBuffer().getBaseName()] =
content: editor.getSelectedText() or editor.getText()
@@ -27,5 +30,5 @@ class Gists
@div class: 'content', =>
@h3 "Gist #{response.id} created", class: 'title'
@p "The url is on your clipboard", class: 'message'
@rootView.append(notification.hide())
rootView.append(notification.hide())
notification.fadeIn().delay(2000).fadeOut(complete: -> $(this).remove())

View File

@@ -0,0 +1,3 @@
'main': 'lib/gists'
'activationEvents':
'gist:create': '.editor'

View File

@@ -2,12 +2,11 @@ RootView = require 'root-view'
$ = require 'jquery'
describe "Gists package", ->
[rootView, editor] = []
[editor] = []
beforeEach ->
rootView = new RootView(fixturesProject.resolve('sample.js'))
atom.loadPackage('gists').getInstance()
atom.loadPackage('gists')
editor = rootView.getActiveEditor()
spyOn($, 'ajax')

View File

@@ -1,12 +0,0 @@
DeferredAtomPackage = require 'deferred-atom-package'
module.exports =
class GoToLinePackage extends DeferredAtomPackage
loadEvents:
'editor:go-to-line': '.editor'
instanceClass: 'go-to-line/lib/go-to-line-view'
onLoadEvent: (event, instance) ->
instance.toggle(event.currentTargetView())

View File

@@ -6,14 +6,15 @@ Point = require 'point'
module.exports =
class GoToLineView extends View
@activate: (rootView) -> new GoToLineView(rootView)
@activate: -> new GoToLineView
@content: ->
@div class: 'go-to-line overlay from-top mini', =>
@subview 'miniEditor', new Editor(mini: true)
@div class: 'message', outlet: 'message'
initialize: (@rootView) ->
initialize: ->
rootView.command 'editor:go-to-line', '.editor', => @toggle()
@miniEditor.on 'focusout', => @detach()
@on 'core:confirm', => @confirm()
@on 'core:cancel', => @detach()
@@ -42,13 +43,13 @@ class GoToLineView extends View
@detach()
return unless editor and lineNumber.length
position = new Point(parseInt(lineNumber - 1, 0))
position = new Point(parseInt(lineNumber - 1))
editor.scrollToBufferPosition(position, center: true)
editor.setCursorBufferPosition(position)
editor.moveCursorToFirstCharacterOfLine()
attach: ->
@previouslyFocusedElement = $(':focus')
@rootView.append(this)
@message.text("Enter a line number 1-#{@rootView.getActiveEditor().getLineCount()}")
rootView.append(this)
@message.text("Enter a line number 1-#{rootView.getActiveEditor().getLineCount()}")
@miniEditor.focus()

View File

@@ -0,0 +1,3 @@
'activationEvents':
'editor:go-to-line': '.editor'
'main': './lib/go-to-line-view'

View File

@@ -1,13 +1,14 @@
RootView = require 'root-view'
GoToLineView = require 'go-to-line/lib/go-to-line-view'
describe 'GoToLine', ->
[rootView, goToLine, editor] = []
[goToLine, editor] = []
beforeEach ->
rootView = new RootView(require.resolve('fixtures/sample.js'))
new RootView(require.resolve('fixtures/sample.js'))
rootView.enableKeymap()
goToLine = atom.loadPackage("go-to-line").getInstance()
editor = rootView.getActiveEditor()
goToLine = GoToLineView.activate()
editor.setCursorBufferPosition([1,0])
afterEach ->

View File

@@ -1,9 +0,0 @@
DeferredAtomPackage = require 'deferred-atom-package'
module.exports =
class MarkdownPreview extends DeferredAtomPackage
loadEvents: ['markdown-preview:toggle']
instanceClass: 'markdown-preview/src/markdown-preview-view'
onLoadEvent: (event, instance) -> instance.toggle()

View File

@@ -5,19 +5,19 @@ $ = require 'jquery'
module.exports =
class MarkdownPreviewView extends ScrollView
@activate: (rootView, state) ->
@instance = new this(rootView)
@activate: ->
@instance = new MarkdownPreviewView
@content: (rootView) ->
@content: ->
@div class: 'markdown-preview', tabindex: -1, =>
@div class: 'markdown-body', outlet: 'markdownBody'
initialize: (@rootView) ->
initialize: ->
super
@editor = @rootView.getActiveEditor()
@subscribe @editor, 'focus', => @detach() unless @detaching
@command 'core:cancel', => @detach() unless @detaching
rootView.command 'markdown-preview:toggle', => @toggle()
@on 'blur', => @detach() unless document.activeElement is this[0]
@command 'core:cancel', => @detach()
toggle: ->
if @hasParent()
@@ -27,22 +27,23 @@ class MarkdownPreviewView extends ScrollView
attach: ->
return unless @isMarkdownFile(@getActivePath())
@rootView.append(this)
rootView.append(this)
@markdownBody.html(@getLoadingHtml())
@loadHtml()
@focus()
detach: ->
return if @detaching
@detaching = true
super
@rootView.focus()
rootView.focus()
@detaching = false
getActivePath: ->
@editor.getPath()
rootView.getActiveEditor()?.getPath()
getActiveText: ->
@editor.getText()
rootView.getActiveEditor()?.getText()
getErrorHtml: (error) ->
$$$ ->
@@ -76,4 +77,4 @@ class MarkdownPreviewView extends ScrollView
@markdownBody.html(html) if @hasParent()
isMarkdownFile: (path) ->
fs.isMarkdownExtension(fs.extension(path))
path and fs.isMarkdownExtension(fs.extension(path))

View File

@@ -0,0 +1,3 @@
'main': 'lib/markdown-preview-view'
'activationEvents':
'markdown-preview:toggle': '.editor'

View File

@@ -1,12 +1,12 @@
$ = require 'jquery'
RootView = require 'root-view'
MarkdownPreview = require 'markdown-preview/src/markdown-preview-view'
MarkdownPreview = require 'markdown-preview/lib/markdown-preview-view'
describe "MarkdownPreview", ->
[rootView, markdownPreview] = []
beforeEach ->
rootView = new RootView(require.resolve('fixtures/markdown'))
atom.loadPackage("markdown-preview")
spyOn(MarkdownPreview.prototype, 'loadHtml')
afterEach ->
rootView.deactivate()
@@ -15,44 +15,37 @@ describe "MarkdownPreview", ->
it "toggles on/off a preview for a .md file", ->
rootView.open('file.md')
editor = rootView.getActiveEditor()
markdownPreview = atom.loadPackage("markdown-preview").getInstance()
expect(rootView.find('.markdown-preview')).not.toExist()
spyOn(markdownPreview, 'loadHtml')
editor.trigger('markdown-preview:toggle')
markdownPreviewView = rootView.find('.markdown-preview')?.view()
expect(rootView.find('.markdown-preview')).toExist()
expect(markdownPreview.loadHtml).toHaveBeenCalled();
expect(markdownPreviewView.loadHtml).toHaveBeenCalled()
markdownPreviewView.trigger('markdown-preview:toggle')
expect(rootView.find('.markdown-preview')).not.toExist()
it "displays a preview for a .markdown file", ->
rootView.open('file.markdown')
editor = rootView.getActiveEditor()
markdownPreview = atom.loadPackage("markdown-preview").getInstance()
expect(rootView.find('.markdown-preview')).not.toExist()
spyOn(markdownPreview, 'loadHtml')
editor.trigger('markdown-preview:toggle')
expect(rootView.find('.markdown-preview')).toExist()
expect(markdownPreview.loadHtml).toHaveBeenCalled();
markdownPreviewView = rootView.find('.markdown-preview')?.view()
expect(markdownPreviewView.loadHtml).toHaveBeenCalled()
it "does not display a preview for non-markdown file", ->
rootView.open('file.js')
editor = rootView.getActiveEditor()
markdownPreview = atom.loadPackage("markdown-preview").getInstance()
expect(rootView.find('.markdown-preview')).not.toExist()
spyOn(markdownPreview, 'loadHtml')
editor.trigger('markdown-preview:toggle')
expect(rootView.find('.markdown-preview')).not.toExist()
expect(markdownPreview.loadHtml).not.toHaveBeenCalled();
expect(MarkdownPreview.prototype.loadHtml).not.toHaveBeenCalled()
describe "core:cancel event", ->
it "removes markdown preview", ->
rootView.open('file.md')
editor = rootView.getActiveEditor()
markdownPreview = atom.loadPackage("markdown-preview").getInstance()
expect(rootView.find('.markdown-preview')).not.toExist()
spyOn(markdownPreview, 'loadHtml')
editor.trigger('markdown-preview:toggle')
markdownPreviewView = rootView.find('.markdown-preview')?.view()
@@ -62,14 +55,19 @@ describe "MarkdownPreview", ->
describe "when the editor receives focus", ->
it "removes the markdown preview view", ->
rootView.attachToDom()
rootView.open('file.md')
editor = rootView.getActiveEditor()
markdownPreview = atom.loadPackage("markdown-preview").getInstance()
expect(rootView.find('.markdown-preview')).not.toExist()
spyOn(markdownPreview, 'loadHtml')
editor.trigger('markdown-preview:toggle')
markdownPreviewView = rootView.find('.markdown-preview')
expect(markdownPreviewView).toExist()
editor.focus()
expect(markdownPreviewView).toExist()
expect(rootView.find('.markdown-preview')).not.toExist()
describe "when no editor is open", ->
it "does not attach", ->
expect(rootView.getActiveEditor()).toBeFalsy()
rootView.trigger('markdown-preview:toggle')
expect(rootView.find('.markdown-preview')).not.toExist()

View File

@@ -4,8 +4,8 @@ TextMatePackage = require 'text-mate-package'
module.exports =
class LoadSnippetsTask extends Task
constructor: (@snippets) ->
super('snippets/src/load-snippets-handler')
@packages = atom.getPackages()
super('snippets/lib/load-snippets-handler')
@packages = atom.getLoadedPackages()
@packages.push(path: config.configDirPath)
started: ->

View File

@@ -1,22 +1,25 @@
AtomPackage = require 'atom-package'
fs = require 'fs'
_ = require 'underscore'
SnippetExpansion = require './src/snippet-expansion'
Snippet = require './src/snippet'
LoadSnippetsTask = require './src/load-snippets-task'
SnippetExpansion = require './snippet-expansion'
Snippet = require './snippet'
LoadSnippetsTask = require './load-snippets-task'
module.exports =
class Snippets extends AtomPackage
snippetsByExtension: {}
loaded: false
activate: (@rootView) ->
activate: ->
window.snippets = this
@loadAll()
@rootView.on 'editor:attached', (e, editor) => @enableSnippetsInEditor(editor)
rootView.on 'editor:attached', (e, editor) => @enableSnippetsInEditor(editor)
deactivate: ->
@loadSnippetsTask?.terminate()
loadAll: ->
new LoadSnippetsTask(this).start()
@loadSnippetsTask = new LoadSnippetsTask(this)
@loadSnippetsTask.start()
loadDirectory: (snippetsDirPath) ->
for snippetsPath in fs.list(snippetsDirPath) when fs.base(snippetsPath).indexOf('.') isnt 0
@@ -41,7 +44,7 @@ class Snippets extends AtomPackage
syntax.addProperties(selector, snippets: snippetsByPrefix)
getBodyParser: ->
require 'snippets/src/snippet-body-parser'
require 'snippets/lib/snippet-body-parser'
enableSnippetsInEditor: (editor) ->
editor.command 'snippets:expand', (e) =>

View File

@@ -0,0 +1 @@
'main': 'lib/snippets'

Some files were not shown because too many files have changed in this diff Show More