Introduce LanguageMode wrapper for Ace modes as a foundation of our own modes

LanguageMode is the central point for all language-specific behavior associated with an EditSession. There is one LanguageMode instance per EditSession. LanguageMode has access to the EditSession and its TokenizedBuffer, and in reverse the EditSession, DisplayBuffer, and TokenizedBuffer also make use of LanguageMode. This is a bit incestuous, but I think it's okay because you can think of LanguageMode as a swappable strategy object that governs language-specific aspects of that constellation of objects.
This commit is contained in:
Nathan Sobo
2012-07-27 12:30:06 -06:00
parent 79893d96b6
commit 3516dea210
10 changed files with 192 additions and 166 deletions

View File

@@ -2,16 +2,16 @@ DisplayBuffer = require 'display-buffer'
Buffer = require 'buffer'
describe "DisplayBuffer", ->
[displayBuffer, buffer, changeHandler, tabText] = []
[editSession, displayBuffer, buffer, changeHandler, tabText] = []
beforeEach ->
tabText = ' '
buffer = new Buffer(require.resolve 'fixtures/sample.js')
displayBuffer = new DisplayBuffer(buffer, {tabText})
editSession = fixturesProject.buildEditSessionForPath('sample.js', { tabText })
{ buffer, displayBuffer } = editSession
changeHandler = jasmine.createSpy 'changeHandler'
displayBuffer.on 'change', changeHandler
afterEach ->
buffer.destroy()
editSession.destroy()
describe "when the buffer changes", ->
it "renders line numbers correctly", ->
@@ -198,12 +198,16 @@ describe "DisplayBuffer", ->
expect(fold.endRow).toBe 9
describe "primitive folding", ->
editSession2 = null
beforeEach ->
buffer.destroy()
buffer = new Buffer(require.resolve 'fixtures/two-hundred.txt')
displayBuffer = new DisplayBuffer(buffer, {tabText})
editSession2 = fixturesProject.buildEditSessionForPath('two-hundred.txt')
{ buffer, displayBuffer } = editSession2
displayBuffer.on 'change', changeHandler
afterEach ->
editSession2.destroy()
describe "when folds are created and destroyed", ->
describe "when a fold spans multiple lines", ->
it "replaces the lines spanned by the fold with a placeholder that references the fold object", ->

View File

