Showing posts with label emacs-live. Show all posts
Showing posts with label emacs-live. Show all posts

Wednesday, May 15, 2013

Emacs Lisp: Font Lock for Clojure's Partial

I love using partial, but I dislike the length of the function name. There's a simple solution, define another function with a shorter name that simply calls (or is) partial. This is exactly what I did in the jry library.

I liked the use of % due to partial feeling similar to creating a function using #(), and % having a special meaning inside #(). I thought they tied well together. Unfortunately, there's an obvious problem, things would be very broken if you tried to use the '%' function in an anonymous function defined with #(). Somewhere along the way this issue caused me to stop using jry/%.

Using partial is great: it's part of the standard lib, and I don't need to explain it to anyone who joins my team or any future maintainers of the code I write. Still, I want something shorter, and I've always had a background thread looking for another shorter-than-partial solution. While recently contributing to emacs-live I found the solution I was looking for: clojure-mode font lock.

The following code can now be found in my emacs configuration.

This solution feels like the best of both worlds. My code still uses the function from the standard library, my colleagues still see a function they already know, and 'partial' only takes up one character space in my buffer. The image below is what you'll see if you put the above emacs-lisp in your config.

Monday, September 17, 2012

emacs lisp: removing a lamba hook

disclaimer: I know almost nothing about emacs lisp, so please forgive any mistakes or incorrect assumptions.

I've been using Clojure for over 4 years at this point, but it's generally been on projects that are mostly Java with a few small components in Clojure. Given that context my teammates preferred that we stick with IntelliJ; however, things have recently changed and the emacs journey has begun.

Taking emacs from 'factory settings' to 'impressive' for me was as easy as getting started with emacs-live.
Emacs Live can be summarized as:
  • a nice structured approach to organising your Emacs config
  • modular in that functionality is organised by discrete packs
  • Indeed, Emacs Live does structure your config nicely; however, in it's own words: Emacs Live is also an opinionated set of defaults. I like all of the defaults... except one: rainbow-delimiters

    I get that people like rainbow-delimeters, and I would never try to convince you not to use them - they're just not for me, and I needed to find out how to get rid of them.

    Emacs Live adds rainbow-delimiters in two different ways. The following code shows how Emacs Live uses add-hook to enable rainbow delimiters for scheme, emacs-lisp, & lisp.
    (dolist (x '(scheme emacs-lisp lisp))
      (add-hook 
        (intern (concat (symbol-name x) "-mode-hook"))
        'rainbow-delimiters-mode))
    The code required to remove rainbow-delimiters from scheme, emacs-lisp, & lisp is very straightforward, and can be found below.
    (dolist (x '(scheme emacs-lisp lisp))
      (remove-hook 
        (intern (concat (symbol-name x) "-mode-hook"))
        'rainbow-delimiters-mode))
    As you can see, replacing add-hook with remove-hook will remove the hook that Emacs Live added for me. Since Emacs Live loads my personal settings last, my remove should successfully work every time. It's a best practice that you create hooks that can be run in any order - and this change is obviously order specific; however, I can't think of a way to follow the hook best practice without hacking the emacs-live checkout. Therefore, it seems like this solution is the most pragmatic.

    The next snippet of code is how Emacs Live adds rainbow delimiters (& a few other things) to clojure-mode.
    (add-hook 'clojure-mode-hook
              (lambda ()
                (enable-paredit-mode)
                (rainbow-delimiters-mode)
                (add-to-list 'ac-sources 'ac-source-yasnippet)
                (setq buffer-save-without-query t)))
    The previous hook was easy to remove, since I knew exactly what function I needed to remove. This hook is more of a problem, since it's anonymous. Additionally, this function is defined within Emacs Live code, so simply changing it to a named function isn't an option (since I don't want to modify the emacs-live checkout).

    Finding a solution wasn't very hard. The first thing I did was try to get a list of the functions that will be fired by the hook. This is as simple as printing, as the following code shows.
    (print clojure-mode-hook)
    I put that simple print statement in my .emacs-live.el, restarted emacs, went to the *Messages* buffer, and found the following line printed out.
    ((lambda nil 
             (enable-paredit-mode)
             (rainbow-delimiters-mode)
             (add-to-list (quote ac-sources) (quote ac-source-yasnippet)) 
             (setq buffer-save-without-query t)))
    As you can see, clojure-mode-hook has a list of the functions that have been added via add-hook. With this information, I added the following code, which first removes the existing hook and then adds a new anonymous function with everything previously specified - sans rainbow-delimiters.
    (remove-hook 'clojure-mode-hook (first clojure-mode-hook))
    
    (add-hook 'clojure-mode-hook
              (lambda ()
                (enable-paredit-mode)
                (add-to-list 'ac-sources 'ac-source-yasnippet)
                (setq buffer-save-without-query t)))
    The above snippet removes my unwanted lambda hook and adds a new hook with everything I do want.

    Is this fragile? You bet. If things change in Emacs Live, I'll need to mirror those changes in my .emacs-live.el - which is why it's recommended that you don't rely on ordering when adding and removing hooks. However, given the situation, this seems like a pragmatic solution.

    Feedback definitely welcome.