2009-11-29

making buffer names unique

When you open a file in emacs, the buffer gets the name of that file. That's all fine, but what if you open multiple files with the same name? At least for me, it's a fairly common to have a number of different Makefile.am buffers Makefile.am<3> etc., but that does really help to find the right one at the same time. Emacs does make those names unique – Makefile.am<2>, quickly.

To do that, emacs provides uniquify – it makes buffer names unique. In your .emacs:

(require 'uniquify) 
(setq 
  uniquify-buffer-name-style 'post-forward
  uniquify-separator ":")

This is emacs, so you can influence the way in which the names are made unique. I prefer post-forward, and as separator I use a : rather than the default |. Note, instead of post-forward there are other bizarre styles, please see the documentation.

Anyway, now, when opening ('visiting') files test/a/foo and test/b/foo, their buffers get the names foo:a and foo:b. In other words, the name followed by a colon and part of the path. I think it's much clearer than the default names foo and foo<2>. One could ask why emacs should not use uniquify as its default behavior; it seems a clear improvement.

Uniquify is a small convenience that's been a documented part of emacs for 20 years. Still, somehow I missed it until this year. I suspect I am not the only one - which is why I write this.

2009-11-19

showing pop-ups

Updated: yes, it's %s, not %d Sometimes, it's nice when emacs can warn you when something is happening or should happen. For example, when a new e-mail has arrived, or when there's a meeting in 15 minutes you should attend.

As always, there are different way to do this, but here's what I've been using for while. Various versions of this have been circulating around mailing lists, so I don't know whom to credit with the original idea – anyway, this is the (modified) version that I'm using.

(defun djcb-popup (title msg &optional icon sound)
  "Show a popup if we're on X, or echo it otherwise; TITLE is the title
of the message, MSG is the context. Optionally, you can provide an ICON and
a sound to be played"

  (interactive)
  (when sound (shell-command
                (concat "mplayer -really-quiet " sound " 2> /dev/null")))
  (if (eq window-system 'x)
    (shell-command (concat "notify-send "

                     (if icon (concat "-i " icon) "")
                     " '" title "' '" msg "'"))
    ;; text only version

    (message (concat title ": " msg))))

A couple of notes:

  • I'm using notify-send for sending notifications; this assumes you are using that system (it's part of the libnotify-bin package in Debian/Ubuntu). You can of course replace it with whatever is available on your system. Alternatives are zenity or kdialog or xmessage (for old-timers) and their equivalents (?) on Windows, MacOS.
  • I'm now using mplayer for playing sounds. This is a bit heavy, but at least plays all kinds of audio files. If you only care about .wav-files, you could replace it with e.g. aplay;
  • as always, please ignore my ego-centric function names :-)

Now, we can use this function by evaluation e.g.

(djcb-popup "Warning" "The end is near"
   "/usr/share/icons/test.png" "/usr/share/sounds/beep.ogg")

showing pop-ups from org-mode appointments

The above popup function is most useful when it's does its work based on some event. To be notified of appointments and the like, there is the emacs appt facility. Here, we set up this appt, and then hook it up with org-mode, so appt can warn us when there's something happening soon…

;; the appointment notification facility
(setq
  appt-message-warning-time 15 ;; warn 15 min in advance

  appt-display-mode-line t     ;; show in the modeline
  appt-display-format 'window) ;; use our func
(appt-activate 1)              ;; active appt (appointment notification)
(display-time)                 ;; time display is required for this...

 ;; update appt each time agenda opened

(add-hook 'org-finalize-agenda-hook 'org-agenda-to-appt)

;; our little façade-function for djcb-popup
 (defun djcb-appt-display (min-to-app new-time msg)
    (djcb-popup (format "Appointment in %s minute(s)" min-to-app) msg 
      "/usr/share/icons/gnome/32x32/status/appointment-soon.png"

      "/usr/share/sounds/ubuntu/stereo/phone-incoming-call.ogg"))
  (setq appt-disp-window-function (function djcb-appt-display))

Of course, you can freely choose a icon / sound to your liking.

showing pop-ups for new mail

Another event you might want to be warned about is new mail. There is something to be set for not letting yourself be disturbed for new mail, but if you sufficiently filter your mails before they enter your inbox, it can be a good way to periodically bring you back from your deep sl ^H^H thinking. For Wanderlust, I use something like this:

(add-hook 'wl-biff-notify-hook
    (lambda()
      (djcb-popup "Wanderlust" "You have new mail!"
        "/usr/share/icons/gnome/32x32/status/mail-unread.png"
        "/usr/share/sounds/ubuntu/stereo/phone-incoming-call.ogg")))

Exercise for the reader: adapt this for your chosen mail client.

2009-11-12

copying lines without selecting them

When I'm programming, I often need to copy a line. Normally, this requires me to first select ('mark') the line I want to copy. That does not seem like a big deal, but when I'm in the 'flow' I want to avoid any little obstacle that can slow me down.

So, how can I copy the current line without selection? I found a nice trick by MacChan on EmacsWiki to accomplish this. It also adds ta function to kill (cut) the current line (similar to kill-line (C-k), but kills the whole line, not just from point (cursor) to the end.

The code below simply embellishes the normal functions with the functionality 'if nothing is selected, assume we mean the current line'. The key bindings stay the same (M-w, C-w).

To enable this, put the following in your .emacs:

(defadvice kill-ring-save (before slick-copy activate compile) "When called
  interactively with no active region, copy a single line instead."
  (interactive (if mark-active (list (region-beginning) (region-end)) (message
  "Copied line") (list (line-beginning-position) (line-beginning-position
  2)))))

(defadvice kill-region (before slick-cut activate compile)
  "When called interactively with no active region, kill a single line instead."
  (interactive
    (if mark-active (list (region-beginning) (region-end))
      (list (line-beginning-position)
        (line-beginning-position 2)))))

It also shows the power of Emacs-Lisp with the defadvice-macro – see the fine documentation. Using defadvice, you can 'decorate' any function with your own modifications. This great power should be used with caution, of course, as to not break other usage that assumes the undecorated versions. In this case, that seem unlikely. And note that the 'advise' only applies when the functions are called interactively.

2009-11-05

bookmarks

Emacs has a very useful system for bookmarks – shortcuts to often-used files. It's also one of those features I only really started using after years of emacs – there seem to be many of such obvious features…

Bookmarks are especially handy if you have long file names, or for examples the special file names for editing root-owned files discussed here before.

To start using bookmarks effectively, there are only a few important key bindings to memorize: C-x r m ('make') will create a new bookmark, defaulting to the current file. Then, you can jump to an existing bookmark with C-x r b ('bookmark') Finally, you can see the list of your bookmarks with C-x r l ('list').

There are a few customizations you can put in your .emacs:

(setq 
  bookmark-default-file "~/.emacs.d/bookmarks" ;; keep my ~/ clean
  bookmark-save-flag 1)                        ;; autosave each change)