diff --git a/src/AvaloniaEdit/AvaloniaEdit.csproj b/src/AvaloniaEdit/AvaloniaEdit.csproj
index 6605d29f..553b2285 100644
--- a/src/AvaloniaEdit/AvaloniaEdit.csproj
+++ b/src/AvaloniaEdit/AvaloniaEdit.csproj
@@ -17,6 +17,7 @@
+
diff --git a/src/AvaloniaEdit/AvaloniaEditCommands.cs b/src/AvaloniaEdit/AvaloniaEditCommands.cs
index dd87f17b..5b523d6f 100644
--- a/src/AvaloniaEdit/AvaloniaEditCommands.cs
+++ b/src/AvaloniaEdit/AvaloniaEditCommands.cs
@@ -20,7 +20,7 @@
using System.Runtime.InteropServices;
using Avalonia;
using Avalonia.Input;
-using Avalonia.Platform;
+using Avalonia.Labs.Input;
namespace AvaloniaEdit
{
@@ -115,13 +115,8 @@ public static class ApplicationCommands
public static RoutedCommand Replace { get; } = new RoutedCommand(nameof(Replace), GetReplaceKeyGesture());
private static KeyModifiers GetPlatformCommandKey()
- {
- if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
- {
- return KeyModifiers.Meta;
- }
-
- return KeyModifiers.Control;
+ {
+ return Application.Current?.PlatformSettings?.HotkeyConfiguration.CommandModifiers ?? KeyModifiers.Control;
}
private static KeyGesture GetReplaceKeyGesture()
diff --git a/src/AvaloniaEdit/Editing/CaretNavigationCommandHandler.cs b/src/AvaloniaEdit/Editing/CaretNavigationCommandHandler.cs
index dc7c3710..100211c9 100644
--- a/src/AvaloniaEdit/Editing/CaretNavigationCommandHandler.cs
+++ b/src/AvaloniaEdit/Editing/CaretNavigationCommandHandler.cs
@@ -25,6 +25,7 @@
using AvaloniaEdit.Utils;
using Avalonia.Input;
using Avalonia.Input.Platform;
+using Avalonia.Labs.Input;
using Avalonia.Media.TextFormatting;
using LogicalDirection = AvaloniaEdit.Document.LogicalDirection;
@@ -61,12 +62,12 @@ public static TextAreaInputHandler Create(TextArea textArea)
return handler;
}
- static readonly List CommandBindings = new List();
+ static readonly List CommandBindings = new List();
static readonly List KeyBindings = new List();
private static void AddBinding(RoutedCommand command, EventHandler handler)
{
- CommandBindings.Add(new RoutedCommandBinding(command, handler));
+ CommandBindings.Add(new CommandBinding(command, handler));
}
private static void AddBinding(RoutedCommand command, KeyModifiers modifiers, Key key, EventHandler handler)
diff --git a/src/AvaloniaEdit/Editing/EditingCommandHandler.cs b/src/AvaloniaEdit/Editing/EditingCommandHandler.cs
index 50940a74..6f5395f6 100644
--- a/src/AvaloniaEdit/Editing/EditingCommandHandler.cs
+++ b/src/AvaloniaEdit/Editing/EditingCommandHandler.cs
@@ -25,6 +25,7 @@
using Avalonia.Input;
using AvaloniaEdit.Utils;
using Avalonia.Controls;
+using Avalonia.Labs.Input;
namespace AvaloniaEdit.Editing
{
@@ -45,19 +46,19 @@ public static TextAreaInputHandler Create(TextArea textArea)
return handler;
}
- private static readonly List CommandBindings = new List();
+ private static readonly List CommandBindings = new List();
private static readonly List KeyBindings = new List();
private static void AddBinding(RoutedCommand command, KeyModifiers modifiers, Key key,
EventHandler handler)
{
- CommandBindings.Add(new RoutedCommandBinding(command, handler));
+ CommandBindings.Add(new CommandBinding(command, handler));
KeyBindings.Add(TextAreaDefaultInputHandler.CreateKeyBinding(command, modifiers, key));
}
private static void AddBinding(RoutedCommand command, EventHandler handler, EventHandler canExecuteHandler = null)
{
- CommandBindings.Add(new RoutedCommandBinding(command, handler, canExecuteHandler));
+ CommandBindings.Add(new CommandBinding(command, handler, canExecuteHandler));
}
static EditingCommandHandler()
diff --git a/src/AvaloniaEdit/Editing/RectangleSelection.cs b/src/AvaloniaEdit/Editing/RectangleSelection.cs
index 0c53fa2a..c33dd689 100644
--- a/src/AvaloniaEdit/Editing/RectangleSelection.cs
+++ b/src/AvaloniaEdit/Editing/RectangleSelection.cs
@@ -21,6 +21,7 @@
using System.Linq;
using System.Text;
using Avalonia;
+using Avalonia.Labs.Input;
using AvaloniaEdit.Document;
using AvaloniaEdit.Utils;
diff --git a/src/AvaloniaEdit/Editing/TextArea.cs b/src/AvaloniaEdit/Editing/TextArea.cs
index cf300858..08c431c6 100644
--- a/src/AvaloniaEdit/Editing/TextArea.cs
+++ b/src/AvaloniaEdit/Editing/TextArea.cs
@@ -39,13 +39,14 @@
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
+using Avalonia.Labs.Input;
namespace AvaloniaEdit.Editing
{
///
/// Control that wraps a TextView and adds support for user input and the caret.
///
- public class TextArea : TemplatedControl, ITextEditorComponent, IRoutedCommandBindable, ILogicalScrollable
+ public class TextArea : TemplatedControl, ITextEditorComponent, ILogicalScrollable
{
///
/// This is the extra scrolling space that occurs after the last line.
@@ -1075,7 +1076,7 @@ internal void OnTextCopied(TextEventArgs e)
TextCopied?.Invoke(this, e);
}
- public IList CommandBindings { get; } = new List();
+ public IList CommandBindings => CommandManager.GetCommandBindings(this);
bool ILogicalScrollable.IsLogicalScrollEnabled => _logicalScrollable?.IsLogicalScrollEnabled ?? default(bool);
diff --git a/src/AvaloniaEdit/Editing/TextAreaDefaultInputHandlers.cs b/src/AvaloniaEdit/Editing/TextAreaDefaultInputHandlers.cs
index c0e796f9..31d56cbf 100644
--- a/src/AvaloniaEdit/Editing/TextAreaDefaultInputHandlers.cs
+++ b/src/AvaloniaEdit/Editing/TextAreaDefaultInputHandlers.cs
@@ -20,6 +20,7 @@
using System.Windows.Input;
using AvaloniaEdit.Document;
using Avalonia.Input;
+using Avalonia.Labs.Input;
namespace AvaloniaEdit.Editing
{
@@ -58,7 +59,7 @@ public TextAreaDefaultInputHandler(TextArea textArea) : base(textArea)
private void AddBinding(RoutedCommand command, EventHandler handler, EventHandler canExecuteHandler = null)
{
- CommandBindings.Add(new RoutedCommandBinding(command, handler, canExecuteHandler));
+ CommandBindings.Add(new CommandBinding(command, handler, canExecuteHandler));
}
internal static KeyBinding CreateKeyBinding(ICommand command, KeyModifiers modifiers, Key key)
diff --git a/src/AvaloniaEdit/Editing/TextAreaInputHandler.cs b/src/AvaloniaEdit/Editing/TextAreaInputHandler.cs
index ce7aa252..f00e53a0 100644
--- a/src/AvaloniaEdit/Editing/TextAreaInputHandler.cs
+++ b/src/AvaloniaEdit/Editing/TextAreaInputHandler.cs
@@ -18,8 +18,10 @@
using System;
using System.Collections.Generic;
+using System.Linq;
using AvaloniaEdit.Utils;
using Avalonia.Input;
+using Avalonia.Labs.Input;
namespace AvaloniaEdit.Editing
{
@@ -108,7 +110,7 @@ public virtual void OnPreviewKeyUp(KeyEventArgs e)
///
public class TextAreaInputHandler : ITextAreaInputHandler
{
- private readonly ObserveAddRemoveCollection _commandBindings;
+ private readonly ObserveAddRemoveCollection _commandBindings;
private readonly List _keyBindings;
private readonly ObserveAddRemoveCollection _nestedInputHandlers;
@@ -118,7 +120,7 @@ public class TextAreaInputHandler : ITextAreaInputHandler
public TextAreaInputHandler(TextArea textArea)
{
TextArea = textArea ?? throw new ArgumentNullException(nameof(textArea));
- _commandBindings = new ObserveAddRemoveCollection(CommandBinding_Added, CommandBinding_Removed);
+ _commandBindings = new ObserveAddRemoveCollection(CommandBinding_Added, CommandBinding_Removed);
_keyBindings = new List();
_nestedInputHandlers = new ObserveAddRemoveCollection(NestedInputHandler_Added, NestedInputHandler_Removed);
}
@@ -135,15 +137,15 @@ public TextAreaInputHandler(TextArea textArea)
///
/// Gets the command bindings of this input handler.
///
- public ICollection CommandBindings => _commandBindings;
+ public ICollection CommandBindings => _commandBindings;
- private void CommandBinding_Added(RoutedCommandBinding commandBinding)
+ private void CommandBinding_Added(CommandBinding commandBinding)
{
if (IsAttached)
TextArea.CommandBindings.Add(commandBinding);
}
- private void CommandBinding_Removed(RoutedCommandBinding commandBinding)
+ private void CommandBinding_Removed(CommandBinding commandBinding)
{
if (IsAttached)
TextArea.CommandBindings.Remove(commandBinding);
@@ -175,7 +177,7 @@ private void CommandBinding_Removed(RoutedCommandBinding commandBinding)
/// The event handler to run when the command is executed.
public void AddBinding(RoutedCommand command, KeyModifiers modifiers, Key key, EventHandler handler)
{
- CommandBindings.Add(new RoutedCommandBinding(command, handler));
+ CommandBindings.Add(new CommandBinding(command, handler));
KeyBindings.Add(new KeyBinding { Command = command, Gesture = new KeyGesture (key, modifiers) });
}
#endregion
@@ -218,9 +220,10 @@ private void TextAreaOnKeyDown(object sender, KeyEventArgs keyEventArgs)
foreach (var commandBinding in CommandBindings)
{
- if (commandBinding.Command.Gesture?.Matches(keyEventArgs) == true)
+ if (commandBinding.Command is RoutedCommand routedCommand
+ && routedCommand.Gestures.Any(g => g.Matches(keyEventArgs)))
{
- commandBinding.Command.Execute(null, (IInputElement)sender);
+ routedCommand.Execute(null, (IInputElement)sender);
keyEventArgs.Handled = true;
break;
}
diff --git a/src/AvaloniaEdit/RoutedCommand.cs b/src/AvaloniaEdit/RoutedCommand.cs
deleted file mode 100644
index 7a204d76..00000000
--- a/src/AvaloniaEdit/RoutedCommand.cs
+++ /dev/null
@@ -1,194 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Windows.Input;
-using Avalonia.Input;
-using Avalonia.Interactivity;
-
-namespace AvaloniaEdit
-{
- public class RoutedCommand : ICommand
- {
- private static IInputElement _inputElement;
-
- public string Name { get; }
- public KeyGesture Gesture { get; }
-
- public RoutedCommand(string name, KeyGesture keyGesture = null)
- {
- Name = name;
- Gesture = keyGesture;
- }
-
- static RoutedCommand()
- {
- CanExecuteEvent.AddClassHandler(CanExecuteEventHandler);
- ExecutedEvent.AddClassHandler(ExecutedEventHandler);
- InputElement.GotFocusEvent.AddClassHandler(GotFocusEventHandler);
- }
-
- private static void CanExecuteEventHandler(Interactive control, CanExecuteRoutedEventArgs args)
- {
- if (control is IRoutedCommandBindable bindable)
- {
- var binding = bindable.CommandBindings.Where(c => c != null)
- .FirstOrDefault(c => c.Command == args.Command && c.DoCanExecute(control, args));
- args.CanExecute = binding != null;
- }
- }
-
- private static void ExecutedEventHandler(Interactive control, ExecutedRoutedEventArgs args)
- {
- if (control is IRoutedCommandBindable bindable)
- {
- // ReSharper disable once UnusedVariable
- var binding = bindable.CommandBindings.Where(c => c != null)
- .FirstOrDefault(c => c.Command == args.Command && c.DoExecuted(control, args));
-
- }
- }
-
- private static void GotFocusEventHandler(Interactive control, GotFocusEventArgs args)
- {
- _inputElement = args.Source as IInputElement;
- }
-
- public static RoutedEvent CanExecuteEvent { get; } = RoutedEvent.Register(nameof(CanExecuteEvent), RoutingStrategies.Bubble, typeof(RoutedCommand));
-
- public bool CanExecute(object parameter, IInputElement target)
- {
- if (target == null) return false;
-
- var args = new CanExecuteRoutedEventArgs(this, parameter);
- target.RaiseEvent(args);
-
- return args.CanExecute;
- }
-
- bool ICommand.CanExecute(object parameter)
- {
- return CanExecute(parameter, _inputElement);
- }
-
- public static RoutedEvent ExecutedEvent { get; } = RoutedEvent.Register(nameof(ExecutedEvent), RoutingStrategies.Bubble, typeof(RoutedCommand));
-
- public void Execute(object parameter, IInputElement target)
- {
- if (target == null) return;
-
- var args = new ExecutedRoutedEventArgs(this, parameter);
- target.RaiseEvent(args);
- }
-
- void ICommand.Execute(object parameter)
- {
- Execute(parameter, _inputElement);
- }
-
- // TODO
- event EventHandler ICommand.CanExecuteChanged
- {
- add { }
- remove { }
- }
- }
-
- public interface IRoutedCommandBindable
- {
- IList CommandBindings { get; }
- }
-
- public class RoutedCommandBinding
- {
- public RoutedCommandBinding(RoutedCommand command,
- EventHandler executed = null,
- EventHandler canExecute = null)
- {
- Command = command;
- if (executed != null) Executed += executed;
- if (canExecute != null) CanExecute += canExecute;
- }
-
- public RoutedCommand Command { get; }
-
- public event EventHandler CanExecute;
-
- public event EventHandler Executed;
-
- internal bool DoCanExecute(object sender, CanExecuteRoutedEventArgs e)
- {
- if (e.Handled) return true;
-
- var canExecute = CanExecute;
- if (canExecute == null)
- {
- if (Executed != null)
- {
- e.Handled = true;
- e.CanExecute = true;
- }
- }
- else
- {
- canExecute(sender, e);
-
- if (e.CanExecute)
- {
- e.Handled = true;
- }
- }
-
- return e.CanExecute;
- }
-
- internal bool DoExecuted(object sender, ExecutedRoutedEventArgs e)
- {
- if (!e.Handled)
- {
- var executed = Executed;
-
- if (executed != null)
- {
- if (DoCanExecute(sender, new CanExecuteRoutedEventArgs(e.Command, e.Parameter)))
- {
- executed(sender, e);
- e.Handled = true;
- return true;
- }
- }
- }
-
- return false;
- }
- }
-
- public sealed class CanExecuteRoutedEventArgs : RoutedEventArgs
- {
- public ICommand Command { get; }
-
- public object Parameter { get; }
-
- public bool CanExecute { get; set; }
-
- internal CanExecuteRoutedEventArgs(ICommand command, object parameter)
- {
- Command = command ?? throw new ArgumentNullException(nameof(command));
- Parameter = parameter;
- RoutedEvent = RoutedCommand.CanExecuteEvent;
- }
- }
-
- public sealed class ExecutedRoutedEventArgs : RoutedEventArgs
- {
- public ICommand Command { get; }
-
- public object Parameter { get; }
-
- internal ExecutedRoutedEventArgs(ICommand command, object parameter)
- {
- Command = command ?? throw new ArgumentNullException(nameof(command));
- Parameter = parameter;
- RoutedEvent = RoutedCommand.ExecutedEvent;
- }
- }
-}
\ No newline at end of file
diff --git a/src/AvaloniaEdit/Search/SearchCommands.cs b/src/AvaloniaEdit/Search/SearchCommands.cs
index 3303f654..c01411f3 100644
--- a/src/AvaloniaEdit/Search/SearchCommands.cs
+++ b/src/AvaloniaEdit/Search/SearchCommands.cs
@@ -19,6 +19,7 @@
using System;
using System.Collections.Generic;
using Avalonia.Input;
+using Avalonia.Labs.Input;
using Avalonia.Threading;
using AvaloniaEdit.Editing;
@@ -67,23 +68,23 @@ public SearchInputHandler(TextArea textArea, SearchPanel panel)
_panel = panel;
}
- internal void RegisterGlobalCommands(ICollection commandBindings)
+ internal void RegisterGlobalCommands(ICollection commandBindings)
{
- commandBindings.Add(new RoutedCommandBinding(ApplicationCommands.Find, ExecuteFind));
- CommandBindings.Add(new RoutedCommandBinding(ApplicationCommands.Replace, ExecuteReplace));
- commandBindings.Add(new RoutedCommandBinding(SearchCommands.FindNext, ExecuteFindNext, CanExecuteWithOpenSearchPanel));
- commandBindings.Add(new RoutedCommandBinding(SearchCommands.FindPrevious, ExecuteFindPrevious, CanExecuteWithOpenSearchPanel));
+ commandBindings.Add(new CommandBinding(ApplicationCommands.Find, ExecuteFind));
+ CommandBindings.Add(new CommandBinding(ApplicationCommands.Replace, ExecuteReplace));
+ commandBindings.Add(new CommandBinding(SearchCommands.FindNext, ExecuteFindNext, CanExecuteWithOpenSearchPanel));
+ commandBindings.Add(new CommandBinding(SearchCommands.FindPrevious, ExecuteFindPrevious, CanExecuteWithOpenSearchPanel));
}
- private void RegisterCommands(ICollection commandBindings)
+ private void RegisterCommands(ICollection commandBindings)
{
- commandBindings.Add(new RoutedCommandBinding(ApplicationCommands.Find, ExecuteFind));
- CommandBindings.Add(new RoutedCommandBinding(ApplicationCommands.Replace, ExecuteReplace));
- commandBindings.Add(new RoutedCommandBinding(SearchCommands.FindNext, ExecuteFindNext, CanExecuteWithOpenSearchPanel));
- commandBindings.Add(new RoutedCommandBinding(SearchCommands.FindPrevious, ExecuteFindPrevious, CanExecuteWithOpenSearchPanel));
- CommandBindings.Add(new RoutedCommandBinding(SearchCommands.ReplaceNext, ExecuteReplaceNext, CanExecuteWithOpenSearchPanel));
- CommandBindings.Add(new RoutedCommandBinding(SearchCommands.ReplaceAll, ExecuteReplaceAll, CanExecuteWithOpenSearchPanel));
- commandBindings.Add(new RoutedCommandBinding(SearchCommands.CloseSearchPanel, ExecuteCloseSearchPanel, CanExecuteWithOpenSearchPanel));
+ commandBindings.Add(new CommandBinding(ApplicationCommands.Find, ExecuteFind));
+ CommandBindings.Add(new CommandBinding(ApplicationCommands.Replace, ExecuteReplace));
+ commandBindings.Add(new CommandBinding(SearchCommands.FindNext, ExecuteFindNext, CanExecuteWithOpenSearchPanel));
+ commandBindings.Add(new CommandBinding(SearchCommands.FindPrevious, ExecuteFindPrevious, CanExecuteWithOpenSearchPanel));
+ CommandBindings.Add(new CommandBinding(SearchCommands.ReplaceNext, ExecuteReplaceNext, CanExecuteWithOpenSearchPanel));
+ CommandBindings.Add(new CommandBinding(SearchCommands.ReplaceAll, ExecuteReplaceAll, CanExecuteWithOpenSearchPanel));
+ commandBindings.Add(new CommandBinding(SearchCommands.CloseSearchPanel, ExecuteCloseSearchPanel, CanExecuteWithOpenSearchPanel));
}
private readonly SearchPanel _panel;
diff --git a/src/AvaloniaEdit/Search/SearchPanel.cs b/src/AvaloniaEdit/Search/SearchPanel.cs
index 1dd23585..42f88896 100644
--- a/src/AvaloniaEdit/Search/SearchPanel.cs
+++ b/src/AvaloniaEdit/Search/SearchPanel.cs
@@ -23,6 +23,7 @@
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Input;
+using Avalonia.Labs.Input;
using Avalonia.Media;
using AvaloniaEdit.Document;
@@ -35,7 +36,7 @@ namespace AvaloniaEdit.Search
///
/// Provides search functionality for AvalonEdit. It is displayed in the top-right corner of the TextArea.
///
- public class SearchPanel : TemplatedControl, IRoutedCommandBindable
+ public class SearchPanel : TemplatedControl
{
private TextArea _textArea;
private SearchInputHandler _handler;
@@ -198,7 +199,7 @@ public static SearchPanel Install(TextEditor editor)
///
/// Adds the commands used by SearchPanel to the given CommandBindingCollection.
///
- public void RegisterCommands(ICollection commandBindings)
+ public void RegisterCommands(ICollection commandBindings)
{
_handler.RegisterGlobalCommands(commandBindings);
}
@@ -227,18 +228,18 @@ private void AttachInternal(TextEditor textEditor)
_textArea.DocumentChanged += TextArea_DocumentChanged;
KeyDown += SearchLayerKeyDown;
- CommandBindings.Add(new RoutedCommandBinding(SearchCommands.FindNext, (sender, e) => FindNext()));
- CommandBindings.Add(new RoutedCommandBinding(SearchCommands.FindPrevious, (sender, e) => FindPrevious()));
- CommandBindings.Add(new RoutedCommandBinding(SearchCommands.CloseSearchPanel, (sender, e) => Close()));
+ CommandBindings.Add(new CommandBinding(SearchCommands.FindNext, (sender, e) => FindNext()));
+ CommandBindings.Add(new CommandBinding(SearchCommands.FindPrevious, (sender, e) => FindPrevious()));
+ CommandBindings.Add(new CommandBinding(SearchCommands.CloseSearchPanel, (sender, e) => Close()));
- CommandBindings.Add(new RoutedCommandBinding(ApplicationCommands.Find, (sender, e) =>
+ CommandBindings.Add(new CommandBinding(ApplicationCommands.Find, (sender, e) =>
{
IsReplaceMode = false;
Reactivate();
}));
- CommandBindings.Add(new RoutedCommandBinding(ApplicationCommands.Replace, (sender, e) => IsReplaceMode = true));
- CommandBindings.Add(new RoutedCommandBinding(SearchCommands.ReplaceNext, (sender, e) => ReplaceNext(), (sender, e) => e.CanExecute = IsReplaceMode));
- CommandBindings.Add(new RoutedCommandBinding(SearchCommands.ReplaceAll, (sender, e) => ReplaceAll(), (sender, e) => e.CanExecute = IsReplaceMode));
+ CommandBindings.Add(new CommandBinding(ApplicationCommands.Replace, (sender, e) => IsReplaceMode = true));
+ CommandBindings.Add(new CommandBinding(SearchCommands.ReplaceNext, (sender, e) => ReplaceNext(), (sender, e) => e.CanExecute = IsReplaceMode));
+ CommandBindings.Add(new CommandBinding(SearchCommands.ReplaceAll, (sender, e) => ReplaceAll(), (sender, e) => e.CanExecute = IsReplaceMode));
IsClosed = true;
}
@@ -559,7 +560,7 @@ protected virtual void OnSearchOptionsChanged(SearchOptionsChangedEventArgs e)
SearchOptionsChanged?.Invoke(this, e);
}
- public IList CommandBindings { get; } = new List();
+ public IList CommandBindings => CommandManager.GetCommandBindings(this);
}
///