Merge branch 'master' into batch-updates

This commit is contained in:
Antonio Scandurra
2015-02-26 11:27:08 +01:00
16 changed files with 264 additions and 81 deletions

View File

@@ -8,6 +8,7 @@ crypto = require 'crypto'
fs = require 'fs-plus'
path = require 'path'
babel = null # Defer until used
Grim = null # Defer until used
stats =
hits: 0
@@ -132,10 +133,30 @@ transpile = (sourceCode, filePath, cachePath) ->
# either generated on the fly or pulled from cache.
loadFile = (module, filePath) ->
sourceCode = fs.readFileSync(filePath, 'utf8')
return module._compile(sourceCode, filePath) unless sourceCode.startsWith('"use 6to5"') or
sourceCode.startsWith("'use 6to5'") or
sourceCode.startsWith('"use babel"') or
sourceCode.startsWith("'use babel'")
if sourceCode.startsWith('"use babel"') or sourceCode.startsWith("'use babel'")
# Continue.
else if sourceCode.startsWith('"use 6to5"') or sourceCode.startsWith("'use 6to5'")
# Create a manual deprecation since the stack is too deep to use Grim
# which limits the depth to 3
Grim ?= require 'grim'
stack = [
{
fileName: __filename
functionName: 'loadFile'
location: "#{__filename}:161:5"
}
{
fileName: filePath
functionName: '<unknown>'
location: "#{filePath}:1:1"
}
]
deprecation =
message: "Use the 'use babel' pragma instead of 'use 6to5'"
stacks: [stack]
Grim.addSerializedDeprecation(deprecation)
else
return module._compile(sourceCode, filePath)
cachePath = getCachePath(sourceCode)
js = getCachedJavaScript(cachePath) ? transpile(sourceCode, filePath, cachePath)

View File

@@ -271,7 +271,7 @@ class Cursor extends Model
{ row, column } = @getScreenPosition()
column = @goalColumn if @goalColumn?
@setScreenPosition({row: row - rowCount, column: column})
@setScreenPosition({row: row - rowCount, column: column}, skipSoftWrapIndentation: true)
@goalColumn = column
# Public: Moves the cursor down one screen row.
@@ -288,7 +288,7 @@ class Cursor extends Model
{ row, column } = @getScreenPosition()
column = @goalColumn if @goalColumn?
@setScreenPosition({row: row + rowCount, column: column})
@setScreenPosition({row: row + rowCount, column: column}, skipSoftWrapIndentation: true)
@goalColumn = column
# Public: Moves the cursor left one screen column.
@@ -359,19 +359,21 @@ class Cursor extends Model
# line.
moveToFirstCharacterOfLine: ->
screenRow = @getScreenRow()
lineBufferRange = @editor.bufferRangeForScreenRange([[screenRow, 0], [screenRow, Infinity]])
screenLineStart = @editor.clipScreenPosition([screenRow, 0], skipSoftWrapIndentation: true)
screenLineEnd = [screenRow, Infinity]
screenLineBufferRange = @editor.bufferRangeForScreenRange([screenLineStart, screenLineEnd])
firstCharacterColumn = null
@editor.scanInBufferRange /\S/, lineBufferRange, ({range, stop}) ->
@editor.scanInBufferRange /\S/, screenLineBufferRange, ({range, stop}) ->
firstCharacterColumn = range.start.column
stop()
if firstCharacterColumn? and firstCharacterColumn isnt @getBufferColumn()
targetBufferColumn = firstCharacterColumn
else
targetBufferColumn = lineBufferRange.start.column
targetBufferColumn = screenLineBufferRange.start.column
@setBufferPosition([lineBufferRange.start.row, targetBufferColumn])
@setBufferPosition([screenLineBufferRange.start.row, targetBufferColumn])
# Public: Moves the cursor to the end of the line.
moveToEndOfScreenLine: ->

View File

