Browse Source
Allow using 'command' attribute on <MenuItem> with custom routed commands defined in AddIns. Implemented offset mapping in AvalonEdit. This allows replacing text in the document without removing all text markers from the replaced region. git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@4191 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61shortcuts
23 changed files with 883 additions and 190 deletions
@ -0,0 +1,91 @@
@@ -0,0 +1,91 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <owner name="Daniel Grunwald"/>
|
||||
// <version>$Revision$</version>
|
||||
// </file>
|
||||
|
||||
using System; |
||||
using System.Windows.Input; |
||||
|
||||
namespace ICSharpCode.AvalonEdit |
||||
{ |
||||
/// <summary>
|
||||
/// Custom commands for AvalonEdit.
|
||||
/// </summary>
|
||||
public static class AvalonEditCommands |
||||
{ |
||||
/// <summary>
|
||||
/// Deletes the current line.
|
||||
/// The default shortcut is Ctrl+D.
|
||||
/// </summary>
|
||||
public static readonly RoutedCommand DeleteLine = new RoutedCommand( |
||||
"DeleteLine", typeof(TextEditor), |
||||
new InputGestureCollection { |
||||
new KeyGesture(Key.D, ModifierKeys.Control) |
||||
}); |
||||
|
||||
/// <summary>
|
||||
/// Removes leading whitespace from the selected lines (or the whole document if the selection is empty).
|
||||
/// </summary>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "Whitespace", |
||||
Justification = "WPF uses 'Whitespace'")] |
||||
public static readonly RoutedCommand RemoveLeadingWhitespace = new RoutedCommand("RemoveLeadingWhitespace", typeof(TextEditor)); |
||||
|
||||
/// <summary>
|
||||
/// Removes trailing whitespace from the selected lines (or the whole document if the selection is empty).
|
||||
/// </summary>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "Whitespace", |
||||
Justification = "WPF uses 'Whitespace'")] |
||||
public static readonly RoutedCommand RemoveTrailingWhitespace = new RoutedCommand("RemoveTrailingWhitespace", typeof(TextEditor)); |
||||
|
||||
/// <summary>
|
||||
/// Converts the selected text to upper case.
|
||||
/// </summary>
|
||||
public static readonly RoutedCommand ConvertToUppercase = new RoutedCommand("ConvertToUppercase", typeof(TextEditor)); |
||||
|
||||
/// <summary>
|
||||
/// Converts the selected text to lower case.
|
||||
/// </summary>
|
||||
public static readonly RoutedCommand ConvertToLowercase = new RoutedCommand("ConvertToLowercase", typeof(TextEditor)); |
||||
|
||||
/// <summary>
|
||||
/// Converts the selected text to title case.
|
||||
/// </summary>
|
||||
public static readonly RoutedCommand ConvertToTitleCase = new RoutedCommand("ConvertToTitleCase", typeof(TextEditor)); |
||||
|
||||
/// <summary>
|
||||
/// Inverts the case of the selected text.
|
||||
/// </summary>
|
||||
public static readonly RoutedCommand InvertCase = new RoutedCommand("InvertCase", typeof(TextEditor)); |
||||
|
||||
/// <summary>
|
||||
/// Converts tabs to spaces in the selected text.
|
||||
/// </summary>
|
||||
public static readonly RoutedCommand ConvertTabsToSpaces = new RoutedCommand("ConvertTabsToSpaces", typeof(TextEditor)); |
||||
|
||||
/// <summary>
|
||||
/// Converts spaces to tabs in the selected text.
|
||||
/// </summary>
|
||||
public static readonly RoutedCommand ConvertSpacesToTabs = new RoutedCommand("ConvertSpacesToTabs", typeof(TextEditor)); |
||||
|
||||
/// <summary>
|
||||
/// Converts leading tabs to spaces in the selected lines (or the whole document if the selection is empty).
|
||||
/// </summary>
|
||||
public static readonly RoutedCommand ConvertLeadingTabsToSpaces = new RoutedCommand("ConvertLeadingTabsToSpaces", typeof(TextEditor)); |
||||
|
||||
/// <summary>
|
||||
/// Converts leading spaces to tabs in the selected lines (or the whole document if the selection is empty).
|
||||
/// </summary>
|
||||
public static readonly RoutedCommand ConvertLeadingSpacesToTabs = new RoutedCommand("ConvertLeadingSpacesToTabs", typeof(TextEditor)); |
||||
|
||||
/// <summary>
|
||||
/// Runs the IIndentationStrategy on the selected lines (or the whole document if the selection is empty).
|
||||
/// </summary>
|
||||
public static readonly RoutedCommand IndentSelection = new RoutedCommand( |
||||
"IndentSelection", typeof(TextEditor), |
||||
new InputGestureCollection { |
||||
new KeyGesture(Key.I, ModifierKeys.Control) |
||||
}); |
||||
} |
||||
} |
@ -0,0 +1,177 @@
@@ -0,0 +1,177 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <owner name="Daniel Grunwald"/>
|
||||
// <version>$Revision$</version>
|
||||
// </file>
|
||||
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Collections.ObjectModel; |
||||
|
||||
namespace ICSharpCode.AvalonEdit.Document |
||||
{ |
||||
/// <summary>
|
||||
/// Contains predefined offset change mapping types.
|
||||
/// </summary>
|
||||
public enum OffsetChangeMappingType |
||||
{ |
||||
/// <summary>
|
||||
/// First the old text is removed, then the new text is inserted.
|
||||
/// </summary>
|
||||
RemoveAndInsert, |
||||
/// <summary>
|
||||
/// The text is replaced character-by-character.
|
||||
/// If the new text is longer than the old text, a single insertion at the end is used to account for the difference.
|
||||
/// If the new text is shorter than the old text, a single deletion at the end is used to account for the difference.
|
||||
/// </summary>
|
||||
CharacterReplace |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Describes a series of offset changes.
|
||||
/// </summary>
|
||||
[Serializable] |
||||
public sealed class OffsetChangeMap : Collection<OffsetChangeMapEntry> |
||||
{ |
||||
/// <summary>
|
||||
/// Immutable OffsetChangeMap that is empty.
|
||||
/// </summary>
|
||||
public static readonly OffsetChangeMap Empty = new OffsetChangeMap(Utils.Empty<OffsetChangeMapEntry>.ReadOnlyCollection); |
||||
|
||||
/// <summary>
|
||||
/// Creates a new OffsetChangeMap instance.
|
||||
/// </summary>
|
||||
public OffsetChangeMap() |
||||
{ |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Creates a new OffsetChangeMap instance.
|
||||
/// </summary>
|
||||
public OffsetChangeMap(int capacity) |
||||
: base(new List<OffsetChangeMapEntry>(capacity)) |
||||
{ |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Private constructor for immutable 'Empty' instance.
|
||||
/// </summary>
|
||||
private OffsetChangeMap(IList<OffsetChangeMapEntry> entries) |
||||
: base(entries) |
||||
{ |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Gets the new offset where the specified offset moves after this document change.
|
||||
/// </summary>
|
||||
public int GetNewOffset(int offset, AnchorMovementType movementType) |
||||
{ |
||||
foreach (OffsetChangeMapEntry entry in this) { |
||||
offset = entry.GetNewOffset(offset, movementType); |
||||
} |
||||
return offset; |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Gets whether this OffsetChangeMap is a valid explanation for the specified document change.
|
||||
/// </summary>
|
||||
public bool IsValidForDocumentChange(int offset, int removalLength, int insertionLength) |
||||
{ |
||||
int endOffset = offset + removalLength; |
||||
foreach (OffsetChangeMapEntry entry in this) { |
||||
// check that ChangeMapEntry is in valid range for this document change
|
||||
if (entry.Offset < offset || entry.Offset + entry.RemovalLength > endOffset) |
||||
return false; |
||||
endOffset += entry.Delta; |
||||
} |
||||
// check that the total delta matches
|
||||
return endOffset == offset + insertionLength; |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Calculates the inverted OffsetChangeMap (used for the undo operation).
|
||||
/// </summary>
|
||||
public OffsetChangeMap Invert() |
||||
{ |
||||
if (this == Empty) |
||||
return this; |
||||
OffsetChangeMap newMap = new OffsetChangeMap(this.Count); |
||||
for (int i = this.Count - 1; i >= 0; i--) { |
||||
OffsetChangeMapEntry entry = this[i]; |
||||
newMap.Add(new OffsetChangeMapEntry(entry.Offset, -entry.Delta)); |
||||
} |
||||
return newMap; |
||||
} |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// An entry in the OffsetChangeMap.
|
||||
/// This represents the offset of a document change (either insertion or removal, not both at once).
|
||||
/// </summary>
|
||||
[Serializable] |
||||
public struct OffsetChangeMapEntry |
||||
{ |
||||
readonly int offset; |
||||
readonly int delta; |
||||
|
||||
/// <summary>
|
||||
/// The offset at which the change occurs.
|
||||
/// </summary>
|
||||
public int Offset { |
||||
get { return offset; } |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// The change delta. If positive, it is equal to InsertionLength; if negative, it is equal to RemovalLength.
|
||||
/// </summary>
|
||||
public int Delta { |
||||
get { return delta; } |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// The number of characters removed.
|
||||
/// Returns 0 if this entry represents an insertion.
|
||||
/// </summary>
|
||||
public int RemovalLength { |
||||
get { |
||||
return delta < 0 ? -delta : 0; |
||||
} |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// The number of characters inserted.
|
||||
/// Returns 0 if this entry represents a removal.
|
||||
/// </summary>
|
||||
public int InsertionLength { |
||||
get { |
||||
return delta > 0 ? delta : 0; |
||||
} |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Gets the new offset where the specified offset moves after this document change.
|
||||
/// </summary>
|
||||
public int GetNewOffset(int oldOffset, AnchorMovementType movementType) |
||||
{ |
||||
if (oldOffset < this.Offset) |
||||
return oldOffset; |
||||
if (oldOffset > this.Offset + this.RemovalLength) |
||||
return oldOffset + this.Delta; |
||||
// offset is inside removed region
|
||||
if (movementType == AnchorMovementType.AfterInsertion) |
||||
return this.Offset + this.InsertionLength; |
||||
else |
||||
return this.Offset; |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Creates a new OffsetChangeMapEntry instance.
|
||||
/// </summary>
|
||||
public OffsetChangeMapEntry(int offset, int delta) |
||||
{ |
||||
this.offset = offset; |
||||
this.delta = delta; |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue