I’ve been a fan of `fpp` (Facebook PathPicker) since I first heard about it. I had long been looking for something like this and had even considered writing it myself. Fortunately someone else spared me the work and did a much better job than I would have.
It’s no exaggeration to say that I use this utility every day at $work. In fact I use it many times per hour. It’s part of my normal workflow now. For example, I like to pipe the output of `git status` to `fpp` and then pick and choose some unit tests I’ve edited and then run them. I may need to do this many times over the course of a day. The problem is that `fpp` doesn’t have a proper built in history. Having to go through this process of picking through the output of a `git status` many times per day is a bit of a time sink. It’s still maybe faster than what I would have done before, but it feels like jumping through hoops. I want to be able to replay any command I’ve just run. It should be easy, right?
As it happens, there’s already a file which `fpp` creates after each run. It’s found in `~/.fpp/.fpp.sh` and it’s executable. So, my first attempt at solving this problem was to add a shell alias: `alias redo=‘sh ~/.fpp/.fpp.sh’`. This lets me re-run the _very last_ command which I’ve just run via `fpp`. I now have instant replay.
However, if I’ve used `fpp` for something else in the meantime, the results of that command replace whatever was in `~/.fpp/.fpp.sh`. I can’t magically get back to the penultimate command which I ran, since it’s now lost forever. After playing with this for a few hours, I realized that I really do need to be able to replay my entire history, since I want to be able to pick an arbitrary command and re-run it. Having to remember exactly what I did last before running `redo` was getting to be frustrating.
As part of the process, I found an open Github issue for `fpp` history. After I commented it on it, @pcottle made the following very helpful suggestion, which was to alias `fpp` and wrap it with my own history logic. That seemed like a good idea. So let’s look at what we have to work with.
On my machines, `~/.fpp/.fpp.sh` generally looks something like this, where the _second last_ line in the file contains the line which I want to re-execute. (There’s a blank line which starts the file, but my syntax highlighter seems to be stripping it away here).
I figured I could pretty easily grab this line from `~/.fpp/.fpp.sh` and log it to my own history file. I’d then add a little functionality to make it all easier to work with. I had thought about doing this in Perl, but just keeping everything in my `.bashrc` file felt like it was going to be the most portable solution. I didn’t want to have to do anything more complicated than updating and sourcing my dot files in order to get this to work.
The code which I came up with does the following:
- Appends the second last line of `~/.fpp/.fpp.sh` to my own history file every time `fpp` is run
- Adds a `–redo` flag, which execs the last line of the history file, when there are no accompanying arguments
- Adds a `–history` flag which will print the contents of this history file to the screen, with accompanying line numbers
- Execs an arbitrary line from the history file if `–redo` is supplied with a positive integer. (The integers correspond to the line numbers provided by `fpp –history`). So, `fpp –redo 10` execs line 10 from `fpp –history`. It’s a bit like `!10` to get to command 10 after running `history` in your shell.
- Execs an abitrary line from the history file (moving backwards) if `–redo` is supplied with a negative integer. ie `fpp –redo -1` execs the last line in the file. `fpp –redo -2` execs the second last line etc
I’m not by any stretch an expert in shell scripting, so I did a lot of searching on StackOverflow, copy/pasting and bugging my colleagues at $work. Eventually and quite happily I’ve come up with an incantation which suits my needs.
This is what I added to my `.bashrc`. Usage is contained inline, in the comments.
This will get out of date over time, so the canonical version should always be found in my dot-files repo.
If you’d like to see something like this built into `fpp` itself, it wouldn’t hurt to bump the issue I mentioned above. I hope someone finds this helpful.