6

I'm not a lisp programmer. But I'm an emacs user, so I use elisp from times to times to do simple scripting. I'm not familiar with lisp style and I'm quite incompatible with it. Default indents quickly become over 80 whitespaces long making the program unreadable. Lisp style implies writing all braces in the single line and that makes me crazy. I'm much more comfortable with the K-R notation:

def doSomething() {
  ...
}

That style may be easily adopted to lisp code:

(defun doSomething ()
   ...
)

So I'm using it for my code, see example. But accidental calls to the indent function ruins line. That is not a big deal, undo function works well. But that still bothers me.

So I'd like to change indent function for lisp mode in either way:

  • work like for java mode (preferred)
  • do nothing (not make things worse at least)
4
  • 3
    As far as I know, there is no existing solution for this. However, you can define your own indentation function and bind it to `indent-line-function'. I don't have the time to implement it for you, but if someone else like to, feel free to post this as an answer. Commented Oct 21, 2015 at 6:08
  • 4
    Just a tiny question, what if, from time to time, you want to share your code, or one of your friend want to share his code with you?
    – Nsukami _
    Commented Oct 21, 2015 at 12:32
  • 4
    Note that this is a really bad idea. The notation you have may look nice for C++ or Java, but this will look terribly ugly for anyone fluent enoguh in Lisp to read your code. You'd better use paredit/smartparens - you will forget about parenthesis in an instant. Remember, that you will probably need to ask a few questions once in a while - and every time someone will be disgusted by the indentation. The tradeoff is non-existent, and the current style holds because it turns out it's more readable this way. Commented Oct 23, 2015 at 14:01
  • I'm afraid C++ and Java programmers has a bigger share of emacs users than pure lisp programmers. The current style is not more readable it is more used. It was at the same point of time, but IT progressed and suggested more readable styles. How can I detect where does statement end, when its closed bracket does not match open?
    – ayvango
    Commented Oct 24, 2015 at 5:32

1 Answer 1

3

If you really do want to change it, it's Emacs, of course you can.

Brutality

In the extreme, one can always use M-x fundamental-mode to “turn off” all of the mode-specific goodies, but that's probably overkill here.

Conformity

The only thing in your code that seems to be particularly injured by indentation was the use of (if … (progn)) forms.

(if … (progn)) is usually considered bad form; one uses one of when, unless, or cond for such cases more often. Switching these to when or cond forms yields what you might have wanted/expected:

Your example code with standard indentation and dangling )s:

(defun my:push-whitespace (&rest skip)
  (if (my:prev-whitespace-pushed) (progn
                                     (setq my:prev-whitespace-mode whitespace-mode)
                                     (setq my:prev-whitespace-pushed t)
                                     (my:force-modes nil 'whitespace-mode)
                                     ))
  )

(defun my:push-whitespace (&rest skip)
  (when (my:prev-whitespace-pushed) 
    (setq my:prev-whitespace-mode whitespace-mode)
    (setq my:prev-whitespace-pushed t)
    (my:force-modes nil 'whitespace-mode)
    )
  )

or

(defun my:push-whitespace (&rest skip)
  (cond ((my:prev-whitespace-pushed) 
         (setq my:prev-whitespace-mode whitespace-mode)
         (setq my:prev-whitespace-pushed t)
         (my:force-modes nil 'whitespace-mode))
        )
  )

Customization

The indentation patterns for various special forms are defined by lisp-indent-function properties on their symbols.

This will change the progn special form to indent from the prior (containing) form's start point, rather than its own:

(defun progn-java-indent (path state indent-point sexp-column normal-indent)
  (declare (ignored path state sexp-column normal-indent))
  ;; Find the point at the start of the containing sexp
  (let ((containing-point (condition-case
                           nil
                           (save-excursion
                            ;; Start at the current line
                            (goto-char indent-point)
                            ;; Up once to `|(progn` and again to its parent
                            (up-list -2)
                            ;; Take that column
                            (current-column))
                           ;; If there isn't a containing list, use the
                           ;; left margin, instead.
                           (scan-error 0))))
    ;; Increase by standard indentation, or 2, by default.
    (+ containing-point (or lisp-indent-offset
                            2))))

The scan-error condition is signaled by up-list when progn appears as a top-level form.

You could put that into your init.el and associate it with

 (put 'progn 'lisp-indent-function 'progn-java-indent)

With your sample code, I get:

(defun my:push-whitespace (&rest skip)
  (if my:prev-whitespace-pushed () (progn
    (setq my:prev-whitespace-mode whitespace-mode)
    (setq my:prev-whitespace-pushed t)
    (my:force-modes nil 'whitespace-mode)
    ))
  )

QED, I think.

1
  • emacs 25.3.1: lisp-indent-function: Wrong number of arguments
    – ideasman42
    Commented Dec 2, 2017 at 5:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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