@@ -0,0 +1,78 @@
Project = require 'project'
Buffer = require 'buffer'
EditSession = require 'edit-session'
describe "LanguageMode", ->
[editSession, buffer, languageMode] = []
afterEach ->
editSession.destroy()
describe "javascript", ->
beforeEach ->
editSession = fixturesProject.buildEditSessionForPath('sample.js', autoIndent: false)
{ buffer, languageMode } = editSession
describe ".toggleLineCommentsInRange(range)", ->
it "comments/uncomments lines in the given range", ->
languageMode.toggleLineCommentsInRange([[4, 5], [7, 8]])
expect(buffer.lineForRow(4)).toBe "// while(items.length > 0) {"
expect(buffer.lineForRow(5)).toBe "// current = items.shift();"
expect(buffer.lineForRow(6)).toBe "// current < pivot ? left.push(current) : right.push(current);"
expect(buffer.lineForRow(7)).toBe "// }"
languageMode.toggleLineCommentsInRange([[4, 5], [5, 8]])
expect(buffer.lineForRow(4)).toBe " while(items.length > 0) {"
expect(buffer.lineForRow(5)).toBe " current = items.shift();"
expect(buffer.lineForRow(6)).toBe "// current < pivot ? left.push(current) : right.push(current);"
expect(buffer.lineForRow(7)).toBe "// }"
describe "fold suggestion", ->
describe ".isBufferRowFoldable(bufferRow)", ->
it "returns true only when the buffer row starts a foldable region", ->
expect(languageMode.isBufferRowFoldable(0)).toBeTruthy()
expect(languageMode.isBufferRowFoldable(1)).toBeTruthy()
expect(languageMode.isBufferRowFoldable(2)).toBeFalsy()
expect(languageMode.isBufferRowFoldable(3)).toBeFalsy()
describe ".rowRangeForFoldAtBufferRow(bufferRow)", ->
it "returns the start/end rows of the foldable region starting at the given row", ->
expect(languageMode.rowRangeForFoldAtBufferRow(0)).toEqual [0, 12]
expect(languageMode.rowRangeForFoldAtBufferRow(1)).toEqual [1, 9]
expect(languageMode.rowRangeForFoldAtBufferRow(2)).toBeNull()
expect(languageMode.rowRangeForFoldAtBufferRow(4)).toEqual [4, 7]
describe "coffeescript", ->
beforeEach ->
editSession = fixturesProject.buildEditSessionForPath('coffee.coffee', autoIndent: false)
{ buffer, languageMode } = editSession
describe ".toggleLineCommentsInRange(range)", ->
it "comments/uncomments lines in the given range", ->
languageMode.toggleLineCommentsInRange([[4, 5], [7, 8]])
expect(buffer.lineForRow(4)).toBe " #pivot = items.shift()"
expect(buffer.lineForRow(5)).toBe " #left = []"
expect(buffer.lineForRow(6)).toBe " #right = []"
expect(buffer.lineForRow(7)).toBe "#"
languageMode.toggleLineCommentsInRange([[4, 5], [5, 8]])
expect(buffer.lineForRow(4)).toBe " pivot = items.shift()"
expect(buffer.lineForRow(5)).toBe " left = []"
expect(buffer.lineForRow(6)).toBe " #right = []"
expect(buffer.lineForRow(7)).toBe "#"
describe "fold suggestion", ->
describe ".isBufferRowFoldable(bufferRow)", ->
it "returns true only when the buffer row starts a foldable region", ->
expect(languageMode.isBufferRowFoldable(0)).toBeTruthy()
expect(languageMode.isBufferRowFoldable(1)).toBeTruthy()
expect(languageMode.isBufferRowFoldable(2)).toBeFalsy()
expect(languageMode.isBufferRowFoldable(3)).toBeFalsy()
expect(languageMode.isBufferRowFoldable(19)).toBeTruthy()
describe ".rowRangeForFoldAtBufferRow(bufferRow)", ->
it "returns the start/end rows of the foldable region starting at the given row", ->
expect(languageMode.rowRangeForFoldAtBufferRow(0)).toEqual [0, 20]
expect(languageMode.rowRangeForFoldAtBufferRow(1)).toEqual [1, 17]
expect(languageMode.rowRangeForFoldAtBufferRow(2)).toBeNull()
expect(languageMode.rowRangeForFoldAtBufferRow(19)).toEqual [19, 20]

View File

@@ -5,17 +5,17 @@ TokenizedBuffer = require 'tokenized-buffer'
Point = require 'point'
describe "LineMap", ->
[tokenizedBuffer, map] = []
[editSession, tokenizedBuffer, map] = []
[line0, line1, line2, line3, line4] = []
beforeEach ->
buffer = new Buffer(require.resolve 'fixtures/sample.js')
tokenizedBuffer = new TokenizedBuffer(buffer)
editSession = fixturesProject.buildEditSessionForPath('sample.js')
{ buffer, tokenizedBuffer } = editSession
map = new LineMap
[line0, line1, line2, line3, line4] = tokenizedBuffer.linesForScreenRows(0, 4)
afterEach ->
tokenizedBuffer.buffer.destroy()
editSession.destroy()
describe ".insertAtBufferRow(row, lineFragments)", ->
it "inserts the given line fragments before the specified buffer row", ->

View File

@@ -3,16 +3,16 @@ Buffer = require 'buffer'
TokenizedBuffer = require 'tokenized-buffer'
describe "ScreenLine", ->
[buffer, tabText, screenLine, tokenizedBuffer] = []
[editSession, buffer, tabText, screenLine, tokenizedBuffer] = []
beforeEach ->
tabText = ' '
buffer = new Buffer(require.resolve 'fixtures/sample.js')
tokenizedBuffer = new TokenizedBuffer(buffer, tabText)
editSession = fixturesProject.buildEditSessionForPath('sample.js')
{ buffer, tokenizedBuffer } = editSession
screenLine = tokenizedBuffer.lineForScreenRow(3)
afterEach ->
buffer.destroy()
editSession.destroy()
describe ".splitAt(column)", ->
it "breaks the line fragment into two fragments", ->

View File

