// Tab across to the next stop, or perform tab completion. private void Tab() { if (TabComplete == null) { // Add the TAB character and repaint the line. AddChar('\t'); } else { if (_state != ReadlineState.Completing) { CollectLastWord('\0'); _state = ReadlineState.Completing; } // Perform tab completion and insert the results. var e = new TabCompleteEventArgs(_lastWord.ToString(), ++_tabCount); TabComplete(this, e); if (e.Insert != null) { _savePosn = _posn; // Insert the value that we found. var saveOverwrite = _overwrite; _overwrite = false; _savePosn = e.Insert.Length; _state = ReadlineState.Completing; foreach (var ch in e.Insert) { AddChar(ch); } _overwrite = saveOverwrite; } else if (e.Alternatives != null && e.Alternatives.Length > 0) { // Print the alternatives for the user. _savePosn = _posn; EndLine(); PrintAlternatives?.Invoke(this, new PrintAlternativesEventArgs(e.Alternatives)); WritePrompt?.Invoke(this, EventArgs.Empty); _posn = _savePosn; _state = ReadlineState.Completing; Redraw(); } else { if (e.Error) { ResetComplete(ReadlineState.MoreInput); } // No alternatives, or alternatives not supplied yet. Console.Beep(); } } }
// Cancel the current line and start afresh with a new prompt. private void CancelLine() { EndLine(); WritePrompt?.Invoke(this, EventArgs.Empty); _posn = 0; _length = 0; _column = 0; _lastColumn = 0; _historyPosn = -1; }
public string ReadPassword(Action writePromtAction) { var readline = new Readline.Readline(History) { CtrlCInterrupts = CtrlCInterrupts, CtrlDIsEOF = CtrlDIsEOF, CtrlZIsEOF = CtrlZIsEOF }; readline.WritePrompt += (sender, args) => WritePrompt?.Invoke(this, EventArgs.Empty); readline.Interrupt += (sender, args) => ShellInterrupt?.Invoke(this, EventArgs.Empty); return(readline.ReadPassword()); }
public string ReadPassword() { var treatControlCAsInterrupt = Console.TreatControlCAsInput; Console.TreatControlCAsInput = !CtrlCInterrupts; try { // Output the prompt. WritePrompt?.Invoke(this, EventArgs.Empty); var pass = new Stack(); for (var consKeyInfo = Console.ReadKey(true); consKeyInfo.Key != ConsoleKey.Enter; consKeyInfo = Console.ReadKey(true)) { if (consKeyInfo.Key == ConsoleKey.Backspace) { try { Console.SetCursorPosition(Console.CursorLeft - 1, Console.CursorTop); Console.Write(" "); Console.SetCursorPosition(Console.CursorLeft - 1, Console.CursorTop); pass.Pop(); } catch (InvalidOperationException) { Console.SetCursorPosition(Console.CursorLeft + 1, Console.CursorTop); } } else { Console.Write("*"); pass.Push(consKeyInfo.KeyChar.ToString()); } } var chars = pass.ToArray(); var password = new string[chars.Length]; Array.Copy(chars, password, chars.Length); Array.Reverse(password); return(string.Join(string.Empty, password)); } finally { Console.TreatControlCAsInput = treatControlCAsInterrupt; } }
// Read the next line of input using line editing. Returns "null" // if an EOF indication is encountered in the input. public string ReadLine() { var treatControlCAsInterrupt = Console.TreatControlCAsInput; Console.TreatControlCAsInput = !CtrlCInterrupts; try { // Output the prompt. WritePrompt?.Invoke(this, EventArgs.Empty); // Enter the main character input loop. _posn = 0; _length = 0; _column = 0; _lastColumn = 0; _overwrite = false; _historyPosn = -1; var ctrlv = false; _state = ReadlineState.MoreInput; do { var key = ConsoleExtensions.ReadKey(true); var ch = key.KeyChar; if (ctrlv) { ctrlv = false; if ((ch >= 0x0001 && ch <= 0x001F) || ch == 0x007F) { // Insert a control character into the buffer. AddChar(ch); continue; } } if (ch != '\0') { switch (ch) { case '\u0001': { // CTRL-A: move to the home position. MoveHome(); } break; case '\u0002': { // CTRL-B: go back one character. MoveLeft(); } break; case '\u0003': { // CTRL-C encountered in "raw" mode. if (CtrlCInterrupts) { EndLine(); Interrupt?.Invoke(null, EventArgs.Empty); return(null); } CancelLine(); _lastWord.Length = 0; } break; case '\u0004': { // CTRL-D: EOF or delete the current character. if (CtrlDIsEOF) { _lastWord.Length = 0; // Signal an EOF if the buffer is empty. if (_length == 0) { EndLine(); return(null); } } else { Delete(); ResetComplete(ReadlineState.MoreInput); } } break; case '\u0005': { // CTRL-E: move to the end position. MoveEnd(); } break; case '\u0006': { // CTRL-F: go forward one character. MoveRight(); } break; case '\u0007': { // CTRL-G: ring the terminal bell. Console.Beep(); } break; case '\u0008': case '\u007F': { if (key.Key == ConsoleKey.Delete) { // Delete the character under the cursor. Delete(); } else { // Delete the character before the cursor. Backspace(); } ResetComplete(ReadlineState.MoreInput); } break; case '\u0009': { // Process a tab. Tab(); } break; case '\u000A': case '\u000D': { // Line termination. EndLine(); ResetComplete(ReadlineState.Done); _lastWord.Length = 0; } break; case '\u000B': { // CTRL-K: erase until the end of the line. EraseToEnd(); } break; case '\u000C': { // CTRL-L: clear screen and redraw. Console.Clear(); WritePrompt?.Invoke(this, EventArgs.Empty); Redraw(); } break; case '\u000E': { // CTRL-N: move down in the history. MoveDown(); } break; case '\u0010': { // CTRL-P: move up in the history. MoveUp(); } break; case '\u0015': { // CTRL-U: erase to the start of the line. EraseToStart(); ResetComplete(ReadlineState.None); } break; case '\u0016': { // CTRL-V: prefix a control character. ctrlv = true; } break; case '\u0017': { // CTRL-W: erase the previous word. EraseWord(); ResetComplete(ReadlineState.MoreInput); } break; case '\u0019': { // CTRL-Y: yank the last erased string. if (_yankedString != null) { foreach (var ch2 in _yankedString) { AddChar(ch2); } } } break; case '\u001A': { // CTRL-Z: Windows end of file indication. if (CtrlZIsEOF && _length == 0) { EndLine(); return(null); } } break; case '\u001B': { // Escape is "clear line". Clear(); ResetComplete(ReadlineState.MoreInput); } break; default: { if (ch >= ' ') { // Ordinary character. AddChar(ch); ResetComplete(ReadlineState.MoreInput); } } break; } } else if (key.Modifiers == 0) { switch (key.Key) { case ConsoleKey.Backspace: { // Delete the character before the cursor. Backspace(); ResetComplete(ReadlineState.MoreInput); } break; case ConsoleKey.Delete: { // Delete the character under the cursor. Delete(); ResetComplete(ReadlineState.MoreInput); } break; case ConsoleKey.Enter: { // Line termination. EndLine(); ResetComplete(ReadlineState.Done); } break; case ConsoleKey.Escape: { // Clear the current line. Clear(); ResetComplete(ReadlineState.None); } break; case ConsoleKey.Tab: { // Process a tab. Tab(); } break; case ConsoleKey.LeftArrow: { // Move left one character. MoveLeft(); } break; case ConsoleKey.RightArrow: { // Move right one character. MoveRight(); } break; case ConsoleKey.UpArrow: { // Move up one line in the history. MoveUp(); } break; case ConsoleKey.DownArrow: { // Move down one line in the history. MoveDown(); } break; case ConsoleKey.Home: { // Move to the beginning of the line. MoveHome(); } break; case ConsoleKey.End: { // Move to the end of the line. MoveEnd(); } break; case ConsoleKey.Insert: { // Toggle insert/overwrite mode. _overwrite = !_overwrite; } break; } } else if ((key.Modifiers & ConsoleModifiers.Alt) != 0) { switch (key.Key) { case ConsoleKey.F: { // ALT-F: move forward a word. MoveForwardWord(); } break; case ConsoleKey.B: { // ALT-B: move backward a word. MoveBackwardWord(); } break; case ConsoleKey.D: { // ALT-D: erase until the end of the word. EraseToEndWord(); } break; case ConsoleKey.Backspace: case ConsoleKey.Delete: { // ALT-DEL: erase until the start of the word. EraseToStartWord(); } break; } } } while (_state != ReadlineState.Done); return(new string(_buffer, 0, _length)); } finally { Console.TreatControlCAsInput = treatControlCAsInterrupt; } }