diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/Caret.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/Caret.cs index 9ecb8f5281..d8df683806 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/Caret.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/Caret.cs @@ -281,19 +281,8 @@ namespace ICSharpCode.AvalonEdit.Editing int caretOffset = textView.Document.GetOffset(position); int firstDocumentLineOffset = visualLine.FirstDocumentLine.Offset; - if (position.VisualColumn < 0) { - position.VisualColumn = visualLine.GetVisualColumn(caretOffset - firstDocumentLineOffset); - } else { - int offsetFromVisualColumn = visualLine.GetRelativeOffset(position.VisualColumn); - offsetFromVisualColumn += firstDocumentLineOffset; - if (offsetFromVisualColumn != caretOffset) { - position.VisualColumn = visualLine.GetVisualColumn(caretOffset - firstDocumentLineOffset); - } else { - if (position.VisualColumn > visualLine.VisualLength && !textArea.Options.EnableVirtualSpace) { - position.VisualColumn = visualLine.VisualLength; - } - } - } + position.VisualColumn = visualLine.ValidateVisualColumn(position, textArea.Options.EnableVirtualSpace); + // search possible caret positions int newVisualColumnForwards = visualLine.GetNextCaretPosition(position.VisualColumn - 1, LogicalDirection.Forward, CaretPositioningMode.Normal); // If position.VisualColumn was valid, we're done with validation. diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/EmptySelection.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/EmptySelection.cs index 79f9c0cd41..f1bf017e52 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/EmptySelection.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/EmptySelection.cs @@ -34,7 +34,7 @@ namespace ICSharpCode.AvalonEdit.Editing var document = textArea.Document; if (document == null) throw ThrowUtil.NoDocumentAssigned(); - return Create(textArea, document.GetOffset(startPosition), document.GetOffset(endPosition)); + return Create(textArea, startPosition, endPosition); } public override IEnumerable Segments { @@ -50,6 +50,7 @@ namespace ICSharpCode.AvalonEdit.Editing { if (newText == null) throw new ArgumentNullException("newText"); + newText = AddSpacesIfRequired(newText, textArea.Caret.Position); if (newText.Length > 0) { if (textArea.ReadOnlySectionProvider.CanInsert(textArea.Caret.Offset)) { textArea.Document.Insert(textArea.Caret.Offset, newText); diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/RectangleSelection.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/RectangleSelection.cs index 9a4f9ff548..341befb25a 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/RectangleSelection.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/RectangleSelection.cs @@ -131,7 +131,7 @@ 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)); + segments.Add(new SelectionSegment(startOffset, startVC, endOffset, endVC, true)); nextLine = vl.LastDocumentLine.NextLine; } while (nextLine.LineNumber <= Math.Max(startLine, endLine)); diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/Selection.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/Selection.cs index 7bbc347cc2..6563aa0f5e 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/Selection.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/Selection.cs @@ -26,7 +26,19 @@ namespace ICSharpCode.AvalonEdit.Editing if (startOffset == endOffset) return textArea.emptySelection; else - return new SimpleSelection(textArea, startOffset, endOffset); + return new SimpleSelection(textArea, + new TextViewPosition(textArea.Document.GetLocation(startOffset)), + new TextViewPosition(textArea.Document.GetLocation(endOffset))); + } + + internal static Selection Create(TextArea textArea, TextViewPosition start, TextViewPosition end) + { + if (textArea == null) + throw new ArgumentNullException("textArea"); + if (textArea.Document.GetOffset(start) == textArea.Document.GetOffset(end) && start.VisualColumn == end.VisualColumn) + return textArea.emptySelection; + else + return new SimpleSelection(textArea, start, end); } /// @@ -67,6 +79,19 @@ namespace ICSharpCode.AvalonEdit.Editing /// public abstract void ReplaceSelectionWithText(string newText); + internal string AddSpacesIfRequired(string newText, TextViewPosition pos) + { + if (textArea.Options.EnableVirtualSpace) { + var vLine = textArea.TextView.GetOrConstructVisualLine(textArea.Document.GetLineByNumber(pos.Line)); + int colDiff = pos.VisualColumn - vLine.VisualLength; + if (colDiff > 0) { + string additionalSpaces = new string(' ', colDiff); + return additionalSpaces + newText; + } + } + return newText; + } + /// /// Updates the selection when the document changes. /// diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/SelectionLayer.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/SelectionLayer.cs index bf005ccb16..1e47cc06d0 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/SelectionLayer.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/SelectionLayer.cs @@ -39,6 +39,7 @@ namespace ICSharpCode.AvalonEdit.Editing BackgroundGeometryBuilder geoBuilder = new BackgroundGeometryBuilder(); geoBuilder.AlignToMiddleOfPixels = true; + geoBuilder.ExtendToFullWidthAtLineEnd = textArea.Options.EnableVirtualSpace; geoBuilder.CornerRadius = textArea.SelectionCornerRadius; foreach (var segment in textArea.Selection.Segments) { geoBuilder.AddSegment(textView, segment); diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/SelectionMouseHandler.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/SelectionMouseHandler.cs index e82c8140a4..b27b2e352d 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/SelectionMouseHandler.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/SelectionMouseHandler.cs @@ -560,12 +560,11 @@ namespace ICSharpCode.AvalonEdit.Editing void ExtendSelectionToMouse(MouseEventArgs e) { - int oldOffset = textArea.Caret.Offset; TextViewPosition oldPosition = textArea.Caret.Position; if (mode == SelectionMode.Normal || mode == SelectionMode.Rectangular) { SetCaretOffsetToMousePosition(e); if (mode == SelectionMode.Normal && textArea.Selection is RectangleSelection) - textArea.Selection = Selection.Create(textArea, oldOffset, textArea.Caret.Offset); + textArea.Selection = new SimpleSelection(textArea, oldPosition, textArea.Caret.Position); else if (mode == SelectionMode.Rectangular && !(textArea.Selection is RectangleSelection)) textArea.Selection = new RectangleSelection(textArea, oldPosition, textArea.Caret.Position); else diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/SelectionSegment.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/SelectionSegment.cs index d58faf7a00..729c325a1a 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/SelectionSegment.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/SelectionSegment.cs @@ -11,16 +11,19 @@ namespace ICSharpCode.AvalonEdit.Editing /// public class SelectionSegment : ISegment { - int startOffset, endOffset; - int startVC, endVC; + readonly int startOffset, endOffset; + readonly int startVC, endVC; + + public bool AllowVirtualSpace { get; private set; } public SelectionSegment(int startOffset, int endOffset) { this.startOffset = Math.Min(startOffset, endOffset); this.endOffset = Math.Max(startOffset, endOffset); + this.startVC = this.endVC = -1; } - public SelectionSegment(int startOffset, int startVC, int endOffset, int endVC) + public SelectionSegment(int startOffset, int startVC, int endOffset, int endVC, bool allowVirtualSpace) { if (startOffset <= endOffset) { this.startOffset = startOffset; @@ -33,6 +36,7 @@ namespace ICSharpCode.AvalonEdit.Editing this.endOffset = startOffset; this.endVC = startVC; } + this.AllowVirtualSpace = allowVirtualSpace; } public int StartOffset { @@ -59,5 +63,10 @@ namespace ICSharpCode.AvalonEdit.Editing public int Length { 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/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/SimpleSelection.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/SimpleSelection.cs index b4a6f565ee..f461d2e166 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/SimpleSelection.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/SimpleSelection.cs @@ -15,22 +15,25 @@ namespace ICSharpCode.AvalonEdit.Editing /// sealed class SimpleSelection : Selection { + readonly TextViewPosition start, end; readonly int startOffset, endOffset; /// /// Creates a new SimpleSelection instance. /// - internal SimpleSelection(TextArea textArea, int startOffset, int endOffset) + internal SimpleSelection(TextArea textArea, TextViewPosition start, TextViewPosition end) : base(textArea) { - this.startOffset = startOffset; - this.endOffset = endOffset; + this.start = start; + this.end = end; + this.startOffset = textArea.Document.GetOffset(start.Location); + this.endOffset = textArea.Document.GetOffset(end.Location); } /// public override IEnumerable Segments { get { - return ExtensionMethods.Sequence(new SelectionSegment(startOffset, endOffset)); + return ExtensionMethods.Sequence(new SelectionSegment(startOffset, start.VisualColumn, endOffset, end.VisualColumn, textArea.Options.EnableVirtualSpace)); } } @@ -47,25 +50,20 @@ namespace ICSharpCode.AvalonEdit.Editing if (newText == null) throw new ArgumentNullException("newText"); using (textArea.Document.RunUpdate()) { - if (IsEmpty) { - if (newText.Length > 0) { - if (textArea.ReadOnlySectionProvider.CanInsert(textArea.Caret.Offset)) { - textArea.Document.Insert(textArea.Caret.Offset, newText); + ISegment[] segmentsToDelete = textArea.GetDeletableSegments(this.SurroundingSegment); + 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, start); } + textArea.Caret.Offset = segmentsToDelete[i].EndOffset; + textArea.Document.Replace(segmentsToDelete[i], newText); + } else { + textArea.Document.Remove(segmentsToDelete[i]); } - } else { - ISegment[] segmentsToDelete = textArea.GetDeletableSegments(this.SurroundingSegment); - for (int i = segmentsToDelete.Length - 1; i >= 0; i--) { - if (i == segmentsToDelete.Length - 1) { - textArea.Caret.Offset = segmentsToDelete[i].EndOffset; - textArea.Document.Replace(segmentsToDelete[i], newText); - } else { - textArea.Document.Remove(segmentsToDelete[i]); - } - } - if (segmentsToDelete.Length != 0) { - textArea.ClearSelection(); - } + } + if (segmentsToDelete.Length != 0) { + textArea.ClearSelection(); } } } @@ -111,7 +109,7 @@ namespace ICSharpCode.AvalonEdit.Editing /// public override Selection SetEndpoint(TextViewPosition endPosition) { - return Create(textArea, startOffset, textArea.Document.GetOffset(endPosition)); + return Create(textArea, start, endPosition); } public override Selection StartSelectionOrSetEndpoint(TextViewPosition startPosition, TextViewPosition endPosition) @@ -119,7 +117,7 @@ namespace ICSharpCode.AvalonEdit.Editing var document = textArea.Document; if (document == null) throw ThrowUtil.NoDocumentAssigned(); - return Create(textArea, startOffset, document.GetOffset(endPosition)); + return Create(textArea, start, endPosition); } /// @@ -135,13 +133,13 @@ namespace ICSharpCode.AvalonEdit.Editing { SimpleSelection other = obj as SimpleSelection; if (other == null) return false; - return this.startOffset == other.startOffset && this.endOffset == other.endOffset && this.textArea == other.textArea; + return this.start.Equals(other.start) && this.end.Equals(other.end) && this.textArea == other.textArea; } /// public override string ToString() { - return "[SimpleSelection Start=" + startOffset + " End=" + endOffset + "]"; + return "[SimpleSelection Start=" + start + " End=" + end + "]"; } } } diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/TextArea.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/TextArea.cs index 5513684090..984e47ca0c 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/TextArea.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/TextArea.cs @@ -386,11 +386,11 @@ namespace ICSharpCode.AvalonEdit.Editing if (value.textArea != this) throw new ArgumentException("Cannot use a Selection instance that belongs to another text area."); if (!object.Equals(selection, value)) { - //Debug.WriteLine("Selection change from " + selection + " to " + value); +// Debug.WriteLine("Selection change from " + selection + " to " + value); if (textView != null) { ISegment oldSegment = selection.SurroundingSegment; ISegment newSegment = value.SurroundingSegment; - if (selection is SimpleSelection && value is SimpleSelection && oldSegment != null && newSegment != null) { + if (!Options.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; diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/BackgroundGeometryBuilder.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/BackgroundGeometryBuilder.cs index 367b12340a..0f3989752e 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/BackgroundGeometryBuilder.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/BackgroundGeometryBuilder.cs @@ -5,10 +5,12 @@ using System; using System.Collections.Generic; using System.Linq; using System.Windows; +using System.Windows.Controls.Primitives; using System.Windows.Media; using System.Windows.Media.TextFormatting; using ICSharpCode.AvalonEdit.Document; +using ICSharpCode.AvalonEdit.Editing; using ICSharpCode.AvalonEdit.Utils; namespace ICSharpCode.AvalonEdit.Rendering @@ -38,6 +40,11 @@ namespace ICSharpCode.AvalonEdit.Rendering /// public bool AlignToMiddleOfPixels { get; set; } + /// + /// Gets/Sets whether to extend the rectangles to full width at line end. + /// + public bool ExtendToFullWidthAtLineEnd { get; set; } + /// /// Creates a new BackgroundGeometryBuilder instance. /// @@ -53,7 +60,7 @@ namespace ICSharpCode.AvalonEdit.Rendering if (textView == null) throw new ArgumentNullException("textView"); Size pixelSize = PixelSnapHelpers.GetPixelSize(textView); - foreach (Rect r in GetRectsForSegment(textView, segment)) { + foreach (Rect r in GetRectsForSegment(textView, segment, ExtendToFullWidthAtLineEnd)) { if (AlignToWholePixels) { AddRectangle(PixelSnapHelpers.Round(r.Left, pixelSize.Width), PixelSnapHelpers.Round(r.Top + 1, pixelSize.Height), @@ -74,21 +81,33 @@ namespace ICSharpCode.AvalonEdit.Rendering /// Calculates the list of rectangle where the segment in shown. /// This returns one rectangle for each line inside the segment. /// - public static IEnumerable GetRectsForSegment(TextView textView, ISegment segment) + public static IEnumerable GetRectsForSegment(TextView textView, ISegment segment, bool extendToFullWidthAtLineEnd = false) { if (textView == null) throw new ArgumentNullException("textView"); if (segment == null) throw new ArgumentNullException("segment"); - return GetRectsForSegmentImpl(textView, segment); + return GetRectsForSegmentImpl(textView, segment, extendToFullWidthAtLineEnd); } - static IEnumerable GetRectsForSegmentImpl(TextView textView, ISegment segment) + static IEnumerable GetRectsForSegmentImpl(TextView textView, ISegment segment, bool extendToFullWidthAtLineEnd) { Vector scrollOffset = textView.ScrollOffset; int segmentStart = segment.Offset; int segmentEnd = segment.Offset + segment.Length; + TextViewPosition start; + TextViewPosition end; + + if (segment is SelectionSegment) { + SelectionSegment sel = (SelectionSegment)segment; + start = new TextViewPosition(textView.Document.GetLocation(sel.StartOffset), sel.StartVisualColumn); + end = new TextViewPosition(textView.Document.GetLocation(sel.EndOffset), sel.EndVisualColumn); + } else { + start = new TextViewPosition(textView.Document.GetLocation(segmentStart), -1); + end = new TextViewPosition(textView.Document.GetLocation(segmentEnd), -1); + } + foreach (VisualLine vl in textView.VisualLines) { int vlStartOffset = vl.FirstDocumentLine.Offset; if (vlStartOffset > segmentEnd) @@ -101,13 +120,13 @@ namespace ICSharpCode.AvalonEdit.Rendering if (segmentStart < vlStartOffset) segmentStartVC = 0; else - segmentStartVC = vl.GetVisualColumn(segmentStart - vlStartOffset); + segmentStartVC = vl.ValidateVisualColumn(start, extendToFullWidthAtLineEnd); int segmentEndVC; if (segmentEnd > vlEndOffset) - segmentEndVC = vl.VisualLength; + segmentEndVC = extendToFullWidthAtLineEnd ? int.MaxValue : vl.VisualLength; else - segmentEndVC = vl.GetVisualColumn(segmentEnd - vlStartOffset); + segmentEndVC = vl.ValidateVisualColumn(end, extendToFullWidthAtLineEnd); TextLine lastTextLine = vl.TextLines.Last(); @@ -121,7 +140,7 @@ namespace ICSharpCode.AvalonEdit.Rendering if (segmentEndVC < visualStartCol) break; - if (segmentStartVC > visualEndCol) + if (lastTextLine != line && segmentStartVC > visualEndCol) continue; int segmentStartVCInLine = Math.Max(segmentStartVC, visualStartCol); int segmentEndVCInLine = Math.Min(segmentEndVC, visualEndCol); @@ -140,14 +159,33 @@ namespace ICSharpCode.AvalonEdit.Rendering continue; yield return new Rect(pos, y, 1, line.Height); } else { - foreach (TextBounds b in line.GetTextBounds(segmentStartVCInLine, segmentEndVCInLine - segmentStartVCInLine)) { - double left = b.Rectangle.Left; - double right = b.Rectangle.Right; - left -= scrollOffset.X; - right -= scrollOffset.X; - // left>right is possible in RTL languages - yield return new Rect(Math.Min(left, right), y, Math.Abs(right - left), line.Height); + Rect lastRect = Rect.Empty; + if (segmentStartVCInLine <= visualEndCol) { + foreach (TextBounds b in line.GetTextBounds(segmentStartVCInLine, segmentEndVCInLine - segmentStartVCInLine)) { + double left = b.Rectangle.Left - scrollOffset.X; + double right = b.Rectangle.Right - scrollOffset.X; + if (!lastRect.IsEmpty) + yield return lastRect; + // left>right is possible in RTL languages + 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(line, segmentStartVC) : line.Width) - scrollOffset.X; + double right = (segmentEndVC == int.MaxValue ? Math.Max(((IScrollInfo)textView).ExtentWidth, ((IScrollInfo)textView).ViewportWidth) : vl.GetTextLineVisualXPosition(line, segmentEndVC)) - scrollOffset.X; + Rect extendSelection = new Rect(Math.Min(left, right), y, Math.Abs(right - left), line.Height); + if (!lastRect.IsEmpty) { + if (extendSelection.IntersectsWith(lastRect)) { + lastRect.Union(extendSelection); + yield return lastRect; + } else { + yield return lastRect; + yield return extendSelection; + } + } else + yield return extendSelection; + } else + yield return lastRect; } } } diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/TextView.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/TextView.cs index b4ef080727..41a7db2929 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/TextView.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/TextView.cs @@ -609,6 +609,18 @@ namespace ICSharpCode.AvalonEdit.Rendering InvalidateMeasure(DispatcherPriority.Normal); } + /// + /// Causes a known layer to redraw. + /// This method does not invalidate visual lines; + /// use the method to do that. + /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "knownLayer", + Justification="This method is meant to invalidate only a specific layer - I just haven't figured out how to do that, yet.")] + public void InvalidateLayer(KnownLayer knownLayer, DispatcherPriority priority) + { + InvalidateMeasure(priority); + } + /// /// Causes the text editor to redraw all lines overlapping with the specified segment. /// Does nothing if segment is null. diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/VisualLine.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/VisualLine.cs index 22309b5b8d..ea86ef907c 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/VisualLine.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/VisualLine.cs @@ -351,6 +351,26 @@ namespace ICSharpCode.AvalonEdit.Rendering return ch.FirstCharacterIndex + ch.TrailingLength; } + public int ValidateVisualColumn(TextViewPosition position, bool allowVirtualSpace) + { + int offset = Document.GetOffset(position); + int firstDocumentLineOffset = this.FirstDocumentLine.Offset; + if (position.VisualColumn < 0) { + return GetVisualColumn(offset - firstDocumentLineOffset); + } else { + int offsetFromVisualColumn = GetRelativeOffset(position.VisualColumn); + offsetFromVisualColumn += firstDocumentLineOffset; + if (offsetFromVisualColumn != offset) { + return GetVisualColumn(offset - firstDocumentLineOffset); + } else { + if (position.VisualColumn > VisualLength && !allowVirtualSpace) { + return VisualLength; + } + } + } + return position.VisualColumn; + } + /// /// Gets the visual column from a document position (relative to top left of the document). /// If the user clicks between two visual columns, returns the first of those columns. diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Search/SearchPanel.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Search/SearchPanel.cs index f1ecd84d8c..cb4c9970e4 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Search/SearchPanel.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Search/SearchPanel.cs @@ -279,7 +279,7 @@ namespace ICSharpCode.AvalonEdit.Search if (!string.IsNullOrEmpty(SearchPattern)) { int offset = textArea.Caret.Offset; if (changeSelection) { - textArea.Selection = SimpleSelection.Empty; + textArea.ClearSelection(); } foreach (SearchResult result in strategy.FindAll(textArea.Document, 0, textArea.Document.TextLength)) { if (currentResult == null && result.StartOffset >= offset) { @@ -303,7 +303,7 @@ namespace ICSharpCode.AvalonEdit.Search void SetResult(SearchResult result) { textArea.Caret.Offset = currentResult.StartOffset; - textArea.Selection = new SimpleSelection(currentResult.StartOffset, currentResult.EndOffset); + textArea.Selection = Selection.Create(textArea, currentResult.StartOffset, currentResult.EndOffset); var foldingManager = textArea.GetService(typeof(FoldingManager)) as FoldingManager; if (foldingManager != null) { foreach (var folding in foldingManager.GetFoldingsContaining(result.StartOffset))