public void GetMessageInlines_RendersWebLinkWithBackslashesInLinkText() { string url = "http://example.com"; string message = $@"The file [..\directory\file.cpp]({url}) has a problem."; var link = new Hyperlink(); link.Tag = new Tuple <int, object>(1, new Uri(url, UriKind.Absolute)); link.Inlines.Add(new Run(@"..\directory\file.cpp")); var expected = new List <Inline> { new Run("The file "), link, new Run(" has a problem.") }; var actual = SdkUIUtilities.GetMessageInlines(message, index: 1, clickHandler: Hyperlink_Click); actual.Count.Should().Be(expected.Count); VerifyTextRun(expected[0], actual[0]); VerifyHyperlink(expected[1], actual[1]); VerifyTextRun(expected[2], actual[2]); }
public SarifLocationTextMarkerTagger( ITextView textView, ITextBuffer textBuffer, IPersistentSpanFactory persistentSpanFactory, ITextViewCaretListenerService <ITextMarkerTag> textViewCaretListenerService, ISarifErrorListEventSelectionService sarifErrorListEventSelectionService) { ThreadHelper.ThrowIfNotOnUIThread(); if (!SdkUIUtilities.TryGetFileNameFromTextBuffer(textBuffer, out this.filePath)) { throw new ArgumentException("Always expect to be able to get file name from text buffer.", nameof(textBuffer)); } this.TextBuffer = textBuffer; this.persistentSpanFactory = persistentSpanFactory; this.sarifErrorListEventSelectionService = sarifErrorListEventSelectionService; // Subscribe to the SARIF error item being selected from the error list // so we can properly filter the tags being shown in the editor // to the currently selected item. this.sarifErrorListEventSelectionService.SelectedItemChanged += this.SelectedSarifItemChanged; // Subscribe to the caret position so we can send enter and exit notifications // to the tags so they can decide potentially change their colors. textViewCaretListenerService.CreateListener(textView, this); }
public void GetMessageInlines_RendersTwoLinksAndHandlesLinkAtTheEnd() { const string message = @"The quick [brown fox](1) jumps over the [lazy dog](2)"; var link1 = new Hyperlink(); link1.Tag = 1; link1.Inlines.Add(new Run("brown fox")); var link2 = new Hyperlink(); link2.Tag = 2; link2.Inlines.Add(new Run("lazy dog")); var expected = new List <Inline> { new Run("The quick "), link1, new Run(" jumps over the "), link2, }; var actual = SdkUIUtilities.GetMessageInlines(message, clickHandler: this.Hyperlink_Click); actual.Count.Should().Be(expected.Count); VerifyTextRun(expected[0], actual[0]); VerifyHyperlink(expected[1], actual[1]); VerifyTextRun(expected[2], actual[2]); VerifyHyperlink(expected[3], actual[3]); }
private void Hyperlink_RequestNavigate(object sender, RequestNavigateEventArgs e) { if (this.NavigateUri != null) { SdkUIUtilities.OpenExternalUrl(this.NavigateUri); } }
private static void VerifyErrorListItemEntry(SarifErrorListItem error, SarifResultTableEntry entry, dynamic test) { error.ShortMessage.Should().Be(test.ShortMessage); error.Message.Should().Be(test.FullMessage); error.RawMessage.Should().Be(test.RawMessage.Trim()); error.HasEmbeddedLinks.Should().Be(test.ContainsHyperlink); entry.TryGetValue(StandardTableKeyNames.Text, out object textColumn).Should().BeTrue(); entry.TryGetValue(StandardTableKeyNames.FullText, out object fullTextColumn).Should().BeTrue(); entry.TryGetValue(StandardTableKeyNames2.TextInlines, out object textInlinesColumn).Should().BeTrue(); entry.TryGetValue(SarifResultTableEntry.FullTextInlinesColumnName, out object fullTextInlinesColumn).Should().BeTrue(); ((string)textColumn).Should().Be(test.ShortMessage); ((string)fullTextColumn).Should().Be(error.HasDetailsContent ? test.FullMessage : null); if (test.ContainsHyperlink) { var textInlines = textInlinesColumn as List <Inline>; textInlines.Should().NotBeNull(); SdkUIUtilities.GetPlainText(textInlines).Should().Be(test.ShortPlainText); var fullTextInlines = fullTextInlinesColumn as List <Inline>; fullTextInlines.Should().NotBeNull(); SdkUIUtilities.GetPlainText(fullTextInlines).Should().Be(test.FullPlainText); } else { textInlinesColumn.Should().BeNull(); fullTextInlinesColumn.Should().BeNull(); } }
internal static async Task ProcessSarifLogAsync(SarifLog sarifLog, string logFilePath, bool cleanErrors, bool openInEditor) { // The creation of the data models must be done on the UI thread (for now). // VS's table data source constructs are indeed thread safe. // The object model (which is eventually handed to WPF\XAML) could also // be constructed on any thread as well. // However the current implementation of the data model and // the "run data cache" have not been augmented to support this // and are not thread safe. // This work could be done in the future to do even less work on the UI // thread if needed. if (!SarifViewerPackage.IsUnitTesting) { await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); } // Clear previous data if (cleanErrors) { CleanAllErrors(); } bool hasResults = false; foreach (Run run in sarifLog.Runs) { // run.tool is required, add one if it's missing if (run.Tool == null) { run.Tool = new Tool { Driver = new ToolComponent { Name = Resources.UnknownToolName, }, }; } if (Instance.WriteRunToErrorList(run, logFilePath, sarifLog) > 0) { hasResults = true; } } if (openInEditor && !SarifViewerPackage.IsUnitTesting) { SdkUIUtilities.OpenDocument(ServiceProvider.GlobalProvider, logFilePath, usePreviewPane: false); } if (hasResults) { if (!SarifViewerPackage.IsUnitTesting) { // We cannot show UI during unit-tests. SdkUIUtilities.ShowToolWindowAsync(new Guid(ToolWindowGuids80.ErrorList), activate: false).FileAndForget(Constants.FileAndForgetFaultEventNames.ShowErrorList); } } RaiseLogProcessed(ExceptionalConditionsCalculator.Calculate(sarifLog)); }
public void GetMessageInlines_RendersOneLinkPlusLiteralBrackets() { const string message = @"The quick [brown fox](1) jumps over the \[lazy dog\]."; var link = new Hyperlink { Tag = 1 }; link.Inlines.Add(new Run("brown fox")); var expected = new List <Inline> { new Run("The quick "), link, new Run(" jumps over the [lazy dog]."), }; List <Inline> actual = SdkUIUtilities.GetMessageInlines(message, clickHandler: this.Hyperlink_Click); actual.Count.Should().Be(expected.Count); VerifyTextRun(expected[0], actual[0]); VerifyHyperlink(expected[1], actual[1]); VerifyTextRun(expected[2], actual[2]); }
public void GetFileLocationPath_UriPathCanBeResolved() { string repoPath = "file:///C:/code/myProject/src/"; var run = new Microsoft.CodeAnalysis.Sarif.Run { OriginalUriBaseIds = new Dictionary <string, ArtifactLocation> { ["REPO_ROOT"] = new ArtifactLocation { Uri = new Uri(repoPath), } }, }; var dataCache = new RunDataCache(); int runId = CodeAnalysisResultManager.Instance.GetNextRunIndex(); CodeAnalysisResultManager.Instance.RunIndexToRunDataCache.Add(runId, dataCache); CodeAnalysisResultManager.Instance.CacheUriBasePaths(run); string filePath = @"AnalysisStep.cs"; var artifact = new ArtifactLocation { Uri = new Uri(filePath, UriKind.Relative), UriBaseId = "REPO_ROOT" }; string path = SdkUIUtilities.GetFileLocationPath(artifact, runId); path.Should().Be(@"C:\code\myProject\src\AnalysisStep.cs"); }
public void GetMessageInlines_RendersWebLink() { string url = "http://example.com"; string message = $"The quick [brown fox]({url}) jumps over the lazy dog."; var link = new Hyperlink(); link.Tag = new Tuple <int, object>(1, new Uri(url, UriKind.Absolute)); link.Inlines.Add(new Run("brown fox")); var expected = new List <Inline> { new Run("The quick "), link, new Run(" jumps over the lazy dog.") }; var actual = SdkUIUtilities.GetMessageInlines(message, index: 1, clickHandler: Hyperlink_Click); actual.Count.Should().Be(expected.Count); VerifyTextRun(expected[0], actual[0]); VerifyHyperlink(expected[1], actual[1]); VerifyTextRun(expected[2], actual[2]); }
public void SarifSnapshot_GetMessageEmbeddedLinkInlines_TwoLinksAndEndsWithLink() { string message = @"The quick [brown fox](1) jumps over the [lazy dog](2)"; var link1 = new Hyperlink(); link1.Tag = new Tuple <int, int>(1, 1); link1.Inlines.Add(new Run("brown fox")); var link2 = new Hyperlink(); link2.Tag = new Tuple <int, int>(1, 2); link2.Inlines.Add(new Run("lazy dog")); var expected = new List <Inline> { new Run("The quick "), link1, new Run(" jumps over the "), link2 }; var actual = SdkUIUtilities.GetMessageInlines(message, index: 1, clickHandler: Hyperlink_Click); actual.Count.Should().Be(expected.Count); VerifyTextRun(expected[0], actual[0]); VerifyHyperlink(expected[1], actual[1]); VerifyTextRun(expected[2], actual[2]); VerifyHyperlink(expected[3], actual[3]); }
public void GetPlainText_ConvertInlinesWithTwoHttpLinks() { // raw text "The quick [brown fox](https://example.com) jumps over the [lazy dog](1)."; const string url = "http://example.com"; const string expected = @"The quick brown fox jumps over the lazy dog."; var hyperlink1 = new Hyperlink(new Run("brown fox")); hyperlink1.NavigateUri = new Uri(url); var hyperlink2 = new Hyperlink(new Run("lazy dog")); hyperlink2.Tag = 1; var inputs = new List <Inline> { new Run("The quick "), hyperlink1, new Run(" jumps over the "), hyperlink2, new Run("."), }; string actual = SdkUIUtilities.GetPlainText(inputs); actual.Should().NotBeNull(); actual.Should().Be(expected); }
internal virtual void SaveFixLedger() { if (s_sourceFileFixLedger.Count > 0) { SdkUIUtilities.StoreObject <Dictionary <string, FixOffsetList> >(s_sourceFileFixLedger, s_sourceFileFixLedgerFileName); } }
// Event handler for HyperLink click event in a XAML element private static void Hyperlink_RequestNavigate(object sender, RequestNavigateEventArgs e) { if (sender is Hyperlink hyperlink && !string.IsNullOrWhiteSpace(hyperlink.NavigateUri?.AbsoluteUri)) { SdkUIUtilities.OpenExternalUrl(hyperlink.NavigateUri.AbsoluteUri); e.Handled = true; } }
public void GetMessageInlines_DoesNotGenerateLinkForEscapedBrackets() { string message = @"The quick \[brown fox\] jumps over the lazy dog."; // Because there are no embedded links, we shouldn't get anything back var actual = SdkUIUtilities.GetMessageInlines(message, index: 1, clickHandler: Hyperlink_Click); actual.Count.Should().Be(0); }
private void RefreshPersistentSpans() { ThreadHelper.ThrowIfNotOnUIThread(); // If this text buffer is not associated with a file, it cannot have any SARIF errors. this.errorsInFile = SdkUIUtilities.TryGetFileNameFromTextBuffer(this.textBuffer, out string fileName) ? GetErrorsInFile(fileName) : Enumerable.Empty <SarifErrorListItem>().ToList(); this.CalculatePersistentSpans(this.errorsInFile); }
public void GetPlainText_GetNullIfInputIsNullOrEmpty() { List <Inline> inputs = null; string actual = SdkUIUtilities.GetPlainText(inputs); actual.Should().BeNull(); inputs = new List <Inline>(); actual = SdkUIUtilities.GetPlainText(inputs); actual.Should().BeNull(); }
public void SarifSnapshot_GetMessageEmbeddedLinkInlines_ZeroLinksEscapedBrackets() { string message = @"The quick \[brown fox\] jumps over the lazy dog."; var expected = new List <Inline> { new Run("The quick [brown fox] jumps over the lazy dog.") }; var actual = SdkUIUtilities.GetMessageInlines(message, index: 1, clickHandler: Hyperlink_Click); VerifyTextRun(expected[0], actual[0]); }
public SarifLocationErrorTagger(ITextBuffer textBuffer, IPersistentSpanFactory persistentSpanFactory, ISarifErrorListEventSelectionService sarifErrorListEventSelectionService) { ThreadHelper.ThrowIfNotOnUIThread(); if (!SdkUIUtilities.TryGetFileNameFromTextBuffer(textBuffer, out this.filePath)) { throw new ArgumentException("Always expect to be able to get file name from text buffer.", nameof(textBuffer)); } this.TextBuffer = textBuffer; this.persistentSpanFactory = persistentSpanFactory; this.sarifErrorListEventSelectionService = sarifErrorListEventSelectionService; this.sarifErrorListEventSelectionService.SelectedItemChanged += this.SarifErrorListEventSelectionService_SelectedItemChanged; }
public void GetFileLocationPath_UriIsLocalPath() { var dataCache = new RunDataCache(); int runId = CodeAnalysisResultManager.Instance.GetNextRunIndex(); CodeAnalysisResultManager.Instance.RunIndexToRunDataCache.Add(runId, dataCache); string filePath = @"C:\repo\src\AnalysisStep.cs"; var artifact = new ArtifactLocation { Uri = new Uri(filePath, UriKind.Absolute) }; string path = SdkUIUtilities.GetFileLocationPath(artifact, runId); path.Should().Be(filePath); }
public void GetFileLocationPath_UriIsNull() { var dataCache = new RunDataCache(); int runId = CodeAnalysisResultManager.Instance.GetNextRunIndex(); CodeAnalysisResultManager.Instance.RunIndexToRunDataCache.Add(runId, dataCache); var artifact = new ArtifactLocation(); string path = SdkUIUtilities.GetFileLocationPath(artifact, runId); path.Should().BeNull(); artifact = null; path = SdkUIUtilities.GetFileLocationPath(artifact, runId); path.Should().BeNull(); }
public void GetPlainText_ConvertInlinesWithPathLink() { // raw text "The quick brown fox jumps over the lazy dog." const string expected = @"The quick brown fox jumps over the lazy dog."; var inputs = new List <Inline> { new Run("The quick "), new Run("brown fox"), new Run(" jumps over the "), new Run("lazy dog."), }; string actual = SdkUIUtilities.GetPlainText(inputs); actual.Should().NotBeNull(); actual.Should().Be(expected); }
#pragma warning restore IDE0044 #pragma warning restore CS0649 /// <inheritdoc/> /// <remarks> /// Note that Visual Studio's tagger aggregation expects and correctly handles null /// if a tagger provider does not want to provide tags. /// </remarks> public ITagger <T> CreateTagger <T>(ITextView textView, ITextBuffer textBuffer) where T : ITag { ThreadHelper.ThrowIfNotOnUIThread(); if (textView == null) { throw new ArgumentNullException(nameof(textView)); } if (textBuffer == null) { throw new ArgumentNullException(nameof(textBuffer)); } // The SARIF viewer needs a text buffer to have a file name in order to be able to associate a SARIF // result location with the file. Visual Studio allows text buffers to be created at any time with our without a filename. // So, if there is no file name, then do not create a tagger for this buffer. if (!SdkUIUtilities.TryGetFileNameFromTextBuffer(textBuffer, out _)) { return(null); } ISarifLocationTagger newTagger = null; if (typeof(T) == typeof(IErrorTag)) { newTagger = new SarifLocationErrorTagger(textBuffer, this.persistentSpanFactory, this.sarifErrorListEventSelectionService); } if (typeof(T) == typeof(ITextMarkerTag)) { newTagger = new SarifLocationTextMarkerTagger(textView, textBuffer, this.persistentSpanFactory, this.textViewCaretListenerService, this.sarifErrorListEventSelectionService); } if (newTagger != null) { this.sarifLocationTaggerService.AddTagger(newTagger); } return(newTagger as ITagger <T>); }
internal virtual void LoadFixLedger() { if (s_sourceFileFixLedger == null) { s_sourceFileFixLedger = SdkUIUtilities.GetStoredObject <Dictionary <string, FixOffsetList> >(s_sourceFileFixLedgerFileName) ?? new Dictionary <string, FixOffsetList>(); // Remove entries where the last modified timestamps don't match // This could indicate that the file was modified or overwritten externally List <string> remove = s_sourceFileFixLedger .Where(e => !File.Exists(e.Key) || File.GetLastWriteTime(e.Key) != e.Value.LastModified) .Select(e => e.Key) .ToList(); if (remove.Count > 0) { remove.ForEach(p => s_sourceFileFixLedger.Remove(p)); SaveFixLedger(); } } }
public void GetPlainText_ConvertInlinesWithLiteralBrackets() { // raw text "The file ['..\directory\file.cpp']({url}) has a \[problem\]." const string expected = @"The file '..\directory\file.cpp' has a \[problem\]."; var hyperlink = new Hyperlink(new Run(@"'..\directory\file.cpp'")); hyperlink.NavigateUri = new Uri("file://*****:*****@" has a \[problem\]."), }; string actual = SdkUIUtilities.GetPlainText(inputs); actual.Should().NotBeNull(); actual.Should().Be(expected); }
public void SarifSnapshot_GetMessageEmbeddedLinkInlines_DontCreateLinks() { string message = @"The quick [brown fox](2) jumps over the lazy dog."; var expected = new List <Inline> { new Run("The quick "), new Run("brown fox"), new Run(" jumps over the lazy dog.") }; var actual = SdkUIUtilities.GetInlinesForErrorMessage(message); actual.Count.Should().Be(expected.Count); for (int i = 0; i < actual.Count; i++) { VerifyTextRun(expected[i], actual[i]); } }
public void GetInlinesForErrorMessage_DoesNotCreateLinks() { const string message = @"The quick [brown fox](2) jumps over the lazy dog."; var expected = new List <Inline> { new Run("The quick "), new Run("brown fox"), new Run(" jumps over the lazy dog."), }; List <Inline> actual = SdkUIUtilities.GetInlinesForErrorMessage(message); actual.Count.Should().Be(expected.Count); for (int i = 0; i < actual.Count; i++) { VerifyTextRun(expected[i], actual[i]); } }
public void GetInlinesForErrorMessage_IgnoresInvalidLink() { // That is, the fact that the link destination doesn't look like a URL // doesn't bother it. string message = @"The quick [brown fox](some text) jumps over the lazy dog."; var expected = new List <Inline> { new Run("The quick "), new Run("brown fox"), new Run(" jumps over the lazy dog.") }; var actual = SdkUIUtilities.GetInlinesForErrorMessage(message); actual.Count.Should().Be(expected.Count); for (int i = 0; i < actual.Count; i++) { VerifyTextRun(expected[i], actual[i]); } }
internal void InlineLink_Click(object sender, RoutedEventArgs e) { ThreadHelper.ThrowIfNotOnUIThread(); if (!(sender is XamlDoc.Hyperlink hyperLink)) { return; } string uriString = null; if (hyperLink.Tag is string uriAsString) { uriString = uriAsString; } else if (hyperLink.Tag is Uri uri) { uriString = uri.ToString(); } if (!string.IsNullOrEmpty(uriString) && Uri.TryCreate(uriString, UriKind.RelativeOrAbsolute, out Uri _)) { SdkUIUtilities.OpenExternalUrl(uriString); } }
public void SarifSnapshot_GetMessageEmbeddedLinkInlines_OneLinkPlusEscapedBrackets() { string message = @"The quick [brown fox](1) jumps over the \[lazy dog\]."; var link = new Hyperlink(); link.Tag = new Tuple <int, int>(1, 1); link.Inlines.Add(new Run("brown fox")); var expected = new List <Inline> { new Run("The quick "), link, new Run(" jumps over the [lazy dog].") }; var actual = SdkUIUtilities.GetMessageInlines(message, index: 1, clickHandler: Hyperlink_Click); actual.Count.Should().Be(expected.Count); VerifyTextRun(expected[0], actual[0]); VerifyHyperlink(expected[1], actual[1]); VerifyTextRun(expected[2], actual[2]); }
public void GetMessageInlines_RendersOneLink() { string message = @"The quick [brown fox](1) jumps over the lazy dog."; var link = new Hyperlink(); link.Tag = new Tuple <int, object>(1, 1); link.Inlines.Add(new Run("brown fox")); var expected = new List <Inline> { new Run("The quick "), link, new Run(" jumps over the lazy dog.") }; var actual = SdkUIUtilities.GetMessageInlines(message, index: 1, clickHandler: Hyperlink_Click); actual.Count.Should().Be(expected.Count); VerifyTextRun(expected[0], actual[0]); VerifyHyperlink(expected[1], actual[1]); VerifyTextRun(expected[2], actual[2]); }