Merge remote-tracking branch 'origin/master' into vim-core-changes

Conflicts:
	src/app/editor.coffee
This commit is contained in:
Mutwin Kraus
2013-04-08 12:54:43 +02:00
48 changed files with 542 additions and 478 deletions

View File

@@ -1,7 +1,6 @@
fsUtils = require 'fs-utils'
_ = require 'underscore'
Package = require 'package'
TextMatePackage = require 'text-mate-package'
Theme = require 'theme'
messageIdCounter = 1
@@ -127,6 +126,9 @@ _.extend atom,
newWindow: (args...) ->
@sendMessageToBrowserProcess('newWindow', args)
restartRendererProcess: ->
@sendMessageToBrowserProcess('restartRendererProcess')
confirm: (message, detailedMessage, buttonLabelsAndCallbacks...) ->
wrapCallback = (callback) => => @dismissModal(callback)
@presentModal =>
@@ -208,9 +210,13 @@ _.extend atom,
originalSendMessageToBrowserProcess(name, data)
receiveMessageFromBrowserProcess: (name, data) ->
if name is 'reply'
[messageId, callbackIndex] = data.shift()
@pendingBrowserProcessCallbacks[messageId]?[callbackIndex]?(data...)
switch name
when 'reply'
[messageId, callbackIndex] = data.shift()
@pendingBrowserProcessCallbacks[messageId]?[callbackIndex]?(data...)
when 'openPath'
path = data[0]
rootView?.open(path)
setWindowState: (keyPath, value) ->
windowState = @getWindowState()

View File

@@ -16,9 +16,10 @@ class BindingSet
parser: null
name: null
constructor: (@selector, commandsByKeystrokes, @index, @name) ->
constructor: (selector, commandsByKeystrokes, @index, @name) ->
BindingSet.parser ?= PEG.buildParser(fsUtils.read(require.resolve 'keystroke-pattern.pegjs'))
@specificity = Specificity(@selector)
@specificity = Specificity(selector)
@selector = selector.replace(/!important/g, '')
@commandsByKeystrokes = @normalizeCommandsByKeystrokes(commandsByKeystrokes)
commandForEvent: (event) ->

View File

@@ -27,6 +27,9 @@ class BufferMarker
isReversed: ->
@tailPosition? and @headPosition.isLessThan(@tailPosition)
isRangeEmpty: ->
@getHeadPosition().isEqual(@getTailPosition())
getRange: ->
if @tailPosition
new Range(@tailPosition, @headPosition)

View File

@@ -12,9 +12,9 @@ class Cursor
needsAutoscroll: null
constructor: ({@editSession, @marker}) ->
@updateVisibility()
@editSession.observeMarker @marker, (e) =>
@setVisible(@selection.isEmpty())
@updateVisibility()
{oldHeadScreenPosition, newHeadScreenPosition} = e
{oldHeadBufferPosition, newHeadBufferPosition} = e
{bufferChanged} = e
@@ -34,6 +34,7 @@ class Cursor
@needsAutoscroll = true
destroy: ->
@destroyed = true
@editSession.destroyMarker(@marker)
@editSession.removeCursor(this)
@trigger 'destroyed'
@@ -59,6 +60,9 @@ class Cursor
unless fn()
@trigger 'autoscrolled' if @needsAutoscroll
updateVisibility: ->
@setVisible(@editSession.isMarkerRangeEmpty(@marker))
setVisible: (visible) ->
if @visible != visible
@visible = visible
@@ -84,6 +88,7 @@ class Cursor
clearSelection: ->
if @selection
@selection.goalBufferRange = null
@selection.clear() unless @selection.retainSelection
getScreenRow: ->

View File