@@ -819,11 +819,12 @@ class DisplayBuffer extends Model
# options - A hash with the following values:
# wrapBeyondNewlines: if `true`, continues wrapping past newlines
# wrapAtSoftNewlines: if `true`, continues wrapping past soft newlines
# skipSoftWrapIndentation: if `true`, skips soft wrap indentation without wrapping to the previous line
# screenLine: if `true`, indicates that you're using a line number, not a row number
#
# Returns the new, clipped {Point}. Note that this could be the same as `position` if no clipping was performed.
clipScreenPosition: (screenPosition, options={}) ->
{ wrapBeyondNewlines, wrapAtSoftNewlines } = options
{ wrapBeyondNewlines, wrapAtSoftNewlines, skipSoftWrapIndentation } = options
{ row, column } = Point.fromObject(screenPosition)
if row < 0
@@ -841,9 +842,15 @@ class DisplayBuffer extends Model
if screenLine.isSoftWrapped() and column >= maxScreenColumn
if wrapAtSoftNewlines
row++
column = 0
column = @screenLines[row].clipScreenColumn(0)
else
column = screenLine.clipScreenColumn(maxScreenColumn - 1)
else if screenLine.isColumnInsideSoftWrapIndentation(column)
if skipSoftWrapIndentation
column = screenLine.clipScreenColumn(0)
else
row--
column = @screenLines[row].getMaxScreenColumn() - 1
else if wrapBeyondNewlines and column > maxScreenColumn and row < @getLastRow()
row++
column = 0
@@ -851,28 +858,6 @@ class DisplayBuffer extends Model
column = screenLine.clipScreenColumn(column, options)
new Point(row, column)
# Given a line, finds the point where it would wrap.
#
# line - The {String} to check
# softWrapColumn - The {Number} where you want soft wrapping to occur
#
# Returns a {Number} representing the `line` position where the wrap would take place.
# Returns `null` if a wrap wouldn't occur.
findWrapColumn: (line, softWrapColumn=@getSoftWrapColumn()) ->
return unless @isSoftWrapped()
return unless line.length > softWrapColumn
if /\s/.test(line[softWrapColumn])
# search forward for the start of a word past the boundary
for column in [softWrapColumn..line.length]
return column if /\S/.test(line[column])
return line.length
else
# search backward for the start of the word on the boundary
for column in [softWrapColumn..0]
return column + 1 if /\s/.test(line[column])
return softWrapColumn
# Calculates a {Range} representing the start of the {TextBuffer} until the end.
#
# Returns a {Range}.
@@ -1157,10 +1142,12 @@ class DisplayBuffer extends Model
bufferRow += foldedRowCount
else
softWraps = 0
while wrapScreenColumn = @findWrapColumn(tokenizedLine.text)
[wrappedLine, tokenizedLine] = tokenizedLine.softWrapAt(wrapScreenColumn)
screenLines.push(wrappedLine)
softWraps++
if @isSoftWrapped()
while wrapScreenColumn = tokenizedLine.findWrapColumn(@getSoftWrapColumn())
[wrappedLine, tokenizedLine] = tokenizedLine.softWrapAt(wrapScreenColumn)
break if wrappedLine.hasOnlySoftWrapIndentation()
screenLines.push(wrappedLine)
softWraps++
screenLines.push(tokenizedLine)
if softWraps > 0

View File

@@ -1,4 +1,5 @@
RegionStyleProperties = ['top', 'left', 'right', 'width', 'height']
SpaceRegex = /\s+/
module.exports =
class HighlightsComponent
@@ -44,8 +45,17 @@ class HighlightsComponent
# update class
if newHighlightState.class isnt oldHighlightState.class
highlightNode.classList.remove(oldHighlightState.class) if oldHighlightState.class?
highlightNode.classList.add(newHighlightState.class)
if oldHighlightState.class?
if SpaceRegex.test(oldHighlightState.class)
highlightNode.classList.remove(oldHighlightState.class.split(SpaceRegex)...)
else
highlightNode.classList.remove(oldHighlightState.class)
if SpaceRegex.test(newHighlightState.class)
highlightNode.classList.add(newHighlightState.class.split(SpaceRegex)...)
else
highlightNode.classList.add(newHighlightState.class)
oldHighlightState.class = newHighlightState.class
@updateHighlightRegions(id, newHighlightState)

View File

@@ -157,7 +157,7 @@ class Package
@activateConfig()
@activateStylesheets()
if @requireMainModule()
@mainModule.activate(atom.packages.getPackageState(@name) ? {})
@mainModule.activate?(atom.packages.getPackageState(@name) ? {})
@mainActivated = true
@activateServices()
catch e

View File

@@ -1817,13 +1817,13 @@ class TextEditor extends Model
# Merge cursors that have the same screen position
mergeCursors: ->
positions = []
positions = {}
for cursor in @getCursors()
position = cursor.getBufferPosition().toString()
if position in positions
if positions.hasOwnProperty(position)
cursor.destroy()
else
positions.push(position)
positions[position] = true
preserveCursorPositionOnBufferReload: ->
cursorPosition = null

View File

@@ -21,7 +21,7 @@ class Token
firstTrailingWhitespaceIndex: null
hasInvisibleCharacters: false
constructor: ({@value, @scopes, @isAtomic, @bufferDelta, @isHardTab, @hasPairedCharacter}) ->
constructor: ({@value, @scopes, @isAtomic, @bufferDelta, @isHardTab, @hasPairedCharacter, @isSoftWrapIndentation}) ->
@screenDelta = @value.length
@bufferDelta ?= @screenDelta
@hasPairedCharacter ?= textUtils.hasPairedCharacter(@value)
@@ -144,6 +144,15 @@ class Token
isHardTab: isHardTab
)
buildSoftWrapIndentationToken: (length) ->
new Token(
value: _.multiplyString(" ", length),
scopes: @scopes,
bufferDelta: 0,
isAtomic: true,
isSoftWrapIndentation: true
)
isOnlyWhitespace: ->
not WhitespaceRegex.test(@value)

