(partial) Fix pinned hovercard rendering with using back/forward buttons
Created by: fkling
This is marked as draft because I cannot reliably avoid the hovercard flickering when clicking copy URL :-/ (also visible in video)
As already mentioned in #36039 pinning a code intel hovercard (via the "Copy link" button) and using the back/forward buttons doesn't work as expected. The hovercard isn't shown when navigating to the pinned URL (only when the page is completely refreshed). That alone isn't bad but it also breaks the hovercards as a whole. The system thinks that there is already a pinned hovercard and therefore doesn't show cards when hovering over other tokens. This can be resolved by the user by selecting another line.
I spend some time to figure out what the issue is. The tl;dr is that some parts of the rxjs pipelines operate on older positioning information, which causes the hover system to not update because it thinks nothing has changed.
More specifically lets look at the pipeline that processes position changes from the URL:
const jumpTargets = positionJumps.pipe(
withLatestFrom(container.updates),
filter(([, { pinned }]) => pinned), // A
map(([position]) => position),
[...]
distinctUntilChanged((a, b) => isEqual(a, b)), // B
[...]
Lets assume we already have a pinned hovercard, e.g. our URL contains
something like L42&popover=pinned
. If we navigate back, lets say the
previously selected line was 21
, we are at L21
. This new position
doesn't make it code location marked as B because the new URL isn't
pinned anymore and thus it's filter out be the filter in code location
A.
Later when we navigate forward (to L42&popover=pinned
), code location
B will prevent that event from propagating because from its
perspective the position hasn't changed (it thinks the previous position
was L42
).
This can be easily fixed by flipping changing the order of the
filter()
and distinctUntilChanged
operators.
However that alone is not enough. Further down in the file we encounter the same problem:
const resolvedPositions = resolvedPositionEvents.pipe(
// Suppress emissions from other events that refer to the same position as the current one.
distinctUntilChanged((a, b) => isEqual(a.position, b.position))
)
Since we are still not propagating position changes that are not pinned,
this distinctUntilChanged
operator causes the same problem.
My undestanding is that this was introduced to prevent the popover from
flickering when it is pinned (because that updates the URL, which
triggers the jumpTargets
pipeline above).
Based on my understanding and my abilities I'm suggesting to update this
part to only apply the distinctUntilChanged
operator when the
hovercard is currently open (or about to be opened). I don't know
whether the logic I added to test that state is correct though.
IMPORTANT: This is a partial fix because jumping between a selected line and a pinned hovercard on the same line still doesn't work (because in that case the position is actually the same). But at this moment I don't have a good solution for this.
Befor/after video:
https://user-images.githubusercontent.com/179026/177359282-1b0b2526-8d87-43cf-80f2-29dc77c523d2.mp4
Test plan
App preview:
Check out the client app preview documentation to learn more.