(or emacs irrelevant)

A few notes on Elisp indentation

I sure do like to keep my Elisp code nice and indented. But sometimes the indentation engine just won't listen.

lisp-indent-function

By default, the indentation is handled as if:

(setq lisp-indent-function 'lisp-indent-function)

At least in one case, it looks horrible:

(cl-labels ((square (x)
                    (* x x)))
  (mapcar #'square '(0 1 2 3 4 5)))
;; => (0 1 4 9 16 25)

That's why I have:

(setq lisp-indent-function 'common-lisp-indent-function)

which leads to this indentation:

(cl-labels ((square (x)
              (* x x)))
  (mapcar #'square '(0 1 2 3 4 5)))
;; => (0 1 4 9 16 25)

Ah, much better. The indentation does change a bit in other places as a result of this. To my experience, it can be fixed on a case-by-case basis by declaring the indent level for the offending function or macro.

Declaring indent level

Here's how it looks like

(defmacro lispy-save-excursion (&rest body)
  "More intuitive (`save-excursion' BODY)."
  (declare (indent 0))
  `(let ((out (save-excursion
                ,@body)))
     (when (bolp)
       (back-to-indentation))
     out))

By default, functions behave as if their indent was declared to nil. Zero here means that we expect zero arguments on the same line, so that this indentation follows:

(lispy-save-excursion
  (lispy--out-forward arg)
  (backward-list)
  (indent-sexp))

The indentation above is just like the one that the original save-excursion has. Note that if I hadn't declared the indent, it would look like this:

(lispy-save-excursion
 (lispy--out-forward arg)
 (backward-list)
 (indent-sexp))

The impact is much larger for statements that require an indent of 1:

Compare the proper thing:

(lispy-dotimes arg
  (when (= (point) (point-max))
    (error "Reached end of buffer"))
  (forward-list))

to this horror:

(lispy-dotimes arg
               (when (= (point) (point-max))
                 (error "Reached end of buffer"))
               (forward-list))

Outro

I've shown two things you can try if you find your Elisp indentation annoying. If you know of more, let me know.

My "refactoring" workflow

Well, "refactoring" is for the Java people, I simply rename things. Just today, I had to do a big rename operation related to the release of lispy 0.22.0. Below, I'll share some functions and packages that I used for that.

My Github setup

Here's it (tree -da -L 1) is:

.
├── .cask
├── gh-pages
├── .git
└── images

I've cloned my gh-pages branch into its own git repository inside the original lispy repository. This way, I can rename functions in the code and the documentation simultaneously.

Declaring functions obsolete in Elisp

It can be done like this:

(define-obsolete-function-alias 'lispy-out-forward
    'lispy-right "0.21.0")
(define-obsolete-function-alias 'lispy-out-backward
    'lispy-left "0.21.0")
(define-obsolete-function-alias 'lispy-out-forward-nostring
    'lispy-right-nostring "0.21.0")

After version "0.21.0" hits, any time you call lispy-left by its now obsolete alias lispy-out-backward, you'll get a message:

`lispy-out-forward' is an obsolete command (as of 0.21.0); use `lispy-right' instead.

So now, since I'm releasing version "0.22.0", I can remove even the alias declarations. I gave people one week of warnings to adjust (just rename to the new name) any of their code that's calling the currently obsolete functions.

Renaming obsolete functions in the documentation

Taking advantage of the repository setup, I can:

Step 1: call rgrep

rgrep is a fine function, I wonder why it's not bound by default; I bind it to C-<, taking advantage of my weird key mappings (I'm actually pressing the C-;-l physical keys).

It requires 3 inputs:

  1. Symbol to search for: I call it with the point positioned on the symbol that I want to rename in the code, in the middle of the define-obsolete-function-alias tag, so rgrep picks up the symbol name as the default and I just type RET to select it.
  2. File pattern: *.el, the current file extension is the default. I type * RET, since I want to match the org and html files as well.
  3. Base directory: this directory will be will be recursively searched for files that match the file pattern; the default ~/git/lispy/ is fine here, RET.

Step 2: call wgrep

wgrep is a fine package, I wonder why it's not more popular. Since it's so similar to wdired (one of the best things since sliced bread, btw), I like to bind the starter to C-x C-q and the finisher to C-c C-c as well:

(eval-after-load 'grep
  '(define-key grep-mode-map
    (kbd "C-x C-q") 'wgrep-change-to-wgrep-mode))

(eval-after-load 'wgrep
  '(define-key grep-mode-map
    (kbd "C-c C-c") 'wgrep-finish-edit))

Step 3: call iedit

iedit is an amazing package, it's crazy-good. Here's how I bind it, since once iedit-mode is on, you can move to the next occurrence with C-i:

(global-set-key (kbd "C-M-i") 'iedit-mode)

In order to change really every occurrence in the buffer, I need to mark the thing that I want to change, before C-M-i. Otherwise, iedit will automatically add symbol bounds (a nice feature, actually), so that e.g. =lispy-out-forward= will not match lispy-out-forward.

Finally, I interactively, char-by-char, rename e.g. lispy-out-forward to lispy-right. The experience is similar to the popular multiple-cursors, which I also like to use, just for different purposes.

Step 4: exiting

When I'm done:

  • I exit iedit-mode with C-M-i.
  • I exit wgrep with C-c C-c
  • I save all affected files if I want, since they aren't saved yet and it's still possible to revert everything.

Outro

Woah, that's a lot of steps!

True, but do note that all three tools can be used on their own for various other tasks. See for instance my other "refactoring" demo, that uses iedit-mode to unbind a let-bound variable in Elisp (should also work for Common Lisp, since the syntax is the same).

There's beauty and utility in having such composable tools. A lot of the time, it's better than to just have one "Rename" button. For instance, when only one buffer is involved, the rgrep-wgrep step can be skipped and I can rename stuff with iedit-mode only.

Or, when the playground for renaming is less than a buffer, I can:

  1. C-x nd - narrow-to-defun or C-x nn - narrow-to-region (both are equivalent to N in lispy)
  2. iedit-mode
  3. C-x nw - widen (W in lispy)

occur-dwim (Do What I Mean)

I'd like to share a little snippet that I like to use instead of a plain M-s o (occur).

smarter-than-the-average-occur

(defun occur-dwim ()
  "Call `occur' with a sane default."
  (interactive)
  (push (if (region-active-p)
            (buffer-substring-no-properties
             (region-beginning)
             (region-end))
          (let ((sym (thing-at-point 'symbol)))
            (when (stringp sym)
              (regexp-quote sym))))
        regexp-history)
  (call-interactively 'occur))

It will offer as the default candidate:

  • the current region, if it's active
  • the current symbol, otherwise

It's pretty good, since I actually want the default candidate in 95% of the cases. Some other functions, such as rgrep are smart like this out-of-the-box.

A Hydra that goes nicely with occur

Since occur, like some other functions (grep, rgrep, compile), works with next-error, it's possible to use this Hydra to navigate the occur matches:

(hydra-create "M-g"
  '(("h" first-error "first")
    ("j" next-error "next")
    ("k" previous-error "prev")))

Hydra was introduced in an earlier post, and is available in GNU ELPA.

What goes around comes around

I usually do a quick internet search to see where I got the code that I'm posting here, reason being that it's nice to list the source, as well as there could be more advanced stuff out there on the same topic.

I saw a few results for "occur-dwim" so I thought that I just copy-pasted it from somewhere. Slight disappointment turned into a small sense of pride, when I found that the source of the copy-pastes was my old Stack Overflow answer:)

Exploring Emacs packages

Currently, MELPA hosts over 2250 packages. That's quite a large number, although it's still feasible to try most of the popular ones. In comparison,

apt-cache pkgnames | wc

gives me the number 50250. I don't recall calling apt-cache pkgnames ever before, while I call package-list-packages all the time. I suppose that this will have to change when the number of packages grows further.

I usually explore packages just as they show up as new in package-list-packages. I'll share the two tools that I use for exploring them.

Smex

Smex is an M-x enhancement for Emacs. In addition to executing commands faster, it gives you an option to jump to the current command's definition with M-..

Here's how I bind smex:

(require 'smex)
(global-set-key "\C-t" 'smex)
(defun smex-prepare-ido-bindings ()
  (define-key ido-completion-map
      (kbd "C-,") 'smex-describe-function)
  (define-key ido-completion-map
      (kbd "C-w") 'smex-where-is)
  (define-key ido-completion-map
      (kbd "C-.") 'smex-find-function)
  (define-key ido-completion-map
      (kbd "C-a") 'move-beginning-of-line)
  ;; (define-key ido-completion-map "\C-i" 'smex-helm)
  ;; (define-key ido-completion-map " " 'smex-helm)
  )

I don't feel bad at all for unbinding transpose-chars, C-t is such a prime binding, that only the best commands can deserve it. And since I touch-type, it's easier for me to hit M-DEL and retype the word when I notice a mistake, than to carefully navigate to the mistake location and call transpose-chars with surgical precision. On the other hand, the number of Emacs packages is only going to grow, so it becomes less and less feasible to bind everything. Instead, seldom used stuff can be called though smex. For instance, I don't bind markdown-toc or speed-type and call them via C-t instead.

Back to the point, C-t ... C-. (smex-find-function) allows me to quickly jump to the source of the package that I want to explore.

Semantic tags

Once I'm in the source code, I can quickly get an overview with g (lispy-goto) from lispy. It uses CEDET's semantic module to get a list of tags in current directory with helm for completion. In my opinion, it's much prettier than helm's own helm-semantic. It also explores more tags for Emacs Lisp, for instance it will capture use-package and global-set-key tags.

A new cute feature that I added recently is a different background for user-visible functions, i.e. the ones that are callable by M-x or smex. Here's how it looks like, for the speed-type package (interactive functions have a purple background):

lispy-goto

If the image text looks too small, you can right click / view image in your browser. Here, I can see at a glance, that there are three commands that I can call. I can also see a few variables, two of them don't include --, so they're probably customizable.

Do things after selecting window

I saw this question today at Stack Overflow - Emacs: How to enable toolbar mode and menubar mode only under a certain mode?. Myself, I never use the menubar or the toolbar. But maybe it's just because it's useless in the modes to which I'm used to. What if there was an option to have the menu bar on just for a few select modes? For instance, if I decided that I want to learn Haskell tomorrow, I wouldn't mind to have the menu bar on for a while, especially if there was some useful stuff there in the menu.

The Code

I'm not aware of a convenient hook for this job; I tried after-change-major-mode-hook, and it doesn't work when switching windows. The universal post-command-hook would be totally lame for this task.

Then it occurred to me, that select-window has to be called eventually in most circumstances. Even ace-window calls select-window.

This is what I came up with so far:

(defvar menubar-last
  (make-ring 20))
(ring-insert menubar-last "dummy")

(defadvice select-window (after select-window-menubar activate)
  (unless (equal (buffer-name) (ring-ref menubar-last 0))
    (ring-insert menubar-last (buffer-name))
    (let ((yes-or-no
           (if (memq major-mode '(r-mode lisp-interaction-mode))
               1 -1)))
      (menu-bar-mode yes-or-no)
      (tool-bar-mode yes-or-no))))

The Ring trickery

It's necessary at least for magit. Doing, for instance, ll operation switches windows many times. So I added a check that the current buffer isn't selected twice.

In Emacs, a ring is like a stack with a limited length: you push onto the head, and if the stack becomes too large, the stuff gets removed from the tail. Perfect for debugging this code, since I don't care what happened 20 window switches ago, I'm only interested in the most recent state. One small annoyance is that the following code will throw, if the ring is empty:

(ring-ref menubar-last 0)

I would prefer if it just returned nil instead. Hence the trick of initializing menubar-last with a dummy item. Note that this annoyance propagates to other areas: (current-kill 0) will throw if you haven't yet copied text since Emacs started.

Outro

I'm not sure if this code is more annoying than useful, but, at least, I learned something new while writing it, and I hope you did too. If you know of a better way to accomplish the original task, please do share.