Merge remote-tracking branch 'origin/master' into mb-deprecate-load-time-package-code

Conflicts:
	package.json
This commit is contained in:
Max Brunsfeld
2015-11-30 10:20:31 -08:00
32 changed files with 426 additions and 123 deletions

View File

@@ -66,13 +66,42 @@ class ApplicationDelegate
ipc.send("call-window-method", "setFullScreen", fullScreen)
openWindowDevTools: ->
remote.getCurrentWindow().openDevTools()
new Promise (resolve) ->
# Defer DevTools interaction to the next tick, because using them during
# event handling causes some wrong input events to be triggered on
# `TextEditorComponent` (Ref.: https://github.com/atom/atom/issues/9697).
process.nextTick ->
if remote.getCurrentWindow().isDevToolsOpened()
resolve()
else
remote.getCurrentWindow().once("devtools-opened", -> resolve())
ipc.send("call-window-method", "openDevTools")
closeWindowDevTools: ->
new Promise (resolve) ->
# Defer DevTools interaction to the next tick, because using them during
# event handling causes some wrong input events to be triggered on
# `TextEditorComponent` (Ref.: https://github.com/atom/atom/issues/9697).
process.nextTick ->
unless remote.getCurrentWindow().isDevToolsOpened()
resolve()
else
remote.getCurrentWindow().once("devtools-closed", -> resolve())
ipc.send("call-window-method", "closeDevTools")
toggleWindowDevTools: ->
remote.getCurrentWindow().toggleDevTools()
new Promise (resolve) =>
# Defer DevTools interaction to the next tick, because using them during
# event handling causes some wrong input events to be triggered on
# `TextEditorComponent` (Ref.: https://github.com/atom/atom/issues/9697).
process.nextTick =>
if remote.getCurrentWindow().isDevToolsOpened()
@closeWindowDevTools().then(resolve)
else
@openWindowDevTools().then(resolve)
executeJavaScriptInWindowDevTools: (code) ->
remote.getCurrentWindow().executeJavaScriptInDevTools(code)
ipc.send("call-window-method", "executeJavaScriptInDevTools", code)
setWindowDocumentEdited: (edited) ->
ipc.send("call-window-method", "setDocumentEdited", edited)

View File

@@ -670,8 +670,7 @@ class AtomEnvironment extends Model
@emitter.emit 'will-throw-error', eventObject
if openDevTools
@openDevTools()
@executeJavaScriptInDevTools('DevToolsAPI.showConsole()')
@openDevTools().then => @executeJavaScriptInDevTools('DevToolsAPI.showConsole()')
@emitter.emit 'did-throw-error', {message, url, line, column, originalError}
@@ -721,10 +720,15 @@ class AtomEnvironment extends Model
###
# Extended: Open the dev tools for the current window.
#
# Returns a {Promise} that resolves when the DevTools have been opened.
openDevTools: ->
@applicationDelegate.openWindowDevTools()
# Extended: Toggle the visibility of the dev tools for the current window.
#
# Returns a {Promise} that resolves when the DevTools have been opened or
# closed.
toggleDevTools: ->
@applicationDelegate.toggleWindowDevTools()

View File

@@ -373,6 +373,8 @@ class AtomApplication
# :windowDimensions - Object with height and width keys.
# :window - {AtomWindow} to open file paths in.
openPaths: ({pathsToOpen, executedFrom, pidToKillWhenClosed, newWindow, devMode, safeMode, windowDimensions, profileStartup, window}={}) ->
devMode = Boolean(devMode)
safeMode = Boolean(safeMode)
locationsToOpen = (@locationForPathToOpen(pathToOpen, executedFrom) for pathToOpen in pathsToOpen)
pathsToOpen = (locationToOpen.pathToOpen for locationToOpen in locationsToOpen)

View File

@@ -158,25 +158,33 @@ require('source-map-support').install({
}
})
var sourceMapPrepareStackTrace = Error.prepareStackTrace
var prepareStackTrace = sourceMapPrepareStackTrace
var prepareStackTraceWithSourceMapping = Error.prepareStackTrace
// Prevent coffee-script from reassigning Error.prepareStackTrace
Object.defineProperty(Error, 'prepareStackTrace', {
get: function () { return prepareStackTrace },
set: function (newValue) {}
})
let prepareStackTrace = prepareStackTraceWithSourceMapping
// Enable Grim to access the raw stack without reassigning Error.prepareStackTrace
Error.prototype.getRawStack = function () { // eslint-disable-line no-extend-native
prepareStackTrace = getRawStack
var result = this.stack
prepareStackTrace = sourceMapPrepareStackTrace
return result
function prepareStackTraceWithRawStackAssignment (error, frames) {
error.rawStack = frames
return prepareStackTrace(error, frames)
}
function getRawStack (_, stack) {
return stack
Object.defineProperty(Error, 'prepareStackTrace', {
get: function () {
return prepareStackTraceWithRawStackAssignment
},
set: function (newValue) {
prepareStackTrace = newValue
process.nextTick(function () {
prepareStackTrace = prepareStackTraceWithSourceMapping
})
}
})
Error.prototype.getRawStack = function () { // eslint-disable-line no-extend-native
// Access this.stack to ensure prepareStackTrace has been run on this error
// because it assigns this.rawStack as a side-effect
this.stack
return this.rawStack
}
Object.keys(COMPILERS).forEach(function (extension) {

View File

@@ -21,7 +21,6 @@ module.exports =
followSymlinks:
type: 'boolean'
default: true
title: 'Follow symlinks'
description: 'Follow symbolic links when searching files and when opening files with the fuzzy finder.'
disabledPackages:
type: 'array'
@@ -54,7 +53,12 @@ module.exports =
destroyEmptyPanes:
type: 'boolean'
default: true
description: 'When the last item of a pane is removed, remove that pane as well.'
title: 'Remove Empty Panes'
description: 'When the last tab of a pane is closed, remove that pane as well.'
closeEmptyWindows:
type: 'boolean'
default: true
description: 'When a window with no open tabs or panes is given the \'Close Tab\' command, close that window.'
fileEncoding:
description: 'Default character set encoding to use when reading and writing files.'
type: 'string'

View File

@@ -699,7 +699,7 @@ class Config
@endTransaction()
fn(args...)
result = callback()
new Promise (resolve, reject) =>
new Promise (resolve, reject) ->
result.then(endTransaction(resolve)).catch(endTransaction(reject))
catch error
@endTransaction()

View File

@@ -1,8 +1,7 @@
Task = require './task'
# Public: Searches local files for lines matching a specified regex.
#
# Implements thenable so it can be used with `Promise.all()`.
# Searches local files for lines matching a specified regex. Implements `.then()`
# so that it can be used with `Promise.all()`.
class DirectorySearch
constructor: (rootPaths, regex, options) ->
scanHandlerOptions =
@@ -22,31 +21,25 @@ class DirectorySearch
@task.terminate()
resolve()
# Public: Implementation of `then()` to satisfy the *thenable* contract.
# This makes it possible to use a `DirectorySearch` with `Promise.all()`.
#
# Returns `Promise`.
then: (args...) ->
@promise.then.apply(@promise, args)
# Public: Cancels the search.
cancel: ->
# This will cause @promise to reject.
@task.cancel()
null
# Default provider for the `atom.directory-searcher` service.
module.exports =
class DefaultDirectorySearcher
# Public: Determines whether this object supports search for a `Directory`.
# Determines whether this object supports search for a `Directory`.
#
# * `directory` {Directory} whose search needs might be supported by this object.
#
# Returns a `boolean` indicating whether this object can search this `Directory`.
canSearchDirectory: (directory) -> true
# Public: Performs a text search for files in the specified `Directory`, subject to the
# Performs a text search for files in the specified `Directory`, subject to the
# specified parameters.
#
# Results are streamed back to the caller by invoking methods on the specified `options`,

View File

@@ -55,7 +55,7 @@ module.exports = ({commandRegistry, commandInstaller, config}) ->
'window:log-deprecation-warnings': -> Grim.logDeprecations()
'window:toggle-auto-indent': -> config.set("editor.autoIndent", not config.get("editor.autoIndent"))
'pane:reopen-closed-item': -> @getModel().reopenItem()
'core:close': -> @getModel().destroyActivePaneItemOrEmptyPane()
'core:close': -> @getModel().closeActivePaneItemOrEmptyPaneOrWindow()
'core:save': -> @getModel().saveActivePaneItem()
'core:save-as': -> @getModel().saveActivePaneItemAs()

View File

@@ -377,7 +377,8 @@ class TextEditorPresenter
endRow = @constrainRow(@getEndTileRow() + @tileSize)
screenRows = [startRow...endRow]
if longestScreenRow = @model.getLongestScreenRow()
longestScreenRow = @model.getLongestScreenRow()
if longestScreenRow?
screenRows.push(longestScreenRow)
if @screenRowsToMeasure?
screenRows.push(@screenRowsToMeasure...)
@@ -1244,14 +1245,7 @@ class TextEditorPresenter
updateHighlightState: (decorationId, properties, screenRange) ->
return unless @startRow? and @endRow? and @lineHeight? and @hasPixelPositionRequirements()
return if screenRange.isEmpty()
if screenRange.start.row < @startRow
screenRange.start.row = @startRow
screenRange.start.column = 0
if screenRange.end.row >= @endRow
screenRange.end.row = @endRow
screenRange.end.column = 0
@constrainRangeToVisibleRowRange(screenRange)
return if screenRange.isEmpty()
@@ -1281,6 +1275,23 @@ class TextEditorPresenter
true
constrainRangeToVisibleRowRange: (screenRange) ->
if screenRange.start.row < @startRow
screenRange.start.row = @startRow
screenRange.start.column = 0
if screenRange.end.row < @startRow
screenRange.end.row = @startRow
screenRange.end.column = 0
if screenRange.start.row >= @endRow
screenRange.start.row = @endRow
screenRange.start.column = 0
if screenRange.end.row >= @endRow
screenRange.end.row = @endRow
screenRange.end.column = 0
repositionRegionWithinTile: (region, tileStartRow) ->
region.top += @scrollTop - tileStartRow * @lineHeight
region.left += @scrollLeft

View File

@@ -581,10 +581,7 @@ class TextEditor extends Model
#
# Returns a {String}.
getTitle: ->
if sessionPath = @getPath()
path.basename(sessionPath)
else
'untitled'
@getFileName() ? 'untitled'
# Essential: Get unique title for display in other parts of the UI, such as
# the window title.
@@ -593,41 +590,52 @@ class TextEditor extends Model
# 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.
# * "<filename> — <unique-dir-prefix>" when other buffers have this file name.
#
# Returns a {String}
getLongTitle: ->
if sessionPath = @getPath()
title = @getTitle()
if @getPath()
fileName = @getFileName()
# find text editors with identical file name.
paths = []
allPathSegments = []
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)
if textEditor.getFileName() is fileName
allPathSegments.push(textEditor.getDirectoryPath().split(path.sep))
# 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
if allPathSegments.length is 0
return fileName
directory = path.basename sessionPath
if nLevel > 1
path.join(directory, "...", fileName)
else
path.join(directory, fileName)
ourPathSegments = @getDirectoryPath().split(path.sep)
allPathSegments.push ourPathSegments
loop
firstSegment = ourPathSegments[0]
commonBase = _.all(allPathSegments, (pathSegments) -> pathSegments.length > 1 and pathSegments[0] is firstSegment)
if commonBase
pathSegments.shift() for pathSegments in allPathSegments
else
break
"#{fileName} \u2014 #{path.join(pathSegments...)}"
else
'untitled'
# Essential: Returns the {String} path of this editor's text buffer.
getPath: -> @buffer.getPath()
getFileName: ->
if fullPath = @getPath()
path.basename(fullPath)
else
null
getDirectoryPath: ->
if fullPath = @getPath()
path.dirname(fullPath)
else
null
# Extended: Returns the {String} character set encoding of this editor's text
# buffer.
getEncoding: -> @buffer.getEncoding()
@@ -678,16 +686,16 @@ class TextEditor extends Model
getSaveDialogOptions: -> {}
checkoutHeadRevision: ->
if filePath = this.getPath()
if @getPath()
checkoutHead = =>
@project.repositoryForDirectory(new Directory(path.dirname(filePath)))
@project.repositoryForDirectory(new Directory(@getDirectoryPath()))
.then (repository) =>
repository?.checkoutHeadForEditor(this)
if @config.get('editor.confirmCheckoutHeadRevision')
@applicationDelegate.confirm
message: 'Confirm Checkout HEAD Revision'
detailedMessage: "Are you sure you want to discard all changes to \"#{path.basename(filePath)}\" since the last Git commit?"
detailedMessage: "Are you sure you want to discard all changes to \"#{@getFileName()}\" since the last Git commit?"
buttons:
OK: checkoutHead
Cancel: null

View File

@@ -42,9 +42,8 @@ class WindowEventHandler
# `.native-key-bindings` class.
handleNativeKeybindings: ->
bindCommandToAction = (command, action) =>
@addEventListener @document, command, (event) =>
if event.target.webkitMatchesSelector('.native-key-bindings')
@applicationDelegate.getCurrentWindow().webContents[action]()
@subscriptions.add @atomEnvironment.commands.add '.native-key-bindings', command, (event) =>
@applicationDelegate.getCurrentWindow().webContents[action]()
bindCommandToAction('core:copy', 'copy')
bindCommandToAction('core:paste', 'paste')

View File

@@ -155,7 +155,7 @@ class Workspace extends Model
projectPaths = @project.getPaths() ? []
if item = @getActivePaneItem()
itemPath = item.getPath?()
itemTitle = item.getTitle?()
itemTitle = item.getLongTitle?() ? item.getTitle?()
projectPath = _.find projectPaths, (projectPath) ->
itemPath is projectPath or itemPath?.startsWith(projectPath + path.sep)
itemTitle ?= "untitled"
@@ -518,6 +518,12 @@ class Workspace extends Model
@project.bufferForPath(filePath, options).then (buffer) =>
@buildTextEditor(_.extend({buffer, largeFileMode}, options))
# Public: Returns a {Boolean} that is `true` if `object` is a `TextEditor`.
#
# * `object` An {Object} you want to perform the check against.
isTextEditor: (object) ->
object instanceof TextEditor
# Extended: Create a new text editor.
#
# Returns a {TextEditor}.
@@ -675,9 +681,15 @@ class Workspace extends Model
destroyActivePane: ->
@getActivePane()?.destroy()
# Destroy the active pane item or the active pane if it is empty.
destroyActivePaneItemOrEmptyPane: ->
if @getActivePaneItem()? then @destroyActivePaneItem() else @destroyActivePane()
# Close the active pane item, or the active pane if it is empty,
# or the current window if there is only the empty root pane.
closeActivePaneItemOrEmptyPaneOrWindow: ->
if @getActivePaneItem()?
@destroyActivePaneItem()
else if @getPanes().length > 1
@destroyActivePane()
else if @config.get('core.closeEmptyWindows')
atom.close()
# Increase the editor font size by 1px.
increaseFontSize: ->