all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
* The indentation of lisp code.
@ 2008-08-11  9:59 A Soare
  0 siblings, 0 replies; 2+ messages in thread
From: A Soare @ 2008-08-11  9:59 UTC (permalink / raw)
  To: Emacs   Dev  [emacs-devel]; +Cc: Richard   Stallman  [rms]

[-- Attachment #1: Type: text/plain, Size: 287 bytes --]


Here is again the code, this time commented.

Very grateful to rms for helping me document it.



____________________________________________________

Avant de prendre le volant, repérez votre itinéraire et visualisez le trafic ! http://itineraire.voila.fr/itineraire.html

[-- Attachment #2: indent.el --]
[-- Type: application/octet-stream, Size: 26617 bytes --]


;;; Here is an implementation of the lisp indent. Note that the indentation is
;;; computed mainly by `lisp-indent-automaton'.
;;;
;;; Lisp-indent-automaton is identical with the automaton of changing the syntax
;;; classes inside `parse-partial-sexp'. Hence, by adding a few lines of code
;;; inside `scan_sexps_forward', we can get the indentation as an 11th parameter
;;; returned after calling `parse-partial-sexp'.
;;;
;;; I computed the indentation using the below formula, that can be applied for
;;; _every_ programming language or even for the text modes. Hence I deduce that
;;; we can have a general indentation concept for emacs, and we can have just
;;; _only_one_ generic function to indent a line or a region, not having a
;;; distinct indent-line function for every major mode. Every major mode will be
;;; able to indent its code using just 2 functions: <MAJOR-MODE>-indent-rules
;;; and <MAJOR-MODE>-what-argument (this latter is not compulsory for every
;;; major mode).
;;;
;;; The formula that I used to compute the indentation is
;;;
;;; Correct-Indent (Line-X) = SUM (Deviation (Line-Containig-Sexp[i])) +
;;;                           Deviation (Line-X) +
;;;                           Current_Alignement (Line-X),
;;;
;;; where i belongs to the set of open sexps that contains the beginning of the
;;; line X, starting from the beginning of the local code (beginning-of-defun),
;;;
;;; and Difference (Line-Containig-Sexp[i]) is the function `diff' defined
;;; inside the automaton `lisp-indent-automaton'.
;;;
;;; The third field of an element of LISP-CODE-TREE-INDENT-VALUE is equal to:
;;;
;;; DIFFERENCE (Line-X) =  SUM (Deviation (Line-Containig-Sexp[i])) +
;;;                        Deviation (Line-X).
;;;
;;; This difference can be expressed also as:
;;;
;;; Correct-Indent (Line-X) = Integral ( From-Starting-Point-of-Code ,
;;;                                      To-Beginning-of-Line-X ,
;;;                                      Of-Function-DIFF )
;;;


(defvar lisp-doc-string-indent 3
   "The indent column of doc-string of some functions in Emacs Lisp code." )

(defvar lisp-code-tree-indent-value nil
   "Old and new indentations during and after running `lisp-indent-automaton'.
The value is a list that contains one element for each line
scanned. These elements are ordered last line first, so the first
element applies to the current line \(or the line after the
region scanned\), and the second element applies to the previous
line, and so on.

Each element looks like \(NEW-INDENT OLD-INDENT DIFFERENCE\),
where OLD-INDENT is the actual indentation of the line, and
NEW-INDENT is the desired indentation for that line. DIFFERENCE
is the difference of the correct indentation of the line where
the containing-sexp starts, and its actual indentation. When a
line starts inside a string, the element is nil.

For instance, in the case where we align this code:

\(defun f \(x y
           z t\)
  \"an example of Emacs Lisp code
that is aligned\"
    \(funcall x
         \(1+
            x
            y
          z\)\)\)

LISP-CODE-TREE-INDENT-VALUE will be:

\(\(12 10 -2\) \(12 12 -2\) \(12 12 -2\) \(11 9 2\) \(2 4 0\) nil \(3 2 0\) \(10 11 0\) \(0 0 0\) \)

Elery element of LISP-CODE-TREE-INDENT-VALUE is associated with a
line:

\(0  0   0\)  |\(defun f \(x y
\(10 11  0\)  |           z t\)
\(3  2   0\)  |  \"an example of Emacs Lisp code
nil         |that is aligned\"
\(2  4   0\)  |    \(funcall x
\(11 9   2\)  |         \(1+
\(12 12 -2\)  |            x
\(12 12 -2\)  |            y
\(12 10 -2\)  |          z\)\)\)")

(defun lisp-code-tree-selector (which &optional struct)
   "Get a field from the first element from
`lisp-code-tree-indent-value' or from an identical data
structure. When STRUCT is not nil, extract a field from the first
element of STRUCT. STRUCT must have the same structure with
`lisp-code-tree-indent-value'.

WHICH can be one of
 :new to get NEW-INDENT
 :old to get OLD-INDENT
 :diff to get DIFFERENCE"
  (let ((o (car (or struct lisp-code-tree-indent-value))))
    (cond ((eq which :new)
           (nth 0 o) )
          ((eq which :old)
           (nth 1 o) )
          ((eq which :diff)
           (nth 2 o) )
          (t (error "Oups! Unknown parameter!")))))

(defun lisp-code-tree-constructor (&optional new-indent old-indent diff)
   "Add a new element like \(NEW-INDENT OLD-INDENT DIFFERENCE\),
aside from the case in which the beginning of the line is inside
a string, in which case we add nil.

When one adds nil to `lisp-code-tree-indent-value', NEW-INDENT,
OLD-INDENT DIFF can miss from the call of
lisp-code-tree-constructor.

NEW-INDENT, OLD-INDENT, DIFF are explained in the definition of
`lisp-code-tree-indent-value'.

When NEW-INDENT is nil, add nil."
  (setq lisp-code-tree-indent-value
        (cons
         (if new-indent
             (list new-indent old-indent diff)
           nil)
         lisp-code-tree-indent-value)))

(mapc
 (lambda (x)
    "A list of indexes of the parameter that is the
     doc-string of some usual functions.

     Each element of the list has the form \(INDEX FUNCTIONS\),
     where FUNCTIONS is an enumeration of functions whose
     doc-string parameter is on the position INDEX."
   (let ((index (car x)))
     (dolist (function (cdr x))
       (put function 'doc-string-elt index))))
 '( (2 deftheme defstruct define-skeleton
       easy-mmode-define-minor-mode define-minor-mode
       easy-mmode-define-global-mode define-global-minor-mode
       define-globalized-minor-mode define-ibuffer-filter
       define-ibuffer-sorter lambda define-category)
    (3 autoload defalias defun defun* defvar defface defcustom
       defgroup defconst defmacro defmacro* defsubst
       define-ibuffer-op defalias defvaralias define-widget
       define-compilation-mode )
    (4 define-derived-mode)
    (7 define-generic-mode )))

(mapc
 (lambda (x)
    "A list of functions whose parameters use special indent.

     Each element of the list has the form \(N FUNCTIONS\), where
     FUNCTIONS is an enumeration of functions whose first N
     parameters' alignement uses double indent. The rest of the
     parameters are aligned using normal indent. If N is zero,
     all the parameters will be indented using normal indent.
     Note the difference between a special form defined here with
     N=0 and an arbitrary function call ( that aligns its
     parameters beneath the first parameter )."
   (let ((index (car x)))
     (dolist (function (cdr x))
       (put function 'lisp-indent-function index))))
 '( (0 progn save-excursion save-window-excursion
       save-selected-window save-restriction save-match-data
       save-current-buffer combine-after-change-calls
       with-output-to-string with-temp-buffer lambda defun defun*
       defcustom define-widget defgroup defface defvar defconst
       defmacro defsubst define-derived-mode autoload)
    (1 prog1 with-current-buffer with-temp-file with-temp-message
       with-syntax-table let let* while catch unwind-protect
       with-output-to-temp-buffer eval-after-load dolist dotimes
       when unless)
    (2 prog2 if read-if condition-case)))

(defun lisp-indent-rules (state indent start-col indent-what-argument lisp-indent-get)
   "Returns a positive integer that represents the appropriate
indentation for the current line.

lisp-indent-rules is always called at the beginning of every line
\(after skipping the white spaces\) from `lisp-indent-automaton'.

STATE, INDENT, START-COL, INDENT-WHAT-ARGUMENT, LISP-INDENT-GET
are defined in `lisp-indent-automaton'"
  (cond ((elt state 3)
         ;; INSIDE A STRING, don't change indentation.
         nil )
        ((null (cadr state))
         ;; OUTSIDE AN EXPRESSION align to the left column
         0 )
        ((null indent)
         ;; an EMPTY PARETHESIS
         (1+ start-col))
        ((and (looking-at "\\s\"")
              (eq (funcall lisp-indent-get indent :first :type) :w)
              (get (intern-soft (funcall lisp-indent-get indent :first :val))
                   'doc-string-elt)
              (eq (let ((ll (length indent)))
                    (mapc (lambda (x)
                            (if (eq :q (funcall lisp-indent-get (list x) :first :type))
                                (setq ll (1- ll))))
                          indent)
                    ll)
                  (get (intern-soft (funcall lisp-indent-get indent :first :val))
                       'doc-string-elt)))
         ;; the DOC-STRING for some functions
         (+ lisp-doc-string-indent start-col) )
        ((and (integerp lisp-indent-offset)
              (integerp (funcall lisp-indent-get indent :first :pos)))
         ;; indent by CONSTANT OFFSET
         (+ (funcall lisp-indent-get indent :first :pos)
            lisp-indent-offset) )
        ((looking-at "\\s<\\s<\\s<")
         ;; COMMENTS that start WITH THREE SEMICOLONS OR MORE, should
         ;; start at the left margin
         0 )
        ((eq (funcall lisp-indent-get indent :first :type) :v)
         ;; the FIRST PARAMETER is a VECTOR
         (funcall lisp-indent-get indent :first :pos) )
        ((eq (funcall lisp-indent-get indent :first :type) :l)
         ;; the FIRST PARAMETER is a LIST
         (funcall lisp-indent-get indent :first :pos) )
        ((and (equal (following-char) ?:)
              (or 
               (eq :c (funcall lisp-indent-get indent :last :type))
               (eq :c (funcall lisp-indent-get indent :n-1 :type))))
         ;; indent a KEYWORD beneath last KEYWORD if there is one in the last 2
         ;; parameters
         (cond ((eq :c (funcall lisp-indent-get indent :last :type))
                (funcall lisp-indent-get indent :last :pos))
               ((eq :c (funcall lisp-indent-get indent :n-1 :type))
                (funcall lisp-indent-get indent :n-1 :pos))) )
        ((and (eq (funcall lisp-indent-get indent :first :type) :w)
              (wholenump (get (intern-soft (funcall lisp-indent-get indent :first :val)) 'lisp-indent-function)))
         ;; here there is a SPECIAL FORM
         (setq oo (or (get (intern-soft (funcall lisp-indent-get indent :first :val)) 'lisp-indent-function)
                      ;; LISP-INDENT-HOOK calls are NOT YET DEFINED
                      nil
                      (get (intern-soft (funcall lisp-indent-get indent :first :val)) 'lisp-indent-hook)))
         (if (> (length indent) oo)
             (+ lisp-body-indent start-col)
           (+ (* 2 lisp-body-indent) start-col)) )
        ((and nil
              (eq (funcall lisp-indent-get indent :first :type) :w)
              (get (intern-soft (funcall lisp-indent-get indent :first :val)) 'lisp-indent-hook))
         ;; INDENT defined BY ANOTHER FUNCTION is NOT YET DEFINED
         (funcall (get (intern-soft (funcall lisp-indent-get indent :first :val)) 'lisp-indent-hook)) )
        ((and (eq (funcall lisp-indent-get indent :first :type) :w)
              (> (length indent) 1))
         ;; INDENT BENEATH the INDENT-WHAT-ARGUMENT parameter
         (funcall lisp-indent-get indent indent-what-argument :pos) )
        (t
         ;;  indent the FIRST PARAMETER of a FUNCTION call
         (funcall lisp-indent-get indent :first :pos))))

(defun lisp-indent-what-argument (indent previous-level-indent lisp-indent-get)
   "This function is always called from `lisp-indent-automaton',
and it returns the index of the parameter beneath which the code
will be aligned on the following line.

INDENT is defined in `lisp-indent-automaton'.

PREVIOUS-LEVEL-INDENT is defined in `lisp-indent-automaton'.

The returned value is one of the contant symbols :first
and :second.

When the returned value is :first, the symbols from the
containing sexp are indented beneath the first parameter of the
sexp.

When the returned value is :second, the symbols from the
containig sexp are indented beneath the second parameter of the
sexp \(we think at a function call in this case\).

LISP-INDENT-GET is the selector for INDENT, and it's defined in
`lisp-indent-automaton'"
  (cond ((and (= (length indent) 3)
              (eq (funcall lisp-indent-get indent :first :type) :w)
              (stringp (funcall lisp-indent-get indent :first :val))
              (>= (length (funcall lisp-indent-get indent :first :val)) 3)
              (string-equal "def" (substring (funcall lisp-indent-get indent :first :val) 0 3)))
         ;; we enter inside the SECOND PARAMETER OF DEFUN, which is a list of
         ;; bound variables, it's not a function call
         :first )
        ((or
          (and (>= (length indent) 2)
               (memq (funcall lisp-indent-get indent :n-1 :type) '(:q :b)))
          (and (eq (funcall lisp-indent-get indent :first :type)
                   :w)
               (string-equal (funcall lisp-indent-get indent :first :val)
                             "quote")))
         ;; a QUOTED OR BACKQUOTED LIST is not a function call
         :first )
        ((and (eq (funcall lisp-indent-get indent :first :type) :w)
              (= (length indent) 2)
              (member (funcall lisp-indent-get indent :first :val) '("let" "lambda" "let*")))
         ;; The BOUND VARIABLES of LET or LAMBDA
         :first )
        ((and (>= (length indent) 2)
              (eq (funcall lisp-indent-get indent :n-1 :type) :M))
         ;; we are into a MACRO CALL INSIDE A BACKQUOTED PARENTHESIS
         :second)
        ;((eq (elt previous-level-indent 0) :b)
        ; we are in a nested parenthesis inside a quoted list
        ;0)
        (t
         ;; indent beneath the FIRST PARAMETER OF A FUNCTION...
         :second)))

(defsubst lisp-indent-advance nil
   "Scan across a single character, and pass to the next state."
  ;; state is defined in `lisp-indent-automaton'
  (setq state (parse-partial-sexp (point) (+ 1 (point)) () () state)) )

(defun lisp-indent-automaton (&optional indent-what-argument start-col
                              indent end previous-level-indent
                              state containing-sexp-deviation)
   "This is an automaton to indent the lisp code. It is the core
of the system of indentation. Note that it is identical with the
automaton used by `parse-partial-sexp'.

Before calling this automaton we must define in the upper
environment and initialize with nil the free variable

 `lisp-code-tree-indent-value'.

Never call this function before initialising this variable. The
only user interface fo this function is `get-lisp-indentation',

Lisp-indent-automaton calls recursively after scanning across an
open parenthesis, id est after passing to a new level of code, or
more after entering a new sexp. At every call, it collects
informations about the structure of the code from the current
sexo into the variable INDENT. The automaton scans a character at
a time.

INDENT-WHAT-ARGUMENT has the same structure as the value returned
by `lisp-indent-what-argument', and it is defined there.

START-COL keeps the column of the start of the containing sexp.

INDENT keeps the kind and position of the lisp objects of the
containing sexp \(a lisp object can be a symbol, a list, or
another data type\). INDENT is a list of elements which are
meaningful in groups of three and that looks like

 '( \(TYPE VALUE POSITION\) ... \)

TYPE is used to distinguish between the kind of the objects, and
can be one of the following keywords:
 :s for a string,
 :w for a symbol,
 :c for a keyword,
 :l for a list,
 :v for a vector,
 :b for a backquoted list,
 :q for a quoted list
 :m inside a backquoted list for the starting of the marker ,@
 :M for the marker ,@

VALUE is used just for symbols, and it keeps the name of the
symbol. Aside from the symbols, this element is unuseful, and it
is nil.

POSITION is the value of the _column_ where there is the object.

Thus, INDENT = \(\(:w \"let\" 10\) \( :l nil 15\)\)

means that the cursor is somewhere inside a list that calls the
special form `let', and after this special form there is also a
sexp in which there might have beed defined some bound variables,
and the cursor is after the sexp of bound variables.

END represents the buffer position where the scanning shell stop.
The starting point is the buffer position where the cursor was
placed before calling the automaton.

STATE is the state of the automaton. It has the same structyre as
the value returned by `parse-partial-sexp'.

PREVIOUS-LEVEL-INDENT keeps the kind and position of the symbols
of the previous level of code; it has the same structure as
INDENT."
  (let (
        (diff
         (lambda ()
            "Computes the deviation between the correct
             indentation and the current indentation. The value
             of the current indentation is obtained by
             integrating the function (Diff - Current-Column)."
           (+ (current-column)
              (if (car lisp-code-tree-indent-value)
                  (- (lisp-code-tree-selector :new)
                     (lisp-code-tree-selector :old))
                0))) )
        (lisp-indent-push
         (lambda (type value position)
            "The constructor for INDENT. Look at the definition
             of INDENT to see the structure of its elements.
             TYPE, VALUE and POSITION are the fields of an
             element of INDENT."
           (setq indent (append indent (list (list type value position))))) )
        (lisp-indent-get
         (lambda (indent n field)
            "The selector for INDENT. Look at the definition of
             INDENT to see the structure of its elements.

             N can be one of the keywords:
              :first for the first element of INDENT
              :second for the second element of INDENT
              :n-1 for the before last element of INDENT
              :last for the last element of INDENT.

             FIELD denotes the field of an element of INDENT, and
             can be one of the symbols:
              :type for TYPE
              :val for VALUE
              :pos for the POSITION"
           (let ((element
                  (nth
                   (cond ((eq n :first) 0 )
                         ((eq n :second) 1 )
                         ((eq n :last) (- (length indent) 1) )
                         ((eq n :n-1) (- (length indent) 2) )
                         (t (error "Oups! N should be one of {first, second, last or n-1} (%s)." n)))
                   indent)))
             (cond ((eq field :type) (nth 0 element) )
                   ((eq field :val) (nth 1 element) )
                   ((eq field :pos) (nth 2 element) )
                   (t (error "Oups! ELEMENT should be one of {type, val, pos} (%s)" n)))))) )
    (catch 'STOP
      (while (< (point) end)
        (cond ((and (elt state 8)
                    (not (elt state 4)))
               ;; INSIDE a STRING
               (and (looking-at "\\s>")
                    (lisp-code-tree-constructor
                     (lisp-indent-rules state indent start-col indent-what-argument lisp-indent-get)))
               (lisp-indent-advance) )
              ((looking-at "\\s\"")
               ;; the START of a STRING
               (let ((col (funcall diff)))
                 (funcall lisp-indent-push :s () col))
               (lisp-indent-advance) )
              ((looking-at "\\s\(")
               (cond ((looking-at "[\[]")
                      ;; a VECTOR
                      (let ((col (funcall diff)))
                        (funcall lisp-indent-push :v () col)
                        (setq state
                              (lisp-indent-automaton
                               :first
                               col nil end indent (lisp-indent-advance)
                               (- (current-column) (funcall diff))))))
                     ((looking-at "[\(]")
                      ;; OPEN a PARENTHESIS
                      (let ((col (funcall diff)))
                        (funcall lisp-indent-push :l () col)
                        (setq state
                              (lisp-indent-automaton
                               (lisp-indent-what-argument indent previous-level-indent lisp-indent-get)
                               col nil end indent (lisp-indent-advance)
                               (- (current-column) (funcall diff))))))) )
              ((looking-at "\\s\)")
               ;; CLOSE a PARENTHESIS or a VECTOR
               (throw 'STOP (lisp-indent-advance)) )
              ((looking-at "\\s ")
               ;; SPACES are ignored
               (while (looking-at "\\s ")
                 (lisp-indent-advance)) )
              ((looking-at "\\sw\\|\\s_")
               ;; a FUNCTION or a PARAMETER
               (let* ((col (funcall diff))
                      r
                      (w (catch 'WORD
                           ;; read the name of the symbol under the point
                           (while t
                             (setq r (concat r (string (following-char))))
                             (lisp-indent-advance)
                             (and (not (looking-at "\\w\\|\\s_"))
                                  (throw 'WORD r))))))
                 (funcall lisp-indent-push (if (= (elt w 0) ?:) :c :w) w col)) )
              ((looking-at "\\s<")
               ;; start of a COMMENT
               (while (not (looking-at "\\s>"))
                 ;; ignore the comments
                 (lisp-indent-advance)) )
              ((looking-at "\\s.")
               ;; skip a PUNCTUATION (non-ASCII) character
               (lisp-indent-advance) )
              ((looking-at "\\s\'")
               ;; QUOTE
               (let ((col (funcall diff)))
                 (funcall lisp-indent-push
                          (cond ((looking-at "[\\`]")
                                 ;; a BACKQUOTE
                                 :b)
                                ((and (looking-at "[\\,]")
                                      ;; maybe the START of a MACRO
                                      (eq (funcall lisp-indent-get
                                                   previous-level-indent :first :type) :b)) :m)
                                ((and (looking-at "[\\@]")
                                      ;; maybe a MACRO
                                      (>= (length indent) 1)
                                      (eq (funcall lisp-indent-get indent :last :type) :m)) :M)
                                (t
                                 ;; a quoted object
                                 :q))
                          () col))
               (lisp-indent-advance) )
              ((looking-at "\\s\\")
               ;; skip a SPECIAL character
               (lisp-indent-advance)
	       (and (looking-at "\\s>")
		    (error "Oups! Error of syntax at %d" (point)))
               (lisp-indent-advance) )
              ((looking-at "\\s>")
               ;; END OF LINE
               (lisp-indent-advance)
               (while (looking-at "\\s ")
                 (lisp-indent-advance))
               (lisp-code-tree-constructor
                (lisp-indent-rules state indent start-col indent-what-argument lisp-indent-get)
                (current-column)
                containing-sexp-deviation) )
              (t
               (error "oops! unknown class of syntax ! (indent failed at position %d)" (point))))))))

(defun get-lisp-indentation (&optional beg end)
   "Used to get the indentation of emacs lisp code from BEG to END,
where BEG and END are the limits of the region we are interested
about. The returned value is explained in the definition of
`lisp-code-tree-indent-value'"
  (if (memq major-mode '(emacs-lisp-mode lisp-interaction-mode))
      (save-excursion
        (goto-char beg)
        (beginning-of-defun)
        (skip-chars-forward "\t\ ")
        (let (lisp-code-tree-indent-value)
          (lisp-code-tree-constructor 0 (current-column) (current-column))
          (lisp-indent-automaton 0 (current-column) nil end nil nil 0)
          (and (< (point) end)
               (error "there is an error of syntax at the point %d" (point)))
          (or lisp-code-tree-indent-value
              (lisp-code-tree-constructor 0 0 0))))
    (error "Oups! get-lisp-indentation is used to indent code into a non Emacs-Lisp buffer")))

(defun indent-sexp nil
   "Indent all the lines of the containing sexp."
  (save-excursion
    (condition-case nil
        (let* ((beg (prog2 (backward-up-list) (point)))
               (end (prog2 (forward-sexp) (point))))
          (indent-region beg end))
      (error nil))))

(defun indent-region (beg end)
   "Indent all the lines of the region. BEG is the point where
the region starts. END is the region ends."
  (save-excursion
    (let* ((sublist (lambda (l n) (let (o) (dotimes (i n) (setq o (cons (elt l i) o))) o)))
           (indent-lines (get-lisp-indentation (min beg end) (max beg end)))
           ;; dif is the deviation of the sexp containing the region, that is
           ;; applied to every line in the region.
           (dif (or (lisp-code-tree-selector
                     :diff
                     (list (nth (1- (count-lines (min beg end) (max beg end))) indent-lines)))
                    0)))
      (goto-char end)
      (beginning-of-line)
      (while (and indent-lines
                  (>= (point) (min beg end)))
        ;; align every line that has associated a non-null indentation, starting
        ;; from the end of the region to the first line of the region.
        (when (car indent-lines)
          (setq l (point))
          (skip-chars-forward "\t ")
          (when (/= (lisp-code-tree-selector :old indent-lines)
                    (+ dif (lisp-code-tree-selector :new indent-lines)))
            (delete-region l (point))
            (indent-to (+ dif (lisp-code-tree-selector :new indent-lines)))))
        (forward-line -1)
        (setq indent-lines (cdr indent-lines)))))
  (deactivate-mark))

(defun lisp-indent-line nil
   "Indent the current line as Lisp code."
  (let* ((pos (point-marker))
         (p (prog2 (beginning-of-line) (point)))
         (indent-lines (get-lisp-indentation p p)))
    (when (consp (car indent-lines))
      (skip-chars-forward "\t ")
      (when (/= (lisp-code-tree-selector :old indent-lines)
                (+ (lisp-code-tree-selector :new indent-lines)
                   (lisp-code-tree-selector :diff indent-lines)))
        (delete-region p (point))
        (indent-to (+ (lisp-code-tree-selector :new indent-lines)
                      (lisp-code-tree-selector :diff indent-lines)))))
    (goto-char (max pos (point)))))


^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: The indentation of lisp code.
@ 2008-08-12 11:12 A Soare
  0 siblings, 0 replies; 2+ messages in thread
From: A Soare @ 2008-08-12 11:12 UTC (permalink / raw)
  To: Emacs   Dev  [emacs-devel]

[-- Attachment #1: Type: text/plain, Size: 494 bytes --]


Please, read the code and report me what you think about, because I want to know what you think _before_ to install the code in emacs. I tested it on more than 20 long files of emacs' sources, so it is little possible to find bugs. However, maybe you could aid me to improve the code, or the comments.




____________________________________________________

Avant de prendre le volant, repérez votre itinéraire et visualisez le trafic ! http://itineraire.voila.fr/itineraire.html

[-- Attachment #2: indent.el --]
[-- Type: application/octet-stream, Size: 26617 bytes --]


;;; Here is an implementation of the lisp indent. Note that the indentation is
;;; computed mainly by `lisp-indent-automaton'.
;;;
;;; Lisp-indent-automaton is identical with the automaton of changing the syntax
;;; classes inside `parse-partial-sexp'. Hence, by adding a few lines of code
;;; inside `scan_sexps_forward', we can get the indentation as an 11th parameter
;;; returned after calling `parse-partial-sexp'.
;;;
;;; I computed the indentation using the below formula, that can be applied for
;;; _every_ programming language or even for the text modes. Hence I deduce that
;;; we can have a general indentation concept for emacs, and we can have just
;;; _only_one_ generic function to indent a line or a region, not having a
;;; distinct indent-line function for every major mode. Every major mode will be
;;; able to indent its code using just 2 functions: <MAJOR-MODE>-indent-rules
;;; and <MAJOR-MODE>-what-argument (this latter is not compulsory for every
;;; major mode).
;;;
;;; The formula that I used to compute the indentation is
;;;
;;; Correct-Indent (Line-X) = SUM (Deviation (Line-Containig-Sexp[i])) +
;;;                           Deviation (Line-X) +
;;;                           Current_Alignement (Line-X),
;;;
;;; where i belongs to the set of open sexps that contains the beginning of the
;;; line X, starting from the beginning of the local code (beginning-of-defun),
;;;
;;; and Difference (Line-Containig-Sexp[i]) is the function `diff' defined
;;; inside the automaton `lisp-indent-automaton'.
;;;
;;; The third field of an element of LISP-CODE-TREE-INDENT-VALUE is equal to:
;;;
;;; DIFFERENCE (Line-X) =  SUM (Deviation (Line-Containig-Sexp[i])) +
;;;                        Deviation (Line-X).
;;;
;;; This difference can be expressed also as:
;;;
;;; Correct-Indent (Line-X) = Integral ( From-Starting-Point-of-Code ,
;;;                                      To-Beginning-of-Line-X ,
;;;                                      Of-Function-DIFF )
;;;


(defvar lisp-doc-string-indent 3
   "The indent column of doc-string of some functions in Emacs Lisp code." )

(defvar lisp-code-tree-indent-value nil
   "Old and new indentations during and after running `lisp-indent-automaton'.
The value is a list that contains one element for each line
scanned. These elements are ordered last line first, so the first
element applies to the current line \(or the line after the
region scanned\), and the second element applies to the previous
line, and so on.

Each element looks like \(NEW-INDENT OLD-INDENT DIFFERENCE\),
where OLD-INDENT is the actual indentation of the line, and
NEW-INDENT is the desired indentation for that line. DIFFERENCE
is the difference of the correct indentation of the line where
the containing-sexp starts, and its actual indentation. When a
line starts inside a string, the element is nil.

For instance, in the case where we align this code:

\(defun f \(x y
           z t\)
  \"an example of Emacs Lisp code
that is aligned\"
    \(funcall x
         \(1+
            x
            y
          z\)\)\)

LISP-CODE-TREE-INDENT-VALUE will be:

\(\(12 10 -2\) \(12 12 -2\) \(12 12 -2\) \(11 9 2\) \(2 4 0\) nil \(3 2 0\) \(10 11 0\) \(0 0 0\) \)

Elery element of LISP-CODE-TREE-INDENT-VALUE is associated with a
line:

\(0  0   0\)  |\(defun f \(x y
\(10 11  0\)  |           z t\)
\(3  2   0\)  |  \"an example of Emacs Lisp code
nil         |that is aligned\"
\(2  4   0\)  |    \(funcall x
\(11 9   2\)  |         \(1+
\(12 12 -2\)  |            x
\(12 12 -2\)  |            y
\(12 10 -2\)  |          z\)\)\)")

(defun lisp-code-tree-selector (which &optional struct)
   "Get a field from the first element from
`lisp-code-tree-indent-value' or from an identical data
structure. When STRUCT is not nil, extract a field from the first
element of STRUCT. STRUCT must have the same structure with
`lisp-code-tree-indent-value'.

WHICH can be one of
 :new to get NEW-INDENT
 :old to get OLD-INDENT
 :diff to get DIFFERENCE"
  (let ((o (car (or struct lisp-code-tree-indent-value))))
    (cond ((eq which :new)
           (nth 0 o) )
          ((eq which :old)
           (nth 1 o) )
          ((eq which :diff)
           (nth 2 o) )
          (t (error "Oups! Unknown parameter!")))))

(defun lisp-code-tree-constructor (&optional new-indent old-indent diff)
   "Add a new element like \(NEW-INDENT OLD-INDENT DIFFERENCE\),
aside from the case in which the beginning of the line is inside
a string, in which case we add nil.

When one adds nil to `lisp-code-tree-indent-value', NEW-INDENT,
OLD-INDENT DIFF can miss from the call of
lisp-code-tree-constructor.

NEW-INDENT, OLD-INDENT, DIFF are explained in the definition of
`lisp-code-tree-indent-value'.

When NEW-INDENT is nil, add nil."
  (setq lisp-code-tree-indent-value
        (cons
         (if new-indent
             (list new-indent old-indent diff)
           nil)
         lisp-code-tree-indent-value)))

(mapc
 (lambda (x)
    "A list of indexes of the parameter that is the
     doc-string of some usual functions.

     Each element of the list has the form \(INDEX FUNCTIONS\),
     where FUNCTIONS is an enumeration of functions whose
     doc-string parameter is on the position INDEX."
   (let ((index (car x)))
     (dolist (function (cdr x))
       (put function 'doc-string-elt index))))
 '( (2 deftheme defstruct define-skeleton
       easy-mmode-define-minor-mode define-minor-mode
       easy-mmode-define-global-mode define-global-minor-mode
       define-globalized-minor-mode define-ibuffer-filter
       define-ibuffer-sorter lambda define-category)
    (3 autoload defalias defun defun* defvar defface defcustom
       defgroup defconst defmacro defmacro* defsubst
       define-ibuffer-op defalias defvaralias define-widget
       define-compilation-mode )
    (4 define-derived-mode)
    (7 define-generic-mode )))

(mapc
 (lambda (x)
    "A list of functions whose parameters use special indent.

     Each element of the list has the form \(N FUNCTIONS\), where
     FUNCTIONS is an enumeration of functions whose first N
     parameters' alignement uses double indent. The rest of the
     parameters are aligned using normal indent. If N is zero,
     all the parameters will be indented using normal indent.
     Note the difference between a special form defined here with
     N=0 and an arbitrary function call ( that aligns its
     parameters beneath the first parameter )."
   (let ((index (car x)))
     (dolist (function (cdr x))
       (put function 'lisp-indent-function index))))
 '( (0 progn save-excursion save-window-excursion
       save-selected-window save-restriction save-match-data
       save-current-buffer combine-after-change-calls
       with-output-to-string with-temp-buffer lambda defun defun*
       defcustom define-widget defgroup defface defvar defconst
       defmacro defsubst define-derived-mode autoload)
    (1 prog1 with-current-buffer with-temp-file with-temp-message
       with-syntax-table let let* while catch unwind-protect
       with-output-to-temp-buffer eval-after-load dolist dotimes
       when unless)
    (2 prog2 if read-if condition-case)))

(defun lisp-indent-rules (state indent start-col indent-what-argument lisp-indent-get)
   "Returns a positive integer that represents the appropriate
indentation for the current line.

lisp-indent-rules is always called at the beginning of every line
\(after skipping the white spaces\) from `lisp-indent-automaton'.

STATE, INDENT, START-COL, INDENT-WHAT-ARGUMENT, LISP-INDENT-GET
are defined in `lisp-indent-automaton'"
  (cond ((elt state 3)
         ;; INSIDE A STRING, don't change indentation.
         nil )
        ((null (cadr state))
         ;; OUTSIDE AN EXPRESSION align to the left column
         0 )
        ((null indent)
         ;; an EMPTY PARETHESIS
         (1+ start-col))
        ((and (looking-at "\\s\"")
              (eq (funcall lisp-indent-get indent :first :type) :w)
              (get (intern-soft (funcall lisp-indent-get indent :first :val))
                   'doc-string-elt)
              (eq (let ((ll (length indent)))
                    (mapc (lambda (x)
                            (if (eq :q (funcall lisp-indent-get (list x) :first :type))
                                (setq ll (1- ll))))
                          indent)
                    ll)
                  (get (intern-soft (funcall lisp-indent-get indent :first :val))
                       'doc-string-elt)))
         ;; the DOC-STRING for some functions
         (+ lisp-doc-string-indent start-col) )
        ((and (integerp lisp-indent-offset)
              (integerp (funcall lisp-indent-get indent :first :pos)))
         ;; indent by CONSTANT OFFSET
         (+ (funcall lisp-indent-get indent :first :pos)
            lisp-indent-offset) )
        ((looking-at "\\s<\\s<\\s<")
         ;; COMMENTS that start WITH THREE SEMICOLONS OR MORE, should
         ;; start at the left margin
         0 )
        ((eq (funcall lisp-indent-get indent :first :type) :v)
         ;; the FIRST PARAMETER is a VECTOR
         (funcall lisp-indent-get indent :first :pos) )
        ((eq (funcall lisp-indent-get indent :first :type) :l)
         ;; the FIRST PARAMETER is a LIST
         (funcall lisp-indent-get indent :first :pos) )
        ((and (equal (following-char) ?:)
              (or 
               (eq :c (funcall lisp-indent-get indent :last :type))
               (eq :c (funcall lisp-indent-get indent :n-1 :type))))
         ;; indent a KEYWORD beneath last KEYWORD if there is one in the last 2
         ;; parameters
         (cond ((eq :c (funcall lisp-indent-get indent :last :type))
                (funcall lisp-indent-get indent :last :pos))
               ((eq :c (funcall lisp-indent-get indent :n-1 :type))
                (funcall lisp-indent-get indent :n-1 :pos))) )
        ((and (eq (funcall lisp-indent-get indent :first :type) :w)
              (wholenump (get (intern-soft (funcall lisp-indent-get indent :first :val)) 'lisp-indent-function)))
         ;; here there is a SPECIAL FORM
         (setq oo (or (get (intern-soft (funcall lisp-indent-get indent :first :val)) 'lisp-indent-function)
                      ;; LISP-INDENT-HOOK calls are NOT YET DEFINED
                      nil
                      (get (intern-soft (funcall lisp-indent-get indent :first :val)) 'lisp-indent-hook)))
         (if (> (length indent) oo)
             (+ lisp-body-indent start-col)
           (+ (* 2 lisp-body-indent) start-col)) )
        ((and nil
              (eq (funcall lisp-indent-get indent :first :type) :w)
              (get (intern-soft (funcall lisp-indent-get indent :first :val)) 'lisp-indent-hook))
         ;; INDENT defined BY ANOTHER FUNCTION is NOT YET DEFINED
         (funcall (get (intern-soft (funcall lisp-indent-get indent :first :val)) 'lisp-indent-hook)) )
        ((and (eq (funcall lisp-indent-get indent :first :type) :w)
              (> (length indent) 1))
         ;; INDENT BENEATH the INDENT-WHAT-ARGUMENT parameter
         (funcall lisp-indent-get indent indent-what-argument :pos) )
        (t
         ;;  indent the FIRST PARAMETER of a FUNCTION call
         (funcall lisp-indent-get indent :first :pos))))

(defun lisp-indent-what-argument (indent previous-level-indent lisp-indent-get)
   "This function is always called from `lisp-indent-automaton',
and it returns the index of the parameter beneath which the code
will be aligned on the following line.

INDENT is defined in `lisp-indent-automaton'.

PREVIOUS-LEVEL-INDENT is defined in `lisp-indent-automaton'.

The returned value is one of the contant symbols :first
and :second.

When the returned value is :first, the symbols from the
containing sexp are indented beneath the first parameter of the
sexp.

When the returned value is :second, the symbols from the
containig sexp are indented beneath the second parameter of the
sexp \(we think at a function call in this case\).

LISP-INDENT-GET is the selector for INDENT, and it's defined in
`lisp-indent-automaton'"
  (cond ((and (= (length indent) 3)
              (eq (funcall lisp-indent-get indent :first :type) :w)
              (stringp (funcall lisp-indent-get indent :first :val))
              (>= (length (funcall lisp-indent-get indent :first :val)) 3)
              (string-equal "def" (substring (funcall lisp-indent-get indent :first :val) 0 3)))
         ;; we enter inside the SECOND PARAMETER OF DEFUN, which is a list of
         ;; bound variables, it's not a function call
         :first )
        ((or
          (and (>= (length indent) 2)
               (memq (funcall lisp-indent-get indent :n-1 :type) '(:q :b)))
          (and (eq (funcall lisp-indent-get indent :first :type)
                   :w)
               (string-equal (funcall lisp-indent-get indent :first :val)
                             "quote")))
         ;; a QUOTED OR BACKQUOTED LIST is not a function call
         :first )
        ((and (eq (funcall lisp-indent-get indent :first :type) :w)
              (= (length indent) 2)
              (member (funcall lisp-indent-get indent :first :val) '("let" "lambda" "let*")))
         ;; The BOUND VARIABLES of LET or LAMBDA
         :first )
        ((and (>= (length indent) 2)
              (eq (funcall lisp-indent-get indent :n-1 :type) :M))
         ;; we are into a MACRO CALL INSIDE A BACKQUOTED PARENTHESIS
         :second)
        ;((eq (elt previous-level-indent 0) :b)
        ; we are in a nested parenthesis inside a quoted list
        ;0)
        (t
         ;; indent beneath the FIRST PARAMETER OF A FUNCTION...
         :second)))

(defsubst lisp-indent-advance nil
   "Scan across a single character, and pass to the next state."
  ;; state is defined in `lisp-indent-automaton'
  (setq state (parse-partial-sexp (point) (+ 1 (point)) () () state)) )

(defun lisp-indent-automaton (&optional indent-what-argument start-col
                              indent end previous-level-indent
                              state containing-sexp-deviation)
   "This is an automaton to indent the lisp code. It is the core
of the system of indentation. Note that it is identical with the
automaton used by `parse-partial-sexp'.

Before calling this automaton we must define in the upper
environment and initialize with nil the free variable

 `lisp-code-tree-indent-value'.

Never call this function before initialising this variable. The
only user interface fo this function is `get-lisp-indentation',

Lisp-indent-automaton calls recursively after scanning across an
open parenthesis, id est after passing to a new level of code, or
more after entering a new sexp. At every call, it collects
informations about the structure of the code from the current
sexo into the variable INDENT. The automaton scans a character at
a time.

INDENT-WHAT-ARGUMENT has the same structure as the value returned
by `lisp-indent-what-argument', and it is defined there.

START-COL keeps the column of the start of the containing sexp.

INDENT keeps the kind and position of the lisp objects of the
containing sexp \(a lisp object can be a symbol, a list, or
another data type\). INDENT is a list of elements which are
meaningful in groups of three and that looks like

 '( \(TYPE VALUE POSITION\) ... \)

TYPE is used to distinguish between the kind of the objects, and
can be one of the following keywords:
 :s for a string,
 :w for a symbol,
 :c for a keyword,
 :l for a list,
 :v for a vector,
 :b for a backquoted list,
 :q for a quoted list
 :m inside a backquoted list for the starting of the marker ,@
 :M for the marker ,@

VALUE is used just for symbols, and it keeps the name of the
symbol. Aside from the symbols, this element is unuseful, and it
is nil.

POSITION is the value of the _column_ where there is the object.

Thus, INDENT = \(\(:w \"let\" 10\) \( :l nil 15\)\)

means that the cursor is somewhere inside a list that calls the
special form `let', and after this special form there is also a
sexp in which there might have beed defined some bound variables,
and the cursor is after the sexp of bound variables.

END represents the buffer position where the scanning shell stop.
The starting point is the buffer position where the cursor was
placed before calling the automaton.

STATE is the state of the automaton. It has the same structyre as
the value returned by `parse-partial-sexp'.

PREVIOUS-LEVEL-INDENT keeps the kind and position of the symbols
of the previous level of code; it has the same structure as
INDENT."
  (let (
        (diff
         (lambda ()
            "Computes the deviation between the correct
             indentation and the current indentation. The value
             of the current indentation is obtained by
             integrating the function (Diff - Current-Column)."
           (+ (current-column)
              (if (car lisp-code-tree-indent-value)
                  (- (lisp-code-tree-selector :new)
                     (lisp-code-tree-selector :old))
                0))) )
        (lisp-indent-push
         (lambda (type value position)
            "The constructor for INDENT. Look at the definition
             of INDENT to see the structure of its elements.
             TYPE, VALUE and POSITION are the fields of an
             element of INDENT."
           (setq indent (append indent (list (list type value position))))) )
        (lisp-indent-get
         (lambda (indent n field)
            "The selector for INDENT. Look at the definition of
             INDENT to see the structure of its elements.

             N can be one of the keywords:
              :first for the first element of INDENT
              :second for the second element of INDENT
              :n-1 for the before last element of INDENT
              :last for the last element of INDENT.

             FIELD denotes the field of an element of INDENT, and
             can be one of the symbols:
              :type for TYPE
              :val for VALUE
              :pos for the POSITION"
           (let ((element
                  (nth
                   (cond ((eq n :first) 0 )
                         ((eq n :second) 1 )
                         ((eq n :last) (- (length indent) 1) )
                         ((eq n :n-1) (- (length indent) 2) )
                         (t (error "Oups! N should be one of {first, second, last or n-1} (%s)." n)))
                   indent)))
             (cond ((eq field :type) (nth 0 element) )
                   ((eq field :val) (nth 1 element) )
                   ((eq field :pos) (nth 2 element) )
                   (t (error "Oups! ELEMENT should be one of {type, val, pos} (%s)" n)))))) )
    (catch 'STOP
      (while (< (point) end)
        (cond ((and (elt state 8)
                    (not (elt state 4)))
               ;; INSIDE a STRING
               (and (looking-at "\\s>")
                    (lisp-code-tree-constructor
                     (lisp-indent-rules state indent start-col indent-what-argument lisp-indent-get)))
               (lisp-indent-advance) )
              ((looking-at "\\s\"")
               ;; the START of a STRING
               (let ((col (funcall diff)))
                 (funcall lisp-indent-push :s () col))
               (lisp-indent-advance) )
              ((looking-at "\\s\(")
               (cond ((looking-at "[\[]")
                      ;; a VECTOR
                      (let ((col (funcall diff)))
                        (funcall lisp-indent-push :v () col)
                        (setq state
                              (lisp-indent-automaton
                               :first
                               col nil end indent (lisp-indent-advance)
                               (- (current-column) (funcall diff))))))
                     ((looking-at "[\(]")
                      ;; OPEN a PARENTHESIS
                      (let ((col (funcall diff)))
                        (funcall lisp-indent-push :l () col)
                        (setq state
                              (lisp-indent-automaton
                               (lisp-indent-what-argument indent previous-level-indent lisp-indent-get)
                               col nil end indent (lisp-indent-advance)
                               (- (current-column) (funcall diff))))))) )
              ((looking-at "\\s\)")
               ;; CLOSE a PARENTHESIS or a VECTOR
               (throw 'STOP (lisp-indent-advance)) )
              ((looking-at "\\s ")
               ;; SPACES are ignored
               (while (looking-at "\\s ")
                 (lisp-indent-advance)) )
              ((looking-at "\\sw\\|\\s_")
               ;; a FUNCTION or a PARAMETER
               (let* ((col (funcall diff))
                      r
                      (w (catch 'WORD
                           ;; read the name of the symbol under the point
                           (while t
                             (setq r (concat r (string (following-char))))
                             (lisp-indent-advance)
                             (and (not (looking-at "\\w\\|\\s_"))
                                  (throw 'WORD r))))))
                 (funcall lisp-indent-push (if (= (elt w 0) ?:) :c :w) w col)) )
              ((looking-at "\\s<")
               ;; start of a COMMENT
               (while (not (looking-at "\\s>"))
                 ;; ignore the comments
                 (lisp-indent-advance)) )
              ((looking-at "\\s.")
               ;; skip a PUNCTUATION (non-ASCII) character
               (lisp-indent-advance) )
              ((looking-at "\\s\'")
               ;; QUOTE
               (let ((col (funcall diff)))
                 (funcall lisp-indent-push
                          (cond ((looking-at "[\\`]")
                                 ;; a BACKQUOTE
                                 :b)
                                ((and (looking-at "[\\,]")
                                      ;; maybe the START of a MACRO
                                      (eq (funcall lisp-indent-get
                                                   previous-level-indent :first :type) :b)) :m)
                                ((and (looking-at "[\\@]")
                                      ;; maybe a MACRO
                                      (>= (length indent) 1)
                                      (eq (funcall lisp-indent-get indent :last :type) :m)) :M)
                                (t
                                 ;; a quoted object
                                 :q))
                          () col))
               (lisp-indent-advance) )
              ((looking-at "\\s\\")
               ;; skip a SPECIAL character
               (lisp-indent-advance)
	       (and (looking-at "\\s>")
		    (error "Oups! Error of syntax at %d" (point)))
               (lisp-indent-advance) )
              ((looking-at "\\s>")
               ;; END OF LINE
               (lisp-indent-advance)
               (while (looking-at "\\s ")
                 (lisp-indent-advance))
               (lisp-code-tree-constructor
                (lisp-indent-rules state indent start-col indent-what-argument lisp-indent-get)
                (current-column)
                containing-sexp-deviation) )
              (t
               (error "oops! unknown class of syntax ! (indent failed at position %d)" (point))))))))

(defun get-lisp-indentation (&optional beg end)
   "Used to get the indentation of emacs lisp code from BEG to END,
where BEG and END are the limits of the region we are interested
about. The returned value is explained in the definition of
`lisp-code-tree-indent-value'"
  (if (memq major-mode '(emacs-lisp-mode lisp-interaction-mode))
      (save-excursion
        (goto-char beg)
        (beginning-of-defun)
        (skip-chars-forward "\t\ ")
        (let (lisp-code-tree-indent-value)
          (lisp-code-tree-constructor 0 (current-column) (current-column))
          (lisp-indent-automaton 0 (current-column) nil end nil nil 0)
          (and (< (point) end)
               (error "there is an error of syntax at the point %d" (point)))
          (or lisp-code-tree-indent-value
              (lisp-code-tree-constructor 0 0 0))))
    (error "Oups! get-lisp-indentation is used to indent code into a non Emacs-Lisp buffer")))

(defun indent-sexp nil
   "Indent all the lines of the containing sexp."
  (save-excursion
    (condition-case nil
        (let* ((beg (prog2 (backward-up-list) (point)))
               (end (prog2 (forward-sexp) (point))))
          (indent-region beg end))
      (error nil))))

(defun indent-region (beg end)
   "Indent all the lines of the region. BEG is the point where
the region starts. END is the region ends."
  (save-excursion
    (let* ((sublist (lambda (l n) (let (o) (dotimes (i n) (setq o (cons (elt l i) o))) o)))
           (indent-lines (get-lisp-indentation (min beg end) (max beg end)))
           ;; dif is the deviation of the sexp containing the region, that is
           ;; applied to every line in the region.
           (dif (or (lisp-code-tree-selector
                     :diff
                     (list (nth (1- (count-lines (min beg end) (max beg end))) indent-lines)))
                    0)))
      (goto-char end)
      (beginning-of-line)
      (while (and indent-lines
                  (>= (point) (min beg end)))
        ;; align every line that has associated a non-null indentation, starting
        ;; from the end of the region to the first line of the region.
        (when (car indent-lines)
          (setq l (point))
          (skip-chars-forward "\t ")
          (when (/= (lisp-code-tree-selector :old indent-lines)
                    (+ dif (lisp-code-tree-selector :new indent-lines)))
            (delete-region l (point))
            (indent-to (+ dif (lisp-code-tree-selector :new indent-lines)))))
        (forward-line -1)
        (setq indent-lines (cdr indent-lines)))))
  (deactivate-mark))

(defun lisp-indent-line nil
   "Indent the current line as Lisp code."
  (let* ((pos (point-marker))
         (p (prog2 (beginning-of-line) (point)))
         (indent-lines (get-lisp-indentation p p)))
    (when (consp (car indent-lines))
      (skip-chars-forward "\t ")
      (when (/= (lisp-code-tree-selector :old indent-lines)
                (+ (lisp-code-tree-selector :new indent-lines)
                   (lisp-code-tree-selector :diff indent-lines)))
        (delete-region p (point))
        (indent-to (+ (lisp-code-tree-selector :new indent-lines)
                      (lisp-code-tree-selector :diff indent-lines)))))
    (goto-char (max pos (point)))))


^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2008-08-12 11:12 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-08-11  9:59 The indentation of lisp code A Soare
  -- strict thread matches above, loose matches on Subject: below --
2008-08-12 11:12 A Soare

Code repositories for project(s) associated with this external index

	https://git.savannah.gnu.org/cgit/emacs.git
	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.