Merge branch 'master' into as-block-decorations

This commit is contained in:
Antonio Scandurra 2016-01-14 09:30:06 -07:00
commit f81843d465
42 changed files with 391 additions and 191 deletions

View File

@ -1,18 +1 @@
See https://atom.io/releases
## 1.4.0
* Switching encoding is now fast also with large files.
* Fixed an issue where disabling and re-enabling a package caused custom keymaps to be overridden.
* Fixed restoring untitled editors on restart. The new behavior never prompts to save new/changed files when closing a window or quitting Atom.
## 1.3.0
* The tree-view now sorts directory entries more naturally, in a locale-sensitive way.
* Lines can now be moved up and down with multiple cursors.
* Improved the performance of marker-dependent code paths such as spell-check and find and replace.
* Fixed copying and pasting in native input fields.
* By default, windows with no pane items are now closed via the `core:close` command. The previous behavior can be restored via the `Close Empty Windows` option in settings.
* Fixed an issue where characters were inserted when toggling the settings view on some keyboard layouts.
* Modules can now temporarily override `Error.prepareStackTrace`. There is also an `Error.prototype.getRawStack()` method if you just need access to the raw v8 trace structure.
* Fixed a problem that caused blurry fonts on monitors that have a slightly higher resolution than 96 DPI.

View File

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

View File

@ -14,6 +14,8 @@ _ = require 'underscore-plus'
packageJson = require '../package.json'
module.exports = (grunt) ->
require('time-grunt')(grunt)
grunt.loadNpmTasks('grunt-babel')
grunt.loadNpmTasks('grunt-coffeelint')
grunt.loadNpmTasks('grunt-lesslint')
@ -36,7 +38,6 @@ module.exports = (grunt) ->
buildDir = grunt.option('build-dir')
buildDir ?= path.join(os.tmpdir(), 'atom-build')
buildDir = path.resolve(buildDir)
disableAutoUpdate = grunt.option('no-auto-update') ? false
channel = grunt.option('channel')
releasableBranches = ['stable', 'beta']
@ -179,7 +180,7 @@ module.exports = (grunt) ->
pkg: grunt.file.readJSON('package.json')
atom: {
appName, channel, metadata, disableAutoUpdate,
appName, channel, metadata,
appFileName, apmFileName,
appDir, buildDir, contentsDir, installDir, shellAppDir, symbolsDir,
}
@ -255,7 +256,7 @@ module.exports = (grunt) ->
outputDir: 'electron'
downloadDir: electronDownloadDir
rebuild: true # rebuild native modules after electron is updated
token: process.env.ATOM_ACCESS_TOKEN
token: process.env.ATOM_ACCESS_TOKEN ? 'da809a6077bb1b0aa7c5623f7b2d5f1fec2faae4'
'create-windows-installer':
installer:

View File

@ -37,6 +37,7 @@
"runas": "^3.1",
"tello": "1.0.5",
"temp": "~0.8.1",
"time-grunt": "1.2.2",
"underscore-plus": "1.x",
"unzip": "~0.1.9",
"vm-compatibility-layer": "~0.1.0",

View File

@ -186,5 +186,4 @@ module.exports = (grunt) ->
dependencies = ['compile', 'generate-license:save', 'generate-module-cache', 'compile-packages-slug']
dependencies.push('copy-info-plist') if process.platform is 'darwin'
dependencies.push('set-exe-icon') if process.platform is 'win32'
dependencies.push('disable-autoupdate') if grunt.config.get('atom.disableAutoUpdate')
grunt.task.run(dependencies...)

View File

@ -1,12 +0,0 @@
fs = require 'fs'
path = require 'path'
module.exports = (grunt) ->
grunt.registerTask 'disable-autoupdate', 'Set up disableAutoUpdate field in package.json file', ->
appDir = fs.realpathSync(grunt.config.get('atom.appDir'))
metadata = grunt.file.readJSON(path.join(appDir, 'package.json'))
metadata._disableAutoUpdate = grunt.config.get('atom.disableAutoUpdate')
grunt.file.write(path.join(appDir, 'package.json'), JSON.stringify(metadata))

5
dot-atom/.gitignore vendored
View File

@ -1,5 +1,6 @@
storage
blob-store
compile-cache
dev
.npm
storage
.node-gyp
.npm

View File

@ -13,7 +13,7 @@
'ctrl-alt-o': 'application:add-project-folder'
'ctrl-shift-pageup': 'pane:move-item-left'
'ctrl-shift-pagedown': 'pane:move-item-right'
'F11': 'window:toggle-full-screen'
'f11': 'window:toggle-full-screen'
# Sublime Parity
'ctrl-,': 'application:show-settings'

View File

@ -19,7 +19,7 @@
'ctrl-alt-o': 'application:add-project-folder'
'ctrl-shift-left': 'pane:move-item-left'
'ctrl-shift-right': 'pane:move-item-right'
'F11': 'window:toggle-full-screen'
'f11': 'window:toggle-full-screen'
# Sublime Parity
'ctrl-,': 'application:show-settings'

View File

