From 292257b4b0e4011c58c18e0e021ecc9e7bead314 Mon Sep 17 00:00:00 2001 From: Latency McLaughlin Date: Sat, 7 Oct 2017 15:29:05 -0700 Subject: [PATCH 1/3] Code formatted Allman style. --- src/ReadLine.Demo/Program.cs | 15 +- src/ReadLine/Abstractions/Console2.cs | 15 +- src/ReadLine/Abstractions/IConsole.cs | 6 +- src/ReadLine/KeyHandler.cs | 246 +++++++------ src/ReadLine/Properties/AssemblyInfo.cs | 12 +- src/ReadLine/ReadLine.cs | 23 +- test/ReadLine.Tests/Abstractions/Console2.cs | 56 +-- test/ReadLine.Tests/KeyHandlerTests.cs | 361 ++++++++++--------- test/ReadLine.Tests/ReadLineTests.cs | 46 ++- 9 files changed, 438 insertions(+), 342 deletions(-) diff --git a/src/ReadLine.Demo/Program.cs b/src/ReadLine.Demo/Program.cs index dda85d6..de8b59d 100755 --- a/src/ReadLine.Demo/Program.cs +++ b/src/ReadLine.Demo/Program.cs @@ -1,13 +1,17 @@ using System; -namespace ReadLine.Demo { - public class Program { - public static void Main(string[] args) { +namespace ReadLine.Demo +{ + public class Program + { + public static void Main(string[] args) + { Console.WriteLine("ReadLine Library Demo"); Console.WriteLine("---------------------"); Console.WriteLine(); - string[] history = { + string[] history = + { "ls -a", "dotnet run", "git init" @@ -15,7 +19,8 @@ public static void Main(string[] args) { ReadLine.AddHistory(history); ReadLine.AutoCompletionHandler = (t, s) => t.StartsWith("git ") - ? new[] { + ? new[] + { "init", "clone", "pull", diff --git a/src/ReadLine/Abstractions/Console2.cs b/src/ReadLine/Abstractions/Console2.cs index f7188d2..b2052fb 100644 --- a/src/ReadLine/Abstractions/Console2.cs +++ b/src/ReadLine/Abstractions/Console2.cs @@ -1,7 +1,10 @@ using System; -namespace ReadLine.Abstractions { - internal class Console2 : IConsole { +namespace ReadLine.Abstractions +{ + internal class Console2 : IConsole + { + public bool PasswordMode { get; set; } public int CursorLeft => Console.CursorLeft; public int CursorTop => Console.CursorTop; @@ -10,16 +13,16 @@ internal class Console2 : IConsole { public int BufferHeight => Console.BufferHeight; - public bool PasswordMode { get; set; } - public void SetBufferSize(int width, int height) => Console.SetBufferSize(width, height); - public void SetCursorPosition(int left, int top) { + public void SetCursorPosition(int left, int top) + { if (!PasswordMode) Console.SetCursorPosition(left, top); } - public void Write(string value) { + public void Write(string value) + { if (PasswordMode) value = new string(default(char), value.Length); diff --git a/src/ReadLine/Abstractions/IConsole.cs b/src/ReadLine/Abstractions/IConsole.cs index 6b764bc..65dfff9 100644 --- a/src/ReadLine/Abstractions/IConsole.cs +++ b/src/ReadLine/Abstractions/IConsole.cs @@ -1,5 +1,7 @@ -namespace ReadLine.Abstractions { - public interface IConsole { +namespace ReadLine.Abstractions +{ + public interface IConsole + { int CursorLeft { get; } int CursorTop { get; } int BufferWidth { get; } diff --git a/src/ReadLine/KeyHandler.cs b/src/ReadLine/KeyHandler.cs index 5a2a225..50070cf 100644 --- a/src/ReadLine/KeyHandler.cs +++ b/src/ReadLine/KeyHandler.cs @@ -3,19 +3,104 @@ using System.Text; using ReadLine.Abstractions; -namespace ReadLine { - public class KeyHandler { - private int _cursorPos; - private int _cursorLimit; - private readonly StringBuilder _text; +namespace ReadLine +{ + public class KeyHandler + { + private readonly IConsole _console2; private readonly List _history; - private int _historyIndex; - private ConsoleKeyInfo _keyInfo; private readonly Dictionary _keyActions; + private readonly StringBuilder _text; private string[] _completions; - private int _completionStart; private int _completionsIndex; - private readonly IConsole _console2; + private int _completionStart; + private int _cursorLimit; + private int _cursorPos; + private int _historyIndex; + private ConsoleKeyInfo _keyInfo; + + public KeyHandler(IConsole console, List history, Func autoCompleteHandler) + { + _console2 = console; + + _historyIndex = history.Count; + _history = history; + _text = new StringBuilder(); + _keyActions = new Dictionary + { + ["LeftArrow"] = MoveCursorLeft, + ["Home"] = MoveCursorHome, + ["End"] = MoveCursorEnd, + ["ControlA"] = MoveCursorHome, + ["ControlB"] = MoveCursorLeft, + ["RightArrow"] = MoveCursorRight, + ["ControlF"] = MoveCursorRight, + ["ControlE"] = MoveCursorEnd, + ["Backspace"] = Backspace, + ["Delete"] = Delete, + ["ControlH"] = Backspace, + ["ControlL"] = ClearLine, + ["UpArrow"] = PrevHistory, + ["ControlP"] = PrevHistory, + ["DownArrow"] = NextHistory, + ["ControlN"] = NextHistory, + ["ControlU"] = () => + { + while (!IsStartOfLine()) + Backspace(); + }, + ["ControlK"] = () => + { + var pos = _cursorPos; + MoveCursorEnd(); + while (_cursorPos > pos) + Backspace(); + }, + ["ControlW"] = () => + { + while (!IsStartOfLine() && _text[_cursorPos - 1] != ' ') + Backspace(); + }, + ["Tab"] = () => + { + if (IsInAutoCompleteMode()) + NextAutoComplete(); + else + { + if (autoCompleteHandler == null || !IsEndOfLine()) + return; + + var anyOf = new[] + { + ' ', + '.', + '/', + '\\', + ':' + }; + var text = _text.ToString(); + + _completionStart = text.LastIndexOfAny(anyOf); + _completionStart = _completionStart == -1 ? 0 : _completionStart + 1; + + _completions = autoCompleteHandler.Invoke(text, _completionStart); + _completions = _completions?.Length == 0 ? null : _completions; + + if (_completions == null) + return; + + StartAutoComplete(); + } + }, + ["ShiftTab"] = () => + { + if (IsInAutoCompleteMode()) + PreviousAutoComplete(); + } + }; + } + + public string Text => _text.ToString(); private bool IsStartOfLine() => _cursorPos == 0; @@ -26,7 +111,8 @@ public class KeyHandler { private bool IsEndOfBuffer() => _console2.CursorLeft == _console2.BufferWidth - 1; private bool IsInAutoCompleteMode() => _completions != null; - private void MoveCursorLeft() { + private void MoveCursorLeft() + { if (IsStartOfLine()) return; @@ -38,16 +124,19 @@ private void MoveCursorLeft() { _cursorPos--; } - private void MoveCursorHome() { + private void MoveCursorHome() + { while (!IsStartOfLine()) MoveCursorLeft(); } - private string BuildKeyInput() { - return (_keyInfo.Modifiers != ConsoleModifiers.Control && _keyInfo.Modifiers != ConsoleModifiers.Shift) ? _keyInfo.Key.ToString() : _keyInfo.Modifiers + _keyInfo.Key.ToString(); + private string BuildKeyInput() + { + return _keyInfo.Modifiers != ConsoleModifiers.Control && _keyInfo.Modifiers != ConsoleModifiers.Shift ? _keyInfo.Key.ToString() : _keyInfo.Modifiers + _keyInfo.Key.ToString(); } - private void MoveCursorRight() { + private void MoveCursorRight() + { if (IsEndOfLine()) return; @@ -59,36 +148,43 @@ private void MoveCursorRight() { _cursorPos++; } - private void MoveCursorEnd() { + private void MoveCursorEnd() + { while (!IsEndOfLine()) MoveCursorRight(); } - private void ClearLine() { + private void ClearLine() + { MoveCursorEnd(); while (!IsStartOfLine()) Backspace(); } - private void WriteNewString(string str) { + private void WriteNewString(string str) + { ClearLine(); foreach (var character in str) WriteChar(character); } - private void WriteString(string str) { + private void WriteString(string str) + { foreach (var character in str) WriteChar(character); } private void WriteChar() => WriteChar(_keyInfo.KeyChar); - private void WriteChar(char c) { - if (IsEndOfLine()) { + private void WriteChar(char c) + { + if (IsEndOfLine()) + { _text.Append(c); _console2.Write(c.ToString()); _cursorPos++; - } else { + } else + { var left = _console2.CursorLeft; var top = _console2.CursorTop; var str = _text.ToString().Substring(_cursorPos); @@ -101,7 +197,8 @@ private void WriteChar(char c) { _cursorLimit++; } - private void Backspace() { + private void Backspace() + { if (IsStartOfLine()) return; @@ -116,7 +213,8 @@ private void Backspace() { _cursorLimit--; } - private void Delete() { + private void Delete() + { if (IsEndOfLine()) return; @@ -130,7 +228,8 @@ private void Delete() { _cursorLimit--; } - private void StartAutoComplete() { + private void StartAutoComplete() + { while (_cursorPos > _completionStart) Backspace(); @@ -139,7 +238,8 @@ private void StartAutoComplete() { WriteString(_completions[_completionsIndex]); } - private void NextAutoComplete() { + private void NextAutoComplete() + { while (_cursorPos > _completionStart) Backspace(); @@ -151,7 +251,8 @@ private void NextAutoComplete() { WriteString(_completions[_completionsIndex]); } - private void PreviousAutoComplete() { + private void PreviousAutoComplete() + { while (_cursorPos > _completionStart) Backspace(); @@ -163,15 +264,19 @@ private void PreviousAutoComplete() { WriteString(_completions[_completionsIndex]); } - private void PrevHistory() { - if (_historyIndex > 0) { + private void PrevHistory() + { + if (_historyIndex > 0) + { _historyIndex--; WriteNewString(_history[_historyIndex]); } } - private void NextHistory() { - if (_historyIndex < _history.Count) { + private void NextHistory() + { + if (_historyIndex < _history.Count) + { _historyIndex++; if (_historyIndex == _history.Count) ClearLine(); @@ -180,87 +285,14 @@ private void NextHistory() { } } - private void ResetAutoComplete() { + private void ResetAutoComplete() + { _completions = null; _completionsIndex = 0; } - public string Text => _text.ToString(); - - public KeyHandler(IConsole console, List history, Func autoCompleteHandler) { - _console2 = console; - - _historyIndex = history.Count; - _history = history; - _text = new StringBuilder(); - _keyActions = new Dictionary { - ["LeftArrow"] = MoveCursorLeft, - ["Home"] = MoveCursorHome, - ["End"] = MoveCursorEnd, - ["ControlA"] = MoveCursorHome, - ["ControlB"] = MoveCursorLeft, - ["RightArrow"] = MoveCursorRight, - ["ControlF"] = MoveCursorRight, - ["ControlE"] = MoveCursorEnd, - ["Backspace"] = Backspace, - ["Delete"] = Delete, - ["ControlH"] = Backspace, - ["ControlL"] = ClearLine, - ["UpArrow"] = PrevHistory, - ["ControlP"] = PrevHistory, - ["DownArrow"] = NextHistory, - ["ControlN"] = NextHistory, - ["ControlU"] = () => { - while (!IsStartOfLine()) - Backspace(); - }, - ["ControlK"] = () => { - var pos = _cursorPos; - MoveCursorEnd(); - while (_cursorPos > pos) - Backspace(); - }, - ["ControlW"] = () => { - while (!IsStartOfLine() && _text[_cursorPos - 1] != ' ') - Backspace(); - }, - ["Tab"] = () => { - if (IsInAutoCompleteMode()) { - NextAutoComplete(); - } else { - if (autoCompleteHandler == null || !IsEndOfLine()) - return; - - var anyOf = new[] { - ' ', - '.', - '/', - '\\', - ':' - }; - var text = _text.ToString(); - - _completionStart = text.LastIndexOfAny(anyOf); - _completionStart = _completionStart == -1 ? 0 : _completionStart + 1; - - _completions = autoCompleteHandler.Invoke(text, _completionStart); - _completions = _completions?.Length == 0 ? null : _completions; - - if (_completions == null) - return; - - StartAutoComplete(); - } - }, - ["ShiftTab"] = () => { - if (IsInAutoCompleteMode()) { - PreviousAutoComplete(); - } - } - }; - } - - public void Handle(ConsoleKeyInfo keyInfo) { + public void Handle(ConsoleKeyInfo keyInfo) + { _keyInfo = keyInfo; // If in auto complete mode and Tab wasn't pressed diff --git a/src/ReadLine/Properties/AssemblyInfo.cs b/src/ReadLine/Properties/AssemblyInfo.cs index 9d08c04..ba9f49b 100644 --- a/src/ReadLine/Properties/AssemblyInfo.cs +++ b/src/ReadLine/Properties/AssemblyInfo.cs @@ -1,5 +1,7 @@ -[assembly: System.Reflection.AssemblyTitle("ReadLine")] -[assembly: System.Reflection.AssemblyDescription("A GNU-Readline like library for .NET/.NET Core")] -[assembly: System.Reflection.AssemblyFileVersion("1.2.1")] -[assembly: System.Reflection.AssemblyVersion("1.2.1")] -[assembly: System.Reflection.AssemblyInformationalVersion("1.2.1")] \ No newline at end of file +using System.Reflection; + +[assembly: AssemblyTitle("ReadLine")] +[assembly: AssemblyDescription("A GNU-Readline like library for .NET/.NET Core")] +[assembly: AssemblyFileVersion("1.2.1")] +[assembly: AssemblyVersion("1.2.1")] +[assembly: AssemblyInformationalVersion("1.2.1")] \ No newline at end of file diff --git a/src/ReadLine/ReadLine.cs b/src/ReadLine/ReadLine.cs index 67d7a81..5581f2b 100755 --- a/src/ReadLine/ReadLine.cs +++ b/src/ReadLine/ReadLine.cs @@ -2,30 +2,37 @@ using System.Collections.Generic; using ReadLine.Abstractions; -namespace ReadLine { - public static class ReadLine { +namespace ReadLine +{ + public static class ReadLine + { private static KeyHandler _keyHandler; private static List _history; - static ReadLine() { + static ReadLine() + { _history = new List(); } + public static Func AutoCompletionHandler { private get; set; } + public static bool PasswordMode { private get; set; } + public static void AddHistory(params string[] text) => _history.AddRange(text); public static List GetHistory() => _history; public static void ClearHistory() => _history = new List(); - public static Func AutoCompletionHandler { private get; set; } - public static bool PasswordMode { private get; set; } - public static string Read(string prompt = "", string defaultInput = "") { + public static string Read(string prompt = "", string defaultInput = "") + { Console.Write(prompt); - _keyHandler = new KeyHandler(new Console2() { + _keyHandler = new KeyHandler(new Console2 + { PasswordMode = PasswordMode }, _history, AutoCompletionHandler); var keyInfo = Console.ReadKey(true); - while (keyInfo.Key != ConsoleKey.Enter) { + while (keyInfo.Key != ConsoleKey.Enter) + { _keyHandler.Handle(keyInfo); keyInfo = Console.ReadKey(true); } diff --git a/test/ReadLine.Tests/Abstractions/Console2.cs b/test/ReadLine.Tests/Abstractions/Console2.cs index c84ce25..2239f50 100644 --- a/test/ReadLine.Tests/Abstractions/Console2.cs +++ b/test/ReadLine.Tests/Abstractions/Console2.cs @@ -1,43 +1,45 @@ using ReadLine.Abstractions; -namespace ReadLine.Tests.Abstractions { - internal class Console2 : IConsole { - public int CursorLeft => _cursorLeft; - - public int CursorTop => _cursorTop; +namespace ReadLine.Tests.Abstractions +{ + internal class Console2 : IConsole + { + public Console2() + { + CursorLeft = 0; + CursorTop = 0; + BufferWidth = 100; + BufferHeight = 100; + } - public int BufferWidth => _bufferWidth; + public int CursorLeft { get; private set; } - public int BufferHeight => _bufferHeight; + public int CursorTop { get; private set; } - private int _cursorLeft; - private int _cursorTop; - private int _bufferWidth; - private int _bufferHeight; + public int BufferWidth { get; private set; } - public Console2() { - _cursorLeft = 0; - _cursorTop = 0; - _bufferWidth = 100; - _bufferHeight = 100; - } + public int BufferHeight { get; private set; } - public void SetBufferSize(int width, int height) { - _bufferWidth = width; - _bufferHeight = height; + public void SetBufferSize(int width, int height) + { + BufferWidth = width; + BufferHeight = height; } - public void SetCursorPosition(int left, int top) { - _cursorLeft = left; - _cursorTop = top; + public void SetCursorPosition(int left, int top) + { + CursorLeft = left; + CursorTop = top; } - public void Write(string value) { - _cursorLeft += value.Length; + public void Write(string value) + { + CursorLeft += value.Length; } - public void WriteLine(string value) { - _cursorLeft += value.Length; + public void WriteLine(string value) + { + CursorLeft += value.Length; } } } \ No newline at end of file diff --git a/test/ReadLine.Tests/KeyHandlerTests.cs b/test/ReadLine.Tests/KeyHandlerTests.cs index 259b3f4..a8306f5 100644 --- a/test/ReadLine.Tests/KeyHandlerTests.cs +++ b/test/ReadLine.Tests/KeyHandlerTests.cs @@ -1,23 +1,22 @@ using System; using System.Collections.Generic; -using Xunit; using ReadLine.Tests.Abstractions; +using Xunit; namespace ReadLine.Tests { - public class KeyHandlerTests { - private KeyHandler _keyHandler; - private ConsoleKeyInfo _keyInfo; - private readonly List _history; - private readonly string[] _completions; - - public KeyHandlerTests() { - _completions = new[] { + public class KeyHandlerTests + { + public KeyHandlerTests() + { + _completions = new[] + { "World", "Angel", "Love" }; - _history = new List(new[] { + _history = new List(new[] + { "dotnet run", "git init", "clear" @@ -40,33 +39,14 @@ public KeyHandlerTests() { _keyHandler.Handle(_keyInfo); } - [Fact] - public void TestWriteChar() { - Assert.Equal("Hello", _keyHandler.Text); - - _keyInfo = new ConsoleKeyInfo(' ', ConsoleKey.Spacebar, false, false, false); - _keyHandler.Handle(_keyInfo); - - _keyInfo = new ConsoleKeyInfo('W', ConsoleKey.W, false, false, false); - _keyHandler.Handle(_keyInfo); - - _keyInfo = new ConsoleKeyInfo('o', ConsoleKey.O, false, false, false); - _keyHandler.Handle(_keyInfo); - - _keyInfo = new ConsoleKeyInfo('r', ConsoleKey.R, false, false, false); - _keyHandler.Handle(_keyInfo); - - _keyInfo = new ConsoleKeyInfo('l', ConsoleKey.L, false, false, false); - _keyHandler.Handle(_keyInfo); - - _keyInfo = new ConsoleKeyInfo('d', ConsoleKey.D, false, false, false); - _keyHandler.Handle(_keyInfo); - - Assert.Equal("Hello World", _keyHandler.Text); - } + private KeyHandler _keyHandler; + private ConsoleKeyInfo _keyInfo; + private readonly List _history; + private readonly string[] _completions; [Fact] - public void TestBackspace() { + public void TestBackspace() + { _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.Backspace, false, false, false); _keyHandler.Handle(_keyInfo); @@ -74,44 +54,41 @@ public void TestBackspace() { } [Fact] - public void TestDelete() { - _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.LeftArrow, false, false, false); - _keyHandler.Handle(_keyInfo); - _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.Delete, false, false, false); - _keyHandler.Handle(_keyInfo); - - Assert.Equal("Hell", _keyHandler.Text); - } - - [Fact] - public void TestDelete_EndOfLine() { - _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.Delete, false, false, false); + public void TestBackwardsTab() + { + _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.Tab, false, false, false); _keyHandler.Handle(_keyInfo); + // Nothing happens when no auto complete handler is set Assert.Equal("Hello", _keyHandler.Text); - } - [Fact] - public void TestControlH() { - _keyInfo = new ConsoleKeyInfo('H', ConsoleKey.H, false, false, true); + _keyHandler = new KeyHandler(new Console2(), _history, (t, s) => _completions); + + _keyInfo = new ConsoleKeyInfo('H', ConsoleKey.H, false, false, false); _keyHandler.Handle(_keyInfo); - Assert.Equal("Hell", _keyHandler.Text); - } + _keyInfo = new ConsoleKeyInfo('i', ConsoleKey.I, false, false, false); + _keyHandler.Handle(_keyInfo); - [Fact] - public void TestHome() { - _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.Home, false, false, false); + _keyInfo = new ConsoleKeyInfo(' ', ConsoleKey.Spacebar, false, false, false); _keyHandler.Handle(_keyInfo); - _keyInfo = new ConsoleKeyInfo('S', ConsoleKey.S, false, false, false); + // Bring up the first Autocomplete + _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.Tab, false, false, false); _keyHandler.Handle(_keyInfo); - Assert.Equal("SHello", _keyHandler.Text); + for (var i = _completions.Length - 1; i >= 0; i--) + { + _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.Tab, true, false, false); + _keyHandler.Handle(_keyInfo); + + Assert.Equal($"Hi {_completions[i]}", _keyHandler.Text); + } } [Fact] - public void TestControlA() { + public void TestControlA() + { _keyInfo = new ConsoleKeyInfo('A', ConsoleKey.A, false, false, true); _keyHandler.Handle(_keyInfo); @@ -122,21 +99,23 @@ public void TestControlA() { } [Fact] - public void TestEnd() { - _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.Home, false, false, false); + public void TestControlB() + { + _keyInfo = new ConsoleKeyInfo('B', ConsoleKey.B, false, false, true); _keyHandler.Handle(_keyInfo); - _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.End, false, false, false); + _keyInfo = new ConsoleKeyInfo(' ', ConsoleKey.Spacebar, false, false, false); _keyHandler.Handle(_keyInfo); - _keyInfo = new ConsoleKeyInfo('!', ConsoleKey.D0, false, false, false); + _keyInfo = new ConsoleKeyInfo('N', ConsoleKey.N, false, false, false); _keyHandler.Handle(_keyInfo); - Assert.Equal("Hello!", _keyHandler.Text); + Assert.Equal("Hell No", _keyHandler.Text); } [Fact] - public void TestControlE() { + public void TestControlE() + { _keyInfo = new ConsoleKeyInfo('A', ConsoleKey.A, false, false, true); _keyHandler.Handle(_keyInfo); @@ -150,63 +129,52 @@ public void TestControlE() { } [Fact] - public void TestLeftArrow() { + public void TestControlF() + { _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.LeftArrow, false, false, false); _keyHandler.Handle(_keyInfo); - _keyInfo = new ConsoleKeyInfo(' ', ConsoleKey.Spacebar, false, false, false); + _keyInfo = new ConsoleKeyInfo('F', ConsoleKey.F, false, false, true); _keyHandler.Handle(_keyInfo); - _keyInfo = new ConsoleKeyInfo('N', ConsoleKey.N, false, false, false); + _keyInfo = new ConsoleKeyInfo('!', ConsoleKey.D0, false, false, false); _keyHandler.Handle(_keyInfo); - Assert.Equal("Hell No", _keyHandler.Text); + Assert.Equal("Hello!", _keyHandler.Text); } [Fact] - public void TestControlB() { - _keyInfo = new ConsoleKeyInfo('B', ConsoleKey.B, false, false, true); - _keyHandler.Handle(_keyInfo); - - _keyInfo = new ConsoleKeyInfo(' ', ConsoleKey.Spacebar, false, false, false); - _keyHandler.Handle(_keyInfo); - - _keyInfo = new ConsoleKeyInfo('N', ConsoleKey.N, false, false, false); + public void TestControlH() + { + _keyInfo = new ConsoleKeyInfo('H', ConsoleKey.H, false, false, true); _keyHandler.Handle(_keyInfo); - Assert.Equal("Hell No", _keyHandler.Text); + Assert.Equal("Hell", _keyHandler.Text); } [Fact] - public void TestRightArrow() { + public void TestControlK() + { _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.LeftArrow, false, false, false); _keyHandler.Handle(_keyInfo); - _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.RightArrow, false, false, false); - _keyHandler.Handle(_keyInfo); - - _keyInfo = new ConsoleKeyInfo('!', ConsoleKey.D0, false, false, false); + _keyInfo = new ConsoleKeyInfo('K', ConsoleKey.K, false, false, true); _keyHandler.Handle(_keyInfo); - Assert.Equal("Hello!", _keyHandler.Text); - } - - [Fact] - public void TestControlF() { - _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.LeftArrow, false, false, false); - _keyHandler.Handle(_keyInfo); + Assert.Equal("Hell", _keyHandler.Text); - _keyInfo = new ConsoleKeyInfo('F', ConsoleKey.F, false, false, true); + _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.Home, false, false, false); _keyHandler.Handle(_keyInfo); - _keyInfo = new ConsoleKeyInfo('!', ConsoleKey.D0, false, false, false); + _keyInfo = new ConsoleKeyInfo('K', ConsoleKey.K, false, false, true); _keyHandler.Handle(_keyInfo); - Assert.Equal("Hello!", _keyHandler.Text); + Assert.Equal(string.Empty, _keyHandler.Text); } [Fact] - public void TestControlL() { + public void TestControlL() + { _keyInfo = new ConsoleKeyInfo('L', ConsoleKey.L, false, false, true); _keyHandler.Handle(_keyInfo); @@ -214,57 +182,38 @@ public void TestControlL() { } [Fact] - public void TestUpArrow() { - for (int i = _history.Count - 1; i >= 0; i--) { - _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.UpArrow, false, false, false); - _keyHandler.Handle(_keyInfo); - - Assert.Equal(_history[i], _keyHandler.Text); - } - } - - [Fact] - public void TestControlP() { - for (int i = _history.Count - 1; i >= 0; i--) { - _keyInfo = new ConsoleKeyInfo('P', ConsoleKey.P, false, false, true); - _keyHandler.Handle(_keyInfo); - - Assert.Equal(_history[i], _keyHandler.Text); - } - } - - [Fact] - public void TestDownArrow() { - for (int i = _history.Count - 1; i >= 0; i--) { + public void TestControlN() + { + for (var i = _history.Count - 1; i >= 0; i--) + { _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.UpArrow, false, false, false); _keyHandler.Handle(_keyInfo); } - foreach (var t in _history) { + foreach (var t in _history) + { Assert.Equal(t, _keyHandler.Text); - _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.DownArrow, false, false, false); + _keyInfo = new ConsoleKeyInfo('N', ConsoleKey.N, false, false, true); _keyHandler.Handle(_keyInfo); } } [Fact] - public void TestControlN() { - for (int i = _history.Count - 1; i >= 0; i--) { - _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.UpArrow, false, false, false); + public void TestControlP() + { + for (var i = _history.Count - 1; i >= 0; i--) + { + _keyInfo = new ConsoleKeyInfo('P', ConsoleKey.P, false, false, true); _keyHandler.Handle(_keyInfo); - } - - foreach (var t in _history) { - Assert.Equal(t, _keyHandler.Text); - _keyInfo = new ConsoleKeyInfo('N', ConsoleKey.N, false, false, true); - _keyHandler.Handle(_keyInfo); + Assert.Equal(_history[i], _keyHandler.Text); } } [Fact] - public void TestControlU() { + public void TestControlU() + { _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.LeftArrow, false, false, false); _keyHandler.Handle(_keyInfo); @@ -283,60 +232,138 @@ public void TestControlU() { } [Fact] - public void TestControlK() { - _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.LeftArrow, false, false, false); + public void TestControlW() + { + _keyInfo = new ConsoleKeyInfo(' ', ConsoleKey.Spacebar, false, false, false); _keyHandler.Handle(_keyInfo); - _keyInfo = new ConsoleKeyInfo('K', ConsoleKey.K, false, false, true); + _keyInfo = new ConsoleKeyInfo('W', ConsoleKey.W, false, false, false); _keyHandler.Handle(_keyInfo); - Assert.Equal("Hell", _keyHandler.Text); + _keyInfo = new ConsoleKeyInfo('o', ConsoleKey.O, false, false, false); + _keyHandler.Handle(_keyInfo); - _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.Home, false, false, false); + _keyInfo = new ConsoleKeyInfo('r', ConsoleKey.R, false, false, false); _keyHandler.Handle(_keyInfo); - _keyInfo = new ConsoleKeyInfo('K', ConsoleKey.K, false, false, true); + _keyInfo = new ConsoleKeyInfo('l', ConsoleKey.L, false, false, false); + _keyHandler.Handle(_keyInfo); + + _keyInfo = new ConsoleKeyInfo('d', ConsoleKey.D, false, false, false); + _keyHandler.Handle(_keyInfo); + + _keyInfo = new ConsoleKeyInfo('W', ConsoleKey.W, false, false, true); + _keyHandler.Handle(_keyInfo); + + Assert.Equal("Hello ", _keyHandler.Text); + + _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.Backspace, false, false, false); + _keyHandler.Handle(_keyInfo); + + _keyInfo = new ConsoleKeyInfo('W', ConsoleKey.W, false, false, true); _keyHandler.Handle(_keyInfo); Assert.Equal(string.Empty, _keyHandler.Text); } [Fact] - public void TestControlW() { - _keyInfo = new ConsoleKeyInfo(' ', ConsoleKey.Spacebar, false, false, false); + public void TestDelete() + { + _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.LeftArrow, false, false, false); + _keyHandler.Handle(_keyInfo); + _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.Delete, false, false, false); _keyHandler.Handle(_keyInfo); - _keyInfo = new ConsoleKeyInfo('W', ConsoleKey.W, false, false, false); + Assert.Equal("Hell", _keyHandler.Text); + } + + [Fact] + public void TestDelete_EndOfLine() + { + _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.Delete, false, false, false); _keyHandler.Handle(_keyInfo); - _keyInfo = new ConsoleKeyInfo('o', ConsoleKey.O, false, false, false); + Assert.Equal("Hello", _keyHandler.Text); + } + + [Fact] + public void TestDownArrow() + { + for (var i = _history.Count - 1; i >= 0; i--) + { + _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.UpArrow, false, false, false); + _keyHandler.Handle(_keyInfo); + } + + foreach (var t in _history) + { + Assert.Equal(t, _keyHandler.Text); + + _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.DownArrow, false, false, false); + _keyHandler.Handle(_keyInfo); + } + } + + [Fact] + public void TestEnd() + { + _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.Home, false, false, false); _keyHandler.Handle(_keyInfo); - _keyInfo = new ConsoleKeyInfo('r', ConsoleKey.R, false, false, false); + _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.End, false, false, false); _keyHandler.Handle(_keyInfo); - _keyInfo = new ConsoleKeyInfo('l', ConsoleKey.L, false, false, false); + _keyInfo = new ConsoleKeyInfo('!', ConsoleKey.D0, false, false, false); _keyHandler.Handle(_keyInfo); - _keyInfo = new ConsoleKeyInfo('d', ConsoleKey.D, false, false, false); + Assert.Equal("Hello!", _keyHandler.Text); + } + + [Fact] + public void TestHome() + { + _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.Home, false, false, false); _keyHandler.Handle(_keyInfo); - _keyInfo = new ConsoleKeyInfo('W', ConsoleKey.W, false, false, true); + _keyInfo = new ConsoleKeyInfo('S', ConsoleKey.S, false, false, false); _keyHandler.Handle(_keyInfo); - Assert.Equal("Hello ", _keyHandler.Text); + Assert.Equal("SHello", _keyHandler.Text); + } - _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.Backspace, false, false, false); + [Fact] + public void TestLeftArrow() + { + _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.LeftArrow, false, false, false); _keyHandler.Handle(_keyInfo); - _keyInfo = new ConsoleKeyInfo('W', ConsoleKey.W, false, false, true); + _keyInfo = new ConsoleKeyInfo(' ', ConsoleKey.Spacebar, false, false, false); _keyHandler.Handle(_keyInfo); - Assert.Equal(string.Empty, _keyHandler.Text); + _keyInfo = new ConsoleKeyInfo('N', ConsoleKey.N, false, false, false); + _keyHandler.Handle(_keyInfo); + + Assert.Equal("Hell No", _keyHandler.Text); + } + + [Fact] + public void TestRightArrow() + { + _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.LeftArrow, false, false, false); + _keyHandler.Handle(_keyInfo); + + _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.RightArrow, false, false, false); + _keyHandler.Handle(_keyInfo); + + _keyInfo = new ConsoleKeyInfo('!', ConsoleKey.D0, false, false, false); + _keyHandler.Handle(_keyInfo); + + Assert.Equal("Hello!", _keyHandler.Text); } [Fact] - public void TestTab() { + public void TestTab() + { _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.Tab, false, false, false); _keyHandler.Handle(_keyInfo); @@ -354,7 +381,8 @@ public void TestTab() { _keyInfo = new ConsoleKeyInfo(' ', ConsoleKey.Spacebar, false, false, false); _keyHandler.Handle(_keyInfo); - foreach (var t in _completions) { + foreach (var t in _completions) + { _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.Tab, false, false, false); _keyHandler.Handle(_keyInfo); @@ -363,34 +391,41 @@ public void TestTab() { } [Fact] - public void TestBackwardsTab() { - _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.Tab, false, false, false); - _keyHandler.Handle(_keyInfo); + public void TestUpArrow() + { + for (var i = _history.Count - 1; i >= 0; i--) + { + _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.UpArrow, false, false, false); + _keyHandler.Handle(_keyInfo); - // Nothing happens when no auto complete handler is set + Assert.Equal(_history[i], _keyHandler.Text); + } + } + + [Fact] + public void TestWriteChar() + { Assert.Equal("Hello", _keyHandler.Text); - _keyHandler = new KeyHandler(new Console2(), _history, (t, s) => _completions); + _keyInfo = new ConsoleKeyInfo(' ', ConsoleKey.Spacebar, false, false, false); + _keyHandler.Handle(_keyInfo); - _keyInfo = new ConsoleKeyInfo('H', ConsoleKey.H, false, false, false); + _keyInfo = new ConsoleKeyInfo('W', ConsoleKey.W, false, false, false); _keyHandler.Handle(_keyInfo); - _keyInfo = new ConsoleKeyInfo('i', ConsoleKey.I, false, false, false); + _keyInfo = new ConsoleKeyInfo('o', ConsoleKey.O, false, false, false); _keyHandler.Handle(_keyInfo); - _keyInfo = new ConsoleKeyInfo(' ', ConsoleKey.Spacebar, false, false, false); + _keyInfo = new ConsoleKeyInfo('r', ConsoleKey.R, false, false, false); _keyHandler.Handle(_keyInfo); - // Bring up the first Autocomplete - _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.Tab, false, false, false); + _keyInfo = new ConsoleKeyInfo('l', ConsoleKey.L, false, false, false); _keyHandler.Handle(_keyInfo); - for (var i = _completions.Length - 1; i >= 0; i--) { - _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.Tab, true, false, false); - _keyHandler.Handle(_keyInfo); + _keyInfo = new ConsoleKeyInfo('d', ConsoleKey.D, false, false, false); + _keyHandler.Handle(_keyInfo); - Assert.Equal($"Hi {_completions[i]}", _keyHandler.Text); - } + Assert.Equal("Hello World", _keyHandler.Text); } } } \ No newline at end of file diff --git a/test/ReadLine.Tests/ReadLineTests.cs b/test/ReadLine.Tests/ReadLineTests.cs index fdcd3a2..7fa28c7 100755 --- a/test/ReadLine.Tests/ReadLineTests.cs +++ b/test/ReadLine.Tests/ReadLineTests.cs @@ -2,10 +2,14 @@ using System.Linq; using Xunit; -namespace ReadLine.Tests { - public class ReadLineTests : IDisposable { - public ReadLineTests() { - string[] history = { +namespace ReadLine.Tests +{ + public class ReadLineTests : IDisposable + { + public ReadLineTests() + { + string[] history = + { "ls -a", "dotnet run", "git init" @@ -13,29 +17,33 @@ public ReadLineTests() { ReadLine.AddHistory(history); } - [Fact] - public void TestNoInitialHistory() { - Assert.Equal(3, ReadLine.GetHistory().Count); - } - - [Fact] - public void TestUpdatesHistory() { - ReadLine.AddHistory("mkdir"); - Assert.Equal(4, ReadLine.GetHistory().Count); - Assert.Equal("mkdir", ReadLine.GetHistory().Last()); + public void Dispose() + { + // If all above tests pass + // clear history works + ReadLine.ClearHistory(); } [Fact] - public void TestGetCorrectHistory() { + public void TestGetCorrectHistory() + { Assert.Equal("ls -a", ReadLine.GetHistory()[0]); Assert.Equal("dotnet run", ReadLine.GetHistory()[1]); Assert.Equal("git init", ReadLine.GetHistory()[2]); } - public void Dispose() { - // If all above tests pass - // clear history works - ReadLine.ClearHistory(); + [Fact] + public void TestNoInitialHistory() + { + Assert.Equal(3, ReadLine.GetHistory().Count); + } + + [Fact] + public void TestUpdatesHistory() + { + ReadLine.AddHistory("mkdir"); + Assert.Equal(4, ReadLine.GetHistory().Count); + Assert.Equal("mkdir", ReadLine.GetHistory().Last()); } } } \ No newline at end of file From 69c677eb6e4cdc24d6b35d01dccfa291bd0f1b2e Mon Sep 17 00:00:00 2001 From: Latency McLaughlin Date: Sun, 8 Oct 2017 03:25:08 -0700 Subject: [PATCH 2/3] Change indent from 2 to 4 spaces. Updated tag in manifest. --- artifacts/ReadLine.1.2.1.nupkg | Bin 18932 -> 17985 bytes src/ReadLine.Demo/Program.cs | 50 +- src/ReadLine/Abstractions/Console2.cs | 42 +- src/ReadLine/Abstractions/IConsole.cs | 22 +- src/ReadLine/KeyHandler.cs | 510 +++++++------- src/ReadLine/ReadLine.cs | 84 +-- src/ReadLine/ReadLine.csproj | 4 +- test/ReadLine.Tests/Abstractions/Console2.cs | 76 +- test/ReadLine.Tests/KeyHandlerTests.cs | 688 +++++++++---------- test/ReadLine.Tests/ReadLine.Tests.csproj | 3 - test/ReadLine.Tests/ReadLineTests.cs | 72 +- 11 files changed, 774 insertions(+), 777 deletions(-) diff --git a/artifacts/ReadLine.1.2.1.nupkg b/artifacts/ReadLine.1.2.1.nupkg index 69eac557a0c37e9afa0a3ea0da737355092eb5b4..8e18dcd2f5e14f0ab8f6dc38b87040c756272c1d 100644 GIT binary patch literal 17985 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 FcmV(FwbK9q literal 18932 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 diff --git a/src/ReadLine.Demo/Program.cs b/src/ReadLine.Demo/Program.cs index de8b59d..8961e55 100755 --- a/src/ReadLine.Demo/Program.cs +++ b/src/ReadLine.Demo/Program.cs @@ -2,34 +2,34 @@ namespace ReadLine.Demo { - public class Program - { - public static void Main(string[] args) + public class Program { - Console.WriteLine("ReadLine Library Demo"); - Console.WriteLine("---------------------"); - Console.WriteLine(); + public static void Main(string[] args) + { + Console.WriteLine("ReadLine Library Demo"); + Console.WriteLine("---------------------"); + Console.WriteLine(); - string[] history = - { - "ls -a", - "dotnet run", - "git init" - }; - ReadLine.AddHistory(history); + string[] history = + { + "ls -a", + "dotnet run", + "git init" + }; + ReadLine.AddHistory(history); - ReadLine.AutoCompletionHandler = (t, s) => t.StartsWith("git ") - ? new[] - { - "init", - "clone", - "pull", - "push" - } - : null; + ReadLine.AutoCompletionHandler = (t, s) => t.StartsWith("git ") + ? new[] + { + "init", + "clone", + "pull", + "push" + } + : null; - var input = ReadLine.Read("(prompt)> "); - Console.Write(input); + var input = ReadLine.Read("(prompt)> "); + Console.Write(input); + } } - } } \ No newline at end of file diff --git a/src/ReadLine/Abstractions/Console2.cs b/src/ReadLine/Abstractions/Console2.cs index b2052fb..d4d2aa0 100644 --- a/src/ReadLine/Abstractions/Console2.cs +++ b/src/ReadLine/Abstractions/Console2.cs @@ -2,33 +2,33 @@ namespace ReadLine.Abstractions { - internal class Console2 : IConsole - { - public bool PasswordMode { get; set; } - public int CursorLeft => Console.CursorLeft; + internal class Console2 : IConsole + { + public bool PasswordMode { get; set; } + public int CursorLeft => Console.CursorLeft; - public int CursorTop => Console.CursorTop; + public int CursorTop => Console.CursorTop; - public int BufferWidth => Console.BufferWidth; + public int BufferWidth => Console.BufferWidth; - public int BufferHeight => Console.BufferHeight; + public int BufferHeight => Console.BufferHeight; - public void SetBufferSize(int width, int height) => Console.SetBufferSize(width, height); + public void SetBufferSize(int width, int height) => Console.SetBufferSize(width, height); - public void SetCursorPosition(int left, int top) - { - if (!PasswordMode) - Console.SetCursorPosition(left, top); - } + public void SetCursorPosition(int left, int top) + { + if (!PasswordMode) + Console.SetCursorPosition(left, top); + } - public void Write(string value) - { - if (PasswordMode) - value = new string(default(char), value.Length); + public void Write(string value) + { + if (PasswordMode) + value = new string(default(char), value.Length); - Console.Write(value); - } + Console.Write(value); + } - public void WriteLine(string value) => Console.WriteLine(value); - } + public void WriteLine(string value) => Console.WriteLine(value); + } } \ No newline at end of file diff --git a/src/ReadLine/Abstractions/IConsole.cs b/src/ReadLine/Abstractions/IConsole.cs index 65dfff9..c128a00 100644 --- a/src/ReadLine/Abstractions/IConsole.cs +++ b/src/ReadLine/Abstractions/IConsole.cs @@ -1,14 +1,14 @@ namespace ReadLine.Abstractions { - public interface IConsole - { - int CursorLeft { get; } - int CursorTop { get; } - int BufferWidth { get; } - int BufferHeight { get; } - void SetCursorPosition(int left, int top); - void SetBufferSize(int width, int height); - void Write(string value); - void WriteLine(string value); - } + public interface IConsole + { + int CursorLeft { get; } + int CursorTop { get; } + int BufferWidth { get; } + int BufferHeight { get; } + void SetCursorPosition(int left, int top); + void SetBufferSize(int width, int height); + void Write(string value); + void WriteLine(string value); + } } \ No newline at end of file diff --git a/src/ReadLine/KeyHandler.cs b/src/ReadLine/KeyHandler.cs index 50070cf..fdb40c0 100644 --- a/src/ReadLine/KeyHandler.cs +++ b/src/ReadLine/KeyHandler.cs @@ -5,303 +5,303 @@ namespace ReadLine { - public class KeyHandler - { - private readonly IConsole _console2; - private readonly List _history; - private readonly Dictionary _keyActions; - private readonly StringBuilder _text; - private string[] _completions; - private int _completionsIndex; - private int _completionStart; - private int _cursorLimit; - private int _cursorPos; - private int _historyIndex; - private ConsoleKeyInfo _keyInfo; - - public KeyHandler(IConsole console, List history, Func autoCompleteHandler) + public class KeyHandler { - _console2 = console; - - _historyIndex = history.Count; - _history = history; - _text = new StringBuilder(); - _keyActions = new Dictionary - { - ["LeftArrow"] = MoveCursorLeft, - ["Home"] = MoveCursorHome, - ["End"] = MoveCursorEnd, - ["ControlA"] = MoveCursorHome, - ["ControlB"] = MoveCursorLeft, - ["RightArrow"] = MoveCursorRight, - ["ControlF"] = MoveCursorRight, - ["ControlE"] = MoveCursorEnd, - ["Backspace"] = Backspace, - ["Delete"] = Delete, - ["ControlH"] = Backspace, - ["ControlL"] = ClearLine, - ["UpArrow"] = PrevHistory, - ["ControlP"] = PrevHistory, - ["DownArrow"] = NextHistory, - ["ControlN"] = NextHistory, - ["ControlU"] = () => + private readonly IConsole _console2; + private readonly List _history; + private readonly Dictionary _keyActions; + private readonly StringBuilder _text; + private string[] _completions; + private int _completionsIndex; + private int _completionStart; + private int _cursorLimit; + private int _cursorPos; + private int _historyIndex; + private ConsoleKeyInfo _keyInfo; + + public KeyHandler(IConsole console, List history, Func autoCompleteHandler) { - while (!IsStartOfLine()) - Backspace(); - }, - ["ControlK"] = () => - { - var pos = _cursorPos; - MoveCursorEnd(); - while (_cursorPos > pos) - Backspace(); - }, - ["ControlW"] = () => - { - while (!IsStartOfLine() && _text[_cursorPos - 1] != ' ') - Backspace(); - }, - ["Tab"] = () => - { - if (IsInAutoCompleteMode()) - NextAutoComplete(); - else - { - if (autoCompleteHandler == null || !IsEndOfLine()) - return; - - var anyOf = new[] + _console2 = console; + + _historyIndex = history.Count; + _history = history; + _text = new StringBuilder(); + _keyActions = new Dictionary { - ' ', - '.', - '/', - '\\', - ':' + ["LeftArrow"] = MoveCursorLeft, + ["Home"] = MoveCursorHome, + ["End"] = MoveCursorEnd, + ["ControlA"] = MoveCursorHome, + ["ControlB"] = MoveCursorLeft, + ["RightArrow"] = MoveCursorRight, + ["ControlF"] = MoveCursorRight, + ["ControlE"] = MoveCursorEnd, + ["Backspace"] = Backspace, + ["Delete"] = Delete, + ["ControlH"] = Backspace, + ["ControlL"] = ClearLine, + ["UpArrow"] = PrevHistory, + ["ControlP"] = PrevHistory, + ["DownArrow"] = NextHistory, + ["ControlN"] = NextHistory, + ["ControlU"] = () => + { + while (!IsStartOfLine()) + Backspace(); + }, + ["ControlK"] = () => + { + var pos = _cursorPos; + MoveCursorEnd(); + while (_cursorPos > pos) + Backspace(); + }, + ["ControlW"] = () => + { + while (!IsStartOfLine() && _text[_cursorPos - 1] != ' ') + Backspace(); + }, + ["Tab"] = () => + { + if (IsInAutoCompleteMode()) + NextAutoComplete(); + else + { + if (autoCompleteHandler == null || !IsEndOfLine()) + return; + + var anyOf = new[] + { + ' ', + '.', + '/', + '\\', + ':' + }; + var text = _text.ToString(); + + _completionStart = text.LastIndexOfAny(anyOf); + _completionStart = _completionStart == -1 ? 0 : _completionStart + 1; + + _completions = autoCompleteHandler.Invoke(text, _completionStart); + _completions = _completions?.Length == 0 ? null : _completions; + + if (_completions == null) + return; + + StartAutoComplete(); + } + }, + ["ShiftTab"] = () => + { + if (IsInAutoCompleteMode()) + PreviousAutoComplete(); + } }; - var text = _text.ToString(); - - _completionStart = text.LastIndexOfAny(anyOf); - _completionStart = _completionStart == -1 ? 0 : _completionStart + 1; - - _completions = autoCompleteHandler.Invoke(text, _completionStart); - _completions = _completions?.Length == 0 ? null : _completions; - - if (_completions == null) - return; - - StartAutoComplete(); - } - }, - ["ShiftTab"] = () => - { - if (IsInAutoCompleteMode()) - PreviousAutoComplete(); } - }; - } - public string Text => _text.ToString(); + public string Text => _text.ToString(); - private bool IsStartOfLine() => _cursorPos == 0; + private bool IsStartOfLine() => _cursorPos == 0; - private bool IsEndOfLine() => _cursorPos == _cursorLimit; + private bool IsEndOfLine() => _cursorPos == _cursorLimit; - private bool IsStartOfBuffer() => _console2.CursorLeft == 0; + private bool IsStartOfBuffer() => _console2.CursorLeft == 0; - private bool IsEndOfBuffer() => _console2.CursorLeft == _console2.BufferWidth - 1; - private bool IsInAutoCompleteMode() => _completions != null; + private bool IsEndOfBuffer() => _console2.CursorLeft == _console2.BufferWidth - 1; + private bool IsInAutoCompleteMode() => _completions != null; - private void MoveCursorLeft() - { - if (IsStartOfLine()) - return; + private void MoveCursorLeft() + { + if (IsStartOfLine()) + return; - if (IsStartOfBuffer()) - _console2.SetCursorPosition(_console2.BufferWidth - 1, _console2.CursorTop - 1); - else - _console2.SetCursorPosition(_console2.CursorLeft - 1, _console2.CursorTop); + if (IsStartOfBuffer()) + _console2.SetCursorPosition(_console2.BufferWidth - 1, _console2.CursorTop - 1); + else + _console2.SetCursorPosition(_console2.CursorLeft - 1, _console2.CursorTop); - _cursorPos--; - } + _cursorPos--; + } - private void MoveCursorHome() - { - while (!IsStartOfLine()) - MoveCursorLeft(); - } + private void MoveCursorHome() + { + while (!IsStartOfLine()) + MoveCursorLeft(); + } - private string BuildKeyInput() - { - return _keyInfo.Modifiers != ConsoleModifiers.Control && _keyInfo.Modifiers != ConsoleModifiers.Shift ? _keyInfo.Key.ToString() : _keyInfo.Modifiers + _keyInfo.Key.ToString(); - } + private string BuildKeyInput() + { + return _keyInfo.Modifiers != ConsoleModifiers.Control && _keyInfo.Modifiers != ConsoleModifiers.Shift ? _keyInfo.Key.ToString() : _keyInfo.Modifiers + _keyInfo.Key.ToString(); + } - private void MoveCursorRight() - { - if (IsEndOfLine()) - return; + private void MoveCursorRight() + { + if (IsEndOfLine()) + return; - if (IsEndOfBuffer()) - _console2.SetCursorPosition(0, _console2.CursorTop + 1); - else - _console2.SetCursorPosition(_console2.CursorLeft + 1, _console2.CursorTop); + if (IsEndOfBuffer()) + _console2.SetCursorPosition(0, _console2.CursorTop + 1); + else + _console2.SetCursorPosition(_console2.CursorLeft + 1, _console2.CursorTop); - _cursorPos++; - } + _cursorPos++; + } - private void MoveCursorEnd() - { - while (!IsEndOfLine()) - MoveCursorRight(); - } + private void MoveCursorEnd() + { + while (!IsEndOfLine()) + MoveCursorRight(); + } - private void ClearLine() - { - MoveCursorEnd(); - while (!IsStartOfLine()) - Backspace(); - } + private void ClearLine() + { + MoveCursorEnd(); + while (!IsStartOfLine()) + Backspace(); + } - private void WriteNewString(string str) - { - ClearLine(); - foreach (var character in str) - WriteChar(character); - } + private void WriteNewString(string str) + { + ClearLine(); + foreach (var character in str) + WriteChar(character); + } - private void WriteString(string str) - { - foreach (var character in str) - WriteChar(character); - } + private void WriteString(string str) + { + foreach (var character in str) + WriteChar(character); + } - private void WriteChar() => WriteChar(_keyInfo.KeyChar); + private void WriteChar() => WriteChar(_keyInfo.KeyChar); - private void WriteChar(char c) - { - if (IsEndOfLine()) - { - _text.Append(c); - _console2.Write(c.ToString()); - _cursorPos++; - } else - { - var left = _console2.CursorLeft; - var top = _console2.CursorTop; - var str = _text.ToString().Substring(_cursorPos); - _text.Insert(_cursorPos, c); - _console2.Write(c + str); - _console2.SetCursorPosition(left, top); - MoveCursorRight(); - } - - _cursorLimit++; - } + private void WriteChar(char c) + { + if (IsEndOfLine()) + { + _text.Append(c); + _console2.Write(c.ToString()); + _cursorPos++; + } else + { + var left = _console2.CursorLeft; + var top = _console2.CursorTop; + var str = _text.ToString().Substring(_cursorPos); + _text.Insert(_cursorPos, c); + _console2.Write(c + str); + _console2.SetCursorPosition(left, top); + MoveCursorRight(); + } + + _cursorLimit++; + } - private void Backspace() - { - if (IsStartOfLine()) - return; - - MoveCursorLeft(); - var index = _cursorPos; - _text.Remove(index, 1); - var replacement = _text.ToString().Substring(index); - var left = _console2.CursorLeft; - var top = _console2.CursorTop; - _console2.Write($"{replacement} "); - _console2.SetCursorPosition(left, top); - _cursorLimit--; - } + private void Backspace() + { + if (IsStartOfLine()) + return; + + MoveCursorLeft(); + var index = _cursorPos; + _text.Remove(index, 1); + var replacement = _text.ToString().Substring(index); + var left = _console2.CursorLeft; + var top = _console2.CursorTop; + _console2.Write($"{replacement} "); + _console2.SetCursorPosition(left, top); + _cursorLimit--; + } - private void Delete() - { - if (IsEndOfLine()) - return; - - var index = _cursorPos; - _text.Remove(index, 1); - var replacement = _text.ToString().Substring(index); - var left = _console2.CursorLeft; - var top = _console2.CursorTop; - _console2.Write($"{replacement} "); - _console2.SetCursorPosition(left, top); - _cursorLimit--; - } + private void Delete() + { + if (IsEndOfLine()) + return; + + var index = _cursorPos; + _text.Remove(index, 1); + var replacement = _text.ToString().Substring(index); + var left = _console2.CursorLeft; + var top = _console2.CursorTop; + _console2.Write($"{replacement} "); + _console2.SetCursorPosition(left, top); + _cursorLimit--; + } - private void StartAutoComplete() - { - while (_cursorPos > _completionStart) - Backspace(); + private void StartAutoComplete() + { + while (_cursorPos > _completionStart) + Backspace(); - _completionsIndex = 0; + _completionsIndex = 0; - WriteString(_completions[_completionsIndex]); - } + WriteString(_completions[_completionsIndex]); + } - private void NextAutoComplete() - { - while (_cursorPos > _completionStart) - Backspace(); + private void NextAutoComplete() + { + while (_cursorPos > _completionStart) + Backspace(); - _completionsIndex++; + _completionsIndex++; - if (_completionsIndex == _completions.Length) - _completionsIndex = 0; + if (_completionsIndex == _completions.Length) + _completionsIndex = 0; - WriteString(_completions[_completionsIndex]); - } + WriteString(_completions[_completionsIndex]); + } - private void PreviousAutoComplete() - { - while (_cursorPos > _completionStart) - Backspace(); + private void PreviousAutoComplete() + { + while (_cursorPos > _completionStart) + Backspace(); - _completionsIndex--; + _completionsIndex--; - if (_completionsIndex == -1) - _completionsIndex = _completions.Length - 1; + if (_completionsIndex == -1) + _completionsIndex = _completions.Length - 1; - WriteString(_completions[_completionsIndex]); - } + WriteString(_completions[_completionsIndex]); + } - private void PrevHistory() - { - if (_historyIndex > 0) - { - _historyIndex--; - WriteNewString(_history[_historyIndex]); - } - } + private void PrevHistory() + { + if (_historyIndex > 0) + { + _historyIndex--; + WriteNewString(_history[_historyIndex]); + } + } - private void NextHistory() - { - if (_historyIndex < _history.Count) - { - _historyIndex++; - if (_historyIndex == _history.Count) - ClearLine(); - else - WriteNewString(_history[_historyIndex]); - } - } + private void NextHistory() + { + if (_historyIndex < _history.Count) + { + _historyIndex++; + if (_historyIndex == _history.Count) + ClearLine(); + else + WriteNewString(_history[_historyIndex]); + } + } - private void ResetAutoComplete() - { - _completions = null; - _completionsIndex = 0; - } + private void ResetAutoComplete() + { + _completions = null; + _completionsIndex = 0; + } - public void Handle(ConsoleKeyInfo keyInfo) - { - _keyInfo = keyInfo; + public void Handle(ConsoleKeyInfo keyInfo) + { + _keyInfo = keyInfo; - // If in auto complete mode and Tab wasn't pressed - if (IsInAutoCompleteMode() && _keyInfo.Key != ConsoleKey.Tab) - ResetAutoComplete(); + // If in auto complete mode and Tab wasn't pressed + if (IsInAutoCompleteMode() && _keyInfo.Key != ConsoleKey.Tab) + ResetAutoComplete(); - _keyActions.TryGetValue(BuildKeyInput(), out var action); - action = action ?? WriteChar; - action.Invoke(); + _keyActions.TryGetValue(BuildKeyInput(), out var action); + action = action ?? WriteChar; + action.Invoke(); + } } - } } \ No newline at end of file diff --git a/src/ReadLine/ReadLine.cs b/src/ReadLine/ReadLine.cs index 5581f2b..a67f7e3 100755 --- a/src/ReadLine/ReadLine.cs +++ b/src/ReadLine/ReadLine.cs @@ -4,48 +4,48 @@ namespace ReadLine { - public static class ReadLine - { - private static KeyHandler _keyHandler; - private static List _history; - - static ReadLine() - { - _history = new List(); - } - - public static Func AutoCompletionHandler { private get; set; } - public static bool PasswordMode { private get; set; } - - public static void AddHistory(params string[] text) => _history.AddRange(text); - public static List GetHistory() => _history; - public static void ClearHistory() => _history = new List(); - - public static string Read(string prompt = "", string defaultInput = "") + public static class ReadLine { - Console.Write(prompt); - - _keyHandler = new KeyHandler(new Console2 - { - PasswordMode = PasswordMode - }, _history, AutoCompletionHandler); - var keyInfo = Console.ReadKey(true); - - while (keyInfo.Key != ConsoleKey.Enter) - { - _keyHandler.Handle(keyInfo); - keyInfo = Console.ReadKey(true); - } - - Console.WriteLine(); - - var text = _keyHandler.Text; - if (string.IsNullOrWhiteSpace(text) && !string.IsNullOrWhiteSpace(defaultInput)) - text = defaultInput; - else - _history.Add(text); - - return text; + private static KeyHandler _keyHandler; + private static List _history; + + static ReadLine() + { + _history = new List(); + } + + public static Func AutoCompletionHandler { private get; set; } + public static bool PasswordMode { private get; set; } + + public static void AddHistory(params string[] text) => _history.AddRange(text); + public static List GetHistory() => _history; + public static void ClearHistory() => _history = new List(); + + public static string Read(string prompt = "", string defaultInput = "") + { + Console.Write(prompt); + + _keyHandler = new KeyHandler(new Console2 + { + PasswordMode = PasswordMode + }, _history, AutoCompletionHandler); + var keyInfo = Console.ReadKey(true); + + while (keyInfo.Key != ConsoleKey.Enter) + { + _keyHandler.Handle(keyInfo); + keyInfo = Console.ReadKey(true); + } + + Console.WriteLine(); + + var text = _keyHandler.Text; + if (string.IsNullOrWhiteSpace(text) && !string.IsNullOrWhiteSpace(defaultInput)) + text = defaultInput; + else + _history.Add(text); + + return text; + } } - } } \ No newline at end of file diff --git a/src/ReadLine/ReadLine.csproj b/src/ReadLine/ReadLine.csproj index 56295ee..615ffac 100755 --- a/src/ReadLine/ReadLine.csproj +++ b/src/ReadLine/ReadLine.csproj @@ -3,7 +3,7 @@ A GNU-Readline like library for .NET/.NET Core ReadLine - Toni Solarin-Sodara;Latency McLaughlin + Toni Solarin-Sodara Toni Solarin-Sodara net47;netcoreapp2.0;netstandard2.0 1.2.1 @@ -29,7 +29,7 @@ Consolidated redundant code and expressions. Repacked for multi-frameworks. Updated versioning. Updated test projects. - + Toni Solarin-Sodara diff --git a/test/ReadLine.Tests/Abstractions/Console2.cs b/test/ReadLine.Tests/Abstractions/Console2.cs index 2239f50..338e874 100644 --- a/test/ReadLine.Tests/Abstractions/Console2.cs +++ b/test/ReadLine.Tests/Abstractions/Console2.cs @@ -2,44 +2,44 @@ namespace ReadLine.Tests.Abstractions { - internal class Console2 : IConsole - { - public Console2() + internal class Console2 : IConsole { - CursorLeft = 0; - CursorTop = 0; - BufferWidth = 100; - BufferHeight = 100; + public Console2() + { + CursorLeft = 0; + CursorTop = 0; + BufferWidth = 100; + BufferHeight = 100; + } + + public int CursorLeft { get; private set; } + + public int CursorTop { get; private set; } + + public int BufferWidth { get; private set; } + + public int BufferHeight { get; private set; } + + public void SetBufferSize(int width, int height) + { + BufferWidth = width; + BufferHeight = height; + } + + public void SetCursorPosition(int left, int top) + { + CursorLeft = left; + CursorTop = top; + } + + public void Write(string value) + { + CursorLeft += value.Length; + } + + public void WriteLine(string value) + { + CursorLeft += value.Length; + } } - - public int CursorLeft { get; private set; } - - public int CursorTop { get; private set; } - - public int BufferWidth { get; private set; } - - public int BufferHeight { get; private set; } - - public void SetBufferSize(int width, int height) - { - BufferWidth = width; - BufferHeight = height; - } - - public void SetCursorPosition(int left, int top) - { - CursorLeft = left; - CursorTop = top; - } - - public void Write(string value) - { - CursorLeft += value.Length; - } - - public void WriteLine(string value) - { - CursorLeft += value.Length; - } - } } \ No newline at end of file diff --git a/test/ReadLine.Tests/KeyHandlerTests.cs b/test/ReadLine.Tests/KeyHandlerTests.cs index a8306f5..90b470f 100644 --- a/test/ReadLine.Tests/KeyHandlerTests.cs +++ b/test/ReadLine.Tests/KeyHandlerTests.cs @@ -5,427 +5,427 @@ namespace ReadLine.Tests { - public class KeyHandlerTests - { - public KeyHandlerTests() + public class KeyHandlerTests { - _completions = new[] - { - "World", - "Angel", - "Love" - }; - _history = new List(new[] - { - "dotnet run", - "git init", - "clear" - }); - _keyHandler = new KeyHandler(new Console2(), _history, null); - - _keyInfo = new ConsoleKeyInfo('H', ConsoleKey.H, false, false, false); - _keyHandler.Handle(_keyInfo); - - _keyInfo = new ConsoleKeyInfo('e', ConsoleKey.E, false, false, false); - _keyHandler.Handle(_keyInfo); - - _keyInfo = new ConsoleKeyInfo('l', ConsoleKey.L, false, false, false); - _keyHandler.Handle(_keyInfo); - - _keyInfo = new ConsoleKeyInfo('l', ConsoleKey.L, false, false, false); - _keyHandler.Handle(_keyInfo); - - _keyInfo = new ConsoleKeyInfo('o', ConsoleKey.O, false, false, false); - _keyHandler.Handle(_keyInfo); - } - - private KeyHandler _keyHandler; - private ConsoleKeyInfo _keyInfo; - private readonly List _history; - private readonly string[] _completions; - - [Fact] - public void TestBackspace() - { - _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.Backspace, false, false, false); - _keyHandler.Handle(_keyInfo); - - Assert.Equal("Hell", _keyHandler.Text); - } - - [Fact] - public void TestBackwardsTab() - { - _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.Tab, false, false, false); - _keyHandler.Handle(_keyInfo); - - // Nothing happens when no auto complete handler is set - Assert.Equal("Hello", _keyHandler.Text); - - _keyHandler = new KeyHandler(new Console2(), _history, (t, s) => _completions); - - _keyInfo = new ConsoleKeyInfo('H', ConsoleKey.H, false, false, false); - _keyHandler.Handle(_keyInfo); - - _keyInfo = new ConsoleKeyInfo('i', ConsoleKey.I, false, false, false); - _keyHandler.Handle(_keyInfo); - - _keyInfo = new ConsoleKeyInfo(' ', ConsoleKey.Spacebar, false, false, false); - _keyHandler.Handle(_keyInfo); - - // Bring up the first Autocomplete - _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.Tab, false, false, false); - _keyHandler.Handle(_keyInfo); - - for (var i = _completions.Length - 1; i >= 0; i--) - { - _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.Tab, true, false, false); - _keyHandler.Handle(_keyInfo); - - Assert.Equal($"Hi {_completions[i]}", _keyHandler.Text); - } - } - - [Fact] - public void TestControlA() - { - _keyInfo = new ConsoleKeyInfo('A', ConsoleKey.A, false, false, true); - _keyHandler.Handle(_keyInfo); - - _keyInfo = new ConsoleKeyInfo('S', ConsoleKey.S, false, false, false); - _keyHandler.Handle(_keyInfo); - - Assert.Equal("SHello", _keyHandler.Text); - } - - [Fact] - public void TestControlB() - { - _keyInfo = new ConsoleKeyInfo('B', ConsoleKey.B, false, false, true); - _keyHandler.Handle(_keyInfo); + public KeyHandlerTests() + { + _completions = new[] + { + "World", + "Angel", + "Love" + }; + _history = new List(new[] + { + "dotnet run", + "git init", + "clear" + }); + _keyHandler = new KeyHandler(new Console2(), _history, null); + + _keyInfo = new ConsoleKeyInfo('H', ConsoleKey.H, false, false, false); + _keyHandler.Handle(_keyInfo); + + _keyInfo = new ConsoleKeyInfo('e', ConsoleKey.E, false, false, false); + _keyHandler.Handle(_keyInfo); + + _keyInfo = new ConsoleKeyInfo('l', ConsoleKey.L, false, false, false); + _keyHandler.Handle(_keyInfo); + + _keyInfo = new ConsoleKeyInfo('l', ConsoleKey.L, false, false, false); + _keyHandler.Handle(_keyInfo); + + _keyInfo = new ConsoleKeyInfo('o', ConsoleKey.O, false, false, false); + _keyHandler.Handle(_keyInfo); + } + + private KeyHandler _keyHandler; + private ConsoleKeyInfo _keyInfo; + private readonly List _history; + private readonly string[] _completions; + + [Fact] + public void TestBackspace() + { + _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.Backspace, false, false, false); + _keyHandler.Handle(_keyInfo); + + Assert.Equal("Hell", _keyHandler.Text); + } + + [Fact] + public void TestBackwardsTab() + { + _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.Tab, false, false, false); + _keyHandler.Handle(_keyInfo); + + // Nothing happens when no auto complete handler is set + Assert.Equal("Hello", _keyHandler.Text); + + _keyHandler = new KeyHandler(new Console2(), _history, (t, s) => _completions); + + _keyInfo = new ConsoleKeyInfo('H', ConsoleKey.H, false, false, false); + _keyHandler.Handle(_keyInfo); + + _keyInfo = new ConsoleKeyInfo('i', ConsoleKey.I, false, false, false); + _keyHandler.Handle(_keyInfo); - _keyInfo = new ConsoleKeyInfo(' ', ConsoleKey.Spacebar, false, false, false); - _keyHandler.Handle(_keyInfo); + _keyInfo = new ConsoleKeyInfo(' ', ConsoleKey.Spacebar, false, false, false); + _keyHandler.Handle(_keyInfo); - _keyInfo = new ConsoleKeyInfo('N', ConsoleKey.N, false, false, false); - _keyHandler.Handle(_keyInfo); + // Bring up the first Autocomplete + _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.Tab, false, false, false); + _keyHandler.Handle(_keyInfo); + + for (var i = _completions.Length - 1; i >= 0; i--) + { + _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.Tab, true, false, false); + _keyHandler.Handle(_keyInfo); - Assert.Equal("Hell No", _keyHandler.Text); - } - - [Fact] - public void TestControlE() - { - _keyInfo = new ConsoleKeyInfo('A', ConsoleKey.A, false, false, true); - _keyHandler.Handle(_keyInfo); - - _keyInfo = new ConsoleKeyInfo('E', ConsoleKey.E, false, false, true); - _keyHandler.Handle(_keyInfo); + Assert.Equal($"Hi {_completions[i]}", _keyHandler.Text); + } + } + + [Fact] + public void TestControlA() + { + _keyInfo = new ConsoleKeyInfo('A', ConsoleKey.A, false, false, true); + _keyHandler.Handle(_keyInfo); + + _keyInfo = new ConsoleKeyInfo('S', ConsoleKey.S, false, false, false); + _keyHandler.Handle(_keyInfo); + + Assert.Equal("SHello", _keyHandler.Text); + } + + [Fact] + public void TestControlB() + { + _keyInfo = new ConsoleKeyInfo('B', ConsoleKey.B, false, false, true); + _keyHandler.Handle(_keyInfo); + + _keyInfo = new ConsoleKeyInfo(' ', ConsoleKey.Spacebar, false, false, false); + _keyHandler.Handle(_keyInfo); + + _keyInfo = new ConsoleKeyInfo('N', ConsoleKey.N, false, false, false); + _keyHandler.Handle(_keyInfo); + + Assert.Equal("Hell No", _keyHandler.Text); + } + + [Fact] + public void TestControlE() + { + _keyInfo = new ConsoleKeyInfo('A', ConsoleKey.A, false, false, true); + _keyHandler.Handle(_keyInfo); + + _keyInfo = new ConsoleKeyInfo('E', ConsoleKey.E, false, false, true); + _keyHandler.Handle(_keyInfo); - _keyInfo = new ConsoleKeyInfo('!', ConsoleKey.D0, false, false, false); - _keyHandler.Handle(_keyInfo); + _keyInfo = new ConsoleKeyInfo('!', ConsoleKey.D0, false, false, false); + _keyHandler.Handle(_keyInfo); - Assert.Equal("Hello!", _keyHandler.Text); - } + Assert.Equal("Hello!", _keyHandler.Text); + } - [Fact] - public void TestControlF() - { - _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.LeftArrow, false, false, false); - _keyHandler.Handle(_keyInfo); + [Fact] + public void TestControlF() + { + _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.LeftArrow, false, false, false); + _keyHandler.Handle(_keyInfo); - _keyInfo = new ConsoleKeyInfo('F', ConsoleKey.F, false, false, true); - _keyHandler.Handle(_keyInfo); + _keyInfo = new ConsoleKeyInfo('F', ConsoleKey.F, false, false, true); + _keyHandler.Handle(_keyInfo); - _keyInfo = new ConsoleKeyInfo('!', ConsoleKey.D0, false, false, false); - _keyHandler.Handle(_keyInfo); + _keyInfo = new ConsoleKeyInfo('!', ConsoleKey.D0, false, false, false); + _keyHandler.Handle(_keyInfo); - Assert.Equal("Hello!", _keyHandler.Text); - } + Assert.Equal("Hello!", _keyHandler.Text); + } - [Fact] - public void TestControlH() - { - _keyInfo = new ConsoleKeyInfo('H', ConsoleKey.H, false, false, true); - _keyHandler.Handle(_keyInfo); + [Fact] + public void TestControlH() + { + _keyInfo = new ConsoleKeyInfo('H', ConsoleKey.H, false, false, true); + _keyHandler.Handle(_keyInfo); - Assert.Equal("Hell", _keyHandler.Text); - } + Assert.Equal("Hell", _keyHandler.Text); + } - [Fact] - public void TestControlK() - { - _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.LeftArrow, false, false, false); - _keyHandler.Handle(_keyInfo); + [Fact] + public void TestControlK() + { + _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.LeftArrow, false, false, false); + _keyHandler.Handle(_keyInfo); - _keyInfo = new ConsoleKeyInfo('K', ConsoleKey.K, false, false, true); - _keyHandler.Handle(_keyInfo); + _keyInfo = new ConsoleKeyInfo('K', ConsoleKey.K, false, false, true); + _keyHandler.Handle(_keyInfo); - Assert.Equal("Hell", _keyHandler.Text); + Assert.Equal("Hell", _keyHandler.Text); - _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.Home, false, false, false); - _keyHandler.Handle(_keyInfo); + _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.Home, false, false, false); + _keyHandler.Handle(_keyInfo); - _keyInfo = new ConsoleKeyInfo('K', ConsoleKey.K, false, false, true); - _keyHandler.Handle(_keyInfo); + _keyInfo = new ConsoleKeyInfo('K', ConsoleKey.K, false, false, true); + _keyHandler.Handle(_keyInfo); - Assert.Equal(string.Empty, _keyHandler.Text); - } + Assert.Equal(string.Empty, _keyHandler.Text); + } - [Fact] - public void TestControlL() - { - _keyInfo = new ConsoleKeyInfo('L', ConsoleKey.L, false, false, true); - _keyHandler.Handle(_keyInfo); + [Fact] + public void TestControlL() + { + _keyInfo = new ConsoleKeyInfo('L', ConsoleKey.L, false, false, true); + _keyHandler.Handle(_keyInfo); - Assert.Equal(string.Empty, _keyHandler.Text); - } + Assert.Equal(string.Empty, _keyHandler.Text); + } - [Fact] - public void TestControlN() - { - for (var i = _history.Count - 1; i >= 0; i--) - { - _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.UpArrow, false, false, false); - _keyHandler.Handle(_keyInfo); - } - - foreach (var t in _history) - { - Assert.Equal(t, _keyHandler.Text); - - _keyInfo = new ConsoleKeyInfo('N', ConsoleKey.N, false, false, true); - _keyHandler.Handle(_keyInfo); - } - } + [Fact] + public void TestControlN() + { + for (var i = _history.Count - 1; i >= 0; i--) + { + _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.UpArrow, false, false, false); + _keyHandler.Handle(_keyInfo); + } - [Fact] - public void TestControlP() - { - for (var i = _history.Count - 1; i >= 0; i--) - { - _keyInfo = new ConsoleKeyInfo('P', ConsoleKey.P, false, false, true); - _keyHandler.Handle(_keyInfo); + foreach (var t in _history) + { + Assert.Equal(t, _keyHandler.Text); - Assert.Equal(_history[i], _keyHandler.Text); - } - } + _keyInfo = new ConsoleKeyInfo('N', ConsoleKey.N, false, false, true); + _keyHandler.Handle(_keyInfo); + } + } - [Fact] - public void TestControlU() - { - _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.LeftArrow, false, false, false); - _keyHandler.Handle(_keyInfo); + [Fact] + public void TestControlP() + { + for (var i = _history.Count - 1; i >= 0; i--) + { + _keyInfo = new ConsoleKeyInfo('P', ConsoleKey.P, false, false, true); + _keyHandler.Handle(_keyInfo); - _keyInfo = new ConsoleKeyInfo('U', ConsoleKey.U, false, false, true); - _keyHandler.Handle(_keyInfo); + Assert.Equal(_history[i], _keyHandler.Text); + } + } + + [Fact] + public void TestControlU() + { + _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.LeftArrow, false, false, false); + _keyHandler.Handle(_keyInfo); - Assert.Equal("o", _keyHandler.Text); + _keyInfo = new ConsoleKeyInfo('U', ConsoleKey.U, false, false, true); + _keyHandler.Handle(_keyInfo); - _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.End, false, false, false); - _keyHandler.Handle(_keyInfo); + Assert.Equal("o", _keyHandler.Text); - _keyInfo = new ConsoleKeyInfo('U', ConsoleKey.U, false, false, true); - _keyHandler.Handle(_keyInfo); + _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.End, false, false, false); + _keyHandler.Handle(_keyInfo); - Assert.Equal(string.Empty, _keyHandler.Text); - } + _keyInfo = new ConsoleKeyInfo('U', ConsoleKey.U, false, false, true); + _keyHandler.Handle(_keyInfo); - [Fact] - public void TestControlW() - { - _keyInfo = new ConsoleKeyInfo(' ', ConsoleKey.Spacebar, false, false, false); - _keyHandler.Handle(_keyInfo); + Assert.Equal(string.Empty, _keyHandler.Text); + } - _keyInfo = new ConsoleKeyInfo('W', ConsoleKey.W, false, false, false); - _keyHandler.Handle(_keyInfo); + [Fact] + public void TestControlW() + { + _keyInfo = new ConsoleKeyInfo(' ', ConsoleKey.Spacebar, false, false, false); + _keyHandler.Handle(_keyInfo); - _keyInfo = new ConsoleKeyInfo('o', ConsoleKey.O, false, false, false); - _keyHandler.Handle(_keyInfo); + _keyInfo = new ConsoleKeyInfo('W', ConsoleKey.W, false, false, false); + _keyHandler.Handle(_keyInfo); - _keyInfo = new ConsoleKeyInfo('r', ConsoleKey.R, false, false, false); - _keyHandler.Handle(_keyInfo); + _keyInfo = new ConsoleKeyInfo('o', ConsoleKey.O, false, false, false); + _keyHandler.Handle(_keyInfo); - _keyInfo = new ConsoleKeyInfo('l', ConsoleKey.L, false, false, false); - _keyHandler.Handle(_keyInfo); + _keyInfo = new ConsoleKeyInfo('r', ConsoleKey.R, false, false, false); + _keyHandler.Handle(_keyInfo); - _keyInfo = new ConsoleKeyInfo('d', ConsoleKey.D, false, false, false); - _keyHandler.Handle(_keyInfo); + _keyInfo = new ConsoleKeyInfo('l', ConsoleKey.L, false, false, false); + _keyHandler.Handle(_keyInfo); - _keyInfo = new ConsoleKeyInfo('W', ConsoleKey.W, false, false, true); - _keyHandler.Handle(_keyInfo); + _keyInfo = new ConsoleKeyInfo('d', ConsoleKey.D, false, false, false); + _keyHandler.Handle(_keyInfo); - Assert.Equal("Hello ", _keyHandler.Text); + _keyInfo = new ConsoleKeyInfo('W', ConsoleKey.W, false, false, true); + _keyHandler.Handle(_keyInfo); - _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.Backspace, false, false, false); - _keyHandler.Handle(_keyInfo); + Assert.Equal("Hello ", _keyHandler.Text); - _keyInfo = new ConsoleKeyInfo('W', ConsoleKey.W, false, false, true); - _keyHandler.Handle(_keyInfo); + _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.Backspace, false, false, false); + _keyHandler.Handle(_keyInfo); - Assert.Equal(string.Empty, _keyHandler.Text); - } + _keyInfo = new ConsoleKeyInfo('W', ConsoleKey.W, false, false, true); + _keyHandler.Handle(_keyInfo); - [Fact] - public void TestDelete() - { - _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.LeftArrow, false, false, false); - _keyHandler.Handle(_keyInfo); - _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.Delete, false, false, false); - _keyHandler.Handle(_keyInfo); + Assert.Equal(string.Empty, _keyHandler.Text); + } + + [Fact] + public void TestDelete() + { + _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.LeftArrow, false, false, false); + _keyHandler.Handle(_keyInfo); + _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.Delete, false, false, false); + _keyHandler.Handle(_keyInfo); + + Assert.Equal("Hell", _keyHandler.Text); + } - Assert.Equal("Hell", _keyHandler.Text); - } + [Fact] + public void TestDelete_EndOfLine() + { + _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.Delete, false, false, false); + _keyHandler.Handle(_keyInfo); - [Fact] - public void TestDelete_EndOfLine() - { - _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.Delete, false, false, false); - _keyHandler.Handle(_keyInfo); + Assert.Equal("Hello", _keyHandler.Text); + } - Assert.Equal("Hello", _keyHandler.Text); - } + [Fact] + public void TestDownArrow() + { + for (var i = _history.Count - 1; i >= 0; i--) + { + _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.UpArrow, false, false, false); + _keyHandler.Handle(_keyInfo); + } - [Fact] - public void TestDownArrow() - { - for (var i = _history.Count - 1; i >= 0; i--) - { - _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.UpArrow, false, false, false); - _keyHandler.Handle(_keyInfo); - } - - foreach (var t in _history) - { - Assert.Equal(t, _keyHandler.Text); - - _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.DownArrow, false, false, false); - _keyHandler.Handle(_keyInfo); - } - } + foreach (var t in _history) + { + Assert.Equal(t, _keyHandler.Text); - [Fact] - public void TestEnd() - { - _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.Home, false, false, false); - _keyHandler.Handle(_keyInfo); + _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.DownArrow, false, false, false); + _keyHandler.Handle(_keyInfo); + } + } - _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.End, false, false, false); - _keyHandler.Handle(_keyInfo); + [Fact] + public void TestEnd() + { + _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.Home, false, false, false); + _keyHandler.Handle(_keyInfo); - _keyInfo = new ConsoleKeyInfo('!', ConsoleKey.D0, false, false, false); - _keyHandler.Handle(_keyInfo); + _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.End, false, false, false); + _keyHandler.Handle(_keyInfo); - Assert.Equal("Hello!", _keyHandler.Text); - } + _keyInfo = new ConsoleKeyInfo('!', ConsoleKey.D0, false, false, false); + _keyHandler.Handle(_keyInfo); - [Fact] - public void TestHome() - { - _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.Home, false, false, false); - _keyHandler.Handle(_keyInfo); + Assert.Equal("Hello!", _keyHandler.Text); + } - _keyInfo = new ConsoleKeyInfo('S', ConsoleKey.S, false, false, false); - _keyHandler.Handle(_keyInfo); + [Fact] + public void TestHome() + { + _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.Home, false, false, false); + _keyHandler.Handle(_keyInfo); - Assert.Equal("SHello", _keyHandler.Text); - } + _keyInfo = new ConsoleKeyInfo('S', ConsoleKey.S, false, false, false); + _keyHandler.Handle(_keyInfo); - [Fact] - public void TestLeftArrow() - { - _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.LeftArrow, false, false, false); - _keyHandler.Handle(_keyInfo); + Assert.Equal("SHello", _keyHandler.Text); + } - _keyInfo = new ConsoleKeyInfo(' ', ConsoleKey.Spacebar, false, false, false); - _keyHandler.Handle(_keyInfo); + [Fact] + public void TestLeftArrow() + { + _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.LeftArrow, false, false, false); + _keyHandler.Handle(_keyInfo); - _keyInfo = new ConsoleKeyInfo('N', ConsoleKey.N, false, false, false); - _keyHandler.Handle(_keyInfo); + _keyInfo = new ConsoleKeyInfo(' ', ConsoleKey.Spacebar, false, false, false); + _keyHandler.Handle(_keyInfo); - Assert.Equal("Hell No", _keyHandler.Text); - } + _keyInfo = new ConsoleKeyInfo('N', ConsoleKey.N, false, false, false); + _keyHandler.Handle(_keyInfo); - [Fact] - public void TestRightArrow() - { - _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.LeftArrow, false, false, false); - _keyHandler.Handle(_keyInfo); + Assert.Equal("Hell No", _keyHandler.Text); + } - _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.RightArrow, false, false, false); - _keyHandler.Handle(_keyInfo); + [Fact] + public void TestRightArrow() + { + _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.LeftArrow, false, false, false); + _keyHandler.Handle(_keyInfo); - _keyInfo = new ConsoleKeyInfo('!', ConsoleKey.D0, false, false, false); - _keyHandler.Handle(_keyInfo); + _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.RightArrow, false, false, false); + _keyHandler.Handle(_keyInfo); - Assert.Equal("Hello!", _keyHandler.Text); - } + _keyInfo = new ConsoleKeyInfo('!', ConsoleKey.D0, false, false, false); + _keyHandler.Handle(_keyInfo); - [Fact] - public void TestTab() - { - _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.Tab, false, false, false); - _keyHandler.Handle(_keyInfo); + Assert.Equal("Hello!", _keyHandler.Text); + } - // Nothing happens when no auto complete handler is set - Assert.Equal("Hello", _keyHandler.Text); + [Fact] + public void TestTab() + { + _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.Tab, false, false, false); + _keyHandler.Handle(_keyInfo); + + // Nothing happens when no auto complete handler is set + Assert.Equal("Hello", _keyHandler.Text); - _keyHandler = new KeyHandler(new Console2(), _history, (t, s) => _completions); + _keyHandler = new KeyHandler(new Console2(), _history, (t, s) => _completions); - _keyInfo = new ConsoleKeyInfo('H', ConsoleKey.H, false, false, false); - _keyHandler.Handle(_keyInfo); + _keyInfo = new ConsoleKeyInfo('H', ConsoleKey.H, false, false, false); + _keyHandler.Handle(_keyInfo); - _keyInfo = new ConsoleKeyInfo('i', ConsoleKey.I, false, false, false); - _keyHandler.Handle(_keyInfo); + _keyInfo = new ConsoleKeyInfo('i', ConsoleKey.I, false, false, false); + _keyHandler.Handle(_keyInfo); - _keyInfo = new ConsoleKeyInfo(' ', ConsoleKey.Spacebar, false, false, false); - _keyHandler.Handle(_keyInfo); + _keyInfo = new ConsoleKeyInfo(' ', ConsoleKey.Spacebar, false, false, false); + _keyHandler.Handle(_keyInfo); - foreach (var t in _completions) - { - _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.Tab, false, false, false); - _keyHandler.Handle(_keyInfo); + foreach (var t in _completions) + { + _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.Tab, false, false, false); + _keyHandler.Handle(_keyInfo); - Assert.Equal($"Hi {t}", _keyHandler.Text); - } - } + Assert.Equal($"Hi {t}", _keyHandler.Text); + } + } - [Fact] - public void TestUpArrow() - { - for (var i = _history.Count - 1; i >= 0; i--) - { - _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.UpArrow, false, false, false); - _keyHandler.Handle(_keyInfo); + [Fact] + public void TestUpArrow() + { + for (var i = _history.Count - 1; i >= 0; i--) + { + _keyInfo = new ConsoleKeyInfo('\0', ConsoleKey.UpArrow, false, false, false); + _keyHandler.Handle(_keyInfo); - Assert.Equal(_history[i], _keyHandler.Text); - } - } + Assert.Equal(_history[i], _keyHandler.Text); + } + } - [Fact] - public void TestWriteChar() - { - Assert.Equal("Hello", _keyHandler.Text); + [Fact] + public void TestWriteChar() + { + Assert.Equal("Hello", _keyHandler.Text); - _keyInfo = new ConsoleKeyInfo(' ', ConsoleKey.Spacebar, false, false, false); - _keyHandler.Handle(_keyInfo); + _keyInfo = new ConsoleKeyInfo(' ', ConsoleKey.Spacebar, false, false, false); + _keyHandler.Handle(_keyInfo); - _keyInfo = new ConsoleKeyInfo('W', ConsoleKey.W, false, false, false); - _keyHandler.Handle(_keyInfo); + _keyInfo = new ConsoleKeyInfo('W', ConsoleKey.W, false, false, false); + _keyHandler.Handle(_keyInfo); - _keyInfo = new ConsoleKeyInfo('o', ConsoleKey.O, false, false, false); - _keyHandler.Handle(_keyInfo); + _keyInfo = new ConsoleKeyInfo('o', ConsoleKey.O, false, false, false); + _keyHandler.Handle(_keyInfo); - _keyInfo = new ConsoleKeyInfo('r', ConsoleKey.R, false, false, false); - _keyHandler.Handle(_keyInfo); + _keyInfo = new ConsoleKeyInfo('r', ConsoleKey.R, false, false, false); + _keyHandler.Handle(_keyInfo); - _keyInfo = new ConsoleKeyInfo('l', ConsoleKey.L, false, false, false); - _keyHandler.Handle(_keyInfo); + _keyInfo = new ConsoleKeyInfo('l', ConsoleKey.L, false, false, false); + _keyHandler.Handle(_keyInfo); - _keyInfo = new ConsoleKeyInfo('d', ConsoleKey.D, false, false, false); - _keyHandler.Handle(_keyInfo); + _keyInfo = new ConsoleKeyInfo('d', ConsoleKey.D, false, false, false); + _keyHandler.Handle(_keyInfo); - Assert.Equal("Hello World", _keyHandler.Text); + Assert.Equal("Hello World", _keyHandler.Text); + } } - } } \ No newline at end of file diff --git a/test/ReadLine.Tests/ReadLine.Tests.csproj b/test/ReadLine.Tests/ReadLine.Tests.csproj index c22ae78..bf74bf8 100755 --- a/test/ReadLine.Tests/ReadLine.Tests.csproj +++ b/test/ReadLine.Tests/ReadLine.Tests.csproj @@ -10,9 +10,6 @@ - - - diff --git a/test/ReadLine.Tests/ReadLineTests.cs b/test/ReadLine.Tests/ReadLineTests.cs index 7fa28c7..9634a64 100755 --- a/test/ReadLine.Tests/ReadLineTests.cs +++ b/test/ReadLine.Tests/ReadLineTests.cs @@ -4,46 +4,46 @@ namespace ReadLine.Tests { - public class ReadLineTests : IDisposable - { - public ReadLineTests() + public class ReadLineTests : IDisposable { - string[] history = - { - "ls -a", - "dotnet run", - "git init" - }; - ReadLine.AddHistory(history); - } + public ReadLineTests() + { + string[] history = + { + "ls -a", + "dotnet run", + "git init" + }; + ReadLine.AddHistory(history); + } - public void Dispose() - { - // If all above tests pass - // clear history works - ReadLine.ClearHistory(); - } + public void Dispose() + { + // If all above tests pass + // clear history works + ReadLine.ClearHistory(); + } - [Fact] - public void TestGetCorrectHistory() - { - Assert.Equal("ls -a", ReadLine.GetHistory()[0]); - Assert.Equal("dotnet run", ReadLine.GetHistory()[1]); - Assert.Equal("git init", ReadLine.GetHistory()[2]); - } + [Fact] + public void TestGetCorrectHistory() + { + Assert.Equal("ls -a", ReadLine.GetHistory()[0]); + Assert.Equal("dotnet run", ReadLine.GetHistory()[1]); + Assert.Equal("git init", ReadLine.GetHistory()[2]); + } - [Fact] - public void TestNoInitialHistory() - { - Assert.Equal(3, ReadLine.GetHistory().Count); - } + [Fact] + public void TestNoInitialHistory() + { + Assert.Equal(3, ReadLine.GetHistory().Count); + } - [Fact] - public void TestUpdatesHistory() - { - ReadLine.AddHistory("mkdir"); - Assert.Equal(4, ReadLine.GetHistory().Count); - Assert.Equal("mkdir", ReadLine.GetHistory().Last()); + [Fact] + public void TestUpdatesHistory() + { + ReadLine.AddHistory("mkdir"); + Assert.Equal(4, ReadLine.GetHistory().Count); + Assert.Equal("mkdir", ReadLine.GetHistory().Last()); + } } - } } \ No newline at end of file From 2f1e2aed2fc4e878434e4d1894df6a7770703f0d Mon Sep 17 00:00:00 2001 From: Latency McLaughlin Date: Sun, 8 Oct 2017 03:34:45 -0700 Subject: [PATCH 3/3] Updated ReadLine.csproj --- src/ReadLine/ReadLine.csproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ReadLine/ReadLine.csproj b/src/ReadLine/ReadLine.csproj index 615ffac..0643dc4 100755 --- a/src/ReadLine/ReadLine.csproj +++ b/src/ReadLine/ReadLine.csproj @@ -10,10 +10,10 @@ ReadLine ReadLine readline;gnu;console;shell;cui - https://github.com/tsolarin/readline - https://github.com/tsolarin/readline/blob/master/LICENSE + https://github.com/tonerdo/readline + https://github.com/tonerdo/readline/blob/master/LICENSE git - https://github.com/tsolarin/readline + https://github.com/tonerdo/readline false false false