Merge branch 'master' into mc-expose-bindings

This commit is contained in:
Matt Colyer
2013-09-26 10:26:13 -07:00
34 changed files with 264 additions and 215 deletions

View File

@@ -93,8 +93,8 @@ class AtomApplication
fs.unlinkSync socketPath if fs.existsSync(socketPath)
server = net.createServer (connection) =>
connection.on 'data', (data) =>
{pathsToOpen, pidToKillWhenClosed, newWindow} = JSON.parse(data)
@openPaths({pathsToOpen, pidToKillWhenClosed, newWindow})
options = JSON.parse(data)
@openPaths(options)
server.listen socketPath
server.on 'error', (error) -> console.error 'Application server failed', error

View File

@@ -28,41 +28,44 @@ class AtomPackage extends Package
getType: -> 'atom'
load: ->
try
@metadata = Package.loadMetadata(@path)
if @isTheme()
@stylesheets = []
@keymaps = []
@menus = []
@grammars = []
@scopedProperties = []
else
@loadKeymaps()
@loadMenus()
@loadStylesheets()
@loadGrammars()
@loadScopedProperties()
if @metadata.activationEvents?
@registerDeferredDeserializers()
@measure 'loadTime', =>
try
@metadata = Package.loadMetadata(@path)
if @isTheme()
@stylesheets = []
@keymaps = []
@menus = []
@grammars = []
@scopedProperties = []
else
@requireMainModule()
@loadKeymaps()
@loadMenus()
@loadStylesheets()
@loadGrammars()
@loadScopedProperties()
catch e
console.warn "Failed to load package named '#{@name}'", e.stack ? e
if @metadata.activationEvents?
@registerDeferredDeserializers()
else
@requireMainModule()
catch e
console.warn "Failed to load package named '#{@name}'", e.stack ? e
this
activate: ({immediate}={}) ->
@loadStylesheets() if @isTheme()
@activateResources()
if @metadata.activationEvents? and not immediate
@subscribeToActivationEvents()
else
@activateNow()
@measure 'activateTime', =>
@loadStylesheets() if @isTheme()
@activateResources()
if @metadata.activationEvents? and not immediate
@subscribeToActivationEvents()
else
@activateNow()
activateNow: ->
try
@activateConfig()
@activateStylesheets()
if @requireMainModule()
@mainModule.activate(atom.getPackageState(@name) ? {})
@mainActivated = true
@@ -78,11 +81,13 @@ class AtomPackage extends Package
@mainModule.activateConfig?()
@configActivated = true
activateStylesheets: ->
type = if @metadata.theme then 'theme' else 'bundled'
applyStylesheet(stylesheetPath, content, type) for [stylesheetPath, content] in @stylesheets
activateResources: ->
keymap.add(keymapPath, map) for [keymapPath, map] in @keymaps
atom.contextMenu.add(menuPath, map['context-menu']) for [menuPath, map] in @menus
type = if @metadata.theme then 'theme' else 'bundled'
applyStylesheet(stylesheetPath, content, type) for [stylesheetPath, content] in @stylesheets
syntax.addGrammar(grammar) for grammar in @grammars
for [scopedPropertiesPath, selector, properties] in @scopedProperties
syntax.addProperties(scopedPropertiesPath, selector, properties)

View File

@@ -42,10 +42,7 @@ class AtomWindow
@openPath(pathToOpen, initialLine)
setupNodePath: (resourcePath) ->
paths = [
'exports'
'node_modules'
]
paths = ['exports', 'node_modules']
paths = paths.map (relativePath) -> path.resolve(resourcePath, relativePath)
process.env['NODE_PATH'] = paths.join path.delimiter

View File

