Tidying up for TEOS

As part of a general migration from darcs to git as my default SCM system (a migration whose reasons include magit being so much better than darcsum), i’ve been tidying up a bit my emacs configuration files and factoring out a small set of libraries that people may find useful.

The new git repository, clonable from http://git.hacks-galore.org/jao/emacs.git and browsable online here, contains a subdirectory called lib with the code i’ve factored out so far:

  • emms contains add-ons for the Emacs multimedia system, including OSD notifications, lyrics retrieval and a play-random-album facility.
  • net is a handbag of networkish utilites: mailbox query and display, emacs-w3m sessions and a weather info fetcher.
  • themes is my own color theme engine, implemented on top of the custom-themes package included in Emacs 23. Defining new color themes is, i think, short and sweet.
  • skels contains a collection of skeletons and related utilities that i use to insert templates in new files.
  • sys is a set of system utilities, most of them from my times as a Mac aficionado and, therefore, probably bit-rotten. Except for jao-osd, which gives you (very rudimentary) access to aosd notifications within emacs.
  • org contains an assortment of extensions for org-mode.
  • tracker is actually a C program that i use to query the tracker daemon that indexes all my documents. The actual queries are performed and displayed in emacs by an Anything extension of mine that i haven’t yet extracted from my configuration as a separate library, and that can be found there.
  • bmk is a (web) bookmark manager that i don’t use anymore (all my bookmarks are kept in org files these days).

There’s also a directory called external with other emacs packages that i use unmodified.

As i said, the idea is that the libraries above should be usable independently of my specific configuration bits, which are contained in the custom folder. The files in that folder will give you additional hints on how to customize the libraries.

With very few exceptions, all these packages are anything but well-documented, but perhaps you’ll find some bits useful. A long delayed project of mine is to use this blog to go through all of them in a series of posts that we could call TEOS, The Emacs Operating System. They would be not only about how the individual libraries work together, but, most importantly, about how they integrate with each other and with other stock Emacs packages to provide an operating environment that, in my humble opinion, surpasses any other commonly used operating system in terms of productivity and extensibility. An Elisp Machine where you are in control and have all the fun.

I’ve been playing with the idea of joining PragProWriMo and make this part of a book writing project that would explore in detail TEOS, with intermediate Emacs users in mind. If i finally go for it, you may consider this post as the first in the series, but i haven’t made up my mind yet.

Be it as it may, i hope you’ll find some elisp snippets above worth stealing for your own Emacs Operation System.

Gnus and Google Groups

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

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

(defun totd ()
  (interactive)
  (random t) ;; seed with time-of-day
  (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

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

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

Tab shuffling in emacs-w3m

Emacs-w3m comes with an excellent tab mode, which you can enable with (setq w3m-use-tab t) in your .emacs. C-cC-t creates new tabs, C-cC-w closes them and you can navigate then with C-cC-[np], or, my favourite, using a tab list via C-cC-s (if you didn’t know about this one, give it a try: it’s very useful).

But i quickly find myself with lots of open tabs that happen to be in the wrong order, and i wanted something akin to Firefox’s ability to move and reorder them around. I didn’t find a way change a tab’s position in a vanilla emacs-w3m, but it wasn’t that difficult to cook up my own solution. This function:

(defun jao-w3m-switch-buffers (dist)
    (interactive "p")
    (let* ((dist (if (zerop dist) 1 dist))
           (current (current-buffer))
           (current-no (w3m-buffer-number current))
           (next (progn (w3m-next-buffer dist)
  			(current-buffer)))
           (next-no (w3m-buffer-number next)))
      (with-current-buffer current
        (rename-buffer "*w3m*<*>")
        (w3m-buffer-set-number next current-no)
	(w3m-buffer-set-number current next-no)
        (w3m-pack-buffer-numbers))
      (switch-to-buffer current)))

switches the current tab with the one to its right (cyclically), or to the n-th to its right if you provide a numerical argument (e.g. M-3). I’ve got this function bound to C-cC-f:

(define-key w3m-mode-map (kbd "C-cC-f") 'jao-w3m-switch-buffers)

Alternatively, one could define a function that moves the current tab to the right a number of times. We can take advantage of the above function for a quick hack:

(defun jao-w3m-move-buffer (dist)
  (interactive "p")
  (let ((dist (if (zerop dist) 1 dist))
    (while (> dist 0)
      (jao-w3m-switch-buffers 1)
      (setq dist (1- dist)))))

and bind that to a shortcut of your choice. There you go: easy tab shuffling.

Eval and replace anywhere

Being a living Elisp virtual machine, Emacs naturally provides the ability to evaluate any Elisp expression anywhere. Just put the cursor right after the expression to be evaluated and press C-xC-e: the result appears in the mini-buffer. I use this continuously, for instance while reading about a variable to know its value. For instance, imagine i see this line in one of my files:

(setq planner-project "planner")

and want to know if planner-project has been modified. I just need to put my cursor right after the variable name and get its value with C-xC-e.

As i said, C-xC-e works in any (well, almost) buffer. Imagine you’re writing a note and need to perform an arithmetic operation: you could write something like

   Yesterday I spent (+ 2234.34 3423.4 (* 12.0 12.2) 10) dollars at ...

put the cursor just before ‘dollars’, press the eval shortcut, and see the result of the arithmetic operation in the mini-buffer. You memorize it, delete the Elisp expression… hmm, wait, this should be easier, shouldn’t it? What we want is Emacs to eval and replace the expression for us.

I’m sure that you already know what comes next :-) As it happens, this time i didn’t need to write the Elisp snippet myself: i stole it instead from Jorgen “forcer” Schäfer’s configuration file:

(defun fc-eval-and-replace ()
  "Replace the preceding sexp with its value."
  (interactive)
  (backward-kill-sexp)
  (prin1 (eval (read (current-kill 0)))
         (current-buffer)))

Complemented with the mandatory shortcut:

(global-set-key (kbd "C-c e") 'fc-eval-and-replace)

this little gem has probably the highest usefulness to lines of code ratio in my Elisp toolbox. Give it a try!

Update: pdq notes in a comment that, if the expression to be evaluated is malformed (like, say, (+1 1)) it gets deleted, and it would be nice if it wouldn’t. A quick way to get this functionality is to catch errors in eval and undo the killing in a generic error handler. To wit:

(defun fc-eval-and-replace ()
  "Replace the preceding sexp with its value."
  (interactive)
  (backward-kill-sexp)
  (condition-case nil
      (prin1 (eval (read (current-kill 0)))
             (current-buffer))
    (error (message "Invalid expression")
           (insert (current-kill 0)))))
Follow

Get every new post delivered to your Inbox.