Merge branch 'master' into batch-updates

This commit is contained in:
Antonio Scandurra
2015-02-27 12:46:25 +01:00
12 changed files with 137 additions and 51 deletions

View File

@@ -104,19 +104,19 @@
"link": "0.30.0",
"markdown-preview": "0.137.0",
"metrics": "0.45.0",
"notifications": "0.28.0",
"open-on-github": "0.32.0",
"notifications": "0.31.0",
"open-on-github": "0.33.0",
"package-generator": "0.38.0",
"release-notes": "0.51.0",
"settings-view": "0.183.0",
"snippets": "0.76.0",
"snippets": "0.77.0",
"spell-check": "0.55.0",
"status-bar": "0.60.0",
"styleguide": "0.44.0",
"symbols-view": "0.84.0",
"symbols-view": "0.85.0",
"tabs": "0.67.0",
"timecop": "0.31.0",
"tree-view": "0.162.0",
"tree-view": "0.163.0",
"update-package-dependencies": "0.8.0",
"welcome": "0.24.0",
"whitespace": "0.29.0",
@@ -138,7 +138,7 @@
"language-make": "0.13.0",
"language-mustache": "0.11.0",
"language-objective-c": "0.15.0",
"language-perl": "0.10.0",
"language-perl": "0.11.0",
"language-php": "0.21.0",
"language-property-list": "0.8.0",
"language-python": "0.32.0",

View File

@@ -3,6 +3,8 @@ Exec = require('child_process').exec
path = require 'path'
Package = require '../src/package'
ThemeManager = require '../src/theme-manager'
_ = require "underscore-plus"
temp = require "temp"
describe "the `atom` global", ->
describe 'window sizing methods', ->
@@ -124,3 +126,29 @@ describe "the `atom` global", ->
line: 2
column: 3
originalError: error
describe "saving and loading", ->
afterEach -> atom.mode = "spec"
it "selects the state based on the current project paths", ->
Atom = atom.constructor
[dir1, dir2] = [temp.mkdirSync("dir1-"), temp.mkdirSync("dir2-")]
loadSettings = _.extend Atom.getLoadSettings(),
initialPaths: [dir1]
windowState: null
spyOn(Atom, 'getLoadSettings').andCallFake -> loadSettings
spyOn(Atom, 'getStorageDirPath').andReturn(temp.mkdirSync("storage-dir-"))
atom.mode = "editor"
atom.state.stuff = "cool"
atom.project.setPaths([dir1, dir2])
atom.saveSync.originalValue.call(atom)
atom1 = Atom.loadOrCreate("editor")
expect(atom1.state.stuff).toBeUndefined()
loadSettings.initialPaths = [dir2, dir1]
atom2 = Atom.loadOrCreate("editor")
expect(atom2.state.stuff).toBe("cool")

View File

@@ -80,6 +80,14 @@ describe "DisplayBuffer", ->
atom.config.set('editor.softWrapAtPreferredLineLength', false)
expect(displayBuffer.tokenizedLineForScreenRow(10).text).toBe ' return '
describe "when editor width is negative", ->
it "does not hang while wrapping", ->
displayBuffer.setDefaultCharWidth(1)
displayBuffer.setWidth(-1)
expect(displayBuffer.tokenizedLineForScreenRow(1).text).toBe " "
expect(displayBuffer.tokenizedLineForScreenRow(2).text).toBe " var sort = function(items) {"
describe "when the line is shorter than the max line length", ->
it "renders the line unchanged", ->
expect(displayBuffer.tokenizedLineForScreenRow(0).text).toBe buffer.lineForRow(0)

View File

@@ -438,6 +438,23 @@ describe "Project", ->
randomPath = path.join("some", "random", "path")
expect(atom.project.relativize(randomPath)).toBe randomPath
describe ".relativizePath(path)", ->
it "returns the root path that contains the given path, and the path relativized to that root path", ->
atom.project.addPath(temp.mkdirSync("another-path"))
rootPath = atom.project.getPaths()[0]
childPath = path.join(rootPath, "some", "child", "directory")
expect(atom.project.relativizePath(childPath)).toEqual [rootPath, path.join("some", "child", "directory")]
rootPath = atom.project.getPaths()[1]
childPath = path.join(rootPath, "some", "child", "directory")
expect(atom.project.relativizePath(childPath)).toEqual [rootPath, path.join("some", "child", "directory")]
describe "when the given path isn't inside of any of the project's path", ->
it "returns null for the root path, and the given path unchanged", ->
randomPath = path.join("some", "random", "path")
expect(atom.project.relativizePath(randomPath)).toEqual [null, randomPath]
describe ".contains(path)", ->
it "returns whether or not the given path is in one of the root directories", ->
rootPath = atom.project.getPaths()[0]

