Archive for September, 2009

Slime-Clojure Setup

Monday, September 7th, 2009

It’s been a while since I blogged about Clojure, since I’ve been pretty busy and haven’t had as much time as I would like to play with it. Before I ran out of time, however, there were a few blog posts I had been planning to write, so I think it’s time to get around to finishing those up. There are three( right now) in total; This one, which is about setting up Slime, One about the test-is framework, and a review of Programming Clojure.

If you’ve done any Lisp programming at all, you’ve probably heard of Slime. Slime is an Emacs module that communicates with Lisp processes and acts as a Repl. It allows you to evaluate expressions in other buffers using the intepreter Slime is running, as well as a bunch of other really cool stuff that I haven’t delved into much. I mostly just use it as a Repl; even just having a repl and having C-x C-e work for non-elisp stuff is quite nice.

To setup Slime to work with clojure, I have the following in addition to the clojure customizations I described here:

(add-to-list 'swank-clojure-extra-classpaths "/home/nflath/.emacs.d/clojure-contrib/clojure-contrib.jar")
(add-to-list 'swank-clojure-extra-classpaths "/home/nflath/.emacs.d/clojure/")
(setq slime-repl-history-file "~/.emacs.d/.slime-history.eld")
(setq swank-clojure-jar-path "/home/nflath/repos-staging/.emacs.d/clojure/clojure-1.1.0-alpha-SNAPSHOT.jar")
(slime)

Going over this now, I see some of the Slime setup went into the segment I posted about, so to be clear the full setup you should have for both clojure and slime is:

(setq clojure-src-root "/home/nflath/.emacs.d")
(require 'clojure-mode)
(add-to-list 'auto-mode-alist '("\\.clj$" . clojure-mode))
(setq swank-clojure-extra-classpaths '())
(add-to-list 'swank-clojure-extra-classpaths "/home/nflath/.emacs.d/clojure-contrib/clojure-contrib.jar")
(add-to-list 'swank-clojure-extra-classpaths "/home/nflath/.emacs.d/clojure/")
(setq slime-repl-history-file "~/.emacs.d/.slime-history.eld")
(setq swank-clojure-jar-path "/home/nflath/repos-staging/.emacs.d/clojure/clojure-1.1.0-alpha-SNAPSHOT.jar")
(clojure-slime-config)
(slime)

These lines essentially setup the classpath Slime will use to look for Java and clojure classes, as well as the location of Clojure itself. You will need to modify these path values in order for them to work on your machine, but it should be fairly easy to figure out where the paths should point. The last line, (slime), will just start the slime interpreter. I’m a big fan of doing things when starting emacs, since I do it so infrequently.

I also use the ’show’ function described here when programming in Clojure. What it does is it displays the methods for the object under point. While this can often be too much info, since Object provides a lot of methods you probably don’t want, it is fairly nice. To do this, I have the following in my user.clj:

(use 'clojure.contrib.repl-utils)

Which will automatically load the repl-utils library that comes with clojure-contrib if user.clj is in slime’s classpath. You should browse through all the functions in this library, actually; it has some great functions for use in the repl. One function especially that we are interested in is show, which displays all the methods that could be called on an object. To integrate this into your Emacs session outside of the slime repl, add this function to your initialization file:

(defun slime-java-describe (symbol-name)
  "Get details on Java class/instance at point."
  (interactive (list (slime-read-symbol-name "Java Class/instance: ")))
  (when (not symbol-name)
    (error "No symbol given"))
  (save-excursion
    (set-buffer (slime-output-buffer))
    (unless (eq (current-buffer) (window-buffer))
      (pop-to-buffer (current-buffer) t))
    (goto-char (point-max))
    (insert (concat "(show " symbol-name ")"))
    (when symbol-name
      (slime-repl-return)
      (other-window 1))))
 
(define-key slime-mode-map (kbd "C-c d") 'slime-java-describe)
(define-key slime-repl-mode-map (kbd "C-c d") 'slime-java-describe)

Now, in your Clojure buffers, C-c d will pop up the slime buffer in another window and display the results of calling show on the thing under point. It doesn’t work as well in the Slime Repl buffer itself, but that’s a limitation I’m willing to live with. Another macro I like in the repl-utils package is source, which will display the source of any built-in function or macro. This allows you to learn a huge amount about idiomatic clojure code by examining the code that makes up clojure itself.

A few notes about the above setup: I have found the slime-clojure connection to be extremely dependent on the ordering in which you load packages. Slime must be started before clojure-test.el is required, or else you won’t be able to use a Slime REPL. The same is true for requiring slime: don’t do it. I don’t know why these cause massive issues, and they shouldn’t, but unfortunately they do. If you encounter any problems, it’s probably due to the order of statements in your initialization file.

That’s all the Slime and Clojure setup I have right now; I’ll no doubt add more as I keep using Clojure. If there are any good Slime customizations you have, please share them in the comments: I love adding new things to my emacs repertoire.

Dirtrack-mode

Saturday, September 5th, 2009

Emacs has two main ways of changing the default directory when in shell-mode. The first, default method is shell-dirtrack-mode. This mode keeps track of commands such as ‘cd’ that change the working directory of the prompt. This, however, runs into problems with commands it doesn’t recognize, for example because you aliased a command to move to a popular directory.

The other mode is dirtrack-mode, which changes the default directory of the shell buffer based on the prompt. This does require you to have the working directory in your prompt, but a) I like having it and b) if you really want, you can strip it out using hooks.

Dir track-mode is built into GNU Emacs, so you don’t have to download anything special. You do have to customize a regexp to conform to the prompt you want(or change your prompt to conform to the regex). For me, my shell prompts are of the form: username@hostname:path/to/file$ , so I ended up with the following value:

(setq-default dirtrack-list '("^[^@]*@\\([^:]*:[^$].*\\)\\$" 1))

The group used to determine the path, in this case, is hostname:path/to/file. This allows me to have dirtrack-mode work when I ssh into other computers, as long as I configure their prompt to follow this format. This does require me to have the machine I consider ‘local’ to have a ‘hostname’ of ‘/’, but in the following section I’ll show how to get this to work correctly no matter what computer you are using. It took me a long time to figure out how to get tab-complition work in shell-mode when I was sshe’d into another computer. To set your prompt to this value, put the following line in your .bashrc:

export PS1="username@hostname:\w$ "

I like to have my shell buffers contain the directory name in them, so I use the following hook. This causes the shell buffer’s name to change whenever dirtrack changes. It ended up being fairly complicated, as I wanted to be able to have more than one shell buffer open in the same directory without things breaking:

(add-hook 'dirtrack-directory-change-hook
          (lambda ()
            (let ((base-buffer-name (concat "shell-" default-directory "-shell"))
                  (i 1)
                  (full-buffer-name base-buffer-name))
              (while (get-buffer full-buffer-name)
                (setq i (1+ i))
                (setq full-buffer-name (concat base-buffer-name "<" (number-to-string i) ">")))
              (rename-buffer full-buffer-name))))

We have only two things left to do: turn on dirtrack mode, and set the prompt to contain ‘/’ instead of the hostname on the local comuter. The following advice first turns off shell-dirtrack-mode, changes the prompt, and then turns on dirtrack mode. You want to do things in this order, because otherwise dirtrack-mode will try and use the actual ‘localhost’ value, which may confuse tramp.

(add-hook 'shell-mode-hook
          (lambda ()
            (shell-dirtrack-mode -1)
            (insert "export PS1=\"nflath@/:\\w$ \"")
            (comint-send-input)
            (dirtrack-mode 1)
            ))

Whenever a shell buffer is opened, shell-dirtrack-mode is turned off. Then, we send the command that will change the prompt and execute it, and then finally turn on dirtrack mode.

Web Browsing in Emacs

Wednesday, September 2nd, 2009

About a week ago, I was using emacs on a remote computer with only a terminal. I was doing some java coding, and attempted to use java-describe to pull up some javadoc. Of course, since I usually use Firefox for url-browsing, this failed. This prompted me to re-install emacs-w3m, to be used in situations where Firefox was unavailable. I tried emacs-w3m for generalized browsing a while ago, but found it insufficient; it’s a bit slow(although faster than w3), doesn’t support javascript, and is a log uglier. However, it’s better than nothing. You do need w3m to use emacs-w3m; it’s faster than w3 mainly because it is the w3m process that does most of the work.

Installing emacs-w3m is pretty easy: I followed the instructions here to check out the sources from CVS and added them to my load-path. This, as well as the customizations in this blog, were enough to get it set up. As a note: all of the customizations here came from this emacs-wiki page or a page it links to; you may want to see if there is anything else that you’d like on those pages. If you don’t already have the w3m browser, you’ll need to install it. On Ubuntu, you can just do ’sudo apt-get install w3m’.

(setq w3m-session-file "~/.emacs.d/.w3m-session")
(setq w3m-session-autosave t)
(setq w3m-session-load-last-sessions t)
(setq w3m-use-cookies t)
(setq browse-url-browser-function 'w3m-browse-url)
(setq browse-url-new-window-flag t)nn

These are all the variables used for customizing w3m that I used. The first three auto-save my w3m sessions; if I close emacs while having w3m buffers opened, the next time I open emacs on that computer the buffers should re-open, much like how save-visisted-files opens all the files that were opened previously. I also allow w3m to use cookies so I can log into sites like gmail and facebook if I end up wanting to do that.

(require 'w3m)
(require 'w3m-session)
(require 'w3m-cookie)

These are the three w3m libraries that I require. w3m is just for standard browing functionality, w3m-session is for the session-saving mentioned above, and w3m-cookie allows cookies to be used when browsing. There are a lot more w3m libraries you can check out, but for the minimal usage I am planning on using it for this is quite enough.

(defun my-w3m-rename-buffer (url)
  "Renames the current buffer to be the current URL"
  (rename-buffer url t))
(add-hook 'w3m-display-hook 'my-w3m-rename-buffer)
 
(add-hook 'w3m-display-hook
          (lambda (url)
            (let ((buffer-read-only nil))
              (delete-trailing-whitespace))))

my-w3m-rename-buffer will rename the current buffer to that of it’s url. Since w3m by default uses names like ‘*w3m*’, ‘*w3m<2>*, and so on for buffer names, this is incredibly useful. Adding the function to w3m-display-hook forces all w3m buffers to have their URLs as their name. The second hook deletes trailing whitespace from w3m buffers. In a lot of cases, trailing whitespace is added, which makes it harder to navigate to where you expect when using C-e; this removes all of that.

(defun w3m-browse-current-buffer ()
  "Look at the current buffer as rendered by w3m."
  (interactive)
  (let ((filename (concat (make-temp-file "w3m-") ".html")))
    (unwind-protect
        (progn
          (write-region (point-min) (point-max) filename)
          (w3m-find-file filename))
      (delete-file filename))))

In case I have a HTML file open in a buffer I’m editing that I want to view in w3m, I have this function. It will open up a new w3m buffer viewing the current buffer. I haven’t had occasion to use it yet, but I saw it on emacs-wiki and it seemed like something that would eventually be useful.

(unless window-system
  (setq browse-url-browser-function 'w3m-browse-url)
  (setq browse-url-new-window-flag t))

This is what sets Emacs to use w3m instead of Firefox. I only evaluate it when window-system is nil; if it is ‘x’, or anything else, I know I have a graphical display and can thus use Firefox. I change the function to use when browsing urls to w3m-browse-url, which will open the url up in w3m. The other option forces w3m to create a new buffer whenever a URL is browsed, instead of using old buffers.