This commit is contained in:
Jessica Lord
2015-05-14 09:48:03 -07:00
16 changed files with 255 additions and 124 deletions

View File

@@ -223,6 +223,8 @@ class Atom extends Model
@disposables?.dispose()
@disposables = new CompositeDisposable
@displayWindow() unless @inSpecMode()
@setBodyPlatformClass()
@loadTime = null
@@ -483,22 +485,27 @@ class Atom extends Model
# Extended: Set the full screen state of the current window.
setFullScreen: (fullScreen=false) ->
ipc.send('call-window-method', 'setFullScreen', fullScreen)
if fullScreen then document.body.classList.add("fullscreen") else document.body.classList.remove("fullscreen")
if fullScreen
document.body.classList.add("fullscreen")
else
document.body.classList.remove("fullscreen")
# Extended: Toggle the full screen state of the current window.
toggleFullScreen: ->
@setFullScreen(not @isFullScreen())
# Schedule the window to be shown and focused on the next tick.
# Restore the window to its previous dimensions and show it.
#
# This is done in a next tick to prevent a white flicker from occurring
# if called synchronously.
displayWindow: ({maximize}={}) ->
# Also restores the full screen and maximized state on the next tick to
# prevent resize glitches.
displayWindow: ->
dimensions = @restoreWindowDimensions()
@show()
setImmediate =>
@show()
@focus()
@setFullScreen(true) if @workspace.fullScreen
@maximize() if maximize
@setFullScreen(true) if @workspace?.fullScreen
@maximize() if dimensions?.maximized and process.platform isnt 'darwin'
# Get the dimensions of this window.
#
@@ -572,6 +579,13 @@ class Atom extends Model
dimensions = @getWindowDimensions()
@state.windowDimensions = dimensions if @isValidDimensions(dimensions)
storeWindowBackground: ->
return if @inSpecMode()
workspaceElement = @views.getView(@workspace)
backgroundColor = window.getComputedStyle(workspaceElement)['background-color']
window.localStorage.setItem('atom:window-background-color', backgroundColor)
# Call this method when establishing a real application window.
startEditorWindow: ->
{safeMode} = @getLoadSettings()
@@ -582,7 +596,6 @@ class Atom extends Model
CommandInstaller.installApmCommand false, (error) ->
console.warn error.message if error?
dimensions = @restoreWindowDimensions()
@loadConfig()
@keymaps.loadBundledKeymaps()
@themes.loadBaseStylesheets()
@@ -602,12 +615,10 @@ class Atom extends Model
@openInitialEmptyEditorIfNecessary()
maximize = dimensions?.maximized and process.platform isnt 'darwin'
@displayWindow({maximize})
unloadEditorWindow: ->
return if not @project
@storeWindowBackground()
@state.grammars = @grammars.serialize()
@state.project = @project.serialize()
@state.workspace = @workspace.serialize()
@@ -747,7 +758,7 @@ class Atom extends Model
# Only reload stylesheets from non-theme packages
for pack in @packages.getActivePackages() when pack.getType() isnt 'theme'
pack.reloadStylesheets?()
null
return
# Notify the browser project of the window's current project path
watchProjectPath: ->

View File

@@ -9,11 +9,10 @@ _ = require 'underscore-plus'
# and maintain the state of all menu items.
module.exports =
class ApplicationMenu
constructor: (@version) ->
constructor: (@version, @autoUpdateManager) ->
@windowTemplates = new WeakMap()
@setActiveTemplate(@getDefaultTemplate())
global.atomApplication.autoUpdateManager.on 'state-changed', (state) =>
@showUpdateMenuItem(state)
@autoUpdateManager.on 'state-changed', (state) => @showUpdateMenuItem(state)
# Public: Updates the entire menu with the given keybindings.
#
@@ -33,7 +32,7 @@ class ApplicationMenu
@menu = Menu.buildFromTemplate(_.deepClone(template))
Menu.setApplicationMenu(@menu)
@showUpdateMenuItem(global.atomApplication.autoUpdateManager.getState())
@showUpdateMenuItem(@autoUpdateManager.getState())
# Register a BrowserWindow with this application menu.
addWindow: (window) ->

