Move all text editor view state into a presenter object #5293

Merged
merged 160 commits into from Feb 9, 2015

Conversation

Projects
None yet
4 participants
Contributor

nathansobo commented Jan 28, 2015

This PR changes our approach to text editor rendering by centralizing all state in a TextEditorPresenter object that sits between the view and the model.

presenter diagram

The presenter manages a mutable state object that is synchronously updated whenever there are changes from the model or changes to measurements from the view. The view consumes this state object when updating the DOM asynchronously so we don't need to recompute it before every render like we do now.

This reconfiguration paves the way to perform all DOM updates manually rather than relying on React's virtual DOM reconciliation system. The view will maintain a copy of the presenter state, and it will perform a comparison of the presenter's state against the copy when updating the DOM.

The net result will be a design very similar to React's reconciliation mechanism, but my hope is that a lower-level implementation targeting our specific problem domain will make this design easier to profile and open up specific optimizations that wouldn't be possible at a higher level of abstraction. We already perform DOM updates to lines and line numbers manually to optimize around reconciliation overhead; this would just complete that process.

Remaining work

Optimizations

  • Perform a single decorations query when the visible row range changes to cache the visible decorations, then read decoration classes from that when building lines, line numbers, etc rather than querying multiple times on every change.
  • When decorations are added / removed, update only the decoration classes on lines and line numbers rather than doing a full pass on their content.
  • Cache foldable status for each line in the tokenized buffer instead of recomputing it every time we update the line numbers.

Fixes

  • Fix velocity scrolling upward
  • Fix TextEditorComponent specs
  • Compute row id correctly when the first visible line is soft-wrapped.
  • Eliminate TextEditorPresenter::getHeight
  • Audit handling of scrollTop/scrollLeft
  • Enforce maximum scrollTop/Left based on height/width and content. This should hopefully address some flakiness in the random test.
  • Editor losing focus when switching grammars with grammar switcher. Does that happen on master too?
  • Gutter background color isn't changing when themes get changed.
  • Switching syntax themes is super slow
Contributor

mark-hahn commented Jan 28, 2015

Is there a problem modifying the DOM directly at the same time?

On Wed, Jan 28, 2015 at 9:44 AM, Nathan Sobo notifications@github.com
wrote:

This PR changes our approach to text editor rendering by centralizing all
state in a TextEditorPresenter object that sits between the view and the
model.

[image: presenter diagram]
https://cloud.githubusercontent.com/assets/1789/5943048/d3ef770a-a6d8-11e4-9ed7-aa4ce2a650f2.png

The presenter manages a mutable state object that is synchronously updated
whenever there are changes from the model or changes to measurements from
the view. The view consumes this state object when updating the DOM
asynchronously so we don't need to recompute it before every render like we
do now.

This reconfiguration paves the way to perform all DOM updates manually
rather than relying on React's virtual DOM reconciliation system. The view
will maintain a copy of the presenter state, and it will perform a
comparison of the presenter's state against the copy when updating the DOM.

The net result will be a design very similar to React's reconciliation
mechanism, but my hope is that a lower-level implementation targeting our
specific problem domain will make this design easier to profile and open up
specific optimizations that wouldn't be possible at a higher level of
abstraction. We already perform DOM updates to lines and line numbers
manually to optimize around reconciliation overhead; this would just

complete that process.

You can view, comment on, or merge this pull request online at:

