Browse Source

Backspace now deletes only a single combining mark.

Backspace no longer is equivalent to Shift+Left followed by Delete. Caret movement with Shift+Left will select the whole grapheme; only backspace can be used to delete part of a grapheme.
newNRILSpyDebugger
Daniel Grunwald 12 years ago
parent
commit
ebb5d25c35
  1. 16
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit.Tests/Utils/CaretNavigationTests.cs
  2. 198
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/CaretNavigationCommandHandler.cs
  3. 48
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/EditingCommandHandler.cs
  4. 16
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/SimpleSelection.cs

16
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit.Tests/Utils/CaretNavigationTests.cs

@ -113,5 +113,21 @@ namespace ICSharpCode.AvalonEdit.Utils
Assert.AreEqual(5, GetPrevCaretStop(c, 6, CaretPositioningMode.WordBorder)); Assert.AreEqual(5, GetPrevCaretStop(c, 6, CaretPositioningMode.WordBorder));
Assert.AreEqual(1, GetPrevCaretStop(c, 5, CaretPositioningMode.WordBorder)); Assert.AreEqual(1, GetPrevCaretStop(c, 5, CaretPositioningMode.WordBorder));
} }
[Test]
public void CombiningMark()
{
string str = " x͆ ";
Assert.AreEqual(3, GetNextCaretStop(str, 1, CaretPositioningMode.Normal));
Assert.AreEqual(1, GetPrevCaretStop(str, 3, CaretPositioningMode.Normal));
}
[Test]
public void StackedCombiningMark()
{
string str = " x͆͆͆͆ ";
Assert.AreEqual(6, GetNextCaretStop(str, 1, CaretPositioningMode.Normal));
Assert.AreEqual(1, GetPrevCaretStop(str, 6, CaretPositioningMode.Normal));
}
} }
} }

198
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/CaretNavigationCommandHandler.cs

