diff --git a/src/Git/Commit.cs b/src/Git/Commit.cs
index 6b0b474a..e432bf4b 100644
--- a/src/Git/Commit.cs
+++ b/src/Git/Commit.cs
@@ -30,6 +30,14 @@ namespace SourceGit.Git {
public string SHA { get; set; }
}
+ ///
+ /// Line of text in file.
+ ///
+ public class Line {
+ public int No { get; set; }
+ public string Content { get; set; }
+ }
+
///
/// SHA
///
@@ -224,10 +232,10 @@ namespace SourceGit.Git {
///
///
///
- public string GetTextFileContent(Repository repo, string file, out bool isBinary) {
- var data = new List();
- var count = 0;
+ public List GetTextFileContent(Repository repo, string file, out bool isBinary) {
+ var data = new List();
var binary = false;
+ var count = 0;
repo.RunCommand($"diff 4b825dc642cb6eb9a060e54bf8d69288fbee4904 {SHA} --numstat -- \"{file}\"", line => {
if (REG_TESTBINARY.IsMatch(line)) binary = true;
@@ -237,29 +245,21 @@ namespace SourceGit.Git {
var errs = repo.RunCommand($"show {SHA}:\"{file}\"", line => {
if (binary) return;
- count++;
- if (data.Count >= 1000) return;
-
if (line.IndexOf('\0') >= 0) {
binary = true;
data.Clear();
- data.Add("BINARY FILE PREVIEW NOT SUPPORTED!");
return;
}
- data.Add(line);
+ count++;
+ data.Add(new Line() { No = count, Content = line });
});
if (errs != null) App.RaiseError(errs);
- }
-
- if (!binary && count > 1000) {
- data.Add("...");
- data.Add($"Total {count} lines. Hide {count-1000} lines.");
}
- isBinary = binary;
- return string.Join("\n", data);
+ isBinary = binary;
+ return data;
}
///
diff --git a/src/UI/CommitViewer.xaml b/src/UI/CommitViewer.xaml
index fbaf5103..17a40048 100644
--- a/src/UI/CommitViewer.xaml
+++ b/src/UI/CommitViewer.xaml
@@ -11,6 +11,26 @@
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
Unloaded="Cleanup">
+
+
+
+
+
+
+
+
@@ -427,16 +447,7 @@
-
-
-
+
diff --git a/src/UI/CommitViewer.xaml.cs b/src/UI/CommitViewer.xaml.cs
index 8826685b..7659a303 100644
--- a/src/UI/CommitViewer.xaml.cs
+++ b/src/UI/CommitViewer.xaml.cs
@@ -1,12 +1,14 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
+using System.Globalization;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
+using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
@@ -423,12 +425,105 @@ namespace SourceGit.UI {
Dispatcher.Invoke(() => {
fileTree.ItemsSource = fileTreeSource;
- filePreview.Text = "";
+ previewEditor.Children.Clear();
});
}
+ private void LayoutPreview(List 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