diff --git a/SourceGit/Git/Diff.cs b/SourceGit/Git/Diff.cs index b53b2a83..d303aa48 100644 --- a/SourceGit/Git/Diff.cs +++ b/SourceGit/Git/Diff.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.IO; using System.Text; using System.Text.RegularExpressions; @@ -30,6 +31,14 @@ namespace SourceGit.Git { Both, } + /// + /// Binary change. + /// + public class BinaryChange { + public long Size = 0; + public long PreSize = 0; + } + /// /// Block /// @@ -215,11 +224,7 @@ namespace SourceGit.Git { rs.Fit(); if (rs.IsBinary) { - var b = new Block(); - b.Mode = LineMode.Indicator; - b.Append("BINARY FILES NOT SUPPORTED!!!"); - rs.Blocks.Clear(); - rs.Blocks.Add(b); + rs.Blocks.Clear(); } else if (rs.Blocks.Count == 0) { var b = new Block(); b.Mode = LineMode.Indicator; @@ -229,5 +234,38 @@ namespace SourceGit.Git { return rs; } + + /// + /// Get file size changes for binary file. + /// + /// + /// + /// + /// + /// + public static BinaryChange GetSizeChange(Repository repo, string[] revisions, string path, string orgPath = null) { + var change = new BinaryChange(); + + if (revisions.Length == 0) { // Compare working copy with HEAD + change.Size = new FileInfo(Path.Combine(repo.Path, path)).Length; + change.PreSize = repo.GetFileSize("HEAD", path); + } else if (revisions.Length == 1) { // Compare HEAD with given revision. + change.Size = repo.GetFileSize("HEAD", path); + if (!string.IsNullOrEmpty(orgPath)) { + change.PreSize = repo.GetFileSize(revisions[0], orgPath); + } else { + change.PreSize = repo.GetFileSize(revisions[0], path); + } + } else { + change.Size = repo.GetFileSize(revisions[1], path); + if (!string.IsNullOrEmpty(orgPath)) { + change.PreSize = repo.GetFileSize(revisions[0], orgPath); + } else { + change.PreSize = repo.GetFileSize(revisions[0], path); + } + } + + return change; + } } } diff --git a/SourceGit/Git/Repository.cs b/SourceGit/Git/Repository.cs index 9a0b0383..b5849d61 100644 --- a/SourceGit/Git/Repository.cs +++ b/SourceGit/Git/Repository.cs @@ -4,6 +4,7 @@ using System.Diagnostics; using System.IO; using System.Text; using System.Text.RegularExpressions; +using System.Windows.Forms; using System.Windows.Threading; using System.Xml.Serialization; @@ -876,6 +877,20 @@ namespace SourceGit.Git { if (errs != null) App.RaiseError(errs); return blame; } + + /// + /// Get file size. + /// + /// + /// + /// + public long GetFileSize(string sha, string path) { + long size = 0; + RunCommand($"cat-file -s {sha}:\"{path}\"", line => { + if (!long.TryParse(line, out size)) size = 0; + }); + return size; + } #endregion #region METHOD_GITFLOW diff --git a/SourceGit/Resources/Icons.xaml b/SourceGit/Resources/Icons.xaml index c6d444d1..3e0d3ba6 100644 --- a/SourceGit/Resources/Icons.xaml +++ b/SourceGit/Resources/Icons.xaml @@ -32,7 +32,8 @@ M958.656 320H960v639.936A64 64 0 0 1 896.128 1024H191.936A63.872 63.872 0 0 1 128 959.936V64.064A64 64 0 0 1 191.936 0H640v320.96h319.616L958.656 320zM320 544c0 17.152 14.464 32 32.192 32h383.552A32.384 32.384 0 0 0 768 544c0-17.152-14.464-32-32.256-32H352.192A32.448 32.448 0 0 0 320 544z m0 128c0 17.152 14.464 32 32.192 32h383.552a32.384 32.384 0 0 0 32.256-32c0-17.152-14.464-32-32.256-32H352.192a32.448 32.448 0 0 0-32.192 32z m0 128c0 17.152 14.464 32 32.192 32h383.552a32.384 32.384 0 0 0 32.256-32c0-17.152-14.464-32-32.256-32H352.192a32.448 32.448 0 0 0-32.192 32z M854.2 306.6L611.3 72.9c-6-5.7-13.9-8.9-22.2-8.9H296c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h277l219 210.6V824c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8V329.6c0-8.7-3.5-17-9.8-23zM553.4 201.4c-6-6-14.1-9.4-22.6-9.4H192c-17.7 0-32 14.3-32 32v704c0 17.7 14.3 32 32 32h512c17.7 0 32-14.3 32-32V397.3c0-8.5-3.4-16.6-9.4-22.6L553.4 201.4zM568 753c0 3.8-3.4 7-7.5 7h-225c-4.1 0-7.5-3.2-7.5-7v-42c0-3.8 3.4-7 7.5-7h225c4.1 0 7.5 3.2 7.5 7v42z m0-220c0 3.8-3.4 7-7.5 7H476v84.9c0 3.9-3.1 7.1-7 7.1h-42c-3.8 0-7-3.2-7-7.1V540h-84.5c-4.1 0-7.5-3.2-7.5-7v-42c0-3.9 3.4-7 7.5-7H420v-84.9c0-3.9 3.2-7.1 7-7.1h42c3.9 0 7 3.2 7 7.1V484h84.5c4.1 0 7.5 3.1 7.5 7v42z M599.22969 424.769286 599.22969 657.383158 424.769286 831.844585 424.769286 424.769286 192.155415 192.155415 831.844585 192.155415Z - + M71.111111 1024V0h661.333333L952.888889 219.420444V1024H71.111111z m808.305778-731.420444l-220.444445-219.448889H144.583111V950.897778h734.833778V292.579556zM438.528 512h-220.444444V219.420444h220.444444V512z m-73.500444-219.420444H291.555556v146.289777h73.472v-146.289777z m0 512h73.500444v73.130666h-220.444444v-73.130666H291.555556v-146.289778H218.083556V585.102222h146.944v219.448889z m293.944888-365.710223h73.472V512H512v-73.130667h73.472v-146.289777H512V219.420444h146.972444v219.448889z m73.472 438.840889H512V585.130667h220.444444v292.579555z m-73.472-219.420444h-73.500444v146.289778h73.500444v-146.289778z + M1024 1024H0V0h1024v1024z m-64-64V320H320V256h640V64H64v896h192V64h64v896z M81.92 81.92v860.16h860.16V81.92H81.92z m802.304 57.856V322.56H139.776V139.776h744.448z m-744.448 240.64H322.56v503.808H139.776V380.416z m240.128 503.808V380.416h504.32v503.808H379.904z diff --git a/SourceGit/UI/CommitViewer.xaml.cs b/SourceGit/UI/CommitViewer.xaml.cs index 916bcfad..66bda1e6 100644 --- a/SourceGit/UI/CommitViewer.xaml.cs +++ b/SourceGit/UI/CommitViewer.xaml.cs @@ -4,7 +4,6 @@ using System.IO; 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.Navigation; @@ -197,7 +196,11 @@ namespace SourceGit.UI { start = "4b825dc642cb6eb9a060e54bf8d69288fbee4904"; } - diffViewer.Diff(repo, $"{start} {commit.SHA}", node.FilePath, node.OriginalPath); + diffViewer.Diff(repo, new DiffViewer.Option() { + RevisionRange = new string[] { start, commit.SHA }, + Path = node.FilePath, + OrgPath = node.OriginalPath + }); } private void ChangeListSelectionChanged(object sender, SelectionChangedEventArgs e) { @@ -211,7 +214,11 @@ namespace SourceGit.UI { start = "4b825dc642cb6eb9a060e54bf8d69288fbee4904"; } - diffViewer.Diff(repo, $"{start} {commit.SHA}", change.Path, change.OriginalPath); + diffViewer.Diff(repo, new DiffViewer.Option() { + RevisionRange = new string[] { start, commit.SHA }, + Path = change.Path, + OrgPath = change.OriginalPath + }); } private void ChangeListContextMenuOpening(object sender, ContextMenuEventArgs e) { diff --git a/SourceGit/UI/DiffViewer.xaml b/SourceGit/UI/DiffViewer.xaml index e029ae3d..ec73ec6d 100644 --- a/SourceGit/UI/DiffViewer.xaml +++ b/SourceGit/UI/DiffViewer.xaml @@ -128,6 +128,29 @@ + + + + + diff --git a/SourceGit/UI/DiffViewer.xaml.cs b/SourceGit/UI/DiffViewer.xaml.cs index b54d40b1..c29b936c 100644 --- a/SourceGit/UI/DiffViewer.xaml.cs +++ b/SourceGit/UI/DiffViewer.xaml.cs @@ -15,6 +15,16 @@ namespace SourceGit.UI { public partial class DiffViewer : UserControl { private double minWidth = 0; + /// + /// Diff options. + /// + public class Option { + public string[] RevisionRange = new string[] { }; + public string Path = ""; + public string OrgPath = null; + public string ExtraArgs = ""; + } + /// /// Constructor /// @@ -28,26 +38,33 @@ namespace SourceGit.UI { /// public void Reset() { mask.Visibility = Visibility.Visible; + sizer.Visibility = Visibility.Collapsed; } /// /// Diff with options. /// /// - /// - /// - /// - public void Diff(Git.Repository repo, string options, string path, string orgPath = null) { - SetTitle(path, orgPath); + /// + public void Diff(Git.Repository repo, Option opts) { + SetTitle(opts.Path, opts.OrgPath); loading.Visibility = Visibility.Visible; + sizer.Visibility = Visibility.Collapsed; + Task.Run(() => { - var args = $"{options} -- "; - if (!string.IsNullOrEmpty(orgPath)) args += $"{orgPath} "; - args += $"\"{path}\""; + var args = $"{opts.ExtraArgs} "; + if (opts.RevisionRange.Length > 0) args += $"{opts.RevisionRange[0]} "; + if (opts.RevisionRange.Length > 1) args += $"{opts.RevisionRange[1]} -- "; + if (!string.IsNullOrEmpty(opts.OrgPath)) args += $"\"{opts.OrgPath}\" "; + args += $"\"{opts.Path}\""; var rs = Git.Diff.Run(repo, args); - SetData(rs); + if (rs.IsBinary) { + SetSizeChangeData(Git.Diff.GetSizeChange(repo, opts.RevisionRange, opts.Path, opts.OrgPath)); + } else { + SetData(rs); + } }); } @@ -67,6 +84,20 @@ namespace SourceGit.UI { } } + /// + /// Show size changes. + /// + /// + private void SetSizeChangeData(Git.Diff.BinaryChange bc) { + Dispatcher.Invoke(() => { + loading.Visibility = Visibility.Collapsed; + mask.Visibility = Visibility.Collapsed; + sizer.Visibility = Visibility.Visible; + txtNewSize.Content = $"{bc.Size} Bytes"; + txtOldSize.Content = $"{bc.PreSize} Bytes"; + }); + } + /// /// Show diff content. /// @@ -175,7 +206,7 @@ namespace SourceGit.UI { break; } } - #endregion + #endregion #region EVENTS /// diff --git a/SourceGit/UI/FileHistories.xaml.cs b/SourceGit/UI/FileHistories.xaml.cs index 22ecb8b1..5f72b4a2 100644 --- a/SourceGit/UI/FileHistories.xaml.cs +++ b/SourceGit/UI/FileHistories.xaml.cs @@ -102,7 +102,10 @@ namespace SourceGit.UI { var start = $"{commit.SHA}^"; if (commit.Parents.Count == 0) start = "4b825dc642cb6eb9a060e54bf8d69288fbee4904"; - diff.Diff(repo, $"{start} {commit.SHA}", file); + diff.Diff(repo, new DiffViewer.Option() { + RevisionRange = new string[] { start, commit.SHA }, + Path = file + }); } /// diff --git a/SourceGit/UI/Stashes.xaml.cs b/SourceGit/UI/Stashes.xaml.cs index 7051fafe..79cfa182 100644 --- a/SourceGit/UI/Stashes.xaml.cs +++ b/SourceGit/UI/Stashes.xaml.cs @@ -82,7 +82,11 @@ namespace SourceGit.UI { var change = e.AddedItems[0] as Git.Change; if (change == null) return; - diff.Diff(repo, $"{selectedStash}^ {selectedStash}", change.Path, change.OriginalPath); + diff.Diff(repo, new DiffViewer.Option() { + RevisionRange = new string[] { $"{selectedStash}^", selectedStash }, + Path = change.Path, + OrgPath = change.OriginalPath + }); } /// diff --git a/SourceGit/UI/WorkingCopy.xaml.cs b/SourceGit/UI/WorkingCopy.xaml.cs index 19201cac..1bd1a9f5 100644 --- a/SourceGit/UI/WorkingCopy.xaml.cs +++ b/SourceGit/UI/WorkingCopy.xaml.cs @@ -133,15 +133,18 @@ namespace SourceGit.UI { return; } + DiffViewer.Option opt; switch (node.Change.WorkTree) { case Git.Change.Status.Added: case Git.Change.Status.Untracked: - diffViewer.Diff(Repo, "--no-index", node.FilePath, "/dev/null"); + opt = new DiffViewer.Option() { ExtraArgs = "--no-index", Path = node.FilePath, OrgPath = "/dev/null" }; break; default: - diffViewer.Diff(Repo, "", node.FilePath, node.Change.OriginalPath); + opt = new DiffViewer.Option() { Path = node.FilePath, OrgPath = node.Change.OriginalPath }; break; } + + diffViewer.Diff(Repo, opt); } private void UnstagedListSelectionChanged(object sender, SelectionChangedEventArgs e) { @@ -161,15 +164,18 @@ namespace SourceGit.UI { return; } + DiffViewer.Option opt; switch (change.WorkTree) { case Git.Change.Status.Added: case Git.Change.Status.Untracked: - diffViewer.Diff(Repo, "--no-index", change.Path, "/dev/null"); + opt = new DiffViewer.Option() { ExtraArgs = "--no-index", Path = change.Path, OrgPath = "/dev/null" }; break; default: - diffViewer.Diff(Repo, "", change.Path, change.OriginalPath); + opt = new DiffViewer.Option() { Path = change.Path, OrgPath = change.OriginalPath }; break; } + + diffViewer.Diff(Repo, opt); } private void SaveAsPatchFromUnstagedChanges(string path, List changes) { @@ -507,7 +513,11 @@ namespace SourceGit.UI { if (!node.IsFile) return; mergePanel.Visibility = Visibility.Collapsed; - diffViewer.Diff(Repo, "--cached", node.FilePath, node.Change.OriginalPath); + diffViewer.Diff(Repo, new DiffViewer.Option() { + ExtraArgs = "--cached", + Path = node.FilePath, + OrgPath = node.Change.OriginalPath + }); e.Handled = true; } @@ -524,7 +534,11 @@ namespace SourceGit.UI { var change = selected[0] as Git.Change; mergePanel.Visibility = Visibility.Collapsed; - diffViewer.Diff(Repo, "--cached", change.Path, change.OriginalPath); + diffViewer.Diff(Repo, new DiffViewer.Option() { + ExtraArgs = "--cached", + Path = change.Path, + OrgPath = change.OriginalPath + }); e.Handled = true; }