Merge branch 'master' into jl-bump-mdpv

This commit is contained in:
Jessica Lord
2015-03-26 17:30:02 -07:00
25 changed files with 351 additions and 148 deletions

View File

@@ -2,7 +2,7 @@
# DESCRIPTION: Image to build Atom and create a .rpm file
# Base docker image
FROM fedora:20
FROM fedora:21
# Install dependencies
RUN yum install -y \
@@ -12,11 +12,11 @@ RUN yum install -y \
glibc-devel \
git-core \
libgnome-keyring-devel \
rpmdevtools
rpmdevtools \
nodejs \
npm
# Install node
RUN curl -sL https://rpm.nodesource.com/setup | bash -
RUN yum install -y nodejs
RUN npm install -g npm@1.4.28 --loglevel error
ADD . /atom
WORKDIR /atom

View File

@@ -1,4 +1,4 @@
Copyright (c) 2014 GitHub Inc.
Copyright (c) 2015 GitHub Inc.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the

View File

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

View File

@@ -46,7 +46,7 @@ module.exports = (grunt) ->
strings =
CompanyName: 'GitHub, Inc.'
FileDescription: 'Atom'
LegalCopyright: 'Copyright (C) 2014 GitHub, Inc. All rights reserved'
LegalCopyright: 'Copyright (C) 2015 GitHub, Inc. All rights reserved'
ProductName: 'Atom'
ProductVersion: version

View File