@@ -1,6 +1,7 @@
_ = require 'underscore'
fs = require 'fs'
fsUtils = require 'fs-utils'
pathWatcher = require 'pathwatcher'
File = require 'file'
EventEmitter = require 'event-emitter'
@@ -39,12 +40,12 @@ class Directory
@unsubscribeFromNativeChangeEvents() if @subscriptionCount() == 0
subscribeToNativeChangeEvents: ->
@watchSubscription = fsUtils.watchPath @path, (eventType) =>
@trigger "contents-changed" if eventType is "contents-change"
@watchSubscription = pathWatcher.watch @path, (eventType) =>
@trigger "contents-changed" if eventType is "change"
unsubscribeFromNativeChangeEvents: ->
if @watchSubscription?
@watchSubscription.unwatch()
@watchSubscription.close()
@watchSubscription = null
_.extend Directory.prototype, EventEmitter

View File

@@ -400,6 +400,9 @@ class DisplayBuffer
isMarkerReversed: (id) ->
@buffer.isMarkerReversed(id)
isMarkerRangeEmpty: (id) ->
@buffer.isMarkerRangeEmpty(id)
observeMarker: (id, callback) ->
@getMarker(id).observe(callback)

View File

@@ -125,8 +125,8 @@ class EditSession
getTabLength: -> @displayBuffer.getTabLength()
setTabLength: (tabLength) -> @displayBuffer.setTabLength(tabLength)
clipBufferPosition: (bufferPosition) ->
@buffer.clipPosition(bufferPosition)
clipBufferPosition: (bufferPosition) -> @buffer.clipPosition(bufferPosition)
clipBufferRange: (range) -> @buffer.clipRange(range)
indentationForBufferRow: (bufferRow) ->
@indentLevelForLine(@lineForBufferRow(bufferRow))
@@ -556,6 +556,9 @@ class EditSession
isMarkerReversed: (args...) ->
@displayBuffer.isMarkerReversed(args...)
isMarkerRangeEmpty: (args...) ->
@displayBuffer.isMarkerRangeEmpty(args...)
hasMultipleCursors: ->
@getCursors().length > 1
@@ -585,10 +588,10 @@ class EditSession
unless options.preserveFolds
@destroyFoldsIntersectingBufferRange(@getMarkerBufferRange(marker))
cursor = @addCursor(marker)
selection = new Selection({editSession: this, marker, cursor})
selection = new Selection(_.extend({editSession: this, marker, cursor}, options))
@selections.push(selection)
selectionBufferRange = selection.getBufferRange()
@mergeIntersectingSelections()
@mergeIntersectingSelections() unless options.suppressMerge
if selection.destroyed
for selection in @getSelections()
if selection.intersectsBufferRange(selectionBufferRange)
@@ -600,7 +603,7 @@ class EditSession
addSelectionForBufferRange: (bufferRange, options={}) ->
options = _.defaults({invalidationStrategy: 'never'}, options)
marker = @markBufferRange(bufferRange, options)
@addSelection(marker)
@addSelection(marker, options)
setSelectedBufferRange: (bufferRange, options) ->
@setSelectedBufferRanges([bufferRange], options)
@@ -623,13 +626,16 @@ class EditSession
_.remove(@selections, selection)
clearSelections: ->
lastSelection = @getLastSelection()
for selection in @getSelections() when selection != lastSelection
selection.destroy()
lastSelection.clear()
@consolidateSelections()
@getSelection().clear()
clearAllSelections: ->
selection.destroy() for selection in @getSelections()
consolidateSelections: ->
selections = @getSelections()
if selections.length > 1
selection.destroy() for selection in selections[0...-1]
true
else
false
getSelections: -> new Array(@selections...)
@@ -761,6 +767,12 @@ class EditSession
selectLine: ->
@expandSelectionsForward (selection) => selection.selectLine()
addSelectionBelow: ->
@expandSelectionsForward (selection) => selection.addSelectionBelow()
addSelectionAbove: ->
@expandSelectionsBackward (selection) => selection.addSelectionAbove()
transpose: ->
@mutateSelectedText (selection) =>
if selection.isEmpty()

