Skip to content

Commit

Permalink
Merge pull request AY2425S1-CS2103T-T11-2#138 from Incogdino/branch-a…
Browse files Browse the repository at this point in the history
…ddCommandHistory

Branch add command history
  • Loading branch information
DesSnowy authored Nov 1, 2024
2 parents c2b9fe9 + f685b7c commit 5592372
Show file tree
Hide file tree
Showing 4 changed files with 288 additions and 0 deletions.
23 changes: 23 additions & 0 deletions docs/UserGuide.md
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,29 @@ Examples:
* `Export path/data/tutorial12.csv` will export the contacts in the Address book as a csv file (tutorial12.csv at the relative path given)


### Accessing command history <kbd>↑</kbd> and <kbd>↓</kbd>

KonTActs automatically saves every (valid or invalid) command entered which can then be retrieved later by using the <kbd>↑</kbd> and <kbd>↓</kbd> arrow keys.

<box type="warning">

Current input in the text field is erased when accessing the command history.
</box>


<box type="warning">

If the current session of KonTActs has no commands added, pressing the <kbd>↑</kbd> and <kbd>↓</kbd> arrow keys will not have any effect.
</box>


Example:
1. `github n/Harry` launches the github account of Harry on the browser
2. The command text field box is now empty.
3. Pressing <kbd>↑</kbd> will retrieve the last input command which will populate the command text field box with `github n/Harry`
4. Continuously pressing <kbd>↑</kbd> will scroll through all commands that have been previously input.
5. Pressing <kbd>↓</kbd> will scroll down to the more recent commands that was last input.


### Exiting the program : `exit`

Expand Down
130 changes: 130 additions & 0 deletions src/main/java/seedu/address/storage/CommandHistory.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
package seedu.address.storage;

import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;

import javafx.scene.input.KeyCode;

/**
* Stores the history of commands entered by the user.
*/
public class CommandHistory {
private static CommandHistory instance = null;
private static Logger logger = Logger.getLogger("CommandHistory");

private ArrayList<String> listOfCommands;
private int index;


/**
* Constructor for CommandHistory.
*/
private CommandHistory() {
this.listOfCommands = new ArrayList<>();
this.index = 0;
}

/**
* Returns the instance of the CommandHistory class. Instantiates a new instance if not instantiated.
*
* @return instance of the {@code CommandHistory} class
*/
public static CommandHistory getInstance() {
if (instance == null) {
instance = new CommandHistory();
}

return instance;
}

/**
* Adds a new command to the {@code CommandHistory} instance.
*
* @param command command to add.
*/
public void addCommand(String command) {
if (command == null) {
return;
}

assert(command != null && !command.isEmpty());

logger.log(Level.INFO, "Adding command into command history");
listOfCommands.add(command);
index = listOfCommands.size();
}

/**
* Returns the requested command by the user based on user's key input. The valid {@KeyCode} inputs are the up
* and down arrow keys.
*
* @param key {@KeyCode} input.
* @return command corresponding to the input requested by the user.
*/
public String getPastCommand(KeyCode key) {
assert(key.isArrowKey() && (key == KeyCode.UP || key == KeyCode.DOWN));

// list of commands is empty
if (listOfCommands.size() == 0) {
logger.log(Level.INFO, "No history of commands, returning empty string");
return "";
}

logger.log(Level.INFO, "Returning requested command");
switch (key) {
case UP:
return getPreviousCommand();
case DOWN:
return getNextCommand();
default:
return "";
}
}

/**
* Returns the previous command in the command history. This corresponds to clicking the up arrow key.
*
* @return previous command in the command history.
*/
private String getPreviousCommand() {
// No commands left in command history
if (index == 0) {
logger.log(Level.INFO, "No more commands preceding this, returning current command.");
return listOfCommands.get(index);
}

logger.log(Level.INFO, "Returning previous command");
String command = listOfCommands.get(index - 1);
index--;

return command;
}

/**
* Returns the next command in the command history. This corresponds to clicking the down arrow key.
*
* @return next command in the command history.
*/
private String getNextCommand() {
// At last parsed command in command history
if (index >= listOfCommands.size() - 1) {
logger.log(Level.INFO, "Returning current command");
index = listOfCommands.size();
return "";
}

logger.log(Level.INFO, "Returning next command");
String command = listOfCommands.get(index + 1);
index++;
return command;
}

/**
* Clears the command history.
*/
public void clearListOfCommands() {
this.listOfCommands.clear();
this.index = 0;
}
}
34 changes: 34 additions & 0 deletions src/main/java/seedu/address/ui/CommandBox.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.Region;
import seedu.address.logic.commands.CommandResult;
import seedu.address.logic.commands.exceptions.CommandException;
import seedu.address.logic.parser.exceptions.ParseException;
import seedu.address.storage.CommandHistory;

/**
* The UI component that is responsible for receiving user command inputs.
Expand All @@ -29,6 +32,7 @@ public CommandBox(CommandExecutor commandExecutor) {
this.commandExecutor = commandExecutor;
// calls #setStyleToDefault() whenever there is a change to the text of the command box.
commandTextField.textProperty().addListener((unused1, unused2, unused3) -> setStyleToDefault());
commandTextField.setOnKeyPressed(event -> handleKeyEvent(event));
}

/**
Expand All @@ -42,13 +46,43 @@ private void handleCommandEntered() {
}

try {
CommandHistory commandHistory = CommandHistory.getInstance();
commandHistory.addCommand(commandText);
commandExecutor.execute(commandText);
commandTextField.setText("");
} catch (CommandException | ParseException e) {
setStyleToIndicateCommandFailure();
}
}

/**
* Handles the event when a key is pressed.
*/
private void handleKeyEvent(KeyEvent event) {
KeyCode key = event.getCode();

if (!key.isArrowKey()) {
return;
}

handleArrowKeyPressed(key);
}

/**
* Handles the event when an arrow key is clicked from {@link #handleKeyEvent(KeyEvent)}.
*
* @param key keycode of the arrow key input.
*/
private void handleArrowKeyPressed(KeyCode key) {
if (!(key == KeyCode.UP || key == KeyCode.DOWN)) {
return;
}

CommandHistory commandHistory = CommandHistory.getInstance();
String commandToSet = commandHistory.getPastCommand(key);
commandTextField.setText(commandToSet);
}

/**
* Sets the command box style to use the default style.
*/
Expand Down
101 changes: 101 additions & 0 deletions src/test/java/seedu/address/storage/CommandHistoryTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package seedu.address.storage;

import static org.junit.jupiter.api.Assertions.assertEquals;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import javafx.scene.input.KeyCode;

public class CommandHistoryTest {
private static final String VALID_COMMAND = "github n/John Doe";
private static final String INVALID_COMMAND = "iloveoop";
private CommandHistory commandHistory = CommandHistory.getInstance();

@BeforeEach
public void setUp() {
// Resets command history
commandHistory.clearListOfCommands();
commandHistory = CommandHistory.getInstance();
}

@Test
void addCommand_nullStringCommand_success() {
commandHistory.addCommand(null);
}

@Test
public void getPastCommand_emptyListOfCommandsWithArrowKey_emptyStringReturned() {
assertEquals(commandHistory.getPastCommand(KeyCode.UP), "");
commandHistory.clearListOfCommands(); //reset list of commands
assertEquals(commandHistory.getPastCommand(KeyCode.DOWN), "");
}

@Test
public void getPastCommand_filledListOfCommandsWithUpArrowKey_commandReturned() {
commandHistory.addCommand(VALID_COMMAND);
commandHistory.addCommand(INVALID_COMMAND);

String firstReturnedCommand = commandHistory.getPastCommand(KeyCode.UP);
assertEquals(firstReturnedCommand, INVALID_COMMAND);

String secondReturnedCommand = commandHistory.getPastCommand(KeyCode.UP);
assertEquals(secondReturnedCommand, VALID_COMMAND);
}

/**
* Tests the edge case where the earliest command is always returned after sufficiently large number of UP arrow
* keys input.
*/
@Test
public void getPastCommand_earliestCommandEntered_commandReturned() {
// Adds two commands into the command history
commandHistory.addCommand(VALID_COMMAND);
commandHistory.addCommand(INVALID_COMMAND);

// Retrieves the first two commands
String firstReturnedCommand = commandHistory.getPastCommand(KeyCode.UP);
String secondReturnedCommand = commandHistory.getPastCommand(KeyCode.UP);

// Attempting the third command -> expected to get the same command as the second command
String thirdReturnedCommand = commandHistory.getPastCommand(KeyCode.UP);
assertEquals(secondReturnedCommand, thirdReturnedCommand);
}

@Test
public void getPastCommand_navigateToCurrentCommand_emptyStringReturned() {
commandHistory.addCommand(VALID_COMMAND);
commandHistory.addCommand(INVALID_COMMAND);

// Returns the last stored command in the command history.
commandHistory.getPastCommand(KeyCode.UP);

String currentCommand = commandHistory.getPastCommand(KeyCode.DOWN);
assertEquals(currentCommand, "");
}

@Test
public void getPastCommand_getCommandWithDownArrowKey_emptyStringReturned() {
commandHistory.addCommand(VALID_COMMAND);
commandHistory.addCommand(INVALID_COMMAND);

// Returns the 2 commands stored in the command history.
commandHistory.getPastCommand(KeyCode.UP);
commandHistory.getPastCommand(KeyCode.UP);

String lastCommandStored = commandHistory.getPastCommand(KeyCode.DOWN);
assertEquals(lastCommandStored, INVALID_COMMAND);
}


@Test
public void clearListOfCommands_emptyStringReturned() {
commandHistory.addCommand(VALID_COMMAND);
commandHistory.addCommand(INVALID_COMMAND);

commandHistory.clearListOfCommands();

String currentCommand = commandHistory.getPastCommand(KeyCode.UP);
assertEquals(currentCommand, "");
}
}

0 comments on commit 5592372

Please sign in to comment.