mirror of
https://github.com/pulsar-edit/pulsar.git
synced 2024-11-13 08:44:12 +03:00
Add top-level .content object to presenter state
It contains the .scrollWidth and then all the lines in a nested .lines object. The .width has been removed from each line and replaced with .content.scrollWidth.
This commit is contained in:
parent
3ec4b632ba
commit
0a9f7586ae
@ -18,13 +18,63 @@ describe "TextEditorPresenter", ->
|
||||
for key, value of expected
|
||||
expect(actual[key]).toBe value
|
||||
|
||||
describe "lines", ->
|
||||
describe "::state.content", ->
|
||||
describe "on initialization", ->
|
||||
it "assigns .scrollWidth based on the clientWidth and the width of the longest line", ->
|
||||
maxLineLength = editor.getMaxScreenLineLength()
|
||||
|
||||
presenter = new TextEditorPresenter(model: editor, clientHeight: 25, clientWidth: 50, scrollTop: 0, baseCharacterWidth: 10, lineHeight: 10, lineOverdrawMargin: 0)
|
||||
expect(presenter.state.content.scrollWidth).toBe 10 * maxLineLength + 1
|
||||
|
||||
presenter = new TextEditorPresenter(model: editor, clientHeight: 25, clientWidth: 10 * maxLineLength + 20, scrollTop: 0, baseCharacterWidth: 10, lineHeight: 10, lineOverdrawMargin: 0)
|
||||
expect(presenter.state.content.scrollWidth).toBe 10 * maxLineLength + 20
|
||||
|
||||
describe "when the ::clientWidth changes", ->
|
||||
it "updates .scrollWidth", ->
|
||||
maxLineLength = editor.getMaxScreenLineLength()
|
||||
presenter = new TextEditorPresenter(model: editor, clientHeight: 25, clientWidth: 50, scrollTop: 0, scrollWidth: 70, lineHeight: 10, baseCharacterWidth: 10, lineOverdrawMargin: 0)
|
||||
|
||||
expect(presenter.state.content.scrollWidth).toBe 10 * maxLineLength + 1
|
||||
presenter.setClientWidth(10 * maxLineLength + 20)
|
||||
expect(presenter.state.content.scrollWidth).toBe 10 * maxLineLength + 20
|
||||
|
||||
describe "when the ::baseCharacterWidth changes", ->
|
||||
it "updates the width of the lines if it changes the ::scrollWidth", ->
|
||||
maxLineLength = editor.getMaxScreenLineLength()
|
||||
presenter = new TextEditorPresenter(model: editor, clientHeight: 25, clientWidth: 50, scrollTop: 0, scrollWidth: 70, lineHeight: 10, baseCharacterWidth: 10, lineOverdrawMargin: 0)
|
||||
|
||||
expect(presenter.state.content.scrollWidth).toBe 10 * maxLineLength + 1
|
||||
presenter.setBaseCharacterWidth(15)
|
||||
expect(presenter.state.content.scrollWidth).toBe 15 * maxLineLength + 1
|
||||
|
||||
describe "when the scoped character widths change", ->
|
||||
beforeEach ->
|
||||
waitsForPromise -> atom.packages.activatePackage('language-javascript')
|
||||
|
||||
it "updates the width of the lines if the ::scrollWidth changes", ->
|
||||
maxLineLength = editor.getMaxScreenLineLength()
|
||||
presenter = new TextEditorPresenter(model: editor, clientHeight: 25, clientWidth: 50, scrollTop: 0, scrollWidth: 70, lineHeight: 10, baseCharacterWidth: 10, lineOverdrawMargin: 0)
|
||||
|
||||
expect(presenter.state.content.scrollWidth).toBe 10 * maxLineLength + 1
|
||||
presenter.setScopedCharWidth(['source.js', 'support.function.js'], 'p', 20)
|
||||
expect(presenter.state.content.scrollWidth).toBe (10 * (maxLineLength - 2)) + (20 * 2) + 1 # 2 of the characters are 20px wide now instead of 10px wide
|
||||
|
||||
describe "when ::softWrapped changes on the editor", ->
|
||||
it "only accounts for the cursor in .scrollWidth if ::softWrapped is false", ->
|
||||
presenter = new TextEditorPresenter(model: editor, clientHeight: 25, clientWidth: 50, scrollTop: 0, scrollWidth: 70, lineHeight: 10, baseCharacterWidth: 10, lineOverdrawMargin: 0)
|
||||
expect(presenter.state.content.scrollWidth).toBe 10 * editor.getMaxScreenLineLength() + 1
|
||||
editor.setSoftWrapped(true)
|
||||
expect(presenter.state.content.scrollWidth).toBe 10 * editor.getMaxScreenLineLength()
|
||||
editor.setSoftWrapped(false)
|
||||
expect(presenter.state.content.scrollWidth).toBe 10 * editor.getMaxScreenLineLength() + 1
|
||||
|
||||
describe "::state.content.lines", ->
|
||||
describe "on initialization", ->
|
||||
it "contains the lines that are visible on screen, plus the overdraw margin", ->
|
||||
presenter = new TextEditorPresenter(model: editor, clientHeight: 25, scrollTop: 0, lineHeight: 10, lineOverdrawMargin: 1)
|
||||
|
||||
line0 = editor.tokenizedLineForScreenRow(0)
|
||||
expectValues presenter.state.lines[line0.id], {
|
||||
expectValues presenter.state.content.lines[line0.id], {
|
||||
screenRow: 0
|
||||
text: line0.text
|
||||
tokens: line0.tokens
|
||||
@ -32,7 +82,7 @@ describe "TextEditorPresenter", ->
|
||||
}
|
||||
|
||||
line1 = editor.tokenizedLineForScreenRow(1)
|
||||
expectValues presenter.state.lines[line1.id], {
|
||||
expectValues presenter.state.content.lines[line1.id], {
|
||||
screenRow: 1
|
||||
text: line1.text
|
||||
tokens: line1.tokens
|
||||
@ -40,7 +90,7 @@ describe "TextEditorPresenter", ->
|
||||
}
|
||||
|
||||
line2 = editor.tokenizedLineForScreenRow(2)
|
||||
expectValues presenter.state.lines[line2.id], {
|
||||
expectValues presenter.state.content.lines[line2.id], {
|
||||
screenRow: 2
|
||||
text: line2.text
|
||||
tokens: line2.tokens
|
||||
@ -49,7 +99,7 @@ describe "TextEditorPresenter", ->
|
||||
|
||||
# this row is rendered due to the overdraw margin
|
||||
line3 = editor.tokenizedLineForScreenRow(3)
|
||||
expectValues presenter.state.lines[line3.id], {
|
||||
expectValues presenter.state.content.lines[line3.id], {
|
||||
screenRow: 3
|
||||
text: line3.text
|
||||
tokens: line3.tokens
|
||||
@ -61,7 +111,7 @@ describe "TextEditorPresenter", ->
|
||||
|
||||
# this row is rendered due to the overdraw margin
|
||||
line10 = editor.tokenizedLineForScreenRow(10)
|
||||
expectValues presenter.state.lines[line10.id], {
|
||||
expectValues presenter.state.content.lines[line10.id], {
|
||||
screenRow: 10
|
||||
text: line10.text
|
||||
tokens: line10.tokens
|
||||
@ -69,7 +119,7 @@ describe "TextEditorPresenter", ->
|
||||
}
|
||||
|
||||
line11 = editor.tokenizedLineForScreenRow(11)
|
||||
expectValues presenter.state.lines[line11.id], {
|
||||
expectValues presenter.state.content.lines[line11.id], {
|
||||
screenRow: 11
|
||||
text: line11.text
|
||||
tokens: line11.tokens
|
||||
@ -77,7 +127,7 @@ describe "TextEditorPresenter", ->
|
||||
}
|
||||
|
||||
line12 = editor.tokenizedLineForScreenRow(12)
|
||||
expectValues presenter.state.lines[line12.id], {
|
||||
expectValues presenter.state.content.lines[line12.id], {
|
||||
screenRow: 12
|
||||
text: line12.text
|
||||
tokens: line12.tokens
|
||||
@ -88,43 +138,26 @@ describe "TextEditorPresenter", ->
|
||||
|
||||
it "contains the lines that are visible on screen, plus and minus the overdraw margin", ->
|
||||
presenter = new TextEditorPresenter(model: editor, clientHeight: 25, scrollTop: 50, lineHeight: 10, lineOverdrawMargin: 1)
|
||||
expect(presenter.state.lines[editor.tokenizedLineForScreenRow(3).id]).toBeUndefined()
|
||||
expect(presenter.state.lines[editor.tokenizedLineForScreenRow(4).id]).toBeDefined()
|
||||
expect(presenter.state.lines[editor.tokenizedLineForScreenRow(9).id]).toBeDefined()
|
||||
expect(presenter.state.lines[editor.tokenizedLineForScreenRow(10).id]).toBeUndefined()
|
||||
expect(presenter.state.content.lines[editor.tokenizedLineForScreenRow(3).id]).toBeUndefined()
|
||||
expect(presenter.state.content.lines[editor.tokenizedLineForScreenRow(4).id]).toBeDefined()
|
||||
expect(presenter.state.content.lines[editor.tokenizedLineForScreenRow(9).id]).toBeDefined()
|
||||
expect(presenter.state.content.lines[editor.tokenizedLineForScreenRow(10).id]).toBeUndefined()
|
||||
|
||||
it "reports all lines as visible if no external ::clientHeight is assigned", ->
|
||||
presenter = new TextEditorPresenter(model: editor, scrollTop: 0, lineHeight: 10, lineOverdrawMargin: 1)
|
||||
expect(presenter.state.lines[editor.tokenizedLineForScreenRow(0).id]).toBeDefined()
|
||||
expect(presenter.state.lines[editor.tokenizedLineForScreenRow(12).id]).toBeDefined()
|
||||
|
||||
it "uses the computed scrollWidth as the length of each line", ->
|
||||
line0 = editor.tokenizedLineForScreenRow(0)
|
||||
line1 = editor.tokenizedLineForScreenRow(1)
|
||||
line2 = editor.tokenizedLineForScreenRow(2)
|
||||
|
||||
maxLineLength = editor.getMaxScreenLineLength()
|
||||
|
||||
presenter = new TextEditorPresenter(model: editor, clientHeight: 25, clientWidth: 50, scrollTop: 0, baseCharacterWidth: 10, lineHeight: 10, lineOverdrawMargin: 0)
|
||||
expect(presenter.state.lines[line0.id].width).toBe 10 * maxLineLength + 1
|
||||
expect(presenter.state.lines[line1.id].width).toBe 10 * maxLineLength + 1
|
||||
expect(presenter.state.lines[line2.id].width).toBe 10 * maxLineLength + 1
|
||||
|
||||
presenter = new TextEditorPresenter(model: editor, clientHeight: 25, clientWidth: 10 * maxLineLength + 20, scrollTop: 0, baseCharacterWidth: 10, lineHeight: 10, lineOverdrawMargin: 0)
|
||||
expect(presenter.state.lines[line0.id].width).toBe 10 * maxLineLength + 20
|
||||
expect(presenter.state.lines[line1.id].width).toBe 10 * maxLineLength + 20
|
||||
expect(presenter.state.lines[line2.id].width).toBe 10 * maxLineLength + 20
|
||||
expect(presenter.state.content.lines[editor.tokenizedLineForScreenRow(0).id]).toBeDefined()
|
||||
expect(presenter.state.content.lines[editor.tokenizedLineForScreenRow(12).id]).toBeDefined()
|
||||
|
||||
it "includes the endOfLineInvisibles in the line state", ->
|
||||
editor.setText("hello\nworld\r\n")
|
||||
presenter = new TextEditorPresenter(model: editor, clientHeight: 25, clientWidth: 50, scrollTop: 0, baseCharacterWidth: 10, lineHeight: 10, lineOverdrawMargin: 0)
|
||||
expect(presenter.state.lines[editor.tokenizedLineForScreenRow(0).id].endOfLineInvisibles).toBeNull()
|
||||
expect(presenter.state.lines[editor.tokenizedLineForScreenRow(1).id].endOfLineInvisibles).toBeNull()
|
||||
expect(presenter.state.content.lines[editor.tokenizedLineForScreenRow(0).id].endOfLineInvisibles).toBeNull()
|
||||
expect(presenter.state.content.lines[editor.tokenizedLineForScreenRow(1).id].endOfLineInvisibles).toBeNull()
|
||||
|
||||
atom.config.set('editor.showInvisibles', true)
|
||||
presenter = new TextEditorPresenter(model: editor, clientHeight: 25, clientWidth: 50, scrollTop: 0, baseCharacterWidth: 10, lineHeight: 10, lineOverdrawMargin: 0)
|
||||
expect(presenter.state.lines[editor.tokenizedLineForScreenRow(0).id].endOfLineInvisibles).toEqual [atom.config.get('editor.invisibles.eol')]
|
||||
expect(presenter.state.lines[editor.tokenizedLineForScreenRow(1).id].endOfLineInvisibles).toEqual [atom.config.get('editor.invisibles.cr'), atom.config.get('editor.invisibles.eol')]
|
||||
expect(presenter.state.content.lines[editor.tokenizedLineForScreenRow(0).id].endOfLineInvisibles).toEqual [atom.config.get('editor.invisibles.eol')]
|
||||
expect(presenter.state.content.lines[editor.tokenizedLineForScreenRow(1).id].endOfLineInvisibles).toEqual [atom.config.get('editor.invisibles.cr'), atom.config.get('editor.invisibles.eol')]
|
||||
|
||||
describe "when ::scrollTop changes", ->
|
||||
it "updates the lines that are visible on screen", ->
|
||||
@ -132,10 +165,10 @@ describe "TextEditorPresenter", ->
|
||||
presenter.setScrollTop(25)
|
||||
|
||||
line0 = editor.tokenizedLineForScreenRow(0)
|
||||
expect(presenter.state.lines[line0.id]).toBeUndefined()
|
||||
expect(presenter.state.content.lines[line0.id]).toBeUndefined()
|
||||
|
||||
line1 = editor.tokenizedLineForScreenRow(1)
|
||||
expectValues presenter.state.lines[line1.id], {
|
||||
expectValues presenter.state.content.lines[line1.id], {
|
||||
screenRow: 1
|
||||
text: line1.text
|
||||
tokens: line1.tokens
|
||||
@ -143,7 +176,7 @@ describe "TextEditorPresenter", ->
|
||||
}
|
||||
|
||||
line2 = editor.tokenizedLineForScreenRow(2)
|
||||
expectValues presenter.state.lines[line2.id], {
|
||||
expectValues presenter.state.content.lines[line2.id], {
|
||||
screenRow: 2
|
||||
text: line2.text
|
||||
tokens: line2.tokens
|
||||
@ -151,7 +184,7 @@ describe "TextEditorPresenter", ->
|
||||
}
|
||||
|
||||
line3 = editor.tokenizedLineForScreenRow(3)
|
||||
expectValues presenter.state.lines[line3.id], {
|
||||
expectValues presenter.state.content.lines[line3.id], {
|
||||
screenRow: 3
|
||||
text: line3.text
|
||||
tokens: line3.tokens
|
||||
@ -159,7 +192,7 @@ describe "TextEditorPresenter", ->
|
||||
}
|
||||
|
||||
line4 = editor.tokenizedLineForScreenRow(4)
|
||||
expectValues presenter.state.lines[line4.id], {
|
||||
expectValues presenter.state.content.lines[line4.id], {
|
||||
screenRow: 4
|
||||
text: line4.text
|
||||
tokens: line4.tokens
|
||||
@ -171,12 +204,12 @@ describe "TextEditorPresenter", ->
|
||||
presenter = new TextEditorPresenter(model: editor, clientHeight: 15, scrollTop: 15, lineHeight: 10, lineOverdrawMargin: 1)
|
||||
|
||||
line5 = editor.tokenizedLineForScreenRow(5)
|
||||
expect(presenter.state.lines[line5.id]).toBeUndefined()
|
||||
expect(presenter.state.content.lines[line5.id]).toBeUndefined()
|
||||
|
||||
presenter.setClientHeight(35)
|
||||
|
||||
line1 = editor.tokenizedLineForScreenRow(1)
|
||||
expectValues presenter.state.lines[line1.id], {
|
||||
expectValues presenter.state.content.lines[line1.id], {
|
||||
screenRow: 1
|
||||
text: line1.text
|
||||
tokens: line1.tokens
|
||||
@ -184,7 +217,7 @@ describe "TextEditorPresenter", ->
|
||||
}
|
||||
|
||||
line2 = editor.tokenizedLineForScreenRow(2)
|
||||
expectValues presenter.state.lines[line2.id], {
|
||||
expectValues presenter.state.content.lines[line2.id], {
|
||||
screenRow: 2
|
||||
text: line2.text
|
||||
tokens: line2.tokens
|
||||
@ -192,7 +225,7 @@ describe "TextEditorPresenter", ->
|
||||
}
|
||||
|
||||
line3 = editor.tokenizedLineForScreenRow(3)
|
||||
expectValues presenter.state.lines[line3.id], {
|
||||
expectValues presenter.state.content.lines[line3.id], {
|
||||
screenRow: 3
|
||||
text: line3.text
|
||||
tokens: line3.tokens
|
||||
@ -200,14 +233,14 @@ describe "TextEditorPresenter", ->
|
||||
}
|
||||
|
||||
line4 = editor.tokenizedLineForScreenRow(4)
|
||||
expectValues presenter.state.lines[line4.id], {
|
||||
expectValues presenter.state.content.lines[line4.id], {
|
||||
screenRow: 4
|
||||
text: line4.text
|
||||
tokens: line4.tokens
|
||||
top: 10 * 4
|
||||
}
|
||||
|
||||
expectValues presenter.state.lines[line4.id], {
|
||||
expectValues presenter.state.content.lines[line4.id], {
|
||||
screenRow: 4
|
||||
text: line4.text
|
||||
tokens: line4.tokens
|
||||
@ -225,105 +258,45 @@ describe "TextEditorPresenter", ->
|
||||
line5 = editor.tokenizedLineForScreenRow(5)
|
||||
line6 = editor.tokenizedLineForScreenRow(6)
|
||||
|
||||
expect(presenter.state.lines[line1.id]).toBeDefined()
|
||||
expect(presenter.state.lines[line2.id]).toBeDefined()
|
||||
expect(presenter.state.lines[line3.id]).toBeDefined()
|
||||
expect(presenter.state.lines[line4.id]).toBeUndefined()
|
||||
expect(presenter.state.lines[line5.id]).toBeUndefined()
|
||||
expect(presenter.state.content.lines[line1.id]).toBeDefined()
|
||||
expect(presenter.state.content.lines[line2.id]).toBeDefined()
|
||||
expect(presenter.state.content.lines[line3.id]).toBeDefined()
|
||||
expect(presenter.state.content.lines[line4.id]).toBeUndefined()
|
||||
expect(presenter.state.content.lines[line5.id]).toBeUndefined()
|
||||
|
||||
presenter.setLineHeight(5)
|
||||
|
||||
expect(presenter.state.lines[line1.id]).toBeUndefined()
|
||||
expect(presenter.state.content.lines[line1.id]).toBeUndefined()
|
||||
|
||||
expectValues presenter.state.lines[line2.id], {
|
||||
expectValues presenter.state.content.lines[line2.id], {
|
||||
screenRow: 2
|
||||
text: line2.text
|
||||
tokens: line2.tokens
|
||||
top: 5 * 2
|
||||
}
|
||||
|
||||
expectValues presenter.state.lines[line3.id], {
|
||||
expectValues presenter.state.content.lines[line3.id], {
|
||||
screenRow: 3
|
||||
text: line3.text
|
||||
tokens: line3.tokens
|
||||
top: 5 * 3
|
||||
}
|
||||
|
||||
expectValues presenter.state.lines[line4.id], {
|
||||
expectValues presenter.state.content.lines[line4.id], {
|
||||
screenRow: 4
|
||||
text: line4.text
|
||||
tokens: line4.tokens
|
||||
top: 5 * 4
|
||||
}
|
||||
|
||||
expectValues presenter.state.lines[line5.id], {
|
||||
expectValues presenter.state.content.lines[line5.id], {
|
||||
screenRow: 5
|
||||
text: line5.text
|
||||
tokens: line5.tokens
|
||||
top: 5 * 5
|
||||
}
|
||||
|
||||
expect(presenter.state.lines[line6.id]).toBeUndefined()
|
||||
|
||||
describe "when the ::clientWidth changes", ->
|
||||
it "updates the width of the lines if it changes the ::scrollWidth", ->
|
||||
line0 = editor.tokenizedLineForScreenRow(0)
|
||||
line1 = editor.tokenizedLineForScreenRow(1)
|
||||
line2 = editor.tokenizedLineForScreenRow(2)
|
||||
|
||||
maxLineLength = editor.getMaxScreenLineLength()
|
||||
|
||||
presenter = new TextEditorPresenter(model: editor, clientHeight: 25, clientWidth: 50, scrollTop: 0, scrollWidth: 70, lineHeight: 10, baseCharacterWidth: 10, lineOverdrawMargin: 0)
|
||||
expect(presenter.state.lines[line0.id].width).toBe 10 * maxLineLength + 1
|
||||
expect(presenter.state.lines[line1.id].width).toBe 10 * maxLineLength + 1
|
||||
expect(presenter.state.lines[line2.id].width).toBe 10 * maxLineLength + 1
|
||||
|
||||
presenter.setClientWidth(10 * maxLineLength + 20)
|
||||
|
||||
expect(presenter.state.lines[line0.id].width).toBe 10 * maxLineLength + 20
|
||||
expect(presenter.state.lines[line1.id].width).toBe 10 * maxLineLength + 20
|
||||
expect(presenter.state.lines[line2.id].width).toBe 10 * maxLineLength + 20
|
||||
|
||||
describe "when the scoped character widths change", ->
|
||||
beforeEach ->
|
||||
waitsForPromise -> atom.packages.activatePackage('language-javascript')
|
||||
|
||||
it "updates the width of the lines if the ::scrollWidth changes", ->
|
||||
line0 = editor.tokenizedLineForScreenRow(0)
|
||||
line1 = editor.tokenizedLineForScreenRow(1)
|
||||
line2 = editor.tokenizedLineForScreenRow(2)
|
||||
|
||||
maxLineLength = editor.getMaxScreenLineLength()
|
||||
|
||||
presenter = new TextEditorPresenter(model: editor, clientHeight: 25, clientWidth: 50, scrollTop: 0, scrollWidth: 70, lineHeight: 10, baseCharacterWidth: 10, lineOverdrawMargin: 0)
|
||||
expect(presenter.state.lines[line0.id].width).toBe 10 * maxLineLength + 1
|
||||
expect(presenter.state.lines[line1.id].width).toBe 10 * maxLineLength + 1
|
||||
expect(presenter.state.lines[line2.id].width).toBe 10 * maxLineLength + 1
|
||||
|
||||
presenter.setScopedCharWidth(['source.js', 'support.function.js'], 'p', 20)
|
||||
|
||||
expect(presenter.state.lines[line0.id].width).toBe (10 * (maxLineLength - 2)) + (20 * 2) + 1 # 2 of the characters are 20px wide now instead of 10px wide
|
||||
expect(presenter.state.lines[line1.id].width).toBe (10 * (maxLineLength - 2)) + (20 * 2) + 1
|
||||
expect(presenter.state.lines[line2.id].width).toBe (10 * (maxLineLength - 2)) + (20 * 2) + 1
|
||||
|
||||
describe "when the ::baseCharacterWidth changes", ->
|
||||
it "updates the width of the lines if it changes the ::scrollWidth", ->
|
||||
line0 = editor.tokenizedLineForScreenRow(0)
|
||||
line1 = editor.tokenizedLineForScreenRow(1)
|
||||
line2 = editor.tokenizedLineForScreenRow(2)
|
||||
|
||||
maxLineLength = editor.getMaxScreenLineLength()
|
||||
|
||||
presenter = new TextEditorPresenter(model: editor, clientHeight: 25, clientWidth: 50, scrollTop: 0, scrollWidth: 70, lineHeight: 10, baseCharacterWidth: 10, lineOverdrawMargin: 0)
|
||||
expect(presenter.state.lines[line0.id].width).toBe 10 * maxLineLength + 1
|
||||
expect(presenter.state.lines[line1.id].width).toBe 10 * maxLineLength + 1
|
||||
expect(presenter.state.lines[line2.id].width).toBe 10 * maxLineLength + 1
|
||||
|
||||
presenter.setBaseCharacterWidth(15)
|
||||
|
||||
expect(presenter.state.lines[line0.id].width).toBe 15 * maxLineLength + 1
|
||||
expect(presenter.state.lines[line1.id].width).toBe 15 * maxLineLength + 1
|
||||
expect(presenter.state.lines[line2.id].width).toBe 15 * maxLineLength + 1
|
||||
expect(presenter.state.content.lines[line6.id]).toBeUndefined()
|
||||
|
||||
describe "when the editor's content changes", ->
|
||||
it "updates the lines state accordingly", ->
|
||||
@ -332,7 +305,7 @@ describe "TextEditorPresenter", ->
|
||||
buffer.insert([2, 0], "hello\nworld\n")
|
||||
|
||||
line1 = editor.tokenizedLineForScreenRow(1)
|
||||
expectValues presenter.state.lines[line1.id], {
|
||||
expectValues presenter.state.content.lines[line1.id], {
|
||||
screenRow: 1
|
||||
text: line1.text
|
||||
tokens: line1.tokens
|
||||
@ -340,7 +313,7 @@ describe "TextEditorPresenter", ->
|
||||
}
|
||||
|
||||
line2 = editor.tokenizedLineForScreenRow(2)
|
||||
expectValues presenter.state.lines[line2.id], {
|
||||
expectValues presenter.state.content.lines[line2.id], {
|
||||
screenRow: 2
|
||||
text: line2.text
|
||||
tokens: line2.tokens
|
||||
@ -348,18 +321,9 @@ describe "TextEditorPresenter", ->
|
||||
}
|
||||
|
||||
line3 = editor.tokenizedLineForScreenRow(3)
|
||||
expectValues presenter.state.lines[line3.id], {
|
||||
expectValues presenter.state.content.lines[line3.id], {
|
||||
screenRow: 3
|
||||
text: line3.text
|
||||
tokens: line3.tokens
|
||||
top: 10 * 3
|
||||
}
|
||||
|
||||
describe "when ::softWrapped changes on the editor", ->
|
||||
it "only accounts for the cursor width if ::softWrapped is false", ->
|
||||
presenter = new TextEditorPresenter(model: editor, clientHeight: 25, clientWidth: 50, scrollTop: 0, scrollWidth: 70, lineHeight: 10, baseCharacterWidth: 10, lineOverdrawMargin: 0)
|
||||
expect(presenter.state.lines[editor.tokenizedLineForScreenRow(0).id].width).toBe 10 * editor.getMaxScreenLineLength() + 1
|
||||
editor.setSoftWrapped(true)
|
||||
expect(presenter.state.lines[editor.tokenizedLineForScreenRow(0).id].width).toBe 10 * editor.getMaxScreenLineLength()
|
||||
editor.setSoftWrapped(false)
|
||||
expect(presenter.state.lines[editor.tokenizedLineForScreenRow(0).id].width).toBe 10 * editor.getMaxScreenLineLength() + 1
|
||||
|
@ -89,32 +89,31 @@ LinesComponent = React.createClass
|
||||
@lineIdsByScreenRow = {}
|
||||
|
||||
removeLineNodes: ->
|
||||
@removeLineNode(id) for id of @oldState
|
||||
@removeLineNode(id) for id of @oldState.lines
|
||||
|
||||
removeLineNode: (id) ->
|
||||
@lineNodesByLineId[id].remove()
|
||||
delete @lineNodesByLineId[id]
|
||||
delete @lineIdsByScreenRow[@screenRowsByLineId[id]]
|
||||
delete @screenRowsByLineId[id]
|
||||
delete @oldState[id]
|
||||
delete @oldState.lines[id]
|
||||
|
||||
updateLineNodes: ->
|
||||
{presenter, lineDecorations, mouseWheelScreenRow} = @props
|
||||
@newState = presenter?.state.lines
|
||||
return unless @newState = presenter?.state.content
|
||||
|
||||
return unless @newState?
|
||||
@oldState ?= {}
|
||||
@oldState ?= {lines: {}}
|
||||
@lineNodesByLineId ?= {}
|
||||
|
||||
for id of @oldState
|
||||
unless @newState.hasOwnProperty(id) or mouseWheelScreenRow is @screenRowsByLineId[id]
|
||||
for id of @oldState.lines
|
||||
unless @newState.lines.hasOwnProperty(id) or mouseWheelScreenRow is @screenRowsByLineId[id]
|
||||
@removeLineNode(id)
|
||||
|
||||
newLineIds = null
|
||||
newLinesHTML = null
|
||||
|
||||
for id, lineState of @newState
|
||||
if @oldState.hasOwnProperty(id)
|
||||
for id, lineState of @newState.lines
|
||||
if @oldState.lines.hasOwnProperty(id)
|
||||
@updateLineNode(id)
|
||||
else
|
||||
newLineIds ?= []
|
||||
@ -123,10 +122,12 @@ LinesComponent = React.createClass
|
||||
newLinesHTML += @buildLineHTML(id)
|
||||
@screenRowsByLineId[id] = lineState.screenRow
|
||||
@lineIdsByScreenRow[lineState.screenRow] = id
|
||||
@oldState[id] = _.clone(lineState)
|
||||
@oldState.lines[id] = _.clone(lineState)
|
||||
|
||||
@renderedDecorationsByLineId[id] = lineDecorations[lineState.screenRow]
|
||||
|
||||
@oldState.scrollWidth = @newState.scrollWidth
|
||||
|
||||
return unless newLineIds?
|
||||
|
||||
WrapperDiv.innerHTML = newLinesHTML
|
||||
@ -139,7 +140,8 @@ LinesComponent = React.createClass
|
||||
|
||||
buildLineHTML: (id) ->
|
||||
{presenter, showIndentGuide, lineHeightInPixels, lineDecorations} = @props
|
||||
{screenRow, tokens, text, top, width, lineEnding, fold, isSoftWrapped, indentLevel} = @newState[id]
|
||||
{scrollWidth} = @newState
|
||||
{screenRow, tokens, text, top, lineEnding, fold, isSoftWrapped, indentLevel} = @newState.lines[id]
|
||||
|
||||
classes = ''
|
||||
if decorations = lineDecorations[screenRow]
|
||||
@ -148,7 +150,7 @@ LinesComponent = React.createClass
|
||||
classes += decoration.class + ' '
|
||||
classes += 'line'
|
||||
|
||||
lineHTML = "<div class=\"#{classes}\" style=\"position: absolute; top: #{top}px; width: #{width}px;\" data-screen-row=\"#{screenRow}\">"
|
||||
lineHTML = "<div class=\"#{classes}\" style=\"position: absolute; top: #{top}px; width: #{scrollWidth}px;\" data-screen-row=\"#{screenRow}\">"
|
||||
|
||||
if text is ""
|
||||
lineHTML += @buildEmptyLineInnerHTML(id)
|
||||
@ -161,7 +163,7 @@ LinesComponent = React.createClass
|
||||
|
||||
buildEmptyLineInnerHTML: (id) ->
|
||||
{showIndentGuide} = @props
|
||||
{indentLevel, tabLength, endOfLineInvisibles} = @newState[id]
|
||||
{indentLevel, tabLength, endOfLineInvisibles} = @newState.lines[id]
|
||||
|
||||
if showIndentGuide and indentLevel > 0
|
||||
invisibleIndex = 0
|
||||
@ -184,7 +186,7 @@ LinesComponent = React.createClass
|
||||
|
||||
buildLineInnerHTML: (id) ->
|
||||
{editor, showIndentGuide} = @props
|
||||
{tokens, text} = @newState[id]
|
||||
{tokens, text} = @newState.lines[id]
|
||||
innerHTML = ""
|
||||
|
||||
scopeStack = []
|
||||
@ -200,7 +202,7 @@ LinesComponent = React.createClass
|
||||
innerHTML
|
||||
|
||||
buildEndOfLineHTML: (id) ->
|
||||
{endOfLineInvisibles} = @newState[id]
|
||||
{endOfLineInvisibles} = @newState.lines[id]
|
||||
|
||||
html = ''
|
||||
if endOfLineInvisibles?
|
||||
@ -234,9 +236,9 @@ LinesComponent = React.createClass
|
||||
"<span class=\"#{scope.replace(/\.+/g, ' ')}\">"
|
||||
|
||||
updateLineNode: (id) ->
|
||||
|
||||
{lineHeightInPixels, lineDecorations} = @props
|
||||
{screenRow, top, width} = @newState[id]
|
||||
{scrollWidth} = @newState
|
||||
{screenRow, top} = @newState.lines[id]
|
||||
|
||||
|
||||
lineNode = @lineNodesByLineId[id]
|
||||
@ -254,7 +256,7 @@ LinesComponent = React.createClass
|
||||
if Decoration.isType(decoration, 'line') and not @hasDecoration(previousDecorations, decoration)
|
||||
lineNode.classList.add(decoration.class)
|
||||
|
||||
lineNode.style.width = width + 'px'
|
||||
lineNode.style.width = scrollWidth + 'px'
|
||||
lineNode.style.top = top + 'px'
|
||||
lineNode.dataset.screenRow = screenRow
|
||||
@screenRowsByLineId[id] = screenRow
|
||||
@ -291,7 +293,7 @@ LinesComponent = React.createClass
|
||||
node = @getDOMNode()
|
||||
|
||||
editor.batchCharacterMeasurement =>
|
||||
for id, lineState of @oldState
|
||||
for id, lineState of @oldState.lines
|
||||
unless @measuredLines.has(id)
|
||||
lineNode = @lineNodesByLineId[id]
|
||||
@measureCharactersInLine(lineState, lineNode)
|
||||
|
@ -5,10 +5,9 @@ module.exports =
|
||||
class TextEditorPresenter
|
||||
constructor: ({@model, @clientHeight, @clientWidth, @scrollTop, @lineHeight, @baseCharacterWidth, @lineOverdrawMargin}) ->
|
||||
@disposables = new CompositeDisposable
|
||||
@state = {}
|
||||
@charWidthsByScope = {}
|
||||
@subscribeToModel()
|
||||
@buildLinesState()
|
||||
@buildState()
|
||||
|
||||
destroy: ->
|
||||
@disposables.dispose()
|
||||
@ -16,13 +15,24 @@ class TextEditorPresenter
|
||||
subscribeToModel: ->
|
||||
@disposables.add @model.onDidChange(@updateLinesState.bind(this))
|
||||
@disposables.add @model.onDidChangeSoftWrapped =>
|
||||
@computeScrollWidth()
|
||||
@updateContentState()
|
||||
@updateLinesState()
|
||||
|
||||
buildState: ->
|
||||
@state = {}
|
||||
@buildContentState()
|
||||
@buildLinesState()
|
||||
|
||||
buildContentState: ->
|
||||
@state.content = {scrollWidth: @computeScrollWidth()}
|
||||
|
||||
buildLinesState: ->
|
||||
@state.lines = {}
|
||||
@state.content.lines = {}
|
||||
@updateLinesState()
|
||||
|
||||
updateContentState: ->
|
||||
@state.content.scrollWidth = @computeScrollWidth()
|
||||
|
||||
updateLinesState: ->
|
||||
visibleLineIds = {}
|
||||
startRow = @getStartRow()
|
||||
@ -32,24 +42,23 @@ class TextEditorPresenter
|
||||
while row < endRow
|
||||
line = @model.tokenizedLineForScreenRow(row)
|
||||
visibleLineIds[line.id] = true
|
||||
if @state.lines.hasOwnProperty(line.id)
|
||||
if @state.content.lines.hasOwnProperty(line.id)
|
||||
@updateLineState(row, line)
|
||||
else
|
||||
@buildLineState(row, line)
|
||||
row++
|
||||
|
||||
for id, line of @state.lines
|
||||
for id, line of @state.content.lines
|
||||
unless visibleLineIds.hasOwnProperty(id)
|
||||
delete @state.lines[id]
|
||||
delete @state.content.lines[id]
|
||||
|
||||
updateLineState: (row, line) ->
|
||||
lineState = @state.lines[line.id]
|
||||
lineState = @state.content.lines[line.id]
|
||||
lineState.screenRow = row
|
||||
lineState.top = row * @getLineHeight()
|
||||
lineState.width = @getScrollWidth()
|
||||
|
||||
buildLineState: (row, line) ->
|
||||
@state.lines[line.id] =
|
||||
@state.content.lines[line.id] =
|
||||
screenRow: row
|
||||
text: line.text
|
||||
tokens: line.tokens
|
||||
@ -58,7 +67,6 @@ class TextEditorPresenter
|
||||
tabLength: line.tabLength
|
||||
fold: line.fold
|
||||
top: row * @getLineHeight()
|
||||
width: @getScrollWidth()
|
||||
|
||||
getStartRow: ->
|
||||
startRow = Math.floor(@getScrollTop() / @getLineHeight()) - @lineOverdrawMargin
|
||||
@ -73,9 +81,7 @@ class TextEditorPresenter
|
||||
computeScrollWidth: ->
|
||||
contentWidth = @pixelPositionForScreenPosition([@model.getLongestScreenRow(), Infinity]).left
|
||||
contentWidth += 1 unless @model.isSoftWrapped() # account for cursor width
|
||||
@scrollWidth = Math.max(contentWidth, @getClientWidth())
|
||||
|
||||
getScrollWidth: -> @scrollWidth ? @computeScrollWidth()
|
||||
Math.max(contentWidth, @getClientWidth())
|
||||
|
||||
setScrollTop: (@scrollTop) ->
|
||||
@updateLinesState()
|
||||
@ -89,7 +95,7 @@ class TextEditorPresenter
|
||||
@clientHeight ? @model.getScreenLineCount() * @getLineHeight()
|
||||
|
||||
setClientWidth: (@clientWidth) ->
|
||||
@computeScrollWidth()
|
||||
@updateContentState()
|
||||
@updateLinesState()
|
||||
|
||||
getClientWidth: -> @clientWidth
|
||||
@ -100,7 +106,7 @@ class TextEditorPresenter
|
||||
getLineHeight: -> @lineHeight
|
||||
|
||||
setBaseCharacterWidth: (@baseCharacterWidth) ->
|
||||
@computeScrollWidth()
|
||||
@updateContentState()
|
||||
@updateLinesState()
|
||||
|
||||
getBaseCharacterWidth: -> @baseCharacterWidth
|
||||
@ -129,7 +135,7 @@ class TextEditorPresenter
|
||||
@characterWidthsChanged() unless @batchingCharacterMeasurement
|
||||
|
||||
characterWidthsChanged: ->
|
||||
@computeScrollWidth()
|
||||
@updateContentState()
|
||||
@updateLinesState()
|
||||
|
||||
clearScopedCharWidths: ->
|
||||
|
Loading…
Reference in New Issue
Block a user