#5293
Commit Summary

  • Start on TextEditorPresenter with lines state
  • Handle changing ::scrollTop in TextEditorPresenter
  • Handle changing ::clientHeight in TextEditorPresenter
  • Handle changing ::lineHeight in TextEditorPresenter
  • Update TextEditorPresenter when the editor’s content changes
  • Add width to lines state based on the computed scrollWidth
  • Instantiate presenter in TextEditorComponent and update measurements
  • Include line text in presenter state
  • Add 1 to the last row to ensure it’s visible
  • 🎨
  • Account for overdrawMargin of startRow when computing the endRow
  • Add 1 pixel to scrollWidth to account for cursor if not soft-wrapped
  • Make all lines visible if no external client height is assigned
  • Use getters in TextEditorPresenter internally for consistency
  • Include endOfLineInvisibles in presenter state
  • Fix endRow calculation
  • Include more fields in line state
  • Disable spec until presenter approach stabilizes
  • Start using TextEditorPresenter in LinesComponent
  • Handle scoped character widths in TextEditorPresenter
  • Update TextEditorPresenter with scoped character widths in component
  • Add top-level .content object to presenter state
  • Remove unused local vars
  • Add content.indentGuidesVisible to TextEditorPresenter::state
  • Update .content.indentGuidesVisible when editor’s grammar changes
  • Use TextEditorPresenter::state.content.indentGuidesVisible
  • Remove unused argument
  • Read scrollWidth from the presenter state when rendering
  • Add .decorationClasses to line state on initial render
  • Add lineStateForScreenRow helper
  • Simplify assertions
  • Instantiate presenter with minimal parameters in specs
  • Handle updates to line decorations in TextEditorPresenter
  • Honor the ‘onlyEmpty’ and ‘onlyNonEmpty’ line decoration options
  • Don’t apply line decorations to last line if it ends at column 0
  • Don’t apply line decorations to mini editors
  • Show/hide line decorations when TextEditor::mini changes
  • Remove unused code
  • Fix spec
  • Reorganize specs on TextEditorPresenter to mirror structure of state
  • Add ::state.content.scrollHeight to TextEditorPresenter
  • Use presenter to supply scrollHeight to lines component
  • Add ::state.content.scrollTop/Left to TextEditorPresenter
  • Use presenter’s scrollTop/scrollLeft in LinesComponent
  • 🎨
  • Add TextEditorPresenter::state.content.cursors
  • Use presenter state in CursorsComponent
  • Fix 0-width cursors in presenter instead of view
  • Add TextEditorPresenter::state.content.blinkCursorsOff
  • Add TextEditorPresenter::onDidUpdateState
  • Blink cursors based on presenter state
  • Remove shouldComponentUpdate hook
  • Remove unused props
  • Fix spec organization
  • Add highlights state to TextEditorPresenter
  • Use presenter to render flashes
  • Use presenter to render highlights
  • Start on TextEditorPresenter::state.lineNumbers
  • Reflect changes to line number decorations in presenter state
  • Deprecate TextEditor::getGutterDecorations
  • Add ‘foldable’ to line number presenter state
  • Move vertical scroll state to root of presenter state object
  • Move .lineNumbers onto .gutter property of presenter state
  • Update presenter scrollHeight when clientHeight changes
  • Use presenter for gutter scrollHeight and scrollTop
  • Key line numbers by buffer row and soft-wrap count
  • Build line numbers based on presenter state
  • Don’t decorate soft-wrapped lines/line numbers unless spanned by
    marker
  • 🎨
  • Honor the ‘onlyHead’ option for line and line-number decorations
  • Remove unused properties in EditorComponent and children
  • Add overlay decorations to TextEditorPresenter::state
  • Use presenter for rendering overlay decorations
  • Remove unused React props and methods that build them
  • Add TextEditorPresenter::state.content.backgroundColor
  • Use backgroundColor from presenter in LinesComponent
  • Add TextEditorPresenter::state.scrollingVertically
  • Use presenter’s scrollingVertically property to defer line
    measurement
  • Set content.indentGuidesVisible in presenter if editor is mini
  • Remove unused local var
  • Use presenter state for placeholder text
  • Use presenter state for gutter background color
  • Add maxLineNumberDigits to presenter state
  • Wait for required measurements before building some presenter state
  • Construct TextEditorPresenter before component mounts
  • Only store backgroundColor and gutterBackgroundColor on presenter
  • Use maxLineNumberDigits from presenter state in GutterComponent
  • Add TextEditorPresenter::state.mousewheelScreenRow