@@ -17,7 +17,7 @@
"url": "http://github.com/atom/atom/raw/master/LICENSE.md"
}
],
"atomShellVersion": "0.21.3",
"atomShellVersion": "0.22.2",
"dependencies": {
"async": "0.2.6",
"atom-keymap": "^4",
@@ -64,8 +64,9 @@
"space-pen": "3.8.2",
"stacktrace-parser": "0.1.1",
"temp": "0.8.1",
"text-buffer": "^5.0.2",
"text-buffer": "^5.1.0",
"theorist": "^1.0.2",
"typescript-simple": "^1.0.0",
"underscore-plus": "^1.6.6"
},
"packageDependencies": {
@@ -110,19 +111,19 @@
"package-generator": "0.38.0",
"release-notes": "0.52.0",
"settings-view": "0.185.0",
"snippets": "0.85.0",
"snippets": "0.86.0",
"spell-check": "0.55.0",
"status-bar": "0.64.0",
"styleguide": "0.44.0",
"symbols-view": "0.92.0",
"symbols-view": "0.93.0",
"tabs": "0.67.0",
"timecop": "0.31.0",
"tree-view": "0.168.0",
"update-package-dependencies": "0.9.0",
"welcome": "0.25.0",
"welcome": "0.26.0",
"whitespace": "0.29.0",
"wrap-guide": "0.31.0",
"language-c": "0.41.0",
"language-c": "0.42.0",
"language-clojure": "0.13.0",
"language-coffee-script": "0.39.0",
"language-csharp": "0.5.0",
@@ -143,12 +144,12 @@
"language-php": "0.21.0",
"language-property-list": "0.8.0",
"language-python": "0.32.0",
"language-ruby": "0.49.0",
"language-ruby": "0.50.0",
"language-ruby-on-rails": "0.21.0",
"language-sass": "0.36.0",
"language-shellscript": "0.13.0",
"language-source": "0.9.0",
"language-sql": "0.14.0",
"language-sql": "0.15.0",
"language-text": "0.6.0",
"language-todo": "0.17.0",
"language-toml": "0.15.0",

View File

@@ -48,7 +48,7 @@ function removeNodeModules() {
readEnvironmentVariables();
removeNodeModules();
cp.safeExec.bind(global, 'npm install npm', {cwd: path.resolve(__dirname, '..', 'build')}, function() {
cp.safeExec.bind(global, 'npm install npm --loglevel error', {cwd: path.resolve(__dirname, '..', 'build')}, function() {
cp.safeExec.bind(global, 'node script/bootstrap', function(error) {
if (error)
process.exit(1);

View File

@@ -57,7 +57,7 @@ function verifyNpm(cb) {
var npmMajorVersion = +versionArray[0] || 0;
var npmMinorVersion = +versionArray[1] || 0;
if (npmMajorVersion === 1 && npmMinorVersion < 4)
cb("npm v1.4+ is required to build Atom.");
cb("npm v1.4+ is required to build Atom. Version " + npmVersion + " was detected.");
else
cb(null, "npm: v" + npmVersion);
});

View File

@@ -3,26 +3,37 @@ CSON = require 'season'
CoffeeCache = require 'coffee-cash'
babel = require '../src/babel'
typescript = require '../src/typescript'
CompileCache = require '../src/compile-cache'
describe "Compile Cache", ->
describe ".addPathToCache(filePath)", ->
it "adds the path to the correct CSON, CoffeeScript, or babel cache", ->
it "adds the path to the correct CSON, CoffeeScript, babel or typescript cache", ->
spyOn(CSON, 'readFileSync').andCallThrough()
spyOn(CoffeeCache, 'addPathToCache').andCallThrough()
spyOn(babel, 'addPathToCache').andCallThrough()
spyOn(typescript, 'addPathToCache').andCallThrough()
CompileCache.addPathToCache(path.join(__dirname, 'fixtures', 'cson.cson'))
expect(CSON.readFileSync.callCount).toBe 1
expect(CoffeeCache.addPathToCache.callCount).toBe 0
expect(babel.addPathToCache.callCount).toBe 0
expect(typescript.addPathToCache.callCount).toBe 0
CompileCache.addPathToCache(path.join(__dirname, 'fixtures', 'coffee.coffee'))
expect(CSON.readFileSync.callCount).toBe 1
expect(CoffeeCache.addPathToCache.callCount).toBe 1
expect(babel.addPathToCache.callCount).toBe 0
expect(typescript.addPathToCache.callCount).toBe 0
CompileCache.addPathToCache(path.join(__dirname, 'fixtures', 'babel', 'babel-double-quotes.js'))
expect(CSON.readFileSync.callCount).toBe 1
expect(CoffeeCache.addPathToCache.callCount).toBe 1
expect(babel.addPathToCache.callCount).toBe 1
expect(typescript.addPathToCache.callCount).toBe 0
CompileCache.addPathToCache(path.join(__dirname, 'fixtures', 'typescript', 'valid.ts'))
expect(CSON.readFileSync.callCount).toBe 1
expect(CoffeeCache.addPathToCache.callCount).toBe 1
expect(babel.addPathToCache.callCount).toBe 1
expect(typescript.addPathToCache.callCount).toBe 1

View File

@@ -15,8 +15,8 @@ describe "DefaultDirectoryProvider", ->
provider = new DefaultDirectoryProvider()
tmp = temp.mkdirSync()
nonNormalizedPath = tmp + path.sep + ".." + path.sep + path.basename(tmp)
expect(tmp.contains("..")).toBe false
expect(nonNormalizedPath.contains("..")).toBe true
expect(tmp.includes("..")).toBe false
expect(nonNormalizedPath.includes("..")).toBe true
directory = provider.directoryForURISync(nonNormalizedPath)
expect(directory.getPath()).toEqual tmp

View File

@@ -48,7 +48,6 @@ describe "DisplayBuffer", ->
expect(displayBuffer.getLineCount()).toBe 100 + originalLineCount
it "reassigns the scrollTop if it exceeds the max possible value after lines are removed", ->
displayBuffer.manageScrollPosition = true
displayBuffer.setHeight(50)
displayBuffer.setLineHeightInPixels(10)
displayBuffer.setScrollTop(80)
@@ -287,7 +286,6 @@ describe "DisplayBuffer", ->
it "sets ::scrollLeft to 0 and keeps it there when soft wrapping is enabled", ->
displayBuffer.setDefaultCharWidth(10)
displayBuffer.setWidth(85)
displayBuffer.manageScrollPosition = true
displayBuffer.setSoftWrapped(false)
displayBuffer.setScrollLeft(Infinity)
@@ -1174,7 +1172,6 @@ describe "DisplayBuffer", ->
describe "::setScrollTop", ->
beforeEach ->
displayBuffer.manageScrollPosition = true
displayBuffer.setLineHeightInPixels(10)
it "disallows negative values", ->
@@ -1196,7 +1193,6 @@ describe "DisplayBuffer", ->
describe "when editor.scrollPastEnd is false", ->
beforeEach ->
atom.config.set("editor.scrollPastEnd", false)
displayBuffer.manageScrollPosition = true
displayBuffer.setLineHeightInPixels(10)
it "does not add the height of the view to the scroll height", ->
@@ -1209,7 +1205,6 @@ describe "DisplayBuffer", ->
describe "when editor.scrollPastEnd is true", ->
beforeEach ->
atom.config.set("editor.scrollPastEnd", true)
displayBuffer.manageScrollPosition = true
displayBuffer.setLineHeightInPixels(10)
it "adds the height of the view to the scroll height", ->
@@ -1221,7 +1216,6 @@ describe "DisplayBuffer", ->
describe "::setScrollLeft", ->
beforeEach ->
displayBuffer.manageScrollPosition = true
displayBuffer.setLineHeightInPixels(10)
displayBuffer.setDefaultCharWidth(10)
@@ -1242,18 +1236,21 @@ describe "DisplayBuffer", ->
describe "::scrollToScreenPosition(position, [options])", ->
beforeEach ->
displayBuffer.manageScrollPosition = true
displayBuffer.setLineHeightInPixels(10)
displayBuffer.setDefaultCharWidth(10)
displayBuffer.setHorizontalScrollbarHeight(0)
displayBuffer.setHeight(50)
displayBuffer.setWidth(50)
displayBuffer.setWidth(150)
it "sets the scroll top and scroll left so the given screen position is in view", ->
displayBuffer.scrollToScreenPosition([8, 20])
expect(displayBuffer.getScrollBottom()).toBe (9 + displayBuffer.getVerticalScrollMargin()) * 10
expect(displayBuffer.getScrollRight()).toBe (20 + displayBuffer.getHorizontalScrollMargin()) * 10
displayBuffer.scrollToScreenPosition([8, 20])
expect(displayBuffer.getScrollBottom()).toBe (9 + displayBuffer.getVerticalScrollMargin()) * 10
expect(displayBuffer.getScrollRight()).toBe (20 + displayBuffer.getHorizontalScrollMargin()) * 10
describe "when the 'center' option is true", ->
it "vertically scrolls to center the given position vertically", ->
displayBuffer.scrollToScreenPosition([8, 20], center: true)
@@ -1320,6 +1317,7 @@ describe "DisplayBuffer", ->
expect(displayBuffer.getVisibleRowRange()).toEqual [0, 0]
it "ends at last buffer row even if there's more space available", ->
displayBuffer.setHeight(150)
displayBuffer.setScrollTop(60)
expect(displayBuffer.getVisibleRowRange()).toEqual [6, 13]
expect(displayBuffer.getVisibleRowRange()).toEqual [0, 13]

1
spec/fixtures/typescript/invalid.ts vendored Normal file
View File

@@ -0,0 +1 @@
var foo = 123 123; // Syntax error

2
spec/fixtures/typescript/valid.ts vendored Normal file
View File

@@ -0,0 +1,2 @@
var inc = v => v + 1
export = inc

View File

@@ -693,7 +693,7 @@ describe "TextEditorComponent", ->
describe "cursor rendering", ->
it "renders the currently visible cursors", ->
cursor1 = editor.getLastCursor()
cursor1.setScreenPosition([0, 5])
cursor1.setScreenPosition([0, 5], autoscroll: false)
wrapperNode.style.height = 4.5 * lineHeightInPixels + 'px'
wrapperNode.style.width = 20 * lineHeightInPixels + 'px'
@@ -706,8 +706,8 @@ describe "TextEditorComponent", ->
expect(cursorNodes[0].offsetWidth).toBe charWidth
expect(cursorNodes[0].style['-webkit-transform']).toBe "translate(#{5 * charWidth}px, #{0 * lineHeightInPixels}px)"
cursor2 = editor.addCursorAtScreenPosition([8, 11])
cursor3 = editor.addCursorAtScreenPosition([4, 10])
cursor2 = editor.addCursorAtScreenPosition([8, 11], autoscroll: false)
cursor3 = editor.addCursorAtScreenPosition([4, 10], autoscroll: false)
nextAnimationFrame()
cursorNodes = componentNode.querySelectorAll('.cursor')
@@ -1524,7 +1524,7 @@ describe "TextEditorComponent", ->
expect(inputNode.offsetLeft).toBe 0
# In bounds, not focused
editor.setCursorBufferPosition([5, 4])
editor.setCursorBufferPosition([5, 4], autoscroll: false)
nextAnimationFrame()
expect(inputNode.offsetTop).toBe 0
expect(inputNode.offsetLeft).toBe 0
@@ -1542,7 +1542,7 @@ describe "TextEditorComponent", ->
expect(inputNode.offsetLeft).toBe 0
# Out of bounds, not focused
editor.setCursorBufferPosition([1, 2])
editor.setCursorBufferPosition([1, 2], autoscroll: false)
nextAnimationFrame()
expect(inputNode.offsetTop).toBe 0
expect(inputNode.offsetLeft).toBe 0

View File

@@ -351,11 +351,11 @@ describe "TextEditorPresenter", ->
expectValues presenter.getState().hiddenInput, {top: 0, left: 0}
expectStateUpdate presenter, -> editor.setCursorBufferPosition([11, 43])
expectValues presenter.getState().hiddenInput, {top: 50 - 10, left: 300 - 10}
expectValues presenter.getState().hiddenInput, {top: 11 * 10 - editor.getScrollTop(), left: 43 * 10 - editor.getScrollLeft()}
newCursor = null
expectStateUpdate presenter, -> newCursor = editor.addCursorAtBufferPosition([6, 10])
expectValues presenter.getState().hiddenInput, {top: (6 * 10) - 40, left: (10 * 10) - 70}
expectValues presenter.getState().hiddenInput, {top: (6 * 10) - editor.getScrollTop(), left: (10 * 10) - editor.getScrollLeft()}
expectStateUpdate presenter, -> newCursor.destroy()
expectValues presenter.getState().hiddenInput, {top: 50 - 10, left: 300 - 10}
@@ -1417,33 +1417,33 @@ describe "TextEditorPresenter", ->
expect(stateForSelection(presenter, 1)).toBeUndefined()
# moving into view
expectStateUpdate presenter, -> editor.getSelections()[1].setBufferRange([[2, 4], [2, 6]])
expectStateUpdate presenter, -> editor.getSelections()[1].setBufferRange([[2, 4], [2, 6]], autoscroll: false)
expectValues stateForSelection(presenter, 1), {
regions: [{top: 2 * 10, left: 4 * 10, width: 2 * 10, height: 10}]
}
# becoming empty
expectStateUpdate presenter, -> editor.getSelections()[1].clear()
expectStateUpdate presenter, -> editor.getSelections()[1].clear(autoscroll: false)
expect(stateForSelection(presenter, 1)).toBeUndefined()
# becoming non-empty
expectStateUpdate presenter, -> editor.getSelections()[1].setBufferRange([[2, 4], [2, 6]])
expectStateUpdate presenter, -> editor.getSelections()[1].setBufferRange([[2, 4], [2, 6]], autoscroll: false)
expectValues stateForSelection(presenter, 1), {
regions: [{top: 2 * 10, left: 4 * 10, width: 2 * 10, height: 10}]
}
# moving out of view
expectStateUpdate presenter, -> editor.getSelections()[1].setBufferRange([[3, 4], [3, 6]])
expectStateUpdate presenter, -> editor.getSelections()[1].setBufferRange([[3, 4], [3, 6]], autoscroll: false)
expect(stateForSelection(presenter, 1)).toBeUndefined()
# adding
expectStateUpdate presenter, -> editor.addSelectionForBufferRange([[1, 4], [1, 6]])
expectStateUpdate presenter, -> editor.addSelectionForBufferRange([[1, 4], [1, 6]], autoscroll: false)
expectValues stateForSelection(presenter, 2), {
regions: [{top: 1 * 10, left: 4 * 10, width: 2 * 10, height: 10}]
}
# moving added selection
expectStateUpdate presenter, -> editor.getSelections()[2].setBufferRange([[1, 4], [1, 8]])
expectStateUpdate presenter, -> editor.getSelections()[2].setBufferRange([[1, 4], [1, 8]], autoscroll: false)
expectValues stateForSelection(presenter, 2), {
regions: [{top: 1 * 10, left: 4 * 10, width: 4 * 10, height: 10}]
}

View File

@@ -921,7 +921,6 @@ describe "TextEditor", ->
describe "autoscroll", ->
beforeEach ->
editor.manageScrollPosition = true
editor.setVerticalScrollMargin(2)
editor.setHorizontalScrollMargin(2)
editor.setLineHeightInPixels(10)
@@ -971,9 +970,8 @@ describe "TextEditor", ->
it "scrolls left when the last cursor gets closer than ::horizontalScrollMargin to the left of the editor", ->
editor.setScrollRight(editor.getScrollWidth())
editor.setCursorScreenPosition([6, 62])
expect(editor.getScrollRight()).toBe editor.getScrollWidth()
editor.setCursorScreenPosition([6, 62], autoscroll: false)
editor.moveLeft()
expect(editor.getScrollLeft()).toBe 59 * 10
@@ -994,6 +992,38 @@ describe "TextEditor", ->
editor.undo()
expect(editor.getScrollTop()).toBe 0
it "honors the autoscroll option on cursor and selection manipulation methods", ->
expect(editor.getScrollTop()).toBe 0
editor.addCursorAtScreenPosition([11, 11], autoscroll: false)
expect(editor.getScrollTop()).toBe 0
editor.addCursorAtBufferPosition([11, 11], autoscroll: false)
expect(editor.getScrollTop()).toBe 0
editor.setCursorScreenPosition([11, 11], autoscroll: false)
expect(editor.getScrollTop()).toBe 0
editor.setCursorBufferPosition([11, 11], autoscroll: false)
expect(editor.getScrollTop()).toBe 0
editor.addSelectionForBufferRange([[11, 11], [11, 11]], autoscroll: false)
expect(editor.getScrollTop()).toBe 0
editor.addSelectionForScreenRange([[11, 11], [11, 12]], autoscroll: false)
expect(editor.getScrollTop()).toBe 0
editor.setSelectedBufferRange([[11, 0], [11, 1]], autoscroll: false)
expect(editor.getScrollTop()).toBe 0
editor.setSelectedScreenRange([[11, 0], [11, 6]], autoscroll: false)
expect(editor.getScrollTop()).toBe 0
editor.clearSelections(autoscroll: false)
expect(editor.getScrollTop()).toBe 0
editor.addSelectionForScreenRange([[0, 0], [0, 4]])
editor.getCursors()[0].setScreenPosition([11, 11], autoscroll: true)
expect(editor.getScrollTop()).toBeGreaterThan 0
editor.getCursors()[0].setBufferPosition([0, 0], autoscroll: true)
expect(editor.getScrollTop()).toBe 0
editor.getSelections()[0].setScreenRange([[11, 0], [11, 4]], autoscroll: true)
expect(editor.getScrollTop()).toBeGreaterThan 0
editor.getSelections()[0].setBufferRange([[0, 0], [0, 4]], autoscroll: true)
expect(editor.getScrollTop()).toBe 0
describe '.logCursorScope()', ->
beforeEach ->
spyOn(atom.notifications, 'addInfo')
@@ -1254,7 +1284,6 @@ describe "TextEditor", ->
expect(editor.getSelectedBufferRange()).toEqual [[0,0], [2,0]]
it "autoscrolls to the selection", ->
editor.manageScrollPosition = true
editor.setLineHeightInPixels(10)
editor.setDefaultCharWidth(10)
editor.setHeight(50)
@@ -1521,24 +1550,28 @@ describe "TextEditor", ->
expect(selection1.getScreenRange()).toEqual [[2, 2], [3, 4]]
describe ".setSelectedBufferRange(range)", ->
describe "when the 'autoscroll' option is true", ->
it "autoscrolls to the selection", ->
editor.manageScrollPosition = true
editor.setLineHeightInPixels(10)
editor.setDefaultCharWidth(10)
editor.setHeight(50)
editor.setWidth(50)
editor.setHorizontalScrollbarHeight(0)
it "autoscrolls the selection if it is last unless the 'autoscroll' option is false", ->
editor.setVerticalScrollMargin(2)
editor.setHorizontalScrollMargin(2)
editor.setLineHeightInPixels(10)
editor.setDefaultCharWidth(10)
editor.setHeight(70)
editor.setWidth(100)
editor.setHorizontalScrollbarHeight(0)
expect(editor.getScrollTop()).toBe 0
expect(editor.getScrollTop()).toBe 0
editor.setSelectedBufferRange([[5, 6], [6, 8]], autoscroll: true)
expect(editor.getScrollBottom()).toBe (7 + editor.getVerticalScrollMargin()) * 10
expect(editor.getScrollRight()).toBe 50
editor.setSelectedBufferRange([[5, 6], [6, 8]])
expect(editor.getScrollBottom()).toBe (7 + editor.getVerticalScrollMargin()) * 10
expect(editor.getScrollRight()).toBe (8 + editor.getHorizontalScrollMargin()) * 10
editor.setSelectedBufferRange([[6, 6], [6, 8]], autoscroll: true)
expect(editor.getScrollBottom()).toBe (7 + editor.getVerticalScrollMargin()) * 10
expect(editor.getScrollRight()).toBe (8 + editor.getHorizontalScrollMargin()) * 10
editor.setSelectedBufferRange([[0, 0], [0, 0]])
expect(editor.getScrollTop()).toBe 0
expect(editor.getScrollLeft()).toBe 0
editor.setSelectedBufferRange([[6, 6], [6, 8]])
expect(editor.getScrollBottom()).toBe (7 + editor.getVerticalScrollMargin()) * 10
expect(editor.getScrollRight()).toBe (8 + editor.getHorizontalScrollMargin()) * 10
describe ".selectMarker(marker)", ->
describe "if the marker is valid", ->
@@ -1560,16 +1593,15 @@ describe "TextEditor", ->
expect(editor.getSelectedBufferRanges()).toEqual [[[0, 0], [0, 0]], [[3, 4], [5, 6]]]
it "autoscrolls to the added selection if needed", ->
editor.manageScrollPosition = true
editor.setVerticalScrollMargin(2)
editor.setHorizontalScrollMargin(2)
editor.setLineHeightInPixels(10)
editor.setDefaultCharWidth(10)
editor.setHeight(50)
editor.setWidth(50)
editor.setHeight(80)
editor.setWidth(100)
editor.addSelectionForBufferRange([[8, 10], [8, 15]])
expect(editor.getScrollTop()).toBe 75
expect(editor.getScrollLeft()).toBe 160
expect(editor.getScrollBottom()).toBe (9 * 10) + (2 * 10)
expect(editor.getScrollRight()).toBe (15 * 10) + (2 * 10)
describe ".addSelectionBelow()", ->
describe "when the selection is non-empty", ->
@@ -1922,7 +1954,6 @@ describe "TextEditor", ->
expect(cursor2.getBufferPosition()).toEqual [2, 7]
it "autoscrolls to the last cursor", ->
editor.manageScrollPosition = true
editor.setCursorScreenPosition([1, 2])
editor.addCursorAtScreenPosition([10, 4])
editor.setLineHeightInPixels(10)
@@ -4056,7 +4087,7 @@ describe "TextEditor", ->
editor.setLineHeightInPixels(10)
editor.setDefaultCharWidth(10)
editor.setHeight(60)
editor.setWidth(50)
editor.setWidth(130)
editor.setHorizontalScrollbarHeight(0)
expect(editor.getScrollTop()).toBe 0
expect(editor.getScrollLeft()).toBe 0
@@ -4072,8 +4103,6 @@ describe "TextEditor", ->
describe ".pageUp/Down()", ->
it "scrolls one screen height up or down and moves the cursor one page length", ->
editor.manageScrollPosition = true
editor.setLineHeightInPixels(10)
editor.setHeight(50)
expect(editor.getScrollHeight()).toBe 130
@@ -4097,8 +4126,6 @@ describe "TextEditor", ->
describe ".selectPageUp/Down()", ->
it "selects one screen height of text up or down", ->
editor.manageScrollPosition = true
editor.setLineHeightInPixels(10)
editor.setHeight(50)
expect(editor.getScrollHeight()).toBe 130

View File

@@ -0,0 +1,30 @@
typescript = require '../src/typescript'
crypto = require 'crypto'
describe "TypeScript transpiler support", ->
describe "::createTypeScriptVersionAndOptionsDigest", ->
it "returns a digest for the library version and specified options", ->
defaultOptions =
target: 1 # ES5
module: 'commonjs'
sourceMap: true
version = '1.4.1'
shasum = crypto.createHash('sha1')
shasum.update('typescript', 'utf8')
shasum.update('\0', 'utf8')
shasum.update(version, 'utf8')
shasum.update('\0', 'utf8')
shasum.update(JSON.stringify(defaultOptions))
expectedDigest = shasum.digest('hex')
observedDigest = typescript.createTypeScriptVersionAndOptionsDigest(version, defaultOptions)
expect(observedDigest).toEqual expectedDigest
describe "when there is a .ts file", ->
it "transpiles it using typescript", ->
transpiled = require('./fixtures/typescript/valid.ts')
expect(transpiled(3)).toBe 4
describe "when the .ts file is invalid", ->
it "does not transpile", ->
expect(-> require('./fixtures/typescript/invalid.ts')).toThrow()

View File

@@ -2,6 +2,7 @@ path = require 'path'
CSON = require 'season'
CoffeeCache = require 'coffee-cash'
babel = require './babel'
typescript = require './typescript'
# This file is required directly by apm so that files can be cached during
# package install so that the first package load in Atom doesn't have to
@@ -16,6 +17,7 @@ exports.addPathToCache = (filePath, atomHome) ->
CoffeeCache.setCacheDirectory(path.join(cacheDir, 'coffee'))
CSON.setCacheDir(path.join(cacheDir, 'cson'))
babel.setCacheDirectory(path.join(cacheDir, 'js', 'babel'))
typescript.setCacheDirectory(path.join(cacheDir, 'ts'))
switch path.extname(filePath)
when '.coffee'
@@ -24,3 +26,5 @@ exports.addPathToCache = (filePath, atomHome) ->
CSON.readFileSync(filePath)
when '.js'
babel.addPathToCache(filePath)
when '.ts'
typescript.addPathToCache(filePath)

View File

@@ -15,7 +15,6 @@ class Cursor extends Model
bufferPosition: null
goalColumn: null
visible: true
needsAutoscroll: null
# Instantiated by a {TextEditor}
constructor: ({@editor, @marker, id}) ->
@@ -30,10 +29,6 @@ class Cursor extends Model
{textChanged} = e
return if oldHeadScreenPosition.isEqual(newHeadScreenPosition)
# Supports old editor view
@needsAutoscroll ?= @isLastCursor() and !textChanged
@autoscroll() if @editor.manageScrollPosition and @isLastCursor() and textChanged
@goalColumn = null
movedEvent =
@@ -53,7 +48,6 @@ class Cursor extends Model
@emit 'destroyed'
@emitter.emit 'did-destroy'
@emitter.dispose()
@needsAutoscroll = true
destroy: ->
@marker.destroy()
@@ -128,8 +122,9 @@ class Cursor extends Model
#
# * `bufferPosition` {Array} of two numbers: the buffer row, and the buffer column.
# * `options` (optional) {Object} with the following keys:
# * `autoscroll` A Boolean which, if `true`, scrolls the {TextEditor} to wherever
# the cursor moves to.
# * `autoscroll` {Boolean} indicating whether to autoscroll to the new
# position. Defaults to `true` if this is the most recently added cursor,
# `false` otherwise.
setBufferPosition: (bufferPosition, options={}) ->
@changePosition options, =>
@marker.setHeadBufferPosition(bufferPosition, options)
@@ -600,7 +595,6 @@ class Cursor extends Model
setVisible: (visible) ->
if @visible != visible
@visible = visible
@needsAutoscroll ?= true if @visible and @isLastCursor()
@emit 'visibility-changed', @visible
@emitter.emit 'did-change-visibility', @visible
@@ -628,11 +622,10 @@ class Cursor extends Model
# Public: Prevents this cursor from causing scrolling.
clearAutoscroll: ->
@needsAutoscroll = null
# Public: Deselects the current selection.
clearSelection: ->
@selection?.clear()
clearSelection: (options) ->
@selection?.clear(options)
# Public: Get the RegExp used by the cursor to determine what a "word" is.
#
@@ -655,12 +648,9 @@ class Cursor extends Model
###
changePosition: (options, fn) ->
@clearSelection()
@needsAutoscroll = options.autoscroll ? @isLastCursor()
@clearSelection(options)
fn()
if @needsAutoscroll
@emit 'autoscrolled' # Support legacy editor
@autoscroll() if @needsAutoscroll and @editor.manageScrollPosition # Support react editor view
@autoscroll() if options.autoscroll ? @isLastCursor()
getPixelRect: ->
@editor.pixelRectForScreenRange(@getScreenRange())

View File

@@ -22,7 +22,6 @@ class DisplayBuffer extends Model
Serializable.includeInto(this)
@properties
manageScrollPosition: false
softWrapped: null
editorWidthInChars: null
lineHeightInPixels: null
@@ -200,12 +199,22 @@ class DisplayBuffer extends Model
# visible - A {Boolean} indicating of the tokenized buffer is shown
setVisible: (visible) -> @tokenizedBuffer.setVisible(visible)
getVerticalScrollMargin: -> @verticalScrollMargin
getVerticalScrollMargin: -> Math.min(@verticalScrollMargin, (@getHeight() - @getLineHeightInPixels()) / 2)
setVerticalScrollMargin: (@verticalScrollMargin) -> @verticalScrollMargin
getHorizontalScrollMargin: -> @horizontalScrollMargin
getVerticalScrollMarginInPixels: ->
scrollMarginInPixels = @getVerticalScrollMargin() * @getLineHeightInPixels()
maxScrollMarginInPixels = (@getHeight() - @getLineHeightInPixels()) / 2
Math.min(scrollMarginInPixels, maxScrollMarginInPixels)
getHorizontalScrollMargin: -> Math.min(@horizontalScrollMargin, (@getWidth() - @getDefaultCharWidth()) / 2)
setHorizontalScrollMargin: (@horizontalScrollMargin) -> @horizontalScrollMargin
getHorizontalScrollMarginInPixels: ->
scrollMarginInPixels = @getHorizontalScrollMargin() * @getDefaultCharWidth()
maxScrollMarginInPixels = (@getWidth() - @getDefaultCharWidth()) / 2
Math.min(scrollMarginInPixels, maxScrollMarginInPixels)
getHorizontalScrollbarHeight: -> @horizontalScrollbarHeight
setHorizontalScrollbarHeight: (@horizontalScrollbarHeight) -> @horizontalScrollbarHeight
@@ -268,26 +277,19 @@ class DisplayBuffer extends Model
getScrollTop: -> @scrollTop
setScrollTop: (scrollTop) ->
if @manageScrollPosition
@scrollTop = Math.round(Math.max(0, Math.min(@getMaxScrollTop(), scrollTop)))
else
@scrollTop = Math.round(scrollTop)
@scrollTop = Math.round(Math.max(0, Math.min(@getMaxScrollTop(), scrollTop)))
getMaxScrollTop: ->
@getScrollHeight() - @getClientHeight()
getScrollBottom: -> @scrollTop + @height
getScrollBottom: -> @scrollTop + @getClientHeight()
setScrollBottom: (scrollBottom) ->
@setScrollTop(scrollBottom - @getClientHeight())
@getScrollBottom()
getScrollLeft: -> @scrollLeft
setScrollLeft: (scrollLeft) ->
if @manageScrollPosition
@scrollLeft = Math.round(Math.max(0, Math.min(@getScrollWidth() - @getClientWidth(), scrollLeft)))
@scrollLeft
else
@scrollLeft = Math.round(scrollLeft)
@scrollLeft = Math.round(Math.max(0, Math.min(@getScrollWidth() - @getClientWidth(), scrollLeft)))
getMaxScrollLeft: ->
@getScrollWidth() - @getClientWidth()
@@ -372,15 +374,16 @@ class DisplayBuffer extends Model
@intersectsVisibleRowRange(start.row, end.row + 1)
scrollToScreenRange: (screenRange, options) ->
verticalScrollMarginInPixels = @getVerticalScrollMargin() * @getLineHeightInPixels()
horizontalScrollMarginInPixels = @getHorizontalScrollMargin() * @getDefaultCharWidth()
verticalScrollMarginInPixels = @getVerticalScrollMarginInPixels()
horizontalScrollMarginInPixels = @getHorizontalScrollMarginInPixels()
{top, left, height, width} = @pixelRectForScreenRange(screenRange)
bottom = top + height
right = left + width
{top, left} = @pixelRectForScreenRange(new Range(screenRange.start, screenRange.start))
{top: endTop, left: endLeft, height: endHeight} = @pixelRectForScreenRange(new Range(screenRange.end, screenRange.end))
bottom = endTop + endHeight
right = endLeft
if options?.center
desiredScrollCenter = top + height / 2
desiredScrollCenter = (top + bottom) / 2
unless @getScrollTop() < desiredScrollCenter < @getScrollBottom()
desiredScrollTop = desiredScrollCenter - @getHeight() / 2
desiredScrollBottom = desiredScrollCenter + @getHeight() / 2
@@ -391,15 +394,26 @@ class DisplayBuffer extends Model
desiredScrollLeft = left - horizontalScrollMarginInPixels
desiredScrollRight = right + horizontalScrollMarginInPixels
if desiredScrollTop < @getScrollTop()
@setScrollTop(desiredScrollTop)
else if desiredScrollBottom > @getScrollBottom()
@setScrollBottom(desiredScrollBottom)
if options?.reversed ? true
if desiredScrollBottom > @getScrollBottom()
@setScrollBottom(desiredScrollBottom)
if desiredScrollTop < @getScrollTop()
@setScrollTop(desiredScrollTop)
if desiredScrollLeft < @getScrollLeft()
@setScrollLeft(desiredScrollLeft)
else if desiredScrollRight > @getScrollRight()
@setScrollRight(desiredScrollRight)
if desiredScrollRight > @getScrollRight()
@setScrollRight(desiredScrollRight)
if desiredScrollLeft < @getScrollLeft()
@setScrollLeft(desiredScrollLeft)
else
if desiredScrollTop < @getScrollTop()
@setScrollTop(desiredScrollTop)
if desiredScrollBottom > @getScrollBottom()
@setScrollBottom(desiredScrollBottom)
if desiredScrollLeft < @getScrollLeft()
@setScrollLeft(desiredScrollLeft)
if desiredScrollRight > @getScrollRight()
@setScrollRight(desiredScrollRight)
scrollToScreenPosition: (screenPosition, options) ->
@scrollToScreenRange(new Range(screenPosition, screenPosition), options)
@@ -1113,7 +1127,7 @@ class DisplayBuffer extends Model
handleTokenizedBufferChange: (tokenizedBufferChange) =>
{start, end, delta, bufferChange} = tokenizedBufferChange
@updateScreenLines(start, end + 1, delta, delayChangeEvent: bufferChange?)
@setScrollTop(Math.min(@getScrollTop(), @getMaxScrollTop())) if @manageScrollPosition and delta < 0
@setScrollTop(Math.min(@getScrollTop(), @getMaxScrollTop())) if delta < 0
updateScreenLines: (startBufferRow, endBufferRow, bufferDelta=0, options={}) ->
startBufferRow = @rowMap.bufferRowRangeForBufferRow(startBufferRow)[0]

View File

@@ -686,7 +686,7 @@ class Pane extends Model
true
handleSaveError: (error) ->
if error.message.endsWith('is a directory')
if error.code is 'EISDIR' or error.message.endsWith('is a directory')
atom.notifications.addWarning("Unable to save file: #{error.message}")
else if error.code is 'EACCES' and error.path?
atom.notifications.addWarning("Unable to save file: Permission denied '#{error.path}'")

View File

@@ -1,6 +1,6 @@
{Point, Range} = require 'text-buffer'
{Model} = require 'theorist'
{pick} = require 'underscore-plus'
{pick} = _ = require 'underscore-plus'
{Emitter} = require 'event-kit'
Grim = require 'grim'
@@ -14,7 +14,6 @@ class Selection extends Model
editor: null
initialScreenRange: null
wordwise: false
needsAutoscroll: null
constructor: ({@cursor, @marker, @editor, id}) ->
@emitter = new Emitter
@@ -35,6 +34,9 @@ class Selection extends Model
destroy: ->
@marker.destroy()
isLastSelection: ->
this is @editor.getLastSelection()
###
Section: Event Subscription
###
@@ -96,19 +98,20 @@ class Selection extends Model
#
# * `screenRange` The new {Range} to select.
# * `options` (optional) {Object} with the keys:
# * `preserveFolds` if `true`, the fold settings are preserved after the selection moves.
# * `autoscroll` if `true`, the {TextEditor} scrolls to the new selection.
# * `preserveFolds` if `true`, the fold settings are preserved after the
# selection moves.
# * `autoscroll` {Boolean} indicating whether to autoscroll to the new
# range. Defaults to `true` if this is the most recently added selection,
# `false` otherwise.
setBufferRange: (bufferRange, options={}) ->
bufferRange = Range.fromObject(bufferRange)
@needsAutoscroll = options.autoscroll
options.reversed ?= @isReversed()
@editor.destroyFoldsContainingBufferRange(bufferRange) unless options.preserveFolds
@modifySelection =>
needsFlash = options.flash
delete options.flash if options.flash?
@cursor.needsAutoscroll = false if @needsAutoscroll?
@marker.setBufferRange(bufferRange, options)
@autoscroll() if @needsAutoscroll and @editor.manageScrollPosition
@autoscroll() if options?.autoscroll ? @isLastSelection()
@decoration.flash('flash', @editor.selectionFlashDuration) if needsFlash
# Public: Returns the starting and ending buffer rows the selection is
@@ -184,9 +187,15 @@ class Selection extends Model
###
# Public: Clears the selection, moving the marker to the head.
clear: ->
#
# * `options` (optional) {Object} with the following keys:
# * `autoscroll` {Boolean} indicating whether to autoscroll to the new
# range. Defaults to `true` if this is the most recently added selection,
# `false` otherwise.
clear: (options) ->
@marker.setProperties(goalScreenRange: null)
@marker.clearTail() unless @retainSelection
@autoscroll() if options?.autoscroll ? @isLastSelection()
@finalize()
# Public: Selects the text from the current cursor position to a given screen
@@ -359,7 +368,6 @@ class Selection extends Model
@editor.unfoldBufferRow(oldBufferRange.end.row)
wasReversed = @isReversed()
@clear()
@cursor.needsAutoscroll = @cursor.isLastCursor()
autoIndentFirstLine = false
precedingText = @editor.getTextInRange([[oldBufferRange.start.row, 0], oldBufferRange.start])
@@ -398,6 +406,8 @@ class Selection extends Model
else if options.autoDecreaseIndent and NonWhitespaceRegExp.test(text)
@editor.autoDecreaseIndentForBufferRow(newBufferRange.start.row)
@autoscroll() if @isLastSelection()
newBufferRange
# Public: Removes the first character before the selection if the selection
@@ -713,7 +723,7 @@ class Selection extends Model
else
options.goalScreenRange = myGoalScreenRange ? otherGoalScreenRange
@setBufferRange(@getBufferRange().union(otherSelection.getBufferRange()), options)
@setBufferRange(@getBufferRange().union(otherSelection.getBufferRange()), _.extend(autoscroll: false, options))
otherSelection.destroy()
###
@@ -755,10 +765,12 @@ class Selection extends Model
@linewise = false
autoscroll: ->
@editor.scrollToScreenRange(@getScreenRange())
if @marker.hasTail()
@editor.scrollToScreenRange(@getScreenRange(), reversed: @isReversed())
else
@cursor.autoscroll()
clearAutoscroll: ->
@needsAutoscroll = null
modifySelection: (fn) ->
@retainSelection = true

View File

@@ -39,7 +39,6 @@ class TextEditorComponent
@lineOverdrawMargin = lineOverdrawMargin if lineOverdrawMargin?
@disposables = new CompositeDisposable
@editor.manageScrollPosition = true
@observeConfig()
@setScrollSensitivity(atom.config.get('editor.scrollSensitivity'))

View File

@@ -76,7 +76,7 @@ class TextEditor extends Model
@delegatesProperties '$lineHeightInPixels', '$defaultCharWidth', '$height', '$width',
'$verticalScrollbarWidth', '$horizontalScrollbarHeight', '$scrollTop', '$scrollLeft',
'manageScrollPosition', toProperty: 'displayBuffer'
toProperty: 'displayBuffer'
constructor: ({@softTabs, initialLine, initialColumn, tabLength, softWrapped, @displayBuffer, buffer, registerEditor, suppressCursorCreation, @mini, @placeholderText, @gutterVisible}) ->
super
@@ -1132,13 +1132,13 @@ class TextEditor extends Model
# Essential: Undo the last change.
undo: ->
@getLastCursor().needsAutoscroll = true
@buffer.undo(this)
@buffer.undo()
@getLastSelection().autoscroll()
# Essential: Redo the last change.
redo: ->
@getLastCursor().needsAutoscroll = true
@buffer.redo(this)
@getLastSelection().autoscroll()
# Extended: Batch multiple operations as a single undo/redo step.
#
@@ -1608,8 +1608,9 @@ class TextEditor extends Model
# * `bufferPosition` A {Point} or {Array} of `[row, column]`
#
# Returns a {Cursor}.
addCursorAtBufferPosition: (bufferPosition) ->
addCursorAtBufferPosition: (bufferPosition, options) ->
@markBufferPosition(bufferPosition, @getSelectionMarkerAttributes())
@getLastSelection().cursor.autoscroll() unless options?.autoscroll is false
@getLastSelection().cursor
# Essential: Add a cursor at the position in screen coordinates.
@@ -1617,8 +1618,9 @@ class TextEditor extends Model
# * `screenPosition` A {Point} or {Array} of `[row, column]`
#
# Returns a {Cursor}.
addCursorAtScreenPosition: (screenPosition) ->
addCursorAtScreenPosition: (screenPosition, options) ->
@markScreenPosition(screenPosition, @getSelectionMarkerAttributes())
@getLastSelection().cursor.autoscroll() unless options?.autoscroll is false
@getLastSelection().cursor
# Essential: Returns {Boolean} indicating whether or not there are multiple cursors.
@@ -1949,9 +1951,8 @@ class TextEditor extends Model
# Returns the added {Selection}.
addSelectionForBufferRange: (bufferRange, options={}) ->
@markBufferRange(bufferRange, _.defaults(@getSelectionMarkerAttributes(), options))
selection = @getLastSelection()
selection.autoscroll() if @manageScrollPosition
selection
@getLastSelection().autoscroll() unless options.autoscroll is false
@getLastSelection()
# Essential: Add a selection for the given range in screen coordinates.
#
@@ -1963,9 +1964,8 @@ class TextEditor extends Model
# Returns the added {Selection}.
addSelectionForScreenRange: (screenRange, options={}) ->
@markScreenRange(screenRange, _.defaults(@getSelectionMarkerAttributes(), options))
selection = @getLastSelection()
selection.autoscroll() if @manageScrollPosition
selection
@getLastSelection().autoscroll() unless options.autoscroll is false
@getLastSelection()
# Essential: Select from the current cursor position to the given position in
# buffer coordinates.
@@ -2271,6 +2271,7 @@ class TextEditor extends Model
@selections.push(selection)
selectionBufferRange = selection.getBufferRange()
@mergeIntersectingSelections(preserveFolds: marker.getProperties().preserveFolds)
if selection.destroyed
for selection in @getSelections()
if selection.intersectsBufferRange(selectionBufferRange)
@@ -2288,9 +2289,9 @@ class TextEditor extends Model
# Reduce one or more selections to a single empty selection based on the most
# recently added cursor.
clearSelections: ->
clearSelections: (options) ->
@consolidateSelections()
@getLastSelection().clear()
@getLastSelection().clear(options)
# Reduce multiple selections to the most recently added selection.
consolidateSelections: ->

106
src/typescript.coffee Normal file
View File

@@ -0,0 +1,106 @@
###
Cache for source code transpiled by TypeScript.
Inspired by https://github.com/atom/atom/blob/7a719d585db96ff7d2977db9067e1d9d4d0adf1a/src/babel.coffee
###
crypto = require 'crypto'
fs = require 'fs-plus'
path = require 'path'
tss = null # Defer until used
stats =
hits: 0
misses: 0
defaultOptions =
target: 1 # ES5
module: 'commonjs'
sourceMap: true
createTypeScriptVersionAndOptionsDigest = (version, options) ->
shasum = crypto.createHash('sha1')
# Include the version of typescript in the hash.
shasum.update('typescript', 'utf8')
shasum.update('\0', 'utf8')
shasum.update(version, 'utf8')
shasum.update('\0', 'utf8')
shasum.update(JSON.stringify(options))
shasum.digest('hex')
cacheDir = null
jsCacheDir = null
getCachePath = (sourceCode) ->
digest = crypto.createHash('sha1').update(sourceCode, 'utf8').digest('hex')
unless jsCacheDir?
tssVersion = require('typescript-simple/package.json').version
jsCacheDir = path.join(cacheDir, createTypeScriptVersionAndOptionsDigest(tssVersion, defaultOptions))
path.join(jsCacheDir, "#{digest}.js")
getCachedJavaScript = (cachePath) ->
if fs.isFileSync(cachePath)
try
cachedJavaScript = fs.readFileSync(cachePath, 'utf8')
stats.hits++
return cachedJavaScript
null
# Returns the TypeScript options that should be used to transpile filePath.
createOptions = (filePath) ->
options = filename: filePath
for key, value of defaultOptions
options[key] = value
options
transpile = (sourceCode, filePath, cachePath) ->
options = createOptions(filePath)
unless tss?
{TypeScriptSimple} = require 'typescript-simple'
tss = new TypeScriptSimple(options, false)
js = tss.compile(sourceCode, filePath)
stats.misses++
try
fs.writeFileSync(cachePath, js)
js
# Function that obeys the contract of an entry in the require.extensions map.
# Returns the transpiled version of the JavaScript code at filePath, which is
# either generated on the fly or pulled from cache.
loadFile = (module, filePath) ->
sourceCode = fs.readFileSync(filePath, 'utf8')
cachePath = getCachePath(sourceCode)
js = getCachedJavaScript(cachePath) ? transpile(sourceCode, filePath, cachePath)
module._compile(js, filePath)
register = ->
Object.defineProperty(require.extensions, '.ts', {
enumerable: true
writable: false
value: loadFile
})
setCacheDirectory = (newCacheDir) ->
if cacheDir isnt newCacheDir
cacheDir = newCacheDir
jsCacheDir = null
module.exports =
register: register
setCacheDirectory: setCacheDirectory
getCacheMisses: -> stats.misses
getCacheHits: -> stats.hits
# Visible for testing.
createTypeScriptVersionAndOptionsDigest: createTypeScriptVersionAndOptionsDigest
addPathToCache: (filePath) ->
return if path.extname(filePath) isnt '.ts'
sourceCode = fs.readFileSync(filePath, 'utf8')
cachePath = getCachePath(sourceCode)
transpile(sourceCode, filePath, cachePath)

View File

@@ -47,6 +47,7 @@ window.onload = function() {
setupCsonCache(cacheDir);
setupSourceMapCache(cacheDir);
setupBabel(cacheDir);
setupTypeScript(cacheDir);
require(loadSettings.bootstrapScript);
require('ipc').sendChannel('window-command', 'window:loaded');
@@ -95,6 +96,12 @@ var setupBabel = function(cacheDir) {
babel.register();
}
var setupTypeScript = function(cacheDir) {
var typescript = require('../src/typescript');
typescript.setCacheDirectory(path.join(cacheDir, 'typescript'));
typescript.register();
}
var setupCsonCache = function(cacheDir) {
require('season').setCacheDir(path.join(cacheDir, 'cson'));
}