Implement basic large file mode for editor

* Don’t tokenize
* Don’t build metadata to support folds and soft wraps

Remaining issues:

* Max line length is hard coded
* Foldable indicators should be disabled
* Folding via API should be disallowed
This commit is contained in:
Nathan Sobo
2015-06-05 02:25:57 +02:00
parent 5b494b7b17
commit de508db9b2
4 changed files with 65 additions and 28 deletions

View File

@@ -24,13 +24,13 @@ class DisplayBuffer extends Model
horizontalScrollMargin: 6
scopedCharacterWidthsChangeCount: 0
constructor: ({tabLength, @editorWidthInChars, @tokenizedBuffer, buffer, ignoreInvisibles}={}) ->
constructor: ({tabLength, @editorWidthInChars, @tokenizedBuffer, buffer, ignoreInvisibles, @largeFileMode}={}) ->
super
@emitter = new Emitter
@disposables = new CompositeDisposable
@tokenizedBuffer ?= new TokenizedBuffer({tabLength, buffer, ignoreInvisibles})
@tokenizedBuffer ?= new TokenizedBuffer({tabLength, buffer, ignoreInvisibles, @largeFileMode})
@buffer = @tokenizedBuffer.buffer
@charWidthsByScope = {}
@markers = {}
@@ -478,7 +478,10 @@ class DisplayBuffer extends Model
#
# Returns {TokenizedLine}
tokenizedLineForScreenRow: (screenRow) ->
@screenLines[screenRow]
if @largeFileMode
@tokenizedBuffer.tokenizedLineForRow(screenRow)
else
@screenLines[screenRow]
# Gets the screen lines for the given screen row range.
#
@@ -487,13 +490,19 @@ class DisplayBuffer extends Model
#
# Returns an {Array} of {TokenizedLine}s.
tokenizedLinesForScreenRows: (startRow, endRow) ->
@screenLines[startRow..endRow]
if @largeFileMode
@tokenizedBuffer.tokenizedLinesForRows(startRow, endRow)
else
@screenLines[startRow..endRow]
# Gets all the screen lines.
#
# Returns an {Array} of {TokenizedLine}s.
getTokenizedLines: ->
new Array(@screenLines...)
if @largeFileMode
@tokenizedBuffer.tokenizedLinesForRows(0, @getLastRow())
else
new Array(@screenLines...)
indentLevelForLine: (line) ->
@tokenizedBuffer.indentLevelForLine(line)
@@ -506,8 +515,11 @@ class DisplayBuffer extends Model
#
# Returns an {Array} of buffer rows as {Numbers}s.
bufferRowsForScreenRows: (startScreenRow, endScreenRow) ->
for screenRow in [startScreenRow..endScreenRow]
@rowMap.bufferRowRangeForScreenRow(screenRow)[0]
if @largeFileMode
[startScreenRow..endScreenRow]
else
for screenRow in [startScreenRow..endScreenRow]
@rowMap.bufferRowRangeForScreenRow(screenRow)[0]
# Creates a new fold between two row numbers.
#
@@ -611,10 +623,16 @@ class DisplayBuffer extends Model
#
# Returns a {Number}.
screenRowForBufferRow: (bufferRow) ->
@rowMap.screenRowRangeForBufferRow(bufferRow)[0]
if @largeFileMode
bufferRow
else
@rowMap.screenRowRangeForBufferRow(bufferRow)[0]
lastScreenRowForBufferRow: (bufferRow) ->
@rowMap.screenRowRangeForBufferRow(bufferRow)[1] - 1
if @largeFileMode
bufferRow
else
@rowMap.screenRowRangeForBufferRow(bufferRow)[1] - 1
# Given a screen row, this converts it into a buffer row.
#
@@ -622,7 +640,10 @@ class DisplayBuffer extends Model
#
# Returns a {Number}.
bufferRowForScreenRow: (screenRow) ->
@rowMap.bufferRowRangeForScreenRow(screenRow)[0]
if @largeFileMode
screenRow
else
@rowMap.bufferRowRangeForScreenRow(screenRow)[0]
# Given a buffer range, this converts it into a screen position.
#
@@ -724,7 +745,10 @@ class DisplayBuffer extends Model
#
# Returns a {Number}.
getLineCount: ->
@screenLines.length
if @largeFileMode
@tokenizedBuffer.getLineCount()
else
@screenLines.length
# Gets the number of the last screen line.
#
@@ -736,13 +760,19 @@ class DisplayBuffer extends Model
#
# Returns a {Number}.
getMaxLineLength: ->
@maxLineLength
if @largeFileMode
100
else
@maxLineLength
# Gets the row number of the longest screen line.
#
# Return a {}
getLongestScreenRow: ->
@longestScreenRow
if @largeFileMode
0
else
@longestScreenRow
# Given a buffer position, this converts it into a screen position.
#
@@ -759,7 +789,7 @@ class DisplayBuffer extends Model
{row, column} = @buffer.clipPosition(bufferPosition)
[startScreenRow, endScreenRow] = @rowMap.screenRowRangeForBufferRow(row)
for screenRow in [startScreenRow...endScreenRow]
screenLine = @screenLines[screenRow]
screenLine = @tokenizedLineForScreenRow(screenRow)
unless screenLine?
throw new BufferToScreenConversionError "No screen line exists when converting buffer row to screen row",
@@ -792,7 +822,7 @@ class DisplayBuffer extends Model
bufferPositionForScreenPosition: (screenPosition, options) ->
{row, column} = @clipScreenPosition(Point.fromObject(screenPosition), options)
[bufferRow] = @rowMap.bufferRowRangeForScreenRow(row)
new Point(bufferRow, @screenLines[row].bufferColumnForScreenColumn(column))
new Point(bufferRow, @tokenizedLineForScreenRow(row).bufferColumnForScreenColumn(column))
# Retrieves the grammar's token scopeDescriptor for a buffer position.
#
@@ -856,13 +886,13 @@ class DisplayBuffer extends Model
else if column < 0
column = 0
screenLine = @screenLines[row]
screenLine = @tokenizedLineForScreenRow(row)
maxScreenColumn = screenLine.getMaxScreenColumn()
if screenLine.isSoftWrapped() and column >= maxScreenColumn
if wrapAtSoftNewlines
row++
column = @screenLines[row].clipScreenColumn(0)
column = @tokenizedLineForScreenRow(row).clipScreenColumn(0)
else
column = screenLine.clipScreenColumn(maxScreenColumn - 1)
else if screenLine.isColumnInsideSoftWrapIndentation(column)
@@ -870,7 +900,7 @@ class DisplayBuffer extends Model
column = screenLine.clipScreenColumn(0)
else
row--
column = @screenLines[row].getMaxScreenColumn() - 1
column = @tokenizedLineForScreenRow(row).getMaxScreenColumn() - 1
else if wrapBeyondNewlines and column > maxScreenColumn and row < @getLastRow()
row++
column = 0
@@ -1137,6 +1167,8 @@ class DisplayBuffer extends Model
@setScrollTop(Math.min(@getScrollTop(), @getMaxScrollTop())) if delta < 0
updateScreenLines: (startBufferRow, endBufferRow, bufferDelta=0, options={}) ->
return if @largeFileMode
startBufferRow = @rowMap.bufferRowRangeForBufferRow(startBufferRow)[0]
endBufferRow = @rowMap.bufferRowRangeForBufferRow(endBufferRow - 1)[1]
startScreenRow = @rowMap.screenRowRangeForBufferRow(startBufferRow)[0]

View File

@@ -376,11 +376,6 @@ class Project extends Model
#
# Returns a promise that resolves to the {TextBuffer}.
buildBuffer: (absoluteFilePath) ->
if fs.getSizeSync(absoluteFilePath) >= 2 * 1048576 # 2MB
error = new Error("Atom can only handle files < 2MB for now.")
error.code = 'EFILETOOLARGE'
throw error
buffer = new TextBuffer({filePath: absoluteFilePath})
@addBuffer(buffer)
buffer.load()
@@ -410,7 +405,8 @@ class Project extends Model
buffer?.destroy()
buildEditorForBuffer: (buffer, editorOptions) ->
editor = new TextEditor(_.extend({buffer, registerEditor: true}, editorOptions))
largeFileMode = fs.getSizeSync(buffer.getPath()) >= 2 * 1048576 # 2MB
editor = new TextEditor(_.extend({buffer, largeFileMode, registerEditor: true}, editorOptions))
editor
eachBuffer: (args...) ->

View File

@@ -75,7 +75,7 @@ class TextEditor extends Model
'autoDecreaseIndentForBufferRow', 'toggleLineCommentForBufferRow', 'toggleLineCommentsForBufferRows',
toProperty: 'languageMode'
constructor: ({@softTabs, initialLine, initialColumn, tabLength, softWrapped, @displayBuffer, buffer, registerEditor, suppressCursorCreation, @mini, @placeholderText, lineNumberGutterVisible}={}) ->
constructor: ({@softTabs, initialLine, initialColumn, tabLength, softWrapped, @displayBuffer, buffer, registerEditor, suppressCursorCreation, @mini, @placeholderText, lineNumberGutterVisible, largeFileMode}={}) ->
super
@emitter = new Emitter
@@ -84,7 +84,7 @@ class TextEditor extends Model
@selections = []
buffer ?= new TextBuffer
@displayBuffer ?= new DisplayBuffer({buffer, tabLength, softWrapped, ignoreInvisibles: @mini})
@displayBuffer ?= new DisplayBuffer({buffer, tabLength, softWrapped, ignoreInvisibles: @mini, largeFileMode})
@buffer = @displayBuffer.buffer
@softTabs = @usesSoftTabs() ? @softTabs ? atom.config.get('editor.softTabs') ? true