File Changes

Patch Links:


Reply to this email directly or view it on GitHub
#5293.

Contributor

nathansobo commented Jan 28, 2015

Is there a problem modifying the DOM directly at the same time?

I might consider it, but I'm trying to break this up into pieces at the request of the team since it's already a big change as is.

Contributor

mark-hahn commented Jan 28, 2015

I'm sorry. I meant could a package modifying the DOM directly conflict
with this presenter modification?

Now that I think about it the answer is probably no.

On Wed, Jan 28, 2015 at 12:47 PM, Nathan Sobo notifications@github.com
wrote:

Is there a problem modifying the DOM directly at the same time?

I might consider it, but I'm trying to break this up into pieces at the
request of the team since it's already a big change as is.


Reply to this email directly or view it on GitHub
#5293 (comment).

Contributor

nathansobo commented Jan 28, 2015

@mark-hahn Yeah it shouldn't interfere. Although one thing I'm hoping to solve is to provide a hook for appropriate times to modify the DOM yourself to prevent reflows. That's fairly fuzzy at the moment though and a ways off.

Contributor

mark-hahn commented Jan 28, 2015

appropriate times to modify the DOM yourself to prevent reflows.

That would be cool. Can a package post changes to the presenter and let it
handle everything?

On Wed, Jan 28, 2015 at 1:22 PM, Nathan Sobo notifications@github.com
wrote:

@mark-hahn https://github.com/mark-hahn Yeah it shouldn't interfere.
Although one thing I'm hoping to solve is to provide a hook for appropriate
times to modify the DOM yourself to prevent reflows. That's fairly
fuzzy at the moment though and a ways off.


Reply to this email directly or view it on GitHub
#5293 (comment).

Contributor

nathansobo commented Jan 29, 2015

The basic structure is in place here, so now it's time to optimize. It breaks down to about 6ms updating the model and presenter state and 4ms updating the DOM for a single character insert. I have reason to believe I can improve on this substantially.

screenshot_2015-01-29_15_56_14

There's a ton of low hanging fruit on the presenter update because I did everything in the most naive way, so that's the work I'll do on this PR and save DOM update optimizations for a subsequent PR. To ensure optimizations don't introduce regressions, I'm going to build a spec that randomly mutates an editor and compares the state of a brand new presenter to that of a preexisting presenter to be sure updates were performed correctly.

After that, some of the presenter optimizations I have in mind:

  • Perform a single decorations query when the visible row range changes to cache the visible decorations, then read decoration classes from that when building lines, line numbers, etc rather than querying multiple times on every change.
  • When decorations are added / removed, update only the decoration classes on lines and line numbers rather than doing a full pass on their content.
  • Cache foldability status on tokenized lines so we don't have to recompute it when updating line numbers.

I have more ideas, but I'd like to try these things first and re-evaluate.

I also want to re-introduce shouldComponentUpdate methods on all the React components which should improve reconciliation performance.

nathansobo and others added some commits Jan 19, 2015