View File

@@ -71,8 +71,8 @@ class AtomApplication
@pathsToOpen ?= []
@windows = []
@autoUpdateManager = new AutoUpdateManager(@version)
@applicationMenu = new ApplicationMenu(@version)
@autoUpdateManager = new AutoUpdateManager(@version, options.test)
@applicationMenu = new ApplicationMenu(@version, @autoUpdateManager)
@atomProtocolHandler = new AtomProtocolHandler(@resourcePath, @safeMode)
@listenForArgumentsFromNewProcess()
@@ -99,7 +99,12 @@ class AtomApplication
# Public: Removes the {AtomWindow} from the global window list.
removeWindow: (window) ->
@windows.splice @windows.indexOf(window), 1
@applicationMenu?.enableWindowSpecificItems(false) if @windows.length is 0
if @windows.length is 0
@applicationMenu?.enableWindowSpecificItems(false)
if process.platform in ['win32', 'linux']
app.quit()
return
@saveState() unless window.isSpec
# Public: Adds the {AtomWindow} to the global window list.
addWindow: (window) ->
@@ -110,10 +115,14 @@ class AtomApplication
unless window.isSpec
focusHandler = => @lastFocusedWindow = window
blurHandler = => @saveState()
window.browserWindow.on 'focus', focusHandler
window.browserWindow.on 'blur', blurHandler
window.browserWindow.once 'closed', =>
@lastFocusedWindow = null if window is @lastFocusedWindow
window.browserWindow.removeListener 'focus', focusHandler
window.browserWindow.removeListener 'blur', blurHandler
window.browserWindow.webContents.once 'did-finish-load', => @saveState()
# Creates server to listen for additional atom application launches.
#
@@ -176,7 +185,7 @@ class AtomApplication
@on 'application:report-issue', -> require('shell').openExternal('https://github.com/atom/atom/blob/master/CONTRIBUTING.md#submitting-issues')
@on 'application:search-issues', -> require('shell').openExternal('https://github.com/issues?q=+is%3Aissue+user%3Aatom')
@on 'application:install-update', -> @autoUpdateManager.install()
@on 'application:install-update', => @autoUpdateManager.install()
@on 'application:check-for-update', => @autoUpdateManager.check()
if process.platform is 'darwin'
@@ -199,17 +208,12 @@ class AtomApplication
@openPathOnEvent('application:open-your-stylesheet', 'atom://.atom/stylesheet')
@openPathOnEvent('application:open-license', path.join(process.resourcesPath, 'LICENSE.md'))
app.on 'window-all-closed', ->
app.quit() if process.platform in ['win32', 'linux']
app.on 'before-quit', =>
@saveState()
app.on 'will-quit', =>
@killAllProcesses()
@deleteSocketFile()
app.on 'will-exit', =>
@saveState() unless @windows.every (window) -> window.isSpec
@killAllProcesses()
@deleteSocketFile()
@@ -422,8 +426,8 @@ class AtomApplication
saveState: ->
states = []
for window in @windows
if loadSettings = window.getLoadSettings()
unless loadSettings.isSpec
unless window.isSpec
if loadSettings = window.getLoadSettings()
states.push(initialPaths: loadSettings.initialPaths)
@storageFolder.store('application.json', states)

View File

@@ -15,7 +15,7 @@ module.exports =
class AutoUpdateManager
_.extend @prototype, EventEmitter.prototype
constructor: (@version) ->
constructor: (@version, @testMode) ->
@state = IdleState
if process.platform is 'win32'
# Squirrel for Windows can't handle query params
@@ -80,10 +80,10 @@ class AutoUpdateManager
autoUpdater.once 'update-not-available', @onUpdateNotAvailable
autoUpdater.once 'error', @onUpdateError
autoUpdater.checkForUpdates()
autoUpdater.checkForUpdates() unless @testMode
install: ->
autoUpdater.quitAndInstall()
autoUpdater.quitAndInstall() unless @testMode
onUpdateNotAvailable: =>
autoUpdater.removeListener 'error', @onUpdateError

View File

