mirror of
https://github.com/sourcegit-scm/sourcegit.git
synced 2024-12-25 21:07:20 -08:00
Compare commits
8 commits
5e75209087
...
0d71f348ec
Author | SHA1 | Date | |
---|---|---|---|
|
0d71f348ec | ||
|
408ece148e | ||
|
11a02343a0 | ||
|
aeea77078b | ||
|
3b09ea45f5 | ||
|
b7abf2ee50 | ||
|
6f256f6f5b | ||
|
5301645f8b |
10 changed files with 245 additions and 85 deletions
|
@ -47,7 +47,7 @@
|
|||
|
||||
## Translation Status
|
||||
|
||||
[![en_US](https://img.shields.io/badge/en__US-100%25-brightgreen)](TRANSLATION.md) [![de__DE](https://img.shields.io/badge/de__DE-99.57%25-yellow)](TRANSLATION.md) [![es__ES](https://img.shields.io/badge/es__ES-99.14%25-yellow)](TRANSLATION.md) [![fr__FR](https://img.shields.io/badge/fr__FR-98.42%25-yellow)](TRANSLATION.md) [![pt__BR](https://img.shields.io/badge/pt__BR-99.14%25-yellow)](TRANSLATION.md) [![ru__RU](https://img.shields.io/badge/ru__RU-100.00%25-brightgreen)](TRANSLATION.md) [![zh__CN](https://img.shields.io/badge/zh__CN-100.00%25-brightgreen)](TRANSLATION.md) [![zh__TW](https://img.shields.io/badge/zh__TW-100.00%25-brightgreen)](TRANSLATION.md)
|
||||
[![en_US](https://img.shields.io/badge/en__US-100%25-brightgreen)](TRANSLATION.md) [![de__DE](https://img.shields.io/badge/de__DE-100.00%25-brightgreen)](TRANSLATION.md) [![es__ES](https://img.shields.io/badge/es__ES-99.14%25-yellow)](TRANSLATION.md) [![fr__FR](https://img.shields.io/badge/fr__FR-98.42%25-yellow)](TRANSLATION.md) [![pt__BR](https://img.shields.io/badge/pt__BR-99.14%25-yellow)](TRANSLATION.md) [![ru__RU](https://img.shields.io/badge/ru__RU-100.00%25-brightgreen)](TRANSLATION.md) [![zh__CN](https://img.shields.io/badge/zh__CN-100.00%25-brightgreen)](TRANSLATION.md) [![zh__TW](https://img.shields.io/badge/zh__TW-100.00%25-brightgreen)](TRANSLATION.md)
|
||||
|
||||
## How to Use
|
||||
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
### de_DE.axaml: 99.57%
|
||||
### de_DE.axaml: 100.00%
|
||||
|
||||
|
||||
<details>
|
||||
<summary>Missing Keys</summary>
|
||||
|
||||
- Text.Repository.FilterCommits.Default
|
||||
- Text.Repository.FilterCommits.Exclude
|
||||
- Text.Repository.FilterCommits.Include
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
|
|
@ -58,7 +58,7 @@
|
|||
<x:String x:Key="Text.BranchCM.DeleteMultiBranches" xml:space="preserve">Lösche alle ausgewählten {0} Branches</x:String>
|
||||
<x:String x:Key="Text.BranchCM.DiscardAll" xml:space="preserve">Alle Änderungen verwerfen</x:String>
|
||||
<x:String x:Key="Text.BranchCM.FastForward" xml:space="preserve">Fast-Forward zu ${0}$</x:String>
|
||||
<x:String x:Key="Text.BranchCM.FetchInto" xml:space="preserve">Fetche ${0}$ nach ${1}$...</x:String>
|
||||
<x:String x:Key="Text.BranchCM.FetchInto" xml:space="preserve">Fetche ${0}$ in ${1}$ hinein...</x:String>
|
||||
<x:String x:Key="Text.BranchCM.Finish" xml:space="preserve">Git Flow - Abschließen ${0}$</x:String>
|
||||
<x:String x:Key="Text.BranchCM.Merge" xml:space="preserve">Merge ${0}$ in ${1}$ hinein...</x:String>
|
||||
<x:String x:Key="Text.BranchCM.Pull" xml:space="preserve">Pull ${0}$</x:String>
|
||||
|
@ -162,8 +162,8 @@
|
|||
<x:String x:Key="Text.Configure.IssueTracker" xml:space="preserve">TICKETSYSTEM</x:String>
|
||||
<x:String x:Key="Text.Configure.IssueTracker.AddSampleGithub" xml:space="preserve">Beispiel für Github-Regel hinzufügen</x:String>
|
||||
<x:String x:Key="Text.Configure.IssueTracker.AddSampleJira" xml:space="preserve">Beispiel für Jira-Regel hinzufügen</x:String>
|
||||
<x:String x:Key="Text.Configure.IssueTracker.AddSampleGitLabIssue" xml:space="preserve">Beispiel für eine Gitlab Issue Regel einfügen</x:String>
|
||||
<x:String x:Key="Text.Configure.IssueTracker.AddSampleGitLabMergeRequest" xml:space="preserve">Beispiel für einen Gitlab Merge Request einfügen</x:String>
|
||||
<x:String x:Key="Text.Configure.IssueTracker.AddSampleGitLabIssue" xml:space="preserve">Beispiel für Gitlab Issue Regel einfügen</x:String>
|
||||
<x:String x:Key="Text.Configure.IssueTracker.AddSampleGitLabMergeRequest" xml:space="preserve">Beispiel für Gitlab Merge Request einfügen</x:String>
|
||||
<x:String x:Key="Text.Configure.IssueTracker.NewRule" xml:space="preserve">Neue Regel</x:String>
|
||||
<x:String x:Key="Text.Configure.IssueTracker.Regex" xml:space="preserve">Ticketnummer Regex-Ausdruck:</x:String>
|
||||
<x:String x:Key="Text.Configure.IssueTracker.RuleName" xml:space="preserve">Name:</x:String>
|
||||
|
@ -171,7 +171,7 @@
|
|||
<x:String x:Key="Text.Configure.IssueTracker.URLTemplate.Tip" xml:space="preserve">Verwende bitte $1, $2 um auf Regex-Gruppenwerte zuzugreifen.</x:String>
|
||||
<x:String x:Key="Text.Configure.OpenAI" xml:space="preserve">OPEN AI</x:String>
|
||||
<x:String x:Key="Text.Configure.OpenAI.Prefered" xml:space="preserve">Bevorzugter Service:</x:String>
|
||||
<x:String x:Key="Text.Configure.OpenAI.Prefered.Tip" xml:space="preserve">Wenn der 'Bevorzugte Service' aktiviert ist, wird SourceGit nur dieses Repository nutzen. Ansonsten wird, wenn mehrere Services verfügbar sind, eine Kontextmenü zur Auswahl angezeigt.</x:String>
|
||||
<x:String x:Key="Text.Configure.OpenAI.Prefered.Tip" xml:space="preserve">Der ausgewählte 'Bevorzugte Service' wird nur in diesem Repository gesetzt und verwendet. Wenn keiner gesetzt ist und mehrere Servies verfügbar sind wird ein Kontextmenü zur Auswahl angezeigt.</x:String>
|
||||
<x:String x:Key="Text.Configure.Proxy" xml:space="preserve">HTTP Proxy</x:String>
|
||||
<x:String x:Key="Text.Configure.Proxy.Placeholder" xml:space="preserve">HTTP Proxy für dieses Repository</x:String>
|
||||
<x:String x:Key="Text.Configure.User" xml:space="preserve">Benutzername</x:String>
|
||||
|
@ -265,7 +265,7 @@
|
|||
<x:String x:Key="Text.EditRepositoryNode.Target" xml:space="preserve">Ziel:</x:String>
|
||||
<x:String x:Key="Text.EditRepositoryNode.TitleForGroup" xml:space="preserve">Ausgewählte Gruppe bearbeiten</x:String>
|
||||
<x:String x:Key="Text.EditRepositoryNode.TitleForRepository" xml:space="preserve">Ausgewähltes Repository bearbeiten</x:String>
|
||||
<x:String x:Key="Text.ExecuteCustomAction" xml:space="preserve">Führe benutzerte Aktion aus</x:String>
|
||||
<x:String x:Key="Text.ExecuteCustomAction" xml:space="preserve">Führe benutzerdefinierte Aktion aus</x:String>
|
||||
<x:String x:Key="Text.ExecuteCustomAction.Name" xml:space="preserve">Name der Aktion:</x:String>
|
||||
<x:String x:Key="Text.FastForwardWithoutCheck" xml:space="preserve">Fast-Forward (ohne Auschecken)</x:String>
|
||||
<x:String x:Key="Text.Fetch" xml:space="preserve">Fetch</x:String>
|
||||
|
@ -535,7 +535,7 @@
|
|||
<x:String x:Key="Text.Repository.AutoFetching" xml:space="preserve">Änderungen automatisch von Remote fetchen...</x:String>
|
||||
<x:String x:Key="Text.Repository.Clean" xml:space="preserve">Aufräumen (GC & Prune)</x:String>
|
||||
<x:String x:Key="Text.Repository.CleanTips" xml:space="preserve">Führt `git gc` auf diesem Repository aus.</x:String>
|
||||
<x:String x:Key="Text.Repository.ClearAllCommitsFilter" xml:space="preserve">Alles löschen</x:String>
|
||||
<x:String x:Key="Text.Repository.ClearAllCommitsFilter" xml:space="preserve">Filter aufheben</x:String>
|
||||
<x:String x:Key="Text.Repository.Configure" xml:space="preserve">Repository Einstellungen</x:String>
|
||||
<x:String x:Key="Text.Repository.Continue" xml:space="preserve">WEITER</x:String>
|
||||
<x:String x:Key="Text.Repository.CustomActions" xml:space="preserve">Benutzerdefinierte Aktionen</x:String>
|
||||
|
@ -543,6 +543,9 @@
|
|||
<x:String x:Key="Text.Repository.EnableReflog" xml:space="preserve">Aktiviere '--reflog' Option</x:String>
|
||||
<x:String x:Key="Text.Repository.Explore" xml:space="preserve">Öffne im Datei-Browser</x:String>
|
||||
<x:String x:Key="Text.Repository.Filter" xml:space="preserve">Suche Branches/Tags/Submodule</x:String>
|
||||
<x:String x:Key="Text.Repository.FilterCommits.Default" xml:space="preserve">Aufheben</x:String>
|
||||
<x:String x:Key="Text.Repository.FilterCommits.Exclude" xml:space="preserve">Im Graph ausblenden</x:String>
|
||||
<x:String x:Key="Text.Repository.FilterCommits.Include" xml:space="preserve">Im Graph filtern</x:String>
|
||||
<x:String x:Key="Text.Repository.LocalBranches" xml:space="preserve">LOKALE BRANCHES</x:String>
|
||||
<x:String x:Key="Text.Repository.NavigateToCurrentHead" xml:space="preserve">Zum HEAD wechseln</x:String>
|
||||
<x:String x:Key="Text.Repository.FirstParentFilterToggle" xml:space="preserve">Aktiviere '--first-parent' Option</x:String>
|
||||
|
@ -601,7 +604,7 @@
|
|||
<x:String x:Key="Text.Start" xml:space="preserve">START</x:String>
|
||||
<x:String x:Key="Text.Stash" xml:space="preserve">Stash</x:String>
|
||||
<x:String x:Key="Text.Stash.IncludeUntracked" xml:space="preserve">Inklusive nicht-verfolgter Dateien</x:String>
|
||||
<x:String x:Key="Text.Stash.KeepIndex" xml:space="preserve">Behalte Dateien des Stages</x:String>
|
||||
<x:String x:Key="Text.Stash.KeepIndex" xml:space="preserve">Behalte gestagte Dateien</x:String>
|
||||
<x:String x:Key="Text.Stash.Message" xml:space="preserve">Name:</x:String>
|
||||
<x:String x:Key="Text.Stash.Message.Placeholder" xml:space="preserve">Optional. Name dieses Stashes</x:String>
|
||||
<x:String x:Key="Text.Stash.OnlyStagedChanges" xml:space="preserve">Nur gestagte Änderungen</x:String>
|
||||
|
|
|
@ -293,7 +293,7 @@ namespace SourceGit.ViewModels
|
|||
history.Icon = App.CreateMenuIcon("Icons.Histories");
|
||||
history.Click += (_, ev) =>
|
||||
{
|
||||
var window = new Views.FileHistories() { DataContext = new FileHistories(_repo, change.Path) };
|
||||
var window = new Views.FileHistories() { DataContext = new FileHistories(_repo, change.Path, _commit.SHA) };
|
||||
window.Show();
|
||||
ev.Handled = true;
|
||||
};
|
||||
|
@ -434,7 +434,7 @@ namespace SourceGit.ViewModels
|
|||
history.Icon = App.CreateMenuIcon("Icons.Histories");
|
||||
history.Click += (_, ev) =>
|
||||
{
|
||||
var window = new Views.FileHistories() { DataContext = new FileHistories(_repo, file.Path) };
|
||||
var window = new Views.FileHistories() { DataContext = new FileHistories(_repo, file.Path, _commit.SHA) };
|
||||
window.Show();
|
||||
ev.Handled = true;
|
||||
};
|
||||
|
|
|
@ -145,6 +145,12 @@ namespace SourceGit.ViewModels
|
|||
LoadDiffContent();
|
||||
}
|
||||
|
||||
public void ToggleTwoSideDiff()
|
||||
{
|
||||
Preference.Instance.UseSideBySideDiff = !Preference.Instance.UseSideBySideDiff;
|
||||
RefreshChangeBlockIndicator();
|
||||
}
|
||||
|
||||
public void OpenExternalMergeTool()
|
||||
{
|
||||
var toolType = Preference.Instance.ExternalMergeToolType;
|
||||
|
|
|
@ -57,14 +57,14 @@ namespace SourceGit.ViewModels
|
|||
private set => SetProperty(ref _viewContent, value);
|
||||
}
|
||||
|
||||
public FileHistories(Repository repo, string file)
|
||||
public FileHistories(Repository repo, string file, string commit = null)
|
||||
{
|
||||
_repo = repo;
|
||||
_file = file;
|
||||
|
||||
Task.Run(() =>
|
||||
{
|
||||
var commits = new Commands.QueryCommits(_repo.FullPath, $"-n 10000 -- \"{file}\"", false).Result();
|
||||
var commits = new Commands.QueryCommits(_repo.FullPath, $"-n 10000 {commit} -- \"{file}\"", false).Result();
|
||||
Dispatcher.UIThread.Invoke(() =>
|
||||
{
|
||||
IsLoading = false;
|
||||
|
|
|
@ -38,7 +38,7 @@ namespace SourceGit.Views
|
|||
}
|
||||
|
||||
public static readonly StyledProperty<IBrush> BackgroundProperty =
|
||||
AvaloniaProperty.Register<CommitRefsPresenter, IBrush>(nameof(Background), null);
|
||||
AvaloniaProperty.Register<CommitRefsPresenter, IBrush>(nameof(Background), Brushes.Transparent);
|
||||
|
||||
public IBrush Background
|
||||
{
|
||||
|
@ -56,7 +56,7 @@ namespace SourceGit.Views
|
|||
}
|
||||
|
||||
public static readonly StyledProperty<bool> UseGraphColorProperty =
|
||||
AvaloniaProperty.Register<CommitRefsPresenter, bool>(nameof(UseGraphColor), false);
|
||||
AvaloniaProperty.Register<CommitRefsPresenter, bool>(nameof(UseGraphColor));
|
||||
|
||||
public bool UseGraphColor
|
||||
{
|
||||
|
@ -96,7 +96,6 @@ namespace SourceGit.Views
|
|||
var x = 1.0;
|
||||
foreach (var item in _items)
|
||||
{
|
||||
var iconRect = new RoundedRect(new Rect(x, 0, 16, 16), new CornerRadius(2, 0, 0, 2));
|
||||
var entireRect = new RoundedRect(new Rect(x, 0, item.Width, 16), new CornerRadius(2));
|
||||
|
||||
if (item.IsHead)
|
||||
|
|
|
@ -131,7 +131,8 @@
|
|||
|
||||
<ToggleButton Classes="line_path"
|
||||
Width="28" Height="18"
|
||||
IsChecked="{Binding Source={x:Static vm:Preference.Instance}, Path=UseSideBySideDiff, Mode=TwoWay}"
|
||||
Command="{Binding ToggleTwoSideDiff}"
|
||||
IsChecked="{Binding Source={x:Static vm:Preference.Instance}, Path=UseSideBySideDiff, Mode=OneWay}"
|
||||
IsVisible="{Binding IsTextDiff}"
|
||||
ToolTip.Tip="{DynamicResource Text.Diff.SideBySide}">
|
||||
<Path Width="12" Height="12" Data="{StaticResource Icons.LayoutHorizontal}" Margin="0,2,0,0"/>
|
||||
|
|
|
@ -13,28 +13,40 @@
|
|||
<ContentControl x:Name="Editor">
|
||||
<ContentControl.DataTemplates>
|
||||
<DataTemplate DataType="m:TextDiff">
|
||||
<v:CombinedTextDiffPresenter FileName="{Binding File}"
|
||||
Foreground="{DynamicResource Brush.FG1}"
|
||||
LineBrush="{DynamicResource Brush.Border2}"
|
||||
EmptyContentBackground="{DynamicResource Brush.Diff.EmptyBG}"
|
||||
AddedContentBackground="{DynamicResource Brush.Diff.AddedBG}"
|
||||
DeletedContentBackground="{DynamicResource Brush.Diff.DeletedBG}"
|
||||
AddedHighlightBrush="{DynamicResource Brush.Diff.AddedHighlight}"
|
||||
DeletedHighlightBrush="{DynamicResource Brush.Diff.DeletedHighlight}"
|
||||
IndicatorForeground="{DynamicResource Brush.FG2}"
|
||||
FontFamily="{DynamicResource Fonts.Monospace}"
|
||||
FontSize="{Binding Source={x:Static vm:Preference.Instance}, Path=EditorFontSize}"
|
||||
UseSyntaxHighlighting="{Binding Source={x:Static vm:Preference.Instance}, Path=UseSyntaxHighlighting}"
|
||||
WordWrap="{Binding Source={x:Static vm:Preference.Instance}, Path=EnableDiffViewWordWrap}"
|
||||
ShowHiddenSymbols="{Binding Source={x:Static vm:Preference.Instance}, Path=ShowHiddenSymbolsInDiffView}"
|
||||
CurrentChangeBlockIdx="{Binding #ThisControl.CurrentChangeBlockIdx}"
|
||||
EnableChunkSelection="{Binding #ThisControl.EnableChunkSelection}"
|
||||
SelectedChunk="{Binding #ThisControl.SelectedChunk, Mode=TwoWay}"/>
|
||||
<Grid ColumnDefinitions="*,1,8">
|
||||
<v:CombinedTextDiffPresenter Grid.Column="0"
|
||||
x:Name="CombinedPresenter"
|
||||
FileName="{Binding File}"
|
||||
Foreground="{DynamicResource Brush.FG1}"
|
||||
LineBrush="{DynamicResource Brush.Border2}"
|
||||
EmptyContentBackground="{DynamicResource Brush.Diff.EmptyBG}"
|
||||
AddedContentBackground="{DynamicResource Brush.Diff.AddedBG}"
|
||||
DeletedContentBackground="{DynamicResource Brush.Diff.DeletedBG}"
|
||||
AddedHighlightBrush="{DynamicResource Brush.Diff.AddedHighlight}"
|
||||
DeletedHighlightBrush="{DynamicResource Brush.Diff.DeletedHighlight}"
|
||||
IndicatorForeground="{DynamicResource Brush.FG2}"
|
||||
FontFamily="{DynamicResource Fonts.Monospace}"
|
||||
FontSize="{Binding Source={x:Static vm:Preference.Instance}, Path=EditorFontSize}"
|
||||
UseSyntaxHighlighting="{Binding Source={x:Static vm:Preference.Instance}, Path=UseSyntaxHighlighting}"
|
||||
WordWrap="{Binding Source={x:Static vm:Preference.Instance}, Path=EnableDiffViewWordWrap}"
|
||||
ShowHiddenSymbols="{Binding Source={x:Static vm:Preference.Instance}, Path=ShowHiddenSymbolsInDiffView}"
|
||||
CurrentChangeBlockIdx="{Binding #ThisControl.CurrentChangeBlockIdx}"
|
||||
EnableChunkSelection="{Binding #ThisControl.EnableChunkSelection}"
|
||||
SelectedChunk="{Binding #ThisControl.SelectedChunk, Mode=TwoWay}"/>
|
||||
|
||||
<Rectangle Grid.Column="1" Fill="{DynamicResource Brush.Border2}" Width="1" HorizontalAlignment="Center" VerticalAlignment="Stretch"/>
|
||||
|
||||
<v:TextDiffViewMinimap Grid.Column="2"
|
||||
DisplayRange="{Binding #CombinedPresenter.DisplayRange}"
|
||||
AddedLineBrush="{DynamicResource Brush.Diff.AddedBG}"
|
||||
DeletedLineBrush="{DynamicResource Brush.Diff.DeletedBG}"/>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate DataType="vm:TwoSideTextDiff">
|
||||
<Grid ColumnDefinitions="*,1,*">
|
||||
<Grid ColumnDefinitions="*,1,*,1,12">
|
||||
<v:SingleSideTextDiffPresenter Grid.Column="0"
|
||||
x:Name="LeftSidePresenter"
|
||||
IsOld="True"
|
||||
FileName="{Binding File}"
|
||||
Foreground="{DynamicResource Brush.FG1}"
|
||||
|
@ -75,6 +87,13 @@
|
|||
CurrentChangeBlockIdx="{Binding #ThisControl.CurrentChangeBlockIdx}"
|
||||
EnableChunkSelection="{Binding #ThisControl.EnableChunkSelection}"
|
||||
SelectedChunk="{Binding #ThisControl.SelectedChunk, Mode=TwoWay}"/>
|
||||
|
||||
<Rectangle Grid.Column="3" Fill="{DynamicResource Brush.Border2}" Width="1" HorizontalAlignment="Center" VerticalAlignment="Stretch"/>
|
||||
|
||||
<v:TextDiffViewMinimap Grid.Column="4"
|
||||
DisplayRange="{Binding #LeftSidePresenter.DisplayRange}"
|
||||
AddedLineBrush="{DynamicResource Brush.Diff.AddedBG}"
|
||||
DeletedLineBrush="{DynamicResource Brush.Diff.DeletedBG}"/>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ContentControl.DataTemplates>
|
||||
|
|
|
@ -46,6 +46,18 @@ namespace SourceGit.Views
|
|||
}
|
||||
}
|
||||
|
||||
public record TextDiffViewRange
|
||||
{
|
||||
public int StartIdx { get; set; } = 0;
|
||||
public int EndIdx { get; set; } = 0;
|
||||
|
||||
public TextDiffViewRange(int startIdx, int endIdx)
|
||||
{
|
||||
StartIdx = startIdx;
|
||||
EndIdx = endIdx;
|
||||
}
|
||||
}
|
||||
|
||||
public class ThemedTextDiffPresenter : TextEditor
|
||||
{
|
||||
public class VerticalSeperatorMargin : AbstractMargin
|
||||
|
@ -211,7 +223,6 @@ namespace SourceGit.Views
|
|||
if (presenter == null)
|
||||
return new Size(0, 0);
|
||||
|
||||
var maxLineNumber = presenter.GetMaxLineNumber();
|
||||
var typeface = TextView.CreateTypeface();
|
||||
var test = new FormattedText(
|
||||
$"-",
|
||||
|
@ -482,6 +493,15 @@ namespace SourceGit.Views
|
|||
get => GetValue(SelectedChunkProperty);
|
||||
set => SetValue(SelectedChunkProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<TextDiffViewRange> DisplayRangeProperty =
|
||||
AvaloniaProperty.Register<ThemedTextDiffPresenter, TextDiffViewRange>(nameof(DisplayRange), new TextDiffViewRange(0, 0));
|
||||
|
||||
public TextDiffViewRange DisplayRange
|
||||
{
|
||||
get => GetValue(DisplayRangeProperty);
|
||||
set => SetValue(DisplayRangeProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<int> CurrentChangeBlockIdxProperty =
|
||||
AvaloniaProperty.Register<ThemedTextDiffPresenter, int>(nameof(CurrentChangeBlockIdx));
|
||||
|
@ -526,25 +546,11 @@ namespace SourceGit.Views
|
|||
|
||||
public void GotoPrevChange()
|
||||
{
|
||||
var view = TextArea.TextView;
|
||||
var lines = GetLines();
|
||||
var firstLineIdx = lines.Count;
|
||||
foreach (var line in view.VisualLines)
|
||||
{
|
||||
if (line.IsDisposed || line.FirstDocumentLine == null || line.FirstDocumentLine.IsDeleted)
|
||||
continue;
|
||||
|
||||
var index = line.FirstDocumentLine.LineNumber - 1;
|
||||
if (index >= lines.Count)
|
||||
continue;
|
||||
|
||||
if (firstLineIdx > index)
|
||||
firstLineIdx = index;
|
||||
}
|
||||
|
||||
var firstLineIdx = DisplayRange.StartIdx;
|
||||
if (firstLineIdx <= 1)
|
||||
return;
|
||||
|
||||
|
||||
var lines = GetLines();
|
||||
var firstLineType = lines[firstLineIdx].Type;
|
||||
var prevLineType = lines[firstLineIdx - 1].Type;
|
||||
var isChangeFirstLine = firstLineType != Models.TextDiffLineType.Normal && firstLineType != Models.TextDiffLineType.Indicator;
|
||||
|
@ -583,22 +589,8 @@ namespace SourceGit.Views
|
|||
|
||||
public void GotoNextChange()
|
||||
{
|
||||
var view = TextArea.TextView;
|
||||
var lines = GetLines();
|
||||
var lastLineIdx = -1;
|
||||
foreach (var line in view.VisualLines)
|
||||
{
|
||||
if (line.IsDisposed || line.FirstDocumentLine == null || line.FirstDocumentLine.IsDeleted)
|
||||
continue;
|
||||
|
||||
var index = line.FirstDocumentLine.LineNumber - 1;
|
||||
if (index >= lines.Count)
|
||||
continue;
|
||||
|
||||
if (lastLineIdx < index)
|
||||
lastLineIdx = index;
|
||||
}
|
||||
|
||||
var lastLineIdx = DisplayRange.EndIdx;
|
||||
if (lastLineIdx >= lines.Count - 1)
|
||||
return;
|
||||
|
||||
|
@ -671,6 +663,7 @@ namespace SourceGit.Views
|
|||
TextArea.TextView.PointerEntered += OnTextViewPointerChanged;
|
||||
TextArea.TextView.PointerMoved += OnTextViewPointerChanged;
|
||||
TextArea.TextView.PointerWheelChanged += OnTextViewPointerWheelChanged;
|
||||
TextArea.TextView.VisualLinesChanged += OnTextViewVisualLinesChanged;
|
||||
|
||||
UpdateTextMate();
|
||||
}
|
||||
|
@ -683,6 +676,7 @@ namespace SourceGit.Views
|
|||
TextArea.TextView.PointerEntered -= OnTextViewPointerChanged;
|
||||
TextArea.TextView.PointerMoved -= OnTextViewPointerChanged;
|
||||
TextArea.TextView.PointerWheelChanged -= OnTextViewPointerWheelChanged;
|
||||
TextArea.TextView.VisualLinesChanged -= OnTextViewVisualLinesChanged;
|
||||
|
||||
if (_textMate != null)
|
||||
{
|
||||
|
@ -790,6 +784,34 @@ namespace SourceGit.Views
|
|||
}
|
||||
}
|
||||
|
||||
private void OnTextViewVisualLinesChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (!TextArea.TextView.VisualLinesValid)
|
||||
{
|
||||
SetCurrentValue(DisplayRangeProperty, new TextDiffViewRange(0, 0));
|
||||
return;
|
||||
}
|
||||
|
||||
var lines = GetLines();
|
||||
var start = int.MaxValue;
|
||||
var count = 0;
|
||||
foreach (var line in TextArea.TextView.VisualLines)
|
||||
{
|
||||
if (line.IsDisposed || line.FirstDocumentLine == null || line.FirstDocumentLine.IsDeleted)
|
||||
continue;
|
||||
|
||||
var index = line.FirstDocumentLine.LineNumber - 1;
|
||||
if (index >= lines.Count)
|
||||
continue;
|
||||
|
||||
count++;
|
||||
if (start > index)
|
||||
start = index;
|
||||
}
|
||||
|
||||
SetCurrentValue(DisplayRangeProperty, new TextDiffViewRange(start, start + count));
|
||||
}
|
||||
|
||||
protected void TrySetChunk(TextDiffViewChunk chunk)
|
||||
{
|
||||
var old = SelectedChunk;
|
||||
|
@ -1107,12 +1129,8 @@ namespace SourceGit.Views
|
|||
|
||||
private void OnTextViewScrollGotFocus(object sender, GotFocusEventArgs e)
|
||||
{
|
||||
if (EnableChunkSelection && sender is ScrollViewer viewer)
|
||||
{
|
||||
var area = viewer.FindDescendantOfType<TextArea>();
|
||||
if (!area.IsPointerOver)
|
||||
TrySetChunk(null);
|
||||
}
|
||||
if (EnableChunkSelection && !TextArea.IsPointerOver)
|
||||
TrySetChunk(null);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1127,6 +1145,8 @@ namespace SourceGit.Views
|
|||
|
||||
public void ForceSyncScrollOffset()
|
||||
{
|
||||
if (_scrollViewer == null)
|
||||
return;
|
||||
if (DataContext is ViewModels.TwoSideTextDiff diff)
|
||||
diff.SyncScrollOffset = _scrollViewer.Offset;
|
||||
}
|
||||
|
@ -1344,12 +1364,8 @@ namespace SourceGit.Views
|
|||
|
||||
private void OnTextViewScrollGotFocus(object sender, GotFocusEventArgs e)
|
||||
{
|
||||
if (EnableChunkSelection && sender is ScrollViewer viewer)
|
||||
{
|
||||
var area = viewer.FindDescendantOfType<TextArea>();
|
||||
if (!area.IsPointerOver)
|
||||
TrySetChunk(null);
|
||||
}
|
||||
if (EnableChunkSelection && !TextArea.IsPointerOver)
|
||||
TrySetChunk(null);
|
||||
}
|
||||
|
||||
private void OnTextViewScrollChanged(object sender, ScrollChangedEventArgs e)
|
||||
|
@ -1366,7 +1382,125 @@ namespace SourceGit.Views
|
|||
|
||||
private ScrollViewer _scrollViewer = null;
|
||||
}
|
||||
|
||||
public class TextDiffViewMinimap : Control
|
||||
{
|
||||
public static readonly StyledProperty<IBrush> AddedLineBrushProperty =
|
||||
AvaloniaProperty.Register<TextDiffViewMinimap, IBrush>(nameof(AddedLineBrush), new SolidColorBrush(Color.FromArgb(60, 0, 255, 0)));
|
||||
|
||||
public IBrush AddedLineBrush
|
||||
{
|
||||
get => GetValue(AddedLineBrushProperty);
|
||||
set => SetValue(AddedLineBrushProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<IBrush> DeletedLineBrushProperty =
|
||||
AvaloniaProperty.Register<TextDiffViewMinimap, IBrush>(nameof(DeletedLineBrush), new SolidColorBrush(Color.FromArgb(60, 255, 0, 0)));
|
||||
|
||||
public IBrush DeletedLineBrush
|
||||
{
|
||||
get => GetValue(DeletedLineBrushProperty);
|
||||
set => SetValue(DeletedLineBrushProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<TextDiffViewRange> DisplayRangeProperty =
|
||||
AvaloniaProperty.Register<TextDiffViewMinimap, TextDiffViewRange>(nameof(DisplayRange), new TextDiffViewRange(0, 0));
|
||||
|
||||
public TextDiffViewRange DisplayRange
|
||||
{
|
||||
get => GetValue(DisplayRangeProperty);
|
||||
set => SetValue(DisplayRangeProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<Color> DisplayRangeColorProperty =
|
||||
AvaloniaProperty.Register<TextDiffViewMinimap, Color>(nameof(DisplayRangeColor), Colors.RoyalBlue);
|
||||
|
||||
public Color DisplayRangeColor
|
||||
{
|
||||
get => GetValue(DisplayRangeColorProperty);
|
||||
set => SetValue(DisplayRangeColorProperty, value);
|
||||
}
|
||||
|
||||
static TextDiffViewMinimap()
|
||||
{
|
||||
AffectsRender<TextDiffViewMinimap>(
|
||||
AddedLineBrushProperty,
|
||||
DeletedLineBrushProperty,
|
||||
DisplayRangeProperty,
|
||||
DisplayRangeColorProperty);
|
||||
}
|
||||
|
||||
public override void Render(DrawingContext context)
|
||||
{
|
||||
var total = 0;
|
||||
if (DataContext is ViewModels.TwoSideTextDiff twoSideDiff)
|
||||
{
|
||||
var halfWidth = Bounds.Width * 0.5;
|
||||
total = Math.Max(twoSideDiff.Old.Count, twoSideDiff.New.Count);
|
||||
RenderSingleSide(context, twoSideDiff.Old, 0, halfWidth);
|
||||
RenderSingleSide(context, twoSideDiff.New, halfWidth, halfWidth);
|
||||
}
|
||||
else if (DataContext is Models.TextDiff diff)
|
||||
{
|
||||
total = diff.Lines.Count;
|
||||
RenderSingleSide(context, diff.Lines, 0, Bounds.Width);
|
||||
}
|
||||
|
||||
var range = DisplayRange;
|
||||
if (range.EndIdx == 0)
|
||||
return;
|
||||
|
||||
var startY = range.StartIdx / (total * 1.0) * Bounds.Height;
|
||||
var endY = range.EndIdx / (total * 1.0) * Bounds.Height;
|
||||
var color = DisplayRangeColor;
|
||||
var brush = new SolidColorBrush(color, 0.2);
|
||||
var pen = new Pen(color.ToUInt32());
|
||||
var rect = new Rect(0, startY, Bounds.Width, endY - startY);
|
||||
|
||||
context.DrawRectangle(brush, null, rect);
|
||||
context.DrawLine(pen, rect.TopLeft, rect.TopRight);
|
||||
context.DrawLine(pen, rect.BottomLeft, rect.BottomRight);
|
||||
}
|
||||
|
||||
protected override void OnDataContextChanged(EventArgs e)
|
||||
{
|
||||
base.OnDataContextChanged(e);
|
||||
InvalidateVisual();
|
||||
}
|
||||
|
||||
private void RenderSingleSide(DrawingContext context, List<Models.TextDiffLine> lines, double x, double width)
|
||||
{
|
||||
var total = lines.Count;
|
||||
var lastLineType = Models.TextDiffLineType.Indicator;
|
||||
var lastLineTypeStart = 0;
|
||||
|
||||
for (int i = 0; i < total; i++)
|
||||
{
|
||||
var line = lines[i];
|
||||
if (line.Type != lastLineType)
|
||||
{
|
||||
RenderBlock(context, lastLineType, lastLineTypeStart, i - lastLineTypeStart, total, x, width);
|
||||
|
||||
lastLineType = line.Type;
|
||||
lastLineTypeStart = i;
|
||||
}
|
||||
}
|
||||
|
||||
RenderBlock(context, lastLineType, lastLineTypeStart, total - lastLineTypeStart, total, x, width);
|
||||
}
|
||||
|
||||
private void RenderBlock(DrawingContext context, Models.TextDiffLineType type, int start, int count, int total, double x, double width)
|
||||
{
|
||||
if (type == Models.TextDiffLineType.Added || type == Models.TextDiffLineType.Deleted)
|
||||
{
|
||||
var brush = type == Models.TextDiffLineType.Added ? AddedLineBrush : DeletedLineBrush;
|
||||
var y = start / (total * 1.0) * Bounds.Height;
|
||||
var h = count / (total * 1.0) * Bounds.Height;
|
||||
context.DrawRectangle(brush, null, new Rect(x, y, width, h));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public partial class TextDiffView : UserControl
|
||||
{
|
||||
public static readonly StyledProperty<bool> UseSideBySideDiffProperty =
|
||||
|
@ -1452,7 +1586,7 @@ namespace SourceGit.Views
|
|||
|
||||
CurrentChangeBlockIdxProperty.Changed.AddClassHandler<TextDiffView>((v, e) =>
|
||||
{
|
||||
if (v.Editor.Presenter != null)
|
||||
if ((int)e.NewValue >= 0 && v.Editor.Presenter != null)
|
||||
{
|
||||
foreach (var p in v.Editor.Presenter.GetVisualDescendants().OfType<ThemedTextDiffPresenter>())
|
||||
{
|
||||
|
@ -1472,7 +1606,7 @@ namespace SourceGit.Views
|
|||
protected override void OnDataContextChanged(EventArgs e)
|
||||
{
|
||||
base.OnDataContextChanged(e);
|
||||
RefreshContent(DataContext as Models.TextDiff, true);
|
||||
RefreshContent(DataContext as Models.TextDiff);
|
||||
}
|
||||
|
||||
protected override void OnPointerExited(PointerEventArgs e)
|
||||
|
|
Loading…
Reference in a new issue