View File

@@ -60,7 +60,7 @@ class Editor extends View
if editSessionOrOptions instanceof EditSession
editSession = editSessionOrOptions
else
{editSession, @mini} = (editSessionOrOptions ? {})
{editSession, @mini} = editSessionOrOptions ? {}
requireStylesheet 'editor'
@@ -104,6 +104,7 @@ class Editor extends View
'editor:move-to-previous-word': @moveCursorToPreviousWord
'editor:select-word': @selectWord
'editor:newline': @insertNewline
'editor:consolidate-selections': @consolidateSelections
'editor:indent': @indent
'editor:auto-indent': @autoIndent
'editor:indent-selected-rows': @indentSelectedRows
@@ -124,6 +125,8 @@ class Editor extends View
'editor:select-to-end-of-word': @selectToEndOfWord
'editor:select-to-beginning-of-word': @selectToBeginningOfWord
'editor:select-to-beginning-of-next-word': @selectToBeginningOfNextWord
'editor:add-selection-below': @addSelectionBelow
'editor:add-selection-above': @addSelectionAbove
'editor:select-line': @selectLine
'editor:transpose': @transpose
'editor:upper-case': @upperCase
@@ -165,7 +168,7 @@ class Editor extends View
documentation = {}
for name, method of editorBindings
do (name, method) =>
@command name, => method.call(this); false
@command name, (e) => method.call(this, e); false
getCursor: -> @activeEditSession.getCursor()
getCursors: -> @activeEditSession.getCursors()
@@ -214,6 +217,8 @@ class Editor extends View
selectAll: -> @activeEditSession.selectAll()
selectToBeginningOfLine: -> @activeEditSession.selectToBeginningOfLine()
selectToEndOfLine: -> @activeEditSession.selectToEndOfLine()
addSelectionBelow: -> @activeEditSession.addSelectionBelow()
addSelectionAbove: -> @activeEditSession.addSelectionAbove()
selectToBeginningOfWord: -> @activeEditSession.selectToBeginningOfWord()
selectToEndOfWord: -> @activeEditSession.selectToEndOfWord()
selectToBeginningOfNextWord: -> @activeEditSession.selectToEndOfWord(); @activeEditSession.selectRight()
@@ -234,6 +239,7 @@ class Editor extends View
cutToEndOfLine: -> @activeEditSession.cutToEndOfLine()
insertText: (text, options) -> @activeEditSession.insertText(text, options)
insertNewline: -> @activeEditSession.insertNewline()
consolidateSelections: (e) -> e.abortKeyBinding() unless @activeEditSession.consolidateSelections()
insertNewlineBelow: -> @activeEditSession.insertNewlineBelow()
insertNewlineAbove: -> @activeEditSession.insertNewlineAbove()
indent: (options) -> @activeEditSession.indent(options)
@@ -782,7 +788,7 @@ class Editor extends View
updateCursorViews: ->
if @newCursors.length > 0
@addCursorView(cursor) for cursor in @newCursors
@addCursorView(cursor) for cursor in @newCursors when not cursor.destroyed
@syncCursorAnimations()
@newCursors = []
@@ -794,11 +800,11 @@ class Editor extends View
updateSelectionViews: ->
if @newSelections.length > 0
@addSelectionView(selection) for selection in @newSelections
@addSelectionView(selection) for selection in @newSelections when not selection.destroyed
@newSelections = []
for selectionView in @getSelectionViews()
if selectionView.destroyed
if selectionView.needsRemoval
selectionView.remove()
else
selectionView.updateDisplay()

View File

