From: Johan Parin
Subject: Modifying indentation in emacs lisp-mode
Date: 
Message-ID: <kvrahwitjy.fsf@uab.ericsson.se>
Hi,

I'm editing Common Lisp in (X)Emacs and would like to modify
indentation for some constructs. I'm already using cl-indent, but that
does not seem to recognize e.g. loop. I would like to be able to write

(loop for i in 0 to 10 do
  (loop for k in 0 to 3 do

instead of

(loop for i in 0 to 10 do
      (loop for k in 0 to 3 do

After lurking around in cl-indent.el and lisp.el, I concluded that the
right way would be to modify the property list of
common-lisp-indent-function. I just can't figure out _how_, I haven't
found any documentation anywhere.

What is the right way to do this?

All help appreciated.
Thanks in advance.

Johan Parin
Ericsson AXE Research & Development
From: Richard Mlynarik
Subject: Re: Modifying indentation in emacs lisp-mode
Date: 
Message-ID: <xcjybc3fu9g.fsf@adoc.xerox.com>
   From: Johan Parin <······@uab.ericsson.se>
   Newsgroups: comp.lang.lisp,comp.emacs.xemacs
   Date: 03 Mar 1997 21:56:01 +0100
   
   I'm editing Common Lisp in (X)Emacs and would like to modify
   indentation for some constructs. I'm already using cl-indent, but that
   does not seem to recognize e.g. loop. I would like to be able to write
   
   (loop for i in 0 to 10 do
     (loop for k in 0 to 3 do
   
   instead of
   
   (loop for i in 0 to 10 do
         (loop for k in 0 to 3 do
   
   After lurking around in cl-indent.el and lisp.el, I concluded that the
   right way would be to modify the property list of
   common-lisp-indent-function. I just can't figure out _how_, I haven't
   found any documentation anywhere.
   
There isn't any documentation other than the code.
It isn't clear to me that any documentation would be clearer than the
code anyway; non-programmers shouldn't be messing with it.

   What is the right way to do this?
   
(put 'loop 'common-lisp-indent-hook 'lisp-indent-loop)

(defun lisp-indent-loop (path state indent-point sexp-column normal-indent)
  ... your code here...)

I nearly got around to writing lisp-indent-loop in 1987, but ran out
of time or interest (I don't use loop) about 20% of the way through.

Look at lisp-indent-tagbody for some hints of how to start.


======================================================================
Addendum: just in case it does anybody any good, here's the GUARANTEED
NON-WORKING code (ie 20% finished, last touched in 1987) I found in in
an old directory.

;; LOOP indenter for use with CL-INDENT

(put 'loop 'common-lisp-indent-hook 'lisp-indent-loop)

(defun lisp-indent-loop (path state indent-point sexp-column normal-indent)
  (let ((containing-form-start (elt state 1)))
    (cond ((cdr path)
           ;; loop is only skin-deep
           normal-indent)
          ((= (car path) 1)
           ;; can't tell yet
           normal-indent)
          ((progn
             (goto-char (1+ containing-form-start))
             ;; move over LOOP
             (forward-sexp 1)
             ;; now looking at first elt of loop body
             (parse-partial-sexp (point) indent-point 1 t)
             (or (eobp)
                 (not (eql (char-syntax (following-char)) ?w))))
           ;; first elt is not a symbol -- this is boring loop
           normal-indent)
          (t
           ;; hairy case!
           (let ((p (point))
                 (bound (progn (goto-char indent-point) (end-of-line)
                               (point))))
             (goto-char p)
             (catch 'exit
               (list
                 (lisp-indent-loop-259 (current-column) bound)
                 containing-form-start)))))))

;; >>> side-effects previous-indent!!! <<<
(defun lisp-indent-loop-inhale-keyword (bound &optional indent)
  (parse-partial-sexp (point) bound 0 t)
  (let ((start (point))
        (end (progn (forward-sexp 1) (point))))
    (cond ((and (not (eobp))
                (eql (char-syntax (char-after start)) ?w))
           (let ((tem (intern-soft (buffer-substring start end))))
; (message "inhaled %s" tem) (sit-for 1)
             (and tem
                  (progn (goto-char start)
                         (skip-chars-backward " \t")
                         (bolp))
                  (progn
                    (goto-char start)
; (debug "previous-indent now %d %s" (current-column) tem) (sit-for 1)
                    (setq previous-indent (current-column))))
             (parse-partial-sexp end bound 0 t)
             tem))
          ((or (eobp) (> (point) bound))
 (debug nil "Must throw ..." (or indent (+ previous-indent 2)))
           (throw 'exit (or indent (+ previous-indent 2))))
          (t
           (parse-partial-sexp end bound 0 t)
           nil))))

(defun lisp-indent-loop-peek-keyword (name bound &optional indent)
  (let* ((p (point))
         (sym (lisp-indent-loop-inhale-keyword bound indent)))
    (if (eq sym name)
        t
      (progn
        (goto-char p)
        nil))))

;; Here's what we should be doing:
;; If this is the first non-named/repear/with/for/as/and/while/until
;;  clause, indent it 3 characters relative to the opening paren
;; If this 


(defun lisp-indent-loop-259 (previous-indent bound)
  (let ((initial t))
    (while (< (point) bound)
      (let ((sym (lisp-indent-loop-inhale-keyword
                   bound (if initial previous-indent (+ 2 previous-indent)))))
        (cond ((and (eq initial 't)
                    (not (memq sym
                               '(named repeat
                                 with for as
                                 and while until))))
                (setq initial 'first))
              ((eq initial 'first)
               (setq initial nil)))
        (if (eq sym 'and)
            (setq sym (lisp-indent-loop-inhale-keyword bound)))
        (cond ((memq sym '(named repeat
                           while until
                           initially finally
                           return
                           always never thereis))
               (lisp-indent-loop-inhale-keyword bound))
              ((memq sym '(with for as))
               ;; skip variable
               (lisp-indent-loop-inhale-keyword bound)
               ;; possibly a typespec
               (setq sym (lisp-indent-loop-inhale-keyword bound))
               (if (not (memq sym '(from downfrom upfrom
                                    in on = first being)))
                   (progn
                     (setq sym (lisp-indent-loop-inhale-keyword bound))
                     (if (not (memq sym '(from downfrom upfrom
                                          in on = first being)))
                         (throw 'exit (+ previous-indent 2)))))
               ;; inhale in/to/from/etc bound
               (lisp-indent-loop-inhale-keyword bound)
               (cond
                 ;((eq sym 'and));>>>>>
                 ((memq sym '(from downfrom upfrom))
                  (lisp-indent-loop-inhale-keyword bound)
                  (if (lisp-indent-loop-peek-keyword 'by bound)
                      (lisp-indent-loop-inhale-keyword bound)))
                 ((memq sym '(in on))
                  (if (lisp-indent-loop-peek-keyword 'by bound)
                      (lisp-indent-inhale-keyword bound)))
                 ((memq sym '(= first))
                  (if (lisp-indent-loop-peek-keyword 'then bound)
                      (lisp-indent-loop-inhale-keyword bound)))
                 (t ;(eq sym 'being)
                  ;; can't tell.
                  (lisp-indent-loop-inhale-keyword bound)
                  (forward-line 1))))
              ((memq sym '(do doing))
               (if initial (setq previous-indent (- previous-indent 3)))
               (let ((previous-indent previous-indent))
                 (while (and (not (eobp))
                             (not (eql (char-syntax (following-char)) ?w)))
 (message "Inhaling form") (sit-for 1)
                   (lisp-indent-loop-inhale-keyword
                     bound
                     (if (prog1 initial (setq initial nil))
                         previous-indent
                         (+ previous-indent 3))))))
              ((memq sym '(collect collecting
                           nconc nconcing append appending
                           count counting sum summing
                           maximize minimize))
               (if initial (setq previous-indent (- previous-indent 3)))
               (lisp-indent-inhale-loop-keyword bound)
               (if (lisp-indent-loop-peek-keyword 'into bound)
                   (lisp-indent-loop-inhale-keyword bound)))
              ((memq sym '(if when unless))
               (if initial (setq previous-indent (- previous-indent 3)))
               ;>>>>
               )
              )))
    previous-indent))