Instead, if the measured line height equals 0, default it to 1 so that
the editor component doesn't start computing `NaN` or `Infinity` values
due to e.g. dividing by 0.
We should probably consider sanitizing line heights smaller than a
certain threshold, but that's non trivial because line height is
expressed as a multiplier of the font size. Also, users may style the
`line-height` property via CSS, which may still throw errors when using
small values.
Calling `pixelPositionForScreenPosition` was sometimes throwing an error
indicating that the requested position was not rendered and that, as
such, could not be measured.
This was caused by trying to measure a line that was visible at the
moment of the call while also having a pending autoscroll request that
would cause that line to go off-screen. Due to how the code was
structured, we would mistakenly detect that line as visible, autoscroll
to a different location, re-render a different region of the buffer and
then try to measure the now invisible line.
This commit fixes this issue by restructuring and simplifying the logic
for rendering extra lines in order to measure them. Now, every line for
which a measurement has been requested is stored in a `linesToMeasure`
map. During the first phase of the update process (after honoring
autoscroll requests), we detect which of these lines are currently
visible and if they're not, store them into the
`extraRenderedScreenLines` map, which is then used to render lines that
are invisible but need to be measured.
Etch's reconciliation routine causes elements to be sometimes
re-ordered. In order to move an element, however, Etch needs to first
detach it from the DOM and then re-append it at the right location.
This behavior is unacceptable for highlight decorations because it could
re-start CSS animations on a certain highlight decoration when a
completely different one is added or removed.
Even though we are still interested in restructuring etch's
reconciliation logic to prevent unwanted re-orderings, with this commit
we are switching to a custom routine to create/update/remove highlight
decorations that prevents unnecessary moves and, as a result, fixes the
undesired behavior described above.
On Linux, when the user performs a middle-button mouse click, Chromium
fires both a mouse-down event *and* a paste event. This commit teaches
the TextEditorComponent to ignore the paste event.
When the user performs a middle-mouse click on a tab, we get close the
tab and attempt to prevent Chromium's default processing for the event.
[1] This prevents Chromium's default processing for the *mouse down*
event, but then Chromium also fires a *paste* event, and that event
pastes the clipboard's current content into the newly-focused text
editor. 🙀
Since Atom already has its own logic for handling pasting, we
shouldn't (🤞) need to handle browser paste events. By ignoring the
browser paste events on Linux, we fixatom/tabs#461.
[1]
ce1d92e0ab/lib/tab-bar-view.coffee (L416-L418)
Based on the assertion failures seen in
https://github.com/atom/atom/issues/15158#issue-247808059, it seems that
the flash for class 'c' sometimes ends before the flash for class 'd'
happens. Prior to this change, we only flashed class 'c' for 100ms, and
perhaps that isn't always enough time.
In this commit, we increase the flash duration from 100ms to 1000ms,
greatly increasing the likelihood that we're allowing enough time for
the flash on class 'd' to take place before the flash for class 'c'
ends. We also extract the scenario into its own test, so that 1) we can
more clearly explain the scenario that these assertions are testing and
2) future intermittent test failures will be easier to isolate.
As shown in #15122, this test sometimes fails in CI with the following
error:
TextEditorComponent
rendering
it blinks cursors when the editor is focused and the cursors are not moving
Expected '0' to be '1'.
at it (C:\projects\atom\spec\text-editor-component-spec.js:414:49)
Expected '0' to be '1'.
at it (C:\projects\atom\spec\text-editor-component-spec.js:415:49)
I *think* this might be a case of overspecification in the test's
assertions. Prior to this commit, the test expected the blinking cursor
to *start* in the visible state, and then transition to the invisible
state. When we see the failure above, I suspect that the cursor has
already transitioned from the visible state to the invisible state by
the time the assertion runs.
Since the test aims to verify that the cursor blinks, it seems like we
should focus on the blinking, and not worry about the *initial* state of
the cursor. This commit removes the assertions that verify the initial
state of the cursor, and instead asserts that the cursor toggles between
the visible and the invisible state.
Before rendering block decorations, we read their heights by putting
them into a special div called `blockDecorationMeasurementsArea`.
Previously, this div was not explicitly sized, which was causing
decorations to wrap while being measured but not when actually rendering
them.
This commit fixes this inconsistency by explicitly styling the
measurement area so that it has the same width as the component scroll
width.
By the time that the animation frame is delivered, the requested
autoscroll
position could not exist anymore. This could cause the editor component
to measure a non-existent line and, as a result, throw an exception.
With this commit we will always ignore measurements for screen lines
that do not exist.
This means we may render more tiles than necessary when we have block
decorations, but it prevents changing the number of rendered tiles
during scrolling with certain combinations of line height and editor
height. If it ever becomes a problem we can get smarter about
subtracting the height of the visible block decorations from the editor
height, but for now this gives us more reliable performance for the
common case.
Previously, we were accidentally depending on the state of the display
layer when forcing it to update its index. This caused us to not index
enough content to cover the visibile area, which meant we weren't
querying enough lines to fill the screen in some situations.
This was causing problems in measurements because in that code path we
assume that text nodes are never empty. This commit also adds a test
verifying this invariant when a text decoration ending right after a
text tag is added.
This was leaving a measurement request in the map that was getting
picked up on the next frame. In some cases, the requested measurement
row was not present, causing an exception.
Some packages are interacting with this method assuming this behavior,
so this commit eliminates `screenPositionForPixelPositionSync` and
instead just performs the DOM update in `screenPositionForPixelPosition`
if it is needed.
Taking the initial measurement was setting the soft wrap column, which
was triggering a display layer reset, which was scheduling an update.
This update occurred at an unexpected time causing an exception.
I was hoping to strictly contain the layouts of highlights an lines
separately, since they are updated during different render phases.
Unfortunately, strict containment requires both divs to be positioned
absolutely. This in turn creates separate stacking contexts for lines
and highlights, which makes it impossible to render highlights in front
lines which themes sometimes need to do. For example,
atom-material-syntax pushes bracket matcher highlights to the front so
they are not obscured by the theme's solid black cursor line background.
/cc @as-cii. You should examine my work here and make sure I'm not
screwing something up with your line/block decoration update code.