@@ -2,6 +2,7 @@ EventEmitter = require 'event-emitter'
fs = require 'fs'
fsUtils = require 'fs-utils'
pathWatcher = require 'pathwatcher'
_ = require 'underscore'
module.exports =
@@ -45,12 +46,13 @@ class File
@unsubscribeFromNativeChangeEvents() if @subscriptionCount() == 0
handleNativeChangeEvent: (eventType, path) ->
if eventType is "remove"
if eventType is "delete"
@unsubscribeFromNativeChangeEvents()
@detectResurrectionAfterDelay()
else if eventType is "move"
else if eventType is "rename"
@setPath(path)
@trigger "moved"
else if eventType is "contents-change"
else if eventType is "change"
oldContents = @read()
newContents = @read(true)
return if oldContents == newContents
@@ -62,19 +64,18 @@ class File
detectResurrection: ->
if @exists()
@subscribeToNativeChangeEvents()
@handleNativeChangeEvent("contents-change", @getPath())
@handleNativeChangeEvent("change", @getPath())
else
@cachedContents = null
@unsubscribeFromNativeChangeEvents()
@trigger "removed"
subscribeToNativeChangeEvents: ->
@watchSubscription = fsUtils.watchPath @path, (eventType, path) =>
@watchSubscription = pathWatcher.watch @path, (eventType, path) =>
@handleNativeChangeEvent(eventType, path)
unsubscribeFromNativeChangeEvents: ->
if @watchSubscription
@watchSubscription.unwatch()
@watchSubscription.close()
@watchSubscription = null
_.extend File.prototype, EventEmitter

View File

@@ -9,6 +9,8 @@
'ctrl-]': 'editor:unfold-current-row'
'ctrl-{': 'editor:fold-all'
'ctrl-}': 'editor:unfold-all'
'alt-shift-down': 'editor:add-selection-below'
'alt-shift-up': 'editor:add-selection-above'
'alt-meta-ctrl-f': 'editor:fold-selection'
'shift-tab': 'editor:outdent-selected-rows'
'meta-[': 'editor:outdent-selected-rows'
@@ -30,3 +32,6 @@
'enter': 'core:confirm',
'escape': 'core:cancel'
'meta-w': 'core:cancel'
'.editor !important, .editor.mini !important':
'escape': 'editor:consolidate-selections'

View File

@@ -7,6 +7,8 @@
'ctrl-N': 'core:select-down'
'ctrl-F': 'core:select-right'
'ctrl-B': 'core:select-left'
'alt-ctrl-n': 'editor:add-selection-below'
'alt-ctrl-p': 'editor:add-selection-above'
'ctrl-h': 'core:backspace'
'ctrl-d': 'core:delete'

View File

@@ -97,11 +97,8 @@ class RootView extends View
changeFocus = options.changeFocus ? true
path = project.resolve(path) if path?
if activePane = @getActivePane()
if editSession = activePane.itemForUri(path)
activePane.showItem(editSession)
else
editSession = project.buildEditSession(path)
activePane.showItem(editSession)
editSession = activePane.itemForUri(path) ? project.buildEditSession(path)
activePane.showItem(editSession)
else
editSession = project.buildEditSession(path)
activePane = new Pane(editSession)

View File

@@ -8,13 +8,13 @@ class SelectionView extends View
@div class: 'selection'
regions: null
destroyed: false
needsRemoval: false
initialize: ({@editor, @selection} = {}) ->
@regions = []
@selection.on 'screen-range-changed', => @editor.requestDisplayUpdate()
@selection.on 'destroyed', =>
@destroyed = true
@needsRemoval = true
@editor.requestDisplayUpdate()
updateDisplay: ->

View File

