DEV Community

Jeremy Friesen for The DEV Team

Posted on • Originally published at takeonrules.com on

Emacs Packages to Get Stuff Done

Recording and Replaying Keystrokes

, I was working on the Forem codebase. Part of the toolchain at Forem is that we run Rubocop auto-correct on any files we commit.
We use Husky to manage our pre-commit hook.

With auto-correction, we sometimes might get a surprise change.
To avoid that surprise change, when we our linters, we try to remember to run the linters against the entire repository. That is not always something we do.

And I got one of those surprises. I wrote a pull request that helped avoid future sneaky auto-corrects.

But I want to write about what I did via Emacs and the command line.

The Steps in the Process

I took the following steps:

  1. Run Rubocop Auto-Correct.
  2. Run Rspec on a Directory.
  3. Use Emacs to Quickly Remove the Specs.

Run Rubocop Auto Correct

Rubocop—a Ruby code style checking and code formatting tool— has numerous “cops” that each check the code for one conceptual thing.

You can run Rubocop on a subdirectory and specifying a single “cop” to run. Below is the “cop” I ran on the app/models directory, I specified to auto-correct any offenses:

$ rubocop app/models \
  --only "Rails/RedundantPresenceValidationOnBelongsTo" \
  --auto-correct
Enter fullscreen mode Exit fullscreen mode

There output was as follows:

102 files inspected, \
27 offenses detected, \
27 offenses auto-correctable
Enter fullscreen mode Exit fullscreen mode

With the --auto-correct switch, the above call to rubocop changed the code.

Run RSpec on a Directory

At Forem, we use RSpec. With rubocop changing the models, I wanted to see how this impacted their specs.

$ rspec spec/models
Enter fullscreen mode Exit fullscreen mode

There were 22 failures, which is less than the number of auto-corrects. Looking at the failures they all had the following form:

Failure/Error: it { is_expected.to validate_presence_of(:author_id) }
Enter fullscreen mode Exit fullscreen mode

Excellent, these appear to all be consistent in structure.
There were two of the form it { is_expected.to validate_presence_of(:relation) }. I found those when I re-ran the specs. And I quickly remediated them by hand.

Use Emacs to Quickly Remove the Specs

I ran the following commands:

consult-ripgrep
Limiting to files in spec/models, I search for validate_presence_of _id). My consult-ripgrep configuration uses fuzzy finding. In essence, my find will look for lines that have both validate_presence_of and _id) in the same line.
embark-export
Export the search results to a new buffer.
kmacro-start-macro
I recorded, by typing, the following key sequence RET 2*C-k C-d M-o n, more on that later.
kmacro-end-macro
End the recording of the macro.
kmacro-call-macro 21 times
Run the just recorded macro 21 times (one for each of the remaining specs to adjust).
M-x save-some-buffers
Write the changes made in the embark buffer to their corresponding files.

For purposes of explaining what’s happening, I said I called kmacro-start-macro, kmacro-end-macro, and kmacro-call-macro. That’s not quite true, I used kmacro-start-macro-or-insert-counter and kmacro-end-or-call-macro. Those are mapped (by default?) to F3 and F4. But from a writing and explaining standpoint, the underlying functions make a bit more sense.

The Keyboard Sequence

The key sequence for kmacro-start-macro assumes:

  • I’m starting in the search results buffer.
  • I have two windows open, one for the search result buffer and one for “work”.

Below, I write about the key macro and what it does:

RET
Open the source file and line for selected search result.
Ctrl + k twice
Delete to the end of line and delete that now blank line. See jnf/kill-line-or-region for more details.
Ctrl + d
Delete the leading blank space.
Alt + o
Jump back to the search result buffer. See ace-window for more details.
n
Move to the next line in the search results buffer.

While recording keyboard macro, I could see what I was changing. I took my time to type and think what I wanted to do.

I recorded the macro, felt comfortable with it, and told Emacs to run it 21 more times.
I could have instead mashed on the F4 key twenty one (21) times.

Conclusion

First, I did all of this from a clean git repository state. This allowed me to make potentially sweeping changes with confidence of being able to revert.

I often use Embark’s embark-export; creating a buffer with a list of candidates. I can interact with the candidates, save the buffer for later, or further narrow those candidates with a different command.

What’s the list of candidates? In the above example, it’s search results. But it can be more than that.
I often pair embark-export with wgrep. Wgrep allows you to edit a grep buffer and apply those changes to the file buffer like sed interactively. Wgrep’s functionality is now a must have for my text editor.

It took me over a year of using Emacs to even start recording and using keyboard macros.
In I wrote Principles of My Text Editor.

Nowadays, I’m usually recording a disposable macro every other day. The more I use Emacs the more I learn and adjust how I can tell Emacs to do more work for me.

Top comments (2)

Collapse
 
katafrakt profile image
Paweł Świątkowski • Edited

Oh, so there's two of us using Emacs for Ruby development :D

Collapse
 
jeremyf profile image
Jeremy Friesen

There are several more that I know of (in particular software developers at research libraries).

I just wish I would have started earlier using Emacs (like in 2005 when a friend recommended it)