@ -15,6 +15,24 @@ using ICSharpCode.AvalonEdit.Utils;
namespace ICSharpCode.AvalonEdit.Editing namespace ICSharpCode.AvalonEdit.Editing
{ {
enum CaretMovementType
{
None,
CharLeft,
CharRight,
Backspace,
WordLeft,
WordRight,
LineUp,
LineDown,
PageUp,
PageDown,
LineStart,
LineEnd,
DocumentStart,
DocumentEnd
}
static class CaretNavigationCommandHandler static class CaretNavigationCommandHandler
{ {
/// <summary> /// <summary>
@ -102,22 +120,6 @@ namespace ICSharpCode.AvalonEdit.Editing
return target as TextArea; return target as TextArea;
} }
enum CaretMovementType
{
CharLeft,
CharRight,
WordLeft,
WordRight,
LineUp,
LineDown,
PageUp,
PageDown,
LineStart,
LineEnd,
DocumentStart,
DocumentEnd
}
static ExecutedRoutedEventHandler OnMoveCaret(CaretMovementType direction) static ExecutedRoutedEventHandler OnMoveCaret(CaretMovementType direction)
{ {
return (target, args) => { return (target, args) => {
@ -140,8 +142,7 @@ namespace ICSharpCode.AvalonEdit.Editing
TextViewPosition oldPosition = textArea.Caret.Position; TextViewPosition oldPosition = textArea.Caret.Position;
MoveCaret(textArea, direction); MoveCaret(textArea, direction);
textArea.Selection = textArea.Selection.StartSelectionOrSetEndpoint(oldPosition, textArea.Caret.Position); textArea.Selection = textArea.Selection.StartSelectionOrSetEndpoint(oldPosition, textArea.Caret.Position);
if (!textArea.Document.IsInUpdate) // if we're inside a larger update (e.g. called by EditingCommandHandler.OnDelete()), avoid calculating the caret rectangle now textArea.Caret.BringCaretToView();
textArea.Caret.BringCaretToView();
} }
}; };
} }
@ -172,43 +173,55 @@ namespace ICSharpCode.AvalonEdit.Editing
} }
#region Caret movement #region Caret movement
static void MoveCaret(TextArea textArea, CaretMovementType direction) internal static void MoveCaret(TextArea textArea, CaretMovementType direction)
{ {
DocumentLine caretLine = textArea.Document.GetLineByNumber(textArea.Caret.Line); double desiredXPos = textArea.Caret.DesiredXPos;
VisualLine visualLine = textArea.TextView.GetOrConstructVisualLine(caretLine); textArea.Caret.Position = GetNewCaretPosition(textArea.TextView, textArea.Caret.Position, direction, textArea.Selection.EnableVirtualSpace, ref desiredXPos);
TextViewPosition caretPosition = textArea.Caret.Position; textArea.Caret.DesiredXPos = desiredXPos;
}
internal static TextViewPosition GetNewCaretPosition(TextView textView, TextViewPosition caretPosition, CaretMovementType direction, bool enableVirtualSpace, ref double desiredXPos)
{
switch (direction) {
case CaretMovementType.None:
return caretPosition;
case CaretMovementType.DocumentStart:
desiredXPos = double.NaN;
return new TextViewPosition(0, 0);
case CaretMovementType.DocumentEnd:
desiredXPos = double.NaN;
return new TextViewPosition(textView.Document.GetLocation(textView.Document.TextLength));
}
DocumentLine caretLine = textView.Document.GetLineByNumber(caretPosition.Line);
VisualLine visualLine = textView.GetOrConstructVisualLine(caretLine);
TextLine textLine = visualLine.GetTextLine(caretPosition.VisualColumn, caretPosition.IsAtEndOfLine); TextLine textLine = visualLine.GetTextLine(caretPosition.VisualColumn, caretPosition.IsAtEndOfLine);
switch (direction) { switch (direction) {
case CaretMovementType.CharLeft: case CaretMovementType.CharLeft:
MoveCaretLeft(textArea, caretPosition, visualLine, CaretPositioningMode.Normal); desiredXPos = double.NaN;
break; return GetPrevCaretPosition(textView, caretPosition, visualLine, CaretPositioningMode.Normal, enableVirtualSpace);
case CaretMovementType.Backspace:
desiredXPos = double.NaN;
return GetPrevCaretPosition(textView, caretPosition, visualLine, CaretPositioningMode.EveryCodepoint, enableVirtualSpace);
case CaretMovementType.CharRight: case CaretMovementType.CharRight:
MoveCaretRight(textArea, caretPosition, visualLine, CaretPositioningMode.Normal); desiredXPos = double.NaN;
break; return GetNextCaretPosition(textView, caretPosition, visualLine, CaretPositioningMode.Normal, enableVirtualSpace);
case CaretMovementType.WordLeft: case CaretMovementType.WordLeft:
MoveCaretLeft(textArea, caretPosition, visualLine, CaretPositioningMode.WordStart); desiredXPos = double.NaN;
break; return GetPrevCaretPosition(textView, caretPosition, visualLine, CaretPositioningMode.WordStart, enableVirtualSpace);
case CaretMovementType.WordRight: case CaretMovementType.WordRight:
MoveCaretRight(textArea, caretPosition, visualLine, CaretPositioningMode.WordStart); desiredXPos = double.NaN;
break; return GetNextCaretPosition(textView, caretPosition, visualLine, CaretPositioningMode.WordStart, enableVirtualSpace);
case CaretMovementType.LineUp: case CaretMovementType.LineUp:
case CaretMovementType.LineDown: case CaretMovementType.LineDown:
case CaretMovementType.PageUp: case CaretMovementType.PageUp:
case CaretMovementType.PageDown: case CaretMovementType.PageDown:
MoveCaretUpDown(textArea, direction, visualLine, textLine, caretPosition.VisualColumn); return GetUpDownCaretPosition(textView, caretPosition, direction, visualLine, textLine, enableVirtualSpace, ref desiredXPos);
break;
case CaretMovementType.DocumentStart:
SetCaretPosition(textArea, 0, 0);
break;
case CaretMovementType.DocumentEnd:
SetCaretPosition(textArea, -1, textArea.Document.TextLength);
break;
case CaretMovementType.LineStart: case CaretMovementType.LineStart:
MoveCaretToStartOfLine(textArea, visualLine, textLine); desiredXPos = double.NaN;
break; return GetStartOfLineCaretPosition(caretPosition.VisualColumn, visualLine, textLine, enableVirtualSpace);
case CaretMovementType.LineEnd: case CaretMovementType.LineEnd:
MoveCaretToEndOfLine(textArea, visualLine, textLine); desiredXPos = double.NaN;
break; return GetEndOfLineCaretPosition(visualLine, textLine);
default: default:
throw new NotSupportedException(direction.ToString()); throw new NotSupportedException(direction.ToString());
} }
@ -216,81 +229,80 @@ namespace ICSharpCode.AvalonEdit.Editing
#endregion #endregion
#region Home/End #region Home/End
static void MoveCaretToStartOfLine(TextArea textArea, VisualLine visualLine, TextLine textLine) static TextViewPosition GetStartOfLineCaretPosition(int oldVC, VisualLine visualLine, TextLine textLine, bool enableVirtualSpace)
{ {
int newVC = visualLine.GetTextLineVisualStartColumn(textLine); int newVC = visualLine.GetTextLineVisualStartColumn(textLine);
if (newVC == 0) if (newVC == 0)
newVC = visualLine.GetNextCaretPosition(newVC - 1, LogicalDirection.Forward, CaretPositioningMode.WordStart, textArea.Selection.EnableVirtualSpace); newVC = visualLine.GetNextCaretPosition(newVC - 1, LogicalDirection.Forward, CaretPositioningMode.WordStart, enableVirtualSpace);
if (newVC < 0) if (newVC < 0)
throw ThrowUtil.NoValidCaretPosition(); throw ThrowUtil.NoValidCaretPosition();
// when the caret is already at the start of the text, jump to start before whitespace // when the caret is already at the start of the text, jump to start before whitespace
if (newVC == textArea.Caret.VisualColumn) if (newVC == oldVC)
newVC = 0; newVC = 0;
int offset = visualLine.FirstDocumentLine.Offset + visualLine.GetRelativeOffset(newVC); return visualLine.GetTextViewPosition(newVC);
SetCaretPosition(textArea, newVC, offset);
} }
static void MoveCaretToEndOfLine(TextArea textArea, VisualLine visualLine, TextLine textLine) static TextViewPosition GetEndOfLineCaretPosition(VisualLine visualLine, TextLine textLine)
{ {
int newVC = visualLine.GetTextLineVisualStartColumn(textLine) + textLine.Length - textLine.TrailingWhitespaceLength; int newVC = visualLine.GetTextLineVisualStartColumn(textLine) + textLine.Length - textLine.TrailingWhitespaceLength;
int offset = visualLine.FirstDocumentLine.Offset + visualLine.GetRelativeOffset(newVC); TextViewPosition pos = visualLine.GetTextViewPosition(newVC);
SetCaretPosition(textArea, newVC, offset, isAtEndOfLine: true); pos.IsAtEndOfLine = true;
return pos;
} }
#endregion #endregion
#region By-character / By-word movement #region By-character / By-word movement
static void MoveCaretRight(TextArea textArea, TextViewPosition caretPosition, VisualLine visualLine, CaretPositioningMode mode) static TextViewPosition GetNextCaretPosition(TextView textView, TextViewPosition caretPosition, VisualLine visualLine, CaretPositioningMode mode, bool enableVirtualSpace)
{ {
int pos = visualLine.GetNextCaretPosition(caretPosition.VisualColumn, LogicalDirection.Forward, mode, textArea.Selection.EnableVirtualSpace); int pos = visualLine.GetNextCaretPosition(caretPosition.VisualColumn, LogicalDirection.Forward, mode, enableVirtualSpace);
if (pos >= 0) { if (pos >= 0) {
SetCaretPosition(textArea, pos, visualLine.GetRelativeOffset(pos) + visualLine.FirstDocumentLine.Offset); return visualLine.GetTextViewPosition(pos);
} else { } else {
// move to start of next line // move to start of next line
DocumentLine nextDocumentLine = visualLine.LastDocumentLine.NextLine; DocumentLine nextDocumentLine = visualLine.LastDocumentLine.NextLine;
if (nextDocumentLine != null) { if (nextDocumentLine != null) {
VisualLine nextLine = textArea.TextView.GetOrConstructVisualLine(nextDocumentLine); VisualLine nextLine = textView.GetOrConstructVisualLine(nextDocumentLine);
pos = nextLine.GetNextCaretPosition(-1, LogicalDirection.Forward, mode, textArea.Selection.EnableVirtualSpace); pos = nextLine.GetNextCaretPosition(-1, LogicalDirection.Forward, mode, enableVirtualSpace);
if (pos < 0) if (pos < 0)
throw ThrowUtil.NoValidCaretPosition(); throw ThrowUtil.NoValidCaretPosition();
SetCaretPosition(textArea, pos, nextLine.GetRelativeOffset(pos) + nextLine.FirstDocumentLine.Offset); return nextLine.GetTextViewPosition(pos);
} else { } else {
// at end of document // at end of document
Debug.Assert(visualLine.LastDocumentLine.Offset + visualLine.LastDocumentLine.TotalLength == textArea.Document.TextLength); Debug.Assert(visualLine.LastDocumentLine.Offset + visualLine.LastDocumentLine.TotalLength == textView.Document.TextLength);
SetCaretPosition(textArea, -1, textArea.Document.TextLength); return new TextViewPosition(textView.Document.GetLocation(textView.Document.TextLength));
} }
} }
} }
static void MoveCaretLeft(TextArea textArea, TextViewPosition caretPosition, VisualLine visualLine, CaretPositioningMode mode) static TextViewPosition GetPrevCaretPosition(TextView textView, TextViewPosition caretPosition, VisualLine visualLine, CaretPositioningMode mode, bool enableVirtualSpace)
{ {
int pos = visualLine.GetNextCaretPosition(caretPosition.VisualColumn, LogicalDirection.Backward, mode, textArea.Selection.EnableVirtualSpace); int pos = visualLine.GetNextCaretPosition(caretPosition.VisualColumn, LogicalDirection.Backward, mode, enableVirtualSpace);
if (pos >= 0) { if (pos >= 0) {
SetCaretPosition(textArea, pos, visualLine.GetRelativeOffset(pos) + visualLine.FirstDocumentLine.Offset); return visualLine.GetTextViewPosition(pos);
} else { } else {
// move to end of previous line // move to end of previous line
DocumentLine previousDocumentLine = visualLine.FirstDocumentLine.PreviousLine; DocumentLine previousDocumentLine = visualLine.FirstDocumentLine.PreviousLine;
if (previousDocumentLine != null) { if (previousDocumentLine != null) {
VisualLine previousLine = textArea.TextView.GetOrConstructVisualLine(previousDocumentLine); VisualLine previousLine = textView.GetOrConstructVisualLine(previousDocumentLine);
pos = previousLine.GetNextCaretPosition(previousLine.VisualLength + 1, LogicalDirection.Backward, mode, textArea.Selection.EnableVirtualSpace); pos = previousLine.GetNextCaretPosition(previousLine.VisualLength + 1, LogicalDirection.Backward, mode, enableVirtualSpace);
if (pos < 0) if (pos < 0)
throw ThrowUtil.NoValidCaretPosition(); throw ThrowUtil.NoValidCaretPosition();
SetCaretPosition(textArea, pos, previousLine.GetRelativeOffset(pos) + previousLine.FirstDocumentLine.Offset); return previousLine.GetTextViewPosition(pos);
} else { } else {
// at start of document // at start of document
Debug.Assert(visualLine.FirstDocumentLine.Offset == 0); Debug.Assert(visualLine.FirstDocumentLine.Offset == 0);
SetCaretPosition(textArea, 0, 0); return new TextViewPosition(0, 0);
} }
} }
} }
#endregion #endregion
#region Line+Page up/down #region Line+Page up/down
static void MoveCaretUpDown(TextArea textArea, CaretMovementType direction, VisualLine visualLine, TextLine textLine, int caretVisualColumn) static TextViewPosition GetUpDownCaretPosition(TextView textView, TextViewPosition caretPosition, CaretMovementType direction, VisualLine visualLine, TextLine textLine, bool enableVirtualSpace, ref double xPos)
{ {
// moving up/down happens using the desired visual X position // moving up/down happens using the desired visual X position
double xPos = textArea.Caret.DesiredXPos;
if (double.IsNaN(xPos)) if (double.IsNaN(xPos))
xPos = visualLine.GetTextLineVisualXPosition(textLine, caretVisualColumn); xPos = visualLine.GetTextLineVisualXPosition(textLine, caretPosition.VisualColumn);
// now find the TextLine+VisualLine where the caret will end up in // now find the TextLine+VisualLine where the caret will end up in
VisualLine targetVisualLine = visualLine; VisualLine targetVisualLine = visualLine;
TextLine targetLine; TextLine targetLine;
@ -304,8 +316,8 @@ namespace ICSharpCode.AvalonEdit.Editing
if (textLineIndex > 0) { if (textLineIndex > 0) {
targetLine = visualLine.TextLines[textLineIndex - 1]; targetLine = visualLine.TextLines[textLineIndex - 1];
} else if (prevLineNumber >= 1) { } else if (prevLineNumber >= 1) {
DocumentLine prevLine = textArea.Document.GetLineByNumber(prevLineNumber); DocumentLine prevLine = textView.Document.GetLineByNumber(prevLineNumber);
targetVisualLine = textArea.TextView.GetOrConstructVisualLine(prevLine); targetVisualLine = textView.GetOrConstructVisualLine(prevLine);
targetLine = targetVisualLine.TextLines[targetVisualLine.TextLines.Count - 1]; targetLine = targetVisualLine.TextLines[targetVisualLine.TextLines.Count - 1];
} else { } else {
targetLine = null; targetLine = null;
@ -319,9 +331,9 @@ namespace ICSharpCode.AvalonEdit.Editing
int nextLineNumber = visualLine.LastDocumentLine.LineNumber + 1; int nextLineNumber = visualLine.LastDocumentLine.LineNumber + 1;
if (textLineIndex < visualLine.TextLines.Count - 1) { if (textLineIndex < visualLine.TextLines.Count - 1) {
targetLine = visualLine.TextLines[textLineIndex + 1]; targetLine = visualLine.TextLines[textLineIndex + 1];
} else if (nextLineNumber <= textArea.Document.LineCount) { } else if (nextLineNumber <= textView.Document.LineCount) {
DocumentLine nextLine = textArea.Document.GetLineByNumber(nextLineNumber); DocumentLine nextLine = textView.Document.GetLineByNumber(nextLineNumber);
targetVisualLine = textArea.TextView.GetOrConstructVisualLine(nextLine); targetVisualLine = textView.GetOrConstructVisualLine(nextLine);
targetLine = targetVisualLine.TextLines[0]; targetLine = targetVisualLine.TextLines[0];
} else { } else {
targetLine = null; targetLine = null;
@ -334,11 +346,11 @@ namespace ICSharpCode.AvalonEdit.Editing
// Page up/down: find the target line using its visual position // Page up/down: find the target line using its visual position
double yPos = visualLine.GetTextLineVisualYPosition(textLine, VisualYPosition.LineMiddle); double yPos = visualLine.GetTextLineVisualYPosition(textLine, VisualYPosition.LineMiddle);
if (direction == CaretMovementType.PageUp) if (direction == CaretMovementType.PageUp)
yPos -= textArea.TextView.RenderSize.Height; yPos -= textView.RenderSize.Height;
else else
yPos += textArea.TextView.RenderSize.Height; yPos += textView.RenderSize.Height;
DocumentLine newLine = textArea.TextView.GetDocumentLineByVisualTop(yPos); DocumentLine newLine = textView.GetDocumentLineByVisualTop(yPos);
targetVisualLine = textArea.TextView.GetOrConstructVisualLine(newLine); targetVisualLine = textView.GetOrConstructVisualLine(newLine);
targetLine = targetVisualLine.GetTextLineByVisualYPosition(yPos); targetLine = targetVisualLine.GetTextLineByVisualYPosition(yPos);
break; break;
} }
@ -347,30 +359,18 @@ namespace ICSharpCode.AvalonEdit.Editing
} }
if (targetLine != null) { if (targetLine != null) {
double yPos = targetVisualLine.GetTextLineVisualYPosition(targetLine, VisualYPosition.LineMiddle); double yPos = targetVisualLine.GetTextLineVisualYPosition(targetLine, VisualYPosition.LineMiddle);
int newVisualColumn = targetVisualLine.GetVisualColumn(new Point(xPos, yPos), textArea.Selection.EnableVirtualSpace); int newVisualColumn = targetVisualLine.GetVisualColumn(new Point(xPos, yPos), enableVirtualSpace);
SetCaretPosition(textArea, targetVisualLine, targetLine, newVisualColumn, false);
textArea.Caret.DesiredXPos = xPos;
}
}
#endregion
#region SetCaretPosition // prevent wrapping to the next line; TODO: could 'IsAtEnd' help here?
static void SetCaretPosition(TextArea textArea, VisualLine targetVisualLine, TextLine targetLine, int targetLineStartCol = targetVisualLine.GetTextLineVisualStartColumn(targetLine);
int newVisualColumn, bool allowWrapToNextLine) if (newVisualColumn >= targetLineStartCol + targetLine.Length) {
{ if (newVisualColumn <= targetVisualLine.VisualLength)
int targetLineStartCol = targetVisualLine.GetTextLineVisualStartColumn(targetLine); newVisualColumn = targetLineStartCol + targetLine.Length - 1;
if (!allowWrapToNextLine && newVisualColumn >= targetLineStartCol + targetLine.Length) { }
if (newVisualColumn <= targetVisualLine.VisualLength) return targetVisualLine.GetTextViewPosition(newVisualColumn);
newVisualColumn = targetLineStartCol + targetLine.Length - 1; } else {
return caretPosition;
} }
int newOffset = targetVisualLine.GetRelativeOffset(newVisualColumn) + targetVisualLine.FirstDocumentLine.Offset;
SetCaretPosition(textArea, newVisualColumn, newOffset);
}
static void SetCaretPosition(TextArea textArea, int newVisualColumn, int newOffset, bool isAtEndOfLine = false)
{
textArea.Caret.Position = new TextViewPosition(textArea.Document.GetLocation(newOffset), newVisualColumn) { IsAtEndOfLine = isAtEndOfLine };
textArea.Caret.DesiredXPos = double.NaN;
} }
#endregion #endregion
} }

