mirror of
https://github.com/sourcegit-scm/sourcegit
synced 2025-06-17 08:24:59 +00:00
parent
0ea4021a64
commit
ee4d8a6a0e
4 changed files with 182 additions and 130 deletions
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
|
@ -10,10 +11,25 @@ namespace SourceGit.ViewModels
|
||||||
{
|
{
|
||||||
public class Blame : ObservableObject
|
public class Blame : ObservableObject
|
||||||
{
|
{
|
||||||
public string Title
|
public string FilePath
|
||||||
{
|
{
|
||||||
get => _title;
|
get;
|
||||||
private set => SetProperty(ref _title, value);
|
}
|
||||||
|
|
||||||
|
public Models.Commit Revision
|
||||||
|
{
|
||||||
|
get => _revision;
|
||||||
|
private set => SetProperty(ref _revision, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Models.BlameData Data
|
||||||
|
{
|
||||||
|
get => _data;
|
||||||
|
private set
|
||||||
|
{
|
||||||
|
if (SetProperty(ref _data, value))
|
||||||
|
OnPropertyChanged(nameof(IsBinary));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsBinary
|
public bool IsBinary
|
||||||
|
@ -21,92 +37,27 @@ namespace SourceGit.ViewModels
|
||||||
get => _data != null && _data.IsBinary;
|
get => _data != null && _data.IsBinary;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool CanMoveBack
|
public bool CanBack
|
||||||
{
|
{
|
||||||
get => _shaHistoryIndex > 0 && _shaHistory.Count > 1;
|
get => _navigationActiveIndex > 0;
|
||||||
}
|
|
||||||
public bool CanMoveForward
|
|
||||||
{
|
|
||||||
get => _shaHistoryIndex < _shaHistory.Count - 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Models.BlameData Data
|
public bool CanForward
|
||||||
{
|
{
|
||||||
get => _data;
|
get => _navigationActiveIndex < _navigationHistory.Count - 1;
|
||||||
private set => SetProperty(ref _data, value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Blame(string repo, string file, string revision)
|
public Blame(string repo, string file, Models.Commit commit)
|
||||||
{
|
{
|
||||||
|
var sha = commit.SHA.Substring(0, 10);
|
||||||
|
|
||||||
|
FilePath = file;
|
||||||
|
Revision = commit;
|
||||||
|
|
||||||
_repo = repo;
|
_repo = repo;
|
||||||
_file = file;
|
_navigationHistory.Add(sha);
|
||||||
|
_commits.Add(sha, commit);
|
||||||
SetBlameData($"{revision.AsSpan(0, 10)}", true);
|
SetBlameData(sha);
|
||||||
}
|
|
||||||
|
|
||||||
private void SetBlameData(string commitSHA, bool resetHistoryForward)
|
|
||||||
{
|
|
||||||
Title = $"{_file} @ {commitSHA}";
|
|
||||||
|
|
||||||
Task.Run(() =>
|
|
||||||
{
|
|
||||||
var result = new Commands.Blame(_repo, _file, commitSHA).Result();
|
|
||||||
Dispatcher.UIThread.Invoke(() =>
|
|
||||||
{
|
|
||||||
Data = result;
|
|
||||||
OnPropertyChanged(nameof(IsBinary));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
if (resetHistoryForward)
|
|
||||||
{
|
|
||||||
if (_shaHistoryIndex < _shaHistory.Count - 1)
|
|
||||||
_shaHistory.RemoveRange(_shaHistoryIndex + 1, _shaHistory.Count - _shaHistoryIndex - 1);
|
|
||||||
|
|
||||||
if (_shaHistory.Count == 0 || _shaHistory[_shaHistoryIndex] != commitSHA)
|
|
||||||
{
|
|
||||||
_shaHistory.Add(commitSHA);
|
|
||||||
_shaHistoryIndex = _shaHistory.Count - 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
OnPropertyChanged(nameof(CanMoveBack));
|
|
||||||
OnPropertyChanged(nameof(CanMoveForward));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Back()
|
|
||||||
{
|
|
||||||
--_shaHistoryIndex;
|
|
||||||
if (_shaHistoryIndex < 0)
|
|
||||||
_shaHistoryIndex = 0;
|
|
||||||
|
|
||||||
NavigateToCommit(_shaHistory[_shaHistoryIndex], false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Forward()
|
|
||||||
{
|
|
||||||
++_shaHistoryIndex;
|
|
||||||
if (_shaHistoryIndex >= _shaHistory.Count)
|
|
||||||
_shaHistoryIndex = _shaHistory.Count - 1;
|
|
||||||
|
|
||||||
NavigateToCommit(_shaHistory[_shaHistoryIndex], false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void NavigateToCommit(string commitSHA, bool resetHistoryForward)
|
|
||||||
{
|
|
||||||
var launcher = App.GetLauncher();
|
|
||||||
if (launcher == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
foreach (var page in launcher.Pages)
|
|
||||||
{
|
|
||||||
if (page.Data is Repository repo && repo.FullPath.Equals(_repo))
|
|
||||||
{
|
|
||||||
repo.NavigateToCommit(commitSHA);
|
|
||||||
SetBlameData(commitSHA, resetHistoryForward);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetCommitMessage(string sha)
|
public string GetCommitMessage(string sha)
|
||||||
|
@ -119,12 +70,102 @@ namespace SourceGit.ViewModels
|
||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Back()
|
||||||
|
{
|
||||||
|
if (_navigationActiveIndex <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_navigationActiveIndex--;
|
||||||
|
OnPropertyChanged(nameof(CanBack));
|
||||||
|
OnPropertyChanged(nameof(CanForward));
|
||||||
|
NavigateToCommit(_navigationHistory[_navigationActiveIndex]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Forward()
|
||||||
|
{
|
||||||
|
if (_navigationActiveIndex >= _navigationHistory.Count - 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_navigationActiveIndex++;
|
||||||
|
OnPropertyChanged(nameof(CanBack));
|
||||||
|
OnPropertyChanged(nameof(CanForward));
|
||||||
|
NavigateToCommit(_navigationHistory[_navigationActiveIndex]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void NavigateToCommit(string commitSHA)
|
||||||
|
{
|
||||||
|
if (!_navigationHistory[_navigationActiveIndex].Equals(commitSHA, StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
_navigationHistory.Add(commitSHA);
|
||||||
|
_navigationActiveIndex = _navigationHistory.Count - 1;
|
||||||
|
OnPropertyChanged(nameof(CanBack));
|
||||||
|
OnPropertyChanged(nameof(CanForward));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Revision.SHA.StartsWith(commitSHA, StringComparison.Ordinal))
|
||||||
|
SetBlameData(commitSHA);
|
||||||
|
|
||||||
|
if (App.GetLauncher() is { Pages: { } pages })
|
||||||
|
{
|
||||||
|
foreach (var page in pages)
|
||||||
|
{
|
||||||
|
if (page.Data is Repository repo && repo.FullPath.Equals(_repo))
|
||||||
|
{
|
||||||
|
repo.NavigateToCommit(commitSHA);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetBlameData(string commitSHA)
|
||||||
|
{
|
||||||
|
if (_cancellationSource is { IsCancellationRequested: false })
|
||||||
|
_cancellationSource.Cancel();
|
||||||
|
|
||||||
|
_cancellationSource = new CancellationTokenSource();
|
||||||
|
var token = _cancellationSource.Token;
|
||||||
|
|
||||||
|
if (_commits.TryGetValue(commitSHA, out var c))
|
||||||
|
{
|
||||||
|
Revision = c;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Task.Run(() =>
|
||||||
|
{
|
||||||
|
var result = new Commands.QuerySingleCommit(_repo, commitSHA).Result();
|
||||||
|
|
||||||
|
Dispatcher.UIThread.Invoke(() =>
|
||||||
|
{
|
||||||
|
if (!token.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
_commits.Add(commitSHA, result);
|
||||||
|
Revision = result ?? new Models.Commit() { SHA = commitSHA };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, token);
|
||||||
|
}
|
||||||
|
|
||||||
|
Task.Run(() =>
|
||||||
|
{
|
||||||
|
var result = new Commands.Blame(_repo, FilePath, commitSHA).Result();
|
||||||
|
|
||||||
|
Dispatcher.UIThread.Invoke(() =>
|
||||||
|
{
|
||||||
|
if (!token.IsCancellationRequested)
|
||||||
|
Data = result;
|
||||||
|
});
|
||||||
|
}, token);
|
||||||
|
}
|
||||||
|
|
||||||
private string _repo;
|
private string _repo;
|
||||||
private string _file;
|
private Models.Commit _revision;
|
||||||
private string _title;
|
private CancellationTokenSource _cancellationSource = null;
|
||||||
private int _shaHistoryIndex = 0;
|
private int _navigationActiveIndex = 0;
|
||||||
private List<string> _shaHistory = [];
|
private List<string> _navigationHistory = [];
|
||||||
private Models.BlameData _data = null;
|
private Models.BlameData _data = null;
|
||||||
private Dictionary<string, string> _commitMessages = new Dictionary<string, string>();
|
private Dictionary<string, Models.Commit> _commits = new();
|
||||||
|
private Dictionary<string, string> _commitMessages = new();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -313,7 +313,7 @@ namespace SourceGit.ViewModels
|
||||||
blame.IsEnabled = change.Index != Models.ChangeState.Deleted;
|
blame.IsEnabled = change.Index != Models.ChangeState.Deleted;
|
||||||
blame.Click += (_, ev) =>
|
blame.Click += (_, ev) =>
|
||||||
{
|
{
|
||||||
App.ShowWindow(new Blame(_repo.FullPath, change.Path, _commit.SHA), false);
|
App.ShowWindow(new Blame(_repo.FullPath, change.Path, _commit), false);
|
||||||
ev.Handled = true;
|
ev.Handled = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -481,7 +481,7 @@ namespace SourceGit.ViewModels
|
||||||
blame.IsEnabled = file.Type == Models.ObjectType.Blob;
|
blame.IsEnabled = file.Type == Models.ObjectType.Blob;
|
||||||
blame.Click += (_, ev) =>
|
blame.Click += (_, ev) =>
|
||||||
{
|
{
|
||||||
App.ShowWindow(new Blame(_repo.FullPath, file.Path, _commit.SHA), false);
|
App.ShowWindow(new Blame(_repo.FullPath, file.Path, _commit), false);
|
||||||
ev.Handled = true;
|
ev.Handled = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:vm="using:SourceGit.ViewModels"
|
xmlns:vm="using:SourceGit.ViewModels"
|
||||||
xmlns:v="using:SourceGit.Views"
|
xmlns:v="using:SourceGit.Views"
|
||||||
|
xmlns:c="using:SourceGit.Converters"
|
||||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
x:Class="SourceGit.Views.Blame"
|
x:Class="SourceGit.Views.Blame"
|
||||||
x:DataType="vm:Blame"
|
x:DataType="vm:Blame"
|
||||||
|
@ -43,22 +44,44 @@
|
||||||
|
|
||||||
<!-- File -->
|
<!-- File -->
|
||||||
<Border Grid.Row="1" Padding="8,0" >
|
<Border Grid.Row="1" Padding="8,0" >
|
||||||
<Grid>
|
<Grid ColumnDefinitions="Auto,*,Auto,Auto,400">
|
||||||
<TextBlock Text="{Binding Title}" VerticalAlignment="Center"/>
|
<Path Grid.Column="0"
|
||||||
<StackPanel HorizontalAlignment="Right" VerticalAlignment="Center" Orientation="Horizontal">
|
Width="14" Height="14"
|
||||||
<Button Classes="icon_button"
|
Data="{StaticResource Icons.File}"/>
|
||||||
IsEnabled="{Binding CanMoveBack}"
|
|
||||||
Width="28"
|
<TextBlock Grid.Column="1"
|
||||||
Click="HistoryBack">
|
Margin="4,0,0,0"
|
||||||
<Path Width="12" Height="12" Stretch="Uniform" Data="{StaticResource Icons.TriangleLeft}"/>
|
VerticalAlignment="Center"
|
||||||
</Button>
|
Text="{Binding FilePath, Mode=OneWay}"/>
|
||||||
<Button Classes="icon_button"
|
|
||||||
IsEnabled="{Binding CanMoveForward}"
|
<Button Grid.Column="2"
|
||||||
Width="28"
|
Classes="icon_button"
|
||||||
Click="HistoryForward">
|
IsEnabled="{Binding CanBack}"
|
||||||
<Path Width="12" Height="12" Stretch="Uniform" Data="{StaticResource Icons.TriangleRight}"/>
|
Width="28"
|
||||||
</Button>
|
Command="{Binding Back}">
|
||||||
</StackPanel>
|
<Path Width="12" Height="12" Data="{StaticResource Icons.TriangleLeft}"/>
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Button Grid.Column="3"
|
||||||
|
Classes="icon_button"
|
||||||
|
IsEnabled="{Binding CanForward}"
|
||||||
|
Width="28"
|
||||||
|
Command="{Binding Forward}">
|
||||||
|
<Path Width="12" Height="12" Data="{StaticResource Icons.TriangleRight}"/>
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Border Grid.Column="4" Background="#40000000" CornerRadius="3" Padding="4,0" Margin="0,2">
|
||||||
|
<Grid ColumnDefinitions="Auto,*">
|
||||||
|
<TextBlock Grid.Column="0"
|
||||||
|
FontWeight="Bold"
|
||||||
|
Margin="0,0,6,0"
|
||||||
|
Text="{Binding Revision.SHA, Converter={x:Static c:StringConverters.ToShortSHA}, Mode=OneWay}"/>
|
||||||
|
|
||||||
|
<TextBlock Grid.Column="2"
|
||||||
|
Text="{Binding Revision.Subject}"
|
||||||
|
TextTrimming="CharacterEllipsis"/>
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Border>
|
</Border>
|
||||||
|
|
||||||
|
|
|
@ -224,9 +224,7 @@ namespace SourceGit.Views
|
||||||
if (rect.Contains(pos))
|
if (rect.Contains(pos))
|
||||||
{
|
{
|
||||||
if (DataContext is ViewModels.Blame blame)
|
if (DataContext is ViewModels.Blame blame)
|
||||||
{
|
blame.NavigateToCommit(info.CommitSHA);
|
||||||
blame.NavigateToCommit(info.CommitSHA, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
e.Handled = true;
|
e.Handled = true;
|
||||||
break;
|
break;
|
||||||
|
@ -433,8 +431,6 @@ namespace SourceGit.Views
|
||||||
public Blame()
|
public Blame()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
AddHandler(PointerReleasedEvent, MouseUpHandler, handledEventsToo: true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnClosed(EventArgs e)
|
protected override void OnClosed(EventArgs e)
|
||||||
|
@ -443,30 +439,22 @@ namespace SourceGit.Views
|
||||||
GC.Collect();
|
GC.Collect();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HistoryBack(object _, RoutedEventArgs e)
|
protected override void OnPointerReleased(PointerReleasedEventArgs e)
|
||||||
{
|
{
|
||||||
if (DataContext is ViewModels.Blame blame)
|
base.OnPointerReleased(e);
|
||||||
{
|
|
||||||
blame.Back();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private void HistoryForward(object _, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
if (DataContext is ViewModels.Blame blame)
|
|
||||||
{
|
|
||||||
blame.Forward();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void MouseUpHandler(object sender, PointerReleasedEventArgs e)
|
if (!e.Handled && DataContext is ViewModels.Blame blame)
|
||||||
{
|
|
||||||
if (e.InitialPressMouseButton == MouseButton.XButton1)
|
|
||||||
{
|
{
|
||||||
HistoryBack(null, null);
|
if (e.InitialPressMouseButton == MouseButton.XButton1)
|
||||||
}
|
{
|
||||||
else if (e.InitialPressMouseButton == MouseButton.XButton2)
|
blame.Back();
|
||||||
{
|
e.Handled = true;
|
||||||
HistoryForward(null, null);
|
}
|
||||||
|
else if (e.InitialPressMouseButton == MouseButton.XButton2)
|
||||||
|
{
|
||||||
|
blame.Forward();
|
||||||
|
e.Handled = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue