December 2016

Emacs's default way to write a file to a different location is #'write-file. This function saves the buffer to a new location, but leaves the old file where it was. But sometimes we want to move a file, so the old file is gone!

There are two built-in functions with similar purpose.

  1. #'rename-file
  2. #'dired-do-rename

Neither of these are great for this use case. The existing functions don't default to the file from the current buffer, so you have to type the existing filename. After calling the function, we're left with a buffer that, when saved, saves to the old location. We don't have a buffer visiting the new file.

So we have to write something! We want something that takes the current buffer, prompts for a new file location, and moves the file there. We can't do the move atomically, so we instead delete the file only when the move was successful.

(defun move-file (new-location)
  "Write this file to NEW-LOCATION, and delete the old one."
  (interactive (list (expand-file-name
                      (if buffer-file-name
                          (read-file-name "Move file to: ")
                        (read-file-name "Move file to: "
                                        default-directory
                                        (expand-file-name (file-name-nondirectory (buffer-name))
                                                          default-directory))))))
  (when (file-exists-p new-location)
    (delete-file new-location))
  (let ((old-location (expand-file-name (buffer-file-name))))
    (message "old file is %s and new file is %s"
             old-location
             new-location)
    (write-file new-location t)
    (when (and old-location
               (file-exists-p new-location)
               (not (string-equal old-location new-location)))
      (delete-file old-location))))

The code that prompts for a new file location is taken from #'write-file, which we also use to move the file to that new location. We then delete the old file. Because we only delete the old file if it exists, it's safe to use this method even when the file was never originally saved.

You can bind it using bind-key:

(bind-key "C-x C-m" #'move-file)

And then have an easier time managing files in Emacs.

Thanks to u/tashbarg and Toby Cubitt for pointing out bugs in the initial implementation.