diff --git a/src/ViewModels/Histories.cs b/src/ViewModels/Histories.cs index 25500a4c..5a943e04 100644 --- a/src/ViewModels/Histories.cs +++ b/src/ViewModels/Histories.cs @@ -1,7 +1,7 @@ using System; using System.Collections; using System.Collections.Generic; - +using Avalonia.Collections; using Avalonia.Controls; using Avalonia.Platform.Storage; using Avalonia.VisualTree; @@ -55,6 +55,11 @@ namespace SourceGit.ViewModels set => SetProperty(ref _detailContext, value); } + public AvaloniaList IssueTrackerRules + { + get => _repo.Settings.IssueTrackerRules; + } + public Histories(Repository repo) { _repo = repo; diff --git a/src/Views/Histories.axaml b/src/Views/Histories.axaml index 510e4e6e..5c2c08ed 100644 --- a/src/Views/Histories.axaml +++ b/src/Views/Histories.axaml @@ -82,10 +82,11 @@ FontSize="10" VerticalAlignment="Center"/> - + diff --git a/src/Views/Histories.axaml.cs b/src/Views/Histories.axaml.cs index 477975ab..c87a4256 100644 --- a/src/Views/Histories.axaml.cs +++ b/src/Views/Histories.axaml.cs @@ -1,7 +1,11 @@ using System; +using System.Collections.Generic; using System.Text; + using Avalonia; +using Avalonia.Collections; using Avalonia.Controls; +using Avalonia.Controls.Documents; using Avalonia.Controls.Primitives; using Avalonia.Input; using Avalonia.Interactivity; @@ -70,6 +74,93 @@ namespace SourceGit.Views } } + public class CommitSubjectPresenter : TextBlock + { + public static readonly StyledProperty SubjectProperty = + AvaloniaProperty.Register(nameof(Subject)); + + public string Subject + { + get => GetValue(SubjectProperty); + set => SetValue(SubjectProperty, value); + } + + public static readonly StyledProperty> IssueTrackerRulesProperty = + AvaloniaProperty.Register>(nameof(IssueTrackerRules)); + + public AvaloniaList IssueTrackerRules + { + get => GetValue(IssueTrackerRulesProperty); + set => SetValue(IssueTrackerRulesProperty, value); + } + + protected override Type StyleKeyOverride => typeof(TextBlock); + + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) + { + base.OnPropertyChanged(change); + + if (change.Property == SubjectProperty || change.Property == IssueTrackerRulesProperty) + { + Inlines.Clear(); + + var subject = Subject; + if (string.IsNullOrEmpty(subject)) + return; + + var rules = IssueTrackerRules; + if (rules == null || rules.Count == 0) + { + Inlines.Add(new Run(subject)); + return; + } + + var matches = new List(); + foreach (var rule in rules) + rule.Matches(matches, subject); + + if (matches.Count == 0) + { + Inlines.Add(new Run(subject)); + return; + } + + matches.Sort((l, r) => l.Start - r.Start); + + int pos = 0; + foreach (var match in matches) + { + if (match.Start > pos) + Inlines.Add(new Run(subject.Substring(pos, match.Start - pos))); + + var link = new TextBlock(); + link.SetValue(TextProperty, subject.Substring(match.Start, match.Length)); + link.SetValue(ToolTip.TipProperty, match.URL); + link.Classes.Add("issue_link"); + link.PointerPressed += OnLinkPointerPressed; + Inlines.Add(link); + + pos = match.Start + match.Length; + } + + if (pos < subject.Length) + Inlines.Add(new Run(subject.Substring(pos))); + } + } + + private void OnLinkPointerPressed(object sender, PointerPressedEventArgs e) + { + if (sender is TextBlock text) + { + var tooltip = text.GetValue(ToolTip.TipProperty) as string; + if (!string.IsNullOrEmpty(tooltip)) + Native.OS.OpenBrowser(tooltip); + + e.Handled = true; + } + } + } + public class CommitTimeTextBlock : TextBlock { public static readonly StyledProperty ShowAsDateTimeProperty =