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

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)