@nathansobo nathansobo Start on TextEditorPresenter with lines state f0920bf
@nathansobo nathansobo Handle changing ::scrollTop in TextEditorPresenter 880e1ce
@nathansobo nathansobo Handle changing ::clientHeight in TextEditorPresenter 9c2ed47
@nathansobo nathansobo Handle changing ::lineHeight in TextEditorPresenter 5a2bbc9
@nathansobo nathansobo Update TextEditorPresenter when the editor’s content changes a1c2e1b
@nathansobo nathansobo Add width to lines state based on the computed scrollWidth
This is based on the ::baseCharacterWidth property for now. To be fully
correct, we need to base the scrollWidth on the actual width of
individual characters.
f4d8ef8
@nathansobo nathansobo Instantiate presenter in TextEditorComponent and update measurements 2120c3c
@nathansobo nathansobo Include line text in presenter state b09b548
@nathansobo nathansobo Add 1 to the last row to ensure it’s visible 0f4bcac
@nathansobo nathansobo 🎨 143183a
@nathansobo nathansobo Account for overdrawMargin of startRow when computing the endRow 2296d2d
@nathansobo nathansobo Add 1 pixel to scrollWidth to account for cursor if not soft-wrapped ac46314
@nathansobo nathansobo Make all lines visible if no external client height is assigned 7095ccd
@nathansobo nathansobo Use getters in TextEditorPresenter internally for consistency
::clientHeight is conditionally computed in the getter, so lets use them
everywhere for consistency.
db50596
@nathansobo nathansobo Include endOfLineInvisibles in presenter state 9a070e7
@nathansobo nathansobo Fix endRow calculation e2693da
@nathansobo nathansobo Include more fields in line state 9e6aa8f
@nathansobo nathansobo Disable spec until presenter approach stabilizes a3fb8b3
@nathansobo nathansobo Start using TextEditorPresenter in LinesComponent
Removed shouldComponentUpdate because we will always update the
component manually once this is done, but I don’t want to accidentally
prevent the component from updating during the conversion process.

This commit has a failing spec due to the presenter not accounting for
individual character widths.
20bb14d
@nathansobo nathansobo Handle scoped character widths in TextEditorPresenter
Signed-off-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
115d764
@nathansobo nathansobo Update TextEditorPresenter with scoped character widths in component
Signed-off-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
3ec4b63
@nathansobo nathansobo 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.
0a9f758
@nathansobo nathansobo Remove unused local vars 22942ae
@nathansobo nathansobo Add content.indentGuidesVisible to TextEditorPresenter::state d0b5253
@nathansobo nathansobo Update .content.indentGuidesVisible when editor’s grammar changes 590391a
@nathansobo nathansobo Use TextEditorPresenter::state.content.indentGuidesVisible 32a1854
@nathansobo nathansobo Remove unused argument 64ef8ad
@nathansobo nathansobo Read scrollWidth from the presenter state when rendering bf9428a
@nathansobo nathansobo Add .decorationClasses to line state on initial render 06ef079
@nathansobo nathansobo Add lineStateForScreenRow helper
The access pattern is pretty noisy in the specs
568b9f6
@nathansobo nathansobo Simplify assertions 9c1efb6
@nathansobo nathansobo Instantiate presenter with minimal parameters in specs 5d8f831
@nathansobo nathansobo Handle updates to line decorations in TextEditorPresenter
This isn’t a super efficient approach, but it is simple and should be
correct. Once we move all state to the presenter we can perform a more
efficient synchronous update when markers change.
7734824
@nathansobo nathansobo Honor the ‘onlyEmpty’ and ‘onlyNonEmpty’ line decoration options 62a1210
@nathansobo nathansobo Don’t apply line decorations to last line if it ends at column 0 a513cf2
@nathansobo nathansobo Don’t apply line decorations to mini editors 9a496e6
@nathansobo nathansobo Show/hide line decorations when TextEditor::mini changes fe5ee52
@nathansobo nathansobo Remove unused code e9d6e36
@nathansobo nathansobo Fix spec 59b1096
@nathansobo nathansobo Reorganize specs on TextEditorPresenter to mirror structure of state de0b5c4
@nathansobo nathansobo Add ::state.content.scrollHeight to TextEditorPresenter 2c5888e
@nathansobo nathansobo Use presenter to supply scrollHeight to lines component 78d87d8
@nathansobo nathansobo Add ::state.content.scrollTop/Left to TextEditorPresenter f479e9d
@nathansobo nathansobo Use presenter’s scrollTop/scrollLeft in LinesComponent add3972
@nathansobo nathansobo 🎨 b7b0ec0
@nathansobo nathansobo Add TextEditorPresenter::state.content.cursors c8b5876
@nathansobo nathansobo Use presenter state in CursorsComponent 4ed07bb
@nathansobo nathansobo Fix 0-width cursors in presenter instead of view 06b5eba
@nathansobo nathansobo Add TextEditorPresenter::state.content.blinkCursorsOff 3c6c385
@nathansobo nathansobo Add TextEditorPresenter::onDidUpdateState
And ensure observers are invoked whenever the state changes in spec.
b412c26
@nathansobo nathansobo Blink cursors based on presenter state
Signed-off-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
3b93f3d
@nathansobo nathansobo Remove shouldComponentUpdate hook
Will be replaced by manual update logic anyway.

Signed-off-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
500f992
@nathansobo nathansobo Remove unused props
Signed-off-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
4b0536a
@nathansobo nathansobo Fix spec organization
Signed-off-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
764139c
@nathansobo nathansobo Add highlights state to TextEditorPresenter
Signed-off-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
2f526c5
@nathansobo nathansobo Use presenter to render flashes
Signed-off-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
49bf3bb
@nathansobo nathansobo Use presenter to render highlights
Signed-off-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
8ebd057
@nathansobo nathansobo Start on TextEditorPresenter::state.lineNumbers
Signed-off-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
970936f
@nathansobo nathansobo Reflect changes to line number decorations in presenter state
Signed-off-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
66c35d6
@nathansobo nathansobo Deprecate TextEditor::getGutterDecorations
Forgot to rename it when we renamed decorations of type ‘gutter’ to
‘line-number’. It’s not used in core or any packages at the time of
this commit.

Signed-off-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
5d2efc0
@maxbrunsfeld @nathansobo maxbrunsfeld Move .lineNumbers onto .gutter property of presenter state
Signed-off-by: Nathan Sobo <nathan@github.com>
33081ce
@maxbrunsfeld @nathansobo maxbrunsfeld Update presenter scrollHeight when clientHeight changes
Signed-off-by: Nathan Sobo <nathan@github.com>
f218e98
@nathansobo nathansobo Add ‘foldable’ to line number presenter state 1ff0b20
@nathansobo nathansobo Use presenter for gutter scrollHeight and scrollTop
Signed-off-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
182531a
@nathansobo nathansobo Move vertical scroll state to root of presenter state object
Signed-off-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
d26e8a2
@nathansobo nathansobo Key line numbers by buffer row and soft-wrap count
…instead of an array. This will make things simpler to diff in the
view.
20838ac
@nathansobo nathansobo Build line numbers based on presenter state b1fe567
@nathansobo nathansobo Don’t decorate soft-wrapped lines/line numbers unless spanned by marker 0802b9b
@nathansobo nathansobo 🎨 af8c38a
@nathansobo nathansobo Honor the ‘onlyHead’ option for line and line-number decorations c4b5a0f
@nathansobo nathansobo Remove unused properties in EditorComponent and children a5580a7
@nathansobo nathansobo Add overlay decorations to TextEditorPresenter::state e4c95d8
@nathansobo nathansobo Use presenter for rendering overlay decorations
We’re still doing some sync DOM reads and computation in the view that
should eventually be made async and moved into the presenter, but I’m
going to leave it alone for now.
9d7285d
@nathansobo nathansobo Remove unused React props and methods that build them 96ba4cc
@nathansobo nathansobo Add TextEditorPresenter::state.content.backgroundColor 71a27de
@nathansobo nathansobo Use backgroundColor from presenter in LinesComponent 837b9ee
@nathansobo nathansobo Add TextEditorPresenter::state.scrollingVertically
This is used by the view to defer measuring new lines until we stop
scrolling.
d4517b1
@nathansobo nathansobo Use presenter’s scrollingVertically property to defer line measurement b21b9c3
@nathansobo nathansobo Set content.indentGuidesVisible in presenter if editor is mini f5fa3b8
@nathansobo nathansobo Remove unused local var
Signed-off-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
1a61133
@maxbrunsfeld @nathansobo maxbrunsfeld Use presenter state for placeholder text
Signed-off-by: Nathan Sobo <nathan@github.com>
fd4f289
@maxbrunsfeld @nathansobo maxbrunsfeld Use presenter state for gutter background color
Signed-off-by: Nathan Sobo <nathan@github.com>
60fca8d
@maxbrunsfeld @nathansobo maxbrunsfeld Add maxLineNumberDigits to presenter state 9cc7ecb
@nathansobo nathansobo Wait for required measurements before building some presenter state
Signed-off-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
ac25596
@nathansobo nathansobo Construct TextEditorPresenter before component mounts
This allows us to use the presenter for all stages of the component
lifecycle rather than needing to wait until it is created.

Signed-off-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
fd50a0d
@nathansobo nathansobo Only store backgroundColor and gutterBackgroundColor on presenter 1a22952
@nathansobo nathansobo Use maxLineNumberDigits from presenter state in GutterComponent a88486e
@nathansobo nathansobo Add TextEditorPresenter::state.mousewheelScreenRow da5ee3f
@nathansobo nathansobo Make “mouse wheel” 2 words in presenter API
Signed-off-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
578a76b
@nathansobo nathansobo Preserve lines in TextEditorPresenter based on ::mouseWheelScreenRow 35d3690
@nathansobo nathansobo Preserve line numbers in presenter based on ::mouseWheelScreenRow 37a040a
@nathansobo nathansobo Clear ::mouseWheelScreenRow after delay even if we don’t actually scroll d9a5d14
@nathansobo nathansobo Handle line and line number preservation in presenter
The target of mousewheel events needs to be preserved when scrolling.
It used to be dealt with in the view, but now we can do it in the
presenter for a simpler view implementation.
76241fb
@nathansobo nathansobo Don’t observe screen line changes in editor component d8cafb1
@nathansobo nathansobo Add spec coverage for deprecated ‘cursor:moved’ event
So we don’t accidentally drop it during this transition
6108c04
@nathansobo nathansobo Drop TextEditorComponent::getRenderedRowRange 9de8ab9
@nathansobo nathansobo Track horizontal/vertical scrollbar height/width in presenter 1b5be9a
@nathansobo nathansobo Rename ::clientHeight/Width to ::height and ::contentFrameWidth
The term “client” was actually a misnomer here because it typically
means the height excluding the scrollbars, which wasn’t how we were
using it here.
42ab02d
@nathansobo nathansobo Give each scrollbar its own state object and track visibility 14776e3
@nathansobo nathansobo Add .right and .bottom to presenter scrollbar states 0910e86
@nathansobo nathansobo Use presenter state for scrollbars and scrollbar corner efdba9f
@nathansobo nathansobo Fix indentation 0e27beb
@nathansobo nathansobo Don’t observe decorations in text editor view da4b3a4
@nathansobo nathansobo Make each section of presenter state self-contained
This means we have some duplicated values in different parts of the
tree, but it’s cleaner in the view since each component only consumes
a single object. Seems like the presenter should convey the correct
data to the correct locations and minimize the logic in the view. A
few duplicated integers is a reasonable trade-off.
bbc1a26
@nathansobo nathansobo Handle auto-height in TextEditorPresenter b521e8d
@nathansobo nathansobo Add specs for updating scrollWidth when the longest line changes f005b20
@nathansobo nathansobo Break out state updates explicitly when editor content changes 9d507ea
@nathansobo nathansobo Remove unnecessary onDidChangeSoftWrapped subscription 4eb39b1
@nathansobo nathansobo 🎨 rename ::getStart/EndRow to ::computeStart/EndRow 510520d
@nathansobo nathansobo 🐎 Don’t update presenter state unless measurements change 74e4756
@nathansobo nathansobo Update scrollbars state when editor content changes 89344c6
@nathansobo nathansobo Add randomized fuzz test for TextEditorPresenter
This test performs random operations on the editor and assigns random
measurements from the view. After each operation, the state of a
pre-existing presenter is compared with that of a new presenter created
with the same parameters.

Since it’s easier to reason about building fresh state than it is to
reason about state updates, I hope this will catch any bugs in our
update logic as we optimize it and explore every corner case.
de5c1fc
@nathansobo nathansobo Use properties directly instead of getters
This will emphasize a design where everything is updated when the model
and view measurements change rather than recomputed as needed.
f99b85a
@nathansobo nathansobo Unify decoration observation 3884a30
@nathansobo nathansobo 🐎 Cache line/line-number decorations to avoid per-line queries 0e85efd
@nathansobo nathansobo Handle highlight state updates in ::updateDecorations f337553
@nathansobo nathansobo Avoid decoration queries when updating individual highlight decorations 4a74d4a
@nathansobo nathansobo Fix action logging in random spec cf50ec1
@nathansobo nathansobo Fix randomized spec failures 7deb411
@nathansobo nathansobo Hide line decorations for invalid markers again 648c58d
@nathansobo nathansobo Avoid full decoration query when line decorations are destroyed 3429035
@nathansobo nathansobo Dispose of decoration subscriptions when it’s destroyed c6f23c2
@nathansobo nathansobo Avoid full decoration query when line decorations’ markers change b78522d
@nathansobo nathansobo Avoid full decorations query when decorations are added 2dc29a6
@nathansobo nathansobo Fix undefined method errors in overlay manager
Access properties directly now
0a6116a
@nathansobo nathansobo Access mouseWheelScreenRow property instead of calling removed method edd595a
@nathansobo nathansobo Emit update events in TextEditorPresenter when highlights are removed 20ce35c
@nathansobo nathansobo Fix velocity scrolling upward
There’s no need to check that the mouseWheelScreenRow is on screen
before preserving the corresponding line.
ac215e1
@nathansobo nathansobo Reference scrollingVertically in the proper location in presenter state 9991cd7
@nathansobo nathansobo Remove ? guard from ::oldState and ::newState references 75652e3
@nathansobo nathansobo In presenter, handle the first line being soft-wrapped
Signed-off-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
cd77870
@nathansobo nathansobo Don’t require sync update before measuring when autoHeight changes
Signed-off-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
78b8039
Contributor

nathansobo commented Feb 3, 2015

We're going to try this out for a couple days before merging, but this should be ready to go. Next steps:

  • Cache "foldable" status of lines so it's cheaper to update the line numbers in the presenter
  • Switch to manual DOM manipulation
  • Try tiled rendering

nathansobo added some commits Feb 3, 2015

@nathansobo nathansobo Preserve line number for mouseWheelScreenRow in a sane way
What we were doing before made no sense.

Signed-off-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
20a9526
@nathansobo nathansobo Prevent updates for off-screen line decoration markers on change
When there were lots of off-screen markers, we were performing lots of
redundant updates when off-screen markers changed. Now we only perform
updates if they intersect the visible row range.

@maxbrunsfeld this should improve the situation for folding/unfolding
when there are lots of others folds. Let me know.
a685f3d
Contributor

maxbrunsfeld commented on a685f3d Feb 4, 2015

🍸 sweet

Contributor

nathansobo commented Feb 4, 2015

Randomized spec is failing. Need to get that resolved before merging.

nathansobo added some commits Feb 4, 2015

@nathansobo nathansobo Merge branch 'master' into ns-editor-presenters
ba6d11e
@nathansobo nathansobo Store ‘isOnlyWhitespace’ in line presenter state
6977660
@nathansobo nathansobo Log code for repeatable randomized presenter spec failures 3e6669c
@nathansobo nathansobo Pass options in DisplayBuffer::screenRangeForBufferRange
3656d4c
@nathansobo nathansobo Constrain scrollTop based on clientHeight and scrollHeight 5bb3095
@nathansobo nathansobo Make randomized presenter spec failures easier to reproduce
1ae25ed
@nathansobo nathansobo Constrain scrollLeft based on computed clientWith and scrollWidth b792190
@nathansobo nathansobo Don’t constrain scrollTop/Left until required measurements are assigned
This commit also adds to the list of required measurements and updates
the spec with a buildPresenter helper to more easily supply default
values for required measurements in each spec when they aren’t relevant
to that spec’s content.
3973939
@nathansobo nathansobo Include scrollbar dimensions in required measurements in presenter 6196882
@nathansobo nathansobo Measure scrollbars immediately when editor becomes visible
This ensures all required measurements are present so assignment of
subsequent measurements such as backgroundColor have an effect.
59d96c9
@nathansobo nathansobo Update vertical scroll state when contentFrameWidth changes
A wider content frame can mean the horizontal scrollbar gets hidden,
which could in turn mean we need to adjust the scrollTop because the
clientHeight changed.
9bdb961
@nathansobo nathansobo Pass view measurements to model via presenter
Someday, we won’t need to pass measurements to the model anymore.
b94576d
@nathansobo nathansobo Rename TextEditorPresenter::height to ::explicitHeight
This clarifies that the height is being assigned externally rather than
derived from the content.
77599c7
@nathansobo nathansobo Remove subscriptions in editor view that are handled in presenter
d14d4aa
Contributor

nathansobo commented Feb 4, 2015

I'm going to go ahead and cache foldable in the tokenized buffer before merging since we're recomputing the gutter more frequently with this design. I'm thinking that's the last step on this unless any other performance issues crop up.

nathansobo added some commits Feb 6, 2015

@nathansobo nathansobo 🎨 a4f9413
@nathansobo nathansobo 🎨 d93950a
@nathansobo nathansobo Cache .foldable on tokenized lines based on block comments
Still need to handle indentation
0081fa2
@nathansobo nathansobo Update .foldable on tokenized lines based on indentation f326c81
@nathansobo nathansobo Use cached .foldable values on TokenizedBuffer instead of recomputing
c8c13b8
Contributor

nathansobo commented Feb 7, 2015

Finished caching "foldable" status on tokenized lines. The sync presenter update for a character entry is down to about 3.4ms, and only about 1ms is spent in the presenter. Still room for optimization there, but I think we have other 🐟 to 🥚 before we worry about it. Want to spend a day using this in its final form before merging.

screenshot 2015-02-06 18 58 36

nathansobo added some commits Feb 9, 2015

@nathansobo nathansobo Merge branch 'master' into ns-editor-presenters
62c8244
@nathansobo nathansobo Update presenter’s gutter background state when background color changes
0d1ba90
@nathansobo nathansobo Batch scoped character measurement in presenter df01c8a
@nathansobo nathansobo Coalesce handling style sheet changes in editor with nextAnimationFrame
Previously, we were delaying handling, but still requesting redundant
handling by requesting multiple frames. Now we don’t request a new
update if there is already one outstanding.
bdfca8b
@nathansobo nathansobo Initialize scopedCharacterWidthsChangeCount to 0 d5719bf
@nathansobo nathansobo 💄 CharWidth -> CharacterWidth in presenter 4f0e199
@nathansobo nathansobo Assign line and character measurements on model via presenter
4819585

nathansobo merged commit 89d5dd3 into master Feb 9, 2015

4 checks passed

atom Build #1889422 succeeded in 606s
Details
atom-linux Build #1889423 succeeded in 135s
Details
atom-rpm Build #1889424 succeeded in 427s
Details
atom-win Build #1889425 succeeded in 524s
Details

nathansobo deleted the ns-editor-presenters branch Feb 9, 2015

Contributor

maxbrunsfeld commented Feb 9, 2015

hoorah! 🍻

Contributor

nathansobo commented Feb 9, 2015

@maxbrunsfeld Give it a build and see if it feels more responsive to you, if you weren't already testing that branch.

double required underscore-plus?

Contributor

nathansobo replied Feb 11, 2015

Thank you!

Contributor

nathansobo replied Feb 11, 2015

Fixed in 98e126b.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment