1

While writing the question I found a viable workaround solution for myself, so I am posting it as Q&A. I am leaving the question open, because my workaround does not allow to set the amount by which things are indented.

By default Emacs indents function calls as

(function-name (first-argument)
               (second-argument))

This is mostly fine, unless nesting gets very deep or if function-name is on the long side. Then it becomes preferable to put all arguments on a separate line, which Emacs indents as

(function-name
 (first-argument)
 (second-argument))

This I find extremely ugly, because it makes code hard to read, when arguments are barely indented at all.

I could add a file local variable -*- lisp-indent-offset: 4 -*- to get more readable

(function-name
    (first-argument)
    (second-argument))

but this then would not affect only functions but would also produce the very much not well-readable

(let ((a (first-argument))
         (b (second-argument)))
    (function-name a b))

or for quoted data, equally bad,

(setq data '(data1
                data2
                data3))
                

This part is probably the most tricky, since Emacs has no fully reliable way to distinguish it from a quoted expression

(setq expression '(function-name
                      (first-argument)
                      (second-argument)))
                      

which I assume is the reason for the default behavior.

Is there any option, short of writing my own indent function, that would allow Emacs Lisp functions to be indented more deeply, without overriding the explicitly declared behavior for macros?

1
1

Workaround

The best I can currently think of is

(advice-add #'function-get :around #'my--get-lisp-indent-function)
(defun my--get-lisp-indent-function (oldfun symbol propname &rest r)
  (let ((value (apply oldfun symbol propname r)))
    (cond ((not (eq propname 'lisp-indent-function))
           value)
          ((and (null value)
                (functionp symbol))
           0)
          (t value))))

Which mostly fulfills the requirement.

I also like to add some customizations, like

(put 'format 'lisp-indent-function 1)
(put 'cl-loop 'lisp-indent-function 0)

Remarks

function-get

Cannot advise 'get, because 'get has its own opcode in compiled code and thus isn't affected by advice.

(functionp symbol)

If always returning the modified value, it would cause incorrect indentation of quoted data lists and binding forms

(setq data '(data1
              data2))
(let ((var1 val1)
       (var2 val2))
  ...)

lisp-indent-function -> 0

Only viable value is 0. For comparison:

;; 0 -> correct, but slightly low indent
(function-name (arg1)
               (arg2))
(function-name
  (arg1)
  (arg2)
  
;; defun -> incorrect
(function-name (arg1)
  (arg2))

;; most-positive-fixnum -> weird, but acceptable?
(function-name
    (arg1)
    (arg2)) ;; Nice!
(function-name (arg1)
    (arg2)) ;; Decidedly not nice.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.