View File

@@ -18,6 +18,8 @@ class TokenizedLine
@tokens = @breakOutAtomicTokens(tokens)
@text = @buildText()
@bufferDelta = @buildBufferDelta()
@softWrapIndentationTokens = @getSoftWrapIndentationTokens()
@softWrapIndentationDelta = @buildSoftWrapIndentationDelta()
@id = idCounter++
@markLeadingAndTrailingWhitespaceTokens()
@@ -49,7 +51,9 @@ class TokenizedLine
break if tokenStartColumn + token.screenDelta > column
tokenStartColumn += token.screenDelta
if token.isAtomic and tokenStartColumn < column
if @isColumnInsideSoftWrapIndentation(tokenStartColumn)
@softWrapIndentationDelta
else if token.isAtomic and tokenStartColumn < column
if skipAtomicTokens
tokenStartColumn + token.screenDelta
else
@@ -85,6 +89,46 @@ class TokenizedLine
getMaxBufferColumn: ->
@startBufferColumn + @bufferDelta
# Given a boundary column, finds the point where this line would wrap.
#
# maxColumn - The {Number} where you want soft wrapping to occur
#
# Returns a {Number} representing the `line` position where the wrap would take place.
# Returns `null` if a wrap wouldn't occur.
findWrapColumn: (maxColumn) ->
return unless @text.length > maxColumn
if /\s/.test(@text[maxColumn])
# search forward for the start of a word past the boundary
for column in [maxColumn..@text.length]
return column if /\S/.test(@text[column])
return @text.length
else
# search backward for the start of the word on the boundary
for column in [maxColumn..0] when @isColumnOutsideSoftWrapIndentation(column)
return column + 1 if /\s/.test(@text[column])
return maxColumn
# Calculates how many trailing spaces in this line's indentation cannot fit in a single tab.
#
# Returns a {Number} representing the odd indentation spaces in this line.
getOddIndentationSpaces: ->
oddIndentLevel = @indentLevel - Math.floor(@indentLevel)
Math.round(@tabLength * oddIndentLevel)
buildSoftWrapIndentationTokens: (token) ->
indentTokens = [0...Math.floor(@indentLevel)].map =>
token.buildSoftWrapIndentationToken(@tabLength)
if @getOddIndentationSpaces()
indentTokens.concat(
token.buildSoftWrapIndentationToken @getOddIndentationSpaces()
)
else
indentTokens
softWrapAt: (column) ->
return [new TokenizedLine([], '', [0, 0], [0, 0]), this] if column == 0
@@ -98,25 +142,50 @@ class TokenizedLine
leftTextLength += nextToken.value.length
leftTokens.push nextToken
indentationTokens = @buildSoftWrapIndentationTokens(leftTokens[0])
leftFragment = new TokenizedLine(
tokens: leftTokens
startBufferColumn: @startBufferColumn
ruleStack: @ruleStack
invisibles: @invisibles
lineEnding: null
lineEnding: null,
indentLevel: @indentLevel,
tabLength: @tabLength
)
rightFragment = new TokenizedLine(
tokens: rightTokens
tokens: indentationTokens.concat(rightTokens)
startBufferColumn: @bufferColumnForScreenColumn(column)
ruleStack: @ruleStack
invisibles: @invisibles
lineEnding: @lineEnding
lineEnding: @lineEnding,
indentLevel: @indentLevel,
tabLength: @tabLength
)
[leftFragment, rightFragment]
isSoftWrapped: ->
@lineEnding is null
isColumnOutsideSoftWrapIndentation: (column) ->
return true if @softWrapIndentationTokens.length == 0
column > @softWrapIndentationDelta
isColumnInsideSoftWrapIndentation: (column) ->
return false if @softWrapIndentationTokens.length == 0
column < @softWrapIndentationDelta
getSoftWrapIndentationTokens: ->
_.select(@tokens, (token) -> token.isSoftWrapIndentation)
buildSoftWrapIndentationDelta: ->
_.reduce @softWrapIndentationTokens, ((acc, token) -> acc + token.screenDelta), 0
hasOnlySoftWrapIndentation: ->
@tokens.length == @softWrapIndentationTokens.length
tokenAtBufferColumn: (bufferColumn) ->
@tokens[@tokenIndexAtBufferColumn(bufferColumn)]
@@ -173,7 +242,7 @@ class TokenizedLine
changedText = true
else
if invisibles.space
if token.hasLeadingWhitespace()
if token.hasLeadingWhitespace() and not token.isSoftWrapIndentation
token.value = token.value.replace LeadingWhitespaceRegex, (leadingWhitespace) ->
leadingWhitespace.replace RepeatedSpaceRegex, invisibles.space
token.hasInvisibleCharacters = true