Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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