@@ -24,13 +24,13 @@ class DisplayBuffer extends Model
horizontalScrollMargin: 6
scopedCharacterWidthsChangeCount: 0
constructor: ({tabLength, @editorWidthInChars, @tokenizedBuffer, buffer, @invisibles}={}) ->
constructor: ({tabLength, @editorWidthInChars, @tokenizedBuffer, buffer, ignoreInvisibles}={}) ->
super
@emitter = new Emitter
@disposables = new CompositeDisposable
@tokenizedBuffer ?= new TokenizedBuffer({tabLength, buffer, @invisibles})
@tokenizedBuffer ?= new TokenizedBuffer({tabLength, buffer, ignoreInvisibles})
@buffer = @tokenizedBuffer.buffer
@charWidthsByScope = {}
@markers = {}
@@ -42,6 +42,7 @@ class DisplayBuffer extends Model
@disposables.add @buffer.onDidUpdateMarkers @handleBufferMarkersUpdated
@disposables.add @buffer.onDidCreateMarker @handleBufferMarkerCreated
@updateAllScreenLines()
@foldMarkerAttributes = Object.freeze({class: 'fold', displayBufferId: @id})
@createFoldForMarker(marker) for marker in @buffer.findMarkers(@getFoldMarkerAttributes())
subscribeToScopedConfigSettings: =>
@@ -86,14 +87,13 @@ class DisplayBuffer extends Model
scrollTop: @scrollTop
scrollLeft: @scrollLeft
tokenizedBuffer: @tokenizedBuffer.serialize()
invisibles: _.clone(@invisibles)
deserializeParams: (params) ->
params.tokenizedBuffer = TokenizedBuffer.deserialize(params.tokenizedBuffer)
params
copy: ->
newDisplayBuffer = new DisplayBuffer({@buffer, tabLength: @getTabLength(), @invisibles})
newDisplayBuffer = new DisplayBuffer({@buffer, tabLength: @getTabLength()})
newDisplayBuffer.setScrollTop(@getScrollTop())
newDisplayBuffer.setScrollLeft(@getScrollLeft())
@@ -428,8 +428,8 @@ class DisplayBuffer extends Model
setTabLength: (tabLength) ->
@tokenizedBuffer.setTabLength(tabLength)
setInvisibles: (@invisibles) ->
@tokenizedBuffer.setInvisibles(@invisibles)
setIgnoreInvisibles: (ignoreInvisibles) ->
@tokenizedBuffer.setIgnoreInvisibles(ignoreInvisibles)
setSoftWrapped: (softWrapped) ->
if softWrapped isnt @softWrapped
@@ -1075,8 +1075,11 @@ class DisplayBuffer extends Model
findFoldMarkers: (attributes) ->
@buffer.findMarkers(@getFoldMarkerAttributes(attributes))
getFoldMarkerAttributes: (attributes={}) ->
_.extend(attributes, class: 'fold', displayBufferId: @id)
getFoldMarkerAttributes: (attributes) ->
if attributes
_.extend(attributes, @foldMarkerAttributes)
else
@foldMarkerAttributes
pauseMarkerChangeEvents: ->
marker.pauseChangeEvents() for marker in @getMarkers()

View File

@@ -303,6 +303,9 @@ class PackageManager
# of the first package isn't skewed by being the first to require atom
require '../exports/atom'
# TODO: remove after a few atom versions.
@uninstallAutocompletePlus()
packagePaths = @getAvailablePackagePaths()
packagePaths = packagePaths.filter (packagePath) => not @isPackageDisabled(path.basename(packagePath))
packagePaths = _.uniq packagePaths, (packagePath) -> path.basename(packagePath)
@@ -409,6 +412,40 @@ class PackageManager
message = "Failed to load the #{path.basename(packagePath)} package"
atom.notifications.addError(message, {stack, detail, dismissable: true})
# TODO: remove these autocomplete-plus specific helpers after a few versions.
uninstallAutocompletePlus: ->
packageDir = null
devDir = path.join("dev", "packages")
for packageDirPath in @packageDirPaths
if not packageDirPath.endsWith(devDir)
packageDir = packageDirPath
break
if packageDir?
dirsToRemove = [
path.join(packageDir, 'autocomplete-plus')
path.join(packageDir, 'autocomplete-atom-api')
path.join(packageDir, 'autocomplete-css')
path.join(packageDir, 'autocomplete-html')
path.join(packageDir, 'autocomplete-emojis')
path.join(packageDir, 'autocomplete-snippets')
]
for dirToRemove in dirsToRemove
@uninstallDirectory(dirToRemove)
return
uninstallDirectory: (directory) ->
symlinkPromise = new Promise (resolve) ->
fs.isSymbolicLink directory, (isSymLink) -> resolve(isSymLink)
dirPromise = new Promise (resolve) ->
fs.isDirectory directory, (isDir) -> resolve(isDir)
Promise.all([symlinkPromise, dirPromise]).then (values) ->
[isSymLink, isDir] = values
if not isSymLink and isDir
fs.remove directory, ->
if Grim.includeDeprecatedAPIs
EmitterMixin = require('emissary').Emitter
EmitterMixin.includeInto(PackageManager)

View File

@@ -84,12 +84,10 @@ class TextEditor extends Model
@selections = []
buffer ?= new TextBuffer
@displayBuffer ?= new DisplayBuffer({buffer, tabLength, softWrapped})
@displayBuffer ?= new DisplayBuffer({buffer, tabLength, softWrapped, ignoreInvisibles: @mini})
@buffer = @displayBuffer.buffer
@softTabs = @usesSoftTabs() ? @softTabs ? atom.config.get('editor.softTabs') ? true
@updateInvisibles()
for marker in @findMarkers(@getSelectionMarkerAttributes())
marker.setProperties(preserveFolds: true)
@addSelection(marker)
@@ -170,21 +168,9 @@ class TextEditor extends Model
@subscribe @displayBuffer.onDidAddDecoration (decoration) => @emit 'decoration-added', decoration
@subscribe @displayBuffer.onDidRemoveDecoration (decoration) => @emit 'decoration-removed', decoration
@subscribeToScopedConfigSettings()
subscribeToScopedConfigSettings: ->
@scopedConfigSubscriptions?.dispose()
@scopedConfigSubscriptions = subscriptions = new CompositeDisposable
scopeDescriptor = @getRootScopeDescriptor()
subscriptions.add atom.config.onDidChange 'editor.showInvisibles', scope: scopeDescriptor, => @updateInvisibles()
subscriptions.add atom.config.onDidChange 'editor.invisibles', scope: scopeDescriptor, => @updateInvisibles()
destroyed: ->
@unsubscribe() if includeDeprecatedAPIs
@disposables.dispose()
@scopedConfigSubscriptions.dispose()
selection.destroy() for selection in @getSelections()
@buffer.release()
@displayBuffer.destroy()
@@ -488,7 +474,7 @@ class TextEditor extends Model
setMini: (mini) ->
if mini isnt @mini
@mini = mini
@updateInvisibles()
@displayBuffer.setIgnoreInvisibles(@mini)
@emitter.emit 'did-change-mini', @mini
@mini
@@ -2779,15 +2765,6 @@ class TextEditor extends Model
shouldAutoIndentOnPaste: ->
atom.config.get("editor.autoIndentOnPaste", scope: @getRootScopeDescriptor())
shouldShowInvisibles: ->
not @mini and atom.config.get('editor.showInvisibles', scope: @getRootScopeDescriptor())
updateInvisibles: ->
if @shouldShowInvisibles()
@displayBuffer.setInvisibles(atom.config.get('editor.invisibles', scope: @getRootScopeDescriptor()))
else
@displayBuffer.setInvisibles(null)
###
Section: Event Handlers
###
@@ -2796,8 +2773,6 @@ class TextEditor extends Model
@softTabs = @usesSoftTabs() ? @softTabs
handleGrammarChange: ->
@updateInvisibles()
@subscribeToScopedConfigSettings()
@unfoldAll()
@emit 'grammar-changed' if includeDeprecatedAPIs
@emitter.emit 'did-change-grammar', @getGrammar()

View File

