Skip to content

Commit

Permalink
Merge pull request #13 from lechu445/add_async_api
Browse files Browse the repository at this point in the history
Add async API
  • Loading branch information
lechu445 authored Feb 17, 2023
2 parents 6d4f3b8 + 9ac8835 commit c931683
Show file tree
Hide file tree
Showing 9 changed files with 194 additions and 61 deletions.
109 changes: 102 additions & 7 deletions ConsoleMenu/ConsoleMenu.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;

[assembly: InternalsVisibleTo("ConsoleMenuTests")]

Expand Down Expand Up @@ -68,7 +70,7 @@ private IReadOnlyList<string> Titles
get
{
ConsoleMenu? current = this;
List<string> titles = new List<string>();
List<string> titles = new();
while (current != null)
{
titles.Add(current.config.Title ?? "");
Expand All @@ -83,7 +85,10 @@ private IReadOnlyList<string> Titles
/// <summary>
/// Don't run this method directly. Just pass a reference to this method.
/// </summary>
public static void Close() => throw new InvalidOperationException("Don't run this method directly. Just pass a reference to this method.");
/// <param name="cancellationToken">Cancellation token.</param>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
/// <exception cref="InvalidOperationException">Thrown if this method is called directly.</exception>
public static Task Close(CancellationToken cancellationToken) => throw new InvalidOperationException("Don't run this method directly. Just pass a reference to this method.");

/// <summary>
/// Close the menu before or after a menu action was triggered.
Expand All @@ -94,7 +99,7 @@ public void CloseMenu()
}

/// <summary>
/// Adds a menu item into this instance.
/// Adds a menu action into this instance.
/// </summary>
/// <param name="name">Name of menu item.</param>
/// <param name="action">Action to call when menu item is chosen.</param>
Expand All @@ -116,12 +121,43 @@ public ConsoleMenu Add(string name, Action action)
child.parent = this;
}

this.menuItems.Add(name, (_) =>
{
action();
return Task.CompletedTask;
});
return this;
}

/// <summary>
/// Adds an asynchronous menu action into this instance.
/// </summary>
/// <param name="name">Name of menu item.</param>
/// <param name="action">Action to call when menu item is chosen.</param>
/// <returns>This instance with added menu item.</returns>
public ConsoleMenu Add(string name, Func<CancellationToken, Task> action)
{
if (name == null)
{
throw new ArgumentNullException(nameof(name));
}

if (action == null)
{
throw new ArgumentNullException(nameof(action));
}

if (action.Target is ConsoleMenu child && action == child.ShowAsync)
{
child.parent = this;
}

this.menuItems.Add(name, action);
return this;
}

/// <summary>
/// Adds a menu item into this instance.
/// Adds a menu action into this instance.
/// </summary>
/// <param name="name">Name of menu item.</param>
/// <param name="action">Action to call when menu item is chosen.</param>
Expand All @@ -138,12 +174,38 @@ public ConsoleMenu Add(string name, Action<ConsoleMenu> action)
throw new ArgumentNullException(nameof(action));
}

this.menuItems.Add(name, () => action(this));
this.menuItems.Add(name, (_) =>
{
action(this);
return Task.CompletedTask;
});
return this;
}

/// <summary>
/// Adds an asynchronous menu action into this instance.
/// </summary>
/// <param name="name">Name of menu item.</param>
/// <param name="action">Action to call when menu item is chosen.</param>
/// <returns>This instance with added menu item.</returns>
public ConsoleMenu Add(string name, Func<ConsoleMenu, CancellationToken, Task> action)
{
if (name == null)
{
throw new ArgumentNullException(nameof(name));
}

if (action is null)
{
throw new ArgumentNullException(nameof(action));
}

this.menuItems.Add(name, (cancellationToken) => action(this, cancellationToken));
return this;
}

/// <summary>
/// Adds range of menu items into this instance.
/// Adds range of menu actions into this instance.
/// </summary>
/// <param name="menuItems">Menu items to add.</param>
/// <returns>This instance with added menu items.</returns>
Expand All @@ -162,6 +224,26 @@ public ConsoleMenu AddRange(IEnumerable<Tuple<string, Action>> menuItems)
return this;
}