@@ -8,7 +8,7 @@ crypto = require 'crypto'
path = require 'path'
dialog = remote.require 'dialog'
app = remote.require 'app'
telepath = require 'telepath'
{Document} = require 'telepath'
ThemeManager = require './theme-manager'
ContextMenuManager = require './context-menu-manager'
@@ -34,9 +34,7 @@ window.atom =
activatePackage: (name, options) ->
if pack = @loadPackage(name, options)
@activePackages[pack.name] = pack
startTime = new Date().getTime()
pack.activate(options)
pack.activateTime = new Date().getTime() - startTime
pack
deactivatePackages: ->
@@ -73,9 +71,7 @@ window.atom =
if packagePath = @resolvePackagePath(name)
return pack if pack = @getLoadedPackage(name)
startTime = new Date().getTime()
pack = Package.load(packagePath, options)
pack.loadTime = new Date().getTime() - startTime
if pack.metadata.theme
@themes.register(pack)
else
@@ -249,34 +245,28 @@ window.atom =
if windowStatePath = @getWindowStatePath()
if fsUtils.exists(windowStatePath)
try
windowStateJson = fsUtils.read(windowStatePath)
documentStateJson = fsUtils.read(windowStatePath)
catch error
console.warn "Error reading window state: #{windowStatePath}", error.stack, error
else
windowStateJson = @getLoadSettings().windowState
documentStateJson = @getLoadSettings().windowState
try
windowState = JSON.parse(windowStateJson or '{}')
documentState = JSON.parse(documentStateJson) if documentStateJson?
catch error
console.warn "Error parsing window state: #{windowStatePath}", error.stack, error
{site, document} = windowState ? {}
if site? and document?
window.site = telepath.Site.deserialize(site)
window.site.deserializeDocument(document) ? window.site.createDocument({})
else
window.site = new telepath.Site(1)
window.site.createDocument({})
doc = Document.deserialize(state: documentState) if documentState?
doc ?= Document.create()
window.site = doc.site # TODO: Remove this when everything is using telepath models
doc
saveWindowState: ->
windowState =
site: site.serialize()
document: @getWindowState().serialize()
windowStateJson = JSON.stringify(windowState)
windowState = @getWindowState()
if windowStatePath = @getWindowStatePath()
fsUtils.writeSync(windowStatePath, "#{windowStateJson}\n")
windowState.saveSync(path: windowStatePath)
else
@getLoadSettings().windowState = windowStateJson
@getLoadSettings().windowState = JSON.stringify(windowState.serialize())
getWindowState: (keyPath) ->
@windowState ?= @loadWindowState()

View File

@@ -117,6 +117,7 @@ class EditSession
project.setPath(path.dirname(@getPath())) unless project.getPath()?
@trigger "title-changed"
@trigger "path-changed"
@subscribe @buffer, "contents-modified", => @trigger "contents-modified"
@subscribe @buffer, "contents-conflicted", => @trigger "contents-conflicted"
@subscribe @buffer, "modified-status-changed", => @trigger "modified-status-changed"
@preserveCursorPositionOnBufferReload()
@@ -376,6 +377,9 @@ class EditSession
# {Delegates to: TextBuffer.lineLengthForRow}
lineLengthForBufferRow: (row) -> @buffer.lineLengthForRow(row)
# {Delegates to: TextBuffer.scan}
scan: (args...) -> @buffer.scan(args...)
# {Delegates to: TextBuffer.scanInRange}
scanInBufferRange: (args...) -> @buffer.scanInRange(args...)

View File

@@ -640,6 +640,7 @@ class Editor extends View
@hiddenInput.on 'focusout', =>
@isFocused = false
@removeClass 'is-focused'
@hiddenInput.offset(top: 0, left: 0)
@underlayer.on 'mousedown', (e) =>
@renderedLines.trigger(e)

View File

@@ -105,8 +105,11 @@ module.exports =
# Identifies how many events are registered.
#
# Returns a {Number}.
subscriptionCount: ->
getSubscriptionCount: ->
count = 0
for name, handlers of @eventHandlersByEventName
count += handlers.length
count
# Deprecated
subscriptionCount: -> @getSubscriptionCount()

View File

@@ -1,13 +1,15 @@
startTime = new Date().getTime()
autoUpdater = require 'auto-updater'
crashReporter = require 'crash-reporter'
delegate = require 'atom-delegate'
app = require 'app'
fs = require 'fs'
module = require 'module'
path = require 'path'
optimist = require 'optimist'
nslog = require 'nslog'
dialog = require 'dialog'
_ = require 'underscore'
console.log = (args...) ->
nslog(args.map((arg) -> JSON.stringify(arg)).join(" "))
@@ -45,14 +47,15 @@ delegate.browserMainParts.preMainMessageLoopRun = ->
require('coffee-script')
if args.devMode
require(path.join(args.resourcePath, 'src', 'coffee-cache'))
require('module').globalPaths.push(path.join(args.resourcePath, 'src'))
module.globalPaths.push(path.join(args.resourcePath, 'src'))
else
appSrcPath = path.resolve(process.argv[0], "../../Resources/app/src")
require('module').globalPaths.push(appSrcPath)
module.globalPaths.push(appSrcPath)
AtomApplication = require 'atom-application'
AtomApplication.open(args)
console.log("App load time: #{new Date().getTime() - startTime}ms")
global.devResourcePath = path.join(app.getHomeDir(), 'github', 'atom')

