Ensure line wrapping interacts cleanly with folding

This commit is contained in:
Nathan Sobo
2012-03-05 19:15:03 -07:00
parent ed13a27821
commit c61510ce99
2 changed files with 38 additions and 14 deletions

View File

@@ -42,8 +42,20 @@ describe "Renderer", ->
expect(renderer.lineForRow(4).text).toBe 'right = [];'
describe "when there is a fold placeholder straddling the max length boundary", ->
it "wraps the line before the fold placeholder", ->
renderer.createFold([[3, 49], [6, 1]])
fdescribe "folding", ->
expect(renderer.lineForRow(3).text).toBe ' var pivot = items.shift(), current, left = []'
expect(renderer.lineForRow(4).text).toBe '... current < pivot ? left.push(current) : '
expect(renderer.lineForRow(5).text).toBe 'right.push(current);'
expect(renderer.lineForRow(6).text).toBe ' }'
renderer.createFold([[6, 56], [8, 15]])
expect(renderer.lineForRow(6).text).toBe 'right.push(...(left).concat(pivot).concat(sort(rig'
expect(renderer.lineForRow(7).text).toBe 'ht));'
expect(renderer.lineForRow(8).text).toBe ' };'
describe "folding", ->
describe "when folds are created and destroyed", ->
describe "when a fold spans multiple lines", ->
it "replaces the lines spanned by the fold with a single line containing a placeholder", ->
@@ -112,7 +124,7 @@ describe "Renderer", ->
expect(line5.text).toBe ' current = items.shift();'
expect(renderer.lineForRow(8).text).toBe ' r... sort(left).concat(pivot).concat(sort(right));'
fit "allows the outer fold to start at the same location as the inner fold", ->
it "allows the outer fold to start at the same location as the inner fold", ->
renderer.createFold([[4, 29], [7, 4]])
renderer.createFold([[4, 29], [9, 2]])
expect(renderer.lineForRow(4).text).toBe " while(items.length > 0) {...};"

View File

@@ -43,11 +43,16 @@ class Renderer
fold = new Fold(this, bufferRange)
@registerFold(bufferRange.start.row, fold)
oldScreenRange = @expandScreenRangeToLineEnds(@screenRangeForBufferRange(bufferRange))
oldScreenRange =
@expandScreenRangeToLineEnds(
@screenRangeForBufferRange(
@expandBufferRangeToLineEnds(bufferRange)))
lines = @buildLineForBufferRow(bufferRange.start.row)
@lineMap.replaceOutputRows(
oldScreenRange.start.row,
oldScreenRange.end.row,
@buildLineForBufferRow(bufferRange.start.row))
lines)
newScreenRange = @expandScreenRangeToLineEnds(
new Range(_.clone(oldScreenRange.start), _.clone(oldScreenRange.start)))
@@ -84,20 +89,23 @@ class Renderer
@buildLinesForBufferRows(bufferRow, bufferRow)
buildLinesForBufferRows: (startRow, endRow) ->
buildLinesForBufferRows = (startRow, endRow, startColumn) =>
buildLinesForBufferRows = (startRow, endRow, startColumn, currentScreenLineLength=0) =>
return [] if startRow > endRow and not startColumn?
startColumn ?= 0
line = @highlighter.lineForRow(startRow).splitAt(startColumn)[1]
wrapColumn = @findWrapColumn(line.text)
wrapColumn = @findWrapColumn(line.text, @maxLineLength - currentScreenLineLength)
for fold in @foldsForBufferRow(startRow)
if fold.start.column >= startColumn
break if fold.start.column > wrapColumn - foldPlaceholderLength
if fold.start.column > wrapColumn - foldPlaceholderLength
wrapColumn = Math.min(wrapColumn, fold.start.column)
break
prefix = line.splitAt(fold.start.column - startColumn)[0]
placeholder = @buildFoldPlaceholder(fold)
suffix = buildLinesForBufferRows(fold.end.row, endRow, fold.end.column)
currentScreenLineLength = currentScreenLineLength + (prefix?.text.length ? 0) + foldPlaceholderLength
suffix = buildLinesForBufferRows(fold.end.row, endRow, fold.end.column, currentScreenLineLength)
return _.compact _.flatten [prefix, placeholder, suffix]
if wrapColumn
@@ -112,19 +120,19 @@ class Renderer
foldStartRowForBufferRow: (bufferRow) ->
@bufferRowForScreenRow(@screenRowForBufferRow(bufferRow))
findWrapColumn: (line) ->
return unless line.length > @maxLineLength
findWrapColumn: (line, maxLineLength) ->
return unless line.length > maxLineLength
if /\s/.test(line[@maxLineLength])
if /\s/.test(line[maxLineLength])
# search forward for the start of a word past the boundary
for column in [@maxLineLength..line.length]
for column in [maxLineLength..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 [@maxLineLength..0]
for column in [maxLineLength..0]
return column + 1 if /\s/.test(line[column])
return @maxLineLength
return maxLineLength
registerFold: (bufferRow, fold) ->
@activeFolds[bufferRow] ?= []
@@ -148,4 +156,8 @@ class Renderer
{ start, end } = screenRange
new Range([start.row, 0], [end.row, @lineMap.lineForOutputRow(end.row).text.length])
expandBufferRangeToLineEnds: (bufferRange) ->
{ start, end } = bufferRange
new Range([start.row, 0], [end.row, @lineMap.lineForInputRow(end.row).text.length])
_.extend Renderer.prototype, EventEmitter