View File

@@ -794,6 +794,8 @@ describe "TextEditorComponent", ->
it "blinks cursors when they aren't moving", ->
cursorsNode = componentNode.querySelector('.cursors')
wrapperNode.focus()
nextAnimationFrame()
expect(cursorsNode.classList.contains('blink-off')).toBe false
advanceClock(component.cursorBlinkPeriod / 2)
@@ -2481,8 +2483,7 @@ describe "TextEditorComponent", ->
gutterWidth = componentNode.querySelector('.gutter').offsetWidth
componentNode.style.width = gutterWidth + 14 * charWidth + editor.getVerticalScrollbarWidth() + 'px'
advanceClock(atom.views.documentPollingInterval)
nextAnimationFrame() # won't poll until cursor blinks
nextAnimationFrame() # handle update requested by poll
nextAnimationFrame()
expect(componentNode.querySelector('.line').textContent).toBe "var quicksort "
it "accounts for the scroll view's padding when determining the wrap location", ->

View File

@@ -1135,49 +1135,63 @@ describe "TextEditorPresenter", ->
presenter = buildPresenter(explicitHeight: 20, scrollTop: 0)
expect(stateForCursor(presenter, 0).width).toBe 10
describe ".blinkCursorsOff", ->
it "alternates between true and false twice per ::cursorBlinkPeriod", ->
describe ".cursorsVisible", ->
it "alternates between true and false twice per ::cursorBlinkPeriod when the editor is focused", ->
cursorBlinkPeriod = 100
cursorBlinkResumeDelay = 200
presenter = buildPresenter({cursorBlinkPeriod, cursorBlinkResumeDelay})
presenter = buildPresenter({cursorBlinkPeriod, cursorBlinkResumeDelay, focused: true})
expect(presenter.state.content.blinkCursorsOff).toBe false
expect(presenter.state.content.cursorsVisible).toBe true
expectStateUpdate presenter, -> advanceClock(cursorBlinkPeriod / 2)
expect(presenter.state.content.blinkCursorsOff).toBe true
expect(presenter.state.content.cursorsVisible).toBe false
expectStateUpdate presenter, -> advanceClock(cursorBlinkPeriod / 2)
expect(presenter.state.content.blinkCursorsOff).toBe false
expect(presenter.state.content.cursorsVisible).toBe true
expectStateUpdate presenter, -> advanceClock(cursorBlinkPeriod / 2)
expect(presenter.state.content.blinkCursorsOff).toBe true
expect(presenter.state.content.cursorsVisible).toBe false
expectStateUpdate presenter, -> advanceClock(cursorBlinkPeriod / 2)
expect(presenter.state.content.cursorsVisible).toBe true
expectStateUpdate presenter, -> presenter.setFocused(false)
expect(presenter.state.content.cursorsVisible).toBe false
advanceClock(cursorBlinkPeriod / 2)
expect(presenter.state.content.cursorsVisible).toBe false
advanceClock(cursorBlinkPeriod / 2)
expect(presenter.state.content.cursorsVisible).toBe false
expectStateUpdate presenter, -> presenter.setFocused(true)
expect(presenter.state.content.cursorsVisible).toBe true
expectStateUpdate presenter, -> advanceClock(cursorBlinkPeriod / 2)
expect(presenter.state.content.cursorsVisible).toBe false
it "stops alternating for ::cursorBlinkResumeDelay when a cursor moves or a cursor is added", ->
cursorBlinkPeriod = 100
cursorBlinkResumeDelay = 200
presenter = buildPresenter({cursorBlinkPeriod, cursorBlinkResumeDelay})
presenter = buildPresenter({cursorBlinkPeriod, cursorBlinkResumeDelay, focused: true})
expect(presenter.state.content.blinkCursorsOff).toBe false
expect(presenter.state.content.cursorsVisible).toBe true
expectStateUpdate presenter, -> advanceClock(cursorBlinkPeriod / 2)
expect(presenter.state.content.blinkCursorsOff).toBe true
expect(presenter.state.content.cursorsVisible).toBe false
expectStateUpdate presenter, -> editor.moveRight()
expect(presenter.state.content.blinkCursorsOff).toBe false
expect(presenter.state.content.cursorsVisible).toBe true
expectStateUpdate presenter, ->
advanceClock(cursorBlinkResumeDelay)
advanceClock(cursorBlinkPeriod / 2)
expect(presenter.state.content.blinkCursorsOff).toBe true
expect(presenter.state.content.cursorsVisible).toBe false
expectStateUpdate presenter, -> advanceClock(cursorBlinkPeriod / 2)
expect(presenter.state.content.blinkCursorsOff).toBe false
expect(presenter.state.content.cursorsVisible).toBe true
expectStateUpdate presenter, -> advanceClock(cursorBlinkPeriod / 2)
expect(presenter.state.content.blinkCursorsOff).toBe true
expect(presenter.state.content.cursorsVisible).toBe false
expectStateUpdate presenter, -> editor.addCursorAtBufferPosition([1, 0])
expect(presenter.state.content.blinkCursorsOff).toBe false
expect(presenter.state.content.cursorsVisible).toBe true
expectStateUpdate presenter, ->
advanceClock(cursorBlinkResumeDelay)
advanceClock(cursorBlinkPeriod / 2)
expect(presenter.state.content.blinkCursorsOff).toBe true
expect(presenter.state.content.cursorsVisible).toBe false
describe ".highlights", ->
stateForHighlight = (presenter, decoration) ->

