Example #1
0
        public static string FetchLine(Func <string, string> suggestionsCallback)
        {
            if (logStream != null)
            {
                throw new NotSupportedException("Log is redirected to file");
            }

            if (ConsoleUtils.IsOutputRedirected)
            {
                return(Console.ReadLine());
            }

            activeInput = true;

            RenderInputPrompt();

            Console.CursorVisible        = true;
            Console.TreatControlCAsInput = true;

            int consoleWidth;

            buffer           = new StringBuilder();
            bufferPosition   = 0;
            bufferLastLength = 0;
            activeSuggestion = null;

            if (inputHistory == null)
            {
                inputHistory = new History();
            }

            inputHistory.CursorToEnd();
            inputHistory.Append("");

            while (activeInput)
            {
                bool isChanged = false;

                ConsoleModifiers mod;
                ConsoleKeyInfo   cki = Console.ReadKey(true);
                if (cki.Key == ConsoleKey.Escape)
                {
                    cki = Console.ReadKey(true);
                    mod = ConsoleModifiers.Alt;
                }
                else
                {
                    mod = cki.Modifiers;
                }

                // Process input
                switch (cki.Key)
                {
                case ConsoleKey.Enter: {
                    if (buffer.Length > 0)
                    {
                        activeInput = false;
                        isChanged   = true;
                    }
                    break;
                }

                case ConsoleKey.LeftArrow: {
                    if (bufferPosition > 0)
                    {
                        bufferPosition--;
                    }
                    break;
                }

                case ConsoleKey.RightArrow: {
                    if (bufferPosition < buffer.Length)
                    {
                        bufferPosition++;
                    }
                    else if (activeSuggestion != null)
                    {
                        buffer.Clear();
                        buffer.Append(activeSuggestion);
                        bufferPosition = buffer.Length;
                        isChanged      = true;
                    }
                    break;
                }

                case ConsoleKey.UpArrow: {
                    if (inputHistory != null && inputHistory.IsPreviousAvailable)
                    {
                        inputHistory.UpdateCurrent(buffer.ToString());
                        buffer.Clear();
                        buffer.Append(inputHistory.GetPrevious());
                        bufferPosition = buffer.Length;
                        isChanged      = true;
                    }
                    break;
                }

                case ConsoleKey.DownArrow: {
                    if (inputHistory != null && inputHistory.IsNextAvailable)
                    {
                        inputHistory.UpdateCurrent(buffer.ToString());
                        buffer.Clear();
                        buffer.Append(inputHistory.GetNext());
                        bufferPosition = buffer.Length;
                        isChanged      = true;
                    }
                    break;
                }

                case ConsoleKey.Home: {
                    bufferPosition = 0;
                    break;
                }

                case ConsoleKey.End: {
                    bufferPosition = buffer.Length;
                    break;
                }

                case ConsoleKey.Backspace: {
                    if (bufferPosition > 0)
                    {
                        bufferPosition--;
                        buffer.Remove(bufferPosition, 1);
                        isChanged = true;
                    }
                    break;
                }

                case ConsoleKey.Delete: {
                    if (bufferPosition < buffer.Length)
                    {
                        buffer.Remove(bufferPosition, 1);
                        isChanged = true;
                    }
                    break;
                }

                case ConsoleKey.Tab: {
                    if (activeSuggestion != null)
                    {
                        buffer.Clear();
                        buffer.Append(activeSuggestion);
                        bufferPosition = buffer.Length;
                        isChanged      = true;
                    }
                    break;
                }

                default: {
                    if (mod == ConsoleModifiers.Control && cki.Key == ConsoleKey.C)
                    {
                        // CTRL+C: Close
                        activeInput = false;
                        buffer      = null;
                    }
                    else if (mod == ConsoleModifiers.Control && cki.Key == ConsoleKey.L)
                    {
                        // CTRL+L: Clear screen
                        Console.Clear();
                        Console.SetCursorPosition(0, 0);
                        RenderInputPrompt();
                        isChanged = true;
                    }
                    else if (cki.KeyChar != (char)0 && !char.IsControl(cki.KeyChar))
                    {
                        buffer.Insert(bufferPosition, cki.KeyChar);
                        bufferPosition++;
                        isChanged = true;
                    }
                    break;
                }
                }

                // Fetch suggestions
                if (activeInput && isChanged && suggestionsCallback != null)
                {
                    activeSuggestion = suggestionsCallback(buffer.ToString());
                }

                RenderInput(isChanged);
                isChanged = false;
            }

            Console.TreatControlCAsInput = false;
            Console.CursorVisible        = false;

            activeInput = false;

            if (buffer != null)
            {
                // Set cursor position to the end and create a new line
                consoleWidth = Console.BufferWidth;
                Console.SetCursorPosition((activeInputX + buffer.Length) % consoleWidth, activeInputY + (activeInputX + buffer.Length) / consoleWidth);
                Console.WriteLine();

                string input = buffer.ToString();

                if (string.IsNullOrEmpty(input))
                {
                    inputHistory.Discard();
                }
                else
                {
                    inputHistory.Accept(input);
                }

                return(input);
            }
            else
            {
                // Erase input line
                Console.SetCursorPosition(0, activeInputY);
                Console.ResetColor();

                for (int i = 0; i <= activeInputX + bufferLastLength; i++)
                {
                    Console.Write(' ');
                }

                Console.SetCursorPosition(0, activeInputY);

                return(null);
            }
        }