From b5a450572074bc81c4975ff5f28def2a7131249d Mon Sep 17 00:00:00 2001 From: Nick Sorrell Date: Thu, 16 Mar 2017 23:15:45 -0400 Subject: [PATCH] Added word completion, exit on escape, home/end --- InteractivePrompt/InteractivePrompt.cs | 100 ++++++++++++++++++- InteractivePrompt/Properties/AssemblyInfo.cs | 4 +- 2 files changed, 100 insertions(+), 4 deletions(-) diff --git a/InteractivePrompt/InteractivePrompt.cs b/InteractivePrompt/InteractivePrompt.cs index d8cd0ed..89517e6 100644 --- a/InteractivePrompt/InteractivePrompt.cs +++ b/InteractivePrompt/InteractivePrompt.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using System.Text.RegularExpressions; using System.Threading.Tasks; namespace Cintio @@ -20,24 +21,34 @@ private static void RewriteLine(List input, int inputPosition) Console.Write(String.Concat(input)); Console.SetCursorPosition(inputPosition + _prompt.Length, Console.CursorTop); } + private static IEnumerable GetMatch(List s, string input) + { + s.Add(input); + for (int i = 0; i < s.Count; i = (i+1)%s.Count) + if (Regex.IsMatch(s[i], ".*(?:" + input + ").*", RegexOptions.IgnoreCase)) + yield return s[i]; + } /// /// Run will start an interactive prompt /// /// This func is provided for the user to handle the input. Input is provided in both string and List<char>. A return response is provided as a string. /// The prompt for the interactive shell /// Startup msg to display to user - public static void Run(Func, string> lambda, string prompt, string startupMsg) + public static void Run(Func, string> lambda, string prompt, string startupMsg, List completionList = null) { _prompt = prompt; Console.WriteLine(startupMsg); List> inputHistory = new List>(); + IEnumerator wordIterator = null; + while (true) { + string completion = null; List input = new List(); int inputPosition = 0; int inputHistoryPosition = inputHistory.Count; - ConsoleKeyInfo key; + ConsoleKeyInfo key, lastKey = new ConsoleKeyInfo(); Console.Write(prompt); do { @@ -58,6 +69,81 @@ public static void Run(Func, string> lambda, string prompt, s Console.SetCursorPosition(Console.CursorLeft + 1, Console.CursorTop); } } + + else if (key.Key == ConsoleKey.Tab && completionList != null && completionList.Count > 0) + { + int tempPosition = inputPosition; + List word = new List(); + while (tempPosition-- > 0 && !string.IsNullOrWhiteSpace(input[tempPosition].ToString())) + word.Insert(0, input[tempPosition]); + + if (lastKey.Key == ConsoleKey.Tab) + { + wordIterator.MoveNext(); + if (completion != null) + { + ClearLine(input); + for (var i = 0; i < completion.Length; i++) + { + input.RemoveAt(--inputPosition); + } + RewriteLine(input, inputPosition); + } + else + { + ClearLine(input); + for (var i = 0; i < string.Concat(word).Length; i++) + { + input.RemoveAt(--inputPosition); + } + RewriteLine(input, inputPosition); + } + } + else + { + ClearLine(input); + for (var i = 0; i < string.Concat(word).Length; i++) + { + input.RemoveAt(--inputPosition); + } + RewriteLine(input, inputPosition); + wordIterator = GetMatch(completionList, string.Concat(word)).GetEnumerator(); + while (wordIterator.Current == null) + wordIterator.MoveNext(); + } + + completion = wordIterator.Current; + ClearLine(input); + foreach (var c in completion.ToCharArray()) + { + input.Insert(inputPosition++, c); + } + RewriteLine(input, inputPosition); + + } + else if (key.Key == ConsoleKey.Home || (key.Key == ConsoleKey.H && key.Modifiers == ConsoleModifiers.Control)) + { + Console.WriteLine("crap"); + inputPosition = 0; + Console.SetCursorPosition(prompt.Length, Console.CursorTop); + } + + else if (key.Key == ConsoleKey.End || (key.Key == ConsoleKey.E && key.Modifiers == ConsoleModifiers.Control)) + { + inputPosition = input.Count; + Console.SetCursorPosition(inputPosition + _prompt.Length, Console.CursorTop); + } + + else if (key.Key == ConsoleKey.Delete) + { + if (inputPosition < input.Count) + { + input.RemoveAt(inputPosition); + ClearLine(input); + RewriteLine(input, inputPosition); + } + } + else if (key.Key == ConsoleKey.UpArrow) { if (inputHistoryPosition > 0) @@ -103,12 +189,22 @@ public static void Run(Func, string> lambda, string prompt, s } } + else if (key.Key == ConsoleKey.Escape) + { + if (lastKey.Key == ConsoleKey.Escape) + Environment.Exit(0); + else + Console.WriteLine("Press Escape again to exit."); + } + else if (key.Key != ConsoleKey.Enter) { input.Insert(inputPosition++, key.KeyChar); RewriteLine(input, inputPosition); } + + lastKey = key; } while (key.Key != ConsoleKey.Enter); Console.WriteLine(); diff --git a/InteractivePrompt/Properties/AssemblyInfo.cs b/InteractivePrompt/Properties/AssemblyInfo.cs index f1c0ef3..bfebb76 100644 --- a/InteractivePrompt/Properties/AssemblyInfo.cs +++ b/InteractivePrompt/Properties/AssemblyInfo.cs @@ -32,5 +32,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.2.0")] -[assembly: AssemblyFileVersion("1.0.2.0")] +[assembly: AssemblyVersion("1.0.3.0")] +[assembly: AssemblyFileVersion("1.0.3.0")]