mirror of
https://github.com/atom/atom.git
synced 2026-02-09 06:05:11 -05:00
WIP: Add a LineWrapper object
Only passing specs are focused. Everything is still broken. Editor uses the line wrapper to render lines, but the line wrapper isn't updating on buffer change events yet. Still moving vertically and clipping positions based on unwrapped lines as well.
This commit is contained in:
@@ -4,6 +4,7 @@ Point = require 'point'
|
||||
Cursor = require 'cursor'
|
||||
Selection = require 'selection'
|
||||
Highlighter = require 'highlighter'
|
||||
LineWrapper = require 'line-wrapper'
|
||||
UndoManager = require 'undo-manager'
|
||||
Range = require 'range'
|
||||
|
||||
@@ -20,12 +21,14 @@ class Editor extends View
|
||||
vScrollMargin: 2
|
||||
hScrollMargin: 10
|
||||
softWrap: false
|
||||
cursor: null
|
||||
buffer: null
|
||||
undoManager: null
|
||||
selection: null
|
||||
lineHeight: null
|
||||
charWidth: null
|
||||
cursor: null
|
||||
selection: null
|
||||
buffer: null
|
||||
highlighter: null
|
||||
lineWrapper: null
|
||||
undoManager: null
|
||||
|
||||
initialize: () ->
|
||||
requireStylesheet 'editor.css'
|
||||
@@ -111,26 +114,8 @@ class Editor extends View
|
||||
@on 'mousemove', moveHandler
|
||||
$(document).one 'mouseup', => @off 'mousemove', moveHandler
|
||||
|
||||
|
||||
buildLineElement: (row) ->
|
||||
maxSegmentLength =
|
||||
if @softWrap
|
||||
Math.floor(@width() / @charWidth)
|
||||
else
|
||||
Infinity
|
||||
currentSegmentLength = 0
|
||||
currentSegment = []
|
||||
segments = [currentSegment]
|
||||
|
||||
for token in @highlighter.tokensForRow(row)
|
||||
if (currentSegmentLength + token.value.length) <= maxSegmentLength
|
||||
currentSegmentLength += token.value.length
|
||||
currentSegment.push(token)
|
||||
else
|
||||
currentSegment = [token]
|
||||
currentSegmentLength = token.value.length
|
||||
segments.push(currentSegment)
|
||||
|
||||
segments = @lineWrapper.segmentsForRow(row)
|
||||
$$ ->
|
||||
for segment in segments
|
||||
@pre class: 'line', =>
|
||||
@@ -148,6 +133,7 @@ class Editor extends View
|
||||
|
||||
setBuffer: (@buffer) ->
|
||||
@highlighter = new Highlighter(@buffer)
|
||||
@lineWrapper = new LineWrapper(Infinity, @highlighter)
|
||||
@undoManager = new UndoManager(@buffer)
|
||||
@renderLines()
|
||||
@setCursorPosition(row: 0, column: 0)
|
||||
@@ -186,6 +172,13 @@ class Editor extends View
|
||||
@lines.find("pre.line:eq(#{row})")
|
||||
|
||||
setSoftWrap: (@softWrap) ->
|
||||
maxLength =
|
||||
if @softWrap
|
||||
Math.floor(@width() / @charWidth)
|
||||
else
|
||||
infinity
|
||||
|
||||
@lineWrapper.setMaxLength(maxLength)
|
||||
@renderLines()
|
||||
|
||||
clipPosition: ({row, column}) ->
|
||||
@@ -199,7 +192,17 @@ class Editor extends View
|
||||
new Point(row, column)
|
||||
|
||||
pixelPositionFromPoint: ({row, column}) ->
|
||||
{ top: row * @lineHeight, left: column * @charWidth }
|
||||
segmentsAbove = 0
|
||||
segmentsAbove += @lineWrapper.segmentsForRow(i).length for i in [0...row]
|
||||
|
||||
for segment in @lineWrapper.segmentsForRow(row)
|
||||
if column > segment.lastIndex
|
||||
segmentsAbove++
|
||||
column -= segment.textLength
|
||||
else
|
||||
break
|
||||
|
||||
{ top: segmentsAbove * @lineHeight, left: column * @charWidth }
|
||||
|
||||
pointFromPixelPosition: ({top, left}) ->
|
||||
{ row: Math.floor(top / @lineHeight), column: Math.floor(left / @charWidth) }
|
||||
|
||||
52
src/atom/line-wrapper.coffee
Normal file
52
src/atom/line-wrapper.coffee
Normal file
@@ -0,0 +1,52 @@
|
||||
getWordRegex = -> /\b[^\s]+/g
|
||||
|
||||
module.exports =
|
||||
class LineWrapper
|
||||
constructor: (@maxLength, @highlighter) ->
|
||||
@buffer = @highlighter.buffer
|
||||
@segmentBuffer()
|
||||
|
||||
setMaxLength: (@maxLength) ->
|
||||
@segmentBuffer()
|
||||
|
||||
segmentBuffer: ->
|
||||
@lines = @segmentRows(0, @buffer.lastRow())
|
||||
|
||||
segmentsForRow: (row) ->
|
||||
@lines[row]
|
||||
|
||||
segmentRows: (start, end) ->
|
||||
for row in [start..end]
|
||||
@segmentRow(row)
|
||||
|
||||
segmentRow: (row) ->
|
||||
wordRegex = getWordRegex()
|
||||
line = @buffer.getLine(row)
|
||||
|
||||
breakIndices = []
|
||||
lastBreakIndex = 0
|
||||
|
||||
while match = wordRegex.exec(line)
|
||||
startIndex = match.index
|
||||
endIndex = startIndex + match[0].length
|
||||
if endIndex - lastBreakIndex > @maxLength
|
||||
breakIndices.push(startIndex)
|
||||
lastBreakIndex = startIndex
|
||||
|
||||
currentSegment = []
|
||||
currentSegment.lastIndex = 0
|
||||
segments = [currentSegment]
|
||||
nextBreak = breakIndices.shift()
|
||||
for token in @highlighter.tokensForRow(row)
|
||||
if currentSegment.lastIndex >= nextBreak
|
||||
nextBreak = breakIndices.shift()
|
||||
newSegment = []
|
||||
newSegment.lastIndex = currentSegment.lastIndex
|
||||
newSegment.textLength = 0
|
||||
segments.push(newSegment)
|
||||
currentSegment = newSegment
|
||||
currentSegment.push token
|
||||
currentSegment.lastIndex += token.value.length
|
||||
currentSegment.textLength += token.value.length
|
||||
|
||||
segments
|
||||
Reference in New Issue
Block a user