View File

@@ -39,3 +39,9 @@ class Package
isTheme: ->
!!@metadata?.theme
# Private:
measure: (key, fn) ->
startTime = new Date().getTime()
fn()
@[key] = new Date().getTime() - startTime

View File

@@ -10,7 +10,7 @@ TextBuffer = require './text-buffer'
EditSession = require './edit-session'
EventEmitter = require './event-emitter'
Directory = require './directory'
BufferedNodeProcess = require './buffered-node-process'
Task = require './task'
Git = require './git'
# Public: Represents a project that's opened in Atom.
@@ -278,65 +278,30 @@ class Project
#
# * regex:
# A RegExp to search with
# * options:
# - paths: an {Array} of glob patterns to search within
# * iterator:
# A Function callback on each file found
scan: (regex, iterator) ->
bufferedData = ""
state = 'readingPath'
filePath = null
readPath = (line) ->
if /^[0-9,; ]+:/.test(line)
state = 'readingLines'
else if /^:/.test line
filePath = line.substr(1)
else
filePath += ('\n' + line)
readLine = (line) ->
if line.length == 0
state = 'readingPath'
filePath = null
else
colonIndex = line.indexOf(':')
matchInfo = line.substring(0, colonIndex)
lineText = line.substring(colonIndex + 1)
readMatches(matchInfo, lineText)
readMatches = (matchInfo, lineText) ->
[lineNumber, matchPositionsText] = matchInfo.match(/(\d+);(.+)/)[1..]
row = parseInt(lineNumber) - 1
matchPositions = matchPositionsText.split(',').map (positionText) -> positionText.split(' ').map (pos) -> parseInt(pos)
for [column, length] in matchPositions
range = new Range([row, column], [row, column + length])
match = lineText.substr(column, length)
iterator({path: filePath, range, match})
scan: (regex, options={}, iterator) ->
if _.isFunction(options)
iterator = options
options = {}
deferred = $.Deferred()
errors = []
stderr = (data) ->
errors.push(data)
stdout = (data) ->
lines = data.split('\n')
lines.pop() # the last segment is a spurious '' because data always ends in \n due to bufferLines: true
for line in lines
readPath(line) if state is 'readingPath'
readLine(line) if state is 'readingLines'
exit = (code) ->
if code is 0
deferred.resolve()
else
console.error("Project scan failed: #{code}", errors.join('\n'))
deferred.reject({command, code})
command = require.resolve('.bin/nak')
args = ['--hidden', '--ackmate', regex.source, @getPath()]
ignoredNames = config.get('core.ignoredNames') ? []
args.unshift('--ignore', ignoredNames.join(',')) if ignoredNames.length > 0
args.unshift('--ignoreCase') if regex.ignoreCase
args.unshift('--addVCSIgnores') if config.get('core.excludeVcsIgnoredPaths')
new BufferedNodeProcess({command, args, stdout, stderr, exit})
searchOptions =
ignoreCase: regex.ignoreCase
inclusions: options.paths
includeHidden: true
excludeVcsIgnores: config.get('core.excludeVcsIgnoredPaths')
exclusions: config.get('core.ignoredNames')
task = Task.once require.resolve('./scan-handler'), @getPath(), regex.source, searchOptions, ->
deferred.resolve()
task.on 'scan:result-found', (result) =>
iterator(result)
deferred
# Private:

View File

