NConsoleMenu by Sebastian Heuchler

<PackageReference Include="NConsoleMenu" Version="0.9.0" />

 CommandQueue

public class CommandQueue
using System; using System.Collections.Generic; using System.Linq; using System.Threading; namespace NConsoleMenu { public class CommandQueue { private class Frame { public IEnumerator<string> E; public Frame(IEnumerable<string> source) { E = source.GetEnumerator(); } } private readonly Stack<Frame> _Frames = new Stack<Frame>(); private readonly ManualResetEvent _InputAvailable = new ManualResetEvent(false); public bool PromptUserForInput { get; set; } = true; public string QueryInput(string prompt) { string text; do { text = TryGetQueuedInput(); if (text == null) { _InputAvailable.Reset(); if (PromptUserForInput) { if (prompt != null) Console.Write(prompt + " "); text = Console.ReadLine(); } } if (text == null && !PromptUserForInput) _InputAvailable.WaitOne(); } while (string.IsNullOrWhiteSpace(text)); return text; } public string TryGetQueuedInput() { lock (_Frames) { while (_Frames.Any()) { Frame frame = _Frames.Peek(); if (frame.E.MoveNext()) return frame.E.Current; _Frames.Pop(); } } return null; } public void AddInput(IEnumerable<string> source) { if (source == null) throw new ArgumentNullException("source"); lock (_Frames) { _Frames.Push(new Frame(source)); _InputAvailable.Set(); } } public void ImmediateInput(string source) { if (source == null) throw new ArgumentNullException("source"); AddInput(new string[1] { source }); } public bool IsEmpty() { lock (_Frames) { return _Frames.Count == 0; } } } }