1

I develop a Visual Studio extension with a custom Code Map. It is a tree view control which nodes represent specific code elements. When you click on the tree node you navigate to the declaration of the corresponding code element in the code editor.

A simplified version of the navigation looks like this:

 public static async Task NavigateAsync(
 Microsoft.VisualStudio.Shell.IAsyncServiceProvider serviceProvider, 
 string filePath,int lineNumber, int character)
 {
 // first I obtain IWpfTextView for the active document
 IWpfTextView wpfTextView = await OpenCodeWindowAsync(serviceProvider, filePath);
 // next, generate the position to navigate to
 ITextSnapshotLine textLine = wpfTextView.TextSnapshot.GetLineFromLineNumber(lineNumber);
 int absoluteOffset = textLine.Start + character;
 // expand all collapsed regions in case we navigate inside them
 // with a call to the helper method
 SnapshotPoint point = wpfTextView.TextSnapshot.GetPoint(absoluteOffset);
 SnapshotSpan span = new SnapshotSpan(point, length: 0);
 await serviceProvider.ExpandAllRegionsContainingSpanAsync(span, wpfTextView); 
 // move the caret to a new position and scroll the code editor to it
 CaretPosition newCaretPosition = wpfTextView.MoveCaretTo(absoluteOffset);
 wpfTextView.ViewScroller.EnsureSpanVisible(span, EnsureSpanVisibleOptions.AlwaysCenter); 
 }

Everything works fine, except the list of visited location in Visual Studio is not updated. I mean the "Navigate Backward" journal located in the top left corner of Visual Studio:

Navigate Backward screenshot

I have found this description of this functionality on MSDN:

https://learn.microsoft.com/en-us/archive/blogs/zainnab/navigate-backward-and-navigate-forward

It mentions that VS creates so-called "go-back markers" which are basically entries in the navigation journal. In some other places they could be also referred to as "way points". They are created under the following conditions:

A go-back marker is dropped under the following conditions:

  • An incremental search (including reverse) leaves a go-back marker at the beginning of the search and another one at the end.

  • A Go To Line action, like CTRL + G, or a mouse-click that moves the cursor 11 lines or more from the current position drops a go-back marker at the new location.

  • A destructive action (like hitting Backspace) after having moved the cursor to a new location drops a go-back marker.

  • Doing a search, like Ctrl+F, drops a go-back marker at the found location.

  • Opening a file drops a go-back marker wherever the cursor was on the old file and drops another on the opened file.

I believe this is what I need. I want to programmatically add such go-back markers but can't find a way to do it. I have looked for them in Google, MSDN, VS Extensibility examples from Mads Kristensen, open source projects on GitHub but so far I haven't managed to find any API that would allow to use them. What I already found:

  • Implementations very close to what I use in other projects that have custom Code Maps for VS

  • Implementations using old VS COM interfaces like this:

    EnvDTE.TextSelection ts = dte.ActiveDocument.Selection as EnvDTE.TextSelection;
    ts.MoveToLineAndOffset(...); 
    

    The navigation works but the navigation journal is still not updated.

  • The navigation implementations that internally call "Go To Definition" command like this. I can't reuse the "Go To Definition" command because:

    • Code Map doesn't have a text under caret that is used by the "Go To Definition" command as a sort of input.
    • In general, I need a custom navigation, not just a navigation to the definition. My extension has other functionality that requires custom navigation rules.

Currently, I'm stuck with this issue and I would really appreciate any help.

UPDATE: I've also tried to check VS open source layers which are stored on GitHub: https://github.com/microsoft/vs-editor-api/tree/main Unfortunately, I haven't found anything I can use, or the implementation of the "Navigate Backward" functionality. Maybe I've just missed it.

There are internal IDocumentNavigationService and IGoToDefinitionService in Roslyn, currently I try to see if I can use them either with a reflection or by using a similar logic. If this approach works our I'll add an answer describing it.

Still, I would always prefer a public API over the usage of the internal services, so my question is still relevant. I would mark answer that uses public API and solved my issue as correct over any answer that relies on calls to internal services.

asked Sep 3, 2023 at 20:30
6
  • You could try find usages of these calls using ILSpy in Visual Studio assemblies. Commented Sep 4, 2023 at 0:40
  • Hi @aybe. Unfortunately, a big part of VS functionality is written in COM, not .Net. So, .net decompiles don’t help here. Commented Sep 4, 2023 at 9:04
  • I have already tried to investigate the WPF visual tree of the control and data context behind it but to no avail. These controls seem to be formed very generally by VS automation model (remember that you can customize all VS toolbars and their location, that’s supported by making the controls logic very generic with some kind of automatiion) Commented Sep 4, 2023 at 9:11
  • I don't see a public API that can help achieve this feature. If you really need a clear public API that can be used, you may need to submit a feature request to enhance the extensibility of the public API. :) Commented Sep 6, 2023 at 9:49
  • The problem is I don't know the exact API that will solve my problem. If you mean the IDocumentNavigationService API then I found such request which was just closed: github.com/dotnet/roslyn/issues/7328 Commented Sep 6, 2023 at 20:17

1 Answer 1

0

Actually, a comment from @JasonMalinowski in my other question also resolved this issue. Since there wasn't any answers for a long time, I will post the link to that comment as an answer: How to navigate to a definition of a Symbol located in the external assembly

And to provide more context - to navigate correctly in Visual Studio you should use a special helper method from VisualStudioWorkspace: https://github.com/dotnet/roslyn/blob/e1b57268c58d0ccd93992ef3495cd22b8ad07412/src/VisualStudio/Core/Def/Implementation/ProjectSystem/VisualStudioWorkspace.cs#L103

In addition to the navigation this helper will also add entries to the VS "navigation journal" I described in the question.

You can also read about this method from another SO answer by @JasonMalinowski: https://stackoverflow.com/a/69668770/2893207

answered Sep 20, 2024 at 21:40
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.