Skip to content

Commit

Permalink
Fix Git Extensions #8211: Incorrect EOL in diff
Browse files Browse the repository at this point in the history
	- allow the text editor to differentiate between various types of end-of-lines when displaying the EOL marker
  • Loading branch information
lhiginbotham committed Oct 10, 2021
1 parent 94b943d commit d0027f2
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 14 deletions.
10 changes: 10 additions & 0 deletions Project/Src/Document/LineManager/EolMarker.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace ICSharpCode.TextEditor.Document
{
public enum EolMarker
{
None,
Cr, // "\r"
CrLf, // "\r\n"
Lf // "\n"
}
}
28 changes: 20 additions & 8 deletions Project/Src/Document/LineManager/LineManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ private void InsertInternal(int offset, string text)
lineCollection.SetSegmentLength(segment, lineBreakOffset - segmentOffset);
var newSegment = lineCollection.InsertSegmentAfter(segment, lengthAfterInsertionPos);
segment.DelimiterLength = ds.Length;
segment.EolMarker = ds.EolMarker;

segment = newSegment;
lastDelimiterEnd = ds.Offset + ds.Length;
Expand Down Expand Up @@ -309,25 +310,35 @@ public int GetNextVisibleLineBelow(int lineNumber, int lineCount)
private DelimiterSegment NextDelimiter(string text, int offset)
{
for (var i = offset; i < text.Length; i++)
{
bool newLineSet = false;
switch (text[i])
{
case '\r':
if (i + 1 < text.Length)
if (text[i + 1] == '\n')
{
delimiterSegment.Offset = i;
delimiterSegment.Length = 2;
return delimiterSegment;
}
if (i + 1 < text.Length && text[i + 1] == '\n')
{
delimiterSegment.Offset = i;
delimiterSegment.Length = 2;
delimiterSegment.EolMarker = EolMarker.CrLf;
return delimiterSegment;
}

#if DATACONSISTENCYTEST
Debug.Assert(condition: false, "Found lone \\r, data consistency problems?");
#endif
newLineSet = true;
delimiterSegment.EolMarker = EolMarker.Cr;
goto case '\n';
case '\n':
delimiterSegment.Offset = i;
delimiterSegment.Length = 1;
if (!newLineSet)
{
delimiterSegment.EolMarker = EolMarker.Lf;
}
return delimiterSegment;
}
}
return null;
}

Expand All @@ -352,8 +363,9 @@ private void OnLineDeleted(LineEventArgs e)

private sealed class DelimiterSegment
{
internal EolMarker EolMarker = EolMarker.None;
internal int Length;
internal int Offset;
}
}
}
}
2 changes: 2 additions & 0 deletions Project/Src/Document/LineManager/LineSegment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ public sealed class LineSegment : ISegment
{
internal LineSegmentTree.Enumerator treeEntry;

public EolMarker EolMarker { get; set; }

public bool IsDeleted => !treeEntry.IsValid;

public int LineNumber => treeEntry.CurrentIndex;
Expand Down
36 changes: 30 additions & 6 deletions Project/Src/Gui/TextView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ private void PaintDocumentLine(Graphics g, int lineNumber, Rectangle lineRectang
if (TextEditorProperties.ShowEOLMarker)
{
var eolMarkerColor = textArea.Document.HighlightingStrategy.GetColorFor("EOLMarkers");
physicalXPos += DrawEOLMarker(g, eolMarkerColor.Color, selectionBeyondEOL ? bgColorBrush : backgroundBrush, physicalXPos, lineRectangle.Y);
physicalXPos += DrawEOLMarker(g, eolMarkerColor.Color, selectionBeyondEOL ? bgColorBrush : backgroundBrush, physicalXPos, lineRectangle.Y, currentLine.EolMarker);
}
else
{
Expand Down Expand Up @@ -1062,17 +1062,41 @@ private void DrawTabMarker(Graphics g, Color color, int x, int y)
DrawString(g, "\u00BB", tabMarkerColor.GetFont(TextEditorProperties.FontContainer), color, x, y);
}

private int DrawEOLMarker(Graphics g, Color color, Brush backBrush, int x, int y)
private int DrawEOLMarker(Graphics g, Color color, Brush backBrush, int x, int y, EolMarker eolMarker)
{
var eolMarkerColor = textArea.Document.HighlightingStrategy.GetColorFor("EOLMarkers");

var width = GetWidth(ch: '\u00B6', eolMarkerColor.GetFont(TextEditorProperties.FontContainer));
int eolMarkerWidth = 0;
string representation = "";

int backslashWidth = GetWidth(ch: '\\', eolMarkerColor.GetFont(TextEditorProperties.FontContainer));
int nWidth = GetWidth(ch: 'n', eolMarkerColor.GetFont(TextEditorProperties.FontContainer));
int rWidth = GetWidth(ch: 'r', eolMarkerColor.GetFont(TextEditorProperties.FontContainer));
switch (eolMarker)
{
case EolMarker.Cr:
eolMarkerWidth = backslashWidth + rWidth;
representation = "\\r";
break;
case EolMarker.CrLf:
eolMarkerWidth = backslashWidth + rWidth + backslashWidth + nWidth;
representation = "\\r\\n";
break;
case EolMarker.Lf:
eolMarkerWidth = backslashWidth + nWidth;
representation = "\\n";
break;
case EolMarker.None:
default:
return 0;
}

g.FillRectangle(
backBrush,
new RectangleF(x, y, width, FontHeight));
new RectangleF(x, y, eolMarkerWidth, FontHeight));

DrawString(g, "\u00B6", eolMarkerColor.GetFont(TextEditorProperties.FontContainer), color, x, y);
return width;
DrawString(g, representation, eolMarkerColor.GetFont(TextEditorProperties.FontContainer), color, x, y);
return eolMarkerWidth;
}

private void DrawVerticalRuler(Graphics g, Rectangle lineRectangle)
Expand Down

0 comments on commit d0027f2

Please sign in to comment.