Wednesday, March 19, 2008

Beat the Save Habit

It only takes one unfortunate program crash where you lose a lot of work to teach you the importance of saving often. I use emacs most of the time, and I had developed a nearly subconscious, paranoid habit of hitting c-x c-s every 5 seconds or so while working. I was starting to catch myself before hitting that save-buffer shortcut even when I was typing in other applications: instant messenging, web page forms, you name it. Meanwhile, I also started noticing applications that didn't require me to tell them to save my precious work. Gmail and blogger come to mind right a way. "Why couldn't emacs do the same?" I wondered. After hashing it out in that blog entry and on the emacs wiki, I added the following to my .emacs file, and I am happy to report that my twitch is gone:


(defun save-buffer-if-visiting-file (&optional args)
  "Save the current buffer only if it is visiting a file"
  (interactive)
  (if (buffer-file-name)
      (save-buffer args)))

;; This causes files that I'm editing to be saved automatically by the
;; emacs auto-save functionality.  I'm hoping to break myself of the
;; c-x c-s twitch.
(add-hook 'auto-save-hook 'save-buffer-if-visiting-file)

;; save every 20 characters typed (this is the minimum)
(setq auto-save-interval 20)

;; save after 1 second of idle time (default is 30)
(setq auto-save-timeout 1)

Now emacs automatically saves my work for me, without me having to ask, and I love it. It makes me a little nervous when I'm working on a file that's not under revision control, but with modern revision control being so easy to set up and use1, that is happening less and less.

If you see any way to improve this, or if you just want to tell me why it's dumb, please comment. My emacs lisp skil1z are pretty feeble.

1 Just type hg init, bzr init, or git init in the directory where the file lives and you are up and running.

7 comments:

Anonymous said...

I believe there is an easier way to do this:
,----[ (info "(emacs)Auto Save Files") ]
|
| If you want auto-saving to be done in the visited file rather than
| in a separate auto-save file, set the variable
| `auto-save-visited-file-name' to a non-`nil' value. In this mode,
| there is no real difference between auto-saving and explicit saving.
`----

Bryan said...

Yes, I read the same thing and thought the same thing. You have to try it though. With that setup, once auto-save saves your work in the file the buffer is considered out of date and you can't continue editing without emacs continually asking you if you are sure you want to edit a buffer that isn't in sync with its file. Very very annoying.

Phil said...

Extra credit: increase the auto-save interval when on battery power to allow the hard disk's spinning down to actually save power.

Bryan said...

Ha! That's one I hadn't thought about. I'm on a desktop at work most of the time, and and besides, my laptop doesn't have a spinning hard drive ;-)

Does auto-save cause the disk to spin up every time it checks whether the file needs to be saved? I doubt that. If you are sitting there thinking and not typing, the auto-save interval shouldn't matter much.

Does auto-save cause the disk to spin up every time it saves? Probably not every time, there's all kinds of caching going on in RAM and in the hard drive device itself.

So, I'd be surprised if the auto-save interval will affect your battery time that much. Someone will have to try it to be sure though.


That being said, I wouldn't mind seeing what the emacs lisp that determines whether you are on battery power looks like ;-)

Yoni Rabkin said...

That is exactly the right idea. "save" is something that should have never been introduced into personal computing. Your operating system should smoothly track everything you do.

grant rettke said...

Awesome

Jason said...

Here's a variation that does it only for files that are actually under version control. I'd be totally paranoid about automatically saving files like this on files where I don't have access to older versions.

;; Save files automatically if they're under version control
(defun save-buffer-if-visiting-vc-file (&optional args)
"Save the current buffer only if it is visiting a file and the
file is under version control"
(interactive)
(if (vc-backend (buffer-file-name))
(save-buffer args)))