Skip to content

Commit fe54d30

Browse files
authored
refactor: collecting inlines for subjects (#1402)
Instead of checking intersections of inline elements yourself before adding an inline element, the new class `InlineElementCollector` prevents intersections internally. Additionally the inline elements are sorted by the new class, so it's no longer necessary to do this after adding the inline elements.
1 parent ba4c0f0 commit fe54d30

File tree

6 files changed

+109
-79
lines changed

6 files changed

+109
-79
lines changed

src/Models/Commit.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,6 @@ public void ParseDecorators(string data)
121121
public class CommitFullMessage
122122
{
123123
public string Message { get; set; } = string.Empty;
124-
public List<InlineElement> Inlines { get; set; } = [];
124+
public InlineElementCollector Inlines { get; set; } = [];
125125
}
126126
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
using System.Collections;
2+
using System.Collections.Generic;
3+
using System.Diagnostics;
4+
5+
namespace SourceGit.Models
6+
{
7+
public class InlineElementCollector : IEnumerable<InlineElement>
8+
{
9+
private readonly List<InlineElement> _implementation = [];
10+
11+
public void Clear()
12+
{
13+
_implementation.Clear();
14+
15+
AssertInvariant();
16+
}
17+
18+
public int Count => _implementation.Count;
19+
20+
public void Add(InlineElement element)
21+
{
22+
23+
var index = FindIndex(element.Start);
24+
if (!IsIntersection(index, element.Start, element.Length))
25+
_implementation.Insert(index, element);
26+
27+
AssertInvariant();
28+
}
29+
30+
[Conditional("DEBUG")]
31+
private void AssertInvariant()
32+
{
33+
if (_implementation.Count == 0)
34+
return;
35+
36+
for (var index = 1; index < _implementation.Count; index++)
37+
{
38+
var prev = _implementation[index - 1];
39+
var curr = _implementation[index];
40+
41+
Debug.Assert(prev.Start + prev.Length <= curr.Start);
42+
}
43+
}
44+
45+
public InlineElement Lookup(int position)
46+
{
47+
var index = FindIndex(position);
48+
return IsIntersection(index, position, 1)
49+
? _implementation[index]
50+
: null;
51+
}
52+
53+
private int FindIndex(int start)
54+
{
55+
var index = 0;
56+
while (index < _implementation.Count && _implementation[index].Start <= start)
57+
index++;
58+
59+
return index;
60+
}
61+
62+
private bool IsIntersection(int index, int start, int length)
63+
{
64+
if (index > 0)
65+
{
66+
var predecessor = _implementation[index - 1];
67+
if (predecessor.Start + predecessor.Length >= start)
68+
return true;
69+
}
70+
71+
if (index < _implementation.Count)
72+
{
73+
var successor = _implementation[index];
74+
if (start + length >= successor.Start)
75+
return true;
76+
}
77+
78+
return false;
79+
}
80+
81+
public IEnumerator<InlineElement> GetEnumerator() => _implementation.GetEnumerator();
82+
83+
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
84+
}
85+
}

src/Models/IssueTrackerRule.cs

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
using System.Collections.Generic;
2-
using System.Text.RegularExpressions;
1+
using System.Text.RegularExpressions;
32

43
using CommunityToolkit.Mvvm.ComponentModel;
54

@@ -46,7 +45,7 @@ public string URLTemplate
4645
set => SetProperty(ref _urlTemplate, value);
4746
}
4847

49-
public void Matches(List<InlineElement> outs, string message)
48+
public void Matches(InlineElementCollector outs, string message)
5049
{
5150
if (_regex == null || string.IsNullOrEmpty(_urlTemplate))
5251
return;
@@ -60,18 +59,6 @@ public void Matches(List<InlineElement> outs, string message)
6059

6160
var start = match.Index;
6261
var len = match.Length;
63-
var intersect = false;
64-
foreach (var exist in outs)
65-
{
66-
if (exist.Intersect(start, len))
67-
{
68-
intersect = true;
69-
break;
70-
}
71-
}
72-
73-
if (intersect)
74-
continue;
7562

7663
var link = _urlTemplate;
7764
for (var j = 1; j < match.Groups.Count; j++)

src/ViewModels/CommitDetail.cs

Lines changed: 2 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -620,9 +620,9 @@ private void Refresh()
620620
});
621621
}
622622

623-
private List<Models.InlineElement> ParseInlinesInMessage(string message)
623+
private Models.InlineElementCollector ParseInlinesInMessage(string message)
624624
{
625-
var inlines = new List<Models.InlineElement>();
625+
var inlines = new Models.InlineElementCollector();
626626
if (_repo.Settings.IssueTrackerRules is { Count: > 0 } rules)
627627
{
628628
foreach (var rule in rules)
@@ -638,18 +638,6 @@ private void Refresh()
638638

639639
var start = match.Index;
640640
var len = match.Length;
641-
var intersect = false;
642-
foreach (var link in inlines)
643-
{
644-
if (link.Intersect(start, len))
645-
{
646-
intersect = true;
647-
break;
648-
}
649-
}
650-
651-
if (intersect)
652-
continue;
653641

654642
var url = message.Substring(start, len);
655643
if (Uri.IsWellFormedUriString(url, UriKind.Absolute))
@@ -665,28 +653,13 @@ private void Refresh()
665653

666654
var start = match.Index;
667655
var len = match.Length;
668-
var intersect = false;
669-
foreach (var link in inlines)
670-
{
671-
if (link.Intersect(start, len))
672-
{
673-
intersect = true;
674-
break;
675-
}
676-
}
677-
678-
if (intersect)
679-
continue;
680656

681657
var sha = match.Groups[1].Value;
682658
var isCommitSHA = new Commands.IsCommitSHA(_repo.FullPath, sha).Result();
683659
if (isCommitSHA)
684660
inlines.Add(new Models.InlineElement(Models.InlineElementType.CommitSHA, start, len, sha));
685661
}
686662

687-
if (inlines.Count > 0)
688-
inlines.Sort((l, r) => l.Start - r.Start);
689-
690663
return inlines;
691664
}
692665

src/Views/CommitMessagePresenter.cs

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -95,26 +95,11 @@ protected override void OnPointerMoved(PointerEventArgs e)
9595
point = new Point(x, y);
9696

9797
var pos = TextLayout.HitTestPoint(point).TextPosition;
98-
foreach (var link in links)
99-
{
100-
if (!link.Intersect(pos, 1))
101-
continue;
102-
103-
if (link == _lastHover)
104-
return;
105-
106-
SetCurrentValue(CursorProperty, Cursor.Parse("Hand"));
107-
108-
_lastHover = link;
109-
if (link.Type == Models.InlineElementType.Link)
110-
ToolTip.SetTip(this, link.Link);
111-
else
112-
ProcessHoverCommitLink(link);
113-
114-
return;
115-
}
11698

117-
ClearHoveredIssueLink();
99+
if (links.Lookup(pos) is { } link)
100+
SetHoveredIssueLink(link);
101+
else
102+
ClearHoveredIssueLink();
118103
}
119104
}
120105

@@ -291,6 +276,20 @@ private void ProcessHoverCommitLink(Models.InlineElement link)
291276
}
292277
}
293278

279+
private void SetHoveredIssueLink(Models.InlineElement link)
280+
{
281+
if (link == _lastHover)
282+
return;
283+
284+
SetCurrentValue(CursorProperty, Cursor.Parse("Hand"));
285+
286+
_lastHover = link;
287+
if (link.Type == Models.InlineElementType.Link)
288+
ToolTip.SetTip(this, link.Link);
289+
else
290+
ProcessHoverCommitLink(link);
291+
}
292+
294293
private void ClearHoveredIssueLink()
295294
{
296295
if (_lastHover != null)

src/Views/CommitSubjectPresenter.cs

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -167,27 +167,13 @@ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs chang
167167

168168
var start = match.Index;
169169
var len = match.Length;
170-
var intersect = false;
171-
foreach (var exist in _elements)
172-
{
173-
if (exist.Intersect(start, len))
174-
{
175-
intersect = true;
176-
break;
177-
}
178-
}
179-
180-
if (intersect)
181-
continue;
182-
183170
_elements.Add(new Models.InlineElement(Models.InlineElementType.Code, start, len, string.Empty));
184171
}
185172

186173
var rules = IssueTrackerRules ?? [];
187174
foreach (var rule in rules)
188175
rule.Matches(_elements, subject);
189176

190-
_elements.Sort((l, r) => l.Start - r.Start);
191177
_needRebuildInlines = true;
192178
InvalidateVisual();
193179
}
@@ -364,7 +350,7 @@ public Inline(double x, FormattedText text, Models.InlineElement elem)
364350
}
365351
}
366352

367-
private List<Models.InlineElement> _elements = [];
353+
private Models.InlineElementCollector _elements = [];
368354
private List<Inline> _inlines = [];
369355
private Models.InlineElement _lastHover = null;
370356
private bool _needRebuildInlines = false;

0 commit comments

Comments
 (0)