Two Gnus tricks

April 21, 2008 by jao

I’ve added a couple of tweaks to my Gnus config lately. Nothing earth-shattering, but in both cases i was writing my own elisp for something that was already in there. So, i’ve thought i’d share them and, maybe, save you the trouble.

The first one is a quickie, and you probably know about it; but for some reason it took me ages to discover the correct configuration knob. When you reply a mail, emacs will use the value of user-mail-address to compose the From: header. One can also tweak gnus-posting-styles to change the address on a per group basis. But what i really wanted was to use the address in the mail i was replying to. I was writing a hook to that effect when i found the variable to set to accomplish it: message-alternative-mails. Here’s how i set it up:

    (setq message-alternative-emails
        (regexp-opt '("jao@gnu.org" "jaortega@goodmail.com" "jao@member.fsf.org")))

Worked like a charm. Now for the second one.

As i’ve mentioned in some post before, Gnus let’s you customise the summary line to your heart’s content by tweaking the variable gnus-summary-line-format. I normally use emacs in a maximized urxvt terminal, so i’ve got plenty of room in my summary lines. One thing i wanted to add is the message’s date in a) my time zone and b) human readable form (you know, something like ‘Today, 22:33′ or ‘Yesterday, 02:44′). I only knew two format directives showing a date (%d and %D), but neither fulfilled my wishes. So i started coding my own, but halfway discovered that Gnus already comes with a custom one, called user-date. You use it by inserting %&user-date; in the line format string. It works in conjunction with a configuration stored in gnus-user-date-format-alist, which contains a lists of pairs. The first member of the pair is the age of the message, the second a time format string for displaying the date of messages that old. You’ll understand it better with an example, taken from my current configuration:

    (setq gnus-user-date-format-alist
          '(((gnus-seconds-today) . "Today, %H:%M")
            ((+ 86400 (gnus-seconds-today)) . "Yesterday, %H:%M")
            (604800 . "%A %H:%M") ;;that's one week
            ((gnus-seconds-month) . "%A %d")
            ((gnus-seconds-year) . "%B %d")
            (t . "%B %d '%y"))) ;;this one is used when no other does match

    (setq gnus-summary-line-format
      (concat "%U%R %~(pad-right 2)t%* %uj %B%~(max-right 30)~(pad-right 30)n  "
              "%~(max-right 90)~(pad-right 90)s %-135=%&user-date;\n"))

I’ve copied my whole line format so that you can see, in addition, how i manage to keep things aligned in a frame around 180 columns wide. For details on the %uj directive, see this previous post.

Numbered links in emacs-w3m

April 12, 2008 by jao

I’ve been trying conkeror as my secondary browser for a while, and i really like it. It has a much smaller memory footprint than Firefox, and it doesn’t take ages to start up. It’s also nicely hackable and extensible (using javascript), and it comes with some interesting functionality, available out of the box. For instance, external editor support or link numbering: pressing ‘f’ numbers all links in the page and you enter a link number to follow it.

As it happens, recent (as in CVS 1.4.4) versions of emacs-w3m offer a similar functionality in the w3m-lnum package. M-x w3m-link-numbering-mode toggles a minor mode showing link numbers on an overlay, and M-n M-x w3m-move-numbered-anchor, where n is the link number, moves the pointer to the desired link. Providing conkeror’s
more handy functionality is then a matter of a few elisp lines:

 
  (require 'w3m-lnum)
  (defun jao-w3m-go-to-linknum ()
    "Turn on link numbers and ask for one to go to."
    (interactive)
    (let ((active w3m-link-numbering-mode))
      (when (not active) (w3m-link-numbering-mode))
      (unwind-protect
          (w3m-move-numbered-anchor (read-number "Anchor number: "))
        (when (not active) (w3m-link-numbering-mode)))))

  (define-key w3m-mode-map "f" 'jao-w3m-go-to-linknum)

Happy browsing!

Map of Emacs Users

October 29, 2007 by jao

Add yourself to the Map of Emacs Users around the world… and leave a note with the emacsen version(s) you use, just for the fun of it! You can also take a look at Emacs google trends (or the Emacs vs. that other editor one), the EmacsUserLocations page or this Emacs Screenshots flickr group.

Gmail envy

October 7, 2007 by jao

Gmail markers Although Gnus is my primary mail reader, there’s lots of things i like about Gmail (actually, Gmail is my primary inbox: Gnus reads mail from there). For instance, a little feature i love in Gmail is those markers that tell you whether you’re one of the direct recipients of a mail. When seeing a long list of mails in a mail list, i can quickly identify those with me explicitly in the To: or Cc: headers: chances are i’m slightly more interested in them.

In Gnus, one can customize the information shown in the message list by tweaking the variable gnus-summary-line-format. If you press C-h v gnus-summary-line-format to see all the formatting options, you’ll see there’s a lot of information to be shown, but not the one we want. But, as is always the case, we have a hook to extend the format to our hearts content: the %uX directive, where X is any letter you want. When Gnus sees that directive, it calls gnus-user-format-function-X, a function you must write returning a string that gets inserted in the summary line. So here we go: first i define a string with a regexp of my email addresses:

(defvar *jao-mails*
        "jao@foo\\.org\\|jao@baz\\.com\\|jao@grogle\\.com")

and then i function which returns a “»” if i’m the only recipient of the message, or a “~” if i’m in the To:, Cc: or BCc: headers among others:

(defun gnus-user-format-function-j (headers)
  (let ((to (gnus-extra-header 'To headers)))
    (if (string-match *jao-mails* to)
        (if (string-match "," to) "~" "»")
        (if (or (string-match *jao-mails*
                              (gnus-extra-header 'Cc headers))
                (string-match *jao-mails*
                              (gnus-extra-header 'BCc headers)))
            "~"
            " "))))

Then all that is left is using it in my gnus-summary-line-format:

(setq
 gnus-summary-line-format
 "%U%R %~(pad-right 2)t%* %uj %B%~(max-right 20)~(pad-right 20)n %s\n")

Picture 2.pngNotice the %uj doing the trick here. I’m sure you’ll come up with other uses to this extension mechanism, which, by the way, is also available for gnus-group-line-format, the variable governing how lines in the *Group* buffer are displayed.

Smooth scrolling

September 10, 2007 by jao

A quick and sweet tip for one of those things surprisingly difficult to get right in emacs: buffer scrolling. If you find awkward the way emacs makes your buffers jump when you move the cursor near their begin or end, try putting this file in your load path and (require 'smooth-scrolling). You can control when scrolling starts by setting the variable smooth-scroll-margin: when the cursor is that far from the top or bottom borders, scrolling begins (default is 10 lines). Works like a charm here.

By the way, as Adam (the author of the code above) points out in the comments below, the problem is trickier than it seems. If you’re curious, this EmacsWiki page gives the details.

Quick keybindings

July 15, 2007 by jao

So, you just executed a complex, wonderful emacs command using the minibuffer and you’re so excited that need to immediately write it down, lest you forget. As you may already know, you don’t need pen and paper for that. Emacs will do it for you: just press C-x ESC ESC (that is, repeat-complex-command) and you’ll see an Elisp form in your minibuffer that reproduces your last command (C-h w C-x ESC ESC for more details). Now C-a C-k and you got it in the kill-ring, ready to be yanked in one of your configuration files.

I don’t use this trick that much because over the years more and more emacs automatisms are recorded either in my nervous system or my config files. Except for one thing: defining keybindings. There’re a bunch of ways to define a keybinding in emacs, and i’m never sure what’s the right one when there’re special keys involved. The solution is to define the key interactively with M-x global-set-key. Once i’m done, i play C-x ESC ESC and presto: an elisp snippet to yank in my .emacs appears in the minibuffer.

Happy binding!

Gnus and Google Groups

June 23, 2007 by jao

Eternal September notwithstanding, i have great daily fun reading a bunch of usenet groups, and their articles are sometimes a source of ideas for blogging. Of course, my usenet client is Gnus; but in a blog post one needs the Google Groups URL when mentioning and article. So, i just spent five minutes writing a snippet to go from Gnus to GG in a keystroke:

(defun jao-gnus-goto-google ()
  (interactive)
  (when (memq major-mode '(gnus-summary-mode gnus-article-mode))
    (when (eq major-mode 'gnus-article-mode)
      (gnus-article-show-summary))
    (let* ((article (gnus-summary-article-number))
           (header (gnus-summary-article-header article))
           (id (substring (mail-header-id header) 1 -1)))
      (browse-url
       (format "http://groups.google.com/groups?selm=%s" id)))))

As you see, i just check that i’m viewing a post, obtain the message identifier (trimming surrounding markup) and construct a query that looks up the corresponding GG article.

Talk about extensibility.

Tip of the Day

June 21, 2007 by jao

Although i don’t use it that much, i’ve had the following defun in my emacs config since i remember:

(defun totd ()
  (interactive)
  (with-output-to-temp-buffer "*Tip of the day*"
    (let* ((commands (loop for s being the symbols
                           when (commandp s) collect s))
           (command (nth (random (length commands)) commands)))
      (princ
       (concat "Your tip for the day is:\\n"
               "========================\\n\\n"
               (describe-function command)
               "\\n\\nInvoke with:\\n\\n"
               (with-temp-buffer
                 (where-is command t)
                 (buffer-string)))))))

(Actually, i’ve tracked it down to a gnu.emacs.help thread dated 2001).

I’m sure you’ve guessed what it does. One possible use is to put the invocation (totd) at the end of your .emacs; but, as i tend to have emacs open for days, if not weeks, in a row, i prefer to just bind it to a keyboard shortcut and press it when i’m idling or thinking of a new post. I can also press the shortcut repeatedly until the random chosen command interests me.

Another possibility (if you don’t find it annoying), is to set a timer to get a periodic tip of the day, using something along the lines of:

(defvar jao-totd-timer (run-at-time "12:00am" (* 3600 24) 'totd))
(defun jao-cancel-totd
  (interactive)
  (cancel-timer jao-totd-timer))

Not that bad as a pastime :-)

Emacsy OS X

June 15, 2007 by jao

mail-emacs.pngLet me tell you how Emacs is more and more taking the center stage in my MacBook. In a previous post i explained how i set up Gnus as my mail (and of course, news) reader: i like Gnus so much that it quickly became my default. And, just in case you didn’t know, Emacs can be OS X’s default mail handler too: just go to Mail’s general preferences pane and set it–it’s that easy. (In the image, i’m setting fink’s carbon emacs package, but you’ll see there too CarbonEmacs or Aquamacs if you have them installed.) With that setting in place, OS X will dutifully use Gnus whenever a mail handler is requested (e.g., when following mailto: URLs, or when using ‘Send this page…’ in Safari).

fast-scripts.pngUnlike Gnus, Emacs is not my default web browser, although i use w3m-el quite a bit (specially for technical manuals). So, every now and then i find myself seeing a page in Safari than i want to open in Emacs. Applescript to the rescue: fire up that ugly Script Editor and type this simple program:


property eclient : "/sw/bin/emacsclient -e "
tell application "Safari"
  set this_url to the URL of document 1
  do shell script eclient & \
          "'(w3m-browse-url \"" & this_url & "\")'"
	tell application "Emacs22" to activate
end tell

(changing the path to emacsclient and the name of your Emacs as needed). Of course, you’ll also need to start the Emacs server somewhere in your init files with (start-server), and to save the above script in ~/Library/Scripts/Applications/Safari. I’ve named it ‘Open in Emacs’, and it appears nicely as an entry in my FastScripts menu.

The last, and most interesting, bit is going in the opposite direction: accessing Safari (or any other Cocoa application, for that matter) from Emacs. Or, put in another one, executing AppleScript snippets within Emacs. One possibility is using Emacs’ shell-command in conjunction with OS X’s osascript, but there’s a sweeter way: the Elisp function do-applescript. For instance, the function jao-as-safari-doc below returns the URL and title of the active page in Safari:

 (defun jao-as-tell-app (app something)
   (let ((res (do-applescript (concat "tell application \""
                                      app "\" to " something))))
     ;; the string returned is quoted
     (substring res 1 -1)))

 (defun jao-as-safari-doc ()
   (interactive)
   (let ((url (jao-as-tell-app "Safari"
                               "get the URL of document 1"))
         (name (jao-as-tell-app "Safari"
                               "get the name of window 1")))
     (cons url name)))

This may seem a bit boring at first, but it can be put to good use: when i see a page worth taking a few notes, i open an org-mode buffer, and type a shortcut bound to the following function:

 (defun jao-org-insert-safari-link ()
   (interactive)
   (let ((l (jao-as-safari-doc)))
     (insert (org-make-link-string (car l) (cdr l)))
     (message "Link to %s inserted" (car l))))

and (minor) magic happens. I’m sure you can think of many other interesting uses of do-applescript, can’t you?

Emacs on the spotlight

June 15, 2007 by jao

I’ve been writing lately several snippets to improve the communication of Emacs with OS X. One of them is this quick and dirty mdfind mode that provides access, within an Emacs buffer, to the results of mdfind commands (the CLI to OS X’s Spotlight). Just put the above file somewhere in your load path, (require 'mdfind) in your init file and invoke M-x mdfind. You’ll be asked for a directory and a search string to perform in that directory. Under the rug, this shell command gets executed:

mdfind -onlyin directory query

The results (a file list) are collected in a special buffer in a new major mode (creatively dubbed mdfind-mode) that inherits from org-mode (this is Emacs 22; if you haven’t yet, take a look at org-mode: it is simply awesome), and that displays the files nicely fontified as links. See the comments at the beginning of mdfind.el for a list of available shortcuts that you can use to navigate and open (using OS X’s default handlers) the files in the list.

The functionality offered is right now limited and there’re many venues for improvement, so i guess i’ll keep adding features as i need them. But you’re encouraged to take this quick hack as an starting point to get the functionality that you deem important (and maybe share the results :-) ). Or, alternatively, to leave your suggestions in the comments section.

mdfind in action