@@ -1,16 +1,17 @@
TokenizedBuffer = require 'tokenized-buffer'
LanguageMode = require 'language-mode'
Buffer = require 'buffer'
Range = require 'range'
describe "TokenizedBuffer", ->
[tokenizedBuffer, buffer] = []
[editSession, tokenizedBuffer, buffer] = []
beforeEach ->
buffer = new Buffer(require.resolve('fixtures/sample.js'))
tokenizedBuffer = new TokenizedBuffer(buffer, ' ')
editSession = fixturesProject.buildEditSessionForPath('sample.js', autoIndent: false)
{ tokenizedBuffer, buffer } = editSession
afterEach ->
buffer.destroy()
editSession.destroy()
describe ".findClosingBracket(startBufferPosition)", ->
it "returns the position of the matching bracket, skipping any nested brackets", ->
@@ -20,81 +21,6 @@ describe "TokenizedBuffer", ->
it "returns the position of the matching bracket, skipping any nested brackets", ->
expect(tokenizedBuffer.findOpeningBracket([9, 2])).toEqual [1, 29]
describe ".toggleLineCommentsInRange(range)", ->
describe "javascript", ->
it "comments/uncomments lines in the given range", ->
tokenizedBuffer.toggleLineCommentsInRange([[4, 5], [7, 8]])
expect(buffer.lineForRow(4)).toBe "// while(items.length > 0) {"
expect(buffer.lineForRow(5)).toBe "// current = items.shift();"
expect(buffer.lineForRow(6)).toBe "// current < pivot ? left.push(current) : right.push(current);"
expect(buffer.lineForRow(7)).toBe "// }"
tokenizedBuffer.toggleLineCommentsInRange([[4, 5], [5, 8]])
expect(buffer.lineForRow(4)).toBe " while(items.length > 0) {"
expect(buffer.lineForRow(5)).toBe " current = items.shift();"
expect(buffer.lineForRow(6)).toBe "// current < pivot ? left.push(current) : right.push(current);"
expect(buffer.lineForRow(7)).toBe "// }"
describe "coffeescript", ->
it "comments/uncomments lines in the given range", ->
buffer.destroy()
buffer = new Buffer(require.resolve('fixtures/coffee.coffee'))
tokenizedBuffer = new TokenizedBuffer(buffer, ' ')
tokenizedBuffer.toggleLineCommentsInRange([[4, 5], [7, 8]])
expect(buffer.lineForRow(4)).toBe " #pivot = items.shift()"
expect(buffer.lineForRow(5)).toBe " #left = []"
expect(buffer.lineForRow(6)).toBe " #right = []"
expect(buffer.lineForRow(7)).toBe "#"
tokenizedBuffer.toggleLineCommentsInRange([[4, 5], [5, 8]])
expect(buffer.lineForRow(4)).toBe " pivot = items.shift()"
expect(buffer.lineForRow(5)).toBe " left = []"
expect(buffer.lineForRow(6)).toBe " #right = []"
expect(buffer.lineForRow(7)).toBe "#"
describe "fold suggestion", ->
describe "javascript", ->
beforeEach ->
buffer.destroy()
buffer = new Buffer(require.resolve 'fixtures/sample.js')
tokenizedBuffer = new TokenizedBuffer(buffer)
describe ".isBufferRowFoldable(bufferRow)", ->
it "returns true only when the buffer row starts a foldable region", ->
expect(tokenizedBuffer.isBufferRowFoldable(0)).toBeTruthy()
expect(tokenizedBuffer.isBufferRowFoldable(1)).toBeTruthy()
expect(tokenizedBuffer.isBufferRowFoldable(2)).toBeFalsy()
expect(tokenizedBuffer.isBufferRowFoldable(3)).toBeFalsy()
describe ".rowRangeForFoldAtBufferRow(bufferRow)", ->
it "returns the start/end rows of the foldable region starting at the given row", ->
expect(tokenizedBuffer.rowRangeForFoldAtBufferRow(0)).toEqual [0, 12]
expect(tokenizedBuffer.rowRangeForFoldAtBufferRow(1)).toEqual [1, 9]
expect(tokenizedBuffer.rowRangeForFoldAtBufferRow(2)).toBeNull()
expect(tokenizedBuffer.rowRangeForFoldAtBufferRow(4)).toEqual [4, 7]
describe "coffeescript", ->
beforeEach ->
buffer.destroy()
buffer = new Buffer(require.resolve 'fixtures/coffee.coffee')
tokenizedBuffer = new TokenizedBuffer(buffer)
describe ".isBufferRowFoldable(bufferRow)", ->
it "returns true only when the buffer row starts a foldable region", ->
expect(tokenizedBuffer.isBufferRowFoldable(0)).toBeTruthy()
expect(tokenizedBuffer.isBufferRowFoldable(1)).toBeTruthy()
expect(tokenizedBuffer.isBufferRowFoldable(2)).toBeFalsy()
expect(tokenizedBuffer.isBufferRowFoldable(3)).toBeFalsy()
expect(tokenizedBuffer.isBufferRowFoldable(19)).toBeTruthy()
describe ".rowRangeForFoldAtBufferRow(bufferRow)", ->
it "returns the start/end rows of the foldable region starting at the given row", ->
expect(tokenizedBuffer.rowRangeForFoldAtBufferRow(0)).toEqual [0, 20]
expect(tokenizedBuffer.rowRangeForFoldAtBufferRow(1)).toEqual [1, 17]
expect(tokenizedBuffer.rowRangeForFoldAtBufferRow(2)).toBeNull()
expect(tokenizedBuffer.rowRangeForFoldAtBufferRow(19)).toEqual [19, 20]
describe "tokenization", ->
it "tokenizes all the lines in the buffer on construction", ->
expect(tokenizedBuffer.lineForScreenRow(0).tokens[0]).toEqual(type: 'keyword.definition', value: 'var')
@@ -225,13 +151,15 @@ describe "TokenizedBuffer", ->
expect(event.newRange).toEqual new Range([2, 0], [7, buffer.lineForRow(7).length])
describe "when the buffer contains tab characters", ->
tabText = null
tabText = ' '
editSession2 = null
beforeEach ->
tabText = ' '
buffer.destroy()
buffer = new Buffer(require.resolve('fixtures/sample-with-tabs.coffee'))
tokenizedBuffer = new TokenizedBuffer(buffer, tabText)
editSession2 = fixturesProject.buildEditSessionForPath('sample-with-tabs.coffee', { tabText })
{ buffer, tokenizedBuffer } = editSession2
afterEach ->
editSession2.destroy()
it "always renders each tab as its own atomic token containing tabText", ->
screenLine0 = tokenizedBuffer.lineForScreenRow(0)

