mirror of
https://github.com/pulsar-edit/pulsar.git
synced 2024-09-20 07:28:08 +03:00
Start basing Buffer's text on a replicable string
This commit is contained in:
parent
010c3435da
commit
dd0f7a032f
21
spec/app/text-buffer-replication-spec.coffee
Normal file
21
spec/app/text-buffer-replication-spec.coffee
Normal file
@ -0,0 +1,21 @@
|
||||
{createSite} = require 'telepath'
|
||||
TextBuffer = require 'text-buffer'
|
||||
|
||||
describe "TextBuffer replication", ->
|
||||
[buffer1, buffer2] = []
|
||||
|
||||
beforeEach ->
|
||||
buffer1 = new TextBuffer(project.resolve('sample.js'))
|
||||
buffer1.insert([0, 0], 'changed\n')
|
||||
doc1 = buffer1.getState()
|
||||
doc2 = doc1.clone(createSite(2))
|
||||
doc1.connect(doc2)
|
||||
buffer2 = deserialize(doc2)
|
||||
|
||||
afterEach ->
|
||||
buffer1.destroy()
|
||||
buffer2.destroy()
|
||||
|
||||
it "replicates the initial path and text of the buffer", ->
|
||||
expect(buffer2.getPath()).toBe buffer1.getPath()
|
||||
expect(buffer2.getText()).toBe buffer1.getText()
|
@ -1,4 +1,4 @@
|
||||
Range = require 'range'
|
||||
{Range} = require 'telepath'
|
||||
_ = require 'underscore'
|
||||
|
||||
### Internal ###
|
||||
@ -22,7 +22,7 @@ class BufferChangeOperation
|
||||
@markersToRestoreOnUndo = @invalidateMarkers(@oldRange)
|
||||
if @oldRange?
|
||||
@oldText = @buffer.getTextInRange(@oldRange)
|
||||
@newRange = @calculateNewRange(@oldRange, @newText)
|
||||
@newRange = Range.fromText(@oldRange.start, @newText)
|
||||
newRange = @changeBuffer
|
||||
oldRange: @oldRange
|
||||
newRange: @newRange
|
||||
@ -47,37 +47,9 @@ class BufferChangeOperation
|
||||
@buffer.resumeEvents()
|
||||
@resumeMarkerObservation()
|
||||
|
||||
splitLines: (text) ->
|
||||
lines = text.split('\n')
|
||||
lineEndings = []
|
||||
for line, index in lines
|
||||
if _.endsWith(line, '\r')
|
||||
lines[index] = line[...-1]
|
||||
lineEndings[index] = '\r\n'
|
||||
else
|
||||
lineEndings[index] = '\n'
|
||||
{lines, lineEndings}
|
||||
|
||||
changeBuffer: ({ oldRange, newRange, newText, oldText }) ->
|
||||
{ prefix, suffix } = @buffer.prefixAndSuffixForRange(oldRange)
|
||||
{lines, lineEndings} = @splitLines(newText)
|
||||
lastLineIndex = lines.length - 1
|
||||
@buffer.text.change(oldRange, newText)
|
||||
|
||||
if lines.length == 1
|
||||
lines = [prefix + newText + suffix]
|
||||
else
|
||||
lines[0] = prefix + lines[0]
|
||||
lines[lastLineIndex] += suffix
|
||||
|
||||
startRow = oldRange.start.row
|
||||
endRow = oldRange.end.row
|
||||
|
||||
normalizeLineEndings = @options.normalizeLineEndings ? true
|
||||
if normalizeLineEndings and suggestedLineEnding = @buffer.suggestedLineEndingForRow(startRow)
|
||||
lineEndings[index] = suggestedLineEnding for index in [0..lastLineIndex]
|
||||
|
||||
_.spliceWithArray(@buffer.lines, startRow, endRow - startRow + 1, lines)
|
||||
_.spliceWithArray(@buffer.lineEndings, startRow, endRow - startRow + 1, lineEndings)
|
||||
@buffer.cachedMemoryContents = null
|
||||
@buffer.conflict = false if @buffer.conflict and !@buffer.isModified()
|
||||
|
||||
@ -88,17 +60,6 @@ class BufferChangeOperation
|
||||
|
||||
newRange
|
||||
|
||||
calculateNewRange: (oldRange, newText) ->
|
||||
newRange = new Range(oldRange.start.copy(), oldRange.start.copy())
|
||||
{lines} = @splitLines(newText)
|
||||
if lines.length == 1
|
||||
newRange.end.column += newText.length
|
||||
else
|
||||
lastLineIndex = lines.length - 1
|
||||
newRange.end.row += lastLineIndex
|
||||
newRange.end.column = lines[lastLineIndex].length
|
||||
newRange
|
||||
|
||||
invalidateMarkers: (oldRange) ->
|
||||
@buffer.getMarkers().map (marker) -> marker.tryToInvalidate(oldRange)
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
_ = require 'underscore'
|
||||
telepath = require 'telepath'
|
||||
fsUtils = require 'fs-utils'
|
||||
File = require 'file'
|
||||
Point = require 'point'
|
||||
@ -14,16 +15,19 @@ BufferMarker = require 'buffer-marker'
|
||||
# the case, as a `Buffer` could be an unsaved chunk of text.
|
||||
module.exports =
|
||||
class TextBuffer
|
||||
@acceptsDocuments: true
|
||||
@idCounter = 1
|
||||
registerDeserializer(this)
|
||||
|
||||
@deserialize: (state) ->
|
||||
new TextBuffer(state)
|
||||
|
||||
stoppedChangingDelay: 300
|
||||
stoppedChangingTimeout: null
|
||||
undoManager: null
|
||||
cachedDiskContents: null
|
||||
cachedMemoryContents: null
|
||||
conflict: false
|
||||
lines: null
|
||||
lineEndings: null
|
||||
file: null
|
||||
validMarkers: null
|
||||
invalidMarkers: null
|
||||
@ -33,13 +37,20 @@ class TextBuffer
|
||||
#
|
||||
# path - A {String} representing the file path
|
||||
# initialText - A {String} setting the starting text
|
||||
constructor: (path, initialText) ->
|
||||
constructor: (args...) ->
|
||||
@id = @constructor.idCounter++
|
||||
@nextMarkerId = 1
|
||||
@validMarkers = {}
|
||||
@invalidMarkers = {}
|
||||
@lines = ['']
|
||||
@lineEndings = []
|
||||
|
||||
if args[0] instanceof telepath.Document
|
||||
@state = args[0]
|
||||
@text = @state.get('text')
|
||||
path = @state.get('path')
|
||||
else
|
||||
[path, initialText] = args
|
||||
@text = telepath.Document.create('', shareStrings: true)
|
||||
@state = telepath.Document.create(deserializer: @constructor.name, text: @text)
|
||||
|
||||
if path
|
||||
@setPath(path)
|
||||
@ -72,15 +83,8 @@ class TextBuffer
|
||||
@destroy() if @refcount <= 0
|
||||
this
|
||||
|
||||
serialize: ->
|
||||
deserializer: 'TextBuffer'
|
||||
path: @getPath()
|
||||
text: @getText() if @isModified()
|
||||
|
||||
getState: -> @serialize()
|
||||
|
||||
@deserialize: ({path, text}) ->
|
||||
new TextBuffer(path, text)
|
||||
serialize: -> @state
|
||||
getState: -> @state
|
||||
|
||||
subscribeToFile: ->
|
||||
@file.on "contents-changed", =>
|
||||
@ -146,6 +150,8 @@ class TextBuffer
|
||||
@file.read() if @file.exists()
|
||||
@subscribeToFile()
|
||||
|
||||
@state.set('path', path)
|
||||
|
||||
@trigger "path-changed", this
|
||||
|
||||
# Retrieves the current buffer's file extension.
|
||||
@ -181,25 +187,13 @@ class TextBuffer
|
||||
#
|
||||
# Returns a {String} of the combined lines.
|
||||
getTextInRange: (range) ->
|
||||
range = @clipRange(range)
|
||||
if range.start.row == range.end.row
|
||||
return @lineForRow(range.start.row)[range.start.column...range.end.column]
|
||||
|
||||
multipleLines = []
|
||||
multipleLines.push @lineForRow(range.start.row)[range.start.column..] # first line
|
||||
multipleLines.push @lineEndingForRow(range.start.row)
|
||||
for row in [range.start.row + 1...range.end.row]
|
||||
multipleLines.push @lineForRow(row) # middle lines
|
||||
multipleLines.push @lineEndingForRow(row)
|
||||
multipleLines.push @lineForRow(range.end.row)[0...range.end.column] # last line
|
||||
|
||||
return multipleLines.join ''
|
||||
@text.getTextInRange(@clipRange(range))
|
||||
|
||||
# Gets all the lines in a file.
|
||||
#
|
||||
# Returns an {Array} of {String}s.
|
||||
getLines: ->
|
||||
@lines
|
||||
@text.getLines()
|
||||
|
||||
# Given a row, returns the line of text.
|
||||
#
|
||||
@ -207,7 +201,7 @@ class TextBuffer
|
||||
#
|
||||
# Returns a {String}.
|
||||
lineForRow: (row) ->
|
||||
@lines[row]
|
||||
@text.lineForRow(row)
|
||||
|
||||
# Given a row, returns its line ending.
|
||||
#
|
||||
@ -215,7 +209,7 @@ class TextBuffer
|
||||
#
|
||||
# Returns a {String}, or `undefined` if `row` is the final row.
|
||||
lineEndingForRow: (row) ->
|
||||
@lineEndings[row] unless row is @getLastRow()
|
||||
@text.lineEndingForRow(row)
|
||||
|
||||
suggestedLineEndingForRow: (row) ->
|
||||
@lineEndingForRow(row) ? @lineEndingForRow(row - 1)
|
||||
@ -226,7 +220,7 @@ class TextBuffer
|
||||
#
|
||||
# Returns a {Number}.
|
||||
lineLengthForRow: (row) ->
|
||||
@lines[row].length
|
||||
@text.lineLengthForRow(row)
|
||||
|
||||
# Given a row, returns the length of the line ending
|
||||
#
|
||||
@ -253,13 +247,13 @@ class TextBuffer
|
||||
#
|
||||
# Returns a {Number}.
|
||||
getLineCount: ->
|
||||
@getLines().length
|
||||
@text.getLineCount()
|
||||
|
||||
# Gets the row number of the last line.
|
||||
#
|
||||
# Returns a {Number}.
|
||||
getLastRow: ->
|
||||
@getLines().length - 1
|
||||
@getLineCount() - 1
|
||||
|
||||
# Finds the last line in the current buffer.
|
||||
#
|
||||
@ -275,20 +269,10 @@ class TextBuffer
|
||||
new Point(lastRow, @lineLengthForRow(lastRow))
|
||||
|
||||
characterIndexForPosition: (position) ->
|
||||
position = @clipPosition(position)
|
||||
|
||||
index = 0
|
||||
for row in [0...position.row]
|
||||
index += @lineLengthForRow(row) + Math.max(@lineEndingLengthForRow(row), 1)
|
||||
index + position.column
|
||||
@text.indexForPoint(position)
|
||||
|
||||
positionForCharacterIndex: (index) ->
|
||||
row = 0
|
||||
while index >= (lineLength = @lineLengthForRow(row) + Math.max(@lineEndingLengthForRow(row), 1))
|
||||
index -= lineLength
|
||||
row++
|
||||
|
||||
new Point(row, index)
|
||||
@text.pointForIndex(index)
|
||||
|
||||
# Given a row, this deletes it from the buffer.
|
||||
#
|
||||
@ -365,10 +349,6 @@ class TextBuffer
|
||||
range = Range.fromObject(range)
|
||||
new Range(@clipPosition(range.start), @clipPosition(range.end))
|
||||
|
||||
prefixAndSuffixForRange: (range) ->
|
||||
prefix: @lines[range.start.row][0...range.start.column]
|
||||
suffix: @lines[range.end.row][range.end.column..]
|
||||
|
||||
# Undos the last operation.
|
||||
#
|
||||
# editSession - The {EditSession} associated with the buffer.
|
||||
@ -413,7 +393,7 @@ class TextBuffer
|
||||
# Identifies if a buffer is empty.
|
||||
#
|
||||
# Returns a {Boolean}.
|
||||
isEmpty: -> @lines.length is 1 and @lines[0].length is 0
|
||||
isEmpty: -> @text.isEmpty()
|
||||
|
||||
# Returns all valid {BufferMarker}s on the buffer.
|
||||
getMarkers: ({includeInvalid} = {}) ->
|
||||
|
2
vendor/telepath
vendored
2
vendor/telepath
vendored
@ -1 +1 @@
|
||||
Subproject commit 3b465ef7e08c188621e3a30817650fbea38d3656
|
||||
Subproject commit 6e7b122559024b32156e11cf8bb53cf810228a19
|
Loading…
Reference in New Issue
Block a user