From 5b494b7b174be6774b786fcc8ea81eb41ab83118 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Fri, 5 Jun 2015 01:19:12 +0200 Subject: [PATCH 01/11] Lazily construct placeholder lines in TokenizedBuffer --- src/tokenized-buffer.coffee | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/tokenized-buffer.coffee b/src/tokenized-buffer.coffee index 55d2e7e37..72a972967 100644 --- a/src/tokenized-buffer.coffee +++ b/src/tokenized-buffer.coffee @@ -112,14 +112,14 @@ class TokenizedBuffer extends Model throw new Error("No grammar found for path: #{path}") hasTokenForSelector: (selector) -> - for {tokens} in @tokenizedLines - for token in tokens + for tokenizedLine in @tokenizedLines when tokenizedLine? + for token in tokenizedLine.tokens return true if selector.matches(token.scopes) false retokenizeLines: -> lastRow = @buffer.getLastRow() - @tokenizedLines = @buildPlaceholderTokenizedLinesForRows(0, lastRow) + @tokenizedLines = new Array(lastRow + 1) @invalidRows = [] @invalidateRow(0) @fullyTokenized = false @@ -248,12 +248,12 @@ class TokenizedBuffer extends Model @emitter.emit 'did-change', event retokenizeWhitespaceRowsIfIndentLevelChanged: (row, increment) -> - line = @tokenizedLines[row] + line = @tokenizedLineForRow(row) if line?.isOnlyWhitespace() and @indentLevelForRow(row) isnt line.indentLevel while line?.isOnlyWhitespace() @tokenizedLines[row] = @buildTokenizedLineForRow(row, @stackForRow(row - 1), @openScopesForRow(row)) row += increment - line = @tokenizedLines[row] + line = @tokenizedLineForRow(row) row - increment @@ -313,7 +313,7 @@ class TokenizedBuffer extends Model tokenizedLines buildPlaceholderTokenizedLinesForRows: (startRow, endRow) -> - @buildPlaceholderTokenizedLineForRow(row) for row in [startRow..endRow] + @buildPlaceholderTokenizedLineForRow(row) for row in [startRow..endRow] by 1 buildPlaceholderTokenizedLineForRow: (row) -> openScopes = [@grammar.startIdForScope(@grammar.scopeName)] @@ -341,7 +341,8 @@ class TokenizedBuffer extends Model null tokenizedLineForRow: (bufferRow) -> - @tokenizedLines[bufferRow] + if 0 <= bufferRow < @tokenizedLines.length + @tokenizedLines[bufferRow] ?= @buildPlaceholderTokenizedLineForRow(bufferRow) stackForRow: (bufferRow) -> @tokenizedLines[bufferRow]?.ruleStack @@ -418,17 +419,17 @@ class TokenizedBuffer extends Model tokenForPosition: (position) -> {row, column} = Point.fromObject(position) - @tokenizedLines[row].tokenAtBufferColumn(column) + @tokenizedLineForRow(row).tokenAtBufferColumn(column) tokenStartPositionForPosition: (position) -> {row, column} = Point.fromObject(position) - column = @tokenizedLines[row].tokenStartColumnForBufferColumn(column) + column = @tokenizedLineForRow(row).tokenStartColumnForBufferColumn(column) new Point(row, column) bufferRangeForScopeAtPosition: (selector, position) -> position = Point.fromObject(position) - {openScopes, tags} = @tokenizedLines[position.row] + {openScopes, tags} = @tokenizedLineForRow(position.row) scopes = openScopes.map (tag) -> atom.grammars.scopeForId(tag) startColumn = 0 From de508db9b2c9cb609f565b38adeeaee0823c7e48 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Fri, 5 Jun 2015 02:25:57 +0200 Subject: [PATCH 02/11] 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 From c34838277d68bd19f0b97ecede4d86c684a111b8 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Fri, 5 Jun 2015 19:55:34 +0200 Subject: [PATCH 03/11] =?UTF-8?q?In=20largeFileMode,=20base=20maxLineLengt?= =?UTF-8?q?h=20on=20the=20longest=20line=20we=E2=80=99ve=20seen?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is pretty hacky. If we want to compute the true longest line, we’ll need to process every line, which is what large file mode is designed to avoid. So now whenever the display buffer returns a line, it has the potential to update the longest line. This is a bit weird because retrieving a line now has a side effect. It’s even more weird because the longest line will actually be wrong for the initial state updates in the TextEditorPresenter. But as soon as the user interacts in any way the dimensions are recomputed, so it works for now. A better approach may be to set a visible region on the display buffer. But I’d like to keep this low-touch until we have a chance to revisit the design of DisplayBuffer in a bigger way. --- src/display-buffer.coffee | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/display-buffer.coffee b/src/display-buffer.coffee index 32f374776..388182c8f 100644 --- a/src/display-buffer.coffee +++ b/src/display-buffer.coffee @@ -479,7 +479,11 @@ class DisplayBuffer extends Model # Returns {TokenizedLine} tokenizedLineForScreenRow: (screenRow) -> if @largeFileMode - @tokenizedBuffer.tokenizedLineForRow(screenRow) + line = @tokenizedBuffer.tokenizedLineForRow(screenRow) + if line.text.length > @maxLineLength + @maxLineLength = line.text.length + @longestScreenRow = screenRow + line else @screenLines[screenRow] @@ -760,19 +764,13 @@ class DisplayBuffer extends Model # # Returns a {Number}. getMaxLineLength: -> - if @largeFileMode - 100 - else - @maxLineLength + @maxLineLength # Gets the row number of the longest screen line. # # Return a {} getLongestScreenRow: -> - if @largeFileMode - 0 - else - @longestScreenRow + @longestScreenRow # Given a buffer position, this converts it into a screen position. # From 639647d1158eb90c510811ab3cb66d199e7a2904 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Fri, 5 Jun 2015 21:31:06 +0200 Subject: [PATCH 04/11] Disallow fold creation in large file mode --- src/display-buffer.coffee | 9 +++++---- src/tokenized-buffer.coffee | 7 ++++++- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/display-buffer.coffee b/src/display-buffer.coffee index 388182c8f..2fccc4eb0 100644 --- a/src/display-buffer.coffee +++ b/src/display-buffer.coffee @@ -532,10 +532,11 @@ class DisplayBuffer extends Model # # Returns the new {Fold}. createFold: (startRow, endRow) -> - foldMarker = - @findFoldMarker({startRow, endRow}) ? - @buffer.markRange([[startRow, 0], [endRow, Infinity]], @getFoldMarkerAttributes()) - @foldForMarker(foldMarker) + unless @largeFileMode + foldMarker = + @findFoldMarker({startRow, endRow}) ? + @buffer.markRange([[startRow, 0], [endRow, Infinity]], @getFoldMarkerAttributes()) + @foldForMarker(foldMarker) isFoldedAtBufferRow: (bufferRow) -> @largestFoldContainingBufferRow(bufferRow)? diff --git a/src/tokenized-buffer.coffee b/src/tokenized-buffer.coffee index 5aa3482a9..f051cb4be 100644 --- a/src/tokenized-buffer.coffee +++ b/src/tokenized-buffer.coffee @@ -263,6 +263,8 @@ class TokenizedBuffer extends Model row - increment updateFoldableStatus: (startRow, endRow) -> + return [startRow, endRow] if @largeFileMode + scanStartRow = @buffer.previousNonBlankRow(startRow) ? startRow scanStartRow-- while scanStartRow > 0 and @tokenizedLineForRow(scanStartRow).isComment() scanEndRow = @buffer.nextNonBlankRow(endRow) ? endRow @@ -278,7 +280,10 @@ class TokenizedBuffer extends Model [startRow, endRow] isFoldableAtRow: (row) -> - @isFoldableCodeAtRow(row) or @isFoldableCommentAtRow(row) + if @largeFileMode + false + else + @isFoldableCodeAtRow(row) or @isFoldableCommentAtRow(row) # Returns a {Boolean} indicating whether the given buffer row starts # a a foldable row range due to the code's indentation patterns. From efd4662de0af4776bca54ed1a79a5c7e4c8f98b2 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Fri, 5 Jun 2015 21:36:11 +0200 Subject: [PATCH 05/11] =?UTF-8?q?Don=E2=80=99t=20allow=20soft=20wrap=20to?= =?UTF-8?q?=20be=20enabled=20in=20large=20file=20mode?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/display-buffer.coffee | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/display-buffer.coffee b/src/display-buffer.coffee index 2fccc4eb0..8aa6e9d1b 100644 --- a/src/display-buffer.coffee +++ b/src/display-buffer.coffee @@ -445,7 +445,10 @@ class DisplayBuffer extends Model @isSoftWrapped() isSoftWrapped: -> - @softWrapped ? @configSettings.softWrap ? false + if @largeFileMode + false + else + @softWrapped ? @configSettings.softWrap ? false # Set the number of characters that fit horizontally in the editor. # From 56273e7eef6c16093ca45eebf346c9903ddb614e Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Fri, 5 Jun 2015 21:44:23 +0200 Subject: [PATCH 06/11] Preserve large file mode across serialization and pane splits --- src/display-buffer.coffee | 3 ++- src/tokenized-buffer.coffee | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/display-buffer.coffee b/src/display-buffer.coffee index 8aa6e9d1b..910f7b177 100644 --- a/src/display-buffer.coffee +++ b/src/display-buffer.coffee @@ -89,13 +89,14 @@ class DisplayBuffer extends Model scrollTop: @scrollTop scrollLeft: @scrollLeft tokenizedBuffer: @tokenizedBuffer.serialize() + largeFileMode: @largeFileMode deserializeParams: (params) -> params.tokenizedBuffer = TokenizedBuffer.deserialize(params.tokenizedBuffer) params copy: -> - newDisplayBuffer = new DisplayBuffer({@buffer, tabLength: @getTabLength()}) + newDisplayBuffer = new DisplayBuffer({@buffer, tabLength: @getTabLength(), @largeFileMode}) newDisplayBuffer.setScrollTop(@getScrollTop()) newDisplayBuffer.setScrollLeft(@getScrollLeft()) diff --git a/src/tokenized-buffer.coffee b/src/tokenized-buffer.coffee index f051cb4be..6337aa3c6 100644 --- a/src/tokenized-buffer.coffee +++ b/src/tokenized-buffer.coffee @@ -44,6 +44,7 @@ class TokenizedBuffer extends Model bufferPath: @buffer.getPath() tabLength: @tabLength ignoreInvisibles: @ignoreInvisibles + largeFileMode: @largeFileMode deserializeParams: (params) -> params.buffer = atom.project.bufferForPathSync(params.bufferPath) From 48ce361bd0f81b369a5f10ce7e9a4c2e5d3c339f Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Fri, 5 Jun 2015 22:24:49 +0200 Subject: [PATCH 07/11] Select grammars based on first 10 lines of content, not the entire file --- src/tokenized-buffer.coffee | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/tokenized-buffer.coffee b/src/tokenized-buffer.coffee index 6337aa3c6..758aef501 100644 --- a/src/tokenized-buffer.coffee +++ b/src/tokenized-buffer.coffee @@ -67,7 +67,7 @@ class TokenizedBuffer extends Model if grammar.injectionSelector? @retokenizeLines() if @hasTokenForSelector(grammar.injectionSelector) else - newScore = grammar.getScore(@buffer.getPath(), @buffer.getText()) + newScore = grammar.getScore(@buffer.getPath(), @getGrammarSelectionContent()) @setGrammar(grammar, newScore) if newScore > @currentGrammarScore setGrammar: (grammar, score) -> @@ -75,7 +75,7 @@ class TokenizedBuffer extends Model @grammar = grammar @rootScopeDescriptor = new ScopeDescriptor(scopes: [@grammar.scopeName]) - @currentGrammarScore = score ? grammar.getScore(@buffer.getPath(), @buffer.getText()) + @currentGrammarScore = score ? grammar.getScore(@buffer.getPath(), @getGrammarSelectionContent()) @grammarUpdateDisposable?.dispose() @grammarUpdateDisposable = @grammar.onDidUpdate => @retokenizeLines() @@ -106,8 +106,11 @@ class TokenizedBuffer extends Model @emit 'grammar-changed', grammar if Grim.includeDeprecatedAPIs @emitter.emit 'did-change-grammar', grammar + getGrammarSelectionContent: -> + @buffer.getTextInRange([[0, 0], [10, 0]]) + reloadGrammar: -> - if grammar = atom.grammars.selectGrammar(@buffer.getPath(), @buffer.getText()) + if grammar = atom.grammars.selectGrammar(@buffer.getPath(), @getGrammarSelectionContent()) @setGrammar(grammar) else throw new Error("No grammar found for path: #{path}") From ffcebdad33bc863e88152ffa94717dfc2d669d84 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Fri, 5 Jun 2015 23:14:11 +0200 Subject: [PATCH 08/11] Remove outdated test --- spec/workspace-spec.coffee | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/spec/workspace-spec.coffee b/spec/workspace-spec.coffee index 009f95a1c..3e94727d4 100644 --- a/spec/workspace-spec.coffee +++ b/spec/workspace-spec.coffee @@ -272,20 +272,6 @@ describe "Workspace", -> beforeEach -> atom.notifications.onDidAddNotification notificationSpy = jasmine.createSpy() - describe "when a large file is opened", -> - beforeEach -> - spyOn(fs, 'getSizeSync').andReturn 2 * 1048577 # 2MB - - it "creates a notification", -> - waitsForPromise -> - workspace.open('file1') - - runs -> - expect(notificationSpy).toHaveBeenCalled() - notification = notificationSpy.mostRecentCall.args[0] - expect(notification.getType()).toBe 'warning' - expect(notification.getMessage()).toContain '< 2MB' - describe "when a file does not exist", -> it "creates an empty buffer for the specified path", -> waitsForPromise -> From df733aa3de889976d43f9d209d15a947883018c0 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Fri, 5 Jun 2015 23:25:48 +0200 Subject: [PATCH 09/11] Add a basic test for opening an editor in largeFileMode if >= 2MB --- spec/workspace-spec.coffee | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/spec/workspace-spec.coffee b/spec/workspace-spec.coffee index 3e94727d4..4918fc65f 100644 --- a/spec/workspace-spec.coffee +++ b/spec/workspace-spec.coffee @@ -224,6 +224,17 @@ describe "Workspace", -> expect(workspace.paneContainer.root.children[0]).toBe pane1 expect(workspace.paneContainer.root.children[1]).toBe pane4 + describe "when the file is large (over 2mb)", -> + it "opens the editor with largeFileMode: true", -> + spyOn(fs, 'getSizeSync').andReturn 2 * 1048577 # 2MB + + editor = null + waitsForPromise -> + workspace.open('sample.js').then (e) -> editor = e + + runs -> + expect(editor.displayBuffer.largeFileMode).toBe true + describe "when passed a path that matches a custom opener", -> it "returns the resource returned by the custom opener", -> fooOpener = (pathToOpen, options) -> {foo: pathToOpen, options} if pathToOpen?.match(/\.foo/) From 3ac9d539ce99d09d17b4dfd2d33c140edeb54e8f Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Fri, 5 Jun 2015 23:40:29 +0200 Subject: [PATCH 10/11] Add a super basic test for large file mode --- spec/text-editor-spec.coffee | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index 8ad1ce390..63b01a178 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -66,6 +66,25 @@ describe "TextEditor", -> expect(editor.tokenizedLineForScreenRow(0).invisibles.eol).toBe '?' + describe "when the editor is constructed with the largeFileMode option set to true", -> + it "loads the editor but doesn't tokenize", -> + editor = null + + waitsForPromise -> + atom.workspace.open('sample.js', largeFileMode: true).then (o) -> editor = o + + runs -> + buffer = editor.getBuffer() + expect(editor.tokenizedLineForScreenRow(0).text).toBe buffer.lineForRow(0) + expect(editor.tokenizedLineForScreenRow(0).tokens.length).toBe 1 + expect(editor.tokenizedLineForScreenRow(1).tokens.length).toBe 2 # soft tab + expect(editor.tokenizedLineForScreenRow(12).text).toBe buffer.lineForRow(12) + expect(editor.tokenizedLineForScreenRow(0).tokens.length).toBe 1 + expect(editor.getCursorScreenPosition()).toEqual [0, 0] + editor.insertText('hey"') + expect(editor.tokenizedLineForScreenRow(0).tokens.length).toBe 1 + expect(editor.tokenizedLineForScreenRow(1).tokens.length).toBe 2 # sof tab + describe "when the editor is constructed with an initialLine option", -> it "positions the cursor on the specified line", -> editor = null From 88812831ce248315f908fe048d0bd38a8d81d86e Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Fri, 5 Jun 2015 23:40:56 +0200 Subject: [PATCH 11/11] Only check for max line length when lines exist --- src/display-buffer.coffee | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/display-buffer.coffee b/src/display-buffer.coffee index 910f7b177..2519fa6d6 100644 --- a/src/display-buffer.coffee +++ b/src/display-buffer.coffee @@ -483,11 +483,11 @@ class DisplayBuffer extends Model # Returns {TokenizedLine} tokenizedLineForScreenRow: (screenRow) -> if @largeFileMode - line = @tokenizedBuffer.tokenizedLineForRow(screenRow) - if line.text.length > @maxLineLength - @maxLineLength = line.text.length - @longestScreenRow = screenRow - line + if line = @tokenizedBuffer.tokenizedLineForRow(screenRow) + if line.text.length > @maxLineLength + @maxLineLength = line.text.length + @longestScreenRow = screenRow + line else @screenLines[screenRow]