View File

@@ -4,8 +4,8 @@ module.exports =
class AceAdaptor
foldWidgets: {}
constructor: (@tokenizedBuffer) ->
@buffer = @tokenizedBuffer.buffer
constructor: (@editSession) ->
@buffer = @editSession.buffer
getLine: (bufferRow) ->
@buffer.lineForRow(bufferRow)
@@ -14,7 +14,7 @@ class AceAdaptor
@buffer.getLineCount()
$findClosingBracket: (bracketType, bufferPosition) ->
@tokenizedBuffer.findClosingBracket([bufferPosition.row, bufferPosition.column - 1])
@editSession.tokenizedBuffer.findClosingBracket([bufferPosition.row, bufferPosition.column - 1])
indentRows: (startRow, endRow, indentString) ->
for row in [startRow..endRow]
@@ -25,4 +25,4 @@ class AceAdaptor
@buffer.change(range, text)
findMatchingBracket: ({row, column}) ->
@tokenizedBuffer.findOpeningBracket([row, column])
@editSession.tokenizedBuffer.findOpeningBracket([row, column])

View File

@@ -12,6 +12,7 @@ module.exports =
class DisplayBuffer
@idCounter: 1
lineMap: null
languageMode: null
tokenizedBuffer: null
activeFolds: null
foldsById: null
@@ -19,7 +20,9 @@ class DisplayBuffer
constructor: (@buffer, options={}) ->
@id = @constructor.idCounter++
@tokenizedBuffer = new TokenizedBuffer(@buffer, options.tabText ? ' ')
options.tabText ?= ' '
@languageMode = options.languageMode
@tokenizedBuffer = new TokenizedBuffer(@buffer, options)
@softWrapColumn = options.softWrapColumn ? Infinity
@activeFolds = {}
@foldsById = {}
@@ -51,14 +54,14 @@ class DisplayBuffer
foldAll: ->
for currentRow in [0..@buffer.getLastRow()]
[startRow, endRow] = @tokenizedBuffer.rowRangeForFoldAtBufferRow(currentRow) ? []
[startRow, endRow] = @languageMode.rowRangeForFoldAtBufferRow(currentRow) ? []
continue unless startRow?
@createFold(startRow, endRow)
toggleFoldAtBufferRow: (bufferRow) ->
for currentRow in [bufferRow..0]
[startRow, endRow] = @tokenizedBuffer.rowRangeForFoldAtBufferRow(currentRow) ? []
[startRow, endRow] = @languageMode.rowRangeForFoldAtBufferRow(currentRow) ? []
continue unless startRow? and startRow <= bufferRow <= endRow
if fold = @largestFoldStartingAtBufferRow(startRow)
@@ -209,7 +212,7 @@ class DisplayBuffer
startBufferColumn = 0
while currentBufferRow <= endBufferRow
screenLine = @tokenizedBuffer.lineForScreenRow(currentBufferRow)
screenLine.foldable = @tokenizedBuffer.isBufferRowFoldable(currentBufferRow)
screenLine.foldable = @languageMode.isBufferRowFoldable(currentBufferRow)
if fold = @largestFoldStartingAtBufferRow(currentBufferRow)
screenLine = screenLine.copy()

