Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Makes mouse/left/right navigation skip injected text. Also fixes bracket decoration bug. #128140

Merged
merged 7 commits into from
Jul 8, 2021

Conversation

hediet
Copy link
Member

@hediet hediet commented Jul 7, 2021

Please don't review yet, there is a bug. Fixed.

@hediet hediet requested a review from alexdima July 7, 2021 15:54
@hediet hediet self-assigned this Jul 7, 2021
@hediet hediet force-pushed the hediet/injected-text-position-normalization branch from 1428c58 to c8118a4 Compare July 7, 2021 20:36
Copy link
Member

@alexdima alexdima left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, but very complex! Took me quite a while to understand.

I've pushed the following changes directly:

  • avoid allocating a Map and strings to set as keys every time the view state is set, especially since 90% or more of the time the calls to viewModel.normalizePosition will be a no-op (lines without injected text and without wrapping). Doing now the same optimization directly in code.
  • removes check for converting model range to view range that was added to fix Decorations that are ending on word-wrapped line leak to the next line whitespace #50163 since this is no longer necessary thanks to the affinity.
  • in normalizePosition, I found it easier to handle the Left and Right affinities directly in the method, without converting to a model position and back. Maybe I'm missing something, but that seemed to be correct.

Let me know how you feel about my changes and if they seem correct to you, then please merge.

There is one follow-up item, but we can file it under an issue separately:

  • If we want to move over inline completions to use injected text, we must figure out how to set ITextContentData.mightBeForeignElement to true for injected text or, even better, add a new property e.g. ITextContentData.injectedTextDecorationId?: string | null. This should then be adopted in inlineCompletionsHoverParticipant.ts. The hover participant wants to know if the mouse is over injected text. This information needs to be captured in _doHitTest, around doing normalization.

@alexdima alexdima added this to the July 2021 milestone Jul 8, 2021
@hediet
Copy link
Member Author

hediet commented Jul 8, 2021

in normalizePosition, I found it easier to handle the Left and Right affinities directly in the method, without converting to a model position and back. Maybe I'm missing something, but that seemed to be correct.

Unfortuntately, I think this is not correct. Multiple injected texts might be injected at the same model position. Then you need to go at the start/end of the first/last injected text at that model position. When no position affinity is set (=none), there is nothing against setting a cursor between injected texts that are injected to the same position.

Even a wrapping point could be immediately before/after an injected text. Left/right normalization must skip it, otherwise move left/right is not going to work properly.
Thats why a view -> model -> view roundtrip imo is the best solution here.

@alexdima
Copy link
Member

alexdima commented Jul 8, 2021

Multiple injected texts might be injected at the same model position

👍 Aha! Very good point! I think this._lineBreakData.getInjectedTextAt can be renamed/changed to do the normalization itself. It doesn't seem to have any other callers. It could be renamed to normalizeOffset() and it could deal inside of it with the touching injected text. What do you think about that?

Even a wrapping point could be immediately before/after an injected text. Left/right normalization must skip it, otherwise move left/right is not going to work properly.

Could that be resolved by invoking this._lineBreakData.getOutputPositionOfOffsetInUnwrappedLine with the correct affinity? I moved that method out of a case where the affinity was always PositionAffinity.None so the parameter was not passed in, but if we'd pass in the affinity, I think that would take care of the wrapping points.

Thats why a view -> model -> view roundtrip imo is the best solution here.

I think this would be correct, but I have this intuition that this might be error-prone (or lossy?). If we ever want to add text elision, doing the roundtrip might bring up more problems.

@hediet
Copy link
Member Author

hediet commented Jul 8, 2021

What do you think about that?

You mean for both left/right/no-affinity normalization or only for no-affinity?
If the latter, then I agree. However, internally that method might still make sense as finding the injected text at a position is easier to understand than normalization.

…th multiple touching injected texts and add a test with this case
@alexdima
Copy link
Member

alexdima commented Jul 8, 2021

This is what I meant -- e03e480

@hediet hediet merged commit de115c7 into main Jul 8, 2021
@hediet hediet deleted the hediet/injected-text-position-normalization branch July 8, 2021 14:47
@Kingwl
Copy link
Contributor

Kingwl commented Jul 9, 2021

Cool! Thanks for the work!

@github-actions github-actions bot locked and limited conversation to collaborators Aug 22, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants