From de508db9b2c9cb609f565b38adeeaee0823c7e48 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Fri, 5 Jun 2015 02:25:57 +0200 Subject: [PATCH] Implement basic large file mode for editor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 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 --- src/display-buffer.coffee | 68 +++++++++++++++++++++++++++---------- src/project.coffee | 8 ++--- src/text-editor.coffee | 4 +-- src/tokenized-buffer.coffee | 13 +++++-- 4 files changed, 65 insertions(+), 28 deletions(-) diff --git a/src/display-buffer.coffee b/src/display-buffer.coffee index d98f93fe3..32f374776 100644 --- a/src/display-buffer.coffee +++ b/src/display-buffer.coffee @@ -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] diff --git a/src/project.coffee b/src/project.coffee index 75cdb714f..e2eed7ac5 100644 --- a/src/project.coffee +++ b/src/project.coffee @@ -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...) -> diff --git a/src/text-editor.coffee b/src/text-editor.coffee index 4aacb3dfa..9a9262e50 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -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 diff --git a/src/tokenized-buffer.coffee b/src/tokenized-buffer.coffee index 72a972967..5aa3482a9 100644 --- a/src/tokenized-buffer.coffee +++ b/src/tokenized-buffer.coffee @@ -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