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

ITextViewOpenClosedListener only provides the correct Selection.Position.Offset once, for all the next calls it's always 0 #395

Open
luislhg opened this issue Jun 25, 2024 · 4 comments
Assignees
Milestone

Comments

@luislhg
Copy link

luislhg commented Jun 25, 2024

Issue
The ITextViewOpenClosedListener is only providing its offsets (textView.Selection.ActivePosition.Offset, textView.Selection.ActivePosition.Offset, textView.Selection.ActivePosition.Offset) for the first time the method TextViewOpenedAsync is called.
All subsequente calls, all the offsets are always 0, regardless of the file opened.

Project Setup

  • Create an empty extension template
  • Create a class "MyListener" with the content below
using Microsoft.VisualStudio.Extensibility;
using Microsoft.VisualStudio.Extensibility.Editor;
using Microsoft.VisualStudio.Extensibility.Shell;
using System.Diagnostics;

namespace ExtensibilityTextListenerBadOffset;
[VisualStudioContribution]
public class MyListener : ExtensionPart, ITextViewOpenClosedListener
{
    public TextViewExtensionConfiguration TextViewExtensionConfiguration => new()
    {
        AppliesTo = [DocumentFilter.FromGlobPattern("**/*", true)],
    };

    public Task TextViewClosedAsync(ITextViewSnapshot textView, CancellationToken cancellationToken)
    {
        return Task.CompletedTask;
    }

    public async Task TextViewOpenedAsync(ITextViewSnapshot textView, CancellationToken cancellationToken)
    {
        // TODO: API BUG?
        // Offsets only get a value at the first time it's ever called.
        // After positions always have 0, thus this is not working as expected.
        Debug.WriteLine($"ActivePosition {textView.Selection.ActivePosition.Offset}");
        Debug.WriteLine($"InsertionPosition {textView.Selection.InsertionPosition.Offset}");
        Debug.WriteLine($"AnchorPosition {textView.Selection.AnchorPosition.Offset}");

        await Extensibility.Shell().ShowPromptAsync($"Offset: {textView.Selection.ActivePosition.Offset}", PromptOptions.OK, cancellationToken);
    }
}

Project Sample is attached.
ExtensibilityTextListenerBadOffset.zip

Repro Steps

@tinaschrepfer tinaschrepfer added this to the Triage milestone Jul 3, 2024
@olegtk
Copy link
Member

olegtk commented Jul 3, 2024

Thank you for reporting this issue, @luislhg. I'm investigating.

@tinaschrepfer tinaschrepfer modified the milestones: Triage, Backlog Jul 19, 2024
@luislhg
Copy link
Author

luislhg commented Aug 3, 2024

@olegtk, thanks, just wanted to provide you some more guidance on how to repro and how useful this is.

After the first time TextViewOpenedAsync is fired, in all subsequent calls the textview.Selection values are always 0.
Below is a video with an Extensibility project at the left, and the Visual Studio debug session reproducing the bug at the right.

Extensibility.TextView.Selection.only.works.first.time.mp4

Why this deeply affects me and the extension:
This issue is preventing my extension from working properly. The goal of this extension feature is to fix the Visual Studio "Go To Definition (F12)" not opening the expected file when using Source Generators, as everytime you press F12 for a property or command that was source generated, VS will open the Source Generated file instead of the actual class and method you want.
My extension is using ITextViewOpenClosedListener to detect VS opened a source generated file, extracting the binding value based on the caret/selection position and then opening the correct file (usually a ViewModel) and closing the source generated file.

Issue and extension in action:

GoToBinding-Full01.mp4

You can see it worked fine - but that was the first call, since the textview isn't providing the selection values for all the next calls, I couldn't find any workaround for this...

Extension source: https://github.com/luislhg/brightextensions?tab=readme-ov-file#bright-xaml
Extension VSIX: https://marketplace.visualstudio.com/items?itemName=luislhg.BrightXaml

@olegtk
Copy link
Member

olegtk commented Dec 19, 2024

It's a timing issue, Go To Definition command first opens the file (at this point we call TextViewOpenedAsync) and then, slightly later, moves the caret to the target location in the file...

@olegtk
Copy link
Member

olegtk commented Dec 19, 2024

Actually looks like VS Code behaves the same way - first I get onDidChangeVisibleTextEditors with selection at 0 and then onDidChangeTextEditorSelection with correct selection.
VS currently doesn't fire TextViewChangedAsync for caret moves though, but it should.
Would it help your extension, @luislhg? It sounds kinda tricky to detect file open this way, but probably doable?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants