瀏覽代碼

Command API doc and code clenaup

Tig 9 月之前
父節點
當前提交
9e658eed94

+ 2 - 2
Terminal.Gui/Application/Application.Keyboard.cs

@@ -169,7 +169,7 @@ public static partial class Application // Keyboard handling
                                             );
         }
 
-        if (CommandImplementations.TryGetValue (command, out Func<CommandContext, bool?>? implementation))
+        if (CommandImplementations.TryGetValue (command, out View.CommandImplementation? implementation))
         {
             var context = new CommandContext (command, keyEvent, appBinding); // Create the context here
 
@@ -418,7 +418,7 @@ public static partial class Application // Keyboard handling
     /// <summary>
     ///     Commands for Application.
     /// </summary>
-    private static Dictionary<Command, Func<CommandContext, bool?>>? CommandImplementations { get; set; }
+    private static Dictionary<Command, View.CommandImplementation>? CommandImplementations { get; set; }
 
     private static void ReplaceKey (Key oldKey, Key newKey)
     {

+ 3 - 0
Terminal.Gui/Input/CommandContext.cs

@@ -11,6 +11,9 @@ namespace Terminal.Gui;
 ///         use <see cref="View.AddCommand(Command,Func{CommandContext,System.Nullable{bool}})"/>.
 ///     </para>
 /// </remarks>
+/// <seealso cref="Application.KeyBindings"/>
+/// <seealso cref="View.KeyBindings"/>
+/// <seealso cref="Command"/>
 #pragma warning restore CS1574 // XML comment has cref attribute that could not be resolved
 public record struct CommandContext
 {

+ 3 - 0
Terminal.Gui/Input/KeyBinding.cs

@@ -8,6 +8,9 @@ namespace Terminal.Gui;
 /// <summary>
 /// Provides a collection of <see cref="Command"/> objects that are scoped to <see cref="KeyBindingScope"/>.
 /// </summary>
+/// <seealso cref="Application.KeyBindings"/>
+/// <seealso cref="View.KeyBindings"/>
+/// <seealso cref="Command"/>
 public record struct KeyBinding
 {
     /// <summary>Initializes a new instance.</summary>

+ 20 - 4
Terminal.Gui/Input/KeyBindingScope.cs

@@ -7,19 +7,28 @@
 /// <remarks>
 ///     <para>Key bindings are scoped to the most-focused view (<see cref="Focused"/>) by default.</para>
 /// </remarks>
+/// <seealso cref="Application.KeyBindings"/>
+/// <seealso cref="View.KeyBindings"/>
+/// <seealso cref="Command"/>
 [Flags]
 public enum KeyBindingScope
 {
     /// <summary>The key binding is disabled.</summary>
     Disabled = 0,
 
-    /// <summary>The key binding is scoped to just the view that has focus.</summary>
+    /// <summary>
+    ///     The key binding is scoped to just the view that has focus.
+    ///     <para>
+    ///     </para>
+    /// </summary>
+    /// <seealso cref="View.KeyBindings"/>
     Focused = 1,
 
     /// <summary>
-    ///     The key binding is scoped to the View's Superview hierarchy and will be triggered even when the View does not have
+    ///     The key binding is scoped to the View's Superview hierarchy and the bound <see cref="Command"/>s will be invoked
+    ///     even when the View does not have
     ///     focus, as
-    ///     long as the SuperView does have focus. This is typically used for <see cref="View.HotKey"/>s.
+    ///     long as some View up the SuperView hierachy does have focus. This is typically used for <see cref="View.HotKey"/>s.
     ///     <para>
     ///         The View must be visible.
     ///     </para>
@@ -28,15 +37,22 @@ public enum KeyBindingScope
     ///         any of its subviews.
     ///     </para>
     /// </summary>
+    /// <seealso cref="View.KeyBindings"/>
+    /// <seeals cref="View.HotKey"/>
     HotKey = 2,
 
     /// <summary>
-    ///     The key binding will be triggered regardless of which view has focus. This is typically used for global
+    ///     The and the bound <see cref="Command"/>s will be invoked regardless of which View has focus. This is typically used
+    ///     for global
     ///     commands, which are called Shortcuts.
     ///     <para>
+    ///         The View does not need to be visible.
+    ///     </para>
+    ///     <para>
     ///         Application-scoped key bindings are only invoked if the key down event was not handled by the focused view or
     ///         any of its subviews, and if the key was not bound to a <see cref="View.HotKey"/>.
     ///     </para>
     /// </summary>
+    /// <seealso cref="Application.KeyBindings"/>
     Application = 4
 }

+ 3 - 0
Terminal.Gui/Input/KeyBindings.cs

@@ -5,6 +5,9 @@ namespace Terminal.Gui;
 /// <summary>
 ///     Provides a collection of <see cref="KeyBinding"/> objects bound to a <see cref="Key"/>.
 /// </summary>
+/// <seealso cref="Application.KeyBindings"/>
+/// <seealso cref="View.KeyBindings"/>
+/// <seealso cref="Command"/>
 public class KeyBindings
 {
     /// <summary>

+ 47 - 31
Terminal.Gui/View/View.Command.cs

@@ -65,8 +65,9 @@ public partial class View // Command APIs
     /// </para>
     /// </remarks>
     /// <returns>
-    ///     If <see langword="true"/> the event was canceled. If <see langword="false"/> the event was raised but not canceled.
-    ///     If <see langword="null"/> no event was raised.
+    ///     <see langword="null"/> if no event was raised; input proessing should continue.
+    ///     <see langword="false"/> if the event was raised and was not handled (or cancelled); input proessing should continue.
+    ///     <see langword="true"/> if the event was raised and handled (or cancelled); input proessing should stop.
     /// </returns>
     protected bool? RaiseAccepting (CommandContext ctx)
     {
@@ -137,8 +138,9 @@ public partial class View // Command APIs
     ///     The <see cref="Selecting"/> event should raised after the state of the View has been changed and before see <see cref="Accepting"/>.
     /// </remarks>
     /// <returns>
-    ///     If <see langword="true"/> the event was canceled. If <see langword="false"/> the event was raised but not canceled.
-    ///     If <see langword="null"/> no event was raised.
+    ///     <see langword="null"/> if no event was raised; input proessing should continue.
+    ///     <see langword="false"/> if the event was raised and was not handled (or cancelled); input proessing should continue.
+    ///     <see langword="true"/> if the event was raised and handled (or cancelled); input proessing should stop.
     /// </returns>
     protected bool? RaiseSelecting (CommandContext ctx)
     {
@@ -177,8 +179,9 @@ public partial class View // Command APIs
     ///     event. The default <see cref="Command.HotKey"/> handler calls this method.
     /// </summary>
     /// <returns>
-    ///     If <see langword="true"/> the event was handled. If <see langword="false"/> the event was raised but not handled.
-    ///     If <see langword="null"/> no event was raised.
+    ///     <see langword="null"/> if no event was raised; input proessing should continue.
+    ///     <see langword="false"/> if the event was raised and was not handled (or cancelled); input proessing should continue.
+    ///     <see langword="true"/> if the event was raised and handled (or cancelled); input proessing should stop.
     /// </returns>
     protected bool? RaiseHandlingHotKey ()
     {
@@ -213,26 +216,35 @@ public partial class View // Command APIs
 
     #endregion Default Implementation
 
+    /// <summary>
+    /// Function signature commands.
+    /// </summary>
+    /// <param name="ctx">Provides information about the circumstances of invoking the command (e.g. <see cref="CommandContext.Key"/>)</param>
+    /// <returns>
+    ///     <see langword="null"/> if no command was found; input proessing should continue.
+    ///     <see langword="false"/> if the command was invoked and was not handled (or cancelled); input proessing should continue.
+    ///     <see langword="true"/> if the command was invoked the command was handled (or cancelled); input proessing should stop.
+    /// </returns>
+    public delegate bool? CommandImplementation (CommandContext ctx);
+
     /// <summary>
     ///     <para>
     ///         Sets the function that will be invoked for a <see cref="Command"/>. Views should call
     ///         AddCommand for each command they support.
     ///     </para>
     ///     <para>
-    ///         If AddCommand has already been called for <paramref name="command"/> <paramref name="f"/> will
+    ///         If AddCommand has already been called for <paramref name="command"/> <paramref name="impl"/> will
     ///         replace the old one.
     ///     </para>
     /// </summary>
     /// <remarks>
     ///     <para>
-    ///         This version of AddCommand is for commands that require <see cref="CommandContext"/>. Use
-    ///         <see cref="AddCommand(Command,Func{System.Nullable{bool}})"/>
-    ///         in cases where the command does not require a <see cref="CommandContext"/>.
+    ///         This version of AddCommand is for commands that require <see cref="CommandContext"/>.
     ///     </para>
     /// </remarks>
     /// <param name="command">The command.</param>
-    /// <param name="f">The function.</param>
-    protected void AddCommand (Command command, Func<CommandContext, bool?> f) { CommandImplementations [command] = f; }
+    /// <param name="impl">The delegate.</param>
+    protected void AddCommand (Command command, CommandImplementation impl) { CommandImplementations [command] = impl; }
 
     /// <summary>
     ///     <para>
@@ -240,7 +252,7 @@ public partial class View // Command APIs
     ///         AddCommand for each command they support.
     ///     </para>
     ///     <para>
-    ///         If AddCommand has already been called for <paramref name="command"/> <paramref name="f"/> will
+    ///         If AddCommand has already been called for <paramref name="command"/> <paramref name="impl"/> will
     ///         replace the old one.
     ///     </para>
     /// </summary>
@@ -248,12 +260,12 @@ public partial class View // Command APIs
     ///     <para>
     ///         This version of AddCommand is for commands that do not require a <see cref="CommandContext"/>.
     ///         If the command requires context, use
-    ///         <see cref="AddCommand(Command,Func{CommandContext,System.Nullable{bool}})"/>
+    ///         <see cref="AddCommand(Command,CommandImplementation)"/>
     ///     </para>
     /// </remarks>
     /// <param name="command">The command.</param>
-    /// <param name="f">The function.</param>
-    protected void AddCommand (Command command, Func<bool?> f) { CommandImplementations [command] = ctx => f (); }
+    /// <param name="impl">The delegate.</param>
+    protected void AddCommand (Command command, Func<bool?> impl) { CommandImplementations [command] = ctx => impl (); }
 
     /// <summary>Returns all commands that are supported by this <see cref="View"/>.</summary>
     /// <returns></returns>
@@ -262,13 +274,13 @@ public partial class View // Command APIs
     /// <summary>
     ///     Invokes the specified commands.
     /// </summary>
-    /// <param name="commands"></param>
-    /// <param name="key">The key that caused the commands to be invoked, if any.</param>
-    /// <param name="keyBinding"></param>
+    /// <param name="commands">The set of commands to invoke.</param>
+    /// <param name="key">The key that caused the command to be invoked, if any. This will be passed as context with the command.</param>
+    /// <param name="keyBinding">The key binding that was bound to the key and caused the invocation, if any. This will be passed as context with the command.</param>
     /// <returns>
-    ///     <see langword="null"/> if no command was found.
-    ///     <see langword="true"/> if the command was invoked the command was handled (or cancelled)
-    ///     <see langword="false"/> if the command was invoked and the command was not handled.
+    ///     <see langword="null"/> if no command was found; input proessing should continue.
+    ///     <see langword="false"/> if at least one command was invoked and was not handled (or cancelled); input proessing should continue.
+    ///     <see langword="true"/> if at least one command was invoked the command was handled (or cancelled); input proessing should stop.
     /// </returns>
     public bool? InvokeCommands (Command [] commands, Key? key = null, KeyBinding? keyBinding = null)
     {
@@ -278,7 +290,9 @@ public partial class View // Command APIs
         {
             if (!CommandImplementations.ContainsKey (command))
             {
-                throw new NotSupportedException (@$"{command} is not supported by ({GetType ().Name}).");
+                throw new NotSupportedException (
+                                                 @$"A KeyBinding was set up for the command {command} ({key}) but that command is not supported by this View ({GetType ().Name})"
+                                                );
             }
 
             // each command has its own return value
@@ -299,15 +313,16 @@ public partial class View // Command APIs
 
     /// <summary>Invokes the specified command.</summary>
     /// <param name="command">The command to invoke.</param>
-    /// <param name="key">The key that caused the command to be invoked, if any.</param>
-    /// <param name="keyBinding"></param>
+    /// <param name="key">The key that caused the command to be invoked, if any. This will be passed as context with the command.</param>
+    /// <param name="keyBinding">The key binding that was bound to the key and caused the invocation, if any. This will be passed as context with the command.</param>
     /// <returns>
-    ///     <see langword="null"/> if no command was found. <see langword="true"/> if the command was invoked, and it
-    ///     handled (or cancelled) the command. <see langword="false"/> if the command was invoked, and it did not handle (or cancel) the command.
+    ///     <see langword="null"/> if no command was found; input proessing should continue.
+    ///     <see langword="false"/> if the command was invoked and was not handled (or cancelled); input proessing should continue.
+    ///     <see langword="true"/> if the command was invoked the command was handled (or cancelled); input proessing should stop.
     /// </returns>
     public bool? InvokeCommand (Command command, Key? key = null, KeyBinding? keyBinding = null)
     {
-        if (CommandImplementations.TryGetValue (command, out Func<CommandContext, bool?>? implementation))
+        if (CommandImplementations.TryGetValue (command, out CommandImplementation? implementation))
         {
             var context = new CommandContext (command, key, keyBinding); // Create the context here
             return implementation (context);
@@ -322,12 +337,13 @@ public partial class View // Command APIs
     /// <param name="command">The command to invoke.</param>
     /// <param name="ctx">Context to pass with the invocation.</param>
     /// <returns>
-    ///     <see langword="null"/> if no command was found. <see langword="true"/> if the command was invoked, and it
-    ///     handled (or cancelled) the command. <see langword="false"/> if the command was invoked, and it did not handle (or cancel) the command.
+    ///     <see langword="null"/> if no command was found; input proessing should continue.
+    ///     <see langword="false"/> if the command was invoked and was not handled (or cancelled); input proessing should continue.
+    ///     <see langword="true"/> if the command was invoked the command was handled (or cancelled); input proessing should stop.
     /// </returns>
     public bool? InvokeCommand (Command command, CommandContext ctx)
     {
-        if (CommandImplementations.TryGetValue (command, out Func<CommandContext, bool?>? implementation))
+        if (CommandImplementations.TryGetValue (command, out CommandImplementation? implementation))
         {
             return implementation (ctx);
         }

+ 10 - 8
Terminal.Gui/View/View.Keyboard.cs

@@ -47,7 +47,7 @@ public partial class View // Keyboard APIs
     ///         opened.
     ///     </para>
     ///     <para>
-    ///         View subclasses can use <see cref="View.AddCommand(Command,Func{CommandContext,System.Nullable{bool}})"/> to
+    ///         View subclasses can use <see cref="View.AddCommand(Command,CommandImplementation)"/> to
     ///         define the
     ///         behavior of the hot key.
     ///     </para>
@@ -498,7 +498,7 @@ public partial class View // Keyboard APIs
     /// <summary>Gets the key bindings for this view.</summary>
     public KeyBindings KeyBindings { get; internal set; } = null!;
 
-    private Dictionary<Command, Func<CommandContext, bool?>> CommandImplementations { get; } = new ();
+    private Dictionary<Command, CommandImplementation> CommandImplementations { get; } = new ();
 
     /// <summary>
     ///     Low-level API called when a user presses a key; invokes any key bindings set on the view. This is called
@@ -511,8 +511,9 @@ public partial class View // Keyboard APIs
     /// <param name="keyEvent">Contains the details about the key that produced the event.</param>
     /// <param name="scope">The scope.</param>
     /// <returns>
-    ///     <see langword="false"/> if the key press was not handled. <see langword="true"/> if the keypress was handled
-    ///     and no other view should see it.
+    ///     <see langword="null"/> if no event was raised; input proessing should continue.
+    ///     <see langword="false"/> if the event was raised and was not handled (or cancelled); input proessing should continue.
+    ///     <see langword="true"/> if the event was raised and handled (or cancelled); input proessing should stop.
     /// </returns>
     public virtual bool? OnInvokingKeyBindings (Key keyEvent, KeyBindingScope scope)
     {
@@ -676,7 +677,7 @@ public partial class View // Keyboard APIs
     }
 
     /// <summary>
-    ///     Invoked when a key is pressed that may be mapped to a key binding. Set <see cref="Key.Handled"/> to true to
+    ///     Raised when a key is pressed that may be mapped to a key binding. Set <see cref="Key.Handled"/> to true to
     ///     stop the key from being processed by other views.
     /// </summary>
     public event EventHandler<Key>? InvokingKeyBindings;
@@ -688,9 +689,9 @@ public partial class View // Keyboard APIs
     /// <param name="key">The key event passed.</param>
     /// <param name="scope">The scope.</param>
     /// <returns>
-    ///     <see langword="null"/> if no command was bound the <paramref name="key"/>. <see langword="true"/> if
-    ///     commands were invoked and at least one handled the command. <see langword="false"/> if commands were invoked and at
-    ///     none handled the command.
+    ///     <see langword="null"/> if no command was invoked; input proessing should continue.
+    ///     <see langword="false"/> if at least one command was invoked and was not handled (or cancelled); input proessing should continue.
+    ///     <see langword="true"/> if at least one command was invoked and handled (or cancelled); input proessing should stop.
     /// </returns>
     protected bool? InvokeKeyBindings (Key key, KeyBindingScope scope)
     {
@@ -721,6 +722,7 @@ public partial class View // Keyboard APIs
         }
 
 #endif
+        return InvokeCommands (binding.Commands, key, binding);
 
         foreach (Command command in binding.Commands)
         {