/// <summary>
/// Adds range of asynchronous menu actions into this instance.
/// </summary>
/// <param name="menuItems">Menu items to add.</param>
/// <returns>This instance with added menu items.</returns>
public ConsoleMenu AddRange(IEnumerable<Tuple<string, Func<CancellationToken, Task>>> menuItems)
{
if (menuItems is null)
{
throw new ArgumentNullException(nameof(menuItems));
}

foreach (var item in menuItems)
{
this.Add(item.Item1, item.Item2);
}

return this;
}

/// <summary>
/// Applies an configuration action on this instance.
/// </summary>
Expand Down Expand Up @@ -206,7 +288,20 @@ public void Show()
this.Console,
new List<string>(this.Titles),
this.config,
this.closeTrigger).Show();
this.closeTrigger).ShowAsync(CancellationToken.None).GetAwaiter().GetResult();
}

/// <summary>
/// Displays the menu in console.
/// </summary>
public async Task ShowAsync(CancellationToken cancellationToken = default)
{
await new ConsoleMenuDisplay(
this.menuItems,
this.Console,
new List<string>(this.Titles),
this.config,
this.closeTrigger).ShowAsync(cancellationToken);
}

/// <summary>
Expand Down
7 changes: 3 additions & 4 deletions ConsoleMenu/ConsoleMenu.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,10 @@
<Authors>lechu445</Authors>
<Product>ConsoleMenu-simple</Product>
<Description>A simple, highly customizable, DOS-like console menu</Description>
<PackageReleaseNotes>- added collection initializer
- added ConsoleMenu.Configure(MenuConfig config)</PackageReleaseNotes>
<PackageReleaseNotes>- added async API</PackageReleaseNotes>
<PackageProjectUrl>https://github.com/lechu445/ConsoleMenu</PackageProjectUrl>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<Version>2.5.0</Version>
<Version>2.6.0</Version>
<RepositoryUrl>https://github.com/lechu445/ConsoleMenu</RepositoryUrl>
<PackageTags>console, menu, simple</PackageTags>
<PackageLicenseFile>LICENSE.txt</PackageLicenseFile>
Expand Down Expand Up @@ -38,7 +37,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.PublicApiAnalyzers" Version="3.3.3">
<PackageReference Include="Microsoft.CodeAnalysis.PublicApiAnalyzers" Version="3.3.4">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
Expand Down
11 changes: 7 additions & 4 deletions ConsoleMenu/ConsoleMenuDisplay.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleTools;

Expand Down Expand Up @@ -30,12 +32,12 @@ public ConsoleMenuDisplay(
this.noSelectorLine = new string(' ', this.config.Selector.Length);
}

