Speeding Up History

Some of us live on the command line. And for us, sometimes 'history' is our favorite command, allowing us to repeat a command we use all the time. Entering "history"(or our favorite shortened alias) then "!event#" we almost do in our sleep.

However, even with this, don't we always want it to be a little faster? Here is a quick and dirty utility(with room for growth). It gives you your history in a pageable format and then it's 1 quick keystroke to reexecute that command you need in a hurry.

Here is a tool for speeding up repeating commands: https://youtu.be/gSCqWIefzU0

Available on GitHub: GitHub - AndrewOfC/hcommander · GitHub

My Linux Bash terminal has the command CTRL R for this, which is some fuzzy search in command history. E.g. if I want to repeat a scp copy operation with a long path, I press CTRL R followed by "scp" and get the last command containing the letters scp. Further input of CTRL R gives other matching command. This works for other parts of a command, e.g. a filename, as well.

And as you posted it under "code review":
I wonder if your code is optimal for

    // delete duplicate commands, preserving most recent
    let mut seen : HashSet<String> = HashSet::new();
    let mut indices_to_delete : Vec<usize> = Vec::new();
    for (index, command) in commands.iter().enumerate() {
        if seen.contains(command) {
            indices_to_delete.insert(0, index);
        }
        seen.insert(command.clone());
    }

    // indices are in reverse order, so they remain valid
    // as they are deleted 'back to front'
    // i.e. delete i+1 keeps index i valid
    for index in indices_to_delete {
        commands.remove(index);
    }

I assume you want to preserve order in the returned Vec, so using a HashSet instead as return value would be no solution? Does Rust has a HashSet that preserves insertion order? Your remove operation should generate a larger move of all entries for each loop iteration. Perhaps just replace all the duplicates in the original vector with an empty string, and finally call a Rust method like keep_if() for all entries that are not empty strings. That should be a bit more efficient.

[EDIT] keep_if() is actually called retain() in Rust :slight_smile:

And you have quite a lot of code just to display the list of history commands and to capture the one character user input, e.g. that sleep() call. My feeling is, that a TUI library could simplify this task -- is there nothing available in Rust?