@@ -126,7 +126,8 @@ class RootView extends View
@command 'pane:reopen-closed-item', =>
@panes.reopenItem()
_.nextTick => atom.setFullScreen(@state.get('fullScreen'))
if @state.get('fullScreen')
_.nextTick => atom.setFullScreen(true)
# Private:
serialize: ->
@@ -173,8 +174,10 @@ class RootView extends View
initialLine = options.initialLine
path = project.relativize(path)
if activePane = @getActivePane()
editSession = activePane.itemForUri(path) if path
editSession ?= project.open(path, {initialLine})
if path
editSession = activePane.itemForUri(path) ? project.open(path, {initialLine})
else
editSession = project.open()
activePane.showItem(editSession)
else
editSession = project.open(path, {initialLine})

15
src/scan-handler.coffee Normal file
View File

@@ -0,0 +1,15 @@
{PathSearcher, PathScanner, search} = require 'scandal'
module.exports = (rootPath, regexSource, options) ->
callback = @async()
searcher = new PathSearcher()
scanner = new PathScanner(rootPath, options)
searcher.on 'results-found', (result) ->
emit('scan:result-found', result)
flags = "g"
flags += "i" if options.ignoreCase
regex = new RegExp(regexSource, flags)
search regex, scanner, searcher, callback

View File

@@ -6,6 +6,7 @@ File = require './file'
EventEmitter = require './event-emitter'
Subscriber = require './subscriber'
guid = require 'guid'
{P} = require 'scandal'
# Private: Represents the contents of a file.
#
@@ -501,7 +502,10 @@ class TextBuffer
# regex - A {RegExp} representing the text to find
# iterator - A {Function} that's called on each match
scan: (regex, iterator) ->
@scanInRange(regex, @getRange(), iterator)
@scanInRange regex, @getRange(), (result) =>
result.lineText = @lineForRow(result.range.start.row)
result.lineTextOffset = 0
iterator(result)
# Scans for text in a given range, calling a function on each match.
#
@@ -538,7 +542,8 @@ class TextBuffer
range = new Range(startPosition, endPosition)
keepLooping = true
replacementText = null
iterator({match, range, stop, replace })
matchText = match[0]
iterator({ match, matchText, range, stop, replace })
if replacementText?
@change(range, replacementText)

View File

@@ -29,18 +29,20 @@ class TextMatePackage extends Package
getType: -> 'textmate'
load: ({sync}={}) ->
@metadata = Package.loadMetadata(@path, true)
@measure 'loadTime', =>
@metadata = Package.loadMetadata(@path, true)
if sync
@loadGrammarsSync()
@loadScopedPropertiesSync()
else
TextMatePackage.getLoadQueue().push(this)
if sync
@loadGrammarsSync()
@loadScopedPropertiesSync()
else
TextMatePackage.getLoadQueue().push(this)
activate: ->
syntax.addGrammar(grammar) for grammar in @grammars
for { selector, properties } in @scopedProperties
syntax.addProperties(@path, selector, properties)
@measure 'activateTime', =>
syntax.addGrammar(grammar) for grammar in @grammars
for { selector, properties } in @scopedProperties
syntax.addProperties(@path, selector, properties)
activateConfig: -> # noop

View File

@@ -29,6 +29,10 @@ class ThemeManager
getActiveThemes: ->
_.clone(@activeThemes)
# Internal-only:
getLoadedThemes: ->
_.clone(@loadedThemes)
# Internal-only:
unload: ->
removeStylesheet(@userStylesheetPath) if @userStylesheetPath?

View File

@@ -28,6 +28,9 @@ _.mixin
escapeRegExp: (string) ->
string.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')
escapeAttribute: (string) ->
string.replace(/"/g, '"').replace(/\n/g, '')
humanizeEventName: (eventName, eventDoc) ->
[namespace, event] = eventName.split(':')
return _.undasherize(namespace) unless event?

View File

@@ -1,8 +1,9 @@
# Like sands through the hourglass, so are the days of our lives.
date = new Date().getTime()
startTime = new Date().getTime()
require './atom'
require './window'
window.setUpEnvironment('editor')
window.startEditorWindow()
console.log "Load time: #{new Date().getTime() - date}"
console.log "Window load time: #{new Date().getTime() - startTime}ms"

View File

@@ -14,7 +14,7 @@ class WindowEventHandler
@reloadRequested = false
@subscribe ipc, 'command', (command, args...) ->
$(window).trigger(command, args...)
$(document.activeElement).trigger(command, args...)
@subscribe ipc, 'context-command', (command, args...) ->
$(atom.contextMenu.activeElement).trigger(command, args...)