View File

@@ -1,6 +1,7 @@
Point = require 'point'
Buffer = require 'buffer'
Anchor = require 'anchor'
LanguageMode = require 'language-mode'
DisplayBuffer = require 'display-buffer'
Cursor = require 'cursor'
Selection = require 'selection'
@@ -22,6 +23,7 @@ class EditSession
scrollTop: 0
scrollLeft: 0
languageMode: null
displayBuffer: null
anchors: null
anchorRanges: null
@@ -34,7 +36,8 @@ class EditSession
constructor: ({@project, @buffer, @tabText, @autoIndent, @softTabs, @softWrap}) ->
@id = @constructor.idCounter++
@softTabs ?= true
@displayBuffer = new DisplayBuffer(@buffer, { @tabText })
@languageMode = new LanguageMode(this, @buffer.getExtension())
@displayBuffer = new DisplayBuffer(@buffer, { @languageMode, @tabText })
@tokenizedBuffer = @displayBuffer.tokenizedBuffer
@anchors = []
@anchorRanges = []
@@ -242,17 +245,17 @@ class EditSession
@displayBuffer.largestFoldStartingAtScreenRow(screenRow)
indentationForRow: (row) ->
@tokenizedBuffer.indentationForRow(row)
@languageMode.indentationForRow(row)
autoIndentTextAfterBufferPosition: (text, bufferPosition) ->
return { text } unless @autoIndent
@tokenizedBuffer.autoIndentTextAfterBufferPosition(text, bufferPosition)
@languageMode.autoIndentTextAfterBufferPosition(text, bufferPosition)
autoOutdentBufferRow: (bufferRow) ->
@tokenizedBuffer.autoOutdentBufferRow(bufferRow)
@languageMode.autoOutdentBufferRow(bufferRow)
toggleLineCommentsInRange: (range) ->
@tokenizedBuffer.toggleLineCommentsInRange(range)
@languageMode.toggleLineCommentsInRange(range)
mutateSelectedText: (fn) ->
@transact => fn(selection) for selection in @getSelections()

View File

@@ -0,0 +1,60 @@
AceAdaptor = require 'ace-adaptor'
Range = require 'range'
module.exports =
class LanguageMode
constructor: (@editSession) ->
@buffer = @editSession.buffer
@aceMode = @requireAceMode()
@aceAdaptor = new AceAdaptor(@editSession)
requireAceMode: (fileExtension) ->
modeName = switch @editSession.buffer.getExtension()
when 'js' then 'javascript'
when 'coffee' then 'coffee'
when 'rb', 'ru' then 'ruby'
when 'c', 'h', 'cpp' then 'c_cpp'
when 'html', 'htm' then 'html'
when 'css' then 'css'
when 'java' then 'java'
when 'xml' then 'xml'
else 'text'
new (require("ace/mode/#{modeName}").Mode)
toggleLineCommentsInRange: (range) ->
range = Range.fromObject(range)
@aceMode.toggleCommentLines(@tokenizedBuffer.stateForRow(range.start.row), @aceAdaptor, range.start.row, range.end.row)
isBufferRowFoldable: (bufferRow) ->
@aceMode.foldingRules?.getFoldWidget(@aceAdaptor, null, bufferRow) == "start"
rowRangeForFoldAtBufferRow: (bufferRow) ->
if aceRange = @aceMode.foldingRules?.getFoldWidgetRange(@aceAdaptor, null, bufferRow)
[aceRange.start.row, aceRange.end.row]
else
null
indentationForRow: (row) ->
state = @tokenizedBuffer.stateForRow(row)
previousRowText = @buffer.lineForRow(row - 1)
@aceMode.getNextLineIndent(state, previousRowText, @editSession.tabText)
autoIndentTextAfterBufferPosition: (text, bufferPosition) ->
{ row, column} = bufferPosition
state = @tokenizedBuffer.stateForRow(row)
lineBeforeCursor = @buffer.lineForRow(row)[0...column]
if text[0] == "\n"
indent = @aceMode.getNextLineIndent(state, lineBeforeCursor, @editSession.tabText)
text = text[0] + indent + text[1..]
else if @aceMode.checkOutdent(state, lineBeforeCursor, text)
shouldOutdent = true
{text, shouldOutdent}
autoOutdentBufferRow: (bufferRow) ->
state = @tokenizedBuffer.stateForRow(bufferRow)
@aceMode.autoOutdent(state, @aceAdaptor, bufferRow)
getLineTokens: (line, state) ->
{tokens, state} = @aceMode.getTokenizer().getLineTokens(line, state)