@ -110,36 +110,9 @@
]
}
{
label: 'Selection'
submenu: [
{ label: 'Add Selection Above', command: 'editor:add-selection-above' }
{ label: 'Add Selection Below', command: 'editor:add-selection-below' }
{ label: 'Single Selection', command: 'editor:consolidate-selections'}
{ label: 'Split into Lines', command: 'editor:split-selections-into-lines'}
{ type: 'separator' }
{ label: 'Select to Top', command: 'core:select-to-top' }
{ label: 'Select to Bottom', command: 'core:select-to-bottom' }
{ type: 'separator' }
{ label: 'Select Line', command: 'editor:select-line' }
{ label: 'Select Word', command: 'editor:select-word' }
{ label: 'Select to Beginning of Word', command: 'editor:select-to-beginning-of-word' }
{ label: 'Select to Beginning of Line', command: 'editor:select-to-beginning-of-line' }
{ label: 'Select to First Character of Line', command: 'editor:select-to-first-character-of-line' }
{ label: 'Select to End of Word', command: 'editor:select-to-end-of-word' }
{ label: 'Select to End of Line', command: 'editor:select-to-end-of-line' }
]
}
{
label: 'Find'
submenu: []
}
{
label: 'View'
submenu: [
{ label: 'Reload', command: 'window:reload' }
{ label: 'Toggle Full Screen', command: 'window:toggle-full-screen' }
{
label: 'Panes'
@ -164,6 +137,7 @@
label: 'Developer'
submenu: [
{ label: 'Open In Dev Mode…', command: 'application:open-dev' }
{ label: 'Reload Window', command: 'window:reload' }
{ label: 'Run Package Specs', command: 'window:run-package-specs' }
{ label: 'Toggle Developer Tools', command: 'window:toggle-dev-tools' }
]
@ -177,6 +151,32 @@
]
}
{
label: 'Selection'
submenu: [
{ label: 'Add Selection Above', command: 'editor:add-selection-above' }
{ label: 'Add Selection Below', command: 'editor:add-selection-below' }
{ label: 'Single Selection', command: 'editor:consolidate-selections'}
{ label: 'Split into Lines', command: 'editor:split-selections-into-lines'}
{ type: 'separator' }
{ label: 'Select to Top', command: 'core:select-to-top' }
{ label: 'Select to Bottom', command: 'core:select-to-bottom' }
{ type: 'separator' }
{ label: 'Select Line', command: 'editor:select-line' }
{ label: 'Select Word', command: 'editor:select-word' }
{ label: 'Select to Beginning of Word', command: 'editor:select-to-beginning-of-word' }
{ label: 'Select to Beginning of Line', command: 'editor:select-to-beginning-of-line' }
{ label: 'Select to First Character of Line', command: 'editor:select-to-first-character-of-line' }
{ label: 'Select to End of Word', command: 'editor:select-to-end-of-word' }
{ label: 'Select to End of Line', command: 'editor:select-to-end-of-line' }
]
}
{
label: 'Find'
submenu: []
}
{
label: 'Packages'
submenu: []

View File

@ -95,7 +95,6 @@
{
label: '&View'
submenu: [
{ label: '&Reload', command: 'window:reload' }
{ label: 'Toggle &Full Screen', command: 'window:toggle-full-screen' }
{ label: 'Toggle Menu Bar', command: 'window:toggle-menu-bar' }
{
@ -121,6 +120,7 @@
label: 'Developer'
submenu: [
{ label: 'Open In &Dev Mode…', command: 'application:open-dev' }
{ label: '&Reload Window', command: 'window:reload' }
{ label: 'Run Package &Specs', command: 'window:run-package-specs' }
{ label: 'Toggle Developer &Tools', command: 'window:toggle-dev-tools' }
]

View File

@ -94,7 +94,6 @@
{
label: '&View'
submenu: [
{ label: '&Reload', command: 'window:reload' }
{ label: 'Toggle &Full Screen', command: 'window:toggle-full-screen' }
{ label: 'Toggle Menu Bar', command: 'window:toggle-menu-bar' }
{
@ -120,6 +119,7 @@
label: 'Developer'
submenu: [
{ label: 'Open In &Dev Mode…', command: 'application:open-dev' }
{ label: '&Reload Window', command: 'window:reload' }
{ label: 'Run Package &Specs', command: 'window:run-package-specs' }
{ label: 'Toggle Developer &Tools', command: 'window:toggle-dev-tools' }
]

View File

@ -1,7 +1,7 @@
{
"name": "atom",
"productName": "Atom",
"version": "1.5.0-dev",
"version": "1.6.0-dev",
"description": "A hackable text editor for the 21st Century.",
"main": "./src/browser/main.js",
"repository": {
@ -22,17 +22,17 @@
"clear-cut": "^2.0.1",
"coffee-script": "1.8.0",
"color": "^0.7.3",
"event-kit": "^1.3.0",
"event-kit": "^1.5.0",
"find-parent-dir": "^0.3.0",
"first-mate": "^5.1.1",
"fs-plus": "^2.8.0",
"fstream": "0.1.24",
"fuzzaldrin": "^2.1",
"git-utils": "^4.0.7",
"git-utils": "^4.1.0",
"grim": "1.5.0",
"jasmine-json": "~0.0",
"jasmine-tagged": "^1.1.4",
"jquery": "^2.1.1",
"jquery": "2.1.4",
"key-path-helpers": "^0.4.0",
"less-cache": "0.22",
"line-top-index": "0.2.0",
@ -53,7 +53,7 @@
"service-hub": "^0.7.0",
"source-map-support": "^0.3.2",
"temp": "0.8.1",
"text-buffer": "8.1.3",
"text-buffer": "8.1.4",
"typescript-simple": "1.0.0",
"underscore-plus": "^1.6.6",
"yargs": "^3.23.0"
@ -66,12 +66,12 @@
"base16-tomorrow-dark-theme": "1.1.0",
"base16-tomorrow-light-theme": "1.1.1",
"one-dark-ui": "1.1.9",
"one-dark-syntax": "1.1.1",
"one-light-syntax": "1.1.1",
"one-light-ui": "1.1.9",
"one-dark-syntax": "1.1.2",
"one-light-syntax": "1.1.2",
"solarized-dark-syntax": "0.39.0",
"solarized-light-syntax": "0.23.0",
"about": "1.1.0",
"about": "1.3.0",
"archive-view": "0.61.0",
"autocomplete-atom-api": "0.9.2",
"autocomplete-css": "0.11.0",
@ -103,16 +103,15 @@
"notifications": "0.62.1",
"open-on-github": "0.40.0",
"package-generator": "0.41.0",
"release-notes": "0.53.0",
"settings-view": "0.232.1",
"settings-view": "0.232.3",
"snippets": "1.0.1",
"spell-check": "0.63.0",
"spell-check": "0.65.0",
"status-bar": "0.80.0",
"styleguide": "0.45.0",
"symbols-view": "0.110.1",
"tabs": "0.88.0",
"timecop": "0.33.0",
"tree-view": "0.198.0",
"tree-view": "0.198.1",
"update-package-dependencies": "0.10.0",
"welcome": "0.33.0",
"whitespace": "0.32.1",
@ -122,24 +121,24 @@
"language-coffee-script": "0.46.0",
"language-csharp": "0.11.0",
"language-css": "0.36.0",
"language-gfm": "0.82.0",
"language-gfm": "0.83.0",
"language-git": "0.11.0",
"language-go": "0.41.0",
"language-html": "0.43.1",
"language-go": "0.42.0",
"language-html": "0.44.0",
"language-hyperlink": "0.16.0",
"language-java": "0.17.0",
"language-javascript": "0.104.0",
"language-json": "0.17.2",
"language-javascript": "0.105.0",
"language-json": "0.17.3",
"language-less": "0.29.0",
"language-make": "0.21.0",
"language-mustache": "0.13.0",
"language-objective-c": "0.15.1",
"language-perl": "0.32.0",
"language-php": "0.34.0",
"language-php": "0.36.0",
"language-property-list": "0.8.0",
"language-python": "0.42.1",
"language-ruby": "0.65.0",
"language-ruby-on-rails": "0.24.0",
"language-python": "0.43.0",
"language-ruby": "0.68.0",
"language-ruby-on-rails": "0.25.0",
"language-sass": "0.45.0",
"language-shellscript": "0.21.0",
"language-source": "0.9.0",

View File

@ -5,8 +5,16 @@ var verifyRequirements = require('./utils/verify-requirements');
var safeExec = require('./utils/child-process-wrapper.js').safeExec;
var path = require('path');
var t0, t1
// Executes an array of commands one by one.
function executeCommands(commands, done, index) {
if (index != undefined) {
t1 = Date.now()
console.log("=> Took " + (t1 - t0) + "ms.");
console.log();
}
index = (index == undefined ? 0 : index);
if (index < commands.length) {
var command = commands[index];
@ -17,6 +25,7 @@ function executeCommands(commands, done, index) {
options = command.options;
command = command.command;
}
t0 = Date.now()
safeExec(command, options, executeCommands.bind(this, commands, done, index + 1));
}
else
@ -96,7 +105,10 @@ function bootstrap() {
message: 'Installing apm...',
options: apmInstallOptions
},
apmPath + ' clean' + apmFlags,
{
command: apmPath + ' clean' + apmFlags,
message: 'Deleting old packages...'
},
moduleInstallCommand,
dedupeApmCommand + ' ' + packagesToDedupe.join(' '),
];

View File

@ -1,4 +1,26 @@
# Users may have this environment variable set. Currently, it causes babel to
# log to stderr, which causes errors on Windows.
# See https://github.com/atom/electron/issues/2033
process.env.DEBUG='*'
path = require('path')
temp = require('temp').track()
CompileCache = require('../src/compile-cache')
describe "Babel transpiler support", ->
originalCacheDir = null
beforeEach ->
originalCacheDir = CompileCache.getCacheDirectory()
CompileCache.setCacheDirectory(temp.mkdirSync('compile-cache'))
for cacheKey in Object.keys(require.cache)
if cacheKey.startsWith(path.join(__dirname, 'fixtures', 'babel'))
console.log('deleting', cacheKey)
delete require.cache[cacheKey]
afterEach ->
CompileCache.setCacheDirectory(originalCacheDir)
describe 'when a .js file starts with /** @babel */;', ->
it "transpiles it using babel", ->
transpiled = require('./fixtures/babel/babel-comment.js')
@ -17,3 +39,12 @@ describe "Babel transpiler support", ->
describe "when a .js file does not start with 'use babel';", ->
it "does not transpile it using babel", ->
expect(-> require('./fixtures/babel/invalid.js')).toThrow()
it "does not try to log to stdout or stderr while parsing the file", ->
spyOn(process.stderr, 'write')
spyOn(process.stdout, 'write')
transpiled = require('./fixtures/babel/babel-double-quotes.js')
expect(process.stdout.write).not.toHaveBeenCalled()
expect(process.stderr.write).not.toHaveBeenCalled()

View File

@ -872,6 +872,26 @@ describe "Config", ->
atom.config.loadUserConfig()
expect(atom.config.get("foo.bar")).toBe "baz"
describe "when the config file fails to load", ->
addErrorHandler = null
beforeEach ->
atom.notifications.onDidAddNotification addErrorHandler = jasmine.createSpy()
spyOn(fs, "existsSync").andCallFake ->
error = new Error()
error.code = 'EPERM'
throw error
it "creates a notification and does not try to save later changes to disk", ->
load = -> atom.config.loadUserConfig()
expect(load).not.toThrow()
expect(addErrorHandler.callCount).toBe 1
atom.config.set("foo.bar", "baz")
advanceClock(100)
expect(atom.config.save).not.toHaveBeenCalled()
expect(atom.config.get("foo.bar")).toBe "baz"
describe ".observeUserConfig()", ->
updatedHandler = null

View File

@ -1253,6 +1253,13 @@ describe "DisplayBuffer", ->
decoration.destroy()
expect(displayBuffer.decorationForId(decoration.id)).not.toBeDefined()
it "does not allow destroyed markers to be decorated", ->
marker.destroy()
expect(->
displayBuffer.decorateMarker(marker, {type: 'overlay', item: document.createElement('div')})
).toThrow("Cannot decorate a destroyed marker")
expect(displayBuffer.getOverlayDecorations()).toEqual []
describe "when a decoration is updated via Decoration::update()", ->
it "emits an 'updated' event containing the new and old params", ->
decoration.onDidChangeProperties updatedSpy = jasmine.createSpy()

View File

@ -19,9 +19,8 @@ class FakeLinesYardstick
setScopedCharacterWidth: (scopeNames, character, width) ->
@getScopedCharacterWidths(scopeNames)[character] = width
pixelPositionForScreenPosition: (screenPosition, clip=true) ->
pixelPositionForScreenPosition: (screenPosition) ->
screenPosition = Point.fromObject(screenPosition)
screenPosition = @model.clipScreenPosition(screenPosition) if clip
targetRow = screenPosition.row
targetColumn = screenPosition.column

View File

@ -125,6 +125,27 @@ describe "Starting Atom", ->
.treeViewRootDirectories()
.then ({value}) -> expect(value).toEqual([otherTempDirPath])
it "opens the new window offset from the other window", ->
runAtom [path.join(tempDirPath, "new-file")], {ATOM_HOME: atomHome}, (client) ->
win0Position = null
win1Position = null
client
.waitForWindowCount(1, 10000)
.execute -> atom.getPosition()
.then ({value}) -> win0Position = value
.waitForNewWindow(->
@startAnotherAtom([path.join(temp.mkdirSync("a-third-dir"), "a-file")], ATOM_HOME: atomHome)
, 5000)
.waitForWindowCount(2, 10000)
.execute -> atom.getPosition()
.then ({value}) -> win1Position = value
.then ->
expect(win1Position.x).toBeGreaterThan(win0Position.x)
# Ideally we'd test the y coordinate too, but if the window's
# already as tall as it can be, then OS X won't move it down outside
# the screen.
# expect(win1Position.y).toBeGreaterThan(win0Position.y)
describe "reopening a directory that was previously opened", ->
it "remembers the state of the window", ->
runAtom [tempDirPath], {ATOM_HOME: atomHome}, (client) ->

View File

@ -1,6 +1,7 @@
LinesYardstick = require '../src/lines-yardstick'
LineTopIndex = require 'line-top-index'
{toArray} = require 'underscore-plus'
{Point} = require 'text-buffer'
describe "LinesYardstick", ->
[editor, mockLineNodesProvider, createdLineNodes, linesYardstick, buildLineNode] = []
@ -66,12 +67,12 @@ describe "LinesYardstick", ->
}
"""
expect(linesYardstick.pixelPositionForScreenPosition([0, 0])).toEqual({left: 0, top: 0})
expect(linesYardstick.pixelPositionForScreenPosition([0, 1])).toEqual({left: 7, top: 0})
expect(linesYardstick.pixelPositionForScreenPosition([0, 5])).toEqual({left: 37.78125, top: 0})
expect(linesYardstick.pixelPositionForScreenPosition([1, 6])).toEqual({left: 43.171875, top: 14})
expect(linesYardstick.pixelPositionForScreenPosition([1, 9])).toEqual({left: 72.171875, top: 14})
expect(linesYardstick.pixelPositionForScreenPosition([2, Infinity])).toEqual({left: 287.859375, top: 28})
expect(linesYardstick.pixelPositionForScreenPosition(Point(0, 0))).toEqual({left: 0, top: 0})
expect(linesYardstick.pixelPositionForScreenPosition(Point(0, 1))).toEqual({left: 7, top: 0})
expect(linesYardstick.pixelPositionForScreenPosition(Point(0, 5))).toEqual({left: 37.78125, top: 0})
expect(linesYardstick.pixelPositionForScreenPosition(Point(1, 6))).toEqual({left: 43.171875, top: 14})
expect(linesYardstick.pixelPositionForScreenPosition(Point(1, 9))).toEqual({left: 72.171875, top: 14})
expect(linesYardstick.pixelPositionForScreenPosition(Point(2, Infinity))).toEqual({left: 287.859375, top: 28})
it "reuses already computed pixel positions unless it is invalidated", ->
atom.styles.addStyleSheet """
@ -81,9 +82,9 @@ describe "LinesYardstick", ->
}
"""
expect(linesYardstick.pixelPositionForScreenPosition([1, 2])).toEqual({left: 19.203125, top: 14})
expect(linesYardstick.pixelPositionForScreenPosition([2, 6])).toEqual({left: 57.609375, top: 28})
expect(linesYardstick.pixelPositionForScreenPosition([5, 10])).toEqual({left: 95.609375, top: 70})
expect(linesYardstick.pixelPositionForScreenPosition(Point(1, 2))).toEqual({left: 19.203125, top: 14})
expect(linesYardstick.pixelPositionForScreenPosition(Point(2, 6))).toEqual({left: 57.609375, top: 28})
expect(linesYardstick.pixelPositionForScreenPosition(Point(5, 10))).toEqual({left: 95.609375, top: 70})
atom.styles.addStyleSheet """
* {
@ -91,15 +92,15 @@ describe "LinesYardstick", ->
}
"""
expect(linesYardstick.pixelPositionForScreenPosition([1, 2])).toEqual({left: 19.203125, top: 14})
expect(linesYardstick.pixelPositionForScreenPosition([2, 6])).toEqual({left: 57.609375, top: 28})
expect(linesYardstick.pixelPositionForScreenPosition([5, 10])).toEqual({left: 95.609375, top: 70})
expect(linesYardstick.pixelPositionForScreenPosition(Point(1, 2))).toEqual({left: 19.203125, top: 14})
expect(linesYardstick.pixelPositionForScreenPosition(Point(2, 6))).toEqual({left: 57.609375, top: 28})
expect(linesYardstick.pixelPositionForScreenPosition(Point(5, 10))).toEqual({left: 95.609375, top: 70})
linesYardstick.invalidateCache()
expect(linesYardstick.pixelPositionForScreenPosition([1, 2])).toEqual({left: 24, top: 14})
expect(linesYardstick.pixelPositionForScreenPosition([2, 6])).toEqual({left: 72, top: 28})
expect(linesYardstick.pixelPositionForScreenPosition([5, 10])).toEqual({left: 120, top: 70})
expect(linesYardstick.pixelPositionForScreenPosition(Point(1, 2))).toEqual({left: 24, top: 14})
expect(linesYardstick.pixelPositionForScreenPosition(Point(2, 6))).toEqual({left: 72, top: 28})
expect(linesYardstick.pixelPositionForScreenPosition(Point(5, 10))).toEqual({left: 120, top: 70})
it "correctly handles RTL characters", ->
atom.styles.addStyleSheet """
@ -110,13 +111,13 @@ describe "LinesYardstick", ->
"""
editor.setText("السلام عليكم")
expect(linesYardstick.pixelPositionForScreenPosition([0, 0]).left).toBe 0
expect(linesYardstick.pixelPositionForScreenPosition([0, 1]).left).toBe 8
expect(linesYardstick.pixelPositionForScreenPosition([0, 2]).left).toBe 16
expect(linesYardstick.pixelPositionForScreenPosition([0, 5]).left).toBe 33
expect(linesYardstick.pixelPositionForScreenPosition([0, 7]).left).toBe 50
expect(linesYardstick.pixelPositionForScreenPosition([0, 9]).left).toBe 67
expect(linesYardstick.pixelPositionForScreenPosition([0, 11]).left).toBe 84
expect(linesYardstick.pixelPositionForScreenPosition(Point(0, 0)).left).toBe 0
expect(linesYardstick.pixelPositionForScreenPosition(Point(0, 1)).left).toBe 8
expect(linesYardstick.pixelPositionForScreenPosition(Point(0, 2)).left).toBe 16
expect(linesYardstick.pixelPositionForScreenPosition(Point(0, 5)).left).toBe 33
expect(linesYardstick.pixelPositionForScreenPosition(Point(0, 7)).left).toBe 50
expect(linesYardstick.pixelPositionForScreenPosition(Point(0, 9)).left).toBe 67
expect(linesYardstick.pixelPositionForScreenPosition(Point(0, 11)).left).toBe 84
it "doesn't report a width greater than 0 when the character to measure is at the beginning of a text node", ->
# This spec documents what seems to be a bug in Chromium, because we'd
@ -141,9 +142,9 @@ describe "LinesYardstick", ->
editor.setText(text)
expect(linesYardstick.pixelPositionForScreenPosition([0, 35]).left).toBe 230.90625
expect(linesYardstick.pixelPositionForScreenPosition([0, 36]).left).toBe 237.5
expect(linesYardstick.pixelPositionForScreenPosition([0, 37]).left).toBe 244.09375
expect(linesYardstick.pixelPositionForScreenPosition(Point(0, 35)).left).toBe 230.90625
expect(linesYardstick.pixelPositionForScreenPosition(Point(0, 36)).left).toBe 237.5
expect(linesYardstick.pixelPositionForScreenPosition(Point(0, 37)).left).toBe 244.09375
describe "::screenPositionForPixelPosition(pixelPosition)", ->
it "converts pixel positions to screen positions", ->

View File

@ -1026,6 +1026,16 @@ describe "PackageManager", ->
expect(atom.packages.enablePackage("this-doesnt-exist")).toBeNull()
expect(console.warn.callCount).toBe 1
it "does not disable an already disabled package", ->
packageName = 'package-with-main'
atom.config.pushAtKeyPath('core.disabledPackages', packageName)
atom.packages.observeDisabledPackages()
expect(atom.config.get('core.disabledPackages')).toContain packageName
atom.packages.disablePackage(packageName)
packagesDisabled = atom.config.get('core.disabledPackages').filter((pack) -> pack is packageName)
expect(packagesDisabled.length).toEqual 1
describe "with themes", ->
didChangeActiveThemesHandler = null

View File

@ -18,6 +18,8 @@ describe "Pane", ->
onDidDestroy: (fn) -> @emitter.on('did-destroy', fn)
destroy: -> @destroyed = true; @emitter.emit('did-destroy')
isDestroyed: -> @destroyed
isPending: -> @pending
pending: false
beforeEach ->
confirm = spyOn(atom.applicationDelegate, 'confirm')
@ -153,6 +155,26 @@ describe "Pane", ->
pane.activateItem(pane.itemAtIndex(1))
expect(observed).toEqual [pane.itemAtIndex(1)]
it "replaces pending items", ->
itemC = new Item("C")
itemD = new Item("D")
itemC.pending = true
itemD.pending = true
expect(itemC.isPending()).toBe true
pane.activateItem(itemC)
expect(pane.getItems().length).toBe 3
expect(pane.getActiveItem()).toBe pane.itemAtIndex(1)
expect(itemD.isPending()).toBe true
pane.activateItem(itemD)
expect(pane.getItems().length).toBe 3
expect(pane.getActiveItem()).toBe pane.itemAtIndex(1)
pane.activateItem(pane.itemAtIndex(2))
expect(pane.getItems().length).toBe 2
expect(pane.getActiveItem()).toBe pane.itemAtIndex(1)
describe "::activateNextItem() and ::activatePreviousItem()", ->
it "sets the active item to the next/previous item, looping around at either end", ->
pane = new Pane(paneParams(items: [new Item("A"), new Item("B"), new Item("C")]))

View File

@ -4809,6 +4809,13 @@ describe('TextEditorComponent', function () {
})
})
describe('::pixelPositionForScreenPosition()', () => {
it('returns the correct horizontal position, even if it is on a row that has not yet been rendered (regression)', () => {
editor.setTextInBufferRange([[5, 0], [6, 0]], 'hello world\n')
expect(wrapperNode.pixelPositionForScreenPosition([5, Infinity]).left).toBeGreaterThan(0)
})
})
describe('middle mouse paste on Linux', function () {
let originalPlatform

View File

@ -5804,3 +5804,29 @@ describe "TextEditor", ->
screenRange: marker1.getRange(),
rangeIsReversed: false
}
describe "pending state", ->
editor1 = null
beforeEach ->
waitsForPromise ->
atom.workspace.open('sample.txt', pending: true).then (o) -> editor1 = o
it "should open file in pending state if 'pending' option is true", ->
expect(editor1.isPending()).toBe true
expect(editor.isPending()).toBe false # By default pending status is false
it "invokes ::onDidTerminatePendingState observers if pending status is terminated", ->
events = []
editor1.onDidTerminatePendingState (event) -> events.push(event)
editor1.terminatePendingState()
expect(editor1.isPending()).toBe false
expect(events).toEqual [editor1]
it "should terminate pending state when buffer is changed", ->
events = []
editor1.onDidTerminatePendingState (event) -> events.push(event)
expect(editor1.isPending()).toBe true
editor1.insertText('I\'ll be back!')
advanceClock(500)
expect(editor1.isPending()).toBe false
expect(events).toEqual [editor1]

View File

@ -42,6 +42,10 @@ exports.getCachePath = function (sourceCode) {
exports.compile = function (sourceCode, filePath) {
if (!babel) {
babel = require('babel-core')
var Logger = require('babel-core/lib/transformation/file/logger')
var noop = function () {}
Logger.prototype.debug = noop
Logger.prototype.verbose = noop
}
var options = {filename: filePath}

View File

@ -103,8 +103,6 @@ class ApplicationMenu
downloadingUpdateItem.visible = false
installUpdateItem.visible = false
return if @autoUpdateManager.isDisabled()
switch state
when 'idle', 'error', 'no-update-available'
checkForUpdateItem.visible = true
@ -119,9 +117,10 @@ class ApplicationMenu
#
# Returns an Array of menu item Objects.
getDefaultTemplate: ->
template = [
[
label: "Atom"
submenu: [
{label: "Check for Update", metadata: {autoUpdate: true}}
{label: 'Reload', accelerator: 'Command+R', click: => @focusedWindow()?.reload()}
{label: 'Close Window', accelerator: 'Command+Shift+W', click: => @focusedWindow()?.close()}
{label: 'Toggle Dev Tools', accelerator: 'Command+Alt+I', click: => @focusedWindow()?.toggleDevTools()}
@ -129,10 +128,6 @@ class ApplicationMenu
]
]
# Add `Check for Update` button if autoUpdateManager is enabled.
template[0].submenu.unshift({label: "Check for Update", metadata: {autoUpdate: true}}) unless @autoUpdateManager.isDisabled()
template
focusedWindow: ->
_.find global.atomApplication.windows, (atomWindow) -> atomWindow.isFocused()

View File

@ -74,8 +74,7 @@ class AtomApplication
@pidsToOpenWindows = {}
@windows = []
disableAutoUpdate = require(path.join(@resourcePath, 'package.json'))._disableAutoUpdate ? false
@autoUpdateManager = new AutoUpdateManager(@version, options.test, disableAutoUpdate)
@autoUpdateManager = new AutoUpdateManager(@version, options.test, @resourcePath)
@applicationMenu = new ApplicationMenu(@version, @autoUpdateManager)
@atomProtocolHandler = new AtomProtocolHandler(@resourcePath, @safeMode)
@ -167,7 +166,7 @@ class AtomApplication
safeMode: @focusedWindow()?.safeMode
@on 'application:quit', -> app.quit()
@on 'application:new-window', -> @openPath(_.extend(windowDimensions: @focusedWindow()?.getDimensions(), getLoadSettings()))
@on 'application:new-window', -> @openPath(getLoadSettings())
@on 'application:new-file', -> (@focusedWindow() ? this).openPath()
@on 'application:open', -> @promptForPathToOpen('all', getLoadSettings())
@on 'application:open-file', -> @promptForPathToOpen('file', getLoadSettings())
@ -229,7 +228,7 @@ class AtomApplication
@openUrl({urlToOpen, @devMode, @safeMode})
app.on 'activate-with-no-open-windows', (event) =>
event.preventDefault()
event?.preventDefault()
@emit('application:new-window')
# A request from the associated render process to open a new render process.
@ -360,6 +359,23 @@ class AtomApplication
focusedWindow: ->
_.find @windows, (atomWindow) -> atomWindow.isFocused()
# Get the platform-specific window offset for new windows.
getWindowOffsetForCurrentPlatform: ->
offsetByPlatform =
darwin: 22
win32: 26
offsetByPlatform[process.platform] ? 0
# Get the dimensions for opening a new window by cascading as appropriate to
# the platform.
getDimensionsForNewWindow: ->
dimensions = (@focusedWindow() ? @lastFocusedWindow)?.getDimensions()
offset = @getWindowOffsetForCurrentPlatform()
if dimensions? and offset?
dimensions.x += offset
dimensions.y += offset
dimensions
# Public: Opens a single path, in an existing window if possible.
#
# options -
@ -370,7 +386,7 @@ class AtomApplication
# :safeMode - Boolean to control the opened window's safe mode.
# :profileStartup - Boolean to control creating a profile of the startup time.
# :window - {AtomWindow} to open file paths in.
openPath: ({pathToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode, profileStartup, window}) ->
openPath: ({pathToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode, profileStartup, window} = {}) ->
@openPaths({pathsToOpen: [pathToOpen], pidToKillWhenClosed, newWindow, devMode, safeMode, profileStartup, window})
# Public: Opens multiple paths, in existing windows if possible.
@ -417,6 +433,7 @@ class AtomApplication
windowInitializationScript ?= require.resolve('../initialize-application-window')
resourcePath ?= @resourcePath
windowDimensions ?= @getDimensionsForNewWindow()
openedWindow = new AtomWindow({locationsToOpen, windowInitializationScript, resourcePath, devMode, safeMode, windowDimensions, profileStartup})
if pidToKillWhenClosed?

View File

@ -1,5 +1,6 @@
autoUpdater = null
_ = require 'underscore-plus'
Config = require '../config'
{EventEmitter} = require 'events'
path = require 'path'
@ -15,10 +16,13 @@ module.exports =
class AutoUpdateManager
_.extend @prototype, EventEmitter.prototype
constructor: (@version, @testMode, @disabled) ->
constructor: (@version, @testMode, resourcePath) ->
@state = IdleState
@iconPath = path.resolve(__dirname, '..', '..', 'resources', 'atom.png')
@feedUrl = "https://atom.io/api/updates?version=#{@version}"
@config = new Config({configDirPath: process.env.ATOM_HOME, resourcePath, enablePersistence: true})
@config.setSchema null, {type: 'object', properties: _.clone(require('../config-schema'))}
@config.load()
process.nextTick => @setupAutoUpdater()
setupAutoUpdater: ->
@ -46,9 +50,13 @@ class AutoUpdateManager
@setState(UpdateAvailableState)
@emitUpdateAvailableEvent(@getWindows()...)
# Only check for updates periodically if enabled and running in release
# version.
@scheduleUpdateCheck() unless /\w{7}/.test(@version) or @disabled
@config.onDidChange 'core.automaticallyUpdate', ({newValue}) =>
if newValue
@scheduleUpdateCheck()
else
@cancelScheduledUpdateCheck()
@scheduleUpdateCheck() if @config.get 'core.automaticallyUpdate'
switch process.platform
when 'win32'
@ -56,9 +64,6 @@ class AutoUpdateManager
when 'linux'
@setState(UnsupportedState)
isDisabled: ->
@disabled
emitUpdateAvailableEvent: (windows...) ->
return unless @releaseVersion?
for atomWindow in windows
@ -74,10 +79,18 @@ class AutoUpdateManager
@state
scheduleUpdateCheck: ->
checkForUpdates = => @check(hidePopups: true)
fourHours = 1000 * 60 * 60 * 4
setInterval(checkForUpdates, fourHours)
checkForUpdates()
# Only schedule update check periodically if running in release version and
# and there is no existing scheduled update check.
unless /\w{7}/.test(@version) or @checkForUpdatesIntervalID
checkForUpdates = => @check(hidePopups: true)
fourHours = 1000 * 60 * 60 * 4
@checkForUpdatesIntervalID = setInterval(checkForUpdates, fourHours)
checkForUpdates()
cancelScheduledUpdateCheck: ->
if @checkForUpdatesIntervalID
clearInterval(@checkForUpdatesIntervalID)
@checkForUpdatesIntervalID = null
check: ({hidePopups}={}) ->
unless hidePopups

View File

@ -104,6 +104,10 @@ module.exports =
description: 'Automatically open an empty editor on startup.'
type: 'boolean'
default: true
automaticallyUpdate:
description: 'Automatically update Atom when a new release is available.'
type: 'boolean'
default: true
editor:
type: 'object'

View File

@ -779,9 +779,14 @@ class Config
loadUserConfig: ->
return if @shouldNotAccessFileSystem()
unless fs.existsSync(@configFilePath)
fs.makeTreeSync(path.dirname(@configFilePath))
CSON.writeFileSync(@configFilePath, {})
try
unless fs.existsSync(@configFilePath)
fs.makeTreeSync(path.dirname(@configFilePath))
CSON.writeFileSync(@configFilePath, {})
catch error
@configFileHasErrors = true
@notifyFailure("Failed to initialize `#{path.basename(@configFilePath)}`", error.stack)
return
try
unless @savePending
@ -820,7 +825,7 @@ class Config
@watchSubscription = null
notifyFailure: (errorMessage, detail) ->
@notificationManager.addError(errorMessage, {detail, dismissable: true})
@notificationManager?.addError(errorMessage, {detail, dismissable: true})
save: ->
return if @shouldNotAccessFileSystem()

View File

@ -812,6 +812,7 @@ class DisplayBuffer extends Model
decorationsState
decorateMarker: (marker, decorationParams) ->
throw new Error("Cannot decorate a destroyed marker") if marker.isDestroyed()
marker = @getMarkerLayer(marker.layer.id).getMarker(marker.id)
decoration = new Decoration(marker, this, decorationParams)
@decorationsByMarkerId[marker.id] ?= []

View File

@ -463,8 +463,12 @@ class GitRepository
refreshStatus: ->
@handlerPath ?= require.resolve('./repository-status-handler')
relativeProjectPaths = @project?.getPaths()
.map (path) => @relativize(path)
.filter (path) -> path.length > 0
@statusTask?.terminate()
@statusTask = Task.once @handlerPath, @getPath(), ({statuses, upstream, branch, submodules}) =>
@statusTask = Task.once @handlerPath, @getPath(), relativeProjectPaths, ({statuses, upstream, branch, submodules}) =>
statusesUnchanged = _.isEqual(statuses, @statuses) and
_.isEqual(upstream, @upstream) and
_.isEqual(branch, @branch) and

View File

@ -77,10 +77,7 @@ class LinesYardstick
else
Point(row, column)
pixelPositionForScreenPosition: (screenPosition, clip=true) ->
screenPosition = Point.fromObject(screenPosition)
screenPosition = @model.clipScreenPosition(screenPosition) if clip
pixelPositionForScreenPosition: (screenPosition) ->
targetRow = screenPosition.row
targetColumn = screenPosition.column

View File

@ -199,7 +199,10 @@ class PackageManager
# Returns the {Package} that was disabled or null if it isn't loaded.
disablePackage: (name) ->
pack = @loadPackage(name)
pack?.disable()
unless @isPackageDisabled(name)
pack?.disable()
pack
# Public: Is the package with the given name disabled?

View File

@ -337,13 +337,19 @@ class Pane extends Model
#
# * `index` {Number}
activateItemAtIndex: (index) ->
@activateItem(@itemAtIndex(index))
item = @itemAtIndex(index) or @getActiveItem()
@setActiveItem(item)
# Public: Make the given item *active*, causing it to be displayed by
# the pane's view.
activateItem: (item) ->
if item?
@addItem(item, @getActiveItemIndex() + 1, false)
if @activeItem?.isPending?()
index = @getActiveItemIndex()
@destroyActiveItem() unless item is @activeItem
else
index = @getActiveItemIndex() + 1
@addItem(item, index, false)
@setActiveItem(item)
# Public: Add the given item to the pane.
@ -574,7 +580,6 @@ class Pane extends Model
# Public: Makes this pane the *active* pane, causing it to gain focus.
activate: ->
throw new Error("Pane has been destroyed") if @isDestroyed()
@container?.setActivePane(this)
@emitter.emit 'did-activate'
@ -721,30 +726,28 @@ class Pane extends Model
message = "#{message} '#{itemPath}'" if itemPath
@notificationManager.addWarning(message, options)
if error.code is 'EISDIR' or error.message?.endsWith?('is a directory')
customMessage = @getMessageForErrorCode(error.code)
if customMessage?
addWarningWithPath("Unable to save file: #{customMessage}")
else if error.code is 'EISDIR' or error.message?.endsWith?('is a directory')
@notificationManager.addWarning("Unable to save file: #{error.message}")
else if error.code is 'EACCES'
addWarningWithPath('Unable to save file: Permission denied')
else if error.code in ['EPERM', 'EBUSY', 'UNKNOWN', 'EEXIST', 'ELOOP', 'EAGAIN']
addWarningWithPath('Unable to save file', detail: error.message)
else if error.code is 'EROFS'
addWarningWithPath('Unable to save file: Read-only file system')
else if error.code is 'ENOSPC'
addWarningWithPath('Unable to save file: No space left on device')
else if error.code is 'ENXIO'
addWarningWithPath('Unable to save file: No such device or address')
else if error.code is 'ENOTSUP'
addWarningWithPath('Unable to save file: Operation not supported on socket')
else if error.code is 'EIO'
addWarningWithPath('Unable to save file: I/O error writing file')
else if error.code is 'EINTR'
addWarningWithPath('Unable to save file: Interrupted system call')
else if error.code is 'ECONNRESET'
addWarningWithPath('Unable to save file: Connection reset')
else if error.code is 'ESPIPE'
addWarningWithPath('Unable to save file: Invalid seek')
else if errorMatch = /ENOTDIR, not a directory '([^']+)'/.exec(error.message)
fileName = errorMatch[1]
@notificationManager.addWarning("Unable to save file: A directory in the path '#{fileName}' could not be written to")
else
throw error
getMessageForErrorCode: (errorCode) ->
switch errorCode
when 'EACCES' then 'Permission denied'
when 'ECONNRESET' then 'Connection reset'
when 'EINTR' then 'Interrupted system call'
when 'EIO' then 'I/O error writing file'
when 'ENOSPC' then 'No space left on device'
when 'ENOTSUP' then 'Operation not supported on socket'
when 'ENXIO' then 'No such device or address'
when 'EROFS' then 'Read-only file system'
when 'ESPIPE' then 'Invalid seek'
when 'ETIMEDOUT' then 'Connection timed out'

View File

@ -288,7 +288,7 @@ class Project extends Model
'atom.repository-provider',
'^0.1.0',
(provider) =>
@repositoryProviders.push(provider)
@repositoryProviders.unshift(provider)
@setPaths(@getPaths()) if null in @repositories
new Disposable =>
@repositoryProviders.splice(@repositoryProviders.indexOf(provider), 1)

View File

@ -169,7 +169,8 @@ module.exports = ({commandRegistry, commandInstaller, config}) ->
'editor:fold-at-indent-level-8': -> @foldAllAtIndentLevel(7)
'editor:fold-at-indent-level-9': -> @foldAllAtIndentLevel(8)
'editor:log-cursor-scope': -> @logCursorScope()
'editor:copy-path': -> @copyPathToClipboard()
'editor:copy-path': -> @copyPathToClipboard(false)
'editor:copy-project-path': -> @copyPathToClipboard(true)
'editor:toggle-indent-guide': -> config.set('editor.showIndentGuide', not config.get('editor.showIndentGuide'))
'editor:toggle-line-numbers': -> config.set('editor.showLineNumbers', not config.get('editor.showLineNumbers'))
'editor:scroll-to-cursor': -> @scrollToCursorPosition()

View File

@ -1,7 +1,7 @@
Git = require 'git-utils'
path = require 'path'
module.exports = (repoPath) ->
module.exports = (repoPath, paths = []) ->
repo = Git.open(repoPath)
upstream = {}
@ -12,7 +12,8 @@ module.exports = (repoPath) ->
if repo?
# Statuses in main repo
workingDirectoryPath = repo.getWorkingDirectory()
for filePath, status of repo.getStatus()
repoStatus = (if paths.length > 0 then repo.getStatusForPaths(paths) else repo.getStatus())
for filePath, status of repoStatus
statuses[filePath] = status
# Statuses in submodules

View File

@ -445,12 +445,17 @@ class TextEditorComponent
getVisibleRowRange: ->
@presenter.getVisibleRowRange()
pixelPositionForScreenPosition: (screenPosition, clip) ->
pixelPositionForScreenPosition: (screenPosition, clip=true) ->
screenPosition = Point.fromObject(screenPosition)
screenPosition = @editor.clipScreenPosition(screenPosition) if clip
unless @presenter.isRowVisible(screenPosition.row)
@presenter.setScreenRowsToMeasure([screenPosition.row])
unless @linesComponent.lineNodeForLineIdAndScreenRow(@presenter.lineIdForScreenRow(screenPosition.row), screenPosition.row)?
@updateSyncPreMeasurement()
pixelPosition = @linesYardstick.pixelPositionForScreenPosition(screenPosition, clip)
pixelPosition = @linesYardstick.pixelPositionForScreenPosition(screenPosition)
@presenter.clearScreenRowsToMeasure()
pixelPosition

View File

@ -459,7 +459,7 @@ class TextEditorPresenter
else
screenPosition = decoration.getMarker().getHeadScreenPosition()
pixelPosition = @pixelPositionForScreenPosition(screenPosition, true)
pixelPosition = @pixelPositionForScreenPosition(screenPosition)
top = pixelPosition.top + @lineHeight
left = pixelPosition.left + @gutterWidth
@ -681,8 +681,10 @@ class TextEditorPresenter
updateHorizontalDimensions: ->
if @baseCharacterWidth?
oldContentWidth = @contentWidth
clip = @model.tokenizedLineForScreenRow(@model.getLongestScreenRow())?.isSoftWrapped()
@contentWidth = @pixelPositionForScreenPosition([@model.getLongestScreenRow(), @model.getMaxScreenLineLength()], clip).left
rightmostPosition = Point(@model.getLongestScreenRow(), @model.getMaxScreenLineLength())
if @model.tokenizedLineForScreenRow(rightmostPosition.row)?.isSoftWrapped()
rightmostPosition = @model.clipScreenPosition(rightmostPosition)
@contentWidth = @pixelPositionForScreenPosition(rightmostPosition).left
@contentWidth += @scrollLeft
@contentWidth += 1 unless @model.isSoftWrapped() # account for cursor width
@ -1007,9 +1009,9 @@ class TextEditorPresenter
hasPixelPositionRequirements: ->
@lineHeight? and @baseCharacterWidth?
pixelPositionForScreenPosition: (screenPosition, clip=true) ->
pixelPositionForScreenPosition: (screenPosition) ->
position =
@linesYardstick.pixelPositionForScreenPosition(screenPosition, clip, true)
@linesYardstick.pixelPositionForScreenPosition(screenPosition)
position.top -= @getScrollTop()
position.left -= @getScrollLeft()
@ -1028,14 +1030,14 @@ class TextEditorPresenter
lineHeight = @model.getLineHeightInPixels()
if screenRange.end.row > screenRange.start.row
top = @linesYardstick.pixelPositionForScreenPosition(screenRange.start, true).top
top = @linesYardstick.pixelPositionForScreenPosition(screenRange.start).top
left = 0
height = (screenRange.end.row - screenRange.start.row + 1) * lineHeight
width = @getScrollWidth()
else
{top, left} = @linesYardstick.pixelPositionForScreenPosition(screenRange.start, false)
{top, left} = @linesYardstick.pixelPositionForScreenPosition(screenRange.start)
height = lineHeight
width = @linesYardstick.pixelPositionForScreenPosition(screenRange.end, false).left - left
width = @linesYardstick.pixelPositionForScreenPosition(screenRange.end).left - left
{top, left, width, height}
@ -1217,8 +1219,8 @@ class TextEditorPresenter
buildHighlightRegions: (screenRange) ->
lineHeightInPixels = @lineHeight
startPixelPosition = @pixelPositionForScreenPosition(screenRange.start, false)
endPixelPosition = @pixelPositionForScreenPosition(screenRange.end, false)
startPixelPosition = @pixelPositionForScreenPosition(screenRange.start)
endPixelPosition = @pixelPositionForScreenPosition(screenRange.end)
spannedRows = screenRange.end.row - screenRange.start.row + 1
regions = []
@ -1520,3 +1522,6 @@ class TextEditorPresenter
isRowVisible: (row) ->
@startRow <= row < @endRow
lineIdForScreenRow: (screenRow) ->
@model.tokenizedLineForScreenRow(screenRow)?.id

View File

@ -92,7 +92,7 @@ class TextEditor extends Model
softWrapped, @displayBuffer, @selectionsMarkerLayer, buffer, suppressCursorCreation,
@mini, @placeholderText, lineNumberGutterVisible, largeFileMode, @config,
@notificationManager, @packageManager, @clipboard, @viewRegistry, @grammarRegistry,
@project, @assert, @applicationDelegate
@project, @assert, @applicationDelegate, @pending
} = params
throw new Error("Must pass a config parameter when constructing TextEditors") unless @config?
@ -161,6 +161,9 @@ class TextEditor extends Model
@disposables.add @buffer.onDidChangeEncoding =>
@emitter.emit 'did-change-encoding', @getEncoding()
@disposables.add @buffer.onDidDestroy => @destroy()
if @pending
@disposables.add @buffer.onDidChangeModified =>
@terminatePendingState() if @buffer.isModified()
@preserveCursorPositionOnBufferReload()
@ -569,6 +572,13 @@ class TextEditor extends Model
getEditorWidthInChars: ->
@displayBuffer.getEditorWidthInChars()
onDidTerminatePendingState: (callback) ->
@emitter.on 'did-terminate-pending-state', callback
terminatePendingState: ->
@pending = false
@emitter.emit 'did-terminate-pending-state', this
###
Section: File Details
###
@ -652,9 +662,13 @@ class TextEditor extends Model
# Essential: Returns {Boolean} `true` if this editor has no content.
isEmpty: -> @buffer.isEmpty()
# Returns {Boolean} `true` if this editor is pending and `false` if it is permanent.
isPending: -> Boolean(@pending)
# Copies the current file path to the native clipboard.
copyPathToClipboard: ->
copyPathToClipboard: (relative = false) ->
if filePath = @getPath()
filePath = atom.project.relativize(filePath) if relative
@clipboard.write(filePath)
###
@ -3043,7 +3057,7 @@ class TextEditor extends Model
# Essential: Scrolls the editor to the given screen position.
#
# * `screenPosition` An object that represents a buffer position. It can be either
# * `screenPosition` An object that represents a screen position. It can be either
# an {Object} (`{row, column}`), {Array} (`[row, column]`), or {Point}
# * `options` (optional) {Object}
# * `center` Center the editor around the position if possible. (default: false)

View File

@ -475,7 +475,7 @@ class Workspace extends Model
when 'EACCES'
@notificationManager.addWarning("Permission denied '#{error.path}'")
return Promise.resolve()
when 'EPERM', 'EBUSY', 'ENXIO', 'EIO', 'ENOTCONN', 'UNKNOWN', 'ECONNRESET', 'EINVAL', 'EMFILE', 'ENOTDIR'
when 'EPERM', 'EBUSY', 'ENXIO', 'EIO', 'ENOTCONN', 'UNKNOWN', 'ECONNRESET', 'EINVAL', 'EMFILE', 'ENOTDIR', 'EAGAIN'
@notificationManager.addWarning("Unable to open '#{error.path ? uri}'", detail: error.message)
return Promise.resolve()
else