From c40f7737212c297cb836e7dfd47af3089cc7d8c8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 13 Nov 2025 20:19:58 +0000 Subject: [PATCH 1/4] Initial plan From 2cc6f158b8b4785ecce969b669e4cb4634678cb9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 13 Nov 2025 20:25:31 +0000 Subject: [PATCH 2/4] Fix clipboard copy for single cell to exclude markdown formatting When copying a single cell value from Stack Viewer, the clipboard now contains just the value without markdown table delimiters. Multiple cell selections still use markdown table format with leading "| " and trailing " |" characters. This fixes the regression where single cell copy would wrap values in "|" characters unnecessarily. Co-authored-by: brianrob <6210322+brianrob@users.noreply.github.com> --- src/PerfView/StackViewer/PerfDataGrid.xaml.cs | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/PerfView/StackViewer/PerfDataGrid.xaml.cs b/src/PerfView/StackViewer/PerfDataGrid.xaml.cs index 851d6eff5..dfb2b03cf 100644 --- a/src/PerfView/StackViewer/PerfDataGrid.xaml.cs +++ b/src/PerfView/StackViewer/PerfDataGrid.xaml.cs @@ -63,16 +63,20 @@ public PerfDataGrid() morphedContent = PadForColumn(morphedContent, i + e.StartColumnDisplayIndex); } - // Add a leading | character to the first column to ensure GitHub renders the content as table - if (i == 0) + // Add markdown table formatting only when multiple columns are selected + if (e.ClipboardRowContent.Count > 1) { - morphedContent = "| " + morphedContent; - } - - // Add a trailing | character to the last column to complete the markdown table row - if (i == e.ClipboardRowContent.Count - 1) - { - morphedContent = morphedContent + " |"; + // Add a leading | character to the first column to ensure GitHub renders the content as table + if (i == 0) + { + morphedContent = "| " + morphedContent; + } + + // Add a trailing | character to the last column to complete the markdown table row + if (i == e.ClipboardRowContent.Count - 1) + { + morphedContent = morphedContent + " |"; + } } // TODO Ugly, morph two cells on different rows into one line for the correct cut/paste experience From a07effc4bddf472445634d7d5fd24259d3e38c14 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 14 Nov 2025 00:29:47 +0000 Subject: [PATCH 3/4] Fix markdown formatting for vertically stacked cell selections Track total selected cells count to properly handle: - 1 cell: no markdown delimiters - 2 cells: no markdown delimiters (range handling) - 3+ cells: markdown table format with delimiters This fixes the corner case where selecting multiple cells from the same column (e.g., "module" and "ntoskrnl" vertically) would not properly format as a markdown table. Co-authored-by: brianrob <6210322+brianrob@users.noreply.github.com> --- src/PerfView/StackViewer/PerfDataGrid.xaml.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/PerfView/StackViewer/PerfDataGrid.xaml.cs b/src/PerfView/StackViewer/PerfDataGrid.xaml.cs index dfb2b03cf..6f4dbee35 100644 --- a/src/PerfView/StackViewer/PerfDataGrid.xaml.cs +++ b/src/PerfView/StackViewer/PerfDataGrid.xaml.cs @@ -63,8 +63,9 @@ public PerfDataGrid() morphedContent = PadForColumn(morphedContent, i + e.StartColumnDisplayIndex); } - // Add markdown table formatting only when multiple columns are selected - if (e.ClipboardRowContent.Count > 1) + // Add markdown table formatting only when more than 2 cells are selected + // Single cell and 2-cell selections (for ranges) should not have markdown formatting + if (m_numSelectedCells > 2) { // Add a leading | character to the first column to ensure GitHub renders the content as table if (i == 0) @@ -524,6 +525,7 @@ private void SelectedCellsChanged(object sender, SelectedCellsChangedEventArgs e { // We don't want the header for single values, or for 2 (for cutting and pasting ranges). int numSelectedCells = window.SelectedCellsChanged(sender, e); + m_numSelectedCells = numSelectedCells; if (numSelectedCells <= 2) { if (numSelectedCells == 2) @@ -563,6 +565,7 @@ private void DoHyperlinkHelp(object sender, System.Windows.RoutedEventArgs e) /// private string m_clipboardRangeStart; private string m_clipboardRangeEnd; + private int m_numSelectedCells; private int[] m_maxColumnInSelection; private int m_FindEnd; private Regex m_findPat; From afbc9d42dd5d19d8286df7a0e4090307a8eeccc4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 14 Nov 2025 00:50:12 +0000 Subject: [PATCH 4/4] Implement proper clipboard formatting based on selection dimensions Updated logic to track columns and rows separately: - Single column selections: include header, NO pipes - Multiple columns + single row: NO header, NO pipes - Multiple columns + multiple rows: include header, YES pipes This properly handles all clipboard scenarios as requested. Co-authored-by: brianrob <6210322+brianrob@users.noreply.github.com> --- src/PerfView/StackViewer/PerfDataGrid.xaml.cs | 79 +++++++++++++++---- 1 file changed, 63 insertions(+), 16 deletions(-) diff --git a/src/PerfView/StackViewer/PerfDataGrid.xaml.cs b/src/PerfView/StackViewer/PerfDataGrid.xaml.cs index 6f4dbee35..13ea58ec2 100644 --- a/src/PerfView/StackViewer/PerfDataGrid.xaml.cs +++ b/src/PerfView/StackViewer/PerfDataGrid.xaml.cs @@ -63,9 +63,11 @@ public PerfDataGrid() morphedContent = PadForColumn(morphedContent, i + e.StartColumnDisplayIndex); } - // Add markdown table formatting only when more than 2 cells are selected - // Single cell and 2-cell selections (for ranges) should not have markdown formatting - if (m_numSelectedCells > 2) + // Add markdown table formatting (| symbols) only when: + // - Multiple columns AND multiple rows selected + // Single column (any rows) or multiple columns in single row: no pipes + bool shouldAddPipes = (m_numSelectedColumns > 1 && m_numSelectedRows > 1); + if (shouldAddPipes) { // Add a leading | character to the first column to ensure GitHub renders the content as table if (i == 0) @@ -526,27 +528,70 @@ private void SelectedCellsChanged(object sender, SelectedCellsChangedEventArgs e // We don't want the header for single values, or for 2 (for cutting and pasting ranges). int numSelectedCells = window.SelectedCellsChanged(sender, e); m_numSelectedCells = numSelectedCells; - if (numSelectedCells <= 2) + + // Calculate the number of unique columns and rows selected + var dataGrid = sender as DataGrid; + if (dataGrid != null && dataGrid.SelectedCells.Count > 0) { - if (numSelectedCells == 2) + var uniqueColumns = new HashSet(); + var uniqueRows = new HashSet(); + foreach (var cell in dataGrid.SelectedCells) { - var dataGrid = sender as DataGrid; - if (dataGrid != null) - { - var cells = dataGrid.SelectedCells; - if (cells != null) - { - m_clipboardRangeStart = GetCellStringValue(cells[0]); - m_clipboardRangeEnd = GetCellStringValue(cells[1]); - } - } + uniqueColumns.Add(cell.Column); + uniqueRows.Add(cell.Item); } - Grid.ClipboardCopyMode = DataGridClipboardCopyMode.ExcludeHeader; + m_numSelectedColumns = uniqueColumns.Count; + m_numSelectedRows = uniqueRows.Count; } else + { + m_numSelectedColumns = 0; + m_numSelectedRows = 0; + } + + // Determine whether to include headers based on selection: + // - Single cell: no header + // - 2 cells (range): no header + // - Single column, multiple cells: include header + // - Multiple columns, single row: no header + // - Multiple columns, multiple rows: include header + bool shouldIncludeHeader = false; + if (numSelectedCells > 2) + { + if (m_numSelectedColumns == 1) + { + // Single column, multiple rows: include header + shouldIncludeHeader = true; + } + else if (m_numSelectedRows > 1) + { + // Multiple columns, multiple rows: include header + shouldIncludeHeader = true; + } + // Multiple columns, single row: no header (shouldIncludeHeader stays false) + } + + if (shouldIncludeHeader) { Grid.ClipboardCopyMode = DataGridClipboardCopyMode.IncludeHeader; } + else + { + Grid.ClipboardCopyMode = DataGridClipboardCopyMode.ExcludeHeader; + } + + if (numSelectedCells == 2) + { + if (dataGrid != null) + { + var cells = dataGrid.SelectedCells; + if (cells != null) + { + m_clipboardRangeStart = GetCellStringValue(cells[0]); + m_clipboardRangeEnd = GetCellStringValue(cells[1]); + } + } + } } m_maxColumnInSelection = null; } @@ -566,6 +611,8 @@ private void DoHyperlinkHelp(object sender, System.Windows.RoutedEventArgs e) private string m_clipboardRangeStart; private string m_clipboardRangeEnd; private int m_numSelectedCells; + private int m_numSelectedColumns; + private int m_numSelectedRows; private int[] m_maxColumnInSelection; private int m_FindEnd; private Regex m_findPat;