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

View File

@ -6,6 +6,6 @@
"url": "https://github.com/atom/atom.git"
},
"dependencies": {
"atom-package-manager": "0.166.0"
"atom-package-manager": "0.167.0"
}
}

View File

@ -37,7 +37,7 @@
"fstream": "0.1.24",
"fuzzaldrin": "^2.1",
"git-utils": "^3.0.0",
"grim": "1.4.0",
"grim": "1.4.1",
"jasmine-json": "~0.0",
"jasmine-tagged": "^1.1.4",
"jquery": "^2.1.1",
@ -84,19 +84,24 @@
"solarized-dark-syntax": "0.35.0",
"solarized-light-syntax": "0.21.0",
"archive-view": "0.57.0",
"autocomplete": "0.47.0",
"autocomplete-atom-api": "0.9.0",
"autocomplete-css": "0.7.2",
"autocomplete-emojis": "2.2.2",
"autocomplete-html": "0.7.2",
"autocomplete-plus": "2.15.2",
"autocomplete-snippets": "1.6.1",
"autoflow": "0.23.0",
"autosave": "0.20.0",
"background-tips": "0.24.0",
"bookmarks": "0.35.0",
"bracket-matcher": "0.74.0",
"command-palette": "0.35.0",
"deprecation-cop": "0.46.0",
"deprecation-cop": "0.47.0",
"dev-live-reload": "0.46.0",
"encoding-selector": "0.20.0",
"exception-reporting": "0.24.0",
"find-and-replace": "0.161.0",
"fuzzy-finder": "0.83.0",
"find-and-replace": "0.162.0",
"fuzzy-finder": "0.84.0",
"git-diff": "0.55.0",
"go-to-line": "0.30.0",
"grammar-selector": "0.47.0",
@ -105,15 +110,15 @@
"keybinding-resolver": "0.32.0",
"link": "0.30.0",
"markdown-preview": "0.148.0",
"metrics": "0.45.0",
"notifications": "0.43.0",
"metrics": "0.47.0",
"notifications": "0.44.0",
"open-on-github": "0.36.0",
"package-generator": "0.39.0",
"release-notes": "0.52.0",
"settings-view": "0.199.0",
"snippets": "0.89.0",
"spell-check": "0.58.0",
"status-bar": "0.71.0",
"status-bar": "0.72.0",
"styleguide": "0.44.0",
"symbols-view": "0.96.0",
"tabs": "0.68.0",
@ -128,7 +133,7 @@
"language-coffee-script": "0.40.0",
"language-csharp": "0.5.0",
"language-css": "0.29.0",
"language-gfm": "0.73.0",
"language-gfm": "0.74.0",
"language-git": "0.10.0",
"language-go": "0.26.0",
"language-html": "0.37.0",

View File

@ -824,3 +824,37 @@ describe "PackageManager", ->
expect(atom.config.get('core.themes')).not.toContain packageName
expect(atom.config.get('core.themes')).not.toContain packageName
expect(atom.config.get('core.disabledPackages')).not.toContain packageName
describe "deleting non-bundled autocomplete packages", ->
[autocompleteCSSPath, autocompletePlusPath] = []
fs = require 'fs-plus'
path = require 'path'
beforeEach ->
fixturePath = path.resolve(__dirname, './fixtures/packages')
autocompleteCSSPath = path.join(fixturePath, 'autocomplete-css')
autocompletePlusPath = path.join(fixturePath, 'autocomplete-plus')
try
fs.mkdirSync(autocompleteCSSPath)
fs.writeFileSync(path.join(autocompleteCSSPath, 'package.json'), '{}')
fs.symlinkSync(path.join(fixturePath, 'package-with-main'), autocompletePlusPath, 'dir')
expect(fs.isDirectorySync(autocompleteCSSPath)).toBe true
expect(fs.isSymbolicLinkSync(autocompletePlusPath)).toBe true
jasmine.unspy(atom.packages, 'uninstallAutocompletePlus')
afterEach ->
try
fs.unlink autocompletePlusPath, ->
it "removes the packages", ->
atom.packages.loadPackages()
waitsFor ->
not fs.isDirectorySync(autocompleteCSSPath)
runs ->
expect(fs.isDirectorySync(autocompleteCSSPath)).toBe false
expect(fs.isSymbolicLinkSync(autocompletePlusPath)).toBe true

View File

@ -140,6 +140,8 @@ beforeEach ->
spyOn(clipboard, 'writeText').andCallFake (text) -> clipboardContent = text
spyOn(clipboard, 'readText').andCallFake -> clipboardContent
spyOn(atom.packages, 'uninstallAutocompletePlus')
addCustomMatchers(this)
afterEach ->

View File

@ -36,23 +36,21 @@ describe "TextEditor", ->
it "preserves the invisibles setting", ->
atom.config.set('editor.showInvisibles', true)
previousInvisibles = editor.displayBuffer.invisibles
previousInvisibles = editor.tokenizedLineForScreenRow(0).invisibles
editor2 = editor.testSerialization()
expect(editor2.displayBuffer.invisibles).toEqual previousInvisibles
expect(editor2.displayBuffer.tokenizedBuffer.invisibles).toEqual previousInvisibles
expect(previousInvisibles).toBeDefined()
expect(editor2.displayBuffer.tokenizedLineForScreenRow(0).invisibles).toEqual previousInvisibles
it "updates invisibles if the settings have changed between serialization and deserialization", ->
atom.config.set('editor.showInvisibles', true)
previousInvisibles = editor.displayBuffer.invisibles
state = editor.serialize()
atom.config.set('editor.invisibles', eol: '?')
editor2 = TextEditor.deserialize(state)
expect(editor2.displayBuffer.invisibles.eol).toBe '?'
expect(editor2.displayBuffer.tokenizedBuffer.invisibles.eol).toBe '?'
expect(editor.tokenizedLineForScreenRow(0).invisibles.eol).toBe '?'
describe "when the editor is constructed with an initialLine option", ->
it "positions the cursor on the specified line", ->

View File

@ -611,7 +611,8 @@ describe "TokenizedBuffer", ->
tokenizedBuffer = new TokenizedBuffer({buffer})
fullyTokenize(tokenizedBuffer)
tokenizedBuffer.setInvisibles(space: 'S', tab: 'T')
atom.config.set("editor.showInvisibles", true)
atom.config.set("editor.invisibles", space: 'S', tab: 'T')
fullyTokenize(tokenizedBuffer)
expect(tokenizedBuffer.tokenizedLineForRow(0).text).toBe "SST Sa line with tabsTand T spacesSTS"
@ -623,7 +624,7 @@ describe "TokenizedBuffer", ->
tokenizedBuffer = new TokenizedBuffer({buffer})
atom.config.set('editor.showInvisibles', true)
tokenizedBuffer.setInvisibles(cr: 'R', eol: 'N')
atom.config.set("editor.invisibles", cr: 'R', eol: 'N')
fullyTokenize(tokenizedBuffer)
expect(tokenizedBuffer.tokenizedLineForRow(0).endOfLineInvisibles).toEqual ['R', 'N']
@ -634,7 +635,7 @@ describe "TokenizedBuffer", ->
expect(left.endOfLineInvisibles).toBe null
expect(right.endOfLineInvisibles).toEqual ['R', 'N']
tokenizedBuffer.setInvisibles(cr: 'R', eol: false)
atom.config.set("editor.invisibles", cr: 'R', eol: false)
expect(tokenizedBuffer.tokenizedLineForRow(0).endOfLineInvisibles).toEqual ['R']
expect(tokenizedBuffer.tokenizedLineForRow(1).endOfLineInvisibles).toEqual []
@ -688,7 +689,8 @@ describe "TokenizedBuffer", ->
it "sets leading and trailing whitespace correctly on a line with invisible characters that is copied", ->
buffer.setText(" \t a line with tabs\tand \tspaces \t ")
tokenizedBuffer.setInvisibles(space: 'S', tab: 'T')
atom.config.set("editor.showInvisibles", true)
atom.config.set("editor.invisibles", space: 'S', tab: 'T')
fullyTokenize(tokenizedBuffer)
line = tokenizedBuffer.tokenizedLineForRow(0).copy()
@ -696,7 +698,8 @@ describe "TokenizedBuffer", ->
expect(line.tokens[line.tokens.length - 1].firstTrailingWhitespaceIndex).toBe 0
it "sets the ::firstNonWhitespaceIndex and ::firstTrailingWhitespaceIndex correctly when tokens are split for soft-wrapping", ->
tokenizedBuffer.setInvisibles(space: 'S')
atom.config.set("editor.showInvisibles", true)
atom.config.set("editor.invisibles", space: 'S')
buffer.setText(" token ")
fullyTokenize(tokenizedBuffer)
token = tokenizedBuffer.tokenizedLines[0].tokens[0]

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]

View File

@ -1,8 +1,6 @@
<!DOCTYPE html>
<html style="background: #fff">
<html>
<head>
<title></title>
<meta http-equiv="Content-Security-Policy" content="default-src *; script-src 'self'; style-src 'self' 'unsafe-inline';">
<script src="index.js"></script>

View File

@ -1,6 +1,9 @@
var fs = require('fs');
var path = require('path');
var loadSettings = null;
var loadSettingsError = null;
window.onload = function() {
try {
var startTime = Date.now();
@ -12,30 +15,19 @@ window.onload = function() {
// Ensure ATOM_HOME is always set before anything else is required
setupAtomHome();
var cacheDir = path.join(process.env.ATOM_HOME, 'compile-cache');
// Use separate compile cache when sudo'ing as root to avoid permission issues
if (process.env.USER === 'root' && process.env.SUDO_USER && process.env.SUDO_USER !== process.env.USER) {
cacheDir = path.join(cacheDir, 'root');
}
var rawLoadSettings = decodeURIComponent(location.hash.substr(1));
var loadSettings;
try {
loadSettings = JSON.parse(rawLoadSettings);
} catch (error) {
console.error("Failed to parse load settings: " + rawLoadSettings);
throw error;
}
// Normalize to make sure drive letter case is consistent on Windows
process.resourcesPath = path.normalize(process.resourcesPath);
if (loadSettingsError) {
throw loadSettingsError;
}
var devMode = loadSettings.devMode || !loadSettings.resourcePath.startsWith(process.resourcesPath + path.sep);
if (loadSettings.profileStartup) {
profileStartup(cacheDir, loadSettings, Date.now() - startTime);
profileStartup(loadSettings, Date.now() - startTime);
} else {
setupWindow(cacheDir, loadSettings);
setupWindow(loadSettings);
setLoadTime(Date.now() - startTime);
}
} catch (error) {
@ -43,6 +35,15 @@ window.onload = function() {
}
}
var getCacheDirectory = function() {
var cacheDir = path.join(process.env.ATOM_HOME, 'compile-cache');
// Use separate compile cache when sudo'ing as root to avoid permission issues
if (process.env.USER === 'root' && process.env.SUDO_USER && process.env.SUDO_USER !== process.env.USER) {
cacheDir = path.join(cacheDir, 'root');
}
return cacheDir;
}
var setLoadTime = function(loadTime) {
if (global.atom) {
global.atom.loadTime = loadTime;
@ -59,7 +60,9 @@ var handleSetupError = function(error) {
console.error(error.stack || error);
}
var setupWindow = function(cacheDir, loadSettings) {
var setupWindow = function(loadSettings) {
var cacheDir = getCacheDirectory();
setupCoffeeCache(cacheDir);
ModuleCache = require('../src/module-cache');
@ -133,16 +136,17 @@ var setupSourceMapCache = function(cacheDir) {
var setupVmCompatibility = function() {
var vm = require('vm');
if (!vm.Script.createContext)
if (!vm.Script.createContext) {
vm.Script.createContext = vm.createContext;
}
}
var profileStartup = function(cacheDir, loadSettings, initialTime) {
var profileStartup = function(loadSettings, initialTime) {
var profile = function() {
console.profile('startup');
try {
var startTime = Date.now()
setupWindow(cacheDir, loadSettings);
setupWindow(loadSettings);
setLoadTime(Date.now() - startTime + initialTime);
} catch (error) {
handleSetupError(error);
@ -162,3 +166,41 @@ var profileStartup = function(cacheDir, loadSettings, initialTime) {
});
}
}
var parseLoadSettings = function() {
var rawLoadSettings = decodeURIComponent(location.hash.substr(1));
try {
loadSettings = JSON.parse(rawLoadSettings);
} catch (error) {
console.error("Failed to parse load settings: " + rawLoadSettings);
loadSettingsError = error;
}
}
var setupWindowBackground = function() {
if (loadSettings && loadSettings.isSpec) {
return;
}
var backgroundColor = window.localStorage.getItem('atom:window-background-color');
if (!backgroundColor) {
return;
}
var backgroundStylesheet = document.createElement('style');
backgroundStylesheet.type = 'text/css';
backgroundStylesheet.innerText = 'html, body { background: ' + backgroundColor + '; }';
document.head.appendChild(backgroundStylesheet);
// Remove once the page loads
window.addEventListener("load", function loadWindow() {
window.removeEventListener("load", loadWindow, false);
setTimeout(function() {
backgroundStylesheet.remove();
backgroundStylesheet = null;
}, 1000);
}, false);
}
parseLoadSettings();
setupWindowBackground();