public void Show()
public async Task ShowAsync(CancellationToken token)
{
var selectedItem = this.menuItems.GetSeletedItem();
if (selectedItem != null)
{
selectedItem.Action.Invoke();
await selectedItem.AsyncAction.Invoke(token);
return;
}

Expand All @@ -48,6 +50,7 @@ public void Show()

while (true)
{
token.ThrowIfCancellationRequested();
do
{
if (this.config.ClearConsole)
Expand Down Expand Up @@ -137,15 +140,15 @@ public void Show()
this.console.WriteLine();
this.console.ForegroundColor = currentForegroundColor;
this.console.BackgroundColor = currentBackgroundColor;
var action = this.menuItems.CurrentItem.Action;
var action = this.menuItems.CurrentItem.AsyncAction;
if (action == ConsoleMenu.Close)
{
this.menuItems.UnsetSelectedIndex();
return;
}
else
{
action();
await action(token).ConfigureAwait(false);
if (this.closeTrigger.IsOn())
{
this.menuItems.UnsetSelectedIndex();
Expand Down
4 changes: 3 additions & 1 deletion ConsoleMenu/ItemsCollection.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleTools;

Expand Down Expand Up @@ -28,7 +30,7 @@ public MenuItem CurrentItem
set => this.menuItems[this.currentItemIndex] = value;
}

public void Add(string name, Action action)
public void Add(string name, Func<CancellationToken, Task> action)
{
this.menuItems.Add(new MenuItem(name, action, this.menuItems.Count));
}
Expand Down
72 changes: 36 additions & 36 deletions ConsoleMenu/MenuConfig.cs
Original file line number Diff line number Diff line change
@@ -1,41 +1,41 @@
#pragma warning disable SA1401 // Fields should be private
#pragma warning disable SA1401 // Fields should be private
using System;
using System.Collections.Generic;

namespace ConsoleTools;

/// <summary>
/// Menu configuration.

/// <summary>
/// Menu configuration.
/// </summary>
public class MenuConfig
{
/// <summary>
/// Initializes a new instance of the <see cref="MenuConfig"/> class.
/// </summary>
public MenuConfig()
{
}

internal MenuConfig(MenuConfig config)
{
this.ArgsPreselectedItemsKey = config.ArgsPreselectedItemsKey;
this.ArgsPreselectedItemsValueSeparator = config.ArgsPreselectedItemsValueSeparator;
this.ClearConsole = config.ClearConsole;
this.EnableBreadcrumb = config.EnableBreadcrumb;
this.EnableFilter = config.EnableFilter;
this.EnableWriteTitle = config.EnableWriteTitle;
this.FilterPrompt = config.FilterPrompt;
this.ItemBackgroundColor = config.ItemBackgroundColor;
this.ItemForegroundColor = config.ItemForegroundColor;
this.SelectedItemBackgroundColor = config.SelectedItemBackgroundColor;
this.SelectedItemForegroundColor = config.SelectedItemForegroundColor;
this.Selector = config.Selector;
this.Title = config.Title;
this.WriteBreadcrumbAction = config.WriteBreadcrumbAction;
this.WriteHeaderAction = config.WriteHeaderAction;
this.WriteItemAction = config.WriteItemAction;
this.WriteTitleAction = config.WriteTitleAction;
}
{
/// <summary>
/// Initializes a new instance of the <see cref="MenuConfig"/> class.
/// </summary>
public MenuConfig()
{
}

internal MenuConfig(MenuConfig config)
{
this.ArgsPreselectedItemsKey = config.ArgsPreselectedItemsKey;
this.ArgsPreselectedItemsValueSeparator = config.ArgsPreselectedItemsValueSeparator;
this.ClearConsole = config.ClearConsole;
this.EnableBreadcrumb = config.EnableBreadcrumb;
this.EnableFilter = config.EnableFilter;
this.EnableWriteTitle = config.EnableWriteTitle;
this.FilterPrompt = config.FilterPrompt;
this.ItemBackgroundColor = config.ItemBackgroundColor;
this.ItemForegroundColor = config.ItemForegroundColor;
this.SelectedItemBackgroundColor = config.SelectedItemBackgroundColor;
this.SelectedItemForegroundColor = config.SelectedItemForegroundColor;
this.Selector = config.Selector;
this.Title = config.Title;
this.WriteBreadcrumbAction = config.WriteBreadcrumbAction;
this.WriteHeaderAction = config.WriteHeaderAction;
this.WriteItemAction = config.WriteItemAction;
this.WriteTitleAction = config.WriteTitleAction;
}

/// <summary>default: Console.ForegroundColor</summary>
public ConsoleColor SelectedItemBackgroundColor = Console.ForegroundColor;
Expand All @@ -47,11 +47,11 @@ internal MenuConfig(MenuConfig config)
public ConsoleColor ItemBackgroundColor = Console.BackgroundColor;

/// <summary>default: Console.ForegroundColor</summary>
public ConsoleColor ItemForegroundColor = Console.ForegroundColor;

public ConsoleColor ItemForegroundColor = Console.ForegroundColor;

/// <summary>default: () => Console.WriteLine("Pick an option:")</summary>
public Action WriteHeaderAction = () => Console.WriteLine("Pick an option:");

public Action WriteHeaderAction = () => Console.WriteLine("Pick an option:");

/// <summary>default: (item) => Console.Write("[{0}] {1}", item.Index, item.Name)</summary>
public Action<MenuItem> WriteItemAction = item => Console.Write("[{0}] {1}", item.Index, item.Name);

Expand Down
Loading

0 comments on commit c931683

Please sign in to comment.