Merge branch 'master' into dh-async-repo

This commit is contained in:
joshaber
2015-11-06 11:43:37 -05:00
32 changed files with 1079 additions and 445 deletions

View File

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

View File

@@ -256,7 +256,7 @@ module.exports = (grunt) ->
loadingGif: path.resolve(__dirname, '..', 'resources', 'win', 'loading.gif')
iconUrl: "https://raw.githubusercontent.com/atom/atom/master/resources/app-icons/#{channel}/atom.ico"
setupIcon: path.resolve(__dirname, '..', 'resources', 'app-icons', channel, 'atom.ico')
remoteReleases: 'https://atom.io/api/updates'
remoteReleases: "https://atom.io/api/updates?version=#{metadata.version}"
shell:
'kill-atom':

View File

@@ -27,7 +27,7 @@
"grunt-peg": "~1.1.0",
"grunt-shell": "~0.3.1",
"grunt-standard": "^1.0.2",
"legal-eagle": "~0.11.0",
"legal-eagle": "~0.12.0",
"minidump": "~0.9",
"npm": "2.13.3",
"rcedit": "~0.3.0",

View File

@@ -1,7 +1,7 @@
{
"name": "atom",
"productName": "Atom",
"version": "1.2.0-dev",
"version": "1.3.0-dev",
"description": "A hackable text editor for the 21st Century.",
"main": "./src/browser/main.js",
"repository": {
@@ -18,6 +18,7 @@
"atom-keymap": "^6.1.0",
"babel-core": "^5.8.21",
"bootstrap": "^3.3.4",
"cached-run-in-this-context": "0.4.0",
"clear-cut": "^2.0.1",
"coffee-script": "1.8.0",
"color": "^0.7.3",
@@ -86,12 +87,12 @@
"background-tips": "0.26.0",
"bookmarks": "0.38.0",
"bracket-matcher": "0.79.0",
"command-palette": "0.36.0",
"command-palette": "0.37.0",
"deprecation-cop": "0.54.0",
"dev-live-reload": "0.47.0",
"encoding-selector": "0.21.0",
"exception-reporting": "0.37.0",
"find-and-replace": "0.189.0",
"find-and-replace": "0.190.0",
"fuzzy-finder": "0.93.0",
"git-diff": "0.57.0",
"go-to-line": "0.30.0",
@@ -113,9 +114,9 @@
"status-bar": "0.80.0",
"styleguide": "0.45.0",
"symbols-view": "0.110.0",
"tabs": "0.87.0",
"tabs": "0.88.0",
"timecop": "0.33.0",
"tree-view": "0.194.0",
"tree-view": "0.196.0",
"update-package-dependencies": "0.10.0",
"welcome": "0.32.0",
"whitespace": "0.32.0",
@@ -124,14 +125,14 @@
"language-clojure": "0.18.0",
"language-coffee-script": "0.43.0",
"language-csharp": "0.11.0",
"language-css": "0.34.0",
"language-css": "0.35.0",
"language-gfm": "0.81.0",
"language-git": "0.10.0",
"language-go": "0.39.0",
"language-go": "0.40.0",
"language-html": "0.42.0",
"language-hyperlink": "0.15.0",
"language-java": "0.16.0",
"language-javascript": "0.97.0",
"language-java": "0.16.1",
"language-javascript": "0.98.0",
"language-json": "0.17.1",
"language-less": "0.28.3",
"language-make": "0.19.0",
@@ -142,15 +143,15 @@
"language-property-list": "0.8.0",
"language-python": "0.41.0",
"language-ruby": "0.60.0",
"language-ruby-on-rails": "0.23.0",
"language-sass": "0.42.0",
"language-shellscript": "0.19.0",
"language-ruby-on-rails": "0.24.0",
"language-sass": "0.42.1",
"language-shellscript": "0.20.0",
"language-source": "0.9.0",
"language-sql": "0.18.0",
"language-sql": "0.19.0",
"language-text": "0.7.0",
"language-todo": "0.27.0",
"language-toml": "0.16.0",
"language-xml": "0.33.1",
"language-xml": "0.34.0",
"language-yaml": "0.24.0"
},
"private": true,

View File

@@ -8,18 +8,22 @@ var semver = require('semver')
series([
section('Preparing to roll the railcars'),
checkCleanWorkingTree,
run('git fetch origin master:master beta:beta stable:stable'),
run('git checkout master'),
run('git pull --ff-only origin master'),
run('git fetch origin beta:beta stable:stable'),
run('git fetch origin --tags'),
section('Checking that merges will be fast-forwards'),
run('git branch --contains beta | grep master'),
run('git branch --contains stable | grep beta'),
section('Updating stable branch'),
run('git checkout stable'),
run('git merge --ff-only origin/stable'),
run('git merge --ff-only origin/beta'),
bumpStableVersion,
section('Updating beta branch'),
run('git checkout beta'),
run('git merge --ff-only origin/beta'),
run('git merge --ff-only origin/master'),
run('git merge --strategy ours origin/stable'),
bumpBetaVersion,
@@ -44,11 +48,12 @@ function checkCleanWorkingTree (next) {
}
function bumpStableVersion (next) {
run('npm version patch')(next)
var newVersion = getCurrentVersion().replace(/-beta.*$/, '')
run('npm version ' + newVersion)(next)
}
function bumpBetaVersion (next) {
var newVersion = semver.inc(getCurrentVersion(), 'preminor', 'beta')
var newVersion = getCurrentVersion().replace(/-dev$/, '-beta0')
run('npm version ' + newVersion)(next)
}

View File

@@ -215,6 +215,17 @@ describe "AtomEnvironment", ->
expect(atom.project.getPaths()).toEqual(initialPaths)
describe "::unloadEditorWindow()", ->
it "saves the BlobStore so it can be loaded after reload", ->
configDirPath = temp.mkdirSync()
fakeBlobStore = jasmine.createSpyObj("blob store", ["save"])
atomEnvironment = new AtomEnvironment({applicationDelegate: atom.applicationDelegate, enablePersistence: true, configDirPath, blobStore: fakeBlobStore, window, document})
atomEnvironment.unloadEditorWindow()
expect(fakeBlobStore.save).toHaveBeenCalled()
atomEnvironment.destroy()
it "saves the serialized state of the window so it can be deserialized after reload", ->
atomEnvironment = new AtomEnvironment({applicationDelegate: atom.applicationDelegate, window, document})
spyOn(atomEnvironment, 'saveStateSync')

View File

@@ -0,0 +1,68 @@
path = require "path"
fs = require 'fs-plus'
temp = require "temp"
AtomPortable = require "../src/browser/atom-portable"
portableModeCommonPlatformBehavior = (platform) ->
describe "with ATOM_HOME environment variable", ->
it "returns false", ->
expect(AtomPortable.isPortableInstall(platform, "C:\\some\\path")).toBe false
describe "without ATOM_HOME environment variable", ->
environmentAtomHome = undefined
portableAtomHomePath = path.join(path.dirname(process.execPath), "..", ".atom")
portableAtomHomeNaturallyExists = fs.existsSync(portableAtomHomePath)
portableAtomHomeBackupPath = "#{portableAtomHomePath}.temp"
beforeEach ->
fs.renameSync(portableAtomHomePath, portableAtomHomeBackupPath) if fs.existsSync(portableAtomHomePath)
afterEach ->
if portableAtomHomeNaturallyExists
fs.renameSync(portableAtomHomeBackupPath, portableAtomHomePath) if not fs.existsSync(portableAtomHomePath)
else
fs.removeSync(portableAtomHomePath) if fs.existsSync(portableAtomHomePath)
fs.removeSync(portableAtomHomeBackupPath) if fs.existsSync(portableAtomHomeBackupPath)
describe "with .atom directory sibling to exec", ->
beforeEach ->
fs.mkdirSync(portableAtomHomePath) if not fs.existsSync(portableAtomHomePath)
describe "without .atom directory sibling to exec", ->
beforeEach ->
fs.removeSync(portableAtomHomePath) if fs.existsSync(portableAtomHomePath)
it "returns false", ->
expect(AtomPortable.isPortableInstall(platform, environmentAtomHome)).toBe false
describe "Set Portable Mode on #win32", ->
portableAtomHomePath = path.join(path.dirname(process.execPath), "..", ".atom")
portableAtomHomeNaturallyExists = fs.existsSync(portableAtomHomePath)
portableAtomHomeBackupPath = "#{portableAtomHomePath}.temp"
beforeEach ->
fs.renameSync(portableAtomHomePath, portableAtomHomeBackupPath) if fs.existsSync(portableAtomHomePath)
afterEach ->
if portableAtomHomeNaturallyExists
fs.renameSync(portableAtomHomeBackupPath, portableAtomHomePath) if not fs.existsSync(portableAtomHomePath)
else
fs.removeSync(portableAtomHomePath) if fs.existsSync(portableAtomHomePath)
fs.removeSync(portableAtomHomeBackupPath) if fs.existsSync(portableAtomHomeBackupPath)
it "creates a portable home directory", ->
expect(fs.existsSync(portableAtomHomePath)).toBe false
AtomPortable.setPortable(process.env.ATOM_HOME)
expect(fs.existsSync(portableAtomHomePath)).toBe true
describe "Check for Portable Mode", ->
describe "Windows", ->
portableModeCommonPlatformBehavior "win32"
describe "Mac", ->
it "returns false", ->
expect(AtomPortable.isPortableInstall("darwin", "darwin")).toBe false
describe "Linux", ->
portableModeCommonPlatformBehavior "linux"

View File

@@ -0,0 +1,69 @@
temp = require 'temp'
FileSystemBlobStore = require '../src/file-system-blob-store'
describe "FileSystemBlobStore", ->
[storageDirectory, blobStore] = []
beforeEach ->
storageDirectory = temp.path()
blobStore = FileSystemBlobStore.load(storageDirectory)
it "is empty when the file doesn't exist", ->
expect(blobStore.get("foo")).toBeUndefined()
expect(blobStore.get("bar")).toBeUndefined()
it "allows to read and write buffers from/to memory without persisting them", ->
blobStore.set("foo", new Buffer("foo"))
blobStore.set("bar", new Buffer("bar"))
expect(blobStore.get("foo")).toEqual(new Buffer("foo"))
expect(blobStore.get("bar")).toEqual(new Buffer("bar"))
it "persists buffers when saved and retrieves them on load, giving priority to in-memory ones", ->
blobStore.set("foo", new Buffer("foo"))
blobStore.set("bar", new Buffer("bar"))
blobStore.save()
blobStore = FileSystemBlobStore.load(storageDirectory)
expect(blobStore.get("foo")).toEqual(new Buffer("foo"))
expect(blobStore.get("bar")).toEqual(new Buffer("bar"))
blobStore.set("foo", new Buffer("changed"))
expect(blobStore.get("foo")).toEqual(new Buffer("changed"))
it "persists both in-memory and previously stored buffers when saved", ->
blobStore.set("foo", new Buffer("foo"))
blobStore.set("bar", new Buffer("bar"))
blobStore.save()
blobStore = FileSystemBlobStore.load(storageDirectory)
blobStore.set("bar", new Buffer("changed"))
blobStore.set("qux", new Buffer("qux"))
blobStore.save()
blobStore = FileSystemBlobStore.load(storageDirectory)
expect(blobStore.get("foo")).toEqual(new Buffer("foo"))
expect(blobStore.get("bar")).toEqual(new Buffer("changed"))
expect(blobStore.get("qux")).toEqual(new Buffer("qux"))
it "allows to delete keys from both memory and stored buffers", ->
blobStore.set("a", new Buffer("a"))
blobStore.set("b", new Buffer("b"))
blobStore.save()
blobStore = FileSystemBlobStore.load(storageDirectory)
blobStore.set("b", new Buffer("b"))
blobStore.set("c", new Buffer("c"))
blobStore.delete("b")
blobStore.delete("c")
blobStore.save()
blobStore = FileSystemBlobStore.load(storageDirectory)
expect(blobStore.get("a")).toEqual(new Buffer("a"))
expect(blobStore.get("b")).toBeUndefined()
expect(blobStore.get("c")).toBeUndefined()

1
spec/fixtures/native-cache/file-1.js vendored Normal file
View File

@@ -0,0 +1 @@
module.exports = function () { return 1; }

1
spec/fixtures/native-cache/file-2.js vendored Normal file
View File

@@ -0,0 +1 @@
module.exports = function () { return 2; }

1
spec/fixtures/native-cache/file-3.js vendored Normal file
View File

@@ -0,0 +1 @@
module.exports = function () { return 3; }

View File

View File

View File

View File

View File

@@ -2,7 +2,7 @@ LinesYardstick = require "../src/lines-yardstick"
{toArray} = require 'underscore-plus'
describe "LinesYardstick", ->
[editor, mockPresenter, mockLineNodesProvider, createdLineNodes, linesYardstick] = []
[editor, mockPresenter, mockLineNodesProvider, createdLineNodes, linesYardstick, buildLineNode] = []
beforeEach ->
waitsForPromise ->
@@ -49,10 +49,10 @@ describe "LinesYardstick", ->
buildLineNode(screenRow)
textNodesForLineIdAndScreenRow: (lineId, screenRow) ->
lineNode = @lineNodeForLineIdAndScreenRow(lineId, screenRow)
iterator = document.createNodeIterator(lineNode, NodeFilter.SHOW_TEXT)
textNodes = []
for span in lineNode.children
for textNode in span.childNodes
textNodes.push(textNode)
while textNode = iterator.nextNode()
textNodes.push(textNode)
textNodes
editor.setLineHeightInPixels(14)
@@ -126,6 +126,33 @@ describe "LinesYardstick", ->
expect(linesYardstick.pixelPositionForScreenPosition([0, 9]).left).toBe 67
expect(linesYardstick.pixelPositionForScreenPosition([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
# expect that Range(0, 0).getBoundingClientRect().width to always be zero.
atom.styles.addStyleSheet """
* {
font-size: 11px;
font-family: monospace;
}
"""
text = " \\vec{w}_j^r(\\text{new}) &= \\vec{w}_j^r(\\text{old}) + \\Delta\\vec{w}_j^r, \\\\"
buildLineNode = (screenRow) ->
lineNode = document.createElement("div")
lineNode.style.whiteSpace = "pre"
# We couldn't reproduce the problem with a simple string, so we're
# attaching the full one that comes from a bug report.
lineNode.innerHTML = '<span><span> </span><span> </span><span><span>\\</span>vec</span><span><span>{</span>w<span>}</span></span>_j^r(<span><span>\\</span>text</span><span><span>{</span>new<span>}</span></span>) &amp;= <span><span>\\</span>vec</span><span><span>{</span>w<span>}</span></span>_j^r(<span><span>\\</span>text</span><span><span>{</span>old<span>}</span></span>) + <span><span>\\</span>Delta</span><span><span>\\</span>vec</span><span><span>{</span>w<span>}</span></span>_j^r, <span>\\\\</span></span>'
jasmine.attachToDOM(lineNode)
createdLineNodes.push(lineNode)
lineNode
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
it "doesn't measure invisible lines if it is explicitly told so", ->
atom.styles.addStyleSheet """
* {

View File

@@ -0,0 +1,47 @@
describe "NativeCompileCache", ->
nativeCompileCache = require '../src/native-compile-cache'
[fakeCacheStore, cachedFiles] = []
beforeEach ->
cachedFiles = []
fakeCacheStore = jasmine.createSpyObj("cache store", ["set", "get", "has", "delete"])
nativeCompileCache.setCacheStore(fakeCacheStore)
nativeCompileCache.install()
it "writes and reads from the cache storage when requiring files", ->
fakeCacheStore.has.andReturn(false)
fakeCacheStore.set.andCallFake (filename, cacheBuffer) ->
cachedFiles.push({filename, cacheBuffer})
fn1 = require('./fixtures/native-cache/file-1')
fn2 = require('./fixtures/native-cache/file-2')
expect(cachedFiles.length).toBe(2)
expect(cachedFiles[0].filename).toBe(require.resolve('./fixtures/native-cache/file-1'))
expect(cachedFiles[0].cacheBuffer).toBeInstanceOf(Uint8Array)
expect(cachedFiles[0].cacheBuffer.length).toBeGreaterThan(0)
expect(fn1()).toBe(1)
expect(cachedFiles[1].filename).toBe(require.resolve('./fixtures/native-cache/file-2'))
expect(cachedFiles[1].cacheBuffer).toBeInstanceOf(Uint8Array)
expect(cachedFiles[1].cacheBuffer.length).toBeGreaterThan(0)
expect(fn2()).toBe(2)
fakeCacheStore.has.andReturn(true)
fakeCacheStore.get.andReturn(cachedFiles[0].cacheBuffer)
fakeCacheStore.set.reset()
fn1 = require('./fixtures/native-cache/file-1')
expect(fakeCacheStore.set).not.toHaveBeenCalled()
expect(fn1()).toBe(1)
it "deletes previously cached code when the cache is not valid", ->
fakeCacheStore.has.andReturn(true)
fakeCacheStore.get.andCallFake -> new Buffer("an invalid cache")
fn3 = require('./fixtures/native-cache/file-3')
expect(fakeCacheStore.delete).toHaveBeenCalledWith(require.resolve('./fixtures/native-cache/file-3'))
expect(fn3()).toBe(3)

View File

@@ -38,6 +38,7 @@ describe "PackageManager", ->
expect(-> pack.reloadStylesheets()).not.toThrow()
expect(addErrorHandler.callCount).toBe 2
expect(addErrorHandler.argsForCall[1][0].message).toContain("Failed to reload the package-with-invalid-styles package stylesheets")
expect(addErrorHandler.argsForCall[1][0].options.packageName).toEqual "package-with-invalid-styles"
it "returns null if the package has an invalid package.json", ->
addErrorHandler = jasmine.createSpy()
@@ -45,6 +46,7 @@ describe "PackageManager", ->
expect(atom.packages.loadPackage("package-with-broken-package-json")).toBeNull()
expect(addErrorHandler.callCount).toBe 1
expect(addErrorHandler.argsForCall[0][0].message).toContain("Failed to load the package-with-broken-package-json package")
expect(addErrorHandler.argsForCall[0][0].options.packageName).toEqual "package-with-broken-package-json"
it "normalizes short repository urls in package.json", ->
{metadata} = atom.packages.loadPackage("package-with-short-url-package-json")
@@ -230,6 +232,7 @@ describe "PackageManager", ->
expect(-> atom.packages.activatePackage('package-with-invalid-activation-commands')).not.toThrow()
expect(addErrorHandler.callCount).toBe 1
expect(addErrorHandler.argsForCall[0][0].message).toContain("Failed to activate the package-with-invalid-activation-commands package")
expect(addErrorHandler.argsForCall[0][0].options.packageName).toEqual "package-with-invalid-activation-commands"
it "adds a notification when the context menu is invalid", ->
addErrorHandler = jasmine.createSpy()
@@ -237,6 +240,7 @@ describe "PackageManager", ->
expect(-> atom.packages.activatePackage('package-with-invalid-context-menu')).not.toThrow()
expect(addErrorHandler.callCount).toBe 1
expect(addErrorHandler.argsForCall[0][0].message).toContain("Failed to activate the package-with-invalid-context-menu package")
expect(addErrorHandler.argsForCall[0][0].options.packageName).toEqual "package-with-invalid-context-menu"
it "adds a notification when the grammar is invalid", ->
addErrorHandler = jasmine.createSpy()
@@ -250,6 +254,7 @@ describe "PackageManager", ->
runs ->
expect(addErrorHandler.callCount).toBe 1
expect(addErrorHandler.argsForCall[0][0].message).toContain("Failed to load a package-with-invalid-grammar package grammar")
expect(addErrorHandler.argsForCall[0][0].options.packageName).toEqual "package-with-invalid-grammar"
it "adds a notification when the settings are invalid", ->
addErrorHandler = jasmine.createSpy()
@@ -263,6 +268,7 @@ describe "PackageManager", ->
runs ->
expect(addErrorHandler.callCount).toBe 1
expect(addErrorHandler.argsForCall[0][0].message).toContain("Failed to load the package-with-invalid-settings package settings")
expect(addErrorHandler.argsForCall[0][0].options.packageName).toEqual "package-with-invalid-settings"
describe "when the package metadata includes `activationHooks`", ->
[mainModule, promise] = []
@@ -351,6 +357,7 @@ describe "PackageManager", ->
expect(-> atom.packages.activatePackage("package-that-throws-an-exception")).not.toThrow()
expect(addErrorHandler.callCount).toBe 1
expect(addErrorHandler.argsForCall[0][0].message).toContain("Failed to load the package-that-throws-an-exception package")
expect(addErrorHandler.argsForCall[0][0].options.packageName).toEqual "package-that-throws-an-exception"
describe "when the package is not found", ->
it "rejects the promise", ->

View File

@@ -168,6 +168,37 @@ describe "TextEditor", ->
buffer.setPath(undefined)
expect(editor.getLongTitle()).toBe 'untitled'
describe ".getUniqueTitle()", ->
it "returns file name when there is no opened file with identical name", ->
expect(editor.getUniqueTitle()).toBe 'sample.js'
buffer.setPath(undefined)
expect(editor.getLongTitle()).toBe 'untitled'
it "returns <parent-directory>/<filename> when opened files has identical file names", ->
editor1 = null
editor2 = null
waitsForPromise ->
atom.workspace.open(path.join('sample-theme-1', 'readme')).then (o) ->
editor1 = o
atom.workspace.open(path.join('sample-theme-2', 'readme')).then (o) ->
editor2 = o
runs ->
expect(editor1.getUniqueTitle()).toBe 'sample-theme-1/readme'
expect(editor2.getUniqueTitle()).toBe 'sample-theme-2/readme'
it "or returns <parent-directory>/.../<filename> when opened files has identical file names", ->
editor1 = null
editor2 = null
waitsForPromise ->
atom.workspace.open(path.join('sample-theme-1', 'src', 'js', 'main.js')).then (o) ->
editor1 = o
atom.workspace.open(path.join('sample-theme-2', 'src', 'js', 'main.js')).then (o) ->
editor2 = o
runs ->
expect(editor1.getUniqueTitle()).toBe 'sample-theme-1/.../main.js'
expect(editor2.getUniqueTitle()).toBe 'sample-theme-2/.../main.js'
it "notifies ::onDidChangeTitle observers when the underlying buffer path changes", ->
observed = []
editor.onDidChangeTitle (title) -> observed.push(title)
@@ -827,6 +858,185 @@ describe "TextEditor", ->
editor.moveToBeginningOfNextWord()
expect(editor.getCursorBufferPosition()).toEqual [11, 9]
describe ".moveToPreviousSubwordBoundary", ->
it "does not move the cursor when there is no previous subword boundary", ->
editor.setText('')
editor.moveToPreviousSubwordBoundary()
expect(editor.getCursorBufferPosition()).toEqual([0, 0])
it "stops at word and underscore boundaries", ->
editor.setText("sub_word \n")
editor.setCursorBufferPosition([0, 9])
editor.moveToPreviousSubwordBoundary()
expect(editor.getCursorBufferPosition()).toEqual([0, 8])
editor.moveToPreviousSubwordBoundary()
expect(editor.getCursorBufferPosition()).toEqual([0, 4])
editor.moveToPreviousSubwordBoundary()
expect(editor.getCursorBufferPosition()).toEqual([0, 0])
editor.setText(" word\n")
editor.setCursorBufferPosition([0, 3])
editor.moveToPreviousSubwordBoundary()
expect(editor.getCursorBufferPosition()).toEqual([0, 1])
it "stops at camelCase boundaries", ->
editor.setText(" getPreviousWord\n")
editor.setCursorBufferPosition([0, 16])
editor.moveToPreviousSubwordBoundary()
expect(editor.getCursorBufferPosition()).toEqual([0, 12])
editor.moveToPreviousSubwordBoundary()
expect(editor.getCursorBufferPosition()).toEqual([0, 4])
editor.moveToPreviousSubwordBoundary()
expect(editor.getCursorBufferPosition()).toEqual([0, 1])
it "skips consecutive non-word characters", ->
editor.setText("e, => \n")
editor.setCursorBufferPosition([0, 6])
editor.moveToPreviousSubwordBoundary()
expect(editor.getCursorBufferPosition()).toEqual([0, 3])
editor.moveToPreviousSubwordBoundary()
expect(editor.getCursorBufferPosition()).toEqual([0, 1])
it "skips consecutive uppercase characters", ->
editor.setText(" AAADF \n")
editor.setCursorBufferPosition([0, 7])
editor.moveToPreviousSubwordBoundary()
expect(editor.getCursorBufferPosition()).toEqual([0, 6])
editor.moveToPreviousSubwordBoundary()
expect(editor.getCursorBufferPosition()).toEqual([0, 1])
editor.setText("ALPhA\n")
editor.setCursorBufferPosition([0, 4])
editor.moveToPreviousSubwordBoundary()
expect(editor.getCursorBufferPosition()).toEqual([0, 2])
it "skips consecutive numbers", ->
editor.setText(" 88 \n")
editor.setCursorBufferPosition([0, 4])
editor.moveToPreviousSubwordBoundary()
expect(editor.getCursorBufferPosition()).toEqual([0, 3])
editor.moveToPreviousSubwordBoundary()
expect(editor.getCursorBufferPosition()).toEqual([0, 1])
it "works with multiple cursors", ->
editor.setText("curOp\ncursorOptions\n")
editor.setCursorBufferPosition([0, 8])
editor.addCursorAtBufferPosition([1, 13])
[cursor1, cursor2] = editor.getCursors()
editor.moveToPreviousSubwordBoundary()
expect(cursor1.getBufferPosition()).toEqual([0, 3])
expect(cursor2.getBufferPosition()).toEqual([1, 6])
it "works with non-English characters", ->
editor.setText("supåTøåst \n")
editor.setCursorBufferPosition([0, 9])
editor.moveToPreviousSubwordBoundary()
expect(editor.getCursorBufferPosition()).toEqual([0, 4])
editor.setText("supaÖast \n")
editor.setCursorBufferPosition([0, 8])
editor.moveToPreviousSubwordBoundary()
expect(editor.getCursorBufferPosition()).toEqual([0, 4])
describe ".moveToNextSubwordBoundary", ->
it "does not move the cursor when there is no next subword boundary", ->
editor.setText('')
editor.moveToNextSubwordBoundary()
expect(editor.getCursorBufferPosition()).toEqual([0, 0])
it "stops at word and underscore boundaries", ->
editor.setText(" sub_word \n")
editor.setCursorBufferPosition([0, 0])
editor.moveToNextSubwordBoundary()
expect(editor.getCursorBufferPosition()).toEqual([0, 1])
editor.moveToNextSubwordBoundary()
expect(editor.getCursorBufferPosition()).toEqual([0, 4])
editor.moveToNextSubwordBoundary()
expect(editor.getCursorBufferPosition()).toEqual([0, 9])
editor.setText("word \n")
editor.setCursorBufferPosition([0, 0])
editor.moveToNextSubwordBoundary()
expect(editor.getCursorBufferPosition()).toEqual([0, 4])
it "stops at camelCase boundaries", ->
editor.setText("getPreviousWord \n")
editor.setCursorBufferPosition([0, 0])
editor.moveToNextSubwordBoundary()
expect(editor.getCursorBufferPosition()).toEqual([0, 3])
editor.moveToNextSubwordBoundary()
expect(editor.getCursorBufferPosition()).toEqual([0, 11])
editor.moveToNextSubwordBoundary()
expect(editor.getCursorBufferPosition()).toEqual([0, 15])
it "skips consecutive non-word characters", ->
editor.setText(", => \n")
editor.setCursorBufferPosition([0, 0])
editor.moveToNextSubwordBoundary()
expect(editor.getCursorBufferPosition()).toEqual([0, 1])
editor.moveToNextSubwordBoundary()
expect(editor.getCursorBufferPosition()).toEqual([0, 4])
it "skips consecutive uppercase characters", ->
editor.setText(" AAADF \n")
editor.setCursorBufferPosition([0, 0])
editor.moveToNextSubwordBoundary()
expect(editor.getCursorBufferPosition()).toEqual([0, 1])
editor.moveToNextSubwordBoundary()
expect(editor.getCursorBufferPosition()).toEqual([0, 6])
editor.setText("ALPhA\n")
editor.setCursorBufferPosition([0, 0])
editor.moveToNextSubwordBoundary()
expect(editor.getCursorBufferPosition()).toEqual([0, 2])
it "skips consecutive numbers", ->
editor.setText(" 88 \n")
editor.setCursorBufferPosition([0, 0])
editor.moveToNextSubwordBoundary()
expect(editor.getCursorBufferPosition()).toEqual([0, 1])
editor.moveToNextSubwordBoundary()
expect(editor.getCursorBufferPosition()).toEqual([0, 3])
it "works with multiple cursors", ->
editor.setText("curOp\ncursorOptions\n")
editor.setCursorBufferPosition([0, 0])
editor.addCursorAtBufferPosition([1, 0])
[cursor1, cursor2] = editor.getCursors()
editor.moveToNextSubwordBoundary()
expect(cursor1.getBufferPosition()).toEqual([0, 3])
expect(cursor2.getBufferPosition()).toEqual([1, 6])
it "works with non-English characters", ->
editor.setText("supåTøåst \n")
editor.setCursorBufferPosition([0, 0])
editor.moveToNextSubwordBoundary()
expect(editor.getCursorBufferPosition()).toEqual([0, 4])
editor.setText("supaÖast \n")
editor.setCursorBufferPosition([0, 0])
editor.moveToNextSubwordBoundary()
expect(editor.getCursorBufferPosition()).toEqual([0, 4])
describe ".moveToBeginningOfNextParagraph()", ->
it "moves the cursor before the first line of the next paragraph", ->
editor.setCursorBufferPosition [0, 6]
@@ -1299,6 +1509,128 @@ describe "TextEditor", ->
expect(selection4.getBufferRange()).toEqual [[3, 30], [3, 31]]
expect(selection4.isReversed()).toBeFalsy()
describe ".selectToPreviousSubwordBoundary", ->
it "selects subwords", ->
editor.setText("")
editor.insertText("_word\n")
editor.insertText(" getPreviousWord\n")
editor.insertText("e, => \n")
editor.insertText(" 88 \n")
editor.setCursorBufferPosition([0, 5])
editor.addCursorAtBufferPosition([1, 7])
editor.addCursorAtBufferPosition([2, 5])
editor.addCursorAtBufferPosition([3, 3])
[selection1, selection2, selection3, selection4] = editor.getSelections()
editor.selectToPreviousSubwordBoundary()
expect(selection1.getBufferRange()).toEqual([[0, 1], [0, 5]])
expect(selection1.isReversed()).toBeTruthy()
expect(selection2.getBufferRange()).toEqual([[1, 4], [1, 7]])
expect(selection2.isReversed()).toBeTruthy()
expect(selection3.getBufferRange()).toEqual([[2, 3], [2, 5]])
expect(selection3.isReversed()).toBeTruthy()
expect(selection4.getBufferRange()).toEqual([[3, 1], [3, 3]])
expect(selection4.isReversed()).toBeTruthy()
describe ".selectToNextSubwordBoundary", ->
it "selects subwords", ->
editor.setText("")
editor.insertText("word_\n")
editor.insertText("getPreviousWord\n")
editor.insertText("e, => \n")
editor.insertText(" 88 \n")
editor.setCursorBufferPosition([0, 1])
editor.addCursorAtBufferPosition([1, 7])
editor.addCursorAtBufferPosition([2, 2])
editor.addCursorAtBufferPosition([3, 1])
[selection1, selection2, selection3, selection4] = editor.getSelections()
editor.selectToNextSubwordBoundary()
expect(selection1.getBufferRange()).toEqual([[0, 1], [0, 4]])
expect(selection1.isReversed()).toBeFalsy()
expect(selection2.getBufferRange()).toEqual([[1, 7], [1, 11]])
expect(selection2.isReversed()).toBeFalsy()
expect(selection3.getBufferRange()).toEqual([[2, 2], [2, 5]])
expect(selection3.isReversed()).toBeFalsy()
expect(selection4.getBufferRange()).toEqual([[3, 1], [3, 3]])
expect(selection4.isReversed()).toBeFalsy()
describe ".deleteToBeginningOfSubword", ->
it "deletes subwords", ->
editor.setText("")
editor.insertText("_word\n")
editor.insertText(" getPreviousWord\n")
editor.insertText("e, => \n")
editor.insertText(" 88 \n")
editor.setCursorBufferPosition([0, 5])
editor.addCursorAtBufferPosition([1, 7])
editor.addCursorAtBufferPosition([2, 5])
editor.addCursorAtBufferPosition([3, 3])
[cursor1, cursor2, cursor3, cursor4] = editor.getCursors()
editor.deleteToBeginningOfSubword()
expect(buffer.lineForRow(0)).toBe('_')
expect(buffer.lineForRow(1)).toBe(' getviousWord')
expect(buffer.lineForRow(2)).toBe('e, ')
expect(buffer.lineForRow(3)).toBe(' ')
expect(cursor1.getBufferPosition()).toEqual([0, 1])
expect(cursor2.getBufferPosition()).toEqual([1, 4])
expect(cursor3.getBufferPosition()).toEqual([2, 3])
expect(cursor4.getBufferPosition()).toEqual([3, 1])
editor.deleteToBeginningOfSubword()
expect(buffer.lineForRow(0)).toBe('')
expect(buffer.lineForRow(1)).toBe(' viousWord')
expect(buffer.lineForRow(2)).toBe('e ')
expect(buffer.lineForRow(3)).toBe(' ')
expect(cursor1.getBufferPosition()).toEqual([0, 0])
expect(cursor2.getBufferPosition()).toEqual([1, 1])
expect(cursor3.getBufferPosition()).toEqual([2, 1])
expect(cursor4.getBufferPosition()).toEqual([3, 0])
editor.deleteToBeginningOfSubword()
expect(buffer.lineForRow(0)).toBe('')
expect(buffer.lineForRow(1)).toBe('viousWord')
expect(buffer.lineForRow(2)).toBe(' ')
expect(buffer.lineForRow(3)).toBe('')
expect(cursor1.getBufferPosition()).toEqual([0, 0])
expect(cursor2.getBufferPosition()).toEqual([1, 0])
expect(cursor3.getBufferPosition()).toEqual([2, 0])
expect(cursor4.getBufferPosition()).toEqual([2, 1])
describe ".deleteToEndOfSubword", ->
it "deletes subwords", ->
editor.setText("")
editor.insertText("word_\n")
editor.insertText("getPreviousWord \n")
editor.insertText("e, => \n")
editor.insertText(" 88 \n")
editor.setCursorBufferPosition([0, 0])
editor.addCursorAtBufferPosition([1, 0])
editor.addCursorAtBufferPosition([2, 2])
editor.addCursorAtBufferPosition([3, 0])
[cursor1, cursor2, cursor3, cursor4] = editor.getCursors()
editor.deleteToEndOfSubword()
expect(buffer.lineForRow(0)).toBe('_')
expect(buffer.lineForRow(1)).toBe('PreviousWord ')
expect(buffer.lineForRow(2)).toBe('e, ')
expect(buffer.lineForRow(3)).toBe('88 ')
expect(cursor1.getBufferPosition()).toEqual([0, 0])
expect(cursor2.getBufferPosition()).toEqual([1, 0])
expect(cursor3.getBufferPosition()).toEqual([2, 2])
expect(cursor4.getBufferPosition()).toEqual([3, 0])
editor.deleteToEndOfSubword()
expect(buffer.lineForRow(0)).toBe('')
expect(buffer.lineForRow(1)).toBe('Word ')
expect(buffer.lineForRow(2)).toBe('e,')
expect(buffer.lineForRow(3)).toBe(' ')
expect(cursor1.getBufferPosition()).toEqual([0, 0])
expect(cursor2.getBufferPosition()).toEqual([1, 0])
expect(cursor3.getBufferPosition()).toEqual([2, 2])
expect(cursor4.getBufferPosition()).toEqual([3, 0])
describe ".selectWordsContainingCursors()", ->
describe "when the cursor is inside a word", ->
it "selects the entire word", ->
@@ -4160,6 +4492,36 @@ describe "TextEditor", ->
"""
expect(editor.getSelectedBufferRange()).toEqual [[13, 0], [14, 2]]
describe ".moveLineUp()", ->
it "moves the line under the cursor up", ->
editor.setCursorBufferPosition([1, 0])
editor.moveLineUp()
expect(editor.getTextInBufferRange([[0, 0], [0, 30]])).toBe " var sort = function(items) {"
expect(editor.indentationForBufferRow(0)).toBe 1
expect(editor.indentationForBufferRow(1)).toBe 0
it "updates the line's indentation when the editor.autoIndent setting is true", ->
atom.config.set('editor.autoIndent', true)
editor.setCursorBufferPosition([1, 0])
editor.moveLineUp()
expect(editor.indentationForBufferRow(0)).toBe 0
expect(editor.indentationForBufferRow(1)).toBe 0
describe ".moveLineDown()", ->
it "moves the line under the cursor down", ->
editor.setCursorBufferPosition([0, 0])
editor.moveLineDown()
expect(editor.getTextInBufferRange([[1, 0], [1, 31]])).toBe "var quicksort = function () {"
expect(editor.indentationForBufferRow(0)).toBe 1
expect(editor.indentationForBufferRow(1)).toBe 0
it "updates the line's indentation when the editor.autoIndent setting is true", ->
atom.config.set('editor.autoIndent', true)
editor.setCursorBufferPosition([0, 0])
editor.moveLineDown()
expect(editor.indentationForBufferRow(0)).toBe 1
expect(editor.indentationForBufferRow(1)).toBe 2
describe ".shouldPromptToSave()", ->
it "returns false when an edit session's buffer is in use by more than one session", ->
jasmine.unspy(editor, 'shouldPromptToSave')
@@ -4461,307 +4823,6 @@ describe "TextEditor", ->
waitsForPromise -> editor.checkoutHeadRevision()
describe ".moveToPreviousSubwordBoundary", ->
it "does not move the cursor when there is no previous subword boundary", ->
editor.setText('')
editor.moveToPreviousSubwordBoundary()
expect(editor.getCursorBufferPosition()).toEqual([0, 0])
it "stops at word and underscore boundaries", ->
editor.setText("sub_word \n")
editor.setCursorBufferPosition([0, 9])
editor.moveToPreviousSubwordBoundary()
expect(editor.getCursorBufferPosition()).toEqual([0, 8])
editor.moveToPreviousSubwordBoundary()
expect(editor.getCursorBufferPosition()).toEqual([0, 4])
editor.moveToPreviousSubwordBoundary()
expect(editor.getCursorBufferPosition()).toEqual([0, 0])
editor.setText(" word\n")
editor.setCursorBufferPosition([0, 3])
editor.moveToPreviousSubwordBoundary()
expect(editor.getCursorBufferPosition()).toEqual([0, 1])
it "stops at camelCase boundaries", ->
editor.setText(" getPreviousWord\n")
editor.setCursorBufferPosition([0, 16])
editor.moveToPreviousSubwordBoundary()
expect(editor.getCursorBufferPosition()).toEqual([0, 12])
editor.moveToPreviousSubwordBoundary()
expect(editor.getCursorBufferPosition()).toEqual([0, 4])
editor.moveToPreviousSubwordBoundary()
expect(editor.getCursorBufferPosition()).toEqual([0, 1])
it "skips consecutive non-word characters", ->
editor.setText("e, => \n")
editor.setCursorBufferPosition([0, 6])
editor.moveToPreviousSubwordBoundary()
expect(editor.getCursorBufferPosition()).toEqual([0, 3])
editor.moveToPreviousSubwordBoundary()
expect(editor.getCursorBufferPosition()).toEqual([0, 1])
it "skips consecutive uppercase characters", ->
editor.setText(" AAADF \n")
editor.setCursorBufferPosition([0, 7])
editor.moveToPreviousSubwordBoundary()
expect(editor.getCursorBufferPosition()).toEqual([0, 6])
editor.moveToPreviousSubwordBoundary()
expect(editor.getCursorBufferPosition()).toEqual([0, 1])
editor.setText("ALPhA\n")
editor.setCursorBufferPosition([0, 4])
editor.moveToPreviousSubwordBoundary()
expect(editor.getCursorBufferPosition()).toEqual([0, 2])
it "skips consecutive numbers", ->
editor.setText(" 88 \n")
editor.setCursorBufferPosition([0, 4])
editor.moveToPreviousSubwordBoundary()
expect(editor.getCursorBufferPosition()).toEqual([0, 3])
editor.moveToPreviousSubwordBoundary()
expect(editor.getCursorBufferPosition()).toEqual([0, 1])
it "works with multiple cursors", ->
editor.setText("curOp\ncursorOptions\n")
editor.setCursorBufferPosition([0, 8])
editor.addCursorAtBufferPosition([1, 13])
[cursor1, cursor2] = editor.getCursors()
editor.moveToPreviousSubwordBoundary()
expect(cursor1.getBufferPosition()).toEqual([0, 3])
expect(cursor2.getBufferPosition()).toEqual([1, 6])
it "works with non-English characters", ->
editor.setText("supåTøåst \n")
editor.setCursorBufferPosition([0, 9])
editor.moveToPreviousSubwordBoundary()
expect(editor.getCursorBufferPosition()).toEqual([0, 4])
editor.setText("supaÖast \n")
editor.setCursorBufferPosition([0, 8])
editor.moveToPreviousSubwordBoundary()
expect(editor.getCursorBufferPosition()).toEqual([0, 4])
describe ".moveToNextSubwordBoundary", ->
it "does not move the cursor when there is no next subword boundary", ->
editor.setText('')
editor.moveToNextSubwordBoundary()
expect(editor.getCursorBufferPosition()).toEqual([0, 0])
it "stops at word and underscore boundaries", ->
editor.setText(" sub_word \n")
editor.setCursorBufferPosition([0, 0])
editor.moveToNextSubwordBoundary()
expect(editor.getCursorBufferPosition()).toEqual([0, 1])
editor.moveToNextSubwordBoundary()
expect(editor.getCursorBufferPosition()).toEqual([0, 4])
editor.moveToNextSubwordBoundary()
expect(editor.getCursorBufferPosition()).toEqual([0, 9])
editor.setText("word \n")
editor.setCursorBufferPosition([0, 0])
editor.moveToNextSubwordBoundary()
expect(editor.getCursorBufferPosition()).toEqual([0, 4])
it "stops at camelCase boundaries", ->
editor.setText("getPreviousWord \n")
editor.setCursorBufferPosition([0, 0])
editor.moveToNextSubwordBoundary()
expect(editor.getCursorBufferPosition()).toEqual([0, 3])
editor.moveToNextSubwordBoundary()
expect(editor.getCursorBufferPosition()).toEqual([0, 11])
editor.moveToNextSubwordBoundary()
expect(editor.getCursorBufferPosition()).toEqual([0, 15])
it "skips consecutive non-word characters", ->
editor.setText(", => \n")
editor.setCursorBufferPosition([0, 0])
editor.moveToNextSubwordBoundary()
expect(editor.getCursorBufferPosition()).toEqual([0, 1])
editor.moveToNextSubwordBoundary()
expect(editor.getCursorBufferPosition()).toEqual([0, 4])
it "skips consecutive uppercase characters", ->
editor.setText(" AAADF \n")
editor.setCursorBufferPosition([0, 0])
editor.moveToNextSubwordBoundary()
expect(editor.getCursorBufferPosition()).toEqual([0, 1])
editor.moveToNextSubwordBoundary()
expect(editor.getCursorBufferPosition()).toEqual([0, 6])
editor.setText("ALPhA\n")
editor.setCursorBufferPosition([0, 0])
editor.moveToNextSubwordBoundary()
expect(editor.getCursorBufferPosition()).toEqual([0, 2])
it "skips consecutive numbers", ->
editor.setText(" 88 \n")
editor.setCursorBufferPosition([0, 0])
editor.moveToNextSubwordBoundary()
expect(editor.getCursorBufferPosition()).toEqual([0, 1])
editor.moveToNextSubwordBoundary()
expect(editor.getCursorBufferPosition()).toEqual([0, 3])
it "works with multiple cursors", ->
editor.setText("curOp\ncursorOptions\n")
editor.setCursorBufferPosition([0, 0])
editor.addCursorAtBufferPosition([1, 0])
[cursor1, cursor2] = editor.getCursors()
editor.moveToNextSubwordBoundary()
expect(cursor1.getBufferPosition()).toEqual([0, 3])
expect(cursor2.getBufferPosition()).toEqual([1, 6])
it "works with non-English characters", ->
editor.setText("supåTøåst \n")
editor.setCursorBufferPosition([0, 0])
editor.moveToNextSubwordBoundary()
expect(editor.getCursorBufferPosition()).toEqual([0, 4])
editor.setText("supaÖast \n")
editor.setCursorBufferPosition([0, 0])
editor.moveToNextSubwordBoundary()
expect(editor.getCursorBufferPosition()).toEqual([0, 4])
describe ".selectToPreviousSubwordBoundary", ->
it "selects subwords", ->
editor.setText("")
editor.insertText("_word\n")
editor.insertText(" getPreviousWord\n")
editor.insertText("e, => \n")
editor.insertText(" 88 \n")
editor.setCursorBufferPosition([0, 5])
editor.addCursorAtBufferPosition([1, 7])
editor.addCursorAtBufferPosition([2, 5])
editor.addCursorAtBufferPosition([3, 3])
[selection1, selection2, selection3, selection4] = editor.getSelections()
editor.selectToPreviousSubwordBoundary()
expect(selection1.getBufferRange()).toEqual([[0, 1], [0, 5]])
expect(selection1.isReversed()).toBeTruthy()
expect(selection2.getBufferRange()).toEqual([[1, 4], [1, 7]])
expect(selection2.isReversed()).toBeTruthy()
expect(selection3.getBufferRange()).toEqual([[2, 3], [2, 5]])
expect(selection3.isReversed()).toBeTruthy()
expect(selection4.getBufferRange()).toEqual([[3, 1], [3, 3]])
expect(selection4.isReversed()).toBeTruthy()
describe ".selectToNextSubwordBoundary", ->
it "selects subwords", ->
editor.setText("")
editor.insertText("word_\n")
editor.insertText("getPreviousWord\n")
editor.insertText("e, => \n")
editor.insertText(" 88 \n")
editor.setCursorBufferPosition([0, 1])
editor.addCursorAtBufferPosition([1, 7])
editor.addCursorAtBufferPosition([2, 2])
editor.addCursorAtBufferPosition([3, 1])
[selection1, selection2, selection3, selection4] = editor.getSelections()
editor.selectToNextSubwordBoundary()
expect(selection1.getBufferRange()).toEqual([[0, 1], [0, 4]])
expect(selection1.isReversed()).toBeFalsy()
expect(selection2.getBufferRange()).toEqual([[1, 7], [1, 11]])
expect(selection2.isReversed()).toBeFalsy()
expect(selection3.getBufferRange()).toEqual([[2, 2], [2, 5]])
expect(selection3.isReversed()).toBeFalsy()
expect(selection4.getBufferRange()).toEqual([[3, 1], [3, 3]])
expect(selection4.isReversed()).toBeFalsy()
describe ".deleteToBeginningOfSubword", ->
it "deletes subwords", ->
editor.setText("")
editor.insertText("_word\n")
editor.insertText(" getPreviousWord\n")
editor.insertText("e, => \n")
editor.insertText(" 88 \n")
editor.setCursorBufferPosition([0, 5])
editor.addCursorAtBufferPosition([1, 7])
editor.addCursorAtBufferPosition([2, 5])
editor.addCursorAtBufferPosition([3, 3])
[cursor1, cursor2, cursor3, cursor4] = editor.getCursors()
editor.deleteToBeginningOfSubword()
expect(buffer.lineForRow(0)).toBe('_')
expect(buffer.lineForRow(1)).toBe(' getviousWord')
expect(buffer.lineForRow(2)).toBe('e, ')
expect(buffer.lineForRow(3)).toBe(' ')
expect(cursor1.getBufferPosition()).toEqual([0, 1])
expect(cursor2.getBufferPosition()).toEqual([1, 4])
expect(cursor3.getBufferPosition()).toEqual([2, 3])
expect(cursor4.getBufferPosition()).toEqual([3, 1])
editor.deleteToBeginningOfSubword()
expect(buffer.lineForRow(0)).toBe('')
expect(buffer.lineForRow(1)).toBe(' viousWord')
expect(buffer.lineForRow(2)).toBe('e ')
expect(buffer.lineForRow(3)).toBe(' ')
expect(cursor1.getBufferPosition()).toEqual([0, 0])
expect(cursor2.getBufferPosition()).toEqual([1, 1])
expect(cursor3.getBufferPosition()).toEqual([2, 1])
expect(cursor4.getBufferPosition()).toEqual([3, 0])
editor.deleteToBeginningOfSubword()
expect(buffer.lineForRow(0)).toBe('')
expect(buffer.lineForRow(1)).toBe('viousWord')
expect(buffer.lineForRow(2)).toBe(' ')
expect(buffer.lineForRow(3)).toBe('')
expect(cursor1.getBufferPosition()).toEqual([0, 0])
expect(cursor2.getBufferPosition()).toEqual([1, 0])
expect(cursor3.getBufferPosition()).toEqual([2, 0])
expect(cursor4.getBufferPosition()).toEqual([2, 1])
describe ".deleteToEndOfSubword", ->
it "deletes subwords", ->
editor.setText("")
editor.insertText("word_\n")
editor.insertText("getPreviousWord \n")
editor.insertText("e, => \n")
editor.insertText(" 88 \n")
editor.setCursorBufferPosition([0, 0])
editor.addCursorAtBufferPosition([1, 0])
editor.addCursorAtBufferPosition([2, 2])
editor.addCursorAtBufferPosition([3, 0])
[cursor1, cursor2, cursor3, cursor4] = editor.getCursors()
editor.deleteToEndOfSubword()
expect(buffer.lineForRow(0)).toBe('_')
expect(buffer.lineForRow(1)).toBe('PreviousWord ')
expect(buffer.lineForRow(2)).toBe('e, ')
expect(buffer.lineForRow(3)).toBe('88 ')
expect(cursor1.getBufferPosition()).toEqual([0, 0])
expect(cursor2.getBufferPosition()).toEqual([1, 0])
expect(cursor3.getBufferPosition()).toEqual([2, 2])
expect(cursor4.getBufferPosition()).toEqual([3, 0])
editor.deleteToEndOfSubword()
expect(buffer.lineForRow(0)).toBe('')
expect(buffer.lineForRow(1)).toBe('Word ')
expect(buffer.lineForRow(2)).toBe('e,')
expect(buffer.lineForRow(3)).toBe(' ')
expect(cursor1.getBufferPosition()).toEqual([0, 0])
expect(cursor2.getBufferPosition()).toEqual([1, 0])
expect(cursor3.getBufferPosition()).toEqual([2, 2])
expect(cursor4.getBufferPosition()).toEqual([3, 0])
describe 'gutters', ->
describe 'the TextEditor constructor', ->
it 'creates a line-number gutter', ->

View File

@@ -1,5 +1,6 @@
crypto = require 'crypto'
path = require 'path'
ipc = require 'ipc'
_ = require 'underscore-plus'
{deprecate} = require 'grim'
@@ -116,7 +117,7 @@ class AtomEnvironment extends Model
# Call .loadOrCreate instead
constructor: (params={}) ->
{@applicationDelegate, @window, @document, configDirPath, @enablePersistence} = params
{@blobStore, @applicationDelegate, @window, @document, configDirPath, @enablePersistence} = params
@state = {version: @constructor.version}
@@ -203,6 +204,15 @@ class AtomEnvironment extends Model
@observeAutoHideMenuBar()
checkPortableHomeWritable = ->
responseChannel = "check-portable-home-writable-response"
ipc.on responseChannel, (response) ->
ipc.removeAllListeners(responseChannel)
atom.notifications.addWarning("#{response.message.replace(/([\\\.+\\-_#!])/g, '\\$1')}") if not response.writable
ipc.send('check-portable-home-writable', responseChannel)
checkPortableHomeWritable()
setConfigSchema: ->
@config.setSchema null, {type: 'object', properties: _.clone(require('./config-schema'))}
@@ -306,6 +316,7 @@ class AtomEnvironment extends Model
@project = null
@commands.clear()
@stylesElement.remove()
@config.unobserveUserConfig()
@uninstallWindowEventHandler()
@@ -636,6 +647,7 @@ class AtomEnvironment extends Model
@state.packageStates = @packages.packageStates
@state.fullScreen = @isFullScreen()
@saveStateSync()
@saveBlobStoreSync()
openInitialEmptyEditorIfNecessary: ->
return unless @config.get('core.openEmptyEditorOnStart')
@@ -759,6 +771,11 @@ class AtomEnvironment extends Model
showSaveDialogSync: (options={}) ->
@applicationDelegate.showSaveDialog(options)
saveBlobStoreSync: ->
return unless @enablePersistence
@blobStore.save()
saveStateSync: ->
return unless @enablePersistence

View File

@@ -0,0 +1,35 @@
fs = require 'fs-plus'
path = require 'path'
ipc = require 'ipc'
module.exports =
class AtomPortable
@getPortableAtomHomePath: ->
execDirectoryPath = path.dirname(process.execPath)
path.join(execDirectoryPath, '..', '.atom')
@setPortable: (existingAtomHome) ->
fs.copySync(existingAtomHome, @getPortableAtomHomePath())
@isPortableInstall: (platform, environmentAtomHome, defaultHome) ->
return false unless platform in ['linux', 'win32']
return false if environmentAtomHome
return false if not fs.existsSync(@getPortableAtomHomePath())
# currently checking only that the directory exists and is writable,
# probably want to do some integrity checks on contents in future
@isPortableAtomHomePathWritable(defaultHome)
@isPortableAtomHomePathWritable: (defaultHome) ->
writable = false
message = ""
try
writePermissionTestFile = path.join(@getPortableAtomHomePath(), "write.test")
fs.writeFileSync(writePermissionTestFile, "test") if not fs.existsSync(writePermissionTestFile)
fs.removeSync(writePermissionTestFile)
writable = true
catch error
message = "Failed to use portable Atom home directory (#{@getPortableAtomHomePath()}). Using the default instead (#{defaultHome}). #{error.message}"
ipc.on 'check-portable-home-writable', (event) ->
event.sender.send 'check-portable-home-writable-response', {writable, message}
writable

View File

@@ -49,6 +49,7 @@ class AtomWindow
loadSettings.resourcePath = @resourcePath
loadSettings.devMode ?= false
loadSettings.safeMode ?= false
loadSettings.atomHome = process.env.ATOM_HOME
# Only send to the first non-spec window created
if @constructor.includeShellLoadTime and not @isSpec

View File

@@ -12,15 +12,14 @@ yargs = require 'yargs'
console.log = require 'nslog'
start = ->
setupAtomHome()
args = parseCommandLine()
setupAtomHome(args)
setupCompileCache()
return if handleStartupEventWithSquirrel()
# NB: This prevents Win10 from showing dupe items in the taskbar
app.setAppUserModelId('com.squirrel.atom.atom')
args = parseCommandLine()
addPathToOpen = (event, pathToOpen) ->
event.preventDefault()
args.pathsToOpen.push(pathToOpen)
@@ -57,11 +56,25 @@ handleStartupEventWithSquirrel = ->
setupCrashReporter = ->
crashReporter.start(productName: 'Atom', companyName: 'GitHub')
setupAtomHome = ->
setupAtomHome = ({setPortable}) ->
return if process.env.ATOM_HOME
atomHome = path.join(app.getHomeDir(), '.atom')
AtomPortable = require './atom-portable'
if setPortable and not AtomPortable.isPortableInstall(process.platform, process.env.ATOM_HOME, atomHome)
try
AtomPortable.setPortable(atomHome)
catch error
console.log("Failed copying portable directory '#{atomHome}' to '#{AtomPortable.getPortableAtomHomePath()}'")
console.log("#{error.message} #{error.stack}")
if AtomPortable.isPortableInstall(process.platform, process.env.ATOM_HOME, atomHome)
atomHome = AtomPortable.getPortableAtomHomePath()
try
atomHome = fs.realpathSync(atomHome)
process.env.ATOM_HOME = atomHome
setupCompileCache = ->
@@ -100,6 +113,7 @@ parseCommandLine = ->
options.boolean('profile-startup').describe('profile-startup', 'Create a profile of the startup execution time.')
options.alias('r', 'resource-path').string('r').describe('r', 'Set the path to the Atom source directory and enable dev-mode.')
options.boolean('safe').describe('safe', 'Do not load packages from ~/.atom/packages or ~/.atom/dev/packages.')
options.boolean('portable').describe('portable', 'Set portable mode. Copies the ~/.atom folder to be a sibling of the installed Atom location if a .atom folder is not already there.')
options.alias('t', 'test').boolean('t').describe('t', 'Run the specified specs and exit with error code on failures.')
options.string('timeout').describe('timeout', 'When in test mode, waits until the specified time (in minutes) and kills the process (exit code: 130).')
options.alias('v', 'version').boolean('v').describe('v', 'Print the version.')
@@ -129,6 +143,7 @@ parseCommandLine = ->
profileStartup = args['profile-startup']
urlsToOpen = []
devResourcePath = process.env.ATOM_DEV_RESOURCE_PATH ? path.join(app.getHomeDir(), 'github', 'atom')
setPortable = args.portable
if args['resource-path']
devMode = true
@@ -149,6 +164,6 @@ parseCommandLine = ->
{resourcePath, devResourcePath, pathsToOpen, urlsToOpen, executedFrom, test,
version, pidToKillWhenClosed, devMode, safeMode, newWindow,
logFile, socketPath, profileStartup, timeout}
logFile, socketPath, profileStartup, timeout, setPortable}
start()

View File

@@ -0,0 +1,111 @@
'use strict'
const fs = require('fs-plus')
const path = require('path')
module.exports =
class FileSystemBlobStore {
static load (directory) {
let instance = new FileSystemBlobStore(directory)
instance.load()
return instance
}
constructor (directory) {
this.inMemoryBlobs = new Map()
this.blobFilename = path.join(directory, 'BLOB')
this.blobMapFilename = path.join(directory, 'MAP')
this.lockFilename = path.join(directory, 'LOCK')
this.storedBlob = new Buffer(0)
this.storedBlobMap = {}
}
load () {
if (!fs.existsSync(this.blobMapFilename)) {
return
}
if (!fs.existsSync(this.blobFilename)) {
return
}
this.storedBlob = fs.readFileSync(this.blobFilename)
this.storedBlobMap = JSON.parse(fs.readFileSync(this.blobMapFilename))
}
save () {
let dump = this.getDump()
let blobToStore = Buffer.concat(dump[0])
let mapToStore = JSON.stringify(dump[1])
let acquiredLock = false
try {
fs.writeFileSync(this.lockFilename, 'LOCK', {flag: 'wx'})
acquiredLock = true
fs.writeFileSync(this.blobFilename, blobToStore)
fs.writeFileSync(this.blobMapFilename, mapToStore)
} catch (error) {
// Swallow the exception silently only if we fail to acquire the lock.
if (error.code !== 'EEXIST') {
throw error
}
} finally {
if (acquiredLock) {
fs.unlinkSync(this.lockFilename)
}
}
}
has (key) {
return this.inMemoryBlobs.hasOwnProperty(key) || this.storedBlobMap.hasOwnProperty(key)
}
get (key) {
return this.getFromMemory(key) || this.getFromStorage(key)
}
set (key, buffer) {
return this.inMemoryBlobs.set(key, buffer)
}
delete (key) {
this.inMemoryBlobs.delete(key)
delete this.storedBlobMap[key]
}
getFromMemory (key) {
return this.inMemoryBlobs.get(key)
}
getFromStorage (key) {
if (!this.storedBlobMap[key]) {
return
}
return this.storedBlob.slice.apply(this.storedBlob, this.storedBlobMap[key])
}
getDump () {
let buffers = []
let blobMap = {}
let currentBufferStart = 0
function dump (key, getBufferByKey) {
let buffer = getBufferByKey(key)
buffers.push(buffer)
blobMap[key] = [currentBufferStart, currentBufferStart + buffer.length]
currentBufferStart += buffer.length
}
for (let key of this.inMemoryBlobs.keys()) {
dump(key, this.getFromMemory.bind(this))
}
for (let key of Object.keys(this.storedBlobMap)) {
if (!blobMap[key]) {
dump(key, this.getFromStorage.bind(this))
}
}
return [buffers, blobMap]
}
}

View File

@@ -1,34 +1,34 @@
# Like sands through the hourglass, so are the days of our lives.
module.exports = ({blobStore}) ->
path = require 'path'
require './window'
{getWindowLoadSettings} = require './window-load-settings-helpers'
path = require 'path'
require './window'
{getWindowLoadSettings} = require './window-load-settings-helpers'
{resourcePath, isSpec, devMode} = getWindowLoadSettings()
{resourcePath, isSpec, devMode} = getWindowLoadSettings()
# Add application-specific exports to module search path.
exportsPath = path.join(resourcePath, 'exports')
require('module').globalPaths.push(exportsPath)
process.env.NODE_PATH = exportsPath
# Add application-specific exports to module search path.
exportsPath = path.join(resourcePath, 'exports')
require('module').globalPaths.push(exportsPath)
process.env.NODE_PATH = exportsPath
# Make React faster
process.env.NODE_ENV ?= 'production' unless devMode
# Make React faster
process.env.NODE_ENV ?= 'production' unless devMode
AtomEnvironment = require './atom-environment'
ApplicationDelegate = require './application-delegate'
window.atom = new AtomEnvironment({
window, document, blobStore,
applicationDelegate: new ApplicationDelegate,
configDirPath: process.env.ATOM_HOME
enablePersistence: true
})
AtomEnvironment = require './atom-environment'
ApplicationDelegate = require './application-delegate'
window.atom = new AtomEnvironment({
window, document,
applicationDelegate: new ApplicationDelegate,
configDirPath: process.env.ATOM_HOME
enablePersistence: true
})
atom.displayWindow()
atom.loadStateSync()
atom.startEditorWindow()
atom.displayWindow()
atom.loadStateSync()
atom.startEditorWindow()
# Workaround for focus getting cleared upon window creation
windowFocused = ->
window.removeEventListener('focus', windowFocused)
setTimeout (-> document.querySelector('atom-workspace').focus()), 0
window.addEventListener('focus', windowFocused)
# Workaround for focus getting cleared upon window creation
windowFocused = ->
window.removeEventListener('focus', windowFocused)
setTimeout (-> document.querySelector('atom-workspace').focus()), 0
window.addEventListener('focus', windowFocused)

View File

@@ -1,69 +1,78 @@
# Start the crash reporter before anything else.
require('crash-reporter').start(productName: 'Atom', companyName: 'GitHub')
remote = require 'remote'
cloneObject = (object) ->
clone = {}
clone[key] = value for key, value of object
clone
exitWithStatusCode = (status) ->
remote.require('app').emit('will-quit')
remote.process.exit(status)
module.exports = ({blobStore}) ->
# Start the crash reporter before anything else.
require('crash-reporter').start(productName: 'Atom', companyName: 'GitHub')
remote = require 'remote'
try
path = require 'path'
ipc = require 'ipc'
{getWindowLoadSettings} = require './window-load-settings-helpers'
AtomEnvironment = require '../src/atom-environment'
ApplicationDelegate = require '../src/application-delegate'
exitWithStatusCode = (status) ->
remote.require('app').emit('will-quit')
remote.process.exit(status)
{testRunnerPath, legacyTestRunnerPath, headless, logFile, testPaths} = getWindowLoadSettings()
try
path = require 'path'
ipc = require 'ipc'
{getWindowLoadSettings} = require './window-load-settings-helpers'
AtomEnvironment = require '../src/atom-environment'
ApplicationDelegate = require '../src/application-delegate'
if headless
# Override logging in headless mode so it goes to the console, regardless
# of the --enable-logging flag to Electron.
console.log = (args...) ->
ipc.send 'write-to-stdout', args.join(' ') + '\n'
console.warn = (args...) ->
ipc.send 'write-to-stderr', args.join(' ') + '\n'
console.error = (args...) ->
ipc.send 'write-to-stderr', args.join(' ') + '\n'
else
# Show window synchronously so a focusout doesn't fire on input elements
# that are focused in the very first spec run.
remote.getCurrentWindow().show()
{testRunnerPath, legacyTestRunnerPath, headless, logFile, testPaths} = getWindowLoadSettings()
handleKeydown = (event) ->
# Reload: cmd-r / ctrl-r
if (event.metaKey or event.ctrlKey) and event.keyCode is 82
ipc.send('call-window-method', 'restart')
if headless
# Override logging in headless mode so it goes to the console, regardless
# of the --enable-logging flag to Electron.
console.log = (args...) ->
ipc.send 'write-to-stdout', args.join(' ') + '\n'
console.warn = (args...) ->
ipc.send 'write-to-stderr', args.join(' ') + '\n'
console.error = (args...) ->
ipc.send 'write-to-stderr', args.join(' ') + '\n'
else
# Show window synchronously so a focusout doesn't fire on input elements
# that are focused in the very first spec run.
remote.getCurrentWindow().show()
# Toggle Dev Tools: cmd-alt-i / ctrl-alt-i
if (event.metaKey or event.ctrlKey) and event.altKey and event.keyCode is 73
ipc.send('call-window-method', 'toggleDevTools')
handleKeydown = (event) ->
# Reload: cmd-r / ctrl-r
if (event.metaKey or event.ctrlKey) and event.keyCode is 82
ipc.send('call-window-method', 'restart')
# Reload: cmd-w / ctrl-w
if (event.metaKey or event.ctrlKey) and event.keyCode is 87
ipc.send('call-window-method', 'close')
# Toggle Dev Tools: cmd-alt-i / ctrl-alt-i
if (event.metaKey or event.ctrlKey) and event.altKey and event.keyCode is 73
ipc.send('call-window-method', 'toggleDevTools')
window.addEventListener('keydown', handleKeydown, true)
# Reload: cmd-w / ctrl-w
if (event.metaKey or event.ctrlKey) and event.keyCode is 87
ipc.send('call-window-method', 'close')
# Add 'exports' to module search path.
exportsPath = path.join(getWindowLoadSettings().resourcePath, 'exports')
require('module').globalPaths.push(exportsPath)
process.env.NODE_PATH = exportsPath # Set NODE_PATH env variable since tasks may need it.
window.addEventListener('keydown', handleKeydown, true)
document.title = "Spec Suite"
# Add 'exports' to module search path.
exportsPath = path.join(getWindowLoadSettings().resourcePath, 'exports')
require('module').globalPaths.push(exportsPath)
process.env.NODE_PATH = exportsPath # Set NODE_PATH env variable since tasks may need it.
testRunner = require(testRunnerPath)
legacyTestRunner = require(legacyTestRunnerPath)
buildAtomEnvironment = (params) -> new AtomEnvironment(params)
buildDefaultApplicationDelegate = (params) -> new ApplicationDelegate()
document.title = "Spec Suite"
promise = testRunner({
logFile, headless, testPaths, buildAtomEnvironment, buildDefaultApplicationDelegate, legacyTestRunner
})
testRunner = require(testRunnerPath)
legacyTestRunner = require(legacyTestRunnerPath)
buildDefaultApplicationDelegate = -> new ApplicationDelegate()
buildAtomEnvironment = (params) ->
params = cloneObject(params)
params.blobStore = blobStore unless params.hasOwnProperty("blobStore")
new AtomEnvironment(params)
promise.then(exitWithStatusCode) if getWindowLoadSettings().headless
catch error
if getWindowLoadSettings().headless
console.error(error.stack ? error)
exitWithStatusCode(1)
else
throw error
promise = testRunner({
logFile, headless, testPaths, buildAtomEnvironment, buildDefaultApplicationDelegate, legacyTestRunner
})
promise.then(exitWithStatusCode) if getWindowLoadSettings().headless
catch error
if getWindowLoadSettings().headless
console.error(error.stack ? error)
exitWithStatusCode(1)
else
throw error

View File

@@ -159,9 +159,12 @@ class LinesYardstick
0
leftPixelPositionForCharInTextNode: (lineNode, textNode, charIndex) ->
@rangeForMeasurement.setStart(textNode, 0)
@rangeForMeasurement.setEnd(textNode, charIndex)
width = @rangeForMeasurement.getBoundingClientRect().width
if charIndex is 0
width = 0
else
@rangeForMeasurement.setStart(textNode, 0)
@rangeForMeasurement.setEnd(textNode, charIndex)
width = @rangeForMeasurement.getBoundingClientRect().width
@rangeForMeasurement.setStart(textNode, 0)
@rangeForMeasurement.setEnd(textNode, textNode.textContent.length)

101
src/native-compile-cache.js Normal file
View File

@@ -0,0 +1,101 @@
'use strict'
const Module = require('module')
const path = require('path')
const cachedVm = require('cached-run-in-this-context')
class NativeCompileCache {
constructor () {
this.cacheStore = null
this.previousModuleCompile = null
}
setCacheStore (store) {
this.cacheStore = store
}
install () {
this.savePreviousModuleCompile()
this.overrideModuleCompile()
}
uninstall () {
this.restorePreviousModuleCompile()
}
savePreviousModuleCompile () {
this.previousModuleCompile = Module.prototype._compile
}
overrideModuleCompile () {
let cacheStore = this.cacheStore
let resolvedArgv = null
// Here we override Node's module.js
// (https://github.com/atom/node/blob/atom/lib/module.js#L378), changing
// only the bits that affect compilation in order to use the cached one.
Module.prototype._compile = function (content, filename) {
let self = this
// remove shebang
content = content.replace(/^\#\!.*/, '')
function require (path) {
return self.require(path)
}
require.resolve = function (request) {
return Module._resolveFilename(request, self)
}
require.main = process.mainModule
// Enable support to add extra extension types
require.extensions = Module._extensions
require.cache = Module._cache
let dirname = path.dirname(filename)
// create wrapper function
let wrapper = Module.wrap(content)
let compiledWrapper = null
if (cacheStore.has(filename)) {
let buffer = cacheStore.get(filename)
let compilationResult = cachedVm.runInThisContextCached(wrapper, filename, buffer)
compiledWrapper = compilationResult.result
if (compilationResult.wasRejected) {
cacheStore.delete(filename)
}
} else {
let compilationResult = cachedVm.runInThisContext(wrapper, filename)
if (compilationResult.cacheBuffer) {
cacheStore.set(filename, compilationResult.cacheBuffer)
}
compiledWrapper = compilationResult.result
}
if (global.v8debug) {
if (!resolvedArgv) {
// we enter the repl if we're not given a filename argument.
if (process.argv[1]) {
resolvedArgv = Module._resolveFilename(process.argv[1], null)
} else {
resolvedArgv = 'repl'
}
}
// Set breakpoint on module start
if (filename === resolvedArgv) {
// Installing this dummy debug event listener tells V8 to start
// the debugger. Without it, the setBreakPoint() fails with an
// 'illegal access' error.
global.v8debug.Debug.setListener(function () {})
global.v8debug.Debug.setBreakPoint(compiledWrapper, 0, 0)
}
}
let args = [self.exports, require, self, filename, dirname, process, global]
return compiledWrapper.apply(self.exports, args)
}
}
restorePreviousModuleCompile () {
Module.prototype._compile = this.previousModuleCompile
}
}
module.exports = new NativeCompileCache()

View File

@@ -467,7 +467,7 @@ class PackageManager
detail = "#{error.message} in #{metadataPath}"
stack = "#{error.stack}\n at #{metadataPath}:1:1"
message = "Failed to load the #{path.basename(packagePath)} package"
@notificationManager.addError(message, {stack, detail, dismissable: true})
@notificationManager.addError(message, {stack, detail, packageName: path.basename(packagePath), dismissable: true})
uninstallDirectory: (directory) ->
symlinkPromise = new Promise (resolve) ->

View File

@@ -293,7 +293,7 @@ class Package
if error?
detail = "#{error.message} in #{grammarPath}"
stack = "#{error.stack}\n at #{grammarPath}:1:1"
@notificationManager.addFatalError("Failed to load a #{@name} package grammar", {stack, detail, dismissable: true})
@notificationManager.addFatalError("Failed to load a #{@name} package grammar", {stack, detail, packageName: @name, dismissable: true})
else
grammar.packageName = @name
grammar.bundledPackage = @bundledPackage
@@ -317,7 +317,7 @@ class Package
if error?
detail = "#{error.message} in #{settingsPath}"
stack = "#{error.stack}\n at #{settingsPath}:1:1"
@notificationManager.addFatalError("Failed to load the #{@name} package settings", {stack, detail, dismissable: true})
@notificationManager.addFatalError("Failed to load the #{@name} package settings", {stack, detail, packageName: @name, dismissable: true})
else
@settings.push(settings)
settings.activate() if @settingsActivated
@@ -634,4 +634,4 @@ class Package
detail = error.message
stack = error.stack ? error
@notificationManager.addFatalError(message, {stack, detail, dismissable: true})
@notificationManager.addFatalError(message, {stack, detail, packageName: @name, dismissable: true})

View File

@@ -573,6 +573,45 @@ class TextEditor extends Model
else
'untitled'
# Essential: Get unique title for display in other parts of the UI
# such as the window title.
#
# If the editor's buffer is unsaved, its title is "untitled"
# If the editor's buffer is saved, its unique title is formatted as one
# of the following,
# * "<filename>" when it is the only editing buffer with this file name.
# * "<unique-dir-prefix>/.../<filename>", where the "..." may be omitted
# if the the direct parent directory is already different.
#
# Returns a {String}
getUniqueTitle: ->
if sessionPath = @getPath()
title = @getTitle()
# find text editors with identical file name.
paths = []
for textEditor in atom.workspace.getTextEditors() when textEditor isnt this
if textEditor.getTitle() is title
paths.push(textEditor.getPath())
if paths.length is 0
return title
fileName = path.basename(sessionPath)
# find the first directory in all these paths that is unique
nLevel = 0
while (_.some(paths, (apath) -> path.basename(apath) is path.basename(sessionPath)))
sessionPath = path.dirname(sessionPath)
paths = _.map(paths, (apath) -> path.dirname(apath))
nLevel += 1
directory = path.basename sessionPath
if nLevel > 1
path.join(directory, "...", fileName)
else
path.join(directory, fileName)
else
'untitled'
# Essential: Get the editor's long title for display in other parts of the UI
# such as the window title.
#
@@ -879,6 +918,7 @@ class TextEditor extends Model
@foldBufferRow(foldedRow)
@setSelectedBufferRange(selection.translate([-insertDelta]), preserveFolds: true, autoscroll: true)
@autoIndentSelectedRows() if @shouldAutoIndent()
# Move lines intersecting the most recent selection down by one row in screen
# coordinates.
@@ -935,6 +975,7 @@ class TextEditor extends Model
@foldBufferRow(foldedRow)
@setSelectedBufferRange(selection.translate([insertDelta]), preserveFolds: true, autoscroll: true)
@autoIndentSelectedRows() if @shouldAutoIndent()
# Duplicate the most recent cursor's current line.
duplicateLines: ->

View File

@@ -1,9 +1,11 @@
(function () {
var fs = require('fs')
var path = require('path')
var FileSystemBlobStore = require('../src/file-system-blob-store')
var NativeCompileCache = require('../src/native-compile-cache')
var loadSettings = null
var loadSettingsError = null
var blobStore = null
window.onload = function () {
try {
@@ -13,8 +15,11 @@
console.error('Unhandled promise rejection %o with error: %o', promise, error)
})
// Ensure ATOM_HOME is always set before anything else is required
setupAtomHome()
blobStore = FileSystemBlobStore.load(
path.join(process.env.ATOM_HOME, 'blob-store/')
)
NativeCompileCache.setCacheStore(blobStore)
NativeCompileCache.install()
// Normalize to make sure drive letter case is consistent on Windows
process.resourcesPath = path.normalize(process.resourcesPath)
@@ -76,28 +81,11 @@
setupVmCompatibility()
setupCsonCache(CompileCache.getCacheDirectory())
require(loadSettings.windowInitializationScript)
var initialize = require(loadSettings.windowInitializationScript)
initialize({blobStore: blobStore})
require('ipc').sendChannel('window-command', 'window:loaded')
}
function setupAtomHome () {
if (!process.env.ATOM_HOME) {
var home
if (process.platform === 'win32') {
home = process.env.USERPROFILE
} else {
home = process.env.HOME
}
var atomHome = path.join(home, '.atom')
try {
atomHome = fs.realpathSync(atomHome)
} catch (error) {
// Ignore since the path might just not exist yet.
}
process.env.ATOM_HOME = atomHome
}
}
function setupCsonCache (cacheDir) {
require('season').setCacheDir(path.join(cacheDir, 'cson'))
}
@@ -181,6 +169,20 @@
}, false)
}
var setupAtomHome = function () {
if (process.env.ATOM_HOME) {
return
}
// Ensure ATOM_HOME is always set before anything else is required
// This is because of a difference in Linux not inherited between browser and render processes
// https://github.com/atom/atom/issues/5412
if (loadSettings && loadSettings.atomHome) {
process.env.ATOM_HOME = loadSettings.atomHome
}
}
parseLoadSettings()
setupAtomHome()
setupWindowBackground()
})()