Erlang mode in Emacs
Luke Gorrie
luke@REDACTED
Tue Dec 17 16:22:09 CET 2002
Luke Gorrie <luke@REDACTED> writes:
> I have a command for aligning the arrows in function heads that I've
> been meaning to send in for years - maybe something we can add to the
> mode and assign a key?
Here's an updated version, which works like the old one except that if
you give a prefix argument (by pressing C-u before the command), it
will indent all arrows in the region, not just the ones in function
heads. Fix courtesy of Matthias Lang, and meant for expressions like
this:
parse([open, {name, Name}|T]) ->
case Name of
"bye" -> {ok, #cmd_tuple{command = bye}};
"delete" -> delete(T);
"install" -> install(T);
"new" -> new(T);
"nop" -> {ok, #cmd_tuple{command = nop}};
"query" -> qry(T);
"reset" -> reset(T);
"set" -> set(T);
"takeover" -> takeover(T);
"update" -> update(T);
"zero" -> zero(T)
end.
Also, the `line-beginning-position' function doesn't exist in XEmacs,
so here is a workaround to make the erlang-align-arrows work there:
(unless (fboundp 'line-beginning-position)
(defalias 'line-beginning-position 'point-at-bol))
(We can't just use point-at-bol all the time, because Emacs20 lacks
that - it seems that some Emacs has to work around.)
Okay, so here's the updated command (two functions now):
(defun erlang-align-arrows (start end)
"Align arrows (\"->\") in function clauses from START to END.
When called interactively, aligns arrows after function clauses inside
the region.
With a prefix argument, aligns all arrows, not just those in function
clauses.
Example:
sum(L) -> sum(L, 0).
sum([H|T], Sum) -> sum(T, Sum + H);
sum([], Sum) -> Sum.
becomes:
sum(L) -> sum(L, 0).
sum([H|T], Sum) -> sum(T, Sum + H);
sum([], Sum) -> Sum."
(interactive "r")
(save-excursion
(let (;; regexp for matching arrows. without a prefix argument,
;; the regexp matches function heads. With a prefix, it
;; matches any arrow.
(re (if current-prefix-arg
"^.*\\(\\)->"
(concat "^" erlang-atom-regexp ".*\\(\\)->")))
;; part of regexp matching directly before the arrow
(arrow-match-pos (if current-prefix-arg
1
(1+ erlang-atom-regexp-matches)))
;; accumulator for positions where arrows are found, ordered
;; by buffer position (from greatest to smallest)
(arrow-positions '())
;; accumulator for longest distance from start of line to arrow
(most-indent 0)
;; marker to track the end of the region we're aligning
(end-marker (progn (goto-char end)
(point-marker))))
;; Pass 1: Find the arrow positions, adjust the whitespace
;; before each arrow to one space, and find the greatest
;; indentation level.
(goto-char start)
(while (re-search-forward re end-marker t)
(goto-char (match-beginning arrow-match-pos))
(just-one-space) ; adjust whitespace
(setq arrow-positions (cons (point) arrow-positions))
(setq most-indent (max most-indent (erlang-column-number))))
(set-marker end-marker nil) ; free the marker
;; Pass 2: Insert extra padding so that all arrow indentation is
;; equal. This is done last-to-first by buffer position, so that
;; inserting spaces before one arrow doesn't change the
;; positions of the next ones.
(mapcar (lambda (arrow-pos)
(goto-char arrow-pos)
(let* ((pad (- most-indent (erlang-column-number))))
(when (> pad 0)
(insert (make-string pad ? )))))
arrow-positions))))
(defun erlang-column-number ()
"Return the column number of the current position in the buffer.
Tab characters are counted by their visual width."
(string-width (buffer-substring (line-beginning-position) (point))))
More information about the erlang-questions
mailing list