View File

@@ -4,70 +4,21 @@ EventEmitter = require 'event-emitter'
Token = require 'token'
Range = require 'range'
Point = require 'point'
AceAdaptor = require 'ace-adaptor'
module.exports =
class TokenizedBuffer
@idCounter: 1
languageMode: null
buffer: null
aceMode: null
aceAdaptor: null
screenLines: null
constructor: (@buffer, @tabText) ->
constructor: (@buffer, { @languageMode, @tabText }) ->
@languageMode.tokenizedBuffer = this
@id = @constructor.idCounter++
@aceMode = @requireAceMode()
@screenLines = @buildScreenLinesForRows('start', 0, @buffer.getLastRow())
@buffer.on "change.tokenized-buffer#{@id}", (e) => @handleBufferChange(e)
@aceAdaptor = new AceAdaptor(this)
requireAceMode: ->
modeName = switch @buffer.getExtension()
when 'js' then 'javascript'
when 'coffee' then 'coffee'
when 'rb', 'ru' then 'ruby'
when 'c', 'h', 'cpp' then 'c_cpp'
when 'html', 'htm' then 'html'
when 'css' then 'css'
when 'java' then 'java'
when 'xml' then 'xml'
else 'text'
new (require("ace/mode/#{modeName}").Mode)
toggleLineCommentsInRange: (range) ->
range = Range.fromObject(range)
@aceMode.toggleCommentLines(@stateForRow(range.start.row), @aceAdaptor, range.start.row, range.end.row)
isBufferRowFoldable: (bufferRow) ->
@aceMode.foldingRules?.getFoldWidget(@aceAdaptor, null, bufferRow) == "start"
rowRangeForFoldAtBufferRow: (bufferRow) ->
if aceRange = @aceMode.foldingRules?.getFoldWidgetRange(@aceAdaptor, null, bufferRow)
[aceRange.start.row, aceRange.end.row]
else
null
indentationForRow: (row) ->
state = @stateForRow(row)
previousRowText = @buffer.lineForRow(row - 1)
@aceMode.getNextLineIndent(state, previousRowText, @tabText)
autoIndentTextAfterBufferPosition: (text, bufferPosition) ->
{ row, column} = bufferPosition
state = @stateForRow(row)
lineBeforeCursor = @buffer.lineForRow(row)[0...column]
if text[0] == "\n"
indent = @aceMode.getNextLineIndent(state, lineBeforeCursor, @tabText)
text = text[0] + indent + text[1..]
else if @aceMode.checkOutdent(state, lineBeforeCursor, text)
shouldOutdent = true
{text, shouldOutdent}
autoOutdentBufferRow: (bufferRow) ->
state = @stateForRow(bufferRow)
@aceMode.autoOutdent(state, @aceAdaptor, bufferRow)
handleBufferChange: (e) ->
oldRange = e.oldRange.copy()
@@ -108,9 +59,8 @@ class TokenizedBuffer
screenLine
buildScreenLineForRow: (state, row) ->
tokenizer = @aceMode.getTokenizer()
line = @buffer.lineForRow(row)
{tokens, state} = tokenizer.getLineTokens(line, state)
{tokens, state} = @languageMode.getLineTokens(line, state)
tokenObjects = []
for tokenProperties in tokens
token = new Token(tokenProperties)