@@ -20,8 +20,9 @@ class TokenizedBuffer extends Model
chunkSize: 50
invalidRows: null
visible: false
configSettings: null
constructor: ({@buffer, @tabLength, @invisibles}) ->
constructor: ({@buffer, @tabLength, @ignoreInvisibles}) ->
@emitter = new Emitter
@disposables = new CompositeDisposable
@@ -39,7 +40,7 @@ class TokenizedBuffer extends Model
serializeParams: ->
bufferPath: @buffer.getPath()
tabLength: @tabLength
invisibles: _.clone(@invisibles)
ignoreInvisibles: @ignoreInvisibles
deserializeParams: (params) ->
params.buffer = atom.project.bufferForPathSync(params.bufferPath)
@@ -76,13 +77,25 @@ class TokenizedBuffer extends Model
@grammarUpdateDisposable = @grammar.onDidUpdate => @retokenizeLines()
@disposables.add(@grammarUpdateDisposable)
@configSettings = tabLength: atom.config.get('editor.tabLength', scope: @rootScopeDescriptor)
scopeOptions = {scope: @rootScopeDescriptor}
@configSettings =
tabLength: atom.config.get('editor.tabLength', scopeOptions)
invisibles: atom.config.get('editor.invisibles', scopeOptions)
showInvisibles: atom.config.get('editor.showInvisibles', scopeOptions)
@grammarTabLengthSubscription?.dispose()
@grammarTabLengthSubscription = atom.config.onDidChange 'editor.tabLength', scope: @rootScopeDescriptor, ({newValue}) =>
if @configSubscriptions?
@configSubscriptions.dispose()
@disposables.remove(@configSubscriptions)
@configSubscriptions = new CompositeDisposable
@configSubscriptions.add atom.config.onDidChange 'editor.tabLength', scopeOptions, ({newValue}) =>
@configSettings.tabLength = newValue
@retokenizeLines()
@disposables.add(@grammarTabLengthSubscription)
['invisibles', 'showInvisibles'].forEach (key) =>
@configSubscriptions.add atom.config.onDidChange "editor.#{key}", scopeOptions, ({newValue}) =>
oldInvisibles = @getInvisiblesToShow()
@configSettings[key] = newValue
@retokenizeLines() unless _.isEqual(@getInvisiblesToShow(), oldInvisibles)
@disposables.add(@configSubscriptions)
@retokenizeLines()
@@ -123,10 +136,11 @@ class TokenizedBuffer extends Model
@tabLength = tabLength
@retokenizeLines()
setInvisibles: (invisibles) ->
unless _.isEqual(invisibles, @invisibles)
@invisibles = invisibles
@retokenizeLines()
setIgnoreInvisibles: (ignoreInvisibles) ->
if ignoreInvisibles isnt @ignoreInvisibles
@ignoreInvisibles = ignoreInvisibles
if @configSettings.showInvisibles and @configSettings.invisibles?
@retokenizeLines()
tokenizeInBackground: ->
return if not @visible or @pendingChunk or not @isAlive()
@@ -302,7 +316,7 @@ class TokenizedBuffer extends Model
tabLength = @getTabLength()
indentLevel = @indentLevelForRow(row)
lineEnding = @buffer.lineEndingForRow(row)
new TokenizedLine({tokens, tabLength, indentLevel, @invisibles, lineEnding})
new TokenizedLine({tokens, tabLength, indentLevel, invisibles: @getInvisiblesToShow(), lineEnding})
buildTokenizedLineForRow: (row, ruleStack) ->
@buildTokenizedLineForRowWithText(row, @buffer.lineForRow(row), ruleStack)
@@ -312,7 +326,13 @@ class TokenizedBuffer extends Model
tabLength = @getTabLength()
indentLevel = @indentLevelForRow(row)
{tokens, ruleStack} = @grammar.tokenizeLine(line, ruleStack, row is 0)
new TokenizedLine({tokens, ruleStack, tabLength, lineEnding, indentLevel, @invisibles})
new TokenizedLine({tokens, ruleStack, tabLength, lineEnding, indentLevel, invisibles: @getInvisiblesToShow()})
getInvisiblesToShow: ->
if @configSettings.showInvisibles and not @ignoreInvisibles
@configSettings.invisibles
else
null
tokenizedLineForRow: (bufferRow) ->
@tokenizedLines[bufferRow]