feature<CommitViewer>: show line numbers in file preview and remove limitation for line counts

This commit is contained in:
leo 2020-12-15 13:12:16 +08:00
parent 0517142330
commit 06d98a374d
5 changed files with 136 additions and 30 deletions

View file

@ -30,6 +30,14 @@ namespace SourceGit.Git {
public string SHA { get; set; } public string SHA { get; set; }
} }
/// <summary>
/// Line of text in file.
/// </summary>
public class Line {
public int No { get; set; }
public string Content { get; set; }
}
/// <summary> /// <summary>
/// SHA /// SHA
/// </summary> /// </summary>
@ -224,10 +232,10 @@ namespace SourceGit.Git {
/// <param name="repo"></param> /// <param name="repo"></param>
/// <param name="file"></param> /// <param name="file"></param>
/// <returns></returns> /// <returns></returns>
public string GetTextFileContent(Repository repo, string file, out bool isBinary) { public List<Line> GetTextFileContent(Repository repo, string file, out bool isBinary) {
var data = new List<string>(); var data = new List<Line>();
var count = 0;
var binary = false; var binary = false;
var count = 0;
repo.RunCommand($"diff 4b825dc642cb6eb9a060e54bf8d69288fbee4904 {SHA} --numstat -- \"{file}\"", line => { repo.RunCommand($"diff 4b825dc642cb6eb9a060e54bf8d69288fbee4904 {SHA} --numstat -- \"{file}\"", line => {
if (REG_TESTBINARY.IsMatch(line)) binary = true; if (REG_TESTBINARY.IsMatch(line)) binary = true;
@ -237,29 +245,21 @@ namespace SourceGit.Git {
var errs = repo.RunCommand($"show {SHA}:\"{file}\"", line => { var errs = repo.RunCommand($"show {SHA}:\"{file}\"", line => {
if (binary) return; if (binary) return;
count++;
if (data.Count >= 1000) return;
if (line.IndexOf('\0') >= 0) { if (line.IndexOf('\0') >= 0) {
binary = true; binary = true;
data.Clear(); data.Clear();
data.Add("BINARY FILE PREVIEW NOT SUPPORTED!");
return; return;
} }
data.Add(line); count++;
data.Add(new Line() { No = count, Content = line });
}); });
if (errs != null) App.RaiseError(errs); if (errs != null) App.RaiseError(errs);
}
if (!binary && count > 1000) {
data.Add("...");
data.Add($"Total {count} lines. Hide {count-1000} lines.");
} }
isBinary = binary; isBinary = binary;
return string.Join("\n", data); return data;
} }
/// <summary> /// <summary>

View file

@ -11,6 +11,26 @@
mc:Ignorable="d" mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800" d:DesignHeight="450" d:DesignWidth="800"
Unloaded="Cleanup"> Unloaded="Cleanup">
<UserControl.Resources>
<Style x:Key="Style.DataGridRow.NoBringIntoView" TargetType="{x:Type DataGridRow}" BasedOn="{StaticResource Style.DataGridRow}">
<EventSetter Event="RequestBringIntoView" Handler="OnPreviewRequestBringIntoView"/>
</Style>
<Style x:Key="Style.DataGridText.LineNumber" TargetType="{x:Type TextBlock}">
<Setter Property="HorizontalAlignment" Value="Right"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="Padding" Value="8,0"/>
<Setter Property="FontSize" Value="12"/>
</Style>
<Style x:Key="Style.DataGridText.Content" TargetType="{x:Type TextBlock}">
<Setter Property="HorizontalAlignment" Value="Left"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="Padding" Value="4,0,0,0"/>
<Setter Property="FontSize" Value="12"/>
</Style>
</UserControl.Resources>
<TabControl> <TabControl>
<TabItem Header="INFORMATION"> <TabItem Header="INFORMATION">
<Grid> <Grid>
@ -427,16 +447,7 @@
<Border Grid.Column="2" BorderThickness="1" Margin="2,0" BorderBrush="{StaticResource Brush.Border2}"> <Border Grid.Column="2" BorderThickness="1" Margin="2,0" BorderBrush="{StaticResource Brush.Border2}">
<Grid> <Grid>
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"> <Grid x:Name="previewEditor" SizeChanged="OnPreviewSizeChanged" TextElement.FontFamily="Consolas" TextElement.Foreground="{StaticResource Brush.FG}"/>
<TextBlock
FontSize="10pt"
FontFamily="Consolas"
Padding="8"
Opacity="0.8"
Background="{StaticResource Brush.BG2}"
Foreground="{StaticResource Brush.FG}"
x:Name="filePreview"/>
</ScrollViewer>
<StackPanel x:Name="maskRevision" Orientation="Vertical" VerticalAlignment="Center" HorizontalAlignment="Center" Visibility="Collapsed"> <StackPanel x:Name="maskRevision" Orientation="Vertical" VerticalAlignment="Center" HorizontalAlignment="Center" Visibility="Collapsed">
<Path x:Name="iconPreviewRevision" Width="64" Height="64" Style="{StaticResource Style.Icon}" Data="{StaticResource Icon.Submodule}" Fill="{StaticResource Brush.FG2}"/> <Path x:Name="iconPreviewRevision" Width="64" Height="64" Style="{StaticResource Style.Icon}" Data="{StaticResource Icon.Submodule}" Fill="{StaticResource Brush.FG2}"/>

View file

@ -1,12 +1,14 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Globalization;
using System.IO; using System.IO;
using System.Security.Cryptography; using System.Security.Cryptography;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input; using System.Windows.Input;
using System.Windows.Media; using System.Windows.Media;
using System.Windows.Media.Imaging; using System.Windows.Media.Imaging;
@ -423,12 +425,105 @@ namespace SourceGit.UI {
Dispatcher.Invoke(() => { Dispatcher.Invoke(() => {
fileTree.ItemsSource = fileTreeSource; fileTree.ItemsSource = fileTreeSource;
filePreview.Text = ""; previewEditor.Children.Clear();
}); });
} }
private void LayoutPreview(List<Git.Commit.Line> data) {
var maxLineNumber = $"{data.Count + 1}";
var formatted = new FormattedText(
maxLineNumber,
CultureInfo.CurrentCulture,
FlowDirection.LeftToRight,
new Typeface(new FontFamily("Consolas"), FontStyles.Normal, FontWeights.Normal, FontStretches.Normal),
12.0,
Brushes.Black,
VisualTreeHelper.GetDpi(this).PixelsPerDip);
var grid = new DataGrid();
grid.SetValue(Grid.RowProperty, 1);
grid.RowHeight = 16.0;
grid.FrozenColumnCount = 1;
grid.ContextMenuOpening += OnPreviewContextMenuOpening;
grid.RowStyle = FindResource("Style.DataGridRow.NoBringIntoView") as Style;
var colLineNumber = new DataGridTextColumn();
colLineNumber.IsReadOnly = true;
colLineNumber.Binding = new Binding("No");
colLineNumber.ElementStyle = FindResource("Style.DataGridText.LineNumber") as Style;
colLineNumber.Width = new DataGridLength(formatted.Width + 16, DataGridLengthUnitType.Pixel);
grid.Columns.Add(colLineNumber);
var offset = formatted.Width + 16;
if (data.Count * 16 > previewEditor.ActualHeight) offset += 8;
var colContent = new DataGridTextColumn();
colContent.IsReadOnly = true;
colContent.Binding = new Binding("Content");
colContent.ElementStyle = FindResource("Style.DataGridText.Content") as Style;
colContent.MinWidth = previewEditor.ActualWidth - offset;
colContent.Width = DataGridLength.SizeToCells;
grid.Columns.Add(colContent);
var splitter = new System.Windows.Shapes.Rectangle();
splitter.Width = 1;
splitter.Fill = FindResource("Brush.Border2") as Brush;
splitter.HorizontalAlignment = HorizontalAlignment.Left;
splitter.Margin = new Thickness(formatted.Width + 15, 0, 0, 0);
grid.ItemsSource = data;
previewEditor.Children.Add(grid);
previewEditor.Children.Add(splitter);
}
private void OnPreviewContextMenuOpening(object sender, ContextMenuEventArgs e) {
var grid = sender as DataGrid;
if (grid == null) return;
var menu = new ContextMenu();
var copy = new MenuItem();
copy.Header = "Copy";
copy.Click += (o, ev) => {
var items = grid.SelectedItems;
if (items.Count == 0) return;
var builder = new StringBuilder();
foreach (var item in items) {
var line = item as Git.Commit.Line;
if (line == null) continue;
builder.Append(line.Content);
builder.AppendLine();
}
Clipboard.SetText(builder.ToString());
};
menu.Items.Add(copy);
menu.IsOpen = true;
e.Handled = true;
}
private void OnPreviewRequestBringIntoView(object sender, RequestBringIntoViewEventArgs e) {
e.Handled = true;
}
private void OnPreviewSizeChanged(object sender, SizeChangedEventArgs e) {
if (previewEditor.Children.Count == 0) return;
var totalWidth = previewEditor.ActualWidth;
var totalHeight = previewEditor.ActualHeight;
var editor = previewEditor.Children[0] as DataGrid;
var minWidth = totalWidth - editor.NonFrozenColumnsViewportHorizontalOffset;
var desireHeight = editor.Items.Count * editor.RowHeight;
if (desireHeight > totalHeight) minWidth -= 8;
editor.Columns[1].MinWidth = minWidth;
editor.Columns[1].Width = DataGridLength.SizeToCells;
editor.UpdateLayout();
}
private async void FileTreeItemSelected(object sender, RoutedPropertyChangedEventArgs<object> e) { private async void FileTreeItemSelected(object sender, RoutedPropertyChangedEventArgs<object> e) {
filePreview.Text = ""; previewEditor.Children.Clear();
maskPreviewNotSupported.Visibility = Visibility.Collapsed; maskPreviewNotSupported.Visibility = Visibility.Collapsed;
maskRevision.Visibility = Visibility.Collapsed; maskRevision.Visibility = Visibility.Collapsed;
@ -450,7 +545,7 @@ namespace SourceGit.UI {
if (isBinary) { if (isBinary) {
Dispatcher.Invoke(() => maskPreviewNotSupported.Visibility = Visibility.Visible); Dispatcher.Invoke(() => maskPreviewNotSupported.Visibility = Visibility.Visible);
} else { } else {
Dispatcher.Invoke(() => filePreview.Text = data); Dispatcher.Invoke(() => LayoutPreview(data));
} }
}); });
} }

