in src/Sarif.Viewer.VisualStudio.Core/ResultTextMarker.cs [239:366]
public bool NavigateTo(bool usePreviewPane, bool moveFocusToCaretLocation)
{
ThreadHelper.ThrowIfNotOnUIThread();
bool documentWasOpened = false;
// Make sure to fully populate region.
if (!this.TryToFullyPopulateRegionAndFilePath())
{
return false;
}
// If the tag doesn't have a persistent span, or its associated document isn't open,
// then this indicates that we need to attempt to open the document and cause it to
// be tagged.
if (!this.PersistentSpanValid())
{
// Now, we need to make sure the document gets tagged before the next section of code
// in this method attempts to navigate to it.
// So the flow looks like this. Get Visual Studio to open the document for us.
// That will cause Visual Studio to create a text view for it.
// Now, just because a text view is created does not mean that
// a request for "tags" has occurred. Tagging (and the display of those tags)
// is highly asynchronous. Taggers are created on demand and disposed when they are no longer
// needed. It is quite common to have multiple taggers active for the same text view and text buffers
// at the same time. (An easy example is a split-window scenario).
// This class relies on a persistent span (this.persistentSpan) being non-null and valid.
// This class "creates" the persistent span when it is asked for its tags in the GetTags
// method.
// To facilitate that, we will:
// 1) Open the document
// 2) Get the text view from the document.
// 2a) That alone may be enough to make the persistent span valid if it was already created.
// 3) If the persistent span still isn't valid (likely because we have crated the persistent span yet), ask ourselves for the tags which will
// cause the span to be created.
IVsWindowFrame vsWindowFrame = SdkUIUtilities.OpenDocument(ServiceProvider.GlobalProvider, this.resolvedFullFilePath, usePreviewPane);
if (vsWindowFrame == null)
{
return false;
}
vsWindowFrame.Show();
documentWasOpened = true;
// At this point, the persistent span may have "become valid" due to the document open.
// If not, then ask ourselves for the tags which will create the persistent span.
if (!this.PersistentSpanValid())
{
if (!SdkUIUtilities.TryGetTextViewFromFrame(vsWindowFrame, out ITextView textView))
{
return false;
}
var componentModel = (IComponentModel)Package.GetGlobalService(typeof(SComponentModel));
if (componentModel == null)
{
return false;
}
IPersistentSpanFactory persistentSpanFactory = componentModel.GetService<IPersistentSpanFactory>();
if (persistentSpanFactory == null)
{
return false;
}
if (!this.TryCreatePersistentSpan(textView.TextBuffer, persistentSpanFactory))
{
return false;
}
}
}
if (!this.PersistentSpanValid())
{
return false;
}
// Now, if the span IS valid it doesn't mean that the editor is visible, so make sure we open the document
// for the user if needed.
// But before we try to call "open document" let's see if we can find an active view because calling
// "open document" is super slow (which causes keyboard navigation from items in the SARIF explorer to be slow
// IF "open document" is called every time.
if (!documentWasOpened ||
!SdkUIUtilities.TryGetActiveViewForTextBuffer(this.persistentSpan.Span.TextBuffer, out IWpfTextView wpfTextView))
{
IVsWindowFrame vsWindowFrame = SdkUIUtilities.OpenDocument(ServiceProvider.GlobalProvider, this.resolvedFullFilePath, usePreviewPane);
if (vsWindowFrame == null)
{
return false;
}
vsWindowFrame.Show();
if (!SdkUIUtilities.TryGetActiveViewForTextBuffer(this.persistentSpan.Span.TextBuffer, out wpfTextView))
{
return false;
}
}
ITextSnapshot currentSnapshot = this.persistentSpan.Span.TextBuffer.CurrentSnapshot;
// Note that "GetSpan" is not really a great name. What is actually happening
// is the "Span" that "GetSpan" is called on is "mapped" onto the passed in
// text snapshot. In essence what this means is take the "persistent span"
// that we have and "replay" any edits that have occurred and return a new
// span. So, if the span is no longer relevant (lets say the text has been deleted)
// then you'll get back an empty span.
SnapshotSpan trackingSpanSnapshot = this.persistentSpan.Span.GetSpan(currentSnapshot);
// If the caret is already in the text within the marker, don't re-select it
// otherwise users cannot move the caret in the region.
// If the caret isn't in the marker, move it there.
if (!trackingSpanSnapshot.Contains(wpfTextView.Caret.Position.BufferPosition) &&
!trackingSpanSnapshot.IsEmpty)
{
wpfTextView.Selection.Select(trackingSpanSnapshot, isReversed: false);
wpfTextView.Caret.MoveTo(trackingSpanSnapshot.End);
wpfTextView.Caret.EnsureVisible();
if (moveFocusToCaretLocation)
{
wpfTextView.VisualElement.Focus();
}
}
return true;
}