diff --git a/src/Resources/Themes.axaml b/src/Resources/Themes.axaml index 36889bca..b01cafe9 100644 --- a/src/Resources/Themes.axaml +++ b/src/Resources/Themes.axaml @@ -25,11 +25,11 @@ #FF1F1F1F #FF6F6F6F #FFFFFFFF - #3C000000 - #3C00FF00 - #3CFF0000 - #5A00FF00 - #50FF0000 + #3C000000 + #3C00FF00 + #3CFF0000 + #5A00FF00 + #50FF0000 @@ -56,11 +56,11 @@ #FFDDDDDD #40F1F1F1 #FF252525 - #3C000000 - #3C00FF00 - #3CFF0000 - #5A00FF00 - #50FF0000 + #3C000000 + #3C00FF00 + #3CFF0000 + #5A00FF00 + #50FF0000 @@ -89,9 +89,9 @@ - - - - - + + + + + diff --git a/src/ViewModels/TwoSideTextDiff.cs b/src/ViewModels/TwoSideTextDiff.cs index ad1b5478..8d2aedcc 100644 --- a/src/ViewModels/TwoSideTextDiff.cs +++ b/src/ViewModels/TwoSideTextDiff.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; - +using Avalonia; using CommunityToolkit.Mvvm.ComponentModel; namespace SourceGit.ViewModels @@ -11,7 +11,13 @@ namespace SourceGit.ViewModels public List New { get; set; } = new List(); public int MaxLineNumber = 0; - public TwoSideTextDiff(Models.TextDiff diff) + public Vector SyncScrollOffset + { + get => _syncScrollOffset; + set => SetProperty(ref _syncScrollOffset, value); + } + + public TwoSideTextDiff(Models.TextDiff diff, TwoSideTextDiff previous = null) { File = diff.File; MaxLineNumber = diff.MaxLineNumber; @@ -35,6 +41,9 @@ namespace SourceGit.ViewModels } FillEmptyLines(); + + if (previous != null && previous.File == File) + _syncScrollOffset = previous._syncScrollOffset; } private void FillEmptyLines() @@ -52,5 +61,7 @@ namespace SourceGit.ViewModels New.Add(new Models.TextDiffLine()); } } + + private Vector _syncScrollOffset = Vector.Zero; } } diff --git a/src/ViewModels/WorkingCopy.cs b/src/ViewModels/WorkingCopy.cs index 16dab612..bb982491 100644 --- a/src/ViewModels/WorkingCopy.cs +++ b/src/ViewModels/WorkingCopy.cs @@ -379,24 +379,16 @@ namespace SourceGit.ViewModels if (isUnstaged) { if (changes.Count == _unstaged.Count && _staged.Count == 0) - { PopupHost.ShowPopup(new Discard(_repo)); - } else - { PopupHost.ShowPopup(new Discard(_repo, changes, true)); - } } else { if (changes.Count == _staged.Count && _unstaged.Count == 0) - { PopupHost.ShowPopup(new Discard(_repo)); - } else - { PopupHost.ShowPopup(new Discard(_repo, changes, false)); - } } } } @@ -921,24 +913,11 @@ namespace SourceGit.ViewModels var isUnstaged = _selectedUnstaged != null && _selectedUnstaged.Count > 0; if (change == null) - { DetailContext = null; - } else if (change.IsConflit && isUnstaged) - { DetailContext = new ConflictContext(_repo.FullPath, change); - } else - { - if (_detailContext is DiffContext previous) - { - DetailContext = new DiffContext(_repo.FullPath, new Models.DiffOption(change, isUnstaged), previous); - } - else - { - DetailContext = new DiffContext(_repo.FullPath, new Models.DiffOption(change, isUnstaged)); - } - } + DetailContext = new DiffContext(_repo.FullPath, new Models.DiffOption(change, isUnstaged), _detailContext as DiffContext); } private async void UseTheirs(List changes) diff --git a/src/Views/DiffView.axaml b/src/Views/DiffView.axaml index 081abdf0..027a2bb3 100644 --- a/src/Views/DiffView.axaml +++ b/src/Views/DiffView.axaml @@ -234,9 +234,7 @@ - + diff --git a/src/Views/TextDiffView.axaml b/src/Views/TextDiffView.axaml index f435b2e2..538a0a6e 100644 --- a/src/Views/TextDiffView.axaml +++ b/src/Views/TextDiffView.axaml @@ -11,18 +11,16 @@ Background="{DynamicResource Brush.Contents}"> - @@ -30,40 +28,36 @@ + UseSyntaxHighlighting="{Binding Source={x:Static vm:Preference.Instance}, Path=UseSyntaxHighlighting}" + WordWrap="{Binding Source={x:Static vm:Preference.Instance}, Path=EnableDiffViewWordWrap}"/> + UseSyntaxHighlighting="{Binding Source={x:Static vm:Preference.Instance}, Path=UseSyntaxHighlighting}" + WordWrap="{Binding Source={x:Static vm:Preference.Instance}, Path=EnableDiffViewWordWrap}"/> diff --git a/src/Views/TextDiffView.axaml.cs b/src/Views/TextDiffView.axaml.cs index 50576cc4..204b5131 100644 --- a/src/Views/TextDiffView.axaml.cs +++ b/src/Views/TextDiffView.axaml.cs @@ -7,6 +7,7 @@ using System.Text; using Avalonia; using Avalonia.Controls; using Avalonia.Controls.Primitives; +using Avalonia.Data; using Avalonia.Input; using Avalonia.Interactivity; using Avalonia.Media; @@ -21,7 +22,161 @@ using AvaloniaEdit.Utils; namespace SourceGit.Views { - public class CombinedTextDiffPresenter : TextEditor + public class IThemedTextDiffPresenter : TextEditor + { + public static readonly StyledProperty FileNameProperty = + AvaloniaProperty.Register(nameof(FileName), string.Empty); + + public string FileName + { + get => GetValue(FileNameProperty); + set => SetValue(FileNameProperty, value); + } + + public static readonly StyledProperty LineBrushProperty = + AvaloniaProperty.Register(nameof(LineBrush), new SolidColorBrush(Colors.DarkGray)); + + public IBrush LineBrush + { + get => GetValue(LineBrushProperty); + set => SetValue(LineBrushProperty, value); + } + + public static readonly StyledProperty EmptyContentBackgroundProperty = + AvaloniaProperty.Register(nameof(EmptyContentBackground), new SolidColorBrush(Color.FromArgb(60, 0, 0, 0))); + + public IBrush EmptyContentBackground + { + get => GetValue(EmptyContentBackgroundProperty); + set => SetValue(EmptyContentBackgroundProperty, value); + } + + public static readonly StyledProperty AddedContentBackgroundProperty = + AvaloniaProperty.Register(nameof(AddedContentBackground), new SolidColorBrush(Color.FromArgb(60, 0, 255, 0))); + + public IBrush AddedContentBackground + { + get => GetValue(AddedContentBackgroundProperty); + set => SetValue(AddedContentBackgroundProperty, value); + } + + public static readonly StyledProperty DeletedContentBackgroundProperty = + AvaloniaProperty.Register(nameof(DeletedContentBackground), new SolidColorBrush(Color.FromArgb(60, 255, 0, 0))); + + public IBrush DeletedContentBackground + { + get => GetValue(DeletedContentBackgroundProperty); + set => SetValue(DeletedContentBackgroundProperty, value); + } + + public static readonly StyledProperty AddedHighlightBrushProperty = + AvaloniaProperty.Register(nameof(AddedHighlightBrush), new SolidColorBrush(Color.FromArgb(90, 0, 255, 0))); + + public IBrush AddedHighlightBrush + { + get => GetValue(AddedHighlightBrushProperty); + set => SetValue(AddedHighlightBrushProperty, value); + } + + public static readonly StyledProperty DeletedHighlightBrushProperty = + AvaloniaProperty.Register(nameof(DeletedHighlightBrush), new SolidColorBrush(Color.FromArgb(80, 255, 0, 0))); + + public IBrush DeletedHighlightBrush + { + get => GetValue(DeletedHighlightBrushProperty); + set => SetValue(DeletedHighlightBrushProperty, value); + } + + public static readonly StyledProperty IndicatorForegroundProperty = + AvaloniaProperty.Register(nameof(IndicatorForeground), Brushes.Gray); + + public IBrush IndicatorForeground + { + get => GetValue(IndicatorForegroundProperty); + set => SetValue(IndicatorForegroundProperty, value); + } + + public static readonly StyledProperty UseSyntaxHighlightingProperty = + AvaloniaProperty.Register(nameof(UseSyntaxHighlighting), false); + + public bool UseSyntaxHighlighting + { + get => GetValue(UseSyntaxHighlightingProperty); + set => SetValue(UseSyntaxHighlightingProperty, value); + } + + protected override Type StyleKeyOverride => typeof(TextEditor); + + public IThemedTextDiffPresenter(TextArea area, TextDocument doc): base(area, doc) + { + IsReadOnly = true; + ShowLineNumbers = false; + BorderThickness = new Thickness(0); + + TextArea.TextView.Margin = new Thickness(4, 0); + TextArea.TextView.Options.EnableHyperlinks = false; + TextArea.TextView.Options.EnableEmailHyperlinks = false; + } + + protected override void OnLoaded(RoutedEventArgs e) + { + base.OnLoaded(e); + UpdateTextMate(); + } + + protected override void OnUnloaded(RoutedEventArgs e) + { + base.OnUnloaded(e); + + if (_textMate != null) + { + _textMate.Dispose(); + _textMate = null; + } + } + + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) + { + base.OnPropertyChanged(change); + + if (change.Property == UseSyntaxHighlightingProperty) + UpdateTextMate(); + else if (change.Property == FileNameProperty) + Models.TextMateHelper.SetGrammarByFileName(_textMate, FileName); + else if (change.Property.Name == "ActualThemeVariant" && change.NewValue != null) + Models.TextMateHelper.SetThemeByApp(_textMate); + } + + protected void UpdateTextMate() + { + if (UseSyntaxHighlighting) + { + if (_textMate == null) + { + TextArea.TextView.LineTransformers.Remove(_lineStyleTransformer); + _textMate = Models.TextMateHelper.CreateForEditor(this); + TextArea.TextView.LineTransformers.Add(_lineStyleTransformer); + Models.TextMateHelper.SetGrammarByFileName(_textMate, FileName); + } + } + else + { + if (_textMate != null) + { + _textMate.Dispose(); + _textMate = null; + GC.Collect(); + + TextArea.TextView.Redraw(); + } + } + } + + private TextMate.Installation _textMate = null; + protected IVisualLineTransformer _lineStyleTransformer = null; + } + + public class CombinedTextDiffPresenter : IThemedTextDiffPresenter { public class LineNumberMargin : AbstractMargin { @@ -104,7 +259,7 @@ namespace SourceGit.Views public override void Render(DrawingContext context) { - var pen = new Pen(_editor.BorderBrush, 1); + var pen = new Pen(_editor.LineBrush, 1); context.DrawLine(pen, new Point(0, 0), new Point(0, Bounds.Height)); } @@ -155,11 +310,11 @@ namespace SourceGit.Views switch (type) { case Models.TextDiffLineType.None: - return _editor.LineBGEmpty; + return _editor.EmptyContentBackground; case Models.TextDiffLineType.Added: - return _editor.LineBGAdd; + return _editor.AddedContentBackground; case Models.TextDiffLineType.Deleted: - return _editor.LineBGDeleted; + return _editor.DeletedContentBackground; default: return null; } @@ -186,7 +341,7 @@ namespace SourceGit.Views { ChangeLinePart(line.Offset, line.EndOffset, v => { - v.TextRunProperties.SetForegroundBrush(_editor.SecondaryFG); + v.TextRunProperties.SetForegroundBrush(_editor.IndicatorForeground); v.TextRunProperties.SetTypeface(new Typeface(_editor.FontFamily, FontStyle.Italic)); }); @@ -195,7 +350,7 @@ namespace SourceGit.Views if (info.Highlights.Count > 0) { - var bg = info.Type == Models.TextDiffLineType.Added ? _editor.SecondaryLineBGAdd : _editor.SecondaryLineBGDeleted; + var bg = info.Type == Models.TextDiffLineType.Added ? _editor.AddedHighlightBrush : _editor.DeletedHighlightBrush; foreach (var highlight in info.Highlights) { ChangeLinePart(line.Offset + highlight.Start, line.Offset + highlight.Start + highlight.Count, v => @@ -209,129 +364,57 @@ namespace SourceGit.Views private readonly CombinedTextDiffPresenter _editor; } - public static readonly StyledProperty DiffDataProperty = - AvaloniaProperty.Register(nameof(DiffData)); - - public Models.TextDiff DiffData - { - get => GetValue(DiffDataProperty); - set => SetValue(DiffDataProperty, value); - } - - public static readonly StyledProperty LineBGEmptyProperty = - AvaloniaProperty.Register(nameof(LineBGEmpty), new SolidColorBrush(Color.FromArgb(60, 0, 0, 0))); - - public IBrush LineBGEmpty - { - get => GetValue(LineBGEmptyProperty); - set => SetValue(LineBGEmptyProperty, value); - } - - public static readonly StyledProperty LineBGAddProperty = - AvaloniaProperty.Register(nameof(LineBGAdd), new SolidColorBrush(Color.FromArgb(60, 0, 255, 0))); - - public IBrush LineBGAdd - { - get => GetValue(LineBGAddProperty); - set => SetValue(LineBGAddProperty, value); - } - - public static readonly StyledProperty LineBGDeletedProperty = - AvaloniaProperty.Register(nameof(LineBGDeleted), new SolidColorBrush(Color.FromArgb(60, 255, 0, 0))); - - public IBrush LineBGDeleted - { - get => GetValue(LineBGDeletedProperty); - set => SetValue(LineBGDeletedProperty, value); - } - - public static readonly StyledProperty SecondaryLineBGAddProperty = - AvaloniaProperty.Register(nameof(SecondaryLineBGAdd), new SolidColorBrush(Color.FromArgb(90, 0, 255, 0))); - - public IBrush SecondaryLineBGAdd - { - get => GetValue(SecondaryLineBGAddProperty); - set => SetValue(SecondaryLineBGAddProperty, value); - } - - public static readonly StyledProperty SecondaryLineBGDeletedProperty = - AvaloniaProperty.Register(nameof(SecondaryLineBGDeleted), new SolidColorBrush(Color.FromArgb(80, 255, 0, 0))); - - public IBrush SecondaryLineBGDeleted - { - get => GetValue(SecondaryLineBGDeletedProperty); - set => SetValue(SecondaryLineBGDeletedProperty, value); - } - - public static readonly StyledProperty SecondaryFGProperty = - AvaloniaProperty.Register(nameof(SecondaryFG), Brushes.Gray); - - public IBrush SecondaryFG - { - get => GetValue(SecondaryFGProperty); - set => SetValue(SecondaryFGProperty, value); - } - - public static readonly StyledProperty SyncScrollOffsetProperty = - AvaloniaProperty.Register(nameof(SyncScrollOffset)); - - public Vector SyncScrollOffset - { - get => GetValue(SyncScrollOffsetProperty); - set => SetValue(SyncScrollOffsetProperty, value); - } - - public static readonly StyledProperty UseSyntaxHighlightingProperty = - AvaloniaProperty.Register(nameof(UseSyntaxHighlighting), false); - - public bool UseSyntaxHighlighting - { - get => GetValue(UseSyntaxHighlightingProperty); - set => SetValue(UseSyntaxHighlightingProperty, value); - } - - protected override Type StyleKeyOverride => typeof(TextEditor); + public Models.TextDiff DiffData => DataContext as Models.TextDiff; public CombinedTextDiffPresenter() : base(new TextArea(), new TextDocument()) { _lineStyleTransformer = new LineStyleTransformer(this); - IsReadOnly = true; - ShowLineNumbers = false; - TextArea.LeftMargins.Add(new LineNumberMargin(this, true) { Margin = new Thickness(8, 0) }); TextArea.LeftMargins.Add(new VerticalSeperatorMargin(this)); TextArea.LeftMargins.Add(new LineNumberMargin(this, false) { Margin = new Thickness(8, 0) }); TextArea.LeftMargins.Add(new VerticalSeperatorMargin(this)); - TextArea.TextView.Margin = new Thickness(4, 0); TextArea.TextView.BackgroundRenderers.Add(new LineBackgroundRenderer(this)); TextArea.TextView.LineTransformers.Add(_lineStyleTransformer); - TextArea.TextView.Options.EnableHyperlinks = false; - TextArea.TextView.Options.EnableEmailHyperlinks = false; + } + + protected override void OnApplyTemplate(TemplateAppliedEventArgs e) + { + base.OnApplyTemplate(e); + + var scroller = (ScrollViewer)e.NameScope.Find("PART_ScrollViewer"); + scroller.Bind(ScrollViewer.OffsetProperty, new Binding("SyncScrollOffset", BindingMode.TwoWay)); } protected override void OnLoaded(RoutedEventArgs e) { base.OnLoaded(e); - - UpdateTextMate(); - TextArea.TextView.ContextRequested += OnTextViewContextRequested; - TextArea.TextView.ScrollOffsetChanged += OnTextViewScrollOffsetChanged; } protected override void OnUnloaded(RoutedEventArgs e) { base.OnUnloaded(e); - TextArea.TextView.ContextRequested -= OnTextViewContextRequested; - TextArea.TextView.ScrollOffsetChanged -= OnTextViewScrollOffsetChanged; + } - if (_textMate != null) + protected override void OnDataContextChanged(EventArgs e) + { + base.OnDataContextChanged(e); + + var textDiff = DataContext as Models.TextDiff; + if (textDiff != null) { - _textMate.Dispose(); - _textMate = null; + var builder = new StringBuilder(); + foreach (var line in textDiff.Lines) + builder.AppendLine(line.Content); + + Text = builder.ToString(); + } + else + { + Text = string.Empty; } GC.Collect(); @@ -346,9 +429,7 @@ namespace SourceGit.Views var menu = new ContextMenu(); var parentView = this.FindAncestorOfType(); if (parentView != null) - { parentView.FillContextMenuForWorkingCopyChange(menu, selection.StartPosition.Line, selection.EndPosition.Line, false); - } var copy = new MenuItem(); copy.Header = App.Text("Copy"); @@ -364,84 +445,9 @@ namespace SourceGit.Views TextArea.TextView.OpenContextMenu(menu); e.Handled = true; } - - private void OnTextViewScrollOffsetChanged(object sender, EventArgs e) - { - SetCurrentValue(SyncScrollOffsetProperty, TextArea.TextView.ScrollOffset); - } - - protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) - { - base.OnPropertyChanged(change); - - if (change.Property == DiffDataProperty) - { - if (DiffData != null) - { - var builder = new StringBuilder(); - foreach (var line in DiffData.Lines) - { - builder.AppendLine(line.Content); - } - - Text = builder.ToString(); - Models.TextMateHelper.SetGrammarByFileName(_textMate, DiffData.File); - } - else - { - Text = string.Empty; - } - } - else if (change.Property == SyncScrollOffsetProperty) - { - if (TextArea.TextView.ScrollOffset != SyncScrollOffset) - { - IScrollable scrollable = TextArea.TextView; - scrollable.Offset = SyncScrollOffset; - } - } - else if (change.Property == UseSyntaxHighlightingProperty) - { - UpdateTextMate(); - } - else if (change.Property.Name == "ActualThemeVariant" && change.NewValue != null) - { - Models.TextMateHelper.SetThemeByApp(_textMate); - } - } - - private void UpdateTextMate() - { - if (UseSyntaxHighlighting) - { - if (_textMate == null) - { - TextArea.TextView.LineTransformers.Remove(_lineStyleTransformer); - _textMate = Models.TextMateHelper.CreateForEditor(this); - TextArea.TextView.LineTransformers.Add(_lineStyleTransformer); - - if (DiffData != null) - Models.TextMateHelper.SetGrammarByFileName(_textMate, DiffData.File); - } - } - else - { - if (_textMate != null) - { - _textMate.Dispose(); - _textMate = null; - GC.Collect(); - - TextArea.TextView.Redraw(); - } - } - } - - private TextMate.Installation _textMate; - private readonly LineStyleTransformer _lineStyleTransformer = null; } - public class SingleSideTextDiffPresenter : TextEditor + public class SingleSideTextDiffPresenter : IThemedTextDiffPresenter { public class LineNumberMargin : AbstractMargin { @@ -523,7 +529,7 @@ namespace SourceGit.Views public override void Render(DrawingContext context) { - var pen = new Pen(_editor.BorderBrush, 1); + var pen = new Pen(_editor.LineBrush, 1); context.DrawLine(pen, new Point(0, 0), new Point(0, Bounds.Height)); } @@ -575,11 +581,11 @@ namespace SourceGit.Views switch (type) { case Models.TextDiffLineType.None: - return _editor.LineBGEmpty; + return _editor.EmptyContentBackground; case Models.TextDiffLineType.Added: - return _editor.LineBGAdd; + return _editor.AddedContentBackground; case Models.TextDiffLineType.Deleted: - return _editor.LineBGDeleted; + return _editor.DeletedContentBackground; default: return null; } @@ -607,7 +613,7 @@ namespace SourceGit.Views { ChangeLinePart(line.Offset, line.EndOffset, v => { - v.TextRunProperties.SetForegroundBrush(_editor.SecondaryFG); + v.TextRunProperties.SetForegroundBrush(_editor.IndicatorForeground); v.TextRunProperties.SetTypeface(new Typeface(_editor.FontFamily, FontStyle.Italic)); }); @@ -616,7 +622,7 @@ namespace SourceGit.Views if (info.Highlights.Count > 0) { - var bg = info.Type == Models.TextDiffLineType.Added ? _editor.LineBGAdd : _editor.LineBGDeleted; + var bg = info.Type == Models.TextDiffLineType.Added ? _editor.AddedHighlightBrush : _editor.DeletedHighlightBrush; foreach (var highlight in info.Highlights) { ChangeLinePart(line.Offset + highlight.Start, line.Offset + highlight.Start + highlight.Count, v => @@ -639,103 +645,16 @@ namespace SourceGit.Views set => SetValue(IsOldProperty, value); } - public static readonly StyledProperty DiffDataProperty = - AvaloniaProperty.Register(nameof(DiffData)); - - public ViewModels.TwoSideTextDiff DiffData - { - get => GetValue(DiffDataProperty); - set => SetValue(DiffDataProperty, value); - } - - public static readonly StyledProperty LineBGEmptyProperty = - AvaloniaProperty.Register(nameof(LineBGEmpty), new SolidColorBrush(Color.FromArgb(60, 0, 0, 0))); - - public IBrush LineBGEmpty - { - get => GetValue(LineBGEmptyProperty); - set => SetValue(LineBGEmptyProperty, value); - } - - public static readonly StyledProperty LineBGAddProperty = - AvaloniaProperty.Register(nameof(LineBGAdd), new SolidColorBrush(Color.FromArgb(60, 0, 255, 0))); - - public IBrush LineBGAdd - { - get => GetValue(LineBGAddProperty); - set => SetValue(LineBGAddProperty, value); - } - - public static readonly StyledProperty LineBGDeletedProperty = - AvaloniaProperty.Register(nameof(LineBGDeleted), new SolidColorBrush(Color.FromArgb(60, 255, 0, 0))); - - public IBrush LineBGDeleted - { - get => GetValue(LineBGDeletedProperty); - set => SetValue(LineBGDeletedProperty, value); - } - - public static readonly StyledProperty SecondaryLineBGAddProperty = - AvaloniaProperty.Register(nameof(SecondaryLineBGAdd), new SolidColorBrush(Color.FromArgb(90, 0, 255, 0))); - - public IBrush SecondaryLineBGAdd - { - get => GetValue(SecondaryLineBGAddProperty); - set => SetValue(SecondaryLineBGAddProperty, value); - } - - public static readonly StyledProperty SecondaryLineBGDeletedProperty = - AvaloniaProperty.Register(nameof(SecondaryLineBGDeleted), new SolidColorBrush(Color.FromArgb(80, 255, 0, 0))); - - public IBrush SecondaryLineBGDeleted - { - get => GetValue(SecondaryLineBGDeletedProperty); - set => SetValue(SecondaryLineBGDeletedProperty, value); - } - - public static readonly StyledProperty SecondaryFGProperty = - AvaloniaProperty.Register(nameof(SecondaryFG), Brushes.Gray); - - public IBrush SecondaryFG - { - get => GetValue(SecondaryFGProperty); - set => SetValue(SecondaryFGProperty, value); - } - - public static readonly StyledProperty SyncScrollOffsetProperty = - AvaloniaProperty.Register(nameof(SyncScrollOffset), Vector.Zero); - - public Vector SyncScrollOffset - { - get => GetValue(SyncScrollOffsetProperty); - set => SetValue(SyncScrollOffsetProperty, value); - } - - public static readonly StyledProperty UseSyntaxHighlightingProperty = - AvaloniaProperty.Register(nameof(UseSyntaxHighlighting), false); - - public bool UseSyntaxHighlighting - { - get => GetValue(UseSyntaxHighlightingProperty); - set => SetValue(UseSyntaxHighlightingProperty, value); - } - - protected override Type StyleKeyOverride => typeof(TextEditor); + public ViewModels.TwoSideTextDiff DiffData => DataContext as ViewModels.TwoSideTextDiff; public SingleSideTextDiffPresenter() : base(new TextArea(), new TextDocument()) { _lineStyleTransformer = new LineStyleTransformer(this); - IsReadOnly = true; - ShowLineNumbers = false; - TextArea.LeftMargins.Add(new LineNumberMargin(this) { Margin = new Thickness(8, 0) }); TextArea.LeftMargins.Add(new VerticalSeperatorMargin(this)); - TextArea.TextView.Margin = new Thickness(4, 0); TextArea.TextView.BackgroundRenderers.Add(new LineBackgroundRenderer(this)); TextArea.TextView.LineTransformers.Add(_lineStyleTransformer); - TextArea.TextView.Options.EnableHyperlinks = false; - TextArea.TextView.Options.EnableEmailHyperlinks = false; } protected override void OnLoaded(RoutedEventArgs e) @@ -745,12 +664,10 @@ namespace SourceGit.Views _scrollViewer = this.FindDescendantOfType(); if (_scrollViewer != null) { - _scrollViewer.Offset = SyncScrollOffset; _scrollViewer.ScrollChanged += OnTextViewScrollChanged; + _scrollViewer.Bind(ScrollViewer.OffsetProperty, new Binding("SyncScrollOffset", BindingMode.OneWay)); } - UpdateTextMate(); - TextArea.PointerWheelChanged += OnTextAreaPointerWheelChanged; TextArea.TextView.ContextRequested += OnTextViewContextRequested; } @@ -765,18 +682,31 @@ namespace SourceGit.Views _scrollViewer = null; } - if (_textMate != null) - { - _textMate.Dispose(); - _textMate = null; - } - TextArea.PointerWheelChanged -= OnTextAreaPointerWheelChanged; TextArea.TextView.ContextRequested -= OnTextViewContextRequested; GC.Collect(); } + protected override void OnDataContextChanged(EventArgs e) + { + base.OnDataContextChanged(e); + + if (DataContext is ViewModels.TwoSideTextDiff diff) + { + var builder = new StringBuilder(); + var lines = IsOld ? diff.Old : diff.New; + foreach (var line in lines) + builder.AppendLine(line.Content); + + Text = builder.ToString(); + } + else + { + Text = string.Empty; + } + } + private void OnTextAreaPointerWheelChanged(object sender, PointerWheelEventArgs e) { if (!TextArea.IsFocused) @@ -785,8 +715,8 @@ namespace SourceGit.Views private void OnTextViewScrollChanged(object sender, ScrollChangedEventArgs e) { - if (TextArea.IsFocused) - SetCurrentValue(SyncScrollOffsetProperty, _scrollViewer.Offset); + if (TextArea.IsFocused && DataContext is ViewModels.TwoSideTextDiff diff) + diff.SyncScrollOffset = _scrollViewer.Offset; } private void OnTextViewContextRequested(object sender, ContextRequestedEventArgs e) @@ -798,9 +728,7 @@ namespace SourceGit.Views var menu = new ContextMenu(); var parentView = this.FindAncestorOfType(); if (parentView != null) - { parentView.FillContextMenuForWorkingCopyChange(menu, selection.StartPosition.Line, selection.EndPosition.Line, IsOld); - } var copy = new MenuItem(); copy.Header = App.Text("Copy"); @@ -817,96 +745,11 @@ namespace SourceGit.Views e.Handled = true; } - protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) - { - base.OnPropertyChanged(change); - - if (change.Property == DiffDataProperty) - { - if (DiffData != null) - { - var builder = new StringBuilder(); - if (IsOld) - { - foreach (var line in DiffData.Old) - { - builder.AppendLine(line.Content); - } - } - else - { - foreach (var line in DiffData.New) - { - builder.AppendLine(line.Content); - } - } - - Text = builder.ToString(); - Models.TextMateHelper.SetGrammarByFileName(_textMate, DiffData.File); - } - else - { - Text = string.Empty; - } - } - else if (change.Property == SyncScrollOffsetProperty) - { - if (!TextArea.IsFocused && _scrollViewer != null) - _scrollViewer.Offset = SyncScrollOffset; - } - else if (change.Property == UseSyntaxHighlightingProperty) - { - UpdateTextMate(); - } - else if (change.Property.Name == "ActualThemeVariant" && change.NewValue != null) - { - Models.TextMateHelper.SetThemeByApp(_textMate); - } - } - - private void UpdateTextMate() - { - if (UseSyntaxHighlighting) - { - if (_textMate == null) - { - TextArea.TextView.LineTransformers.Remove(_lineStyleTransformer); - _textMate = Models.TextMateHelper.CreateForEditor(this); - TextArea.TextView.LineTransformers.Add(_lineStyleTransformer); - - if (DiffData != null) - Models.TextMateHelper.SetGrammarByFileName(_textMate, DiffData.File); - } - } - else - { - if (_textMate != null) - { - _textMate.Dispose(); - _textMate = null; - GC.Collect(); - - TextArea.TextView.Redraw(); - } - } - } - - private TextMate.Installation _textMate; - private readonly LineStyleTransformer _lineStyleTransformer = null; private ScrollViewer _scrollViewer = null; } public partial class TextDiffView : UserControl { - public static readonly StyledProperty TextDiffProperty = - AvaloniaProperty.Register(nameof(TextDiff), null); - - public Models.TextDiff TextDiff - { - get => GetValue(TextDiffProperty); - set => SetValue(TextDiffProperty, value); - } - public static readonly StyledProperty UseSideBySideDiffProperty = AvaloniaProperty.Register(nameof(UseSideBySideDiff), false); @@ -916,13 +759,20 @@ namespace SourceGit.Views set => SetValue(UseSideBySideDiffProperty, value); } - public static readonly StyledProperty SyncScrollOffsetProperty = - AvaloniaProperty.Register(nameof(SyncScrollOffset)); - - public Vector SyncScrollOffset + static TextDiffView() { - get => GetValue(SyncScrollOffsetProperty); - set => SetValue(SyncScrollOffsetProperty, value); + UseSideBySideDiffProperty.Changed.AddClassHandler((v, e) => + { + if (v.DataContext is Models.TextDiff diff) + { + diff.SyncScrollOffset = Vector.Zero; + + if (v.UseSideBySideDiff) + v.Content = new ViewModels.TwoSideTextDiff(diff); + else + v.Content = diff; + } + }); } public TextDiffView() @@ -932,6 +782,10 @@ namespace SourceGit.Views public void FillContextMenuForWorkingCopyChange(ContextMenu menu, int startLine, int endLine, bool isOldSide) { + var diff = DataContext as Models.TextDiff; + if (diff == null) + return; + var parentView = this.FindAncestorOfType(); if (parentView == null) return; @@ -951,7 +805,7 @@ namespace SourceGit.Views endLine = tmp; } - var selection = GetUnifiedSelection(startLine, endLine, isOldSide); + var selection = GetUnifiedSelection(diff, startLine, endLine, isOldSide); if (!selection.HasChanges) return; @@ -1033,17 +887,17 @@ namespace SourceGit.Views var tmpFile = Path.GetTempFileName(); if (change.WorkTree == Models.ChangeState.Untracked) { - TextDiff.GenerateNewPatchFromSelection(change, null, selection, false, tmpFile); + diff.GenerateNewPatchFromSelection(change, null, selection, false, tmpFile); } else if (!UseSideBySideDiff) { var treeGuid = new Commands.QueryStagedFileBlobGuid(ctx.RepositoryPath, change.Path).Result(); - TextDiff.GeneratePatchFromSelection(change, treeGuid, selection, false, tmpFile); + diff.GeneratePatchFromSelection(change, treeGuid, selection, false, tmpFile); } else { var treeGuid = new Commands.QueryStagedFileBlobGuid(ctx.RepositoryPath, change.Path).Result(); - TextDiff.GeneratePatchFromSelectionSingleSide(change, treeGuid, selection, false, isOldSide, tmpFile); + diff.GeneratePatchFromSelectionSingleSide(change, treeGuid, selection, false, isOldSide, tmpFile); } new Commands.Apply(ctx.RepositoryPath, tmpFile, true, "nowarn", "--cache --index").Exec(); @@ -1065,17 +919,17 @@ namespace SourceGit.Views var tmpFile = Path.GetTempFileName(); if (change.WorkTree == Models.ChangeState.Untracked) { - TextDiff.GenerateNewPatchFromSelection(change, null, selection, true, tmpFile); + diff.GenerateNewPatchFromSelection(change, null, selection, true, tmpFile); } else if (!UseSideBySideDiff) { var treeGuid = new Commands.QueryStagedFileBlobGuid(ctx.RepositoryPath, change.Path).Result(); - TextDiff.GeneratePatchFromSelection(change, treeGuid, selection, true, tmpFile); + diff.GeneratePatchFromSelection(change, treeGuid, selection, true, tmpFile); } else { var treeGuid = new Commands.QueryStagedFileBlobGuid(ctx.RepositoryPath, change.Path).Result(); - TextDiff.GeneratePatchFromSelectionSingleSide(change, treeGuid, selection, true, isOldSide, tmpFile); + diff.GeneratePatchFromSelectionSingleSide(change, treeGuid, selection, true, isOldSide, tmpFile); } new Commands.Apply(ctx.RepositoryPath, tmpFile, true, "nowarn", "--reverse").Exec(); @@ -1103,15 +957,15 @@ namespace SourceGit.Views var tmpFile = Path.GetTempFileName(); if (change.Index == Models.ChangeState.Added) { - TextDiff.GenerateNewPatchFromSelection(change, treeGuid, selection, true, tmpFile); + diff.GenerateNewPatchFromSelection(change, treeGuid, selection, true, tmpFile); } else if (!UseSideBySideDiff) { - TextDiff.GeneratePatchFromSelection(change, treeGuid, selection, true, tmpFile); + diff.GeneratePatchFromSelection(change, treeGuid, selection, true, tmpFile); } else { - TextDiff.GeneratePatchFromSelectionSingleSide(change, treeGuid, selection, true, isOldSide, tmpFile); + diff.GeneratePatchFromSelectionSingleSide(change, treeGuid, selection, true, isOldSide, tmpFile); } new Commands.Apply(ctx.RepositoryPath, tmpFile, true, "nowarn", "--cache --index --reverse").Exec(); @@ -1133,17 +987,17 @@ namespace SourceGit.Views var tmpFile = Path.GetTempFileName(); if (change.WorkTree == Models.ChangeState.Untracked) { - TextDiff.GenerateNewPatchFromSelection(change, null, selection, true, tmpFile); + diff.GenerateNewPatchFromSelection(change, null, selection, true, tmpFile); } else if (!UseSideBySideDiff) { var treeGuid = new Commands.QueryStagedFileBlobGuid(ctx.RepositoryPath, change.Path).Result(); - TextDiff.GeneratePatchFromSelection(change, treeGuid, selection, true, tmpFile); + diff.GeneratePatchFromSelection(change, treeGuid, selection, true, tmpFile); } else { var treeGuid = new Commands.QueryStagedFileBlobGuid(ctx.RepositoryPath, change.Path).Result(); - TextDiff.GeneratePatchFromSelectionSingleSide(change, treeGuid, selection, true, isOldSide, tmpFile); + diff.GeneratePatchFromSelectionSingleSide(change, treeGuid, selection, true, isOldSide, tmpFile); } new Commands.Apply(ctx.RepositoryPath, tmpFile, true, "nowarn", "--index --reverse").Exec(); @@ -1162,44 +1016,29 @@ namespace SourceGit.Views menu.Items.Add(new MenuItem() { Header = "-" }); } - protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) + protected override void OnDataContextChanged(EventArgs e) { - base.OnPropertyChanged(change); + base.OnDataContextChanged(e); - var data = TextDiff; - if (data == null) + var diff = DataContext as Models.TextDiff; + if (diff == null) { Content = null; - SyncScrollOffset = Vector.Zero; + GC.Collect(); return; - } - - if (change.Property == TextDiffProperty) - { - if (UseSideBySideDiff) - Content = new ViewModels.TwoSideTextDiff(TextDiff); - else - Content = TextDiff; - - SetCurrentValue(SyncScrollOffsetProperty, TextDiff.SyncScrollOffset); } - else if (change.Property == UseSideBySideDiffProperty) - { - if (UseSideBySideDiff) - Content = new ViewModels.TwoSideTextDiff(TextDiff); - else - Content = TextDiff; - SetCurrentValue(SyncScrollOffsetProperty, Vector.Zero); - } + if (UseSideBySideDiff) + Content = new ViewModels.TwoSideTextDiff(diff, Content as ViewModels.TwoSideTextDiff); + else + Content = diff; } - private Models.TextDiffSelection GetUnifiedSelection(int startLine, int endLine, bool isOldSide) + private Models.TextDiffSelection GetUnifiedSelection(Models.TextDiff diff, int startLine, int endLine, bool isOldSide) { var rs = new Models.TextDiffSelection(); - var diff = TextDiff; - endLine = Math.Min(endLine, TextDiff.Lines.Count); + endLine = Math.Min(endLine, diff.Lines.Count); if (Content is ViewModels.TwoSideTextDiff twoSides) { var target = isOldSide ? twoSides.Old : twoSides.New; @@ -1233,8 +1072,8 @@ namespace SourceGit.Views var firstContent = target[firstContentLine]; var endContent = target[endContentLine]; - startLine = TextDiff.Lines.IndexOf(firstContent) + 1; - endLine = TextDiff.Lines.IndexOf(endContent) + 1; + startLine = diff.Lines.IndexOf(firstContent) + 1; + endLine = diff.Lines.IndexOf(endContent) + 1; } rs.StartLine = startLine;