diff --git a/src/StructuredLogViewer/Controls/BuildControl.xaml.cs b/src/StructuredLogViewer/Controls/BuildControl.xaml.cs index fb9edcb1..3fc70ce4 100644 --- a/src/StructuredLogViewer/Controls/BuildControl.xaml.cs +++ b/src/StructuredLogViewer/Controls/BuildControl.xaml.cs @@ -42,6 +42,7 @@ public partial class BuildControl : UserControl private MenuItem viewSubtreeTextItem; private MenuItem searchInSubtreeItem; private MenuItem searchInNodeByNameItem; + private MenuItem searchThisNode; private MenuItem excludeSubtreeFromSearchItem; private MenuItem excludeNodeByNameFromSearch; private MenuItem goToTimeLineItem; @@ -185,6 +186,7 @@ public BuildControl(Build build, string logFilePath) excludeSubtreeFromSearchItem = new MenuItem() { Header = "Exclude subtree from search" }; excludeNodeByNameFromSearch = new MenuItem() { Header = "Exclude node from search" }; searchInNodeByNameItem = new MenuItem() { Header = "Search in this node." }; + searchThisNode = new MenuItem() { Header = "Search This Node" }; goToTimeLineItem = new MenuItem() { Header = "Go to timeline" }; goToTracingItem = new MenuItem() { Header = "Go to tracing" }; copyChildrenItem = new MenuItem() { Header = "Copy children" }; @@ -217,6 +219,7 @@ public BuildControl(Build build, string logFilePath) excludeSubtreeFromSearchItem.Click += (s, a) => ExcludeSubtreeFromSearch(); excludeNodeByNameFromSearch.Click += (s, a) => ExcludeNodeByNameFromSearch(); searchInNodeByNameItem.Click += (s, a) => SearchInNodeByName(); + searchThisNode.Click += (s, a) => SearchThisNode(); goToTimeLineItem.Click += (s, a) => GoToTimeLine(); goToTracingItem.Click += (s, a) => GoToTracing(); copyChildrenItem.Click += (s, a) => CopyChildren(); @@ -243,6 +246,7 @@ public BuildControl(Build build, string logFilePath) contextMenu.AddItem(searchNuGetItem); contextMenu.AddItem(searchInSubtreeItem); contextMenu.AddItem(searchInNodeByNameItem); + contextMenu.AddItem(searchThisNode); contextMenu.AddItem(excludeSubtreeFromSearchItem); contextMenu.AddItem(excludeNodeByNameFromSearch); contextMenu.AddItem(goToTimeLineItem); @@ -389,6 +393,7 @@ public void Dispose() excludeSubtreeFromSearchItem = null; excludeNodeByNameFromSearch = null; searchInNodeByNameItem = null; + searchThisNode = null; goToTimeLineItem = null; goToTracingItem = null; copyChildrenItem = null; @@ -855,6 +860,16 @@ private void ContextMenu_Opened(object sender, RoutedEventArgs e) debugItem.Visibility = canRun; hideItem.Visibility = node is TreeNode ? Visibility.Visible : Visibility.Collapsed; + if (node is SearchableItem searchItem) + { + searchThisNode.Visibility = Visibility.Visible; + searchThisNode.Header = $"Search {searchItem.SearchText}"; + } + else + { + searchThisNode.Visibility = Visibility.Collapsed; + } + if (node is TimedNode timedNode) { showTimeItem.Visibility = Visibility.Visible; @@ -1569,6 +1584,15 @@ public void SearchInNodeByName() } } + public void SearchThisNode() + { + if (treeView.SelectedItem is SearchableItem searchNode) + { + searchLogControl.SearchText = searchNode.SearchText; + SelectSearchTab(); + } + } + public void ExcludeSubtreeFromSearch() { if (treeView.SelectedItem is TimedNode treeNode) diff --git a/src/StructuredLogViewer/Controls/TracingControl.xaml.cs b/src/StructuredLogViewer/Controls/TracingControl.xaml.cs index ea348324..29f4f10b 100644 --- a/src/StructuredLogViewer/Controls/TracingControl.xaml.cs +++ b/src/StructuredLogViewer/Controls/TracingControl.xaml.cs @@ -741,6 +741,10 @@ private Panel CreatePanelForNodeDivider(bool showTime) var textBlock = new TextBlock(); textBlock.Text = $"{i}s"; + // Set these to make TextBlock scale like TrueType. + textBlock.SnapsToDevicePixels = true; + TextOptions.SetTextFormattingMode(textBlock, TextFormattingMode.Ideal); + // add textHeight/2 pixels of front padding Canvas.SetLeft(textBlock, textHeight / 2 + i * OneSecondPixelWidth); canvas.Children.Add(textBlock); diff --git a/src/StructuredLogger/Analyzers/BuildAnalyzer.cs b/src/StructuredLogger/Analyzers/BuildAnalyzer.cs index 4a5e9328..bebddcaf 100644 --- a/src/StructuredLogger/Analyzers/BuildAnalyzer.cs +++ b/src/StructuredLogger/Analyzers/BuildAnalyzer.cs @@ -231,16 +231,18 @@ string Intern(string text) var top10Tasks = build.GetOrCreateNodeWithName(folderName); foreach (var kvp in durations) { - var taskItem = new Item + var taskItem = new SearchableItem { - Text = Intern(kvp.Key) + " = " + Intern($"{TextUtilities.DisplayDuration(kvp.Value.Duration)}, {kvp.Value.Count} calls.") + Text = Intern(kvp.Key) + " = " + Intern($"{TextUtilities.DisplayDuration(kvp.Value.Duration)}, {kvp.Value.Count} calls."), + SearchText = $@"$task ""{kvp.Key}""", }; var childNodes = kvp.Value.ChildNodes.OrderByDescending(kv => kv.Value.Duration).Take(10); foreach (var durationNodes in childNodes) { - taskItem.AddChild(new Item + taskItem.AddChild(new SearchableItem { - Text = Intern(durationNodes.Key) + " = " + Intern($"{TextUtilities.DisplayDuration(durationNodes.Value.Duration)}, {durationNodes.Value.Count} calls.") + Text = Intern(durationNodes.Key) + " = " + Intern($"{TextUtilities.DisplayDuration(durationNodes.Value.Duration)}, {durationNodes.Value.Count} calls."), + SearchText = $@"$target ""{durationNodes.Key}""", }); } top10Tasks.AddChild(taskItem); diff --git a/src/StructuredLogger/ObjectModel/SearchableItem.cs b/src/StructuredLogger/ObjectModel/SearchableItem.cs new file mode 100644 index 00000000..d2cc3d36 --- /dev/null +++ b/src/StructuredLogger/ObjectModel/SearchableItem.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Microsoft.Build.Logging.StructuredLogger +{ + public class SearchableItem : Item + { + public SearchableItem() : base() { } + + public string SearchText + { + get { return _searchText ?? this.Text; } + set { _searchText = value; } + } + + private string _searchText; + } +}