diff --git a/ICSharpCode.AvalonEdit/Editing/Caret.cs b/ICSharpCode.AvalonEdit/Editing/Caret.cs
index d8df683..2149bdf 100644
--- a/ICSharpCode.AvalonEdit/Editing/Caret.cs
+++ b/ICSharpCode.AvalonEdit/Editing/Caret.cs
@@ -281,14 +281,14 @@ namespace ICSharpCode.AvalonEdit.Editing
int caretOffset = textView.Document.GetOffset(position);
int firstDocumentLineOffset = visualLine.FirstDocumentLine.Offset;
- position.VisualColumn = visualLine.ValidateVisualColumn(position, textArea.Options.EnableVirtualSpace);
+ position.VisualColumn = visualLine.ValidateVisualColumn(position, textArea.Selection.EnableVirtualSpace);
// search possible caret positions
- int newVisualColumnForwards = visualLine.GetNextCaretPosition(position.VisualColumn - 1, LogicalDirection.Forward, CaretPositioningMode.Normal);
+ int newVisualColumnForwards = visualLine.GetNextCaretPosition(position.VisualColumn - 1, LogicalDirection.Forward, CaretPositioningMode.Normal, textArea.Selection.EnableVirtualSpace);
// If position.VisualColumn was valid, we're done with validation.
if (newVisualColumnForwards != position.VisualColumn) {
// also search backwards so that we can pick the better match
- int newVisualColumnBackwards = visualLine.GetNextCaretPosition(position.VisualColumn + 1, LogicalDirection.Backward, CaretPositioningMode.Normal);
+ int newVisualColumnBackwards = visualLine.GetNextCaretPosition(position.VisualColumn + 1, LogicalDirection.Backward, CaretPositioningMode.Normal, textArea.Selection.EnableVirtualSpace);
if (newVisualColumnForwards < 0 && newVisualColumnBackwards < 0)
throw ThrowUtil.NoValidCaretPosition();
diff --git a/ICSharpCode.AvalonEdit/Editing/CaretNavigationCommandHandler.cs b/ICSharpCode.AvalonEdit/Editing/CaretNavigationCommandHandler.cs
index 5d458d9..4d995f5 100644
--- a/ICSharpCode.AvalonEdit/Editing/CaretNavigationCommandHandler.cs
+++ b/ICSharpCode.AvalonEdit/Editing/CaretNavigationCommandHandler.cs
@@ -180,7 +180,7 @@ namespace ICSharpCode.AvalonEdit.Editing
#region Home/End
static void MoveCaretToStartOfLine(TextArea textArea, VisualLine visualLine)
{
- int newVC = visualLine.GetNextCaretPosition(-1, LogicalDirection.Forward, CaretPositioningMode.WordStart);
+ int newVC = visualLine.GetNextCaretPosition(-1, LogicalDirection.Forward, CaretPositioningMode.WordStart, textArea.Selection.EnableVirtualSpace);
if (newVC < 0)
throw ThrowUtil.NoValidCaretPosition();
// when the caret is already at the start of the text, jump to start before whitespace
@@ -201,7 +201,7 @@ namespace ICSharpCode.AvalonEdit.Editing
#region By-character / By-word movement
static void MoveCaretRight(TextArea textArea, TextViewPosition caretPosition, VisualLine visualLine, CaretPositioningMode mode)
{
- int pos = visualLine.GetNextCaretPosition(caretPosition.VisualColumn, LogicalDirection.Forward, mode);
+ int pos = visualLine.GetNextCaretPosition(caretPosition.VisualColumn, LogicalDirection.Forward, mode, textArea.Selection.EnableVirtualSpace);
if (pos >= 0) {
SetCaretPosition(textArea, pos, visualLine.GetRelativeOffset(pos) + visualLine.FirstDocumentLine.Offset);
} else {
@@ -209,7 +209,7 @@ namespace ICSharpCode.AvalonEdit.Editing
DocumentLine nextDocumentLine = visualLine.LastDocumentLine.NextLine;
if (nextDocumentLine != null) {
VisualLine nextLine = textArea.TextView.GetOrConstructVisualLine(nextDocumentLine);
- pos = nextLine.GetNextCaretPosition(-1, LogicalDirection.Forward, mode);
+ pos = nextLine.GetNextCaretPosition(-1, LogicalDirection.Forward, mode, textArea.Selection.EnableVirtualSpace);
if (pos < 0)
throw ThrowUtil.NoValidCaretPosition();
SetCaretPosition(textArea, pos, nextLine.GetRelativeOffset(pos) + nextLine.FirstDocumentLine.Offset);
@@ -223,7 +223,7 @@ namespace ICSharpCode.AvalonEdit.Editing
static void MoveCaretLeft(TextArea textArea, TextViewPosition caretPosition, VisualLine visualLine, CaretPositioningMode mode)
{
- int pos = visualLine.GetNextCaretPosition(caretPosition.VisualColumn, LogicalDirection.Backward, mode);
+ int pos = visualLine.GetNextCaretPosition(caretPosition.VisualColumn, LogicalDirection.Backward, mode, textArea.Selection.EnableVirtualSpace);
if (pos >= 0) {
SetCaretPosition(textArea, pos, visualLine.GetRelativeOffset(pos) + visualLine.FirstDocumentLine.Offset);
} else {
@@ -231,7 +231,7 @@ namespace ICSharpCode.AvalonEdit.Editing
DocumentLine previousDocumentLine = visualLine.FirstDocumentLine.PreviousLine;
if (previousDocumentLine != null) {
VisualLine previousLine = textArea.TextView.GetOrConstructVisualLine(previousDocumentLine);
- pos = previousLine.GetNextCaretPosition(previousLine.VisualLength + 1, LogicalDirection.Backward, mode);
+ pos = previousLine.GetNextCaretPosition(previousLine.VisualLength + 1, LogicalDirection.Backward, mode, textArea.Selection.EnableVirtualSpace);
if (pos < 0)
throw ThrowUtil.NoValidCaretPosition();
SetCaretPosition(textArea, pos, previousLine.GetRelativeOffset(pos) + previousLine.FirstDocumentLine.Offset);
@@ -307,7 +307,7 @@ namespace ICSharpCode.AvalonEdit.Editing
}
if (targetLine != null) {
double yPos = targetVisualLine.GetTextLineVisualYPosition(targetLine, VisualYPosition.LineMiddle);
- int newVisualColumn = targetVisualLine.GetVisualColumn(new Point(xPos, yPos));
+ int newVisualColumn = targetVisualLine.GetVisualColumn(new Point(xPos, yPos), textArea.Selection.EnableVirtualSpace);
SetCaretPosition(textArea, targetVisualLine, targetLine, newVisualColumn, false);
textArea.Caret.DesiredXPos = xPos;
}
diff --git a/ICSharpCode.AvalonEdit/Editing/EditingCommandHandler.cs b/ICSharpCode.AvalonEdit/Editing/EditingCommandHandler.cs
index dbf3741..18b8591 100644
--- a/ICSharpCode.AvalonEdit/Editing/EditingCommandHandler.cs
+++ b/ICSharpCode.AvalonEdit/Editing/EditingCommandHandler.cs
@@ -398,7 +398,7 @@ namespace ICSharpCode.AvalonEdit.Editing
if (textArea.ReadOnlySectionProvider.CanInsert(currentLine.Offset)) {
textArea.Document.Insert(currentLine.Offset, text);
}
- } else if (rectangular && textArea.Selection.IsEmpty) {
+ } else if (rectangular && textArea.Selection.IsEmpty && !(textArea.Selection is RectangleSelection)) {
if (!RectangleSelection.PerformRectangularPaste(textArea, textArea.Caret.Position, text, false))
textArea.ReplaceSelectionWithText(text);
} else {
diff --git a/ICSharpCode.AvalonEdit/Editing/RectangleSelection.cs b/ICSharpCode.AvalonEdit/Editing/RectangleSelection.cs
index 341befb..c201780 100644
--- a/ICSharpCode.AvalonEdit/Editing/RectangleSelection.cs
+++ b/ICSharpCode.AvalonEdit/Editing/RectangleSelection.cs
@@ -8,6 +8,7 @@ using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Media.TextFormatting;
+
using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.AvalonEdit.Rendering;
using ICSharpCode.AvalonEdit.Utils;
@@ -42,8 +43,8 @@ namespace ICSharpCode.AvalonEdit.Editing
InitDocument();
this.startLine = start.Line;
this.endLine = end.Line;
- this.startXPos = GetXPos(start);
- this.endXPos = GetXPos(end);
+ this.startXPos = GetXPos(textArea, start);
+ this.endXPos = GetXPos(textArea, end);
this.startOffset = document.GetOffset(start);
this.endOffset = document.GetOffset(end);
CalculateSegments();
@@ -56,7 +57,7 @@ namespace ICSharpCode.AvalonEdit.Editing
this.startLine = startLine;
this.endLine = end.Line;
this.startXPos = startXPos;
- this.endXPos = GetXPos(end);
+ this.endXPos = GetXPos(textArea, end);
this.startOffset = startOffset;
this.endOffset = document.GetOffset(end);
CalculateSegments();
@@ -68,19 +69,26 @@ namespace ICSharpCode.AvalonEdit.Editing
InitDocument();
this.startLine = start.Line;
this.endLine = endLine;
- this.startXPos = GetXPos(start);
+ this.startXPos = GetXPos(textArea, start);
this.endXPos = endXPos;
this.startOffset = document.GetOffset(start);
this.endOffset = endOffset;
CalculateSegments();
}
- double GetXPos(TextViewPosition pos)
+ static double GetXPos(TextArea textArea, TextViewPosition pos)
{
- DocumentLine documentLine = document.GetLineByNumber(pos.Line);
+ DocumentLine documentLine = textArea.Document.GetLineByNumber(pos.Line);
VisualLine visualLine = textArea.TextView.GetOrConstructVisualLine(documentLine);
- TextLine textLine = visualLine.GetTextLine(pos.VisualColumn);
- return visualLine.GetTextLineVisualXPosition(textLine, pos.VisualColumn);
+ int vc = visualLine.ValidateVisualColumn(pos, true);
+ TextLine textLine = visualLine.GetTextLine(vc);
+ return visualLine.GetTextLineVisualXPosition(textLine, vc);
+ }
+
+ int GetVisualColumnFromXPos(int line, double xPos)
+ {
+ var vl = textArea.TextView.GetOrConstructVisualLine(textArea.Document.GetLineByNumber(line));
+ return vl.GetVisualColumn(new Point(xPos, 0), true);
}
///
@@ -108,6 +116,11 @@ namespace ICSharpCode.AvalonEdit.Editing
}
}
+ ///
+ public override bool EnableVirtualSpace {
+ get { return true; }
+ }
+
///
public override ISegment SurroundingSegment {
get {
@@ -120,6 +133,7 @@ namespace ICSharpCode.AvalonEdit.Editing
get { return segments; }
}
+
void CalculateSegments()
{
DocumentLine nextLine = document.GetLineByNumber(Math.Min(startLine, endLine));
@@ -131,10 +145,10 @@ namespace ICSharpCode.AvalonEdit.Editing
int baseOffset = vl.FirstDocumentLine.Offset;
int startOffset = baseOffset + vl.GetRelativeOffset(startVC);
int endOffset = baseOffset + vl.GetRelativeOffset(endVC);
- segments.Add(new SelectionSegment(startOffset, startVC, endOffset, endVC, true));
+ segments.Add(new SelectionSegment(startOffset, startVC, endOffset, endVC));
nextLine = vl.LastDocumentLine.NextLine;
- } while (nextLine.LineNumber <= Math.Max(startLine, endLine));
+ } while (nextLine != null && nextLine.LineNumber <= Math.Max(startLine, endLine));
}
///
@@ -156,97 +170,81 @@ namespace ICSharpCode.AvalonEdit.Editing
///
public override Selection SetEndpoint(TextViewPosition endPosition)
{
- return new RectangleSelection(textArea, startLine, startXPos, startOffset, endPosition);
+ var r = new RectangleSelection(textArea, startLine, startXPos, startOffset, endPosition);
+ return r;
}
///
public override Selection UpdateOnDocumentChange(DocumentChangeEventArgs e)
{
- throw new NotImplementedException();
-// return new RectangleSelection(textArea,
-// e.GetNewOffset(StartOffset, AnchorMovementType.AfterInsertion),
-// e.GetNewOffset(EndOffset, AnchorMovementType.BeforeInsertion));
+ TextLocation newStartLocation = textArea.Document.GetLocation(e.GetNewOffset(startOffset, AnchorMovementType.AfterInsertion));
+ TextLocation newEndLocation = textArea.Document.GetLocation(e.GetNewOffset(endOffset, AnchorMovementType.BeforeInsertion));
+
+ return new RectangleSelection(textArea,
+ new TextViewPosition(newStartLocation, GetVisualColumnFromXPos(newStartLocation.Line, startXPos)),
+ new TextViewPosition(newEndLocation, GetVisualColumnFromXPos(newEndLocation.Line, endXPos)));
}
///
public override void ReplaceSelectionWithText(string newText)
{
- throw new NotImplementedException(); /*
if (newText == null)
throw new ArgumentNullException("newText");
using (textArea.Document.RunUpdate()) {
- TextLocation start = document.GetLocation(StartOffset);
- TextLocation end = document.GetLocation(EndOffset);
- int editColumn = Math.Min(start.Column, end.Column);
+ TextViewPosition start = new TextViewPosition(document.GetLocation(startOffset), GetVisualColumnFromXPos(startLine, startXPos));
+ TextViewPosition end = new TextViewPosition(document.GetLocation(endOffset), GetVisualColumnFromXPos(endLine, endXPos));
+ int insertionLength;
+ int totalInsertionLength = 0;
+ int firstInsertionLength = 0;
+ int editOffset = Math.Min(startOffset, endOffset);
if (NewLineFinder.NextNewLine(newText, 0) == SimpleSegment.Invalid) {
// insert same text into every line
- foreach (ISegment lineSegment in this.Segments.Reverse()) {
- ReplaceSingleLineText(textArea, lineSegment, newText);
+ foreach (SelectionSegment lineSegment in this.Segments.Reverse()) {
+ ReplaceSingleLineText(textArea, lineSegment, newText, out insertionLength);
+ totalInsertionLength += insertionLength;
+ firstInsertionLength = insertionLength;
}
- TextLocation newStart = new TextLocation(start.Line, editColumn + newText.Length);
- TextLocation newEnd = new TextLocation(end.Line, editColumn + newText.Length);
- textArea.Caret.Location = newEnd;
- textArea.Selection = new RectangleSelection(document, document.GetOffset(newStart), document.GetOffset(newEnd));
+ int newEndOffset = editOffset + totalInsertionLength;
+ TextViewPosition pos = new TextViewPosition(document.GetLocation(editOffset + firstInsertionLength));
+
+ textArea.Selection = new RectangleSelection(textArea, pos, Math.Max(startLine, endLine), GetXPos(textArea, pos), newEndOffset);
+ textArea.Caret.Position = textArea.TextView.GetPosition(new Point(GetXPos(textArea, pos), textArea.TextView.GetVisualTopByDocumentLine(Math.Max(startLine, endLine)))).GetValueOrDefault();
} else {
- // convert all segment start/ends to anchors
- var segments = this.Segments.Select(s => new AnchorSegment(this.document, s)).ToList();
- SimpleSegment ds = NewLineFinder.NextNewLine(newText, 0);
- // we'll check whether all lines have the same length. If so, we can continue using a rectangular selection.
- int commonLength = -1;
- // now insert lines into rectangular selection
- int lastDelimiterEnd = 0;
- bool isAtEnd = false;
- int i;
- for (i = 0; i < segments.Count; i++) {
- string lineText;
- if (ds == SimpleSegment.Invalid || (i == segments.Count - 1)) {
- lineText = newText.Substring(lastDelimiterEnd);
- isAtEnd = true;
- // if we have more lines to insert than this selection is long, we cannot continue using a rectangular selection
- if (ds != SimpleSegment.Invalid)
- commonLength = -1;
- } else {
- lineText = newText.Substring(lastDelimiterEnd, ds.Offset - lastDelimiterEnd);
- }
- if (i == 0) {
- commonLength = lineText.Length;
- } else if (commonLength != lineText.Length) {
- commonLength = -1;
- }
- ReplaceSingleLineText(textArea, segments[i], lineText);
- if (isAtEnd)
- break;
- lastDelimiterEnd = ds.EndOffset;
- ds = NewLineFinder.NextNewLine(newText, lastDelimiterEnd);
- }
- if (commonLength >= 0) {
- TextLocation newStart = new TextLocation(start.Line, editColumn + commonLength);
- TextLocation newEnd = new TextLocation(start.Line + i, editColumn + commonLength);
- textArea.Selection = new RectangleSelection(document, document.GetOffset(newStart), document.GetOffset(newEnd));
- } else {
- textArea.Selection = Selection.Empty;
+ string[] lines = newText.Split(new[] { "\r\n", "\r", "\n" }, segments.Count, StringSplitOptions.None);
+ int line = Math.Min(startLine, endLine);
+ for (int i = lines.Length - 1; i >= 0; i--) {
+ ReplaceSingleLineText(textArea, segments[i], lines[i], out insertionLength);
+ firstInsertionLength = insertionLength;
}
+ TextViewPosition pos = new TextViewPosition(document.GetLocation(editOffset + firstInsertionLength));
+ textArea.ClearSelection();
+ textArea.Caret.Position = textArea.TextView.GetPosition(new Point(GetXPos(textArea, pos), textArea.TextView.GetVisualTopByDocumentLine(Math.Max(startLine, endLine)))).GetValueOrDefault();
}
- }*/
+ }
}
- static void ReplaceSingleLineText(TextArea textArea, ISegment lineSegment, string newText)
+ void ReplaceSingleLineText(TextArea textArea, SelectionSegment lineSegment, string newText, out int insertionLength)
{
if (lineSegment.Length == 0) {
- if (newText.Length > 0 && textArea.ReadOnlySectionProvider.CanInsert(lineSegment.Offset)) {
- textArea.Document.Insert(lineSegment.Offset, newText);
+ if (newText.Length > 0 && textArea.ReadOnlySectionProvider.CanInsert(lineSegment.StartOffset)) {
+ newText = AddSpacesIfRequired(newText, new TextViewPosition(document.GetLocation(lineSegment.StartOffset), lineSegment.StartVisualColumn));
+ textArea.Document.Insert(lineSegment.StartOffset, newText);
}
} else {
ISegment[] segmentsToDelete = textArea.GetDeletableSegments(lineSegment);
for (int i = segmentsToDelete.Length - 1; i >= 0; i--) {
if (i == segmentsToDelete.Length - 1) {
+ if (segmentsToDelete[i].Offset == SurroundingSegment.Offset && segmentsToDelete[i].Length == SurroundingSegment.Length) {
+ newText = AddSpacesIfRequired(newText, new TextViewPosition(document.GetLocation(lineSegment.StartOffset), lineSegment.StartVisualColumn));
+ }
textArea.Document.Replace(segmentsToDelete[i], newText);
} else {
textArea.Document.Remove(segmentsToDelete[i]);
}
}
}
+ insertionLength = newText.Length;
}
///
@@ -258,12 +256,12 @@ namespace ICSharpCode.AvalonEdit.Editing
throw new ArgumentNullException("textArea");
if (text == null)
throw new ArgumentNullException("text");
- int newLineCount = text.Count(c => c == '\n');
+ int newLineCount = text.Count(c => c == '\n'); // TODO might not work in all cases, but single \r line endings are really rare today.
TextLocation endLocation = new TextLocation(startPosition.Line + newLineCount, startPosition.Column);
if (endLocation.Line <= textArea.Document.LineCount) {
int endOffset = textArea.Document.GetOffset(endLocation);
- if (textArea.Document.GetLocation(endOffset) == endLocation) {
- RectangleSelection rsel = new RectangleSelection(textArea, startPosition, new TextViewPosition(endLocation));
+ if (textArea.Selection.EnableVirtualSpace || textArea.Document.GetLocation(endOffset) == endLocation) {
+ RectangleSelection rsel = new RectangleSelection(textArea, startPosition, endLocation.Line, GetXPos(textArea, startPosition), endOffset);
rsel.ReplaceSelectionWithText(text);
if (selectInsertedText && textArea.Selection is RectangleSelection) {
RectangleSelection sel = (RectangleSelection)textArea.Selection;
@@ -296,7 +294,7 @@ namespace ICSharpCode.AvalonEdit.Editing
{
// It's possible that ToString() gets called on old (invalid) selections, e.g. for "change from... to..." debug message
// make sure we don't crash even when the desired locations don't exist anymore.
- return "[RectangleSelection " + startOffset + " to " + endOffset + "]";
+ return string.Format("[RectangleSelection {0} {1} {2} to {3} {4} {5}]", startLine, startOffset, startXPos, endLine, endOffset, endXPos);
}
}
}
diff --git a/ICSharpCode.AvalonEdit/Editing/Selection.cs b/ICSharpCode.AvalonEdit/Editing/Selection.cs
index 354c0ee..0a11937 100644
--- a/ICSharpCode.AvalonEdit/Editing/Selection.cs
+++ b/ICSharpCode.AvalonEdit/Editing/Selection.cs
@@ -81,7 +81,7 @@ namespace ICSharpCode.AvalonEdit.Editing
internal string AddSpacesIfRequired(string newText, TextViewPosition pos)
{
- if (textArea.Options.EnableVirtualSpace && !string.IsNullOrEmpty(newText)) {
+ if (EnableVirtualSpace && !string.IsNullOrEmpty(newText) && newText != "\r\n" && newText != "\n" && newText != "\r") {
var line = textArea.Document.GetLineByNumber(pos.Line);
string lineText = textArea.Document.GetText(line);
var vLine = textArea.TextView.GetOrConstructVisualLine(line);
@@ -112,6 +112,10 @@ namespace ICSharpCode.AvalonEdit.Editing
get { return Length == 0; }
}
+ public virtual bool EnableVirtualSpace {
+ get { return textArea.Options.EnableVirtualSpace; }
+ }
+
///
/// Gets the selection length.
///
diff --git a/ICSharpCode.AvalonEdit/Editing/SelectionColorizer.cs b/ICSharpCode.AvalonEdit/Editing/SelectionColorizer.cs
index 7af054e..e75f043 100644
--- a/ICSharpCode.AvalonEdit/Editing/SelectionColorizer.cs
+++ b/ICSharpCode.AvalonEdit/Editing/SelectionColorizer.cs
@@ -28,19 +28,24 @@ namespace ICSharpCode.AvalonEdit.Editing
int lineStartOffset = context.VisualLine.FirstDocumentLine.Offset;
int lineEndOffset = context.VisualLine.LastDocumentLine.Offset + context.VisualLine.LastDocumentLine.TotalLength;
- foreach (var segment in textArea.Selection.Segments) {
+ foreach (SelectionSegment segment in textArea.Selection.Segments) {
int segmentStart = segment.StartOffset;
int segmentEnd = segment.EndOffset;
if (segmentEnd <= lineStartOffset)
continue;
if (segmentStart >= lineEndOffset)
continue;
- int startColumn = segment.StartVisualColumn;
- int endColumn = segment.EndVisualColumn;
- if (startColumn < 0)
- startColumn = context.VisualLine.GetVisualColumn(Math.Max(0, segmentStart - lineStartOffset));
- if (endColumn < 0)
- endColumn = context.VisualLine.GetVisualColumn(segmentEnd - lineStartOffset);
+ int startColumn;
+ if (segmentStart < lineStartOffset)
+ startColumn = 0;
+ else
+ startColumn = context.VisualLine.ValidateVisualColumn(segment.StartOffset, segment.StartVisualColumn, textArea.Selection.EnableVirtualSpace);
+
+ int endColumn;
+ if (segmentEnd > lineEndOffset)
+ endColumn = textArea.Selection.EnableVirtualSpace ? int.MaxValue : context.VisualLine.VisualLengthWithEndOfLineMarker;
+ else
+ endColumn = context.VisualLine.ValidateVisualColumn(segment.EndOffset, segment.EndVisualColumn, textArea.Selection.EnableVirtualSpace);
ChangeVisualElements(
startColumn, endColumn,
diff --git a/ICSharpCode.AvalonEdit/Editing/SelectionLayer.cs b/ICSharpCode.AvalonEdit/Editing/SelectionLayer.cs
index 1e47cc0..2c56008 100644
--- a/ICSharpCode.AvalonEdit/Editing/SelectionLayer.cs
+++ b/ICSharpCode.AvalonEdit/Editing/SelectionLayer.cs
@@ -39,7 +39,7 @@ namespace ICSharpCode.AvalonEdit.Editing
BackgroundGeometryBuilder geoBuilder = new BackgroundGeometryBuilder();
geoBuilder.AlignToMiddleOfPixels = true;
- geoBuilder.ExtendToFullWidthAtLineEnd = textArea.Options.EnableVirtualSpace;
+ geoBuilder.ExtendToFullWidthAtLineEnd = textArea.Selection.EnableVirtualSpace;
geoBuilder.CornerRadius = textArea.SelectionCornerRadius;
foreach (var segment in textArea.Selection.Segments) {
geoBuilder.AddSegment(textView, segment);
diff --git a/ICSharpCode.AvalonEdit/Editing/SelectionMouseHandler.cs b/ICSharpCode.AvalonEdit/Editing/SelectionMouseHandler.cs
index b27b2e3..915e430 100644
--- a/ICSharpCode.AvalonEdit/Editing/SelectionMouseHandler.cs
+++ b/ICSharpCode.AvalonEdit/Editing/SelectionMouseHandler.cs
@@ -9,8 +9,8 @@ using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Documents;
using System.Windows.Input;
+using System.Windows.Media.TextFormatting;
using System.Windows.Threading;
-
using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.AvalonEdit.Rendering;
using ICSharpCode.AvalonEdit.Utils;
@@ -454,11 +454,11 @@ namespace ICSharpCode.AvalonEdit.Editing
pos += textView.ScrollOffset;
VisualLine line = textView.GetVisualLineFromVisualTop(pos.Y);
if (line != null) {
- int visualColumn = line.GetVisualColumn(pos);
- int wordStartVC = line.GetNextCaretPosition(visualColumn + 1, LogicalDirection.Backward, CaretPositioningMode.WordStartOrSymbol);
+ int visualColumn = line.GetVisualColumn(pos, textArea.Selection.EnableVirtualSpace);
+ int wordStartVC = line.GetNextCaretPosition(visualColumn + 1, LogicalDirection.Backward, CaretPositioningMode.WordStartOrSymbol, textArea.Selection.EnableVirtualSpace);
if (wordStartVC == -1)
wordStartVC = 0;
- int wordEndVC = line.GetNextCaretPosition(wordStartVC, LogicalDirection.Forward, CaretPositioningMode.WordBorderOrSymbol);
+ int wordEndVC = line.GetNextCaretPosition(wordStartVC, LogicalDirection.Forward, CaretPositioningMode.WordBorderOrSymbol, textArea.Selection.EnableVirtualSpace);
if (wordEndVC == -1)
wordEndVC = line.VisualLength;
int relOffset = line.FirstDocumentLine.Offset;
@@ -507,7 +507,27 @@ namespace ICSharpCode.AvalonEdit.Editing
pos.Y = textView.DocumentHeight - ExtensionMethods.Epsilon;
VisualLine line = textView.GetVisualLineFromVisualTop(pos.Y);
if (line != null) {
- visualColumn = line.GetVisualColumn(pos);
+ visualColumn = line.GetVisualColumn(pos, textArea.Selection.EnableVirtualSpace);
+ return line.GetRelativeOffset(visualColumn) + line.FirstDocumentLine.Offset;
+ }
+ return -1;
+ }
+
+ int GetOffsetFromMousePositionFirstTextLineOnly(Point positionRelativeToTextView, out int visualColumn)
+ {
+ visualColumn = 0;
+ TextView textView = textArea.TextView;
+ Point pos = positionRelativeToTextView;
+ if (pos.Y < 0)
+ pos.Y = 0;
+ if (pos.Y > textView.ActualHeight)
+ pos.Y = textView.ActualHeight;
+ pos += textView.ScrollOffset;
+ if (pos.Y > textView.DocumentHeight)
+ pos.Y = textView.DocumentHeight - ExtensionMethods.Epsilon;
+ VisualLine line = textView.GetVisualLineFromVisualTop(pos.Y);
+ if (line != null) {
+ visualColumn = line.GetVisualColumn(line.TextLines.First(), positionRelativeToTextView.X, textArea.Selection.EnableVirtualSpace);
return line.GetRelativeOffset(visualColumn) + line.FirstDocumentLine.Offset;
}
return -1;
@@ -548,7 +568,11 @@ namespace ICSharpCode.AvalonEdit.Editing
void SetCaretOffsetToMousePosition(MouseEventArgs e, ISegment allowedSegment)
{
int visualColumn;
- int offset = GetOffsetFromMousePosition(e, out visualColumn);
+ int offset;
+ if (mode == SelectionMode.Rectangular)
+ offset = GetOffsetFromMousePositionFirstTextLineOnly(e.GetPosition(textArea.TextView), out visualColumn);
+ else
+ offset = GetOffsetFromMousePosition(e, out visualColumn);
if (allowedSegment != null) {
offset = offset.CoerceValue(allowedSegment.Offset, allowedSegment.EndOffset);
}
diff --git a/ICSharpCode.AvalonEdit/Editing/SelectionSegment.cs b/ICSharpCode.AvalonEdit/Editing/SelectionSegment.cs
index 729c325..eff919b 100644
--- a/ICSharpCode.AvalonEdit/Editing/SelectionSegment.cs
+++ b/ICSharpCode.AvalonEdit/Editing/SelectionSegment.cs
@@ -14,8 +14,9 @@ namespace ICSharpCode.AvalonEdit.Editing
readonly int startOffset, endOffset;
readonly int startVC, endVC;
- public bool AllowVirtualSpace { get; private set; }
-
+ ///
+ /// Creates a SelectionSegment from two offsets.
+ ///
public SelectionSegment(int startOffset, int endOffset)
{
this.startOffset = Math.Min(startOffset, endOffset);
@@ -23,9 +24,12 @@ namespace ICSharpCode.AvalonEdit.Editing
this.startVC = this.endVC = -1;
}
- public SelectionSegment(int startOffset, int startVC, int endOffset, int endVC, bool allowVirtualSpace)
+ ///
+ /// Creates a SelectionSegment from two offsets and visual columns.
+ ///
+ public SelectionSegment(int startOffset, int startVC, int endOffset, int endVC)
{
- if (startOffset <= endOffset) {
+ if (startOffset < endOffset || (startOffset == endOffset && startVC <= endVC)) {
this.startOffset = startOffset;
this.startVC = startVC;
this.endOffset = endOffset;
@@ -36,25 +40,37 @@ namespace ICSharpCode.AvalonEdit.Editing
this.endOffset = startOffset;
this.endVC = startVC;
}
- this.AllowVirtualSpace = allowVirtualSpace;
}
+ ///
+ /// Gets the start offset.
+ ///
public int StartOffset {
get { return startOffset; }
}
+ ///
+ /// Gets the end offset.
+ ///
public int EndOffset {
get { return endOffset; }
}
+ ///
+ /// Gets the start visual column.
+ ///
public int StartVisualColumn {
get { return startVC; }
}
+ ///
+ /// Gets the end visual column.
+ ///
public int EndVisualColumn {
get { return endVC; }
}
+ ///
int ISegment.Offset {
get { return startOffset; }
}
@@ -64,6 +80,7 @@ namespace ICSharpCode.AvalonEdit.Editing
get { return endOffset - startOffset; }
}
+ ///
public override string ToString()
{
return string.Format("[SelectionSegment StartOffset={0}, EndOffset={1}, StartVC={2}, EndVC={3}]", startOffset, endOffset, startVC, endVC);
diff --git a/ICSharpCode.AvalonEdit/Editing/SimpleSelection.cs b/ICSharpCode.AvalonEdit/Editing/SimpleSelection.cs
index f2a88c9..2da357a 100644
--- a/ICSharpCode.AvalonEdit/Editing/SimpleSelection.cs
+++ b/ICSharpCode.AvalonEdit/Editing/SimpleSelection.cs
@@ -33,7 +33,7 @@ namespace ICSharpCode.AvalonEdit.Editing
///
public override IEnumerable Segments {
get {
- return ExtensionMethods.Sequence(new SelectionSegment(startOffset, start.VisualColumn, endOffset, end.VisualColumn, textArea.Options.EnableVirtualSpace));
+ return ExtensionMethods.Sequence(new SelectionSegment(startOffset, start.VisualColumn, endOffset, end.VisualColumn));
}
}
diff --git a/ICSharpCode.AvalonEdit/Editing/TextArea.cs b/ICSharpCode.AvalonEdit/Editing/TextArea.cs
index d8f26d5..a8dc300 100644
--- a/ICSharpCode.AvalonEdit/Editing/TextArea.cs
+++ b/ICSharpCode.AvalonEdit/Editing/TextArea.cs
@@ -378,6 +378,7 @@ namespace ICSharpCode.AvalonEdit.Editing
///
/// Gets/Sets the selection in this text area.
///
+
public Selection Selection {
get { return selection; }
set {
@@ -390,7 +391,7 @@ namespace ICSharpCode.AvalonEdit.Editing
if (textView != null) {
ISegment oldSegment = selection.SurroundingSegment;
ISegment newSegment = value.SurroundingSegment;
- if (!Options.EnableVirtualSpace && (selection is SimpleSelection && value is SimpleSelection && oldSegment != null && newSegment != null)) {
+ if (!Selection.EnableVirtualSpace && (selection is SimpleSelection && value is SimpleSelection && oldSegment != null && newSegment != null)) {
// perf optimization:
// When a simple selection changes, don't redraw the whole selection, but only the changed parts.
int oldSegmentOffset = oldSegment.Offset;
@@ -870,19 +871,19 @@ namespace ICSharpCode.AvalonEdit.Editing
}
}
- internal void RemoveSelectedText()
- {
- if (this.Document == null)
- throw ThrowUtil.NoDocumentAssigned();
- selection.ReplaceSelectionWithText(string.Empty);
- #if DEBUG
- if (!selection.IsEmpty) {
- foreach (ISegment s in selection.Segments) {
- Debug.Assert(this.ReadOnlySectionProvider.GetDeletableSegments(s).Count() == 0);
- }
- }
- #endif
+internal void RemoveSelectedText()
+{
+ if (this.Document == null)
+ throw ThrowUtil.NoDocumentAssigned();
+ selection.ReplaceSelectionWithText(string.Empty);
+ #if DEBUG
+ if (!selection.IsEmpty) {
+ foreach (ISegment s in selection.Segments) {
+ Debug.Assert(this.ReadOnlySectionProvider.GetDeletableSegments(s).Count() == 0);
}
+ }
+ #endif
+}
internal void ReplaceSelectionWithText(string newText)
{
diff --git a/ICSharpCode.AvalonEdit/ICSharpCode.AvalonEdit.csproj b/ICSharpCode.AvalonEdit/ICSharpCode.AvalonEdit.csproj
index 7637c92..3d644e2 100644
--- a/ICSharpCode.AvalonEdit/ICSharpCode.AvalonEdit.csproj
+++ b/ICSharpCode.AvalonEdit/ICSharpCode.AvalonEdit.csproj
@@ -262,7 +262,6 @@
-
FormattedTextElement.cs
@@ -340,7 +339,9 @@
-
+
+ ObserveAddRemoveCollection.cs
+
diff --git a/ICSharpCode.AvalonEdit/Rendering/BackgroundGeometryBuilder.cs b/ICSharpCode.AvalonEdit/Rendering/BackgroundGeometryBuilder.cs
index 9d5d74c..e2f0dcd 100644
--- a/ICSharpCode.AvalonEdit/Rendering/BackgroundGeometryBuilder.cs
+++ b/ICSharpCode.AvalonEdit/Rendering/BackgroundGeometryBuilder.cs
@@ -124,7 +124,7 @@ namespace ICSharpCode.AvalonEdit.Rendering
int segmentEndVC;
if (segmentEnd > vlEndOffset)
- segmentEndVC = extendToFullWidthAtLineEnd ? int.MaxValue : vl.VisualLength;
+ segmentEndVC = extendToFullWidthAtLineEnd ? int.MaxValue : vl.VisualLengthWithEndOfLineMarker;
else
segmentEndVC = vl.ValidateVisualColumn(end, extendToFullWidthAtLineEnd);
@@ -170,8 +170,8 @@ namespace ICSharpCode.AvalonEdit.Rendering
lastRect = new Rect(Math.Min(left, right), y, Math.Abs(right - left), line.Height);
}
}
- if (segmentEndVC >= vl.VisualLength) {
- double left = (segmentStartVC > vl.VisualLength ? vl.GetTextLineVisualXPosition(lastTextLine, segmentStartVC) : line.Width) - scrollOffset.X;
+ if (segmentEndVC >= vl.VisualLengthWithEndOfLineMarker) {
+ double left = (segmentStartVC > vl.VisualLengthWithEndOfLineMarker ? vl.GetTextLineVisualXPosition(lastTextLine, segmentStartVC) : line.Width) - scrollOffset.X;
double right = ((segmentEndVC == int.MaxValue || line != lastTextLine) ? Math.Max(((IScrollInfo)textView).ExtentWidth, ((IScrollInfo)textView).ViewportWidth) : vl.GetTextLineVisualXPosition(lastTextLine, segmentEndVC)) - scrollOffset.X;
Rect extendSelection = new Rect(Math.Min(left, right), y, Math.Abs(right - left), line.Height);
if (!lastRect.IsEmpty) {
diff --git a/ICSharpCode.AvalonEdit/Rendering/NewLineElementGenerator.cs b/ICSharpCode.AvalonEdit/Rendering/NewLineElementGenerator.cs
deleted file mode 100644
index 0718010..0000000
--- a/ICSharpCode.AvalonEdit/Rendering/NewLineElementGenerator.cs
+++ /dev/null
@@ -1,88 +0,0 @@
-// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
-// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
-
-using System;
-using System.Windows;
-using System.Windows.Documents;
-using System.Windows.Media;
-using System.Windows.Media.TextFormatting;
-using ICSharpCode.AvalonEdit.Document;
-using ICSharpCode.AvalonEdit.Utils;
-
-namespace ICSharpCode.AvalonEdit.Rendering
-{
- // This class is internal because it does not need to be accessed by the user - it can be configured using TextEditorOptions.
-
- ///
- /// Elements generator that displays "¶" at the end of lines.
- ///
- ///
- /// This element generator can be easily enabled and configured using the
- /// .
- ///
- sealed class NewLineElementGenerator : VisualLineElementGenerator, IBuiltinElementGenerator
- {
- void IBuiltinElementGenerator.FetchOptions(TextEditorOptions options)
- {
- }
-
- public override int GetFirstInterestedOffset(int startOffset)
- {
- DocumentLine lastDocumentLine = CurrentContext.VisualLine.LastDocumentLine;
- if (lastDocumentLine.DelimiterLength > 0)
- return lastDocumentLine.Offset + lastDocumentLine.Length;
- else
- return -1;
- }
-
- public override VisualLineElement ConstructElement(int offset)
- {
- string newlineText;
- DocumentLine lastDocumentLine = CurrentContext.VisualLine.LastDocumentLine;
- if (lastDocumentLine.DelimiterLength == 2) {
- newlineText = "\u00B6";
- } else if (lastDocumentLine.DelimiterLength == 1) {
- char newlineChar = CurrentContext.Document.GetCharAt(lastDocumentLine.Offset + lastDocumentLine.Length);
- if (newlineChar == '\r')
- newlineText = "\\r";
- else if (newlineChar == '\n')
- newlineText = "\\n";
- else
- newlineText = "?";
- } else {
- return null;
- }
- return new NewLineTextElement(CurrentContext.TextView.cachedElements.GetTextForNonPrintableCharacter(newlineText, CurrentContext));
- }
-
- sealed class NewLineTextElement : FormattedTextElement
- {
- public NewLineTextElement(TextLine text) : base(text, 0)
- {
- BreakBefore = LineBreakCondition.BreakPossible;
- BreakAfter = LineBreakCondition.BreakRestrained;
- }
-
- public override int GetNextCaretPosition(int visualColumn, LogicalDirection direction, CaretPositioningMode mode)
- {
- // only place a caret stop before the newline, no caret stop after it
- if (visualColumn > this.VisualColumn && direction == LogicalDirection.Backward ||
- visualColumn < this.VisualColumn && direction == LogicalDirection.Forward)
- {
- return this.VisualColumn;
- } else {
- return -1;
- }
- }
-
- public override bool IsWhitespace(int visualColumn)
- {
- return true;
- }
-
- public override bool HandlesLineBorders {
- get { return true; }
- }
- }
- }
-}
diff --git a/ICSharpCode.AvalonEdit/Rendering/TextView.cs b/ICSharpCode.AvalonEdit/Rendering/TextView.cs
index 41a7db2..a03d344 100644
--- a/ICSharpCode.AvalonEdit/Rendering/TextView.cs
+++ b/ICSharpCode.AvalonEdit/Rendering/TextView.cs
@@ -263,7 +263,7 @@ namespace ICSharpCode.AvalonEdit.Rendering
#endregion
#region Builtin ElementGenerators
- NewLineElementGenerator newLineElementGenerator;
+// NewLineElementGenerator newLineElementGenerator;
SingleCharacterElementGenerator singleCharacterElementGenerator;
LinkElementGenerator linkElementGenerator;
MailLinkElementGenerator mailLinkElementGenerator;
@@ -272,7 +272,7 @@ namespace ICSharpCode.AvalonEdit.Rendering
{
TextEditorOptions options = this.Options;
- AddRemoveDefaultElementGeneratorOnDemand(ref newLineElementGenerator, options.ShowEndOfLine);
+// AddRemoveDefaultElementGeneratorOnDemand(ref newLineElementGenerator, options.ShowEndOfLine);
AddRemoveDefaultElementGeneratorOnDemand(ref singleCharacterElementGenerator, options.ShowBoxForControlCharacters || options.ShowSpaces || options.ShowTabs);
AddRemoveDefaultElementGeneratorOnDemand(ref linkElementGenerator, options.EnableHyperlinks);
AddRemoveDefaultElementGeneratorOnDemand(ref mailLinkElementGenerator, options.EnableEmailHyperlinks);
@@ -1013,7 +1013,7 @@ namespace ICSharpCode.AvalonEdit.Rendering
var textLines = new List();
paragraphProperties.indent = 0;
paragraphProperties.firstLineInParagraph = true;
- while (textOffset <= visualLine.VisualLength) {
+ while (textOffset <= visualLine.VisualLengthWithEndOfLineMarker) {
TextLine textLine = formatter.FormatLine(
textSource,
textOffset,
@@ -1025,7 +1025,7 @@ namespace ICSharpCode.AvalonEdit.Rendering
textOffset += textLine.Length;
// exit loop so that we don't do the indentation calculation if there's only a single line
- if (textOffset >= visualLine.VisualLength)
+ if (textOffset >= visualLine.VisualLengthWithEndOfLineMarker)
break;
if (paragraphProperties.firstLineInParagraph) {
diff --git a/ICSharpCode.AvalonEdit/Rendering/VisualLine.cs b/ICSharpCode.AvalonEdit/Rendering/VisualLine.cs
index ea86ef9..f6ac5e1 100644
--- a/ICSharpCode.AvalonEdit/Rendering/VisualLine.cs
+++ b/ICSharpCode.AvalonEdit/Rendering/VisualLine.cs
@@ -65,6 +65,14 @@ namespace ICSharpCode.AvalonEdit.Rendering
///
public int VisualLength { get; private set; }
+ public int VisualLengthWithEndOfLineMarker {
+ get {
+ int length = VisualLength;
+ if (textView.Options.ShowEndOfLine && LastDocumentLine.NextLine != null) length++;
+ return length;
+ }
+ }
+
///
/// Gets the height of the visual line in device-independent pixels.
///
@@ -226,7 +234,7 @@ namespace ICSharpCode.AvalonEdit.Rendering
{
if (visualColumn < 0)
throw new ArgumentOutOfRangeException("visualColumn");
- if (visualColumn >= VisualLength)
+ if (visualColumn >= VisualLengthWithEndOfLineMarker)
return TextLines[TextLines.Count - 1];
foreach (TextLine line in TextLines) {
if (visualColumn < line.Length)
@@ -322,9 +330,9 @@ namespace ICSharpCode.AvalonEdit.Rendering
if (textLine == null)
throw new ArgumentNullException("textLine");
double xPos = textLine.GetDistanceFromCharacterHit(
- new CharacterHit(Math.Min(visualColumn, VisualLength), 0));
- if (visualColumn > VisualLength) {
- xPos += (visualColumn - VisualLength) * textView.WideSpaceWidth;
+ new CharacterHit(Math.Min(visualColumn, VisualLengthWithEndOfLineMarker), 0));
+ if (visualColumn > VisualLengthWithEndOfLineMarker) {
+ xPos += (visualColumn - VisualLengthWithEndOfLineMarker) * textView.WideSpaceWidth;
}
return xPos;
}
@@ -340,35 +348,43 @@ namespace ICSharpCode.AvalonEdit.Rendering
public int GetVisualColumn(Point point, bool allowVirtualSpace)
{
- TextLine textLine = GetTextLineByVisualYPosition(point.Y);
- if (point.X > textLine.WidthIncludingTrailingWhitespace) {
+ return GetVisualColumn(GetTextLineByVisualYPosition(point.Y), point.X, allowVirtualSpace);
+ }
+
+ public int GetVisualColumn(TextLine textLine, double xPos, bool allowVirtualSpace)
+ {
+ if (xPos > textLine.WidthIncludingTrailingWhitespace) {
if (allowVirtualSpace && textLine == TextLines[TextLines.Count - 1]) {
- int virtualX = (int)Math.Round((point.X - textLine.WidthIncludingTrailingWhitespace) / textView.WideSpaceWidth);
- return VisualLength + virtualX;
+ int virtualX = (int)Math.Round((xPos - textLine.WidthIncludingTrailingWhitespace) / textView.WideSpaceWidth);
+ return VisualLengthWithEndOfLineMarker + virtualX;
}
}
- CharacterHit ch = textLine.GetCharacterHitFromDistance(point.X);
+ CharacterHit ch = textLine.GetCharacterHitFromDistance(xPos);
return ch.FirstCharacterIndex + ch.TrailingLength;
}
public int ValidateVisualColumn(TextViewPosition position, bool allowVirtualSpace)
{
- int offset = Document.GetOffset(position);
+ return ValidateVisualColumn(Document.GetOffset(position), position.VisualColumn, allowVirtualSpace);
+ }
+
+ public int ValidateVisualColumn(int offset, int visualColumn, bool allowVirtualSpace)
+ {
int firstDocumentLineOffset = this.FirstDocumentLine.Offset;
- if (position.VisualColumn < 0) {
+ if (visualColumn < 0) {
return GetVisualColumn(offset - firstDocumentLineOffset);
} else {
- int offsetFromVisualColumn = GetRelativeOffset(position.VisualColumn);
+ int offsetFromVisualColumn = GetRelativeOffset(visualColumn);
offsetFromVisualColumn += firstDocumentLineOffset;
if (offsetFromVisualColumn != offset) {
return GetVisualColumn(offset - firstDocumentLineOffset);
} else {
- if (position.VisualColumn > VisualLength && !allowVirtualSpace) {
+ if (visualColumn > VisualLength && !allowVirtualSpace) {
return VisualLength;
}
}
}
- return position.VisualColumn;
+ return visualColumn;
}
///
@@ -387,7 +403,7 @@ namespace ICSharpCode.AvalonEdit.Rendering
if (allowVirtualSpace && textLine == TextLines[TextLines.Count - 1]) {
// clicking virtual space in the last line
int virtualX = (int)((point.X - textLine.WidthIncludingTrailingWhitespace) / textView.WideSpaceWidth);
- return VisualLength + virtualX;
+ return VisualLengthWithEndOfLineMarker + virtualX;
} else {
// GetCharacterHitFromDistance returns a hit with FirstCharacterIndex=last character in line
// and TrailingLength=1 when clicking behind the line, so the floor function needs to handle this case
@@ -407,11 +423,11 @@ namespace ICSharpCode.AvalonEdit.Rendering
///
/// Gets the next possible caret position after visualColumn, or -1 if there is no caret position.
///
- public int GetNextCaretPosition(int visualColumn, LogicalDirection direction, CaretPositioningMode mode)
+ public int GetNextCaretPosition(int visualColumn, LogicalDirection direction, CaretPositioningMode mode, bool allowVirtualSpace)
{
if (elements.Count == 0) {
// special handling for empty visual lines:
- if (textView.Options.EnableVirtualSpace) {
+ if (allowVirtualSpace) {
if (direction == LogicalDirection.Forward)
return Math.Max(0, visualColumn + 1);
else if (visualColumn > 0)
@@ -436,7 +452,7 @@ namespace ICSharpCode.AvalonEdit.Rendering
// If the last element doesn't handle line borders, return the line end as caret stop
if (visualColumn > this.VisualLength && !elements[elements.Count-1].HandlesLineBorders && HasImplicitStopAtLineEnd(mode)) {
- if (textView.Options.EnableVirtualSpace)
+ if (allowVirtualSpace)
return visualColumn - 1;
else
return this.VisualLength;
@@ -478,10 +494,10 @@ namespace ICSharpCode.AvalonEdit.Rendering
}
// if we've found nothing, and the last element doesn't handle line borders,
// return the line end as caret stop
- if (!elements[elements.Count-1].HandlesLineBorders && HasImplicitStopAtLineEnd(mode)) {
+ if ((allowVirtualSpace || !elements[elements.Count-1].HandlesLineBorders) && HasImplicitStopAtLineEnd(mode)) {
if (visualColumn < this.VisualLength)
return this.VisualLength;
- else if (textView.Options.EnableVirtualSpace)
+ else if (allowVirtualSpace)
return visualColumn + 1;
}
}
diff --git a/ICSharpCode.AvalonEdit/Rendering/VisualLineTextSource.cs b/ICSharpCode.AvalonEdit/Rendering/VisualLineTextSource.cs
index 375a09b..a9c05c6 100644
--- a/ICSharpCode.AvalonEdit/Rendering/VisualLineTextSource.cs
+++ b/ICSharpCode.AvalonEdit/Rendering/VisualLineTextSource.cs
@@ -49,12 +49,33 @@ namespace ICSharpCode.AvalonEdit.Rendering
return run;
}
}
+ if (TextView.Options.ShowEndOfLine && textSourceCharacterIndex == VisualLine.VisualLength) {
+ return CreateTextRunForNewLine();
+ }
return new TextEndOfParagraph(1);
} catch (Exception ex) {
Debug.WriteLine(ex.ToString());
throw;
}
}
+
+ TextRun CreateTextRunForNewLine()
+ {
+ string newlineText = "";
+ DocumentLine lastDocumentLine = VisualLine.LastDocumentLine;
+ if (lastDocumentLine.DelimiterLength == 2) {
+ newlineText = "¶";
+ } else if (lastDocumentLine.DelimiterLength == 1) {
+ char newlineChar = Document.GetCharAt(lastDocumentLine.Offset + lastDocumentLine.Length);
+ if (newlineChar == '\r')
+ newlineText = "\\r";
+ else if (newlineChar == '\n')
+ newlineText = "\\n";
+ else
+ newlineText = "?";
+ }
+ return new FormattedTextRun(new FormattedTextElement(TextView.cachedElements.GetTextForNonPrintableCharacter(newlineText, this), 0), GlobalTextRunProperties);
+ }
public override TextSpan GetPrecedingText(int textSourceCharacterIndexLimit)
{
diff --git a/ICSharpCode.AvalonEdit/Utils/ExtensionMethods.cs b/ICSharpCode.AvalonEdit/Utils/ExtensionMethods.cs
index 2dec831..0676256 100644
--- a/ICSharpCode.AvalonEdit/Utils/ExtensionMethods.cs
+++ b/ICSharpCode.AvalonEdit/Utils/ExtensionMethods.cs
@@ -192,5 +192,15 @@ namespace ICSharpCode.AvalonEdit.Utils
if (f != null && !f.IsFrozen)
Debug.WriteLine("Performance warning: Not frozen: " + f.ToString());
}
+
+ [Conditional("DEBUG")]
+ public static void Log(bool condition, string format, params object[] args)
+ {
+ if (condition) {
+ string output = DateTime.Now.ToString("hh:MM:ss") + ": " + string.Format(format, args) + Environment.NewLine + Environment.StackTrace;
+ Console.WriteLine(output);
+ Debug.WriteLine(output);
+ }
+ }
}
}