48
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/EditingCommandHandler.cs

@ -46,12 +46,12 @@ namespace ICSharpCode.AvalonEdit.Editing
static EditingCommandHandler() static EditingCommandHandler()
{ {
CommandBindings.Add(new CommandBinding(ApplicationCommands.Delete, OnDelete(ApplicationCommands.NotACommand), CanDelete)); CommandBindings.Add(new CommandBinding(ApplicationCommands.Delete, OnDelete(CaretMovementType.None), CanDelete));
AddBinding(EditingCommands.Delete, ModifierKeys.None, Key.Delete, OnDelete(EditingCommands.SelectRightByCharacter)); AddBinding(EditingCommands.Delete, ModifierKeys.None, Key.Delete, OnDelete(CaretMovementType.CharRight));
AddBinding(EditingCommands.DeleteNextWord, ModifierKeys.Control, Key.Delete, OnDelete(EditingCommands.SelectRightByWord)); AddBinding(EditingCommands.DeleteNextWord, ModifierKeys.Control, Key.Delete, OnDelete(CaretMovementType.WordRight));
AddBinding(EditingCommands.Backspace, ModifierKeys.None, Key.Back, OnDelete(EditingCommands.SelectLeftByCharacter)); AddBinding(EditingCommands.Backspace, ModifierKeys.None, Key.Back, OnDelete(CaretMovementType.Backspace));
InputBindings.Add(TextAreaDefaultInputHandler.CreateFrozenKeyBinding(EditingCommands.Backspace, ModifierKeys.Shift, Key.Back)); // make Shift-Backspace do the same as plain backspace InputBindings.Add(TextAreaDefaultInputHandler.CreateFrozenKeyBinding(EditingCommands.Backspace, ModifierKeys.Shift, Key.Back)); // make Shift-Backspace do the same as plain backspace
AddBinding(EditingCommands.DeletePreviousWord, ModifierKeys.Control, Key.Back, OnDelete(EditingCommands.SelectLeftByWord)); AddBinding(EditingCommands.DeletePreviousWord, ModifierKeys.Control, Key.Back, OnDelete(CaretMovementType.WordLeft));
AddBinding(EditingCommands.EnterParagraphBreak, ModifierKeys.None, Key.Enter, OnEnter); AddBinding(EditingCommands.EnterParagraphBreak, ModifierKeys.None, Key.Enter, OnEnter);
AddBinding(EditingCommands.EnterLineBreak, ModifierKeys.Shift, Key.Enter, OnEnter); AddBinding(EditingCommands.EnterLineBreak, ModifierKeys.Shift, Key.Enter, OnEnter);
AddBinding(EditingCommands.TabForward, ModifierKeys.None, Key.Tab, OnTab); AddBinding(EditingCommands.TabForward, ModifierKeys.None, Key.Tab, OnTab);
@ -225,34 +225,24 @@ namespace ICSharpCode.AvalonEdit.Editing
#endregion #endregion
#region Delete #region Delete
static ExecutedRoutedEventHandler OnDelete(RoutedUICommand selectingCommand) static ExecutedRoutedEventHandler OnDelete(CaretMovementType caretMovement)
{ {
return (target, args) => { return (target, args) => {
TextArea textArea = GetTextArea(target); TextArea textArea = GetTextArea(target);
if (textArea != null && textArea.Document != null) { if (textArea != null && textArea.Document != null) {
// call BeginUpdate before running the 'selectingCommand' if (textArea.Selection.IsEmpty) {
// so that undoing the delete does not select the deleted character TextViewPosition startPos = textArea.Caret.Position;
using (textArea.Document.RunUpdate()) { bool enableVirtualSpace = textArea.Options.EnableVirtualSpace;
if (textArea.Selection.IsEmpty) { // When pressing delete; don't move the caret further into virtual space - instead delete the newline
TextViewPosition oldCaretPosition = textArea.Caret.Position; if (caretMovement == CaretMovementType.CharRight)
if (textArea.Caret.IsInVirtualSpace && selectingCommand == EditingCommands.SelectRightByCharacter) enableVirtualSpace = false;
EditingCommands.SelectRightByWord.Execute(args.Parameter, textArea); double desiredXPos = textArea.Caret.DesiredXPos;
else TextViewPosition endPos = CaretNavigationCommandHandler.GetNewCaretPosition(
selectingCommand.Execute(args.Parameter, textArea); textArea.TextView, startPos, caretMovement, enableVirtualSpace, ref desiredXPos);
bool hasSomethingDeletable = false; // Don't select the text to be deleted; just reuse the ReplaceSelectionWithText logic
foreach (ISegment s in textArea.Selection.Segments) { var sel = new SimpleSelection(textArea, startPos, endPos);
if (textArea.GetDeletableSegments(s).Length > 0) { sel.ReplaceSelectionWithText(string.Empty);
hasSomethingDeletable = true; } else {
break;
}
}
if (!hasSomethingDeletable) {
// If nothing in the selection is deletable; then reset caret+selection
// to the previous value. This prevents the caret from moving through read-only sections.
textArea.Caret.Position = oldCaretPosition;
textArea.ClearSelection();
}
}
textArea.RemoveSelectedText(); textArea.RemoveSelectedText();
} }
textArea.Caret.BringCaretToView(); textArea.Caret.BringCaretToView();

16
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/SimpleSelection.cs

@ -55,10 +55,16 @@ namespace ICSharpCode.AvalonEdit.Editing
if (segmentsToDelete[i].Offset == SurroundingSegment.Offset && segmentsToDelete[i].Length == SurroundingSegment.Length) { if (segmentsToDelete[i].Offset == SurroundingSegment.Offset && segmentsToDelete[i].Length == SurroundingSegment.Length) {
newText = AddSpacesIfRequired(newText, start, end); newText = AddSpacesIfRequired(newText, start, end);
} }
int vc = textArea.Caret.VisualColumn; if (string.IsNullOrEmpty(newText)) {
textArea.Caret.Offset = segmentsToDelete[i].EndOffset; // place caret at the beginning of the selection
if (string.IsNullOrEmpty(newText)) if (start.CompareTo(end) <= 0)
textArea.Caret.VisualColumn = vc; textArea.Caret.Position = start;
else
textArea.Caret.Position = end;
} else {
// place caret so that it ends up behind the new text
textArea.Caret.Offset = segmentsToDelete[i].EndOffset;
}
textArea.Document.Replace(segmentsToDelete[i], newText); textArea.Document.Replace(segmentsToDelete[i], newText);
} else { } else {
textArea.Document.Remove(segmentsToDelete[i]); textArea.Document.Remove(segmentsToDelete[i]);
@ -100,7 +106,7 @@ namespace ICSharpCode.AvalonEdit.Editing
/// <inheritdoc/> /// <inheritdoc/>
public override bool IsEmpty { public override bool IsEmpty {
get { return startOffset == endOffset; } get { return startOffset == endOffset && start.VisualColumn == end.VisualColumn; }
} }
/// <inheritdoc/> /// <inheritdoc/>

Loading…
Cancel
Save