@@ -32,6 +32,8 @@ public override void Render(DrawingContext context)
3232 if ( _editor . BlameData == null )
3333 return ;
3434
35+ _shaHitBoxes . Clear ( ) ;
36+
3537 var view = TextView ;
3638 if ( view is { VisualLinesValid : true } )
3739 {
@@ -51,8 +53,23 @@ public override void Render(DrawingContext context)
5153
5254 var info = _editor . BlameData . LineInfos [ lineNumber - 1 ] ;
5355 var x = 8.0 ;
56+ var lineTop = line . GetTextLineVisualYPosition ( line . TextLines [ 0 ] , VisualYPosition . LineTop ) - view . VerticalOffset ;
5457 var y = line . GetTextLineVisualYPosition ( line . TextLines [ 0 ] , VisualYPosition . LineMiddle ) - view . VerticalOffset ;
55- if ( ! info . IsFirstInGroup )
58+
59+ var forceDrawFirstVisualLine = lineTop < 0 ;
60+ if ( forceDrawFirstVisualLine )
61+ {
62+ // When there is enough space (the 2nd visual line is not a group leader),
63+ // move the line to make sure it is not cropped
64+ if ( lineNumber < _editor . BlameData . LineInfos . Count )
65+ {
66+ var nextLineInfo = _editor . BlameData . LineInfos [ lineNumber ] ;
67+ if ( ! nextLineInfo . IsFirstInGroup )
68+ y = lineHeight * 0.5 ;
69+ }
70+ }
71+
72+ if ( ! info . IsFirstInGroup && ! forceDrawFirstVisualLine )
5673 continue ;
5774
5875 var shaLink = new FormattedText (
@@ -62,9 +79,8 @@ public override void Render(DrawingContext context)
6279 typeface ,
6380 _editor . FontSize ,
6481 Brushes . DarkOrange ) ;
65- var shaLinkTop = y - shaLink . Height * 0.5 ;
66- var underlineY = PixelSnapHelpers . PixelAlign ( y + shaLink . Height * 0.5 + 0.5 , pixelHeight ) ;
67- context . DrawText ( shaLink , new Point ( x , shaLinkTop ) ) ;
82+ var shaLinkMiddle = y - shaLink . Height * 0.5 ;
83+ context . DrawText ( shaLink , new Point ( x , shaLinkMiddle ) ) ;
6884 x += shaLink . Width + 8 ;
6985
7086 var author = new FormattedText (
@@ -89,10 +105,10 @@ public override void Render(DrawingContext context)
89105 context . DrawText ( time , new Point ( width - time . Width - 8 , timeTop ) ) ;
90106
91107 if ( lineNumber > 1 )
92- {
93- var lineTop = line . GetTextLineVisualYPosition ( line . TextLines [ 0 ] , VisualYPosition . LineTop ) - view . VerticalOffset ;
94108 context . DrawLine ( new Pen ( _editor . BorderBrush , 1 ) , new Point ( 0 , lineTop ) , new Point ( Bounds . Width , lineTop ) ) ;
95- }
109+
110+ var hitBox = new HitBox ( new Rect ( 8 , lineTop , shaLink . Width , lineHeight ) , info ) ;
111+ _shaHitBoxes . Add ( hitBox ) ;
96112 }
97113 }
98114 }
@@ -152,95 +168,48 @@ protected override void OnPointerMoved(PointerEventArgs e)
152168 {
153169 base . OnPointerMoved ( e ) ;
154170
155- var view = TextView ;
156- if ( ! e . Handled && view is { VisualLinesValid : true } )
157- {
158- var pos = e . GetPosition ( this ) ;
159- var typeface = view . CreateTypeface ( ) ;
160- var lineHeight = view . DefaultLineHeight ;
171+ if ( DataContext is not ViewModels . Blame blame )
172+ return ;
161173
162- foreach ( var line in view . VisualLines )
174+ var pos = e . GetPosition ( this ) ;
175+ foreach ( var box in _shaHitBoxes )
176+ {
177+ if ( box . Rect . Contains ( pos ) )
163178 {
164- if ( line . IsDisposed || line . FirstDocumentLine == null || line . FirstDocumentLine . IsDeleted )
165- continue ;
166-
167- var lineNumber = line . FirstDocumentLine . LineNumber ;
168- if ( lineNumber > _editor . BlameData . LineInfos . Count )
169- break ;
170-
171- var info = _editor . BlameData . LineInfos [ lineNumber - 1 ] ;
172- var y = line . GetTextLineVisualYPosition ( line . TextLines [ 0 ] , VisualYPosition . LineTop ) - view . VerticalOffset ;
173- var shaLink = new FormattedText (
174- info . CommitSHA ,
175- CultureInfo . CurrentCulture ,
176- FlowDirection . LeftToRight ,
177- typeface ,
178- _editor . FontSize ,
179- Brushes . DarkOrange ) ;
180-
181- var rect = new Rect ( 8 , y , shaLink . Width , lineHeight ) ;
182- if ( rect . Contains ( pos ) )
183- {
184- Cursor = Cursor . Parse ( "Hand" ) ;
185-
186- if ( DataContext is ViewModels . Blame blame )
187- {
188- var msg = blame . GetCommitMessage ( info . CommitSHA ) ;
189- ToolTip . SetTip ( this , msg ) ;
190- }
191-
192- return ;
193- }
179+ Cursor = Cursor . Parse ( "Hand" ) ;
180+ var msg = blame . GetCommitMessage ( box . LineInfo . CommitSHA ) ;
181+ ToolTip . SetTip ( this , msg ) ;
182+ return ;
194183 }
195-
196- Cursor = Cursor . Default ;
197- ToolTip . SetTip ( this , null ) ;
198184 }
185+
186+ Cursor = Cursor . Default ;
187+ ToolTip . SetTip ( this , null ) ;
199188 }
200189
201190 protected override void OnPointerPressed ( PointerPressedEventArgs e )
202191 {
203192 base . OnPointerPressed ( e ) ;
204193
205- var view = TextView ;
206- if ( ! e . Handled && e . GetCurrentPoint ( this ) . Properties . IsLeftButtonPressed && view is { VisualLinesValid : true } )
207- {
208- var pos = e . GetPosition ( this ) ;
209- var typeface = view . CreateTypeface ( ) ;
194+ if ( DataContext is not ViewModels . Blame blame )
195+ return ;
210196
211- foreach ( var line in view . VisualLines )
197+ var pos = e . GetPosition ( this ) ;
198+ foreach ( var box in _shaHitBoxes )
199+ {
200+ if ( box . Rect . Contains ( pos ) )
212201 {
213- if ( line . IsDisposed || line . FirstDocumentLine == null || line . FirstDocumentLine . IsDeleted )
214- continue ;
215-
216- var lineNumber = line . FirstDocumentLine . LineNumber ;
217- if ( lineNumber > _editor . BlameData . LineInfos . Count )
218- break ;
219-
220- var info = _editor . BlameData . LineInfos [ lineNumber - 1 ] ;
221- var y = line . GetTextLineVisualYPosition ( line . TextLines [ 0 ] , VisualYPosition . TextTop ) - view . VerticalOffset ;
222- var shaLink = new FormattedText (
223- info . CommitSHA ,
224- CultureInfo . CurrentCulture ,
225- FlowDirection . LeftToRight ,
226- typeface ,
227- _editor . FontSize ,
228- Brushes . DarkOrange ) ;
229-
230- var rect = new Rect ( 8 , y , shaLink . Width , shaLink . Height ) ;
231- if ( rect . Contains ( pos ) )
232- {
233- if ( DataContext is ViewModels . Blame blame )
234- blame . NavigateToCommit ( info . File , info . CommitSHA ) ;
235-
236- e . Handled = true ;
237- break ;
238- }
202+ blame . NavigateToCommit ( box . LineInfo . File , box . LineInfo . CommitSHA ) ;
203+ e . Handled = true ;
204+ break ;
239205 }
240206 }
241207 }
242208
209+ private record HitBox ( Rect Rect , Models . BlameLineInfo LineInfo ) ;
210+
243211 private readonly BlameTextEditor _editor = null ;
212+ private List < HitBox > _shaHitBoxes = [ ] ;
244213 }
245214
246215 public class VerticalSeparatorMargin : AbstractMargin
0 commit comments