View file

@ -7,7 +7,7 @@
mc:Ignorable="d" mc:Ignorable="d"
FontFamily="Consolas"> FontFamily="Consolas">
<UserControl.Resources> <UserControl.Resources>
<Style x:Key="Style.DataGridRow.TextChange" TargetType="{x:Type DataGridRow}" BasedOn="{StaticResource Style.DataGridRow}"> <Style x:Key="Style.DataGridRow.NoBringIntoView" TargetType="{x:Type DataGridRow}" BasedOn="{StaticResource Style.DataGridRow}">
<EventSetter Event="RequestBringIntoView" Handler="OnLineRequestBringIntoView"/> <EventSetter Event="RequestBringIntoView" Handler="OnLineRequestBringIntoView"/>
</Style> </Style>

View file

@ -421,7 +421,7 @@ namespace SourceGit.UI {
grid.RowHeight = 16.0; grid.RowHeight = 16.0;
grid.FrozenColumnCount = lineNumbers.Length; grid.FrozenColumnCount = lineNumbers.Length;
grid.ContextMenuOpening += OnTextChangeContextMenuOpening; grid.ContextMenuOpening += OnTextChangeContextMenuOpening;
grid.RowStyle = FindResource("Style.DataGridRow.TextChange") as Style; grid.RowStyle = FindResource("Style.DataGridRow.NoBringIntoView") as Style;
foreach (var number in lineNumbers) { foreach (var number in lineNumbers) {
var colLineNumber = new DataGridTextColumn(); var colLineNumber = new DataGridTextColumn();