(Note: Geek post ahead. You have been warned.)

Admittedly, I'm an Emacs power user (and no, I am not as hardcore as some people). Emacs has been my primary text editor for the longest time— the first time I picked up Emacs was way back in 2004, a little over four years ago, when I decided to just sit down and learn the little bugger. Now, I do a lot in the editor: my mail is handled and served by Gnus, I handle my TODO lists and outlines through Org Mode, and I do the majority of my text editing and coding in it.

The last item bears a little explanation. My work entails a lot of heavy text editing in the form of code. I am a programmer by profession, and that means that I spend a majority of time looking at code if not writing it. We do a lot of Java where I work, and most of the company uses Eclipse as the IDE of choice. I use Emacs.

Now, Emacs has some decent support for editing Java files in the form of java-mode, which features basic syntax coloring. That's a good bit, but it isn't exactly what I need— if syntax coloring was all I needed, I could just edit files in gedit. And, admittedly, there are a lot of goodies that a full blown IDE such as Eclipse can bring to the table— code completion comes to mind, especially since Java can get somewhat verbose.

So, my Emacs config also includes JDEE, the Java Development Environment for Emacs. Unfortunately, JDEE development has been relatively stagnant of late, what with it only supporting ant and not Maven— and the latter is a big deal in our shop, as we use AppFuse 2 in a lot of our projects.

Fortunately, someone wrote a decent parser for Maven 2 POMs (which isn't really a parser as it simply asks Maven for the classpath, but what the hey, it works). Unfortunately, it doesn't work for multi-module projects, for one reason or another (and I'm bad at debugging elisp. So, I decided to write a custom macro to handle it. I simple place the following in a JDEE prj.el file (in the root directory of my project):

(jmi/load-multi-module-pom
 "/path/to/project/root/here"
 '("pom.xml" "core/pom.xml" "web/pom.xml") ;; Path to module POMs
 ('(jde-project-name "My JDEE Maven Project") ;; Other JDEE variables set here
  '(jde-expand-classpath-p t)
  '(jde-lib-directory-names '("^lib" "^jar" "^java" "^plugins"))
  '(jde-expand-classpath-p t)
  '(jde-ant-enable-find t)
  '(jde-gen-k&r t)
  '(tab-width 4)
  '(jde-compile-option-command-line-args
    (quote ("-Xlint:all" "-Xlint:-serial")))))

Et, voila. I get multi-module support. The macro is pretty simple, but it's the first I've ever written (and I'm thinking I could have written it as a function, if not for the expansion of the JDEE variable list at the end):

;; Project file helper for multi-module Maven projects
(defmacro jmi/load-multi-module-pom (base-path pom-path-list other-variable-setters)
  "Macro to load multi-module projects into JDEE. BASE-PATH is
the path to the root of the multi-module project, POM-PATH-LIST
is a list of paths to the submodule pom.xml (relative to
BASE-PATH). Pass in a list of JDEE variables to set in OTHER-VARIABLE-SETTERS."
  (let ((my-classpath (make-symbol "my-full-classpath"))
        (my-sourcepath (make-symbol "my-sourcepath")))
    `(progn
       (require 'pom-parser)
       (setq ,my-classpath  '("/usr/share/java"))
       (setq ,my-sourcepath  '())
       (mapcar
        (lambda (pom-name)
          (progn
            (message "Reading %s" pom-name)
            (with-pom (concat ,base-path pom-name)
              (pom-set-jde-variables *pom-node*))
            (setq ,my-classpath (append ,my-classpath jde-global-classpath))
            (if (stringp jde-sourcepath)
                (setq ,my-sourcepath (append ,my-sourcepath (list jde-sourcepath)))
              (setq ,my-sourcepath (append ,my-sourcepath jde-sourcepath)))))
        ,pom-path-list)
       (jde-set-variables
        ,@other-variable-setters
        '(jde-global-classpath ,my-classpath)
        '(jde-sourcepath ,my-sourcepath)))))

I'll probably elaborate on more of my Java development environment under Emacs in future posts...

Previously: Goodbye, pogi man. We'll miss you.