View File

@@ -24,7 +24,7 @@ class TokenizedBuffer extends Model
visible: false
configSettings: null
constructor: ({@buffer, @tabLength, @ignoreInvisibles}) ->
constructor: ({@buffer, @tabLength, @ignoreInvisibles, @largeFileMode}) ->
@emitter = new Emitter
@disposables = new CompositeDisposable
@tokenIterator = new TokenIterator
@@ -209,6 +209,8 @@ class TokenizedBuffer extends Model
return
invalidateRow: (row) ->
return if @largeFileMode
@invalidRows.push(row)
@invalidRows.sort (a, b) -> a - b
@tokenizeInBackground()
@@ -230,7 +232,10 @@ class TokenizedBuffer extends Model
@updateInvalidRows(start, end, delta)
previousEndStack = @stackForRow(end) # used in spill detection below
newTokenizedLines = @buildTokenizedLinesForRows(start, end + delta, @stackForRow(start - 1), @openScopesForRow(start))
if @largeFileMode
newTokenizedLines = @buildPlaceholderTokenizedLinesForRows(start, end + delta)
else
newTokenizedLines = @buildTokenizedLinesForRows(start, end + delta, @stackForRow(start - 1), @openScopesForRow(start))
_.spliceWithArray(@tokenizedLines, start, end - start + 1, newTokenizedLines)
start = @retokenizeWhitespaceRowsIfIndentLevelChanged(start - 1, -1)
@@ -344,6 +349,10 @@ class TokenizedBuffer extends Model
if 0 <= bufferRow < @tokenizedLines.length
@tokenizedLines[bufferRow] ?= @buildPlaceholderTokenizedLineForRow(bufferRow)
tokenizedLinesForRows: (startRow, endRow) ->
for row in [startRow..endRow] by 1
@tokenizedLineForRow(row)
stackForRow: (bufferRow) ->
@tokenizedLines[bufferRow]?.ruleStack