Exemplo n.º 1
0
        // TODO - Consider the case where a "cursor" is implemented, allowing deletion / modification at various places in the string and having to keep track of placement

        public UserInteraction GetUserInteraction(string userInputString, bool isUpArrowPressed, bool isDownArrowPressed, TerminalState terminalState)
        {
            // Make sure we actually have a user interaction to deal with this frame - if not, short circuit and just return
            var userInteraction = new UserInteraction();

            if (string.IsNullOrEmpty(userInputString) && !isUpArrowPressed && !isDownArrowPressed)
            {
                return(userInteraction);
            }

            // First, check to see if the user hit the up arrow key to scroll through their last inputs
            if (isUpArrowPressed)
            {
                var previousCommands             = terminalState.GetPreviousTerminalCommands();
                var currentSelectedCommandNumber = terminalState.GetTerminalCommandSelectedNumber();

                var selectedCommand = GetPreviousCommandWithArrowKeys(previousCommands, currentSelectedCommandNumber, isUpArrow: true);

                // If, for whatever reason, we could not find the selected command for the user, do not try to change their input or do anything
                if (selectedCommand == null)
                {
                    return(userInteraction);
                }

                // Clear out and modify the user's current input, they want this replaced with a previous submitted input
                terminalState.ClearCurrentInput();
                var isSetInputSuccess = terminalState.TrySetCurrentInput(selectedCommand.TerminalCommandInput);

                if (isSetInputSuccess)
                {
                    userInteraction.IsInputModified = true;
                    userInteraction.ModifiedInput   = selectedCommand.TerminalCommandInput;
                    terminalState.SetTerminalCommandSelectedNumber(selectedCommand.TerminalCommandNumber);
                }
                else
                {
                    Debug.Assert(isSetInputSuccess, $"Failed to set current input: {selectedCommand.TerminalCommandInput}");
                }

                return(userInteraction);
            }

            // Next, check to see if the user hit the down arrow key to scroll through their last inputs
            if (isDownArrowPressed)
            {
                var previousCommands             = terminalState.GetPreviousTerminalCommands();
                var currentSelectedCommandNumber = terminalState.GetTerminalCommandSelectedNumber();

                var selectedCommand = GetPreviousCommandWithArrowKeys(previousCommands, currentSelectedCommandNumber, isUpArrow: false);

                // If, for whatever reason, we could not find the selected command for the user, do not try to change their input or do anything
                if (selectedCommand == null)
                {
                    return(userInteraction);
                }

                // Clear out and modify the user's current input, they want this replaced with a previous submitted input
                terminalState.ClearCurrentInput();
                var isSetInputSuccess = terminalState.TrySetCurrentInput(selectedCommand.TerminalCommandInput);

                if (isSetInputSuccess)
                {
                    userInteraction.IsInputModified = true;
                    userInteraction.ModifiedInput   = selectedCommand.TerminalCommandInput;
                    terminalState.SetTerminalCommandSelectedNumber(selectedCommand.TerminalCommandNumber);
                }
                else
                {
                    Debug.Assert(isSetInputSuccess, $"Failed to set current input: {selectedCommand.TerminalCommandInput}");
                }

                return(userInteraction);
            }

            // If the user starts typing, we know they did not try to find a previous command (or are modifying a previous one)
            // At that point, remove any command that may have been selected and treat this as a brand new input case
            terminalState.ClearTerminalCommandSelectedNumber();

            // Parse which characters the user's have pressed
            foreach (char userInputCharacter in userInputString)
            {
                // Case of enter or return being pressed to submit the user's input
                if (_submitCharacters.Contains(userInputCharacter))
                {
                    // Get the user's full input (not including enter or any prompt characters)
                    userInteraction.IsInputSubmitted = true;
                    userInteraction.SubmittedInput   = terminalState.GetCurrentInput();

                    // Clear the user's input since it has been submitted, regardless of its validity
                    terminalState.ClearCurrentInput();
                    userInteraction.IsInputModified = true;
                    userInteraction.ModifiedInput   = string.Empty;
                }

                // Case of backspace or delete bring pressed to delete some of user's input not yet submitted
                else if (_deleteCharacters.Contains(userInputCharacter))
                {
                    var currentInput = terminalState.GetCurrentInput();

                    // If the last character is being deleted, the state should be cleared differently
                    if (currentInput.Length == 1)
                    {
                        terminalState.ClearCurrentInput();
                        userInteraction.IsInputModified = true;
                        userInteraction.ModifiedInput   = string.Empty;
                    }

                    // Otherwise if there is more than one character, delete the last character
                    else if (currentInput.Length != 0)
                    {
                        // If we have characters to delete, remove them and reflect that change back to the user
                        var updatedInput      = currentInput.Remove(currentInput.Length - 1);
                        var isSetInputSuccess = terminalState.TrySetCurrentInput(updatedInput);

                        if (isSetInputSuccess)
                        {
                            userInteraction.IsInputModified = true;
                            userInteraction.ModifiedInput   = updatedInput;
                        }

                        Debug.Assert(isSetInputSuccess, $"Failed to set current input: {updatedInput}");
                    }
                }

                // Case of every other key, treated as the text of the key pressed
                else
                {
                    var currentInput      = terminalState.GetCurrentInput();
                    var updatedInput      = currentInput + userInputCharacter;
                    var isSetInputSuccess = terminalState.TrySetCurrentInput(updatedInput);

                    if (isSetInputSuccess)
                    {
                        userInteraction.IsInputModified = true;
                        userInteraction.ModifiedInput   = updatedInput;
                    }
                    else
                    {
                        // We may be over the character limit, so check if the input is valid before asserting that it should have been set
                        var isValidInput = terminalState.TryValidateInput(updatedInput, out var validInput);
                        Debug.Assert(!isSetInputSuccess && !isValidInput, $"Failed to set current input with valid input: {validInput}");
                    }
                }
            }

            return(userInteraction);
        }