mirror of
https://github.com/sourcegit-scm/sourcegit.git
synced 2024-12-24 20:57:19 -08:00
Rewrite diff viewer
This commit is contained in:
parent
dbd7a13705
commit
04ca0a9236
8 changed files with 2336 additions and 2200 deletions
233
SourceGit/Git/Diff.cs
Normal file
233
SourceGit/Git/Diff.cs
Normal file
|
@ -0,0 +1,233 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
namespace SourceGit.Git {
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Diff helper.
|
||||||
|
/// </summary>
|
||||||
|
public class Diff {
|
||||||
|
private static readonly Regex REG_INDICATOR = new Regex(@"^@@ \-(\d+),?\d* \+(\d+),?\d* @@", RegexOptions.None);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Line mode.
|
||||||
|
/// </summary>
|
||||||
|
public enum LineMode {
|
||||||
|
Normal,
|
||||||
|
Indicator,
|
||||||
|
Empty,
|
||||||
|
Added,
|
||||||
|
Deleted,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Side
|
||||||
|
/// </summary>
|
||||||
|
public enum Side {
|
||||||
|
Left,
|
||||||
|
Right,
|
||||||
|
Both,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Block
|
||||||
|
/// </summary>
|
||||||
|
public class Block {
|
||||||
|
public Side Side = Side.Both;
|
||||||
|
public LineMode Mode = LineMode.Normal;
|
||||||
|
public int LeftStart = 0;
|
||||||
|
public int RightStart = 0;
|
||||||
|
public int Count = 0;
|
||||||
|
public StringBuilder Builder = new StringBuilder();
|
||||||
|
|
||||||
|
public bool IsLeftDelete => Side == Side.Left && Mode == LineMode.Deleted;
|
||||||
|
public bool IsRightAdded => Side == Side.Right && Mode == LineMode.Added;
|
||||||
|
public bool IsBothSideNormal => Side == Side.Both && Mode == LineMode.Normal;
|
||||||
|
public bool CanShowNumber => Mode != LineMode.Indicator && Mode != LineMode.Empty;
|
||||||
|
|
||||||
|
public void Append(string data) {
|
||||||
|
if (Count > 0) Builder.AppendLine();
|
||||||
|
Builder.Append(data);
|
||||||
|
Count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Diff result.
|
||||||
|
/// </summary>
|
||||||
|
public class Result {
|
||||||
|
public bool IsValid = false;
|
||||||
|
public bool IsBinary = false;
|
||||||
|
public List<Block> Blocks = new List<Block>();
|
||||||
|
public int LeftLineCount = 0;
|
||||||
|
public int RightLineCount = 0;
|
||||||
|
|
||||||
|
public void SetBinary() {
|
||||||
|
IsValid = true;
|
||||||
|
IsBinary = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(Block b) {
|
||||||
|
if (b.Count == 0) return;
|
||||||
|
|
||||||
|
switch (b.Side) {
|
||||||
|
case Side.Left:
|
||||||
|
LeftLineCount += b.Count;
|
||||||
|
break;
|
||||||
|
case Side.Right:
|
||||||
|
RightLineCount += b.Count;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LeftLineCount += b.Count;
|
||||||
|
RightLineCount += b.Count;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Blocks.Add(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Fit() {
|
||||||
|
if (LeftLineCount > RightLineCount) {
|
||||||
|
var b = new Block();
|
||||||
|
b.Side = Side.Right;
|
||||||
|
b.Mode = LineMode.Empty;
|
||||||
|
|
||||||
|
var delta = LeftLineCount - RightLineCount;
|
||||||
|
for (int i = 0; i < delta; i++) b.Append("");
|
||||||
|
|
||||||
|
Add(b);
|
||||||
|
} else if (LeftLineCount < RightLineCount) {
|
||||||
|
var b = new Block();
|
||||||
|
b.Side = Side.Left;
|
||||||
|
b.Mode = LineMode.Empty;
|
||||||
|
|
||||||
|
var delta = RightLineCount - LeftLineCount;
|
||||||
|
for (int i = 0; i < delta; i++) b.Append("");
|
||||||
|
|
||||||
|
Add(b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Run diff process.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="repo"></param>
|
||||||
|
/// <param name="args"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static Result Run(Repository repo, string args) {
|
||||||
|
var rs = new Result();
|
||||||
|
var current = new Block();
|
||||||
|
var left = 0;
|
||||||
|
var right = 0;
|
||||||
|
|
||||||
|
repo.RunCommand($"diff --ignore-cr-at-eol {args}", line => {
|
||||||
|
if (rs.IsBinary) return;
|
||||||
|
|
||||||
|
if (!rs.IsValid) {
|
||||||
|
var match = REG_INDICATOR.Match(line);
|
||||||
|
if (!match.Success) {
|
||||||
|
if (line.StartsWith("Binary ")) rs.SetBinary();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
rs.IsValid = true;
|
||||||
|
left = int.Parse(match.Groups[1].Value);
|
||||||
|
right = int.Parse(match.Groups[2].Value);
|
||||||
|
current.Mode = LineMode.Indicator;
|
||||||
|
current.Append(line);
|
||||||
|
} else {
|
||||||
|
if (line[0] == '-') {
|
||||||
|
if (current.IsLeftDelete) {
|
||||||
|
current.Append(line.Substring(1));
|
||||||
|
} else {
|
||||||
|
rs.Add(current);
|
||||||
|
|
||||||
|
current = new Block();
|
||||||
|
current.Side = Side.Left;
|
||||||
|
current.Mode = LineMode.Deleted;
|
||||||
|
current.LeftStart = left;
|
||||||
|
current.Append(line.Substring(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
left++;
|
||||||
|
} else if (line[0] == '+') {
|
||||||
|
if (current.IsRightAdded) {
|
||||||
|
current.Append(line.Substring(1));
|
||||||
|
} else {
|
||||||
|
rs.Add(current);
|
||||||
|
|
||||||
|
current = new Block();
|
||||||
|
current.Side = Side.Right;
|
||||||
|
current.Mode = LineMode.Added;
|
||||||
|
current.RightStart = right;
|
||||||
|
current.Append(line.Substring(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
right++;
|
||||||
|
} else if (line[0] == '\\') {
|
||||||
|
var tmp = new Block();
|
||||||
|
tmp.Side = current.Side;
|
||||||
|
tmp.Mode = LineMode.Indicator;
|
||||||
|
tmp.Append(line.Substring(1));
|
||||||
|
|
||||||
|
rs.Add(current);
|
||||||
|
rs.Add(tmp);
|
||||||
|
rs.Fit();
|
||||||
|
|
||||||
|
current = new Block();
|
||||||
|
current.LeftStart = left;
|
||||||
|
current.RightStart = right;
|
||||||
|
} else {
|
||||||
|
var match = REG_INDICATOR.Match(line);
|
||||||
|
if (match.Success) {
|
||||||
|
rs.Add(current);
|
||||||
|
rs.Fit();
|
||||||
|
|
||||||
|
left = int.Parse(match.Groups[1].Value);
|
||||||
|
right = int.Parse(match.Groups[2].Value);
|
||||||
|
|
||||||
|
current = new Block();
|
||||||
|
current.Mode = LineMode.Indicator;
|
||||||
|
current.Append(line);
|
||||||
|
} else {
|
||||||
|
if (current.IsBothSideNormal) {
|
||||||
|
current.Append(line.Substring(1));
|
||||||
|
} else {
|
||||||
|
rs.Add(current);
|
||||||
|
rs.Fit();
|
||||||
|
|
||||||
|
current = new Block();
|
||||||
|
current.LeftStart = left;
|
||||||
|
current.RightStart = right;
|
||||||
|
current.Append(line.Substring(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
left++;
|
||||||
|
right++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
rs.Add(current);
|
||||||
|
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);
|
||||||
|
} else if (rs.Blocks.Count == 0) {
|
||||||
|
var b = new Block();
|
||||||
|
b.Mode = LineMode.Indicator;
|
||||||
|
b.Append("NO CHANGES OR ONLY WHITESPACE CHANGES!!!");
|
||||||
|
rs.Blocks.Add(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -827,26 +827,6 @@ namespace SourceGit.Git {
|
||||||
return stashes;
|
return stashes;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Diff
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="startRevision"></param>
|
|
||||||
/// <param name="endRevision"></param>
|
|
||||||
/// <param name="file"></param>
|
|
||||||
/// <param name="orgFile"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public List<string> Diff(string startRevision, string endRevision, string file, string orgFile = null) {
|
|
||||||
var args = $"diff --ignore-cr-at-eol {startRevision} {endRevision} -- ";
|
|
||||||
if (!string.IsNullOrEmpty(orgFile)) args += $"\"{orgFile}\" ";
|
|
||||||
args += $"\"{file}\"";
|
|
||||||
|
|
||||||
var data = new List<string>();
|
|
||||||
var errs = RunCommand(args, line => data.Add(line));
|
|
||||||
|
|
||||||
if (errs != null) App.RaiseError(errs);
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Blame file.
|
/// Blame file.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -186,7 +186,7 @@ namespace SourceGit.UI {
|
||||||
Task.Run(() => LayoutChanges());
|
Task.Run(() => LayoutChanges());
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void ChangeTreeItemSelected(object sender, RoutedPropertyChangedEventArgs<object> e) {
|
private void ChangeTreeItemSelected(object sender, RoutedPropertyChangedEventArgs<object> e) {
|
||||||
diffViewer.Reset();
|
diffViewer.Reset();
|
||||||
|
|
||||||
var node = e.NewValue as Node;
|
var node = e.NewValue as Node;
|
||||||
|
@ -197,16 +197,10 @@ namespace SourceGit.UI {
|
||||||
start = "4b825dc642cb6eb9a060e54bf8d69288fbee4904";
|
start = "4b825dc642cb6eb9a060e54bf8d69288fbee4904";
|
||||||
}
|
}
|
||||||
|
|
||||||
List<string> data = new List<string>();
|
diffViewer.Diff(repo, $"{start} {commit.SHA}", node.FilePath, node.OriginalPath);
|
||||||
|
|
||||||
await Task.Run(() => {
|
|
||||||
data = repo.Diff(start, commit.SHA, node.FilePath, node.OriginalPath);
|
|
||||||
});
|
|
||||||
|
|
||||||
diffViewer.SetData(data, node.FilePath, node.OriginalPath);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void ChangeListSelectionChanged(object sender, SelectionChangedEventArgs e) {
|
private void ChangeListSelectionChanged(object sender, SelectionChangedEventArgs e) {
|
||||||
if (e.AddedItems.Count != 1) return;
|
if (e.AddedItems.Count != 1) return;
|
||||||
|
|
||||||
var change = e.AddedItems[0] as Git.Change;
|
var change = e.AddedItems[0] as Git.Change;
|
||||||
|
@ -217,13 +211,7 @@ namespace SourceGit.UI {
|
||||||
start = "4b825dc642cb6eb9a060e54bf8d69288fbee4904";
|
start = "4b825dc642cb6eb9a060e54bf8d69288fbee4904";
|
||||||
}
|
}
|
||||||
|
|
||||||
List<string> data = new List<string>();
|
diffViewer.Diff(repo, $"{start} {commit.SHA}", change.Path, change.OriginalPath);
|
||||||
|
|
||||||
await Task.Run(() => {
|
|
||||||
data = repo.Diff(start, commit.SHA, change.Path, change.OriginalPath);
|
|
||||||
});
|
|
||||||
|
|
||||||
diffViewer.SetData(data, change.Path, change.OriginalPath);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ChangeListContextMenuOpening(object sender, ContextMenuEventArgs e) {
|
private void ChangeListContextMenuOpening(object sender, ContextMenuEventArgs e) {
|
||||||
|
|
|
@ -134,6 +134,10 @@
|
||||||
<Label Margin="0,8,0,0" Content="SELECT FILE TO VIEW CHANGES" FontSize="18" FontWeight="UltraBold" HorizontalAlignment="Center"/>
|
<Label Margin="0,8,0,0" Content="SELECT FILE TO VIEW CHANGES" FontSize="18" FontWeight="UltraBold" HorizontalAlignment="Center"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Border>
|
</Border>
|
||||||
|
|
||||||
|
<Border x:Name="loading" Grid.RowSpan="2" Background="{StaticResource Brush.BG3}" Visibility="Collapsed">
|
||||||
|
<Label Content="LOADING ..." FontSize="18" FontWeight="UltraBold" HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="{StaticResource Brush.FG2}"/>
|
||||||
|
</Border>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Border>
|
</Border>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Text.RegularExpressions;
|
using System.Threading.Tasks;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using System.Windows.Documents;
|
using System.Windows.Documents;
|
||||||
|
@ -16,17 +15,6 @@ namespace SourceGit.UI {
|
||||||
public partial class DiffViewer : UserControl {
|
public partial class DiffViewer : UserControl {
|
||||||
private double minWidth = 0;
|
private double minWidth = 0;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Line mode.
|
|
||||||
/// </summary>
|
|
||||||
public enum LineMode {
|
|
||||||
Normal,
|
|
||||||
Indicator,
|
|
||||||
Empty,
|
|
||||||
Added,
|
|
||||||
Deleted,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Constructor
|
/// Constructor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -35,120 +23,6 @@ namespace SourceGit.UI {
|
||||||
Reset();
|
Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="lines"></param>
|
|
||||||
/// <param name="file"></param>
|
|
||||||
/// <param name="orgFile"></param>
|
|
||||||
public void SetData(List<string> lines, string file, string orgFile = null) {
|
|
||||||
minWidth = Math.Max(leftText.ActualWidth, rightText.ActualWidth) - 16;
|
|
||||||
|
|
||||||
fileName.Text = file;
|
|
||||||
if (!string.IsNullOrEmpty(orgFile)) {
|
|
||||||
orgFileNamePanel.Visibility = Visibility.Visible;
|
|
||||||
orgFileName.Text = orgFile;
|
|
||||||
} else {
|
|
||||||
orgFileNamePanel.Visibility = Visibility.Collapsed;
|
|
||||||
}
|
|
||||||
|
|
||||||
leftText.Document.Blocks.Clear();
|
|
||||||
rightText.Document.Blocks.Clear();
|
|
||||||
|
|
||||||
leftLineNumber.Text = "";
|
|
||||||
rightLineNumber.Text = "";
|
|
||||||
|
|
||||||
Regex regex = new Regex(@"^@@ \-(\d+),?\d* \+(\d+),?\d* @@", RegexOptions.None);
|
|
||||||
bool started = false;
|
|
||||||
|
|
||||||
List<Paragraph> leftData = new List<Paragraph>();
|
|
||||||
List<Paragraph> rightData = new List<Paragraph>();
|
|
||||||
List<string> leftNumbers = new List<string>();
|
|
||||||
List<string> rightNumbers = new List<string>();
|
|
||||||
|
|
||||||
int leftLine = 0;
|
|
||||||
int rightLine = 0;
|
|
||||||
bool bLastLeft = true;
|
|
||||||
|
|
||||||
foreach (var line in lines) {
|
|
||||||
if (!started) {
|
|
||||||
var match = regex.Match(line);
|
|
||||||
if (!match.Success) continue;
|
|
||||||
|
|
||||||
MakeParagraph(leftData, line, LineMode.Indicator);
|
|
||||||
MakeParagraph(rightData, line, LineMode.Indicator);
|
|
||||||
leftNumbers.Add("");
|
|
||||||
rightNumbers.Add("");
|
|
||||||
|
|
||||||
leftLine = int.Parse(match.Groups[1].Value);
|
|
||||||
rightLine = int.Parse(match.Groups[2].Value);
|
|
||||||
started = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (line[0] == '-') {
|
|
||||||
MakeParagraph(leftData, line.Substring(1), LineMode.Deleted);
|
|
||||||
leftNumbers.Add(leftLine.ToString());
|
|
||||||
leftLine++;
|
|
||||||
bLastLeft = true;
|
|
||||||
} else if (line[0] == '+') {
|
|
||||||
MakeParagraph(rightData, line.Substring(1), LineMode.Added);
|
|
||||||
rightNumbers.Add(rightLine.ToString());
|
|
||||||
rightLine++;
|
|
||||||
bLastLeft = false;
|
|
||||||
} else if (line[0] == '\\') {
|
|
||||||
if (bLastLeft) {
|
|
||||||
MakeParagraph(leftData, line.Substring(1), LineMode.Indicator);
|
|
||||||
leftNumbers.Add("");
|
|
||||||
} else {
|
|
||||||
MakeParagraph(rightData, line.Substring(1), LineMode.Indicator);
|
|
||||||
rightNumbers.Add("");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
FitBothSide(leftData, leftNumbers, rightData, rightNumbers);
|
|
||||||
bLastLeft = true;
|
|
||||||
|
|
||||||
var match = regex.Match(line);
|
|
||||||
if (match.Success) {
|
|
||||||
MakeParagraph(leftData, line, LineMode.Indicator);
|
|
||||||
MakeParagraph(rightData, line, LineMode.Indicator);
|
|
||||||
leftNumbers.Add("");
|
|
||||||
rightNumbers.Add("");
|
|
||||||
|
|
||||||
leftLine = int.Parse(match.Groups[1].Value);
|
|
||||||
rightLine = int.Parse(match.Groups[2].Value);
|
|
||||||
} else {
|
|
||||||
var data = line.Substring(1);
|
|
||||||
MakeParagraph(leftData, data, LineMode.Normal);
|
|
||||||
MakeParagraph(rightData, data, LineMode.Normal);
|
|
||||||
leftNumbers.Add(leftLine.ToString());
|
|
||||||
rightNumbers.Add(rightLine.ToString());
|
|
||||||
leftLine++;
|
|
||||||
rightLine++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FitBothSide(leftData, leftNumbers, rightData, rightNumbers);
|
|
||||||
|
|
||||||
if (leftData.Count == 0) {
|
|
||||||
MakeParagraph(leftData, "NOT SUPPORTED OR NO DATA", LineMode.Indicator);
|
|
||||||
MakeParagraph(rightData, "NOT SUPPORTED OR NO DATA", LineMode.Indicator);
|
|
||||||
leftNumbers.Add("");
|
|
||||||
rightNumbers.Add("");
|
|
||||||
}
|
|
||||||
|
|
||||||
leftLineNumber.Text = string.Join("\n", leftNumbers);
|
|
||||||
rightLineNumber.Text = string.Join("\n", rightNumbers);
|
|
||||||
leftText.Document.PageWidth = minWidth + 16;
|
|
||||||
rightText.Document.PageWidth = minWidth + 16;
|
|
||||||
leftText.Document.Blocks.AddRange(leftData);
|
|
||||||
rightText.Document.Blocks.AddRange(rightData);
|
|
||||||
leftText.ScrollToHome();
|
|
||||||
|
|
||||||
mask.Visibility = Visibility.Collapsed;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Reset data.
|
/// Reset data.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -156,13 +30,72 @@ namespace SourceGit.UI {
|
||||||
mask.Visibility = Visibility.Visible;
|
mask.Visibility = Visibility.Visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Diff with options.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="repo"></param>
|
||||||
|
/// <param name="options"></param>
|
||||||
|
/// <param name="path"></param>
|
||||||
|
/// <param name="orgPath"></param>
|
||||||
|
public void Diff(Git.Repository repo, string options, string path, string orgPath = null) {
|
||||||
|
SetTitle(path, orgPath);
|
||||||
|
Task.Run(() => {
|
||||||
|
var args = $"{options} -- ";
|
||||||
|
if (!string.IsNullOrEmpty(orgPath)) args += $"{orgPath} ";
|
||||||
|
args += $"\"{path}\"";
|
||||||
|
|
||||||
|
var rs = Git.Diff.Run(repo, args);
|
||||||
|
SetData(rs);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#region LAYOUT
|
||||||
|
/// <summary>
|
||||||
|
/// Show diff title
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="file"></param>
|
||||||
|
/// <param name="orgFile"></param>
|
||||||
|
private void SetTitle(string file, string orgFile) {
|
||||||
|
fileName.Text = file;
|
||||||
|
if (!string.IsNullOrEmpty(orgFile)) {
|
||||||
|
orgFileNamePanel.Visibility = Visibility.Visible;
|
||||||
|
orgFileName.Text = orgFile;
|
||||||
|
} else {
|
||||||
|
orgFileNamePanel.Visibility = Visibility.Collapsed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Show diff content.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="rs"></param>
|
||||||
|
private void SetData(Git.Diff.Result rs) {
|
||||||
|
Dispatcher.Invoke(() => {
|
||||||
|
loading.Visibility = Visibility.Collapsed;
|
||||||
|
mask.Visibility = Visibility.Collapsed;
|
||||||
|
|
||||||
|
minWidth = Math.Max(leftText.ActualWidth, rightText.ActualWidth) - 16;
|
||||||
|
|
||||||
|
leftLineNumber.Text = "";
|
||||||
|
rightLineNumber.Text = "";
|
||||||
|
leftText.Document.Blocks.Clear();
|
||||||
|
rightText.Document.Blocks.Clear();
|
||||||
|
|
||||||
|
foreach (var b in rs.Blocks) ShowBlock(b);
|
||||||
|
|
||||||
|
leftText.Document.PageWidth = minWidth + 16;
|
||||||
|
rightText.Document.PageWidth = minWidth + 16;
|
||||||
|
leftText.ScrollToHome();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Make paragraph.
|
/// Make paragraph.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="collection"></param>
|
/// <param name="b"></param>
|
||||||
/// <param name="content"></param>
|
private void ShowBlock(Git.Diff.Block b) {
|
||||||
/// <param name="mode"></param>
|
var content = b.Builder.ToString();
|
||||||
private void MakeParagraph(List<Paragraph> collection, string content, LineMode mode) {
|
|
||||||
Paragraph p = new Paragraph(new Run(content));
|
Paragraph p = new Paragraph(new Run(content));
|
||||||
p.Margin = new Thickness(0);
|
p.Margin = new Thickness(0);
|
||||||
p.Padding = new Thickness();
|
p.Padding = new Thickness();
|
||||||
|
@ -171,20 +104,20 @@ namespace SourceGit.UI {
|
||||||
p.Foreground = FindResource("Brush.FG") as SolidColorBrush;
|
p.Foreground = FindResource("Brush.FG") as SolidColorBrush;
|
||||||
p.FontStyle = FontStyles.Normal;
|
p.FontStyle = FontStyles.Normal;
|
||||||
|
|
||||||
switch (mode) {
|
switch (b.Mode) {
|
||||||
case LineMode.Normal:
|
case Git.Diff.LineMode.Normal:
|
||||||
break;
|
break;
|
||||||
case LineMode.Indicator:
|
case Git.Diff.LineMode.Indicator:
|
||||||
p.Foreground = Brushes.Gray;
|
p.Foreground = Brushes.Gray;
|
||||||
p.FontStyle = FontStyles.Italic;
|
p.FontStyle = FontStyles.Italic;
|
||||||
break;
|
break;
|
||||||
case LineMode.Empty:
|
case Git.Diff.LineMode.Empty:
|
||||||
p.Background = new SolidColorBrush(Color.FromArgb(40, 0, 0, 0));
|
p.Background = new SolidColorBrush(Color.FromArgb(40, 0, 0, 0));
|
||||||
break;
|
break;
|
||||||
case LineMode.Added:
|
case Git.Diff.LineMode.Added:
|
||||||
p.Background = new SolidColorBrush(Color.FromArgb(60, 0, 255, 0));
|
p.Background = new SolidColorBrush(Color.FromArgb(60, 0, 255, 0));
|
||||||
break;
|
break;
|
||||||
case LineMode.Deleted:
|
case Git.Diff.LineMode.Deleted:
|
||||||
p.Background = new SolidColorBrush(Color.FromArgb(60, 255, 0, 0));
|
p.Background = new SolidColorBrush(Color.FromArgb(60, 255, 0, 0));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -200,39 +133,49 @@ namespace SourceGit.UI {
|
||||||
TextFormattingMode.Ideal);
|
TextFormattingMode.Ideal);
|
||||||
|
|
||||||
if (minWidth < formatter.Width) minWidth = formatter.Width;
|
if (minWidth < formatter.Width) minWidth = formatter.Width;
|
||||||
collection.Add(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
switch (b.Side) {
|
||||||
/// Fit both side with empty lines.
|
case Git.Diff.Side.Left:
|
||||||
/// </summary>
|
leftText.Document.Blocks.Add(p);
|
||||||
/// <param name="left"></param>
|
for (int i = 0; i < b.Count; i++) {
|
||||||
/// <param name="leftNumbers"></param>
|
if (b.CanShowNumber) leftLineNumber.AppendText($"{i + b.LeftStart}\n");
|
||||||
/// <param name="right"></param>
|
else leftLineNumber.AppendText("\n");
|
||||||
/// <param name="rightNumbers"></param>
|
}
|
||||||
private void FitBothSide(List<Paragraph> left, List<string> leftNumbers, List<Paragraph> right, List<string> rightNumbers) {
|
break;
|
||||||
int leftCount = left.Count;
|
case Git.Diff.Side.Right:
|
||||||
int rightCount = right.Count;
|
rightText.Document.Blocks.Add(p);
|
||||||
int diff = 0;
|
for (int i = 0; i < b.Count; i++) {
|
||||||
List<Paragraph> fitContent = null;
|
if (b.CanShowNumber) rightLineNumber.AppendText($"{i + b.RightStart}\n");
|
||||||
List<string> fitNumber = null;
|
else rightLineNumber.AppendText("\n");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
leftText.Document.Blocks.Add(p);
|
||||||
|
|
||||||
if (leftCount > rightCount) {
|
var cp = new Paragraph(new Run(content));
|
||||||
diff = leftCount - rightCount;
|
cp.Margin = new Thickness(0);
|
||||||
fitContent = right;
|
cp.Padding = new Thickness();
|
||||||
fitNumber = rightNumbers;
|
cp.LineHeight = 1;
|
||||||
} else if (rightCount > leftCount) {
|
cp.Background = p.Background;
|
||||||
diff = rightCount - leftCount;
|
cp.Foreground = p.Foreground;
|
||||||
fitContent = left;
|
cp.FontStyle = p.FontStyle;
|
||||||
fitNumber = leftNumbers;
|
rightText.Document.Blocks.Add(cp);
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < diff; i++) {
|
for (int i = 0; i < b.Count; i++) {
|
||||||
MakeParagraph(fitContent, "", LineMode.Empty);
|
if (b.Mode != Git.Diff.LineMode.Indicator) {
|
||||||
fitNumber.Add("");
|
leftLineNumber.AppendText($"{i + b.LeftStart}\n");
|
||||||
|
rightLineNumber.AppendText($"{i + b.RightStart}\n");
|
||||||
|
} else {
|
||||||
|
leftLineNumber.AppendText("\n");
|
||||||
|
rightLineNumber.AppendText("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region EVENTS
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sync scroll both sides.
|
/// Sync scroll both sides.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -290,5 +233,6 @@ namespace SourceGit.UI {
|
||||||
rightText.Document.PageWidth = rightText.ActualWidth;
|
rightText.Document.PageWidth = rightText.ActualWidth;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,18 +95,14 @@ namespace SourceGit.UI {
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="sender"></param>
|
/// <param name="sender"></param>
|
||||||
/// <param name="e"></param>
|
/// <param name="e"></param>
|
||||||
private async void CommitSelectionChanged(object sender, SelectionChangedEventArgs e) {
|
private void CommitSelectionChanged(object sender, SelectionChangedEventArgs e) {
|
||||||
if (e.AddedItems.Count != 1) return;
|
if (e.AddedItems.Count != 1) return;
|
||||||
|
|
||||||
var commit = e.AddedItems[0] as Git.Commit;
|
var commit = e.AddedItems[0] as Git.Commit;
|
||||||
var start = $"{commit.SHA}^";
|
var start = $"{commit.SHA}^";
|
||||||
if (commit.Parents.Count == 0) start = "4b825dc642cb6eb9a060e54bf8d69288fbee4904";
|
if (commit.Parents.Count == 0) start = "4b825dc642cb6eb9a060e54bf8d69288fbee4904";
|
||||||
|
|
||||||
List<string> data = new List<string>();
|
diff.Diff(repo, $"{start} {commit.SHA}", file);
|
||||||
await Task.Run(() => {
|
|
||||||
data = repo.Diff(start, commit.SHA, file);
|
|
||||||
});
|
|
||||||
diff.SetData(data, $"{file} @ {commit.ShortSHA}");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -82,8 +82,7 @@ namespace SourceGit.UI {
|
||||||
var change = e.AddedItems[0] as Git.Change;
|
var change = e.AddedItems[0] as Git.Change;
|
||||||
if (change == null) return;
|
if (change == null) return;
|
||||||
|
|
||||||
var data = repo.Diff($"{selectedStash}^", selectedStash, change.Path, change.OriginalPath);
|
diff.Diff(repo, $"{selectedStash}^ {selectedStash}", change.Path, change.OriginalPath);
|
||||||
diff.SetData(data, change.Path, change.OriginalPath);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -133,18 +133,15 @@ namespace SourceGit.UI {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<string> data;
|
|
||||||
switch (node.Change.WorkTree) {
|
switch (node.Change.WorkTree) {
|
||||||
case Git.Change.Status.Added:
|
case Git.Change.Status.Added:
|
||||||
case Git.Change.Status.Untracked:
|
case Git.Change.Status.Untracked:
|
||||||
data = Repo.Diff("", "--no-index", node.FilePath, "/dev/null");
|
diffViewer.Diff(Repo, "--no-index", node.FilePath, "/dev/null");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
data = Repo.Diff("", "", node.FilePath, node.Change.OriginalPath);
|
diffViewer.Diff(Repo, "", node.FilePath, node.Change.OriginalPath);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
diffViewer.SetData(data, node.FilePath, node.Change.OriginalPath);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UnstagedListSelectionChanged(object sender, SelectionChangedEventArgs e) {
|
private void UnstagedListSelectionChanged(object sender, SelectionChangedEventArgs e) {
|
||||||
|
@ -164,18 +161,15 @@ namespace SourceGit.UI {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<string> data;
|
|
||||||
switch (change.WorkTree) {
|
switch (change.WorkTree) {
|
||||||
case Git.Change.Status.Added:
|
case Git.Change.Status.Added:
|
||||||
case Git.Change.Status.Untracked:
|
case Git.Change.Status.Untracked:
|
||||||
data = Repo.Diff("", "--no-index", change.Path, "/dev/null");
|
diffViewer.Diff(Repo, "--no-index", change.Path, "/dev/null");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
data = Repo.Diff("", "", change.Path, change.OriginalPath);
|
diffViewer.Diff(Repo, "", change.Path, change.OriginalPath);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
diffViewer.SetData(data, change.Path, change.OriginalPath);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SaveAsPatchFromUnstagedChanges(string path, List<Git.Change> changes) {
|
private void SaveAsPatchFromUnstagedChanges(string path, List<Git.Change> changes) {
|
||||||
|
@ -513,8 +507,7 @@ namespace SourceGit.UI {
|
||||||
if (!node.IsFile) return;
|
if (!node.IsFile) return;
|
||||||
|
|
||||||
mergePanel.Visibility = Visibility.Collapsed;
|
mergePanel.Visibility = Visibility.Collapsed;
|
||||||
List<string> data = Repo.Diff("", "--cached", node.FilePath, node.Change.OriginalPath);
|
diffViewer.Diff(Repo, "--cached", node.FilePath, node.Change.OriginalPath);
|
||||||
diffViewer.SetData(data, node.FilePath, node.Change.OriginalPath);
|
|
||||||
e.Handled = true;
|
e.Handled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -531,8 +524,7 @@ namespace SourceGit.UI {
|
||||||
|
|
||||||
var change = selected[0] as Git.Change;
|
var change = selected[0] as Git.Change;
|
||||||
mergePanel.Visibility = Visibility.Collapsed;
|
mergePanel.Visibility = Visibility.Collapsed;
|
||||||
List<string> data = Repo.Diff("", "--cached", change.Path, change.OriginalPath);
|
diffViewer.Diff(Repo, "--cached", change.Path, change.OriginalPath);
|
||||||
diffViewer.SetData(data, change.Path, change.OriginalPath);
|
|
||||||
e.Handled = true;
|
e.Handled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -667,7 +659,7 @@ namespace SourceGit.UI {
|
||||||
private async void Unstage(object sender, RoutedEventArgs e) {
|
private async void Unstage(object sender, RoutedEventArgs e) {
|
||||||
var files = new List<string>();
|
var files = new List<string>();
|
||||||
|
|
||||||
if (App.Preference.UIUseListInUnstaged) {
|
if (App.Preference.UIUseListInStaged) {
|
||||||
var selected = stageList.SelectedItems;
|
var selected = stageList.SelectedItems;
|
||||||
foreach (var one in selected) {
|
foreach (var one in selected) {
|
||||||
var node = one as Git.Change;
|
var node = one as Git.Change;
|
||||||
|
|
Loading…
Reference in a new issue