Skip to content

Commit

Permalink
Optimize WPF components to get lines in viewport and by query finding
Browse files Browse the repository at this point in the history
  • Loading branch information
kingcean authored and mmanela committed Jan 22, 2025
1 parent cdc1260 commit 4aa953b
Show file tree
Hide file tree
Showing 11 changed files with 590 additions and 183 deletions.
2 changes: 1 addition & 1 deletion DiffPlex.App/DiffPlex.App.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
<None Remove="DiffTextView.xaml" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\DiffPlex.Windows\Internals.cs" Link="Internals.cs" />
<Compile Include="..\DiffPlex.Windows\Helper.cs" Link="Helper.cs" />
<Compile Include="..\DiffPlex.Wpf.Demo\TestData.cs" Link="TestData.cs" />
</ItemGroup>

Expand Down
82 changes: 71 additions & 11 deletions DiffPlex.Windows/Converters.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,13 @@ namespace DiffPlex.UI;
/// <summary>
/// The base converter for change type.
/// </summary>
public class DiffChangeTypeConverter : IValueConverter
/// <param name="defaultChangeType">The default chagne type.</param>
public class DiffChangeTypeConverter(ChangeType defaultChangeType) : IValueConverter
{
/// <summary>
/// Initializes a new instance of the DiffChangeTypeConverter class.
/// </summary>
/// <param name="defaultChangeType">The default chagne type.</param>
public DiffChangeTypeConverter(ChangeType defaultChangeType)
{
ModifyChangeType = defaultChangeType;
}

/// <summary>
/// Gets or sets the default change type for modify.
/// </summary>
public ChangeType ModifyChangeType { get; set; }
public ChangeType ModifyChangeType { get; set; } = defaultChangeType;

/// <summary>
/// Gets or sets the default change type for modify.
Expand Down Expand Up @@ -129,3 +121,71 @@ public NewDiffChangeTypeConverter()
{
}
}

/// <summary>
/// The base converter for change type.
/// </summary>
/// <param name="defaultChangeType">The default chagne type.</param>
public class DiffTextHighlighterConverter(ChangeType defaultChangeType) : IValueConverter
{
/// <summary>
/// Gets or sets the default change type for modify.
/// </summary>
public ChangeType ModifyChangeType { get; set; } = defaultChangeType;

/// <summary>
/// Gets or sets the foreground.
/// </summary>
public Brush Foreground { get; set; }

/// <summary>
/// Converts a source to target.
/// </summary>
public object Convert(object value, Type targetType, object parameter, string language)
{
if (value is FrameworkElement element) value = element.DataContext;
if (value is not List<DiffPiece> sub)
{
if (value is DiffPiece p) sub = p.SubPieces;
else return null;
}

return InternalUtilities.GetTextHighlighter(sub, ModifyChangeType, Foreground ?? (parameter as Brush));
}

/// <summary>
/// Converts the source back.
/// </summary>
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
return null;
}
}

/// <summary>
/// The diff change type converter for old text.
/// </summary>
public class DeletedDiffTextHighlighterConverter : DiffTextHighlighterConverter
{
/// <summary>
/// Initializes a new instance of the DeletedDiffTextHighlighterConverter class.
/// </summary>
public DeletedDiffTextHighlighterConverter()
: base(ChangeType.Deleted)
{
}
}

/// <summary>
/// The diff change type converter for new text.
/// </summary>
public class InsertedDiffTextHighlighterConverter : DiffTextHighlighterConverter
{
/// <summary>
/// Initializes a new instance of the InsertedDiffTextHighlighterConverter class.
/// </summary>
public InsertedDiffTextHighlighterConverter()
: base(ChangeType.Inserted)
{
}
}
2 changes: 1 addition & 1 deletion DiffPlex.Windows/DiffPlex.Windows.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.6.241114003" />
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26100.1742" />
<PackageReference Include="Trivial.WindowsKit" Version="9.0.0" />
<PackageReference Include="Trivial.WindowsKit" Version="9.2.0" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="All" />
</ItemGroup>

Expand Down
63 changes: 60 additions & 3 deletions DiffPlex.Windows/DiffTextView.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -545,13 +545,13 @@ public void ScrollNextDiffIntoView()
/// </summary>
/// <param name="q">The string to seek.</param>
/// <returns>All line numbers with the given string.</returns>
public IEnumerable<int> Find(string q)
public IEnumerable<DiffTextViewInfo> Find(string q)
{
var list = GetActiveListView();
foreach (var item in list.Items)
{
if (!GetItemFromList(list, item, out var container, out var model)) continue;
if (model.Contains(q)) yield return model.LineNumber;
if (item is not BaseDiffTextViewModel m) continue;
if (m.Contains(q)) yield return m.ToInfo();
}
}

Expand All @@ -577,6 +577,28 @@ public bool Focus(int lineNumber, FocusState focusState)
}
}

/// <summary>
/// Attempts to set focus to a specific line.
/// </summary>
/// <param name="info">The line.</param>
/// <param name="focusState">How this element obtains focus.</param>
/// <returns>true if keyboard focus and logical focus were set to the specific line; otherwise, false, if only logical focus was set to the specific line, or if the call to this method did not force the focus to change.</returns>
public bool Focus(DiffTextViewInfo info, FocusState focusState)
{
if (!info.Position.HasValue) return false;
switch (info.ViewType)
{
case DiffTextViewType.Inline:
return FocusInUnifiedView(info.Position.Value, focusState);
case DiffTextViewType.Left:
return FocusInSplitView(info.Position.Value, true, focusState);
case DiffTextViewType.Right:
return FocusInSplitView(info.Position.Value, false, focusState);
}

return false;
}