@@ -4,11 +4,15 @@ _ = require 'underscore'
module.exports =
class Selection
wordwise: false
cursor: null
marker: null
editSession: null
initialScreenRange: null
goalBufferRange: null
wordwise: false
needsAutoscroll: null
constructor: ({@cursor, @marker, @editSession}) ->
constructor: ({@cursor, @marker, @editSession, @goalBufferRange}) ->
@cursor.selection = this
@editSession.observeMarker @marker, => @screenRangeChanged()
@cursor.on 'destroyed.selection', =>
@@ -148,6 +152,40 @@ class Selection
selectToEndOfWord: ->
@modifySelection => @cursor.moveToEndOfWord()
addSelectionBelow: ->
range = (@goalBufferRange ? @getBufferRange()).copy()
nextRow = range.end.row + 1
for row in [nextRow..@editSession.getLastBufferRow()]
range.start.row = row
range.end.row = row
clippedRange = @editSession.clipBufferRange(range)
if range.isEmpty()
continue if range.end.column > 0 and clippedRange.end.column is 0
else
continue if clippedRange.isEmpty()
@editSession.addSelectionForBufferRange(range, goalBufferRange: range, suppressMerge: true)
break
addSelectionAbove: ->
range = (@goalBufferRange ? @getBufferRange()).copy()
previousRow = range.end.row - 1
for row in [previousRow..0]
range.start.row = row
range.end.row = row
clippedRange = @editSession.clipBufferRange(range)
if range.isEmpty()
continue if range.end.column > 0 and clippedRange.end.column is 0
else
continue if clippedRange.isEmpty()
@editSession.addSelectionForBufferRange(range, goalBufferRange: range, suppressMerge: true)
break
insertText: (text, options={}) ->
oldBufferRange = @getBufferRange()
@editSession.destroyFoldsContainingBufferRow(oldBufferRange.end.row)
@@ -369,10 +407,14 @@ class Selection
@getBufferRange().intersectsWith(bufferRange)
intersectsWith: (otherSelection) ->
@getScreenRange().intersectsWith(otherSelection.getScreenRange())
@getBufferRange().intersectsWith(otherSelection.getBufferRange())
merge: (otherSelection, options) ->
@setBufferRange(@getBufferRange().union(otherSelection.getBufferRange()), options)
if @goalBufferRange and otherSelection.goalBufferRange
@goalBufferRange = @goalBufferRange.union(otherSelection.goalBufferRange)
else if otherSelection.goalBufferRange
@goalBufferRange = otherSelection.goalBufferRange
otherSelection.destroy()
_.extend Selection.prototype, EventEmitter

View File

@@ -37,17 +37,17 @@ class Buffer
@lineEndings = []
if path
throw "Path '#{path}' does not exist" unless fsUtils.exists(path)
@setPath(path)
if initialText?
@setText(initialText)
@updateCachedDiskContents()
else
else if fsUtils.exists(path)
@reload()
else
@setText('')
else
@setText(initialText ? '')
@undoManager = new UndoManager(this)
destroy: ->
@@ -340,6 +340,9 @@ class Buffer
isMarkerReversed: (id) ->
@validMarkers[id]?.isReversed()
isMarkerRangeEmpty: (id) ->
@validMarkers[id]?.isRangeEmpty()
observeMarker: (id, callback) ->
@validMarkers[id]?.observe(callback)

View File

@@ -25,6 +25,12 @@ window.setUpEnvironment = ->
$(document).on 'keydown', keymap.handleKeyEvent
keymap.bindDefaultKeys()
ignoreEvents = (e) ->
e.preventDefault()
e.stopPropagation()
$(document).on 'dragover', ignoreEvents
$(document).on 'drop', ignoreEvents
requireStylesheet 'reset'
requireStylesheet 'atom'
requireStylesheet 'overlay'
@@ -148,7 +154,16 @@ window.applyStylesheet = (id, text, ttype = 'bundled') ->
$("head").append "<style class='#{ttype}' id='#{id}'>#{text}</style>"
window.reload = ->
$native.reload()
timesReloaded = process.global.timesReloaded ? 0
++timesReloaded
restartValue = if window.location.search.indexOf('spec-bootstrap') == -1 then 10 else 3
if timesReloaded > restartValue
atom.restartRendererProcess()
else
$native.reload()
process.global.timesReloaded = timesReloaded
window.onerror = ->
atom.showDevTools()