/// <summary> /// Attempts to locate an active "code window" view for the given text buffer. /// </summary> /// <param name="textBuffer">The text buffer for which to locate a view.</param> /// <param name="wpfTextView">On successful return, contains an instance of <see cref="IWpfTextView"/> that is being used to display the text buffer contents.</param> /// <returns>Returns true if a view can be located.</returns> public static bool TryGetActiveViewForTextBuffer(ITextBuffer textBuffer, out IWpfTextView wpfTextView) { wpfTextView = null; if (!textBuffer.Properties.TryGetProperty(typeof(IVsTextBuffer), out IVsTextBuffer vsTextBuffer)) { return(false); } if (!(Package.GetGlobalService(typeof(SVsTextManager)) is IVsTextManager2 textManager2)) { return(false); } if (textManager2.GetActiveView2(fMustHaveFocus: 0, pBuffer: vsTextBuffer, grfIncludeViewFrameType: (uint)_VIEWFRAMETYPE.vftCodeWindow, ppView: out IVsTextView vsTextView) != VSConstants.S_OK) { return(false); } if (!SdkUIUtilities.TryGetWpfTextView(vsTextView, out wpfTextView)) { return(false); } return(true); }
public void NavigateTo(bool usePreviewPane = true) { if (LineMarker != null) { LineMarker?.NavigateTo(usePreviewPane); } else { // The user clicked an inline link with an integer target, which points to // a Location object that does NOT have a region associated with it. // Before anything else, see if this is an external link we should open in the browser. if (Uri.TryCreate(this.FilePath, UriKind.Absolute, out Uri uri)) { if (!uri.IsFile) { System.Diagnostics.Process.Start(uri.OriginalString); return; } } if (!File.Exists(this.FilePath)) { CodeAnalysisResultManager.Instance.TryRebaselineAllSarifErrors(RunId, this.UriBaseId, this.FilePath); } if (File.Exists(this.FilePath)) { SdkUIUtilities.OpenDocument(SarifViewerPackage.ServiceProvider, this.FilePath, usePreviewPane); } } }
private string GetDocumentName(uint docCookie, IVsWindowFrame pFrame) { string documentName = null; IVsRunningDocumentTable runningDocTable = SdkUIUtilities.GetService <SVsRunningDocumentTable, IVsRunningDocumentTable>(ServiceProvider); if (runningDocTable != null) { uint grfRDTFlags; uint dwReadLocks; uint dwEditLocks; IVsHierarchy pHier; uint itemId; IntPtr docData = IntPtr.Zero; try { int hr = runningDocTable.GetDocumentInfo(docCookie, out grfRDTFlags, out dwReadLocks, out dwEditLocks, out documentName, out pHier, out itemId, out docData); } finally { if (docData != IntPtr.Zero) { Marshal.Release(docData); } } } return(documentName); }
internal IVsWindowFrame NavigateTo(bool usePreviewPane) { // Fall back to the file and line number if (!File.Exists(this.FullFilePath)) { if (!CodeAnalysisResultManager.Instance.TryRebaselineAllSarifErrors(this.UriBaseId, this.FullFilePath)) { return(null); } } IVsWindowFrame windowFrame = SdkUIUtilities.OpenDocument(SarifViewerPackage.ServiceProvider, this.FullFilePath, usePreviewPane); if (windowFrame != null) { IVsTextView textView = GetTextViewFromFrame(windowFrame); if (textView == null) { return(null); } var sourceLocation = this.GetSourceLocation(); // Navigate the caret to the desired location. Text span uses 0-based indexes TextSpan ts; ts.iEndLine = ts.iStartLine = sourceLocation.StartLine - 1; ts.iEndIndex = ts.iStartIndex = Math.Max(sourceLocation.StartColumn - 1, 0); textView.EnsureSpanVisible(ts); textView.SetSelection(ts.iStartLine, ts.iStartIndex, ts.iEndLine, ts.iEndIndex); } return(windowFrame); }
public SarifErrorListItem(Run run, int runIndex, Notification notification, string logFilePath, ProjectNameCache projectNameCache) : this() { ThreadHelper.ThrowIfNotOnUIThread(); this.RunIndex = runIndex; string ruleId = null; if (notification.AssociatedRule != null) { ruleId = notification.AssociatedRule.Id; } else if (notification.Descriptor != null) { ruleId = notification.Descriptor.Id; } run.TryGetRule(ruleId, out ReportingDescriptor rule); this.RawMessage = notification.Message.Text?.Trim() ?? string.Empty; (this.ShortMessage, this.Message) = SdkUIUtilities.SplitResultMessage(this.RawMessage, MaxConcisedTextLength); this.Level = notification.Level; this.LogFilePath = logFilePath; this.FileName = SdkUIUtilities.GetFileLocationPath(notification.Locations?[0]?.PhysicalLocation?.ArtifactLocation, this.RunIndex) ?? string.Empty; this.ProjectName = projectNameCache.GetName(this.FileName); this.Locations.Add(new LocationModel(resultId: this.ResultId, runIndex: this.RunIndex) { FilePath = FileName }); this.Tool = run.Tool.ToToolModel(); this.Rule = rule.ToRuleModel(ruleId); this.Invocation = run.Invocations?[0]?.ToInvocationModel(); this.WorkingDirectory = Path.Combine(Path.GetTempPath(), this.RunIndex.ToString()); this.HelpLink = this.Rule?.HelpUri; }
internal void AddAllowedDownloadHost(string host) { if (!this._allowedDownloadHosts.Contains(host)) { this._allowedDownloadHosts.Add(host); SdkUIUtilities.StoreObject <List <string> >(this._allowedDownloadHosts, AllowedDownloadHostsFileName); } }
// This method is called when you click an inline link, with an integer target, which // points to a Location object that has a region associated with it. internal IVsWindowFrame NavigateTo(bool usePreviewPane) { ThreadHelper.ThrowIfNotOnUIThread(); // Before anything else, see if this is an external link we should open in the browser. Uri uri; if (Uri.TryCreate(this.FullFilePath, UriKind.Absolute, out uri)) { if (!uri.IsFile) { System.Diagnostics.Process.Start(uri.OriginalString); return(null); } } // Fall back to the file and line number if (!File.Exists(this.FullFilePath)) { if (!CodeAnalysisResultManager.Instance.TryRebaselineAllSarifErrors(_runId, this.UriBaseId, this.FullFilePath)) { return(null); } } if (File.Exists(this.FullFilePath) && Uri.TryCreate(this.FullFilePath, UriKind.Absolute, out uri)) { // Fill out the region's properties FileRegionsCache regionsCache = CodeAnalysisResultManager.Instance.RunDataCaches[_runId].FileRegionsCache; Region = regionsCache.PopulateTextRegionProperties(Region, uri, true); } IVsWindowFrame windowFrame = SdkUIUtilities.OpenDocument(SarifViewerPackage.ServiceProvider, this.FullFilePath, usePreviewPane); if (windowFrame != null) { IVsTextView textView = GetTextViewFromFrame(windowFrame); if (textView == null) { return(null); } var sourceLocation = this.GetSourceLocation(); // Navigate the caret to the desired location. Text span uses 0-based indexes TextSpan ts; ts.iStartLine = sourceLocation.StartLine - 1; ts.iEndLine = sourceLocation.EndLine - 1; ts.iStartIndex = Math.Max(sourceLocation.StartColumn - 1, 0); ts.iEndIndex = Math.Max(sourceLocation.EndColumn - 1, 0); textView.EnsureSpanVisible(ts); textView.SetSelection(ts.iStartLine, ts.iStartIndex, ts.iEndLine, ts.iEndIndex); } return(windowFrame); }
// This ctor is internal rather than private for unit test purposes. internal CodeAnalysisResultManager( IFileSystem fileSystem, PromptForResolvedPathDelegate promptForResolvedPathDelegate = null) { this._fileSystem = fileSystem; this._promptForResolvedPathDelegate = promptForResolvedPathDelegate ?? this.PromptForResolvedPath; this._allowedDownloadHosts = SdkUIUtilities.GetStoredObject <List <string> >(AllowedDownloadHostsFileName) ?? new List <string>(); // Get temporary path for embedded files. this.temporaryFilePath = Path.GetTempPath(); this.temporaryFilePath = Path.Combine(this.temporaryFilePath, TemporaryFileDirectoryName); }
public SarifErrorListItem(Run run, int runIndex, Result result, string logFilePath, ProjectNameCache projectNameCache) : this() { if (!SarifViewerPackage.IsUnitTesting) { #pragma warning disable VSTHRD108 // Assert thread affinity unconditionally ThreadHelper.ThrowIfNotOnUIThread(); #pragma warning restore VSTHRD108 } bool runHasSuppressions = run.HasSuppressedResults(); bool runHasAbsentResults = run.HasAbsentResults(); this.RunIndex = runIndex; this.ResultId = Interlocked.Increment(ref currentResultId); this.SarifResult = result; ReportingDescriptor rule = result.GetRule(run); this.Tool = run.Tool.ToToolModel(); this.Rule = rule.ToRuleModel(result.RuleId); this.Invocation = run.Invocations?[0]?.ToInvocationModel(); this.WorkingDirectory = Path.Combine(Path.GetTempPath(), this.RunIndex.ToString()); this.HelpLink = this.Rule?.HelpUri; this.RawMessage = result.GetMessageText(rule, concise: false).Trim(); (this.ShortMessage, this.Message) = SdkUIUtilities.SplitResultMessage(this.RawMessage, MaxConcisedTextLength); string xamlContent = null; if (this.SarifResult?.Message?.TryGetProperty(XamlPropertyName, out xamlContent) == true) { this.XamlMessage = Regex.Unescape(xamlContent); } this.FileName = result.GetPrimaryTargetFile(run); this.ProjectName = projectNameCache.GetName(this.FileName); this.Category = runHasAbsentResults ? result.GetCategory() : nameof(BaselineState.None); this.Region = result.GetPrimaryTargetRegion(); this.Level = this.GetEffectiveLevel(result); this.VSSuppressionState = runHasSuppressions && result.IsSuppressed() ? VSSuppressionState.Suppressed : VSSuppressionState.Active; this.LogFilePath = logFilePath; if (this.Region != null) { this.LineNumber = this.Region.StartLine; this.ColumnNumber = this.Region.StartColumn; } }
// This ctor is internal rather than private for unit test purposes. internal CodeAnalysisResultManager( IFileSystem fileSystem, PromptForResolvedPathDelegate promptForResolvedPathDelegate = null) { _fileSystem = fileSystem; _promptForResolvedPathDelegate = promptForResolvedPathDelegate ?? PromptForResolvedPath; this.SarifErrors = new List <SarifErrorListItem>(); _remappedUriBasePaths = new Dictionary <string, Uri>(); _remappedPathPrefixes = new List <Tuple <string, string> >(); _fileToNewLineIndexMap = new Dictionary <string, NewLineIndex>(); _allowedDownloadHosts = SdkUIUtilities.GetStoredObject <List <string> >(AllowedDownloadHostsFileName) ?? new List <string>(); // Get temporary path for embedded files. TemporaryFilePath = Path.GetTempPath(); TemporaryFilePath = Path.Combine(TemporaryFilePath, TemporaryFileDirectoryName); }
/// <summary> /// Open the file using the current document state scope /// </summary> private static IVsWindowFrame OpenDocumentInCurrentScope(IServiceProvider provider, string file) { ThreadHelper.ThrowIfNotOnUIThread(); IVsUIShellOpenDocument openDoc = SdkUIUtilities.GetService <SVsUIShellOpenDocument, IVsUIShellOpenDocument>(provider); IVsRunningDocumentTable runningDocTable = SdkUIUtilities.GetService <SVsRunningDocumentTable, IVsRunningDocumentTable>(provider); if (openDoc == null || runningDocTable == null) { throw Marshal.GetExceptionForHR(VSConstants.E_FAIL); } uint cookieDocLock = FindDocument(runningDocTable, file); IVsWindowFrame windowFrame; Guid textViewGuid = VSConstants.LOGVIEWID_TextView; // Unused variables IVsUIHierarchy uiHierarchy; Microsoft.VisualStudio.OLE.Interop.IServiceProvider serviceProvider; uint itemId; int hr = openDoc.OpenDocumentViaProject(file, ref textViewGuid, out serviceProvider, out uiHierarchy, out itemId, out windowFrame); if (ErrorHandler.Failed(hr)) { throw Marshal.GetExceptionForHR(hr); } if (cookieDocLock == 0) // Document was not open earlier, and should be open now. { cookieDocLock = FindDocument(runningDocTable, file); } if (windowFrame != null) { // This will make the document visible to the user and switch focus to it. ShowNoActivate doesn't help because for tabbed documents they // are not brought to the front if they are already opened. windowFrame.Show(); } return(windowFrame); }
public SarifErrorListItem(Run run, Notification notification, string logFilePath, ProjectNameCache projectNameCache) : this() { ThreadHelper.ThrowIfNotOnUIThread(); _runId = CodeAnalysisResultManager.Instance.CurrentRunId; ReportingDescriptor rule; string ruleId = null; if (notification.AssociatedRule != null) { ruleId = notification.AssociatedRule.Id; } else if (notification.Descriptor != null) { ruleId = notification.Descriptor.Id; } run.TryGetRule(ruleId, out rule); Message = notification.Message.Text.Trim(); ShortMessage = ExtensionMethods.GetFirstSentence(notification.Message.Text); if (!Message.EndsWith(".")) { ShortMessage = ShortMessage.TrimEnd('.'); } Level = notification.Level; LogFilePath = logFilePath; FileName = SdkUIUtilities.GetFileLocationPath(notification.Locations?[0]?.PhysicalLocation?.ArtifactLocation, _runId) ?? ""; ProjectName = projectNameCache.GetName(FileName); Locations.Add(new LocationModel() { FilePath = FileName }); Tool = run.Tool.ToToolModel(); Rule = rule.ToRuleModel(ruleId); Invocation = run.Invocations?[0]?.ToInvocationModel(); WorkingDirectory = Path.Combine(Path.GetTempPath(), _runId.ToString()); }
internal void AddAllowedDownloadHost(string host) { _allowedDownloadHosts.Add(host); SdkUIUtilities.StoreObject <List <string> >(_allowedDownloadHosts, AllowedDownloadHostsFileName); }
/// <summary> /// Attempts to navigate a VS editor to the text marker. /// </summary> /// <param name="usePreviewPane">Indicates whether to use VS's preview pane.</param> /// <param name="moveFocusToCaretLocation">Indicates whether to move focus to the caret location.</param> /// <returns>Returns true if a VS editor was opened.</returns> /// <remarks> /// The <paramref name="usePreviewPane"/> indicates whether Visual Studio opens the document as a preview (tab to the right) /// rather than as an "open code editor" (tab attached to other open documents on the left). /// </remarks> 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); }