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

@@ -1,7 +1,7 @@
{
"name": "atom",
"productName": "Atom",
"version": "0.183.0",
"version": "0.185.0",
"description": "A hackable text editor for the 21st Century.",
"main": "./src/browser/main.js",
"repository": {
@@ -93,9 +93,9 @@
"dev-live-reload": "0.41.0",
"encoding-selector": "0.18.0",
"exception-reporting": "0.24.0",
"find-and-replace": "0.157.0",
"find-and-replace": "0.158.0",
"fuzzy-finder": "0.68.0",
"git-diff": "0.53.0",
"git-diff": "0.54.0",
"go-to-line": "0.30.0",
"grammar-selector": "0.45.0",
"image-view": "0.49.0",
@@ -116,7 +116,7 @@
"symbols-view": "0.84.0",
"tabs": "0.67.0",
"timecop": "0.31.0",
"tree-view": "0.161.0",
"tree-view": "0.162.0",
"update-package-dependencies": "0.8.0",
"welcome": "0.24.0",
"whitespace": "0.29.0",
@@ -132,14 +132,14 @@
"language-html": "0.29.0",
"language-hyperlink": "0.12.2",
"language-java": "0.14.0",
"language-javascript": "0.58.0",
"language-javascript": "0.59.0",
"language-json": "0.12.0",
"language-less": "0.25.0",
"language-make": "0.13.0",
"language-mustache": "0.11.0",
"language-objective-c": "0.15.0",
"language-perl": "0.10.0",
"language-php": "0.20.0",
"language-php": "0.21.0",
"language-property-list": "0.8.0",
"language-python": "0.32.0",
"language-ruby": "0.48.0",

View File

@@ -1,7 +1,14 @@
babel = require '../src/babel'
crypto = require 'crypto'
grim = require 'grim'
describe "Babel transpiler support", ->
beforeEach ->
jasmine.snapshotDeprecations()
afterEach ->
jasmine.restoreDeprecationsSnapshot()
describe "::createBabelVersionAndOptionsDigest", ->
it "returns a digest for the library version and specified options", ->
defaultOptions =
@@ -30,21 +37,27 @@ describe "Babel transpiler support", ->
it "transpiles it using babel", ->
transpiled = require('./fixtures/babel/babel-single-quotes.js')
expect(transpiled(3)).toBe 4
expect(grim.getDeprecationsLength()).toBe 0
describe "when a .js file starts with 'use 6to5';", ->
it "transpiles it using 6to5", ->
it "transpiles it using babel and adds a pragma deprecation", ->
expect(grim.getDeprecationsLength()).toBe 0
transpiled = require('./fixtures/babel/6to5-single-quotes.js')
expect(transpiled(3)).toBe 4
expect(grim.getDeprecationsLength()).toBe 1
describe 'when a .js file starts with "use babel";', ->
it "transpiles it using babel", ->
transpiled = require('./fixtures/babel/babel-double-quotes.js')
expect(transpiled(3)).toBe 4
expect(grim.getDeprecationsLength()).toBe 0
describe 'when a .js file starts with "use 6to5";', ->
it "transpiles it using babel", ->
it "transpiles it using babel and adds a pragma deprecation", ->
expect(grim.getDeprecationsLength()).toBe 0
transpiled = require('./fixtures/babel/6to5-double-quotes.js')
expect(transpiled(3)).toBe 4
expect(grim.getDeprecationsLength()).toBe 1
describe "when a .js file does not start with 'use 6to6';", ->
it "does not transpile it using babel", ->

View File

@@ -75,7 +75,7 @@ describe "DisplayBuffer", ->
expect(displayBuffer.tokenizedLineForScreenRow(10).text).toBe ' return '
atom.config.set('editor.preferredLineLength', 5)
expect(displayBuffer.tokenizedLineForScreenRow(10).text).toBe 'funct'
expect(displayBuffer.tokenizedLineForScreenRow(10).text).toBe ' fun'
atom.config.set('editor.softWrapAtPreferredLineLength', false)
expect(displayBuffer.tokenizedLineForScreenRow(10).text).toBe ' return '
@@ -92,7 +92,7 @@ describe "DisplayBuffer", ->
describe "when there is whitespace before the boundary", ->
it "wraps the line at the end of the first whitespace preceding the boundary", ->
expect(displayBuffer.tokenizedLineForScreenRow(10).text).toBe ' return '
expect(displayBuffer.tokenizedLineForScreenRow(11).text).toBe 'sort(left).concat(pivot).concat(sort(right));'
expect(displayBuffer.tokenizedLineForScreenRow(11).text).toBe ' sort(left).concat(pivot).concat(sort(right));'
describe "when there is no whitespace before the boundary", ->
it "wraps the line exactly at the boundary since there's no more graceful place to wrap it", ->
@@ -105,7 +105,7 @@ describe "DisplayBuffer", ->
describe "when there is a whitespace character at the max length boundary", ->
it "wraps the line at the first non-whitespace character following the boundary", ->
expect(displayBuffer.tokenizedLineForScreenRow(3).text).toBe ' var pivot = items.shift(), current, left = [], '
expect(displayBuffer.tokenizedLineForScreenRow(4).text).toBe 'right = [];'
expect(displayBuffer.tokenizedLineForScreenRow(4).text).toBe ' right = [];'
describe "when there are hard tabs", ->
beforeEach ->
@@ -115,6 +115,11 @@ describe "DisplayBuffer", ->
expect(displayBuffer.tokenizedLineForScreenRow(3).tokens[0].isHardTab).toBeTruthy()
expect(displayBuffer.tokenizedLineForScreenRow(3).tokens[1].isHardTab).toBeTruthy()
describe "when a line is wrapped", ->
it "correctly tokenizes soft wrap indentation tokens", ->
expect(displayBuffer.tokenizedLineForScreenRow(4).tokens[0].isSoftWrapIndentation).toBeTruthy()
expect(displayBuffer.tokenizedLineForScreenRow(4).tokens[1].isSoftWrapIndentation).toBeTruthy()
describe "when the buffer changes", ->
describe "when buffer lines are updated", ->
describe "when whitespace is added after the max line length", ->
@@ -138,8 +143,8 @@ describe "DisplayBuffer", ->
it "rewraps the line and emits a change event", ->
buffer.insert([6, 28], '1234567890')
expect(displayBuffer.tokenizedLineForScreenRow(7).text).toBe ' current < pivot ? '
expect(displayBuffer.tokenizedLineForScreenRow(8).text).toBe 'left1234567890.push(current) : '
expect(displayBuffer.tokenizedLineForScreenRow(9).text).toBe 'right.push(current);'
expect(displayBuffer.tokenizedLineForScreenRow(8).text).toBe ' left1234567890.push(current) : '
expect(displayBuffer.tokenizedLineForScreenRow(9).text).toBe ' right.push(current);'
expect(displayBuffer.tokenizedLineForScreenRow(10).text).toBe ' }'
expect(changeHandler).toHaveBeenCalledWith(start: 7, end: 8, screenDelta: 1, bufferDelta: 0)
@@ -148,7 +153,7 @@ describe "DisplayBuffer", ->
it "inserts / updates wrapped lines and emits a change event", ->
buffer.insert([6, 21], '1234567890 abcdefghij 1234567890\nabcdefghij')
expect(displayBuffer.tokenizedLineForScreenRow(7).text).toBe ' current < pivot1234567890 abcdefghij '
expect(displayBuffer.tokenizedLineForScreenRow(8).text).toBe '1234567890'
expect(displayBuffer.tokenizedLineForScreenRow(8).text).toBe ' 1234567890'
expect(displayBuffer.tokenizedLineForScreenRow(9).text).toBe 'abcdefghij ? left.push(current) : '
expect(displayBuffer.tokenizedLineForScreenRow(10).text).toBe 'right.push(current);'
@@ -159,7 +164,7 @@ describe "DisplayBuffer", ->
buffer.setTextInRange([[3, 21], [7, 5]], ';')
expect(displayBuffer.tokenizedLineForScreenRow(3).text).toBe ' var pivot = items;'
expect(displayBuffer.tokenizedLineForScreenRow(4).text).toBe ' return '
expect(displayBuffer.tokenizedLineForScreenRow(5).text).toBe 'sort(left).concat(pivot).concat(sort(right));'
expect(displayBuffer.tokenizedLineForScreenRow(5).text).toBe ' sort(left).concat(pivot).concat(sort(right));'
expect(displayBuffer.tokenizedLineForScreenRow(6).text).toBe ' };'
expect(changeHandler).toHaveBeenCalledWith(start: 3, end: 9, screenDelta: -6, bufferDelta: -4)
@@ -191,10 +196,10 @@ describe "DisplayBuffer", ->
expect(displayBuffer.bufferPositionForScreenPosition([3, 5])).toEqual([3, 5])
expect(displayBuffer.screenPositionForBufferPosition([3, 50])).toEqual([3, 50])
expect(displayBuffer.screenPositionForBufferPosition([3, 51])).toEqual([3, 50])
expect(displayBuffer.bufferPositionForScreenPosition([4, 0])).toEqual([3, 51])
expect(displayBuffer.bufferPositionForScreenPosition([4, 0])).toEqual([3, 50])
expect(displayBuffer.bufferPositionForScreenPosition([3, 50])).toEqual([3, 50])
expect(displayBuffer.screenPositionForBufferPosition([3, 62])).toEqual([4, 11])
expect(displayBuffer.bufferPositionForScreenPosition([4, 11])).toEqual([3, 62])
expect(displayBuffer.screenPositionForBufferPosition([3, 62])).toEqual([4, 15])
expect(displayBuffer.bufferPositionForScreenPosition([4, 11])).toEqual([3, 58])
# following a wrapped line
expect(displayBuffer.screenPositionForBufferPosition([4, 5])).toEqual([5, 5])
@@ -209,9 +214,9 @@ describe "DisplayBuffer", ->
describe ".setEditorWidthInChars(length)", ->
it "changes the length at which lines are wrapped and emits a change event for all screen lines", ->
displayBuffer.setEditorWidthInChars(40)
expect(tokensText displayBuffer.tokenizedLineForScreenRow(4).tokens).toBe 'left = [], right = [];'
expect(tokensText displayBuffer.tokenizedLineForScreenRow(4).tokens).toBe ' left = [], right = [];'
expect(tokensText displayBuffer.tokenizedLineForScreenRow(5).tokens).toBe ' while(items.length > 0) {'
expect(tokensText displayBuffer.tokenizedLineForScreenRow(12).tokens).toBe 'sort(left).concat(pivot).concat(sort(rig'
expect(tokensText displayBuffer.tokenizedLineForScreenRow(12).tokens).toBe ' sort(left).concat(pivot).concat(sort'
expect(changeHandler).toHaveBeenCalledWith(start: 0, end: 15, screenDelta: 3, bufferDelta: 0)
it "only allows positive widths to be assigned", ->
@@ -222,7 +227,7 @@ describe "DisplayBuffer", ->
it "sets ::scrollLeft to 0 and keeps it there when soft wrapping is enabled", ->
displayBuffer.setDefaultCharWidth(10)
displayBuffer.setWidth(50)
displayBuffer.setWidth(85)
displayBuffer.manageScrollPosition = true
displayBuffer.setSoftWrapped(false)
@@ -597,8 +602,8 @@ describe "DisplayBuffer", ->
describe "when wrapBeyondNewlines is false (the default)", ->
it "wraps positions beyond the end of hard newlines to the end of the line", ->
expect(displayBuffer.clipScreenPosition([1, 10000])).toEqual [1, 30]
expect(displayBuffer.clipScreenPosition([4, 30])).toEqual [4, 11]
expect(displayBuffer.clipScreenPosition([4, 1000])).toEqual [4, 11]
expect(displayBuffer.clipScreenPosition([4, 30])).toEqual [4, 15]
expect(displayBuffer.clipScreenPosition([4, 1000])).toEqual [4, 15]
describe "when wrapBeyondNewlines is true", ->
it "wraps positions past the end of hard newlines to the next line", ->
@@ -610,6 +615,18 @@ describe "DisplayBuffer", ->
displayBuffer.createFold(3, 5)
expect(displayBuffer.clipScreenPosition([3, 5], wrapBeyondNewlines: true)).toEqual [4, 0]
describe "when skipSoftWrapIndentation is false (the default)", ->
it "wraps positions at the end of previous soft-wrapped line", ->
expect(displayBuffer.clipScreenPosition([4, 0])).toEqual [3, 50]
expect(displayBuffer.clipScreenPosition([4, 1])).toEqual [3, 50]
expect(displayBuffer.clipScreenPosition([4, 3])).toEqual [3, 50]
describe "when skipSoftWrapIndentation is true", ->
it "clips positions to the beginning of the line", ->
expect(displayBuffer.clipScreenPosition([4, 0], skipSoftWrapIndentation: true)).toEqual [4, 4]
expect(displayBuffer.clipScreenPosition([4, 1], skipSoftWrapIndentation: true)).toEqual [4, 4]
expect(displayBuffer.clipScreenPosition([4, 3], skipSoftWrapIndentation: true)).toEqual [4, 4]
describe "when wrapAtSoftNewlines is false (the default)", ->
it "clips positions at the end of soft-wrapped lines to the character preceding the end of the line", ->
expect(displayBuffer.clipScreenPosition([3, 50])).toEqual [3, 50]
@@ -620,9 +637,9 @@ describe "DisplayBuffer", ->
describe "when wrapAtSoftNewlines is true", ->
it "wraps positions at the end of soft-wrapped lines to the next screen line", ->
expect(displayBuffer.clipScreenPosition([3, 50], wrapAtSoftNewlines: true)).toEqual [3, 50]
expect(displayBuffer.clipScreenPosition([3, 51], wrapAtSoftNewlines: true)).toEqual [4, 0]
expect(displayBuffer.clipScreenPosition([3, 58], wrapAtSoftNewlines: true)).toEqual [4, 0]
expect(displayBuffer.clipScreenPosition([3, 1000], wrapAtSoftNewlines: true)).toEqual [4, 0]
expect(displayBuffer.clipScreenPosition([3, 51], wrapAtSoftNewlines: true)).toEqual [4, 4]
expect(displayBuffer.clipScreenPosition([3, 58], wrapAtSoftNewlines: true)).toEqual [4, 4]
expect(displayBuffer.clipScreenPosition([3, 1000], wrapAtSoftNewlines: true)).toEqual [4, 4]
describe "when skipAtomicTokens is false (the default)", ->
it "clips screen positions in the middle of atomic tab characters to the beginning of the character", ->
@@ -655,8 +672,8 @@ describe "DisplayBuffer", ->
buffer.setText('\t\taa bb cc dd ee ff gg')
displayBuffer.setSoftWrapped(true)
displayBuffer.setEditorWidthInChars(10)
expect(displayBuffer.screenPositionForBufferPosition([0, 10], wrapAtSoftNewlines: true)).toEqual [1, 0]
expect(displayBuffer.bufferPositionForScreenPosition([1, 0])).toEqual [0, 10]
expect(displayBuffer.screenPositionForBufferPosition([0, 10], wrapAtSoftNewlines: true)).toEqual [1, 4]
expect(displayBuffer.bufferPositionForScreenPosition([1, 0])).toEqual [0, 9]
describe "::getMaxLineLength()", ->
it "returns the length of the longest screen line", ->

View File

@@ -0,0 +1 @@
module.exports = {}

View File

@@ -0,0 +1,4 @@
{
"name": "package-with-no-activate",
"version": "1.0.0"
}

View File

@@ -220,6 +220,17 @@ describe "PackageManager", ->
expect(console.error).not.toHaveBeenCalled()
expect(console.warn).not.toHaveBeenCalled()
describe "when the package does not export an activate function", ->
it "activates the package and does not throw an exception or log a warning", ->
spyOn(console, "warn")
expect(-> atom.packages.activatePackage('package-with-no-activate')).not.toThrow()
waitsFor ->
atom.packages.isPackageActive('package-with-no-activate')
runs ->
expect(console.warn).not.toHaveBeenCalled()
it "passes the activate method the package's previously serialized state if it exists", ->
pack = null
waitsForPromise ->

View File

@@ -1171,6 +1171,14 @@ describe "TextEditorComponent", ->
regions = componentNode.querySelectorAll('.test-highlight .region')
expect(regions.length).toBe 2
it "allows multiple space-delimited decoration classes", ->
decoration.setProperties(type: 'highlight', class: 'foo bar')
nextAnimationFrame()
expect(componentNode.querySelectorAll('.foo.bar').length).toBe 1
decoration.setProperties(type: 'highlight', class: 'bar baz')
nextAnimationFrame()
expect(componentNode.querySelectorAll('.bar.baz').length).toBe 1
it "renders classes on the regions directly if 'deprecatedRegionClass' option is defined", ->
decoration = editor.decorateMarker(marker, type: 'highlight', class: 'test-highlight', deprecatedRegionClass: 'test-highlight-region')
nextAnimationFrame()

View File

@@ -287,7 +287,7 @@ describe "TextEditor", ->
it "positions the cursor at the buffer position that corresponds to the given screen position", ->
editor.setCursorScreenPosition([9, 0])
expect(editor.getCursorBufferPosition()).toEqual [8, 11]
expect(editor.getCursorBufferPosition()).toEqual [8, 10]
describe ".moveUp()", ->
it "moves the cursor up", ->
@@ -334,6 +334,17 @@ describe "TextEditor", ->
expect(editor.getCursors()).toEqual [cursor1]
expect(cursor1.getBufferPosition()).toEqual [0,0]
describe "when the cursor was moved down from the beginning of an indented soft-wrapped line", ->
it "moves to the beginning of the previous line", ->
editor.setSoftWrapped(true)
editor.setEditorWidthInChars(50)
editor.setCursorScreenPosition([3, 0])
editor.moveDown()
editor.moveDown()
editor.moveUp()
expect(editor.getCursorScreenPosition()).toEqual [4, 4]
describe ".moveDown()", ->
it "moves the cursor down", ->
editor.setCursorScreenPosition([2, 2])
@@ -375,6 +386,16 @@ describe "TextEditor", ->
editor.moveUp()
expect(editor.getCursorScreenPosition().column).toBe 0
describe "when the cursor is at the beginning of an indented soft-wrapped line", ->
it "moves to the beginning of the line's continuation on the next screen row", ->
editor.setSoftWrapped(true)
editor.setEditorWidthInChars(50)
editor.setCursorScreenPosition([3, 0])
editor.moveDown()
expect(editor.getCursorScreenPosition()).toEqual [4, 4]
describe "when there is a selection", ->
beforeEach ->
editor.setSelectedBufferRange([[4, 9],[5, 10]])
@@ -432,6 +453,16 @@ describe "TextEditor", ->
editor.moveLeft()
expect(editor.getCursorScreenPosition()).toEqual [10, 0]
describe "when line is wrapped and follow previous line indentation", ->
beforeEach ->
editor.setSoftWrapped(true)
editor.setEditorWidthInChars(50)
it "wraps to the end of the previous line", ->
editor.setCursorScreenPosition([4, 4])
editor.moveLeft()
expect(editor.getCursorScreenPosition()).toEqual [3, 50]
describe "when the cursor is on the first line", ->
it "remains in the same position (0,0)", ->
editor.setCursorScreenPosition(row: 0, column: 0)
@@ -628,11 +659,11 @@ describe "TextEditor", ->
editor.moveToFirstCharacterOfLine()
[cursor1, cursor2] = editor.getCursors()
expect(cursor1.getScreenPosition()).toEqual [2,0]
expect(cursor2.getScreenPosition()).toEqual [8,4]
expect(cursor2.getScreenPosition()).toEqual [8,2]
editor.moveToFirstCharacterOfLine()
expect(cursor1.getScreenPosition()).toEqual [2,0]
expect(cursor2.getScreenPosition()).toEqual [8,0]
expect(cursor2.getScreenPosition()).toEqual [8,2]
describe "when soft wrap is off", ->
it "moves to the first character of the current line or the beginning of the line if it's already on the first character", ->

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