/// <summary>
/// Attempts to set focus to a specific line.
/// </summary>
Expand Down Expand Up @@ -636,6 +658,41 @@ public void ScrollIntoView(int lineNumber, ScrollIntoViewAlignment alignment = S
}
}

/// <summary>
/// Scrolls the list to bring the specified line number into view with the specified alignment.
/// </summary>
/// <param name="info">The line info.</param>
/// <param name="alignment">An enumeration value that specifies whether the item uses default or leading alignment.</param>
public void ScrollIntoView(DiffTextViewInfo info, ScrollIntoViewAlignment alignment = ScrollIntoViewAlignment.Default)
{
if (info.Position == null) return;
var lineNumber = info.Position.Value;
switch (info.ViewType)
{
case DiffTextViewType.Inline:
{
var line = inlines.FirstOrDefault(ele => ele?.Position == lineNumber);
if (line is null) return;
UnifiedElement.ScrollIntoView(line, alignment);
break;
}
case DiffTextViewType.Left:
{
var line = sideBySide.FirstOrDefault(ele => ele?.Left?.Position == lineNumber);
if (line is null) return;
SplitElement.ScrollIntoView(line, alignment);
break;
}
case DiffTextViewType.Right:
{
var line = sideBySide.FirstOrDefault(ele => ele?.Right?.Position == lineNumber);
if (line is null) return;
SplitElement.ScrollIntoView(line, alignment);
break;
}
}
}

/// <summary>
/// Collapses unchanged sections.
/// </summary>
Expand Down
136 changes: 0 additions & 136 deletions DiffPlex.Windows/Internals.cs → DiffPlex.Windows/Helper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -166,139 +166,3 @@ public static async Task<string> TryGetFileTextAsync(Window window, Action<Excep
return null;
}
}

/// <summary>
/// The base view model for diff text.
/// </summary>
internal abstract class BaseDiffTextViewModel
{
/// <summary>
/// Get or set the line number.
/// </summary>
public int LineNumber { get; set; }

/// <summary>
/// Gets a value indicating whether the line is unchanged.
/// </summary>
public abstract bool IsUnchanged { get; }

/// <summary>
/// Gets a value indicating whether the current line is null.
/// </summary>
public abstract bool IsNullLine { get; }

/// <summary>
/// Returns a value indicating whether a specified substring occurs within the text in this view model.
/// </summary>
/// <param name="q">The string to seek.</param>
/// <returns>true if the value parameter occurs within the text in this view model; otherwise, false.</returns>
public abstract bool Contains(string q);
}

/// <summary>
/// The diff text view model of split mode.
/// </summary>
internal class DiffTextViewModel : BaseDiffTextViewModel
{
public DiffTextViewModel()
{
}

public DiffTextViewModel(int number, DiffPiece left, DiffPiece right)
: this(number, left, right, null)
{
}

public DiffTextViewModel(int number, DiffPiece left, DiffPiece right, DiffTextViewReference reference)
{
LineNumber = number;
Left = left;
Right = right;
Reference = reference;
}

public DiffPiece Left { get; private set; }

public DiffPiece Right { get; private set; }

public DiffTextViewReference Reference { get; private set; }

public string LeftText => Left?.Text;

public string RightText => Right?.Text;

/// <inheritdoc />
public override bool IsUnchanged => Right?.Type == ChangeType.Unchanged;

/// <inheritdoc />
public override bool IsNullLine => Right is null;

public IEnumerable<TextHighlighter> GetLeftHighlighter()
=> InternalUtilities.GetTextHighlighter(Left?.SubPieces, ChangeType.Deleted, Reference?.Element?.Foreground);

public IEnumerable<TextHighlighter> GetRightHighlighter()
=> InternalUtilities.GetTextHighlighter(Right?.SubPieces, ChangeType.Inserted, Reference?.Element?.Foreground);

/// <inheritdoc />
public override bool Contains(string q)
{
if (string.IsNullOrEmpty(q)) return false;
var v = Right?.Text;
if (v != null && v.Contains(q)) return true;
v = Left?.Text;
if (v != null && v.Contains(q)) return true;
return false;
}
}

/// <summary>
/// The diff text view model of unified mode.
/// </summary>
internal class InlineDiffTextViewModel : BaseDiffTextViewModel
{
public InlineDiffTextViewModel()
{
}

public InlineDiffTextViewModel(int number, DiffPiece line)
: this(number, line, null)
{
}

public InlineDiffTextViewModel(int number, DiffPiece line, DiffTextViewReference reference)
{
LineNumber = number;
Line = line;
Reference = reference;
}

public DiffPiece Line { get; private set; }

public string Text => Line?.Text;

public int? Position => Line?.Position;

public DiffTextViewReference Reference { get; private set; }

/// <inheritdoc />
public override bool IsUnchanged => Line?.Type == ChangeType.Unchanged;

/// <inheritdoc />
public override bool IsNullLine => Line is null;

public IEnumerable<TextHighlighter> GetTextHighlighter()
=> InternalUtilities.GetTextHighlighter(Line?.SubPieces, ChangeType.Deleted, Reference?.Element?.Foreground);

/// <inheritdoc />
public override bool Contains(string q)
{
if (string.IsNullOrEmpty(q)) return false;
var v = Line?.Text;
return v != null && v.Contains(q);
}
}

internal class DiffTextViewReference(DiffTextView element)
{
public DiffTextView Element { get; set; } = element;
}
Loading

0 comments on commit 4aa953b

Please sign in to comment.