File Management in Emacs with dired-mode
IMPORTANT NOTES
Dired is Big
dired
has turned out to be a far, FAR bigger thing to learn than I had anticipated.
That, coupled with the fact that my writing time vanished in the fires of the last week of school means I did not fully explore dired
and will be returning to it later.
Consider this merely an introduction to the very basics.
I will be returning to this again in the future.
I use evil-collection
All the keybindings I describe below are true on my system after installing evil-collection
.
If you are running pure Emacs, these keybindings will not work.
In fact, some of them may do surprising things (I don't know, I used dired
like three times before I installed evil-collection
and two of them were by accident).
I recommend using this reference card from the GNU website to find the keybindings which match with what I am describing.
Cost of Context Switches
As a teacher, I deal with context switches all day, and they are easily one of the biggest drains on my productivity. What is a context switch? Put simply, a context switch is when you have to change from one task, environment, or context to another.
Whether you're talking about software or wetware, there is a penalty to context switches. For a computer, this can be reduced through well-written software or by throwing more hardware at the problem. But for your brain, there is a fairly hard floor to how small you can make that penalty.
I'm pretty good at context switches because I have to be. My classes take a blended learning approach to delivering the content, my student progress through the curriculum at different paces. In a typical class of 15-20 students, I might have 10 different problems that the students might be working on.
Each of those problems is a computer program that I have to read, comprehend, and mentally check for bugs and syntax errors before I can give that student meaningful feedback on their work.
If the student has encountered a fairly obscure bug, it can take me a bit of time to get a feel for what is happening.
It's even worse if the student has written some tangled or misnamed code (For the love of all that is holy, kids, stop naming your functions MyFunction
).
There's no way for me to avoid the constant context switching in class (even if I tried to make them all complete the programs at the same time, they would use write pretty divergent solutions to some of them), but I do all I can to avoid it in other areas of my life.
There are lots of techniques for doing this, but one of them is to keep a consistent interface for the tasks which you are doing. One of the goals of this Year of Emacs project is to complete as many of my daily tasks as possible inside Emacs to see whether or not the adoption cost of using Emacs for that task is less than the cost of context switching out of Emacs to complete it.
End of Year Cleanup
Right now, I'm in year-end cleanup mode. Notes from old classes need to be archived, plans for next year need to be started, and some files and folders need to be copied over. This is typically a lot of working with Finder. That involves a lot of working with the mouse. And mousing is one of the most expensive operations in terms of context switching for a touch typist. This high cost is because you lose your place on the home row. While each individual interaction with the mouse may not seem like much, it can end up happening a lot, which adds up quickly over time.
Working from the command line is possible, and I've done it before. But there is an interface issue there also because it isn't typically interactive. I want to move a few files, and then see the new directory listing right away. With the terminal, that's an extra command.
Furthermore, if you're working with a particularly full directory, ls
is not a very efficient way of viewing the file listing.
For example, the dired
buffer with my Google drive folder (synced specifically so I can use dired
to manage my Google Drive Files) had 123 lines.
Try working with that in a terminal, at best you'll be seeing half the files at a time when you start out.
That number might go down relatively quickly, but it's still more commands that you have to type in.
Basics using evil-collection
One of the first challenges I had was that dired
doesn't use Evil keybindings, even if you've installed evil-mode.
I know a lot of people reading this will probably say I should just learn the Emacs keybindings.
Sorry, that's not going to happen.
Vim is instinctive for me at this point.
When I see a text buffer, my first instinct is to j
or k
my way through the lines.
It's so ingrained, I do it in text buffers where I have never had Vim keys.
More than once, I have been typing while talking to a student and looked at my screen to see that the last line of my Google Doc had something like 5bctnJavaScript$
at the end.
This will be even more true in Emacs, where every other buffer I interact with right now (except Magit buffers) use Vim keys.
So I need dired
buffers to have Vim keys if I'm going to use them: enter evil-collection
.
Evil-collection is a collection of keybindings for major modes that mimic (to a degree) Vim keybindings.
While I could definitely roll my own keybindings using the :bind
feature in use-package
, it is actually pretty difficult to create consistent, memorable, and ergonomic keybindings.
I like that there are already bindings I can use, which means I don't have to try to make up my own.
Having said that, I one of the larger projects I plan on tackling over the summer is using hydra
to replace evil-leader
and use that to replace some of the multi-key chords needed in things like org-mode (C-c C-v t
, I'm looking at you).
Here is the setup for evil-collection
.
(use-package evil-collection :after (evil) :config (setq evil-collection-mode-list '(dired)) (evil-collection-init))
A couple of things to note here for people new to use-package
.
- Notice the use of
:after (evil)
. This script will not loadevil-collection
untilevil
has been loaded. Because that is a list, you can add additional modes to it. For example, if I was using the bindings forelpy
, I might make that:after (evil elpy)
to ensure that theelpy
package was available before the bindings for it were created. :config
is code that is run after the package is loaded.:init
is code that is run before the package is loaded. I initially tried to use:custom
here, but it didn't initialize the value correctly. I'm not sure why that was, as I was given to understand that:custom
was designed to set variables needed by the package.
evil-collection-mode-list
is a list containing the modes in which you want the evil-collection bindings.
It defaults to all of the modes.
Because I want to explicitly explore the bindings rather than just using them blindly, I am setting this variable explicitly and adding modes as I need them.
It's possible that I won't like the bindings for some modes.
I might also choose to roll hydras for some of them rather than using the evil-collection
bindings.
In all cases, I want to have control over what is set and what is not set in my Emacs setup.
Using dired
Configuration
While most new Emacsers assume that use-package
is meant to install packages, it's actually meant to manage packages.
What's the difference, you say?
Well, dired
is already installed in your Emacs, but you can still use use-package
to set up dired
.
Here is the setup I'm currently using.
(use-package dired :ensure nil :config (when (string= system-type "darwin") (setq dired-use-ls-dired t insert-directory-program "/usr/local/bin/gls")) :custom (dired-listing-switches "-aBhl --group-directories-first"))
One important note here is the :ensure nil
at the top.
I have use-package-always-ensure
set to t
at the beginning of my Emacs.org.
This means every package has :ensure t
by default.
Ensure means (roughly) "This must be downloaded, find it from one of the package repositories."
But dired
isn't on the package repositories, it's built-in.
So we need to set ensure
to nil
for this package.
Finally, we use the dired-listing-switches
to pass a different set of switches to ls
than the defaults.
You can set this to whatever you like, the ones I've included here will do the following: List all entries, directories first, except backup files (those ending in ~
), using the long listing format and human readable sizes.
Play around on the command line until you get something you like, and then set your dired-listing-switches
to that.
Mac OS Users
As noted above, dired
uses the ls
command if possible to generate the directory listing.
But Apple is using a non-GNU set of core-utils
.
That means that the listing switches for dired
won't work correctly without telling it where to find a GNU version of the core-utils
.
To begin, run brew install core-utils
(Or the equivalent command on your package manager of choice).
Now, you need to tell Emacs where to find those core-utils
, but only when running Mac OS.
That's what the when
command in the listing above does.
Entering dired-mode
The way I usually get into dired-mode
is through the find-file command.
As noted in my Emacs.org file, that is bound to <SPC> e
on my system.
Once there, if you select the top-most entry (/path/to/current/directory/.
), you will open that directory in dired-mode
.
You can also open dired-mode
directly using C-x d
and then supplying a directory path (using helm).
Using dired-mode
Once in dired-mode
, I can use the j
and k
keys to navigate up and down.
While there are searching functions, I did not need them for what I was working on because I need to inspect pretty much every file as part of my end of year cleanup.
Once your cursor is on the line for a given file, you can press <RET>
to open that buffer in the dired window.
Because I'm working with the directory, I generally want to open it in the other window so I can keep my dired buffer open.
For that, simply press S-<RET>
.
But the real power of dired-mode
is not in opening files, it is in changing the directory structure.
To do this, you first mark the files or directories you wish to operate on.
If you want to delete the files, you can simply mark them with d
, which will mark them for deletion.
After you have flagged them for deletion, pressing x
will delete them.
Alternatively, pressing m
while in dired mode will mark the file or directory for any action.
This is what I usually do.
After you have marked the files you wish to act on, pressing D
or will delete them.
Or, you can use R
to rename them (this runs the mv
command, so it can also be used to move them to another directory).
I think the benefits of m
over d
are twofold.
First, you only have to remember a single, mnemonic command.
Sure d
makes sense for delete, but it doesn't actually delete the files.
It only marks them for deletion.
m
for mark is a better mnemonic than d
for mark for deletion.
Secondly, I like that the commands to operate on marked files are all uppercase. This is a solid reminder that you're about to do something. It separates and distinguishes potentially destructive actions from generally harmless ones.
You can use ^
to move up a directory, and <RET>
on a sub-directory will open that directory in its own dired buffer.
You can also create new directories with +
.
Once you are finished, you can then simply close the dired buffer with q
.
Final Thoughts
Dired really surprised me with how useful it is. I was certain that it would be useful, but it surprised me how quickly it surpassed the tools I had been using previously. In previous years, this process has taken me a week of 2-3 sessions a day, 1-2 hours per session. Much of that was the delay inherent in using a website (Google Drive, in this case), a lot of it is having to use the mouse, but whatever the reason, it was time consuming at a time of the year when I don't really have a lot of extra time.
This time, I was able to complete this over the course of about 5 hours.
That includes the time I spent configuring and learning dired
.
My experience has typically been that any tool this useful (4x faster, give or take) takes a similarly long time to learn.
I will be the first to say that I have not learned everything there is to do with directories in Emacs.
I have not touched dired-x
, wdired
, dired-aux
, or any of the 3rd party packages that supplement dired
.
I have barely touched searching in a directory.
I have only used 3 of the actions available (create directory, delete, rename).
I have only used 1 of the means of marking.
Future Expansions
There is now a way to get Google Drive directly in Emacs via GVFS
.
I haven't played with it because, well, I'm tired of fighting with my Mac right now and installing GVFS
purports to be easy, but my experience has been that this is rarely as true as is implied.
This would allow me to work with the Google Drive file structure via Emacs (with Tramp).
This will worth together with pullover, which has the tagline "Texting while driving (other apps) is dangerous. Let's pull over there to edit the text in Emacs instead!"
That sounds amazing. If it actually works, I hold to combine that with emacsclient and org-protocol to move even more things into Emacs. If anybody has worked on this and gotten it working, please let me know!