55using System . Text . RegularExpressions ;
66using System . Threading . Tasks ;
77
8- using Avalonia . Collections ;
98using Avalonia . Controls ;
109using Avalonia . Media . Imaging ;
1110using Avalonia . Platform . Storage ;
@@ -46,7 +45,7 @@ public Models.Commit Commit
4645 }
4746 }
4847
49- public string FullMessage
48+ public Models . CommitFullMessage FullMessage
5049 {
5150 get => _fullMessage ;
5251 private set => SetProperty ( ref _fullMessage , value ) ;
@@ -85,11 +84,11 @@ public List<Models.Change> SelectedChanges
8584 }
8685 }
8786
88- public AvaloniaList < string > Children
87+ public List < string > Children
8988 {
90- get ;
91- private set ;
92- } = [ ] ;
89+ get => _children ;
90+ private set => SetProperty ( ref _children , value ) ;
91+ }
9392
9493 public string SearchChangeFilter
9594 {
@@ -109,43 +108,36 @@ public object ViewRevisionFileContent
109108 set => SetProperty ( ref _viewRevisionFileContent , value ) ;
110109 }
111110
112- public AvaloniaList < Models . CommitLink > WebLinks
111+ public List < Models . CommitLink > WebLinks
113112 {
114113 get ;
115114 private set ;
116115 } = [ ] ;
117116
118- public AvaloniaList < Models . IssueTrackerRule > IssueTrackerRules
119- {
120- get => _repo . Settings ? . IssueTrackerRules ;
121- }
122-
123117 public string RevisionFileSearchFilter
124118 {
125119 get => _revisionFileSearchFilter ;
126120 set
127121 {
128122 if ( SetProperty ( ref _revisionFileSearchFilter , value ) )
129123 {
130- RevisionFileSearchSuggestion . Clear ( ) ;
131-
132124 if ( ! string . IsNullOrEmpty ( value ) )
133125 {
134- if ( _revisionFiles . Count == 0 )
126+ if ( _revisionFiles == null )
135127 {
136128 var sha = Commit . SHA ;
137129
138130 Task . Run ( ( ) =>
139131 {
140132 var files = new Commands . QueryRevisionFileNames ( _repo . FullPath , sha ) . Result ( ) ;
133+ var filesList = new List < string > ( ) ;
134+ filesList . AddRange ( files ) ;
141135
142136 Dispatcher . UIThread . Invoke ( ( ) =>
143137 {
144138 if ( sha == Commit . SHA )
145139 {
146- _revisionFiles . Clear ( ) ;
147- _revisionFiles . AddRange ( files ) ;
148-
140+ _revisionFiles = filesList ;
149141 if ( ! string . IsNullOrEmpty ( _revisionFileSearchFilter ) )
150142 UpdateRevisionFileSearchSuggestion ( ) ;
151143 }
@@ -159,23 +151,17 @@ public string RevisionFileSearchFilter
159151 }
160152 else
161153 {
162- IsRevisionFileSearchSuggestionOpen = false ;
154+ RevisionFileSearchSuggestion = null ;
163155 GC . Collect ( ) ;
164156 }
165157 }
166158 }
167159 }
168160
169- public AvaloniaList < string > RevisionFileSearchSuggestion
161+ public List < string > RevisionFileSearchSuggestion
170162 {
171- get ;
172- private set ;
173- } = [ ] ;
174-
175- public bool IsRevisionFileSearchSuggestionOpen
176- {
177- get => _isRevisionFileSearchSuggestionOpen ;
178- set => SetProperty ( ref _isRevisionFileSearchSuggestionOpen , value ) ;
163+ get => _revisionFileSearchSuggestion ;
164+ private set => SetProperty ( ref _revisionFileSearchSuggestion , value ) ;
179165 }
180166
181167 public CommitDetail ( Repository repo )
@@ -212,23 +198,17 @@ public void Cleanup()
212198 {
213199 _repo = null ;
214200 _commit = null ;
215-
216- if ( _changes != null )
217- _changes . Clear ( ) ;
218- if ( _visibleChanges != null )
219- _visibleChanges . Clear ( ) ;
220- if ( _selectedChanges != null )
221- _selectedChanges . Clear ( ) ;
222-
201+ _changes = null ;
202+ _visibleChanges = null ;
203+ _selectedChanges = null ;
223204 _signInfo = null ;
224205 _searchChangeFilter = null ;
225206 _diffContext = null ;
226207 _viewRevisionFileContent = null ;
227208 _cancelToken = null ;
228-
229209 WebLinks . Clear ( ) ;
230- _revisionFiles . Clear ( ) ;
231- RevisionFileSearchSuggestion . Clear ( ) ;
210+ _revisionFiles = null ;
211+ _revisionFileSearchSuggestion = null ;
232212 }
233213
234214 public void NavigateTo ( string commitSHA )
@@ -251,6 +231,11 @@ public void ClearRevisionFileSearchFilter()
251231 RevisionFileSearchFilter = string . Empty ;
252232 }
253233
234+ public void CancelRevisionFileSuggestions ( )
235+ {
236+ RevisionFileSearchSuggestion = null ;
237+ }
238+
254239 public Models . Commit GetParent ( string sha )
255240 {
256241 return new Commands . QuerySingleCommit ( _repo . FullPath , sha ) . Result ( ) ;
@@ -322,7 +307,12 @@ public void ViewRevisionFile(Models.Object file)
322307 if ( commit != null )
323308 {
324309 var body = new Commands . QueryCommitFullMessage ( submoduleRoot , file . SHA ) . Result ( ) ;
325- var submodule = new Models . RevisionSubmodule ( ) { Commit = commit , FullMessage = body } ;
310+ var submodule = new Models . RevisionSubmodule ( )
311+ {
312+ Commit = commit ,
313+ FullMessage = new Models . CommitFullMessage { Message = body }
314+ } ;
315+
326316 Dispatcher . UIThread . Invoke ( ( ) => ViewRevisionFileContent = submodule ) ;
327317 }
328318 else
@@ -332,7 +322,7 @@ public void ViewRevisionFile(Models.Object file)
332322 ViewRevisionFileContent = new Models . RevisionSubmodule ( )
333323 {
334324 Commit = new Models . Commit ( ) { SHA = file . SHA } ,
335- FullMessage = string . Empty ,
325+ FullMessage = null ,
336326 } ;
337327 } ) ;
338328 }
@@ -622,23 +612,22 @@ public ContextMenu CreateRevisionFileContextMenu(Models.Object file)
622612 private void Refresh ( )
623613 {
624614 _changes = null ;
625- _revisionFiles . Clear ( ) ;
615+ _revisionFiles = null ;
626616
627617 SignInfo = null ;
628618 ViewRevisionFileContent = null ;
629- Children . Clear ( ) ;
619+ Children = null ;
630620 RevisionFileSearchFilter = string . Empty ;
631- IsRevisionFileSearchSuggestionOpen = false ;
632-
633- GC . Collect ( ) ;
621+ RevisionFileSearchSuggestion = null ;
634622
635623 if ( _commit == null )
636624 return ;
637625
638626 Task . Run ( ( ) =>
639627 {
640- var fullMessage = new Commands . QueryCommitFullMessage ( _repo . FullPath , _commit . SHA ) . Result ( ) ;
641- Dispatcher . UIThread . Invoke ( ( ) => FullMessage = fullMessage ) ;
628+ var message = new Commands . QueryCommitFullMessage ( _repo . FullPath , _commit . SHA ) . Result ( ) ;
629+ var links = ParseLinksInMessage ( message ) ;
630+ Dispatcher . UIThread . Invoke ( ( ) => FullMessage = new Models . CommitFullMessage { Message = message , Links = links } ) ;
642631 } ) ;
643632
644633 Task . Run ( ( ) =>
@@ -694,6 +683,49 @@ private void Refresh()
694683 } ) ;
695684 }
696685
686+ private List < Models . Hyperlink > ParseLinksInMessage ( string message )
687+ {
688+ var links = new List < Models . Hyperlink > ( ) ;
689+ if ( _repo . Settings . IssueTrackerRules is { Count : > 0 } rules )
690+ {
691+ foreach ( var rule in rules )
692+ rule . Matches ( links , message ) ;
693+ }
694+
695+ var shas = REG_SHA_FORMAT ( ) . Matches ( message ) ;
696+ for ( int i = 0 ; i < shas . Count ; i ++ )
697+ {
698+ var sha = shas [ i ] ;
699+ if ( ! sha . Success )
700+ continue ;
701+
702+ var hash = sha . Groups [ 1 ] . Value ;
703+ var test = new Commands . IsCommitSHA ( _repo . FullPath , hash ) . Result ( ) ;
704+ if ( ! test )
705+ continue ;
706+
707+ var start = sha . Index ;
708+ var len = sha . Length ;
709+ var intersect = false ;
710+ foreach ( var link in links )
711+ {
712+ if ( link . Intersect ( start , len ) )
713+ {
714+ intersect = true ;
715+ break ;
716+ }
717+ }
718+
719+ if ( ! intersect )
720+ links . Add ( new Models . Hyperlink ( start , len , hash , true ) ) ;
721+ }
722+
723+ if ( links . Count > 0 )
724+ links . Sort ( ( l , r ) => l . Start - r . Start ) ;
725+
726+ return links ;
727+ }
728+
697729 private void RefreshVisibleChanges ( )
698730 {
699731 if ( _changes == null )
@@ -813,11 +845,12 @@ private void UpdateRevisionFileSearchSuggestion()
813845 break ;
814846 }
815847
816- RevisionFileSearchSuggestion . Clear ( ) ;
817- RevisionFileSearchSuggestion . AddRange ( suggestion ) ;
818- IsRevisionFileSearchSuggestionOpen = suggestion . Count > 0 ;
848+ RevisionFileSearchSuggestion = suggestion ;
819849 }
820850
851+ [ GeneratedRegex ( @"\b([0-9a-fA-F]{6,40})\b" ) ]
852+ private static partial Regex REG_SHA_FORMAT ( ) ;
853+
821854 [ GeneratedRegex ( @"^version https://git-lfs.github.com/spec/v\d+\r?\noid sha256:([0-9a-f]+)\r?\nsize (\d+)[\r\n]*$" ) ]
822855 private static partial Regex REG_LFS_FORMAT ( ) ;
823856
@@ -828,17 +861,18 @@ private void UpdateRevisionFileSearchSuggestion()
828861
829862 private Repository _repo = null ;
830863 private Models . Commit _commit = null ;
831- private string _fullMessage = string . Empty ;
864+ private Models . CommitFullMessage _fullMessage = null ;
832865 private Models . CommitSignInfo _signInfo = null ;
866+ private List < string > _children = null ;
833867 private List < Models . Change > _changes = null ;
834868 private List < Models . Change > _visibleChanges = null ;
835869 private List < Models . Change > _selectedChanges = null ;
836870 private string _searchChangeFilter = string . Empty ;
837871 private DiffContext _diffContext = null ;
838872 private object _viewRevisionFileContent = null ;
839873 private Commands . Command . CancelToken _cancelToken = null ;
840- private List < string > _revisionFiles = [ ] ;
874+ private List < string > _revisionFiles = null ;
841875 private string _revisionFileSearchFilter = string . Empty ;
842- private bool _isRevisionFileSearchSuggestionOpen = false ;
876+ private List < string > _revisionFileSearchSuggestion = null ;
843877 }
844878}
0 commit comments