Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Emacs align-regexp on = but not ==

I am working in Haskell and frequently come across code similar to the following:

func i j | i == j = i
         | otherwise = j

I want to align on the '=' character using align-regexp but don't have the elisp knowhow. I have tried just doing " = " without the quotes, but this inserts an unwanted space character before each '='. I have found a proposed solution here but I can't seem to get that to do anything at all.

Please help me write a function or hard-coded macro that will allow me to set a keybinding for this.

like image 891
Karl Avatar asked Jan 11 '11 02:01

Karl


1 Answers

C-u M-x align-regexp RET \(\s-*\) = RET 1 RET 0 RET n

(n.b. there's a space after the '=', but it's not very obvious.)

Which is to say...

Use a prefix argument to tell align-regexp to ask you for more parameters than it does by default.

See C-h f align-regexp and C-h v align-rules-list for details, but in short:

\(\s-*\) is the default 'group' for deletion/expansion. We append our pattern to the end of that: ' = '. (Note that \s- is Emacs regexp syntax for whitespace.)

1 simply refers to parenthesised group 1 (as above). This is the default.

0 for the spacing to use between the two parts of the line. By default this is 1, and is why you were ending up with an additional space.

n to not align any subsequent pattern matches after the first in each line.

edit: Actually, the Q&A you linked to is near identical, and works fine for me on Emacs 23.2.1, so this is a duplicate, but to continue and answer the key-binding aspect:

You can bind that (or any) sequence via keyboard macros. Here's the end result, which you can probably just add to your init file, although I recommend you go through the process yourself. Use whatever you like in place of C-c a for the key. C-c (letter) and F5-F9 are reserved for end-users to bind as they please, so one of those will be safe from being clobbered by a mode's keymap.

(global-set-key (kbd "C-c a") (lambda (&optional arg) "Keyboard macro." (interactive "p") (kmacro-exec-ring-item (quote ([21 134217848 97 108 105 103 110 45 114 101 103 101 120 112 return 32 61 32 return return backspace 48 return 110] 0 "%d")) arg)))

I did that by:

  1. selecting the text.
  2. F3 to start recording.
  3. performing the align-regexp as above (being careful to type everything verbatim, and not use minibuffer history or yanking).1
  4. F4 to stop recording.
  5. C-x C-k n align-single-equals RET to give the macro a name
  6. M-x insert-kbd-macro RET align-single-equals RET to get the lisp.
  7. Wrapping the (lambda) expression with (global-set-key) to bind it. (Although you could also use the (fset 'align-single-equals ...) code as provided, and then bind the key to that symbol.

1 If you make a mistake when recording a complicated macro, don't fret — Emacs provides a really good macro editor which you can use to fix any mistakes after you finish recording (just type C-x C-k e), so you don't need to be perfect.

edit 2: May as well add an example of a function, as per comments.

(defun my-align-single-equals ()
  "Align on a single equals sign (with a space either side)."
  (interactive)
  (align-regexp
   (region-beginning) (region-end)
   "\\(\\s-*\\) = " 1 0 nil))

(global-set-key (kbd "C-c a") 'my-align-single-equals)
like image 116
phils Avatar answered Oct 10 '22 11:10

phils