View File

@@ -73,7 +73,7 @@ class Atom extends Model
# Loads and returns the serialized state corresponding to this window
# if it exists; otherwise returns undefined.
@loadState: (mode) ->
statePath = @getStatePath(mode)
statePath = @getStatePath(@getLoadSettings().initialPaths, mode)
if fs.existsSync(statePath)
try
@@ -90,14 +90,13 @@ class Atom extends Model
# Returns the path where the state for the current window will be
# located if it exists.
@getStatePath: (mode) ->
@getStatePath: (paths, mode) ->
switch mode
when 'spec'
filename = 'spec'
when 'editor'
{initialPaths} = @getLoadSettings()
if initialPaths?.length > 0
sha1 = crypto.createHash('sha1').update(initialPaths.join("\n")).digest('hex')
if paths?.length > 0
sha1 = crypto.createHash('sha1').update(paths.slice().sort().join("\n")).digest('hex')
filename = "editor-#{sha1}"
if filename
@@ -773,7 +772,7 @@ class Atom extends Model
saveSync: ->
stateString = JSON.stringify(@state)
if statePath = @constructor.getStatePath(@mode)
if statePath = @constructor.getStatePath(@project?.getPaths(), @mode)
fs.writeFileSync(statePath, stateString, 'utf8')
else
@getCurrentWindow().loadSettings.windowState = stateString

View File

@@ -22,6 +22,7 @@ class AutoUpdateManager
# https://github.com/Squirrel/Squirrel.Windows/issues/132
@feedUrl = 'https://atom.io/api/updates'
else
@iconPath = path.resolve(__dirname, '..', '..', 'resources', 'atom.png')
@feedUrl = "https://atom.io/api/updates?version=#{@version}"
process.nextTick => @setupAutoUpdater()
@@ -89,7 +90,7 @@ class AutoUpdateManager
dialog.showMessageBox
type: 'info'
buttons: ['OK']
icon: path.resolve(__dirname, '..', '..', 'resources', 'atom.png')
icon: @iconPath
message: 'No update available.'
title: 'No Update Available'
detail: "Version #{@version} is the latest version."
@@ -100,7 +101,7 @@ class AutoUpdateManager
dialog.showMessageBox
type: 'warning'
buttons: ['OK']
icon: path.resolve(__dirname, '..', '..', 'resources', 'atom.png')
icon: @iconPath
message: 'There was an error checking for updates.'
title: 'Update Error'
detail: message

View File

@@ -13,12 +13,12 @@ class CursorsComponent
@oldState ?= {cursors: {}}
# update blink class
if newState.blinkCursorsOff isnt @oldState.blinkCursorsOff
if newState.blinkCursorsOff
@domNode.classList.add 'blink-off'
else
if newState.cursorsVisible isnt @oldState.cursorsVisible
if newState.cursorsVisible
@domNode.classList.remove 'blink-off'
@oldState.blinkCursorsOff = newState.blinkCursorsOff
else
@domNode.classList.add 'blink-off'
@oldState.cursorsVisible = newState.cursorsVisible
# remove cursors
for id of @oldState.cursors

View File

@@ -458,7 +458,7 @@ class DisplayBuffer extends Model
width = @width ? @getScrollWidth()
width -= @getVerticalScrollbarWidth()
if width? and @defaultCharWidth > 0
Math.floor(width / @defaultCharWidth)
Math.max(0, Math.floor(width / @defaultCharWidth))
else
@editorWidthInChars

View File

@@ -266,15 +266,25 @@ class Project extends Model
else
undefined
# Public: Make the given path relative to the project directory.
#
# * `fullPath` {String} full path
relativize: (fullPath) ->
@relativizePath(fullPath)[1]
# Public: Get the path to the project directory that contains the given path,
# and the relative path from that project directory to the given path.
#
# * `fullPath` {String} An absolute path.
#
# Returns an {Array} with two elements:
# * `projectPath` The {String} path to the project directory that contains the
# given path, or `null` if none is found.
# * `relativePath` {String} The relative path from the project directory to
# the given path.
relativizePath: (fullPath) ->
return fullPath if fullPath?.match(/[A-Za-z0-9+-.]+:\/\//) # leave path alone if it has a scheme
for rootDirectory in @rootDirectories
relativePath = rootDirectory.relativize(fullPath)
return relativePath if relativePath isnt fullPath
fullPath
return [rootDirectory.getPath(), relativePath] unless relativePath is fullPath
[null, fullPath]
# Public: Determines whether the given path (real or symbolic) is inside the
# project's directory.

View File

@@ -25,7 +25,7 @@ class TextEditorPresenter
@observeModel()
@observeConfig()
@buildState()
@startBlinkingCursors()
@startBlinkingCursors() if @focused
@enterBatchMode()
destroy: ->
@@ -160,7 +160,7 @@ class TextEditorPresenter
hiddenInput: {}
content:
scrollingVertically: false
blinkCursorsOff: false
cursorsVisible: false
lines: {}
highlights: {}
overlays: {}
@@ -619,6 +619,10 @@ class TextEditorPresenter
setFocused: (focused) ->
unless @focused is focused
@focused = focused
if @focused
@startBlinkingCursors()
else
@stopBlinkingCursors(false)
@updateFocusedState()
@updateHiddenInputState()
@@ -1092,18 +1096,22 @@ class TextEditorPresenter
@updateCursorState(cursor)
startBlinkingCursors: ->
@toggleCursorBlinkHandle = setInterval(@toggleCursorBlink.bind(this), @getCursorBlinkPeriod() / 2)
unless @toggleCursorBlinkHandle
@state.content.cursorsVisible = true
@toggleCursorBlinkHandle = setInterval(@toggleCursorBlink.bind(this), @getCursorBlinkPeriod() / 2)
stopBlinkingCursors: ->
clearInterval(@toggleCursorBlinkHandle)
stopBlinkingCursors: (visible) ->
if @toggleCursorBlinkHandle
@state.content.cursorsVisible = visible
clearInterval(@toggleCursorBlinkHandle)
@toggleCursorBlinkHandle = null
toggleCursorBlink: ->
@state.content.blinkCursorsOff = not @state.content.blinkCursorsOff
@state.content.cursorsVisible = not @state.content.cursorsVisible
@emitter.emit 'did-update-state'
pauseCursorBlinking: ->
@state.content.blinkCursorsOff = false
@stopBlinkingCursors()
@stopBlinkingCursors(true)
@startBlinkingCursorsAfterDelay ?= _.debounce(@startBlinkingCursors, @getCursorBlinkResumeDelay())
@startBlinkingCursorsAfterDelay()
@emitter.emit 'did-update-state'