mirror of
https://github.com/pulsar-edit/pulsar.git
synced 2024-09-20 07:28:08 +03:00
Make TokenizedBuffer a telepath.Model subclass
There's a bunch of improvised code to make this work right now because of the circularity of this refactoring. It will stabilize over time.
This commit is contained in:
parent
b61654b52f
commit
a4d2b4d21a
@ -2389,17 +2389,16 @@ describe "Editor", ->
|
||||
|
||||
describe "when a better-matched grammar is added to syntax", ->
|
||||
it "switches to the better-matched grammar and re-tokenizes the buffer", ->
|
||||
editor.destroy()
|
||||
jsGrammar = atom.syntax.selectGrammar('a.js')
|
||||
atom.syntax.removeGrammar(jsGrammar)
|
||||
|
||||
editor = atom.project.openSync('sample.js', autoIndent: false)
|
||||
expect(editor.getGrammar()).toBe atom.syntax.nullGrammar
|
||||
expect(editor.lineForScreenRow(0).tokens.length).toBe 1
|
||||
editor2 = atom.project.openSync('sample.js', autoIndent: false)
|
||||
expect(editor2.getGrammar()).toBe atom.syntax.nullGrammar
|
||||
expect(editor2.lineForScreenRow(0).tokens.length).toBe 1
|
||||
|
||||
atom.syntax.addGrammar(jsGrammar)
|
||||
expect(editor.getGrammar()).toBe jsGrammar
|
||||
expect(editor.lineForScreenRow(0).tokens.length).toBeGreaterThan 1
|
||||
expect(editor2.getGrammar()).toBe jsGrammar
|
||||
expect(editor2.lineForScreenRow(0).tokens.length).toBeGreaterThan 1
|
||||
|
||||
describe "auto-indent", ->
|
||||
copyText = (text, {startColumn}={}) ->
|
||||
|
@ -698,18 +698,16 @@ describe "Pane", ->
|
||||
expect(newPane.items.length).toBe pane.items.length - 1
|
||||
|
||||
it "focuses the pane after attach only if had focus when serialized", ->
|
||||
reloadContainer = ->
|
||||
containerState = container.serialize()
|
||||
container.remove()
|
||||
container = atom.deserializers.deserialize(containerState)
|
||||
pane = container.getRoot()
|
||||
container.attachToDom()
|
||||
|
||||
container.attachToDom()
|
||||
pane.focus()
|
||||
reloadContainer()
|
||||
expect(pane).toMatchSelector(':has(:focus)')
|
||||
|
||||
container2 = atom.deserializers.deserialize(container.serialize())
|
||||
pane2 = container2.getRoot()
|
||||
container2.attachToDom()
|
||||
expect(pane2).toMatchSelector(':has(:focus)')
|
||||
|
||||
$(document.activeElement).blur()
|
||||
reloadContainer()
|
||||
expect(pane).not.toMatchSelector(':has(:focus)')
|
||||
container3 = atom.deserializers.deserialize(container.serialize())
|
||||
pane3 = container3.getRoot()
|
||||
container3.attachToDom()
|
||||
expect(pane3).not.toMatchSelector(':has(:focus)')
|
||||
|
@ -18,22 +18,14 @@ describe "TokenizedBuffer", ->
|
||||
advanceClock() while tokenizedBuffer.firstInvalidRow()?
|
||||
changeHandler?.reset()
|
||||
|
||||
describe "@deserialize(state)", ->
|
||||
it "constructs a tokenized buffer with the same buffer and tabLength setting", ->
|
||||
buffer = atom.project.bufferForPathSync('sample.js')
|
||||
tokenizedBuffer1 = new TokenizedBuffer(buffer: buffer, tabLength: 4)
|
||||
tokenizedBuffer2 = atom.deserializers.deserialize(tokenizedBuffer1.serialize())
|
||||
expect(tokenizedBuffer2.buffer).toBe tokenizedBuffer1.buffer
|
||||
expect(tokenizedBuffer2.getTabLength()).toBe tokenizedBuffer1.getTabLength()
|
||||
|
||||
describe "when the buffer is destroyed", ->
|
||||
beforeEach ->
|
||||
buffer = atom.project.bufferForPathSync('sample.js')
|
||||
tokenizedBuffer = new TokenizedBuffer({buffer})
|
||||
tokenizedBuffer = atom.create(new TokenizedBuffer({buffer}))
|
||||
startTokenizing(tokenizedBuffer)
|
||||
|
||||
it "stops tokenization", ->
|
||||
tokenizedBuffer.destroy()
|
||||
tokenizedBuffer.state.destroy()
|
||||
spyOn(tokenizedBuffer, 'tokenizeNextChunk')
|
||||
advanceClock()
|
||||
expect(tokenizedBuffer.tokenizeNextChunk).not.toHaveBeenCalled()
|
||||
@ -41,7 +33,7 @@ describe "TokenizedBuffer", ->
|
||||
describe "when the buffer contains soft-tabs", ->
|
||||
beforeEach ->
|
||||
buffer = atom.project.bufferForPathSync('sample.js')
|
||||
tokenizedBuffer = new TokenizedBuffer({buffer})
|
||||
tokenizedBuffer = atom.create(new TokenizedBuffer({buffer}))
|
||||
startTokenizing(tokenizedBuffer)
|
||||
tokenizedBuffer.on "changed", changeHandler = jasmine.createSpy('changeHandler')
|
||||
|
||||
@ -321,7 +313,7 @@ describe "TokenizedBuffer", ->
|
||||
beforeEach ->
|
||||
atom.packages.activatePackage('language-coffee-script', sync: true)
|
||||
buffer = atom.project.bufferForPathSync('sample-with-tabs.coffee')
|
||||
tokenizedBuffer = new TokenizedBuffer({buffer})
|
||||
tokenizedBuffer = atom.create(new TokenizedBuffer({buffer}))
|
||||
startTokenizing(tokenizedBuffer)
|
||||
|
||||
afterEach ->
|
||||
@ -355,7 +347,7 @@ describe "TokenizedBuffer", ->
|
||||
'abc\uD835\uDF97def'
|
||||
//\uD835\uDF97xyz
|
||||
"""
|
||||
tokenizedBuffer = new TokenizedBuffer({buffer})
|
||||
tokenizedBuffer = atom.create(new TokenizedBuffer({buffer}))
|
||||
fullyTokenize(tokenizedBuffer)
|
||||
|
||||
afterEach ->
|
||||
@ -392,7 +384,7 @@ describe "TokenizedBuffer", ->
|
||||
|
||||
buffer = atom.project.bufferForPathSync()
|
||||
buffer.setText "<div class='name'><%= User.find(2).full_name %></div>"
|
||||
tokenizedBuffer = new TokenizedBuffer({buffer})
|
||||
tokenizedBuffer = atom.create(new TokenizedBuffer({buffer}))
|
||||
tokenizedBuffer.setGrammar(atom.syntax.selectGrammar('test.erb'))
|
||||
fullyTokenize(tokenizedBuffer)
|
||||
|
||||
@ -411,7 +403,7 @@ describe "TokenizedBuffer", ->
|
||||
|
||||
it "returns the correct token (regression)", ->
|
||||
buffer = atom.project.bufferForPathSync('sample.js')
|
||||
tokenizedBuffer = new TokenizedBuffer({buffer})
|
||||
tokenizedBuffer = atom.create(new TokenizedBuffer({buffer}))
|
||||
fullyTokenize(tokenizedBuffer)
|
||||
expect(tokenizedBuffer.tokenForPosition([1,0]).scopes).toEqual ["source.js"]
|
||||
expect(tokenizedBuffer.tokenForPosition([1,1]).scopes).toEqual ["source.js"]
|
||||
@ -420,7 +412,7 @@ describe "TokenizedBuffer", ->
|
||||
describe ".bufferRangeForScopeAtPosition(selector, position)", ->
|
||||
beforeEach ->
|
||||
buffer = atom.project.bufferForPathSync('sample.js')
|
||||
tokenizedBuffer = new TokenizedBuffer({buffer})
|
||||
tokenizedBuffer = atom.create(new TokenizedBuffer({buffer}))
|
||||
fullyTokenize(tokenizedBuffer)
|
||||
|
||||
describe "when the selector does not match the token at the position", ->
|
||||
|
@ -80,6 +80,11 @@ class Atom
|
||||
setBodyPlatformClass: ->
|
||||
document.body.classList.add("platform-#{process.platform}")
|
||||
|
||||
# Public: Create a new telepath model. This won't be needed when Atom is itself
|
||||
# a telepath model.
|
||||
create: (model) ->
|
||||
@site.createDocument(model)
|
||||
|
||||
# Public: Get the current window
|
||||
getCurrentWindow: ->
|
||||
remote.getCurrentWindow()
|
||||
@ -420,7 +425,7 @@ class Atom
|
||||
serializedWindowState = @loadSerializedWindowState()
|
||||
doc = Document.deserialize(serializedWindowState) if serializedWindowState?
|
||||
doc ?= Document.create()
|
||||
doc.registerModelClasses(require('./text-buffer'), require('./project'))
|
||||
doc.registerModelClasses(require('./text-buffer'), require('./project'), require('./tokenized-buffer'))
|
||||
# TODO: Remove this when everything is using telepath models
|
||||
if @site?
|
||||
@site.setRootDocument(doc)
|
||||
|
@ -27,17 +27,18 @@ class DisplayBuffer
|
||||
if optionsOrState instanceof telepath.Document
|
||||
@state = optionsOrState
|
||||
@id = @state.get('id')
|
||||
@tokenizedBuffer = atom.deserializers.deserialize(@state.get('tokenizedBuffer'))
|
||||
@tokenizedBuffer = @state.get('tokenizedBuffer')
|
||||
@tokenizedBuffer.created()
|
||||
@buffer = @tokenizedBuffer.buffer
|
||||
else
|
||||
{@buffer, softWrap, editorWidthInChars} = optionsOrState
|
||||
{@buffer, softWrap, editorWidthInChars, tabLength} = optionsOrState
|
||||
@id = guid.create().toString()
|
||||
@tokenizedBuffer = new TokenizedBuffer(optionsOrState)
|
||||
@tokenizedBuffer = new TokenizedBuffer({tabLength, @buffer, project: atom.project})
|
||||
@state = atom.site.createDocument
|
||||
deserializer: @constructor.name
|
||||
version: @constructor.version
|
||||
id: @id
|
||||
tokenizedBuffer: @tokenizedBuffer.getState()
|
||||
tokenizedBuffer: @tokenizedBuffer
|
||||
softWrap: softWrap ? atom.config.get('editor.softWrap') ? false
|
||||
editorWidthInChars: editorWidthInChars
|
||||
|
||||
@ -62,6 +63,7 @@ class DisplayBuffer
|
||||
@updateWrappedScreenLines() if @getSoftWrap()
|
||||
|
||||
serialize: -> @state.clone()
|
||||
|
||||
getState: -> @state
|
||||
|
||||
copy: ->
|
||||
@ -654,6 +656,7 @@ class DisplayBuffer
|
||||
softWraps = 0
|
||||
while wrapScreenColumn = @findWrapColumn(tokenizedLine.text)
|
||||
[wrappedLine, tokenizedLine] = tokenizedLine.softWrapAt(wrapScreenColumn)
|
||||
|
||||
newScreenLines.push(wrappedLine)
|
||||
softWraps++
|
||||
newScreenLines.push(tokenizedLine)
|
||||
|
@ -106,7 +106,7 @@ class EditorView extends View
|
||||
@edit(editor)
|
||||
else if @mini
|
||||
@edit(new Editor
|
||||
buffer: TextBuffer.createAsRoot()
|
||||
buffer: atom.create(new TextBuffer)
|
||||
softWrap: false
|
||||
tabLength: 2
|
||||
softTabs: true
|
||||
|
@ -34,7 +34,7 @@ class Project extends telepath.Model
|
||||
# Private: Called by telepath.
|
||||
created: ->
|
||||
for buffer in @buffers.getValues()
|
||||
buffer.once 'destroyed', (buffer) => @removeBuffer(buffer)
|
||||
buffer.once 'destroyed', (buffer) => @removeBuffer(buffer) if @isAlive()
|
||||
|
||||
@openers = []
|
||||
@editors = []
|
||||
@ -64,7 +64,7 @@ class Project extends telepath.Model
|
||||
# Private:
|
||||
destroyed: ->
|
||||
editor.destroy() for editor in @getEditors()
|
||||
buffer.release() for buffer in @getBuffers()
|
||||
buffer.destroy() for buffer in @getBuffers()
|
||||
@destroyRepo()
|
||||
|
||||
# Private:
|
||||
@ -239,7 +239,7 @@ class Project extends telepath.Model
|
||||
# Private:
|
||||
addBufferAtIndex: (buffer, index, options={}) ->
|
||||
buffer = @buffers.insert(index, buffer)
|
||||
buffer.once 'destroyed', => @removeBuffer(buffer)
|
||||
buffer.once 'destroyed', => @removeBuffer(buffer) if @isAlive()
|
||||
@emit 'buffer-created', buffer
|
||||
buffer
|
||||
|
||||
|
@ -81,12 +81,12 @@ class TextBuffer extends telepath.Model
|
||||
@emit 'changed', bufferChangeEvent
|
||||
@scheduleModifiedEvents()
|
||||
|
||||
destroy: ->
|
||||
unless @destroyed
|
||||
destroyed: ->
|
||||
unless @alreadyDestroyed
|
||||
@cancelStoppedChangingTimeout()
|
||||
@file?.off()
|
||||
@unsubscribe()
|
||||
@destroyed = true
|
||||
@alreadyDestroyed = true
|
||||
@emit 'destroyed', this
|
||||
|
||||
isRetained: -> @refcount > 0
|
||||
|
@ -1,16 +1,16 @@
|
||||
_ = require 'underscore-plus'
|
||||
TokenizedLine = require './tokenized-line'
|
||||
{Emitter, Subscriber} = require 'emissary'
|
||||
Token = require './token'
|
||||
telepath = require 'telepath'
|
||||
{Point, Range} = telepath
|
||||
{Model, Point, Range} = require 'telepath'
|
||||
|
||||
### Internal ###
|
||||
|
||||
module.exports =
|
||||
class TokenizedBuffer
|
||||
Emitter.includeInto(this)
|
||||
Subscriber.includeInto(this)
|
||||
class TokenizedBuffer extends Model
|
||||
@properties
|
||||
bufferPath: null
|
||||
tabLength: -> atom.config.get('editor.tabLength') ? 2
|
||||
project: null
|
||||
|
||||
grammar: null
|
||||
currentGrammarScore: null
|
||||
@ -20,24 +20,19 @@ class TokenizedBuffer
|
||||
invalidRows: null
|
||||
visible: false
|
||||
|
||||
@acceptsDocuments: true
|
||||
atom.deserializers.add(this)
|
||||
constructor: ->
|
||||
super
|
||||
@deserializing = @state?
|
||||
|
||||
@deserialize: (state) ->
|
||||
new this(state)
|
||||
created: ->
|
||||
if @deserializing
|
||||
@deserializing = false
|
||||
return this
|
||||
|
||||
constructor: (optionsOrState) ->
|
||||
if optionsOrState instanceof telepath.Document
|
||||
@state = optionsOrState
|
||||
|
||||
# TODO: This needs to be made async, but should wait until the new Telepath changes land
|
||||
@buffer = atom.project.bufferForPathSync(optionsOrState.get('bufferPath'))
|
||||
if @buffer? and @buffer.isAlive()
|
||||
@bufferPath = @buffer.getPath()
|
||||
else
|
||||
{ @buffer, tabLength } = optionsOrState
|
||||
@state = atom.site.createDocument
|
||||
deserializer: @constructor.name
|
||||
bufferPath: @buffer.getPath()
|
||||
tabLength: tabLength ? atom.config.get('editor.tabLength') ? 2
|
||||
@buffer = @project.bufferForPathSync(@bufferPath)
|
||||
|
||||
@subscribe atom.syntax, 'grammar-added grammar-updated', (grammar) =>
|
||||
if grammar.injectionSelector?
|
||||
@ -48,12 +43,22 @@ class TokenizedBuffer
|
||||
|
||||
@on 'grammar-changed grammar-updated', => @resetTokenizedLines()
|
||||
@subscribe @buffer, "changed", (e) => @handleBufferChange(e)
|
||||
@subscribe @buffer, "path-changed", => @state.set('bufferPath', @buffer.getPath())
|
||||
@subscribe @buffer, "path-changed", => @bufferPath = @buffer.getPath()
|
||||
|
||||
@subscribe @$tabLength.changes.onValue (tabLength) =>
|
||||
lastRow = @buffer.getLastRow()
|
||||
@tokenizedLines = @buildPlaceholderTokenizedLinesForRows(0, lastRow)
|
||||
@invalidateRow(0)
|
||||
@emit "changed", { start: 0, end: lastRow, delta: 0 }
|
||||
|
||||
@reloadGrammar()
|
||||
|
||||
serialize: -> @state.clone()
|
||||
getState: -> @state
|
||||
# TODO: Remove when everything is a telepath model
|
||||
destroy: ->
|
||||
@destroyed()
|
||||
|
||||
destroyed: ->
|
||||
@unsubscribe()
|
||||
|
||||
setGrammar: (grammar, score) ->
|
||||
return if grammar is @grammar
|
||||
@ -87,24 +92,19 @@ class TokenizedBuffer
|
||||
#
|
||||
# Returns a {Number}.
|
||||
getTabLength: ->
|
||||
@state.get('tabLength')
|
||||
@tabLength
|
||||
|
||||
# Specifies the tab length.
|
||||
#
|
||||
# tabLength - A {Number} that defines the new tab length.
|
||||
setTabLength: (tabLength) ->
|
||||
@state.set('tabLength', tabLength)
|
||||
lastRow = @buffer.getLastRow()
|
||||
@tokenizedLines = @buildPlaceholderTokenizedLinesForRows(0, lastRow)
|
||||
@invalidateRow(0)
|
||||
@emit "changed", { start: 0, end: lastRow, delta: 0 }
|
||||
setTabLength: (@tabLength) ->
|
||||
|
||||
tokenizeInBackground: ->
|
||||
return if not @visible or @pendingChunk or @destroyed
|
||||
return if not @visible or @pendingChunk or not @isAlive()
|
||||
@pendingChunk = true
|
||||
_.defer =>
|
||||
@pendingChunk = false
|
||||
@tokenizeNextChunk() unless @destroyed
|
||||
@tokenizeNextChunk() if @isAlive() and @buffer.isAlive()
|
||||
|
||||
tokenizeNextChunk: ->
|
||||
rowsRemaining = @chunkSize
|
||||
@ -248,10 +248,6 @@ class TokenizedBuffer
|
||||
endColumn = tokenizedLine.bufferColumnForToken(lastToken) + lastToken.bufferDelta
|
||||
new Range([position.row, startColumn], [position.row, endColumn])
|
||||
|
||||
destroy: ->
|
||||
@unsubscribe()
|
||||
@destroyed = true
|
||||
|
||||
iterateTokensInBufferRange: (bufferRange, iterator) ->
|
||||
bufferRange = Range.fromObject(bufferRange)
|
||||
{ start, end } = bufferRange
|
||||
|
Loading…
Reference in New Issue
Block a user