diff --git a/src/AddIns/Misc/SearchAndReplace/Project/Commands/SearchToolbarCommands.cs b/src/AddIns/Misc/SearchAndReplace/Project/Commands/SearchToolbarCommands.cs
index 738bef2e9b..4b1366daf5 100644
--- a/src/AddIns/Misc/SearchAndReplace/Project/Commands/SearchToolbarCommands.cs
+++ b/src/AddIns/Misc/SearchAndReplace/Project/Commands/SearchToolbarCommands.cs
@@ -35,8 +35,8 @@ namespace SearchAndReplace
void OnKeyPress(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter) {
- CommitSearch();
e.Handled = true;
+ CommitSearch();
}
}
diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/Caret.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/Caret.cs
index 472bb13523..cdeed6b49b 100644
--- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/Caret.cs
+++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/Caret.cs
@@ -5,13 +5,13 @@
// $Revision$
//
+using ICSharpCode.AvalonEdit.Utils;
using System;
using System.Diagnostics;
using System.Windows;
using System.Windows.Documents;
using System.Windows.Media.TextFormatting;
using System.Windows.Threading;
-
using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.AvalonEdit.Rendering;
@@ -58,7 +58,7 @@ namespace ICSharpCode.AvalonEdit.Editing
///
/// Gets/Sets the position of the caret.
- /// Retrieving this property will validate the visual column.
+ /// Retrieving this property will validate the visual column (which can be expensive).
/// Use the property instead if you don't need the visual column.
///
public TextViewPosition Position {
@@ -264,7 +264,9 @@ namespace ICSharpCode.AvalonEdit.Editing
// then try backwards
newVisualColumn = visualLine.GetNextCaretPosition(position.VisualColumn + 1, LogicalDirection.Backward, CaretPositioningMode.Normal);
}
- if (newVisualColumn >= 0 && newVisualColumn != position.VisualColumn) {
+ if (newVisualColumn < 0)
+ throw ThrowUtil.NoValidCaretPosition();
+ if (newVisualColumn != position.VisualColumn) {
int newOffset = visualLine.GetRelativeOffset(newVisualColumn) + firstDocumentLineOffset;
this.Position = new TextViewPosition(textView.Document.GetLocation(newOffset), newVisualColumn);
}
@@ -294,7 +296,9 @@ namespace ICSharpCode.AvalonEdit.Editing
{
if (textView != null) {
VisualLine visualLine = textView.GetOrConstructVisualLine(textView.Document.GetLineByNumber(position.Line));
- textView.MakeVisible(CalcCaretRectangle(visualLine));
+ Rect caretRectangle = CalcCaretRectangle(visualLine);
+ caretRectangle.Inflate(30, 30); // leave at least 30 pixels distance to the view border
+ textView.MakeVisible(caretRectangle);
}
}
diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/CaretNavigationCommandHandler.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/CaretNavigationCommandHandler.cs
index 6d3d8b0f36..18a5717778 100644
--- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/CaretNavigationCommandHandler.cs
+++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/CaretNavigationCommandHandler.cs
@@ -7,6 +7,7 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media.TextFormatting;
@@ -185,9 +186,8 @@ namespace ICSharpCode.AvalonEdit.Editing
static void MoveCaretToStartOfLine(TextArea textArea, VisualLine visualLine)
{
int newVC = visualLine.GetNextCaretPosition(-1, LogicalDirection.Forward, CaretPositioningMode.WordStart);
- // in empty lines (whitespace only), jump to the end
if (newVC < 0)
- newVC = visualLine.VisualLength;
+ throw ThrowUtil.NoValidCaretPosition();
// when the caret is already at the start of the text, jump to start before whitespace
if (newVC == textArea.Caret.VisualColumn)
newVC = 0;
@@ -211,18 +211,40 @@ namespace ICSharpCode.AvalonEdit.Editing
SetCaretPosition(textArea, pos, visualLine.GetRelativeOffset(pos) + visualLine.FirstDocumentLine.Offset);
} else {
// move to start of next line
- SetCaretPosition(textArea, 0, visualLine.LastDocumentLine.Offset + visualLine.LastDocumentLine.TotalLength);
+ DocumentLine nextDocumentLine = visualLine.LastDocumentLine.NextLine;
+ if (nextDocumentLine != null) {
+ VisualLine nextLine = textArea.TextView.GetOrConstructVisualLine(nextDocumentLine);
+ pos = nextLine.GetNextCaretPosition(-1, LogicalDirection.Forward, mode);
+ if (pos < 0)
+ throw ThrowUtil.NoValidCaretPosition();
+ SetCaretPosition(textArea, pos, nextLine.GetRelativeOffset(pos) + nextLine.FirstDocumentLine.Offset);
+ } else {
+ // at end of document
+ Debug.Assert(visualLine.LastDocumentLine.Offset + visualLine.LastDocumentLine.TotalLength == textArea.Document.TextLength);
+ SetCaretPosition(textArea, -1, textArea.Document.TextLength);
+ }
}
}
-
+
static void MoveCaretLeft(TextArea textArea, TextViewPosition caretPosition, VisualLine visualLine, CaretPositioningMode mode)
{
int pos = visualLine.GetNextCaretPosition(caretPosition.VisualColumn, LogicalDirection.Backward, mode);
if (pos >= 0) {
SetCaretPosition(textArea, pos, visualLine.GetRelativeOffset(pos) + visualLine.FirstDocumentLine.Offset);
- } else if (caretPosition.Line > 1) {
- DocumentLine prevLine = textArea.Document.GetLineByNumber(caretPosition.Line - 1);
- SetCaretPosition(textArea, -1, prevLine.Offset + prevLine.Length);
+ } else {
+ // move to end of previous line
+ DocumentLine previousDocumentLine = visualLine.FirstDocumentLine.PreviousLine;
+ if (previousDocumentLine != null) {
+ VisualLine previousLine = textArea.TextView.GetOrConstructVisualLine(previousDocumentLine);
+ pos = previousLine.GetNextCaretPosition(previousLine.VisualLength + 1, LogicalDirection.Backward, mode);
+ if (pos < 0)
+ throw ThrowUtil.NoValidCaretPosition();
+ SetCaretPosition(textArea, pos, previousLine.GetRelativeOffset(pos) + previousLine.FirstDocumentLine.Offset);
+ } else {
+ // at start of document
+ Debug.Assert(visualLine.FirstDocumentLine.Offset == 0);
+ SetCaretPosition(textArea, 0, 0);
+ }
}
}
#endregion
diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/EditingCommandHandler.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/EditingCommandHandler.cs
index c8afb01915..737c48034f 100644
--- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/EditingCommandHandler.cs
+++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/EditingCommandHandler.cs
@@ -232,16 +232,6 @@ namespace ICSharpCode.AvalonEdit.Editing
if (textArea.Selection.IsEmpty)
selectingCommand.Execute(args.Parameter, textArea);
textArea.RemoveSelectedText();
- if (selectingCommand == EditingCommands.SelectLeftByWord) {
- // Special case: when Ctrl+Backspace deletes until the start of the line,
- // also delete the previous line delimiter.
- // This allows deleting lines that consist only of indentation using a single
- // press on Ctrl+Backspace.
- if (textArea.Caret.Column == 1 && textArea.Caret.VisualColumn == 0 && textArea.Caret.Line > 1) {
- DocumentLine previousLine = textArea.Document.GetLineByNumber(textArea.Caret.Line - 1);
- textArea.Document.Remove(previousLine.EndOffset, previousLine.DelimiterLength);
- }
- }
}
textArea.Caret.BringCaretToView();
args.Handled = true;
diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/VisualLine.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/VisualLine.cs
index 4def3e5364..6140ea04ea 100644
--- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/VisualLine.cs
+++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/VisualLine.cs
@@ -334,7 +334,8 @@ namespace ICSharpCode.AvalonEdit.Rendering
if (direction == LogicalDirection.Backward) {
// Search Backwards:
// 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) {
+ // (we don't check the mode here: we treat a line end as word start, border, etc.
+ if (visualColumn > this.VisualLength && !elements[elements.Count-1].HandlesLineBorders && HasImplicitStopAtLineEnd(mode)) {
return this.VisualLength;
}
// skip elements that start after or at visualColumn
@@ -350,14 +351,14 @@ namespace ICSharpCode.AvalonEdit.Rendering
if (pos >= 0)
return pos;
}
- // if we've found nothing, and the first element doesn't handle line borders,
- // return the line start as caret stop
- if (visualColumn > 0 && !elements[0].HandlesLineBorders)
+ // If we've found nothing, and the first element doesn't handle line borders,
+ // return the line start as normal caret stop.
+ if (visualColumn > 0 && !elements[0].HandlesLineBorders && HasImplicitStopAtLineStart(mode))
return 0;
} else {
// Search Forwards:
// If the first element doesn't handle line borders, return the line start as caret stop
- if (visualColumn < 0 && !elements[0].HandlesLineBorders)
+ if (visualColumn < 0 && !elements[0].HandlesLineBorders && HasImplicitStopAtLineStart(mode))
return 0;
// skip elements that end before or at visualColumn
for (i = 0; i < elements.Count; i++) {
@@ -374,11 +375,21 @@ 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 (visualColumn < this.VisualLength && !elements[elements.Count-1].HandlesLineBorders)
+ if (visualColumn < this.VisualLength && !elements[elements.Count-1].HandlesLineBorders && HasImplicitStopAtLineEnd(mode))
return this.VisualLength;
}
// we've found nothing, return -1 and let the caret search continue in the next line
return -1;
}
+
+ static bool HasImplicitStopAtLineStart(CaretPositioningMode mode)
+ {
+ return mode == CaretPositioningMode.Normal;
+ }
+
+ static bool HasImplicitStopAtLineEnd(CaretPositioningMode mode)
+ {
+ return true;
+ }
}
}
diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Utils/NullSafeCollection.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Utils/NullSafeCollection.cs
index 0151a8c2c7..4f54f94eef 100644
--- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Utils/NullSafeCollection.cs
+++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Utils/NullSafeCollection.cs
@@ -13,7 +13,7 @@ namespace ICSharpCode.AvalonEdit.Utils
///
/// A collection that cannot contain null values.
///
- public sealed class NullSafeCollection : Collection where T : class
+ public class NullSafeCollection : Collection where T : class
{
///
protected override void InsertItem(int index, T item)
diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Utils/ObserveAddRemoveCollection.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Utils/ObserveAddRemoveCollection.cs
index 2f13a4f972..7e761e4210 100644
--- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Utils/ObserveAddRemoveCollection.cs
+++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Utils/ObserveAddRemoveCollection.cs
@@ -12,6 +12,8 @@ namespace ICSharpCode.AvalonEdit.Utils
{
///
/// A collection where adding and removing items causes a callback.
+ /// It is valid for the onAdd callback to throw an exception - this will prevent the new item from
+ /// being added to the collection.
///
sealed class ObserveAddRemoveCollection : Collection
{
@@ -54,7 +56,8 @@ namespace ICSharpCode.AvalonEdit.Utils
if (onAdd != null)
onAdd(item);
} catch {
- // when adding the new item fails, just remove the old one
+ // When adding the new item fails, just remove the old one
+ // (we cannot keep the old item since we already successfully called onRemove for it)
base.RemoveAt(index);
throw;
}
diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Utils/TextUtilities.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Utils/TextUtilities.cs
index 1b626635a8..86a5b64ad9 100644
--- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Utils/TextUtilities.cs
+++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Utils/TextUtilities.cs
@@ -191,6 +191,11 @@ namespace ICSharpCode.AvalonEdit.Utils
/// The mode for caret positioning.
/// The offset of the next caret position, or -1 if there is no further caret position
/// in the text source.
+ ///
+ /// This method is NOT equivalent to the actual caret movement when using VisualLine.GetNextCaretPosition.
+ /// In real caret movement, there are additional caret stops at line starts and ends. However, this method
+ /// doesn't know anything about lines: it is often called with a textSource that represents only a single VisualTextElement.
+ ///
public static int GetNextCaretPosition(ITextSource textSource, int offset, LogicalDirection direction, CaretPositioningMode mode)
{
if (textSource == null)
diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Utils/ThrowUtil.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Utils/ThrowUtil.cs
index 90832ea91a..a545e26285 100644
--- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Utils/ThrowUtil.cs
+++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Utils/ThrowUtil.cs
@@ -22,7 +22,7 @@ namespace ICSharpCode.AvalonEdit.Utils
/// Use this method to throw an ArgumentNullException when using parameters for base
/// constructor calls.
///
- /// public VisualLineText(string text) : base(ThrowUtil.CheckNull(text, "text").Length)
+ /// public VisualLineText(string text) : base(ThrowUtil.CheckNotNull(text, "text").Length)
///
///
public static T CheckNotNull(T val, string parameterName) where T : class
@@ -43,5 +43,10 @@ namespace ICSharpCode.AvalonEdit.Utils
{
throw new InvalidOperationException("Document is null");
}
+
+ public static InvalidOperationException NoValidCaretPosition()
+ {
+ throw new InvalidOperationException("Could not find a valid caret position in the line");
+ }
}
}
diff --git a/src/Main/Base/Project/Src/Gui/Workbench/WpfWorkbench.xaml b/src/Main/Base/Project/Src/Gui/Workbench/WpfWorkbench.xaml
index 036530e9b5..4444d51dbe 100644
--- a/src/Main/Base/Project/Src/Gui/Workbench/WpfWorkbench.xaml
+++ b/src/Main/Base/Project/Src/Gui/Workbench/WpfWorkbench.xaml
@@ -9,6 +9,6 @@
-
+
\ No newline at end of file