Merge branch 'as-minimize-startup-sync-io' into as-ns-startup-snapshot

This commit is contained in:
Antonio Scandurra
2017-03-07 11:25:41 +01:00
28 changed files with 3699 additions and 3072 deletions

View File

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

View File

@@ -10,7 +10,7 @@ In this directory you can only find very specific build and API level documentat
Instructions for building Atom on various platforms from source.
* [macOS](./build-instructions/macos.md)
* [macOS](./build-instructions/macOS.md)
* [Windows](./build-instructions/windows.md)
* [Linux](./build-instructions/linux.md)
* [FreeBSD](./build-instructions/freebsd.md)

View File

@@ -15,7 +15,7 @@
"electronVersion": "1.3.13",
"dependencies": {
"async": "0.2.6",
"atom-keymap": "7.1.21",
"atom-keymap": "7.1.22",
"atom-select-list": "0.0.15",
"atom-ui": "0.4.1",
"babel-core": "6.22.1",
@@ -40,8 +40,8 @@
"devtron": "1.3.0",
"event-kit": "^2.1.0",
"find-parent-dir": "^0.3.0",
"first-mate": "6.1.0",
"fs-plus": "2.9.2",
"first-mate": "6.3.0",
"fs-plus": "2.10.1",
"fstream": "0.1.24",
"fuzzaldrin": "^2.1",
"git-utils": "4.1.2",
@@ -60,7 +60,7 @@
"normalize-package-data": "^2.0.0",
"nslog": "^3",
"oniguruma": "6.1.0",
"pathwatcher": "6.8.0",
"pathwatcher": "6.9.0",
"postcss": "5.2.4",
"postcss-selector-parser": "2.2.1",
"property-accessors": "^1.1.3",
@@ -76,7 +76,7 @@
"sinon": "1.17.4",
"source-map-support": "^0.3.2",
"temp": "0.8.1",
"text-buffer": "10.3.12",
"text-buffer": "10.4.2",
"typescript-simple": "1.0.0",
"underscore-plus": "^1.6.6",
"winreg": "^1.2.1",
@@ -89,16 +89,16 @@
"atom-light-ui": "0.46.0",
"base16-tomorrow-dark-theme": "1.5.0",
"base16-tomorrow-light-theme": "1.5.0",
"one-dark-ui": "1.9.1",
"one-light-ui": "1.9.1",
"one-dark-ui": "1.9.2",
"one-light-ui": "1.9.2",
"one-dark-syntax": "1.7.1",
"one-light-syntax": "1.7.1",
"solarized-dark-syntax": "1.1.2",
"solarized-light-syntax": "1.1.2",
"about": "1.7.4",
"archive-view": "0.62.2",
"about": "1.7.5",
"archive-view": "0.63.0",
"autocomplete-atom-api": "0.10.0",
"autocomplete-css": "0.15.0",
"autocomplete-css": "0.15.1",
"autocomplete-html": "0.7.2",
"autocomplete-plus": "2.34.2",
"autocomplete-snippets": "1.11.0",
@@ -112,10 +112,10 @@
"deprecation-cop": "0.56.2",
"dev-live-reload": "0.47.0",
"encoding-selector": "0.23.2",
"exception-reporting": "0.41.1",
"find-and-replace": "0.206.3",
"fuzzy-finder": "1.4.1",
"git-diff": "1.3.2",
"exception-reporting": "0.41.2",
"find-and-replace": "0.207.0",
"fuzzy-finder": "1.5.0",
"git-diff": "1.3.3",
"go-to-line": "0.32.0",
"grammar-selector": "0.49.3",
"image-view": "0.61.1",
@@ -128,51 +128,51 @@
"notifications": "0.66.2",
"open-on-github": "1.2.1",
"package-generator": "1.1.0",
"settings-view": "0.247.2",
"snippets": "1.0.5",
"settings-view": "0.248.0",
"snippets": "1.1.1",
"spell-check": "0.71.1",
"status-bar": "1.8.1",
"status-bar": "1.8.3",
"styleguide": "0.49.3",
"symbols-view": "0.114.0",
"tabs": "0.104.1",
"symbols-view": "0.115.2",
"tabs": "0.104.2",
"timecop": "0.36.0",
"tree-view": "0.214.1",
"update-package-dependencies": "0.10.0",
"tree-view": "0.215.1",
"update-package-dependencies": "0.11.0",
"welcome": "0.36.2",
"whitespace": "0.36.2",
"wrap-guide": "0.39.1",
"language-c": "0.56.0",
"wrap-guide": "0.40.0",
"language-c": "0.57.0",
"language-clojure": "0.22.2",
"language-coffee-script": "0.48.4",
"language-coffee-script": "0.48.5",
"language-csharp": "0.14.2",
"language-css": "0.42.0",
"language-gfm": "0.88.0",
"language-gfm": "0.88.1",
"language-git": "0.19.0",
"language-go": "0.43.1",
"language-html": "0.47.2",
"language-hyperlink": "0.16.1",
"language-java": "0.26.0",
"language-java": "0.27.0",
"language-javascript": "0.126.1",
"language-json": "0.18.3",
"language-less": "0.30.1",
"language-json": "0.19.0",
"language-less": "0.31.0",
"language-make": "0.22.3",
"language-mustache": "0.13.1",
"language-objective-c": "0.15.1",
"language-perl": "0.37.0",
"language-php": "0.37.4",
"language-property-list": "0.9.0",
"language-php": "0.37.5",
"language-property-list": "0.9.1",
"language-python": "0.45.2",
"language-ruby": "0.70.5",
"language-ruby-on-rails": "0.25.2",
"language-sass": "0.57.1",
"language-sass": "0.58.0",
"language-shellscript": "0.25.0",
"language-source": "0.9.0",
"language-sql": "0.25.3",
"language-text": "0.7.1",
"language-text": "0.7.2",
"language-todo": "0.29.1",
"language-toml": "0.18.1",
"language-xml": "0.34.16",
"language-yaml": "0.28.0"
"language-xml": "0.35.0",
"language-yaml": "0.29.0"
},
"private": true,
"scripts": {

View File

@@ -7,7 +7,11 @@ URL: https://atom.io/
AutoReqProv: no # Avoid libchromiumcontent.so missing dependency
Prefix: <%= installDir %>
%ifarch i386 i486 i586 i686
Requires: lsb-core-noarch, libXss.so.1
%else
Requires: lsb-core-noarch, libXss.so.1()(64bit)
%endif
%description
<%= description %>

View File

@@ -126,6 +126,7 @@ describe "AtomEnvironment", ->
beforeEach ->
errors = []
spyOn(atom, 'isReleasedVersion').andReturn(true)
atom.onDidFailAssertion (error) -> errors.push(error)
describe "if the condition is false", ->
@@ -147,6 +148,11 @@ describe "AtomEnvironment", ->
atom.assert(false, "a == b", {foo: 'bar'})
expect(errors[0].metadata).toEqual {foo: 'bar'}
describe "when Atom has been built from source", ->
it "throws an error", ->
atom.isReleasedVersion.andReturn(false)
expect(-> atom.assert(false, 'testing')).toThrow('Assertion failed: testing')
describe "if the condition is true", ->
it "does nothing", ->
result = atom.assert(true, "a == b")

View File

@@ -3,7 +3,10 @@ const DOMElementPool = require ('../src/dom-element-pool')
describe('DOMElementPool', function () {
let domElementPool
beforeEach(() => { domElementPool = new DOMElementPool() })
beforeEach(() => {
domElementPool = new DOMElementPool()
spyOn(atom, 'isReleasedVersion').andReturn(true)
})
it('builds DOM nodes, recycling them when they are freed', function () {
let elements

View File

@@ -4,27 +4,24 @@ import {it, fit, ffit, fffit, beforeEach, afterEach} from './async-spec-helpers'
import {Emitter, Disposable, CompositeDisposable} from 'event-kit'
import {HistoryManager, HistoryProject} from '../src/history-manager'
import StateStore from '../src/state-store'
describe("HistoryManager", () => {
let historyManager, commandRegistry, project, localStorage, stateStore
let historyManager, commandRegistry, project, stateStore
let commandDisposable, projectDisposable
beforeEach(() => {
beforeEach(async () => {
commandDisposable = jasmine.createSpyObj('Disposable', ['dispose'])
commandRegistry = jasmine.createSpyObj('CommandRegistry', ['add'])
commandRegistry.add.andReturn(commandDisposable)
localStorage = jasmine.createSpyObj('LocalStorage', ['getItem', 'setItem'])
localStorage.items = {
history: JSON.stringify({
projects: [
{ paths: ['/1', 'c:\\2'], lastOpened: new Date(2016, 9, 17, 17, 16, 23) },
{ paths: ['/test'], lastOpened: new Date(2016, 9, 17, 11, 12, 13) }
]
})
}
localStorage.getItem.andCallFake((key) => localStorage.items[key])
localStorage.setItem.andCallFake((key, value) => localStorage.items[key] = value)
stateStore = new StateStore('history-manager-test', 1)
await stateStore.save('history-manager', {
projects: [
{paths: ['/1', 'c:\\2'], lastOpened: new Date(2016, 9, 17, 17, 16, 23)},
{paths: ['/test'], lastOpened: new Date(2016, 9, 17, 11, 12, 13)}
]
})
projectDisposable = jasmine.createSpyObj('Disposable', ['dispose'])
project = jasmine.createSpyObj('Project', ['onDidChangePaths'])
@@ -33,7 +30,12 @@ describe("HistoryManager", () => {
return projectDisposable
})
historyManager = new HistoryManager({project, commands:commandRegistry, localStorage})
historyManager = new HistoryManager({stateStore, project, commands: commandRegistry})
await historyManager.loadState()
})
afterEach(async () => {
await stateStore.clear()
})
describe("constructor", () => {
@@ -65,33 +67,28 @@ describe("HistoryManager", () => {
})
describe("clearProjects", () => {
it("clears the list of projects", () => {
it("clears the list of projects", async () => {
expect(historyManager.getProjects().length).not.toBe(0)
historyManager.clearProjects()
await historyManager.clearProjects()
expect(historyManager.getProjects().length).toBe(0)
})
it("saves the state", () => {
expect(localStorage.setItem).not.toHaveBeenCalled()
historyManager.clearProjects()
expect(localStorage.setItem).toHaveBeenCalled()
expect(localStorage.setItem.calls[0].args[0]).toBe('history')
it("saves the state", async () => {
await historyManager.clearProjects()
const historyManager2 = new HistoryManager({stateStore, project, commands: commandRegistry})
await historyManager2.loadState()
expect(historyManager.getProjects().length).toBe(0)
})
it("fires the onDidChangeProjects event", () => {
expect(localStorage.setItem).not.toHaveBeenCalled()
historyManager.clearProjects()
expect(localStorage.setItem).toHaveBeenCalled()
expect(localStorage.setItem.calls[0].args[0]).toBe('history')
it("fires the onDidChangeProjects event", async () => {
const didChangeSpy = jasmine.createSpy()
historyManager.onDidChangeProjects(didChangeSpy)
await historyManager.clearProjects()
expect(historyManager.getProjects().length).toBe(0)
expect(didChangeSpy).toHaveBeenCalled()
})
})
it("loads state", () => {
expect(localStorage.getItem).toHaveBeenCalledWith('history')
})
it("listens to project.onDidChangePaths adding a new project", () => {
const start = new Date()
project.didChangePathsListener(['/a/new', '/path/or/two'])
@@ -112,61 +109,61 @@ describe("HistoryManager", () => {
})
describe("loadState", () => {
it("defaults to an empty array if no state", () => {
localStorage.items.history = null
historyManager.loadState()
it("defaults to an empty array if no state", async () => {
await stateStore.clear()
await historyManager.loadState()
expect(historyManager.getProjects()).toEqual([])
})
it("defaults to an empty array if no projects", () => {
localStorage.items.history = JSON.stringify('')
historyManager.loadState()
it("defaults to an empty array if no projects", async () => {
await stateStore.save('history-manager', {})
await historyManager.loadState()
expect(historyManager.getProjects()).toEqual([])
})
})
describe("addProject", () => {
it("adds a new project to the end", () => {
it("adds a new project to the end", async () => {
const date = new Date(2010, 10, 9, 8, 7, 6)
historyManager.addProject(['/a/b'], date)
await historyManager.addProject(['/a/b'], date)
const projects = historyManager.getProjects()
expect(projects.length).toBe(3)
expect(projects[2].paths).toEqual(['/a/b'])
expect(projects[2].lastOpened).toBe(date)
})
it("adds a new project to the start", () => {
it("adds a new project to the start", async () => {
const date = new Date()
historyManager.addProject(['/so/new'], date)
await historyManager.addProject(['/so/new'], date)
const projects = historyManager.getProjects()
expect(projects.length).toBe(3)
expect(projects[0].paths).toEqual(['/so/new'])
expect(projects[0].lastOpened).toBe(date)
})
it("updates an existing project and moves it to the start", () => {
it("updates an existing project and moves it to the start", async () => {
const date = new Date()
historyManager.addProject(['/test'], date)
await historyManager.addProject(['/test'], date)
const projects = historyManager.getProjects()
expect(projects.length).toBe(2)
expect(projects[0].paths).toEqual(['/test'])
expect(projects[0].lastOpened).toBe(date)
})
it("fires the onDidChangeProjects event when adding a project", () => {
it("fires the onDidChangeProjects event when adding a project", async () => {
const didChangeSpy = jasmine.createSpy()
const beforeCount = historyManager.getProjects().length
historyManager.onDidChangeProjects(didChangeSpy)
historyManager.addProject(['/test-new'], new Date())
await historyManager.addProject(['/test-new'], new Date())
expect(didChangeSpy).toHaveBeenCalled()
expect(historyManager.getProjects().length).toBe(beforeCount + 1)
})
it("fires the onDidChangeProjects event when updating a project", () => {
it("fires the onDidChangeProjects event when updating a project", async () => {
const didChangeSpy = jasmine.createSpy()
const beforeCount = historyManager.getProjects().length
historyManager.onDidChangeProjects(didChangeSpy)
historyManager.addProject(['/test'], new Date())
await historyManager.addProject(['/test'], new Date())
expect(didChangeSpy).toHaveBeenCalled()
expect(historyManager.getProjects().length).toBe(beforeCount)
})
@@ -186,14 +183,12 @@ describe("HistoryManager", () => {
})
describe("saveState" ,() => {
it("saves the state", () => {
historyManager.addProject(["/save/state"])
historyManager.saveState()
expect(localStorage.setItem).toHaveBeenCalled()
expect(localStorage.setItem.calls[0].args[0]).toBe('history')
expect(localStorage.items['history']).toContain('/save/state')
historyManager.loadState()
expect(historyManager.getProjects()[0].paths).toEqual(['/save/state'])
it("saves the state", async () => {
await historyManager.addProject(["/save/state"])
await historyManager.saveState()
const historyManager2 = new HistoryManager({stateStore, project, commands: commandRegistry})
await historyManager2.loadState()
expect(historyManager2.getProjects()[0].paths).toEqual(['/save/state'])
})
})
})

View File

@@ -5,7 +5,7 @@ describe "PanelContainer", ->
[container] = []
class TestPanelItem
constructior: ->
constructor: ->
beforeEach ->
container = new PanelContainer
@@ -39,6 +39,23 @@ describe "PanelContainer", ->
panel1.destroy()
expect(removePanelSpy).toHaveBeenCalledWith({panel: panel1, index: 0})
describe "::destroy()", ->
it "destroys the container and all of its panels", ->
destroyedPanels = []
panel1 = new Panel(item: new TestPanelItem())
panel1.onDidDestroy -> destroyedPanels.push(panel1)
container.addPanel(panel1)
panel2 = new Panel(item: new TestPanelItem())
panel2.onDidDestroy -> destroyedPanels.push(panel2)
container.addPanel(panel2)
container.destroy()
expect(container.getPanels().length).toBe(0)
expect(destroyedPanels).toEqual([panel1, panel2])
describe "panel priority", ->
describe 'left / top panel container', ->
[initialPanel] = []

View File

@@ -28,7 +28,13 @@ describe "TextEditor", ->
editor.foldBufferRow(4)
expect(editor.isFoldedAtBufferRow(4)).toBeTruthy()
editor2 = TextEditor.deserialize(editor.serialize(), atom)
editor2 = TextEditor.deserialize(editor.serialize(), {
assert: atom.assert,
textEditors: atom.textEditors,
project: {
bufferForIdSync: (id) -> TextBuffer.deserialize(editor.buffer.serialize())
}
})
expect(editor2.id).toBe editor.id
expect(editor2.getBuffer().getPath()).toBe editor.getBuffer().getPath()

View File

@@ -54,12 +54,10 @@ describe "WorkspaceElement", ->
it "updates the font-family based on the 'editor.fontFamily' config value", ->
initialCharWidth = editor.getDefaultCharWidth()
fontFamily = atom.config.get('editor.fontFamily')
fontFamily += ', "Apple Color Emoji"' if process.platform is 'darwin'
expect(getComputedStyle(editorElement).fontFamily).toBe fontFamily
atom.config.set('editor.fontFamily', 'sans-serif')
fontFamily = atom.config.get('editor.fontFamily')
fontFamily += ', "Apple Color Emoji"' if process.platform is 'darwin'
expect(getComputedStyle(editorElement).fontFamily).toBe fontFamily
expect(editor.getDefaultCharWidth()).not.toBe initialCharWidth

File diff suppressed because it is too large Load Diff

2082
spec/workspace-spec.js Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
_ = require 'underscore-plus'
{screen, ipcRenderer, remote, shell, webFrame} = require 'electron'
{ipcRenderer, remote, shell} = require 'electron'
ipcHelpers = require './ipc-helpers'
{Disposable} = require 'event-kit'
getWindowLoadSettings = require './get-window-load-settings'
@@ -80,6 +80,12 @@ class ApplicationDelegate
setWindowFullScreen: (fullScreen=false) ->
ipcHelpers.call('window-method', 'setFullScreen', fullScreen)
onDidEnterFullScreen: (callback) ->
ipcHelpers.on(ipcRenderer, 'did-enter-full-screen', callback)
onDidLeaveFullScreen: (callback) ->
ipcHelpers.on(ipcRenderer, 'did-leave-full-screen', callback)
openWindowDevTools: ->
# Defer DevTools interaction to the next tick, because using them during
# event handling causes some wrong input events to be triggered on
@@ -254,20 +260,6 @@ class ApplicationDelegate
openExternal: (url) ->
shell.openExternal(url)
disableZoom: ->
outerCallback = ->
webFrame.setZoomLevelLimits(1, 1)
outerCallback()
# Set the limits every time a display is added or removed, otherwise the
# configuration gets reset to the default, which allows zooming the
# webframe.
screen.on('display-added', outerCallback)
screen.on('display-removed', outerCallback)
new Disposable ->
screen.removeListener('display-added', outerCallback)
screen.removeListener('display-removed', outerCallback)
checkForUpdate: ->
ipcRenderer.send('command', 'application:check-for-update')

View File

@@ -215,8 +215,6 @@ class AtomEnvironment extends Model
@stylesElement = @styles.buildStylesElement()
@document.head.appendChild(@stylesElement)
@disposables.add(@applicationDelegate.disableZoom())
@keymaps.subscribeToFileReadFailure()
@keymaps.loadBundledKeymaps()
@@ -231,14 +229,12 @@ class AtomEnvironment extends Model
@observeAutoHideMenuBar()
@history = new HistoryManager({@project, @commands, localStorage})
@history = new HistoryManager({@project, @commands, @stateStore})
# Keep instances of HistoryManager in sync
@history.onDidChangeProjects (e) =>
@disposables.add @history.onDidChangeProjects (e) =>
@applicationDelegate.didChangeHistoryManager() unless e.reloaded
@disposables.add @applicationDelegate.onDidChangeHistoryManager(=> @history.loadState())
new ReopenProjectMenuManager({@menu, @commands, @history, @config, open: (paths) => @open(pathsToOpen: paths)})
attachSaveStateListeners: ->
saveState = _.debounce((=>
window.requestIdleCallback => @saveState({isUnloading: false}) unless @unloaded
@@ -716,7 +712,14 @@ class AtomEnvironment extends Model
@openInitialEmptyEditorIfNecessary()
Promise.all([loadStatePromise, updateProcessEnvPromise])
loadHistoryPromise = @history.loadState().then =>
@reopenProjectMenuManager = new ReopenProjectMenuManager({
@menu, @commands, @history, @config,
open: (paths) => @open(pathsToOpen: paths)
})
@reopenProjectMenuManager.update()
Promise.all([loadStatePromise, loadHistoryPromise, updateProcessEnvPromise])
serialize: (options) ->
version: @constructor.version
@@ -844,6 +847,8 @@ class AtomEnvironment extends Model
error.metadata = callbackOrMetadata
@emitter.emit 'did-fail-assertion', error
unless @isReleasedVersion()
throw error
false

View File

@@ -839,7 +839,7 @@ class Config
relativePath = sourcePath.substring(templateConfigDirPath.length + 1)
destinationPath = path.join(@configDirPath, relativePath)
queue.push({sourcePath, destinationPath})
fs.traverseTree(templateConfigDirPath, onConfigDirFile, (path) -> true)
fs.traverseTree(templateConfigDirPath, onConfigDirFile, ((path) -> true), (->))
loadUserConfig: ->
return if @shouldNotAccessFileSystem()

View File

@@ -4,7 +4,7 @@ let windowLoadSettings = null
module.exports = () => {
if (!windowLoadSettings) {
windowLoadSettings = remote.getCurrentWindow().loadSettings
windowLoadSettings = JSON.parse(remote.getCurrentWindow().loadSettingsJSON)
}
return windowLoadSettings
}

View File

@@ -15,7 +15,7 @@ PathSplitRegex = new RegExp("[/.]")
module.exports =
class GrammarRegistry extends FirstMate.GrammarRegistry
constructor: ({@config}={}) ->
super(maxTokensPerLine: 100)
super(maxTokensPerLine: 100, maxLineLength: 1000)
createToken: (value, scopes) -> new Token({value, scopes})

View File

@@ -1,6 +1,6 @@
/** @babel */
import {Emitter} from 'event-kit'
import {Emitter, CompositeDisposable} from 'event-kit'
// Extended: History manager for remembering which projects have been opened.
//
@@ -8,12 +8,17 @@ import {Emitter} from 'event-kit'
//
// The project history is used to enable the 'Reopen Project' menu.
export class HistoryManager {
constructor ({project, commands, localStorage}) {
this.localStorage = localStorage
commands.add('atom-workspace', {'application:clear-project-history': this.clearProjects.bind(this)})
constructor ({stateStore, project, commands}) {
this.stateStore = stateStore
this.emitter = new Emitter()
this.loadState()
project.onDidChangePaths((projectPaths) => this.addProject(projectPaths))
this.projects = []
this.disposables = new CompositeDisposable()
this.disposables.add(commands.add('atom-workspace', {'application:clear-project-history': this.clearProjects.bind(this)}))
this.disposables.add(project.onDidChangePaths((projectPaths) => this.addProject(projectPaths)))
}
destroy () {
this.disposables.dispose()
}
// Public: Obtain a list of previously opened projects.
@@ -27,9 +32,12 @@ export class HistoryManager {
//
// Note: This is not a privacy function - other traces will still exist,
// e.g. window state.
clearProjects () {
//
// Return a {Promise} that resolves when the history has been successfully
// cleared.
async clearProjects () {
this.projects = []
this.saveState()
await this.saveState()
this.didChangeProjects()
}
@@ -46,7 +54,7 @@ export class HistoryManager {
this.emitter.emit('did-change-projects', args || { reloaded: false })
}
addProject (paths, lastOpened) {
async addProject (paths, lastOpened) {
if (paths.length === 0) return
let project = this.getProject(paths)
@@ -57,11 +65,11 @@ export class HistoryManager {
project.lastOpened = lastOpened || new Date()
this.projects.sort((a, b) => b.lastOpened - a.lastOpened)
this.saveState()
await this.saveState()
this.didChangeProjects()
}
removeProject (paths) {
async removeProject (paths) {
if (paths.length === 0) return
let project = this.getProject(paths)
@@ -70,7 +78,7 @@ export class HistoryManager {
let index = this.projects.indexOf(project)
this.projects.splice(index, 1)
this.saveState()
await this.saveState()
this.didChangeProjects()
}
@@ -84,31 +92,25 @@ export class HistoryManager {
return null
}
loadState () {
const state = JSON.parse(this.localStorage.getItem('history'))
if (state && state.projects) {
this.projects = state.projects.filter(p => Array.isArray(p.paths) && p.paths.length > 0).map(p => new HistoryProject(p.paths, new Date(p.lastOpened)))
this.didChangeProjects({ reloaded: true })
async loadState () {
const history = await this.stateStore.load('history-manager')
if (history && history.projects) {
this.projects = history.projects.filter(p => Array.isArray(p.paths) && p.paths.length > 0).map(p => new HistoryProject(p.paths, new Date(p.lastOpened)))
this.didChangeProjects({reloaded: true})
} else {
this.projects = []
}
}
saveState () {
const state = JSON.stringify({
projects: this.projects.map(p => ({
paths: p.paths, lastOpened: p.lastOpened
}))
})
this.localStorage.setItem('history', state)
async saveState () {
const projects = this.projects.map(p => ({paths: p.paths, lastOpened: p.lastOpened}))
await this.stateStore.save('history-manager', {projects})
}
async importProjectHistory () {
for (let project of await HistoryImporter.getAllProjects()) {
this.addProject(project.paths, project.lastOpened)
await this.addProject(project.paths, project.lastOpened)
}
this.saveState()
this.didChangeProjects()
}
}

View File

@@ -6,8 +6,8 @@ StorageFolder = require '../storage-folder'
Config = require '../config'
FileRecoveryService = require './file-recovery-service'
ipcHelpers = require '../ipc-helpers'
{BrowserWindow, Menu, app, dialog, ipcMain, shell} = require 'electron'
{CompositeDisposable} = require 'event-kit'
{BrowserWindow, Menu, app, dialog, ipcMain, shell, screen} = require 'electron'
{CompositeDisposable, Disposable} = require 'event-kit'
fs = require 'fs-plus'
path = require 'path'
os = require 'os'
@@ -89,7 +89,7 @@ class AtomApplication
if process.platform is 'darwin' and @config.get('core.useCustomTitleBar')
@config.unset('core.useCustomTitleBar')
@config.set('core.titleBar', 'custom')
@config.onDidChange 'core.titleBar', @promptForRestart.bind(this)
@autoUpdateManager = new AutoUpdateManager(
@@ -394,6 +394,8 @@ class AtomApplication
@disposable.add ipcHelpers.on ipcMain, 'did-change-paths', =>
@saveState(false)
@disposable.add(@disableZoomOnDisplayChange())
setupDockMenu: ->
if process.platform is 'darwin'
dockMenu = Menu.buildFromTemplate [
@@ -812,3 +814,17 @@ class AtomApplication
args.push("--resource-path=#{@resourcePath}")
app.relaunch({args})
app.quit()
disableZoomOnDisplayChange: ->
outerCallback = =>
for window in @windows
window.disableZoom()
# Set the limits every time a display is added or removed, otherwise the
# configuration gets reset to the default, which allows zooming the
# webframe.
screen.on('display-added', outerCallback)
screen.on('display-removed', outerCallback)
new Disposable ->
screen.removeListener('display-added', outerCallback)
screen.removeListener('display-removed', outerCallback)

View File

@@ -83,12 +83,18 @@ class AtomWindow
@representedDirectoryPaths = loadSettings.initialPaths
@env = loadSettings.env if loadSettings.env?
@browserWindow.loadSettings = loadSettings
@browserWindow.loadSettingsJSON = JSON.stringify(loadSettings)
@browserWindow.on 'window:loaded', =>
@emit 'window:loaded'
@resolveLoadedPromise()
@browserWindow.on 'enter-full-screen', =>
@browserWindow.webContents.send('did-enter-full-screen')
@browserWindow.on 'leave-full-screen', =>
@browserWindow.webContents.send('did-leave-full-screen')
@browserWindow.loadURL url.format
protocol: 'file'
pathname: "#{@resourcePath}/static/index.html"
@@ -101,6 +107,7 @@ class AtomWindow
hasPathToOpen = not (locationsToOpen.length is 1 and not locationsToOpen[0].pathToOpen?)
@openLocations(locationsToOpen) if hasPathToOpen and not @isSpecWindow()
@disableZoom()
@atomApplication.addWindow(this)
@@ -303,3 +310,6 @@ class AtomWindow
@atomApplication.saveState()
copy: -> @browserWindow.copy()
disableZoom: ->
@browserWindow.webContents.setZoomLevelLimits(1, 1)

View File

@@ -34,7 +34,7 @@ class PanelContainer
isModal: -> @location is 'modal'
getPanels: -> @panels
getPanels: -> @panels.slice()
addPanel: (panel) ->
@subscriptions.add panel.onDidDestroy(@panelDestroyed.bind(this))

View File

@@ -58,7 +58,7 @@ export default class ReopenProjectMenuManager {
// Windows users can right-click Atom taskbar and remove project from the jump list.
// We have to honor that or the group stops working. As we only get a partial list
// each time we remove them from history entirely.
applyWindowsJumpListRemovals () {
async applyWindowsJumpListRemovals () {
if (process.platform !== 'win32') return
if (this.app === undefined) {
this.app = require('remote').app
@@ -68,7 +68,7 @@ export default class ReopenProjectMenuManager {
if (removed.length === 0) return
for (let project of this.historyManager.getProjects()) {
if (removed.includes(ReopenProjectMenuManager.taskDescription(project.paths))) {
this.historyManager.removeProject(project.paths)
await this.historyManager.removeProject(project.paths)
}
}
}

View File

@@ -192,6 +192,9 @@ class TextEditor extends Model
@displayLayer.setTextDecorationLayer(@tokenizedBuffer)
@defaultMarkerLayer = @displayLayer.addMarkerLayer()
@disposables.add(@defaultMarkerLayer.onDidDestroy =>
@assert(false, "defaultMarkerLayer destroyed at an unexpected time")
)
@selectionsMarkerLayer ?= @addMarkerLayer(maintainHistory: true, persistent: true)
@selectionsMarkerLayer.trackDestructionInOnDidCreateMarkerCallbacks = true
@@ -384,7 +387,7 @@ class TextEditor extends Model
softWrapHangingIndentLength: @displayLayer.softWrapHangingIndent
@id, @softTabs, @softWrapped, @softWrapAtPreferredLineLength,
@preferredLineLength, @mini, @editorWidthInChars, @width, @largeFileMode,
@preferredLineLength, @mini, @editorWidthInChars, @width, @largeFileMode,
@registered, @invisibles, @showInvisibles, @showIndentGuide, @autoHeight, @autoWidth
}

View File

@@ -8,8 +8,6 @@ ScopeDescriptor = require './scope-descriptor'
TokenizedBufferIterator = require './tokenized-buffer-iterator'
NullGrammar = require './null-grammar'
MAX_LINE_LENGTH_TO_TOKENIZE = 500
module.exports =
class TokenizedBuffer extends Model
grammar: null
@@ -253,8 +251,6 @@ class TokenizedBuffer extends Model
buildTokenizedLineForRowWithText: (row, text, ruleStack = @stackForRow(row - 1), openScopes = @openScopesForRow(row)) ->
lineEnding = @buffer.lineEndingForRow(row)
if text.length > MAX_LINE_LENGTH_TO_TOKENIZE
text = text.slice(0, MAX_LINE_LENGTH_TO_TOKENIZE)
{tags, ruleStack} = @grammar.tokenizeLine(text, ruleStack, row is 0, false)
new TokenizedLine({openScopes, text, tags, ruleStack, lineEnding, @tokenIterator})

View File

@@ -20,14 +20,8 @@ class WindowEventHandler
@subscriptions.add listen(@document, 'click', 'a', @handleLinkClick)
@subscriptions.add listen(@document, 'submit', 'form', @handleFormSubmit)
browserWindow = @applicationDelegate.getCurrentWindow()
browserWindow.on 'enter-full-screen', @handleEnterFullScreen
@subscriptions.add new Disposable =>
browserWindow.removeListener('enter-full-screen', @handleEnterFullScreen)
browserWindow.on 'leave-full-screen', @handleLeaveFullScreen
@subscriptions.add new Disposable =>
browserWindow.removeListener('leave-full-screen', @handleLeaveFullScreen)
@subscriptions.add(@applicationDelegate.onDidEnterFullScreen(@handleEnterFullScreen))
@subscriptions.add(@applicationDelegate.onDidLeaveFullScreen(@handleLeaveFullScreen))
@subscriptions.add @atomEnvironment.commands.add @window,
'window:toggle-full-screen': @handleWindowToggleFullScreen

View File

@@ -44,15 +44,10 @@ class WorkspaceElement extends HTMLElement
@subscriptions.add @config.onDidChange 'editor.lineHeight', @updateGlobalTextEditorStyleSheet.bind(this)
updateGlobalTextEditorStyleSheet: ->
fontFamily = @config.get('editor.fontFamily')
# TODO: There is a bug in how some emojis (e.g. ❤️) are rendered on macOS.
# This workaround should be removed once we update to Chromium 51, where the
# problem was fixed.
fontFamily += ', "Apple Color Emoji"' if process.platform is 'darwin'
styleSheetSource = """
atom-text-editor {
font-size: #{@config.get('editor.fontSize')}px;
font-family: #{fontFamily};
font-family: #{@config.get('editor.fontFamily')};
line-height: #{@config.get('editor.lineHeight')};
}
"""

File diff suppressed because it is too large Load Diff

1402
src/workspace.js Normal file

File diff suppressed because it is too large Load Diff