From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Didier Verna Newsgroups: gmane.emacs.devel Subject: Common Lisp indentation improvements Date: Fri, 06 May 2011 21:07:09 +0200 Organization: The XEmacs Project Message-ID: NNTP-Posting-Host: lo.gmane.org Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Trace: dough.gmane.org 1304774524 10499 80.91.229.12 (7 May 2011 13:22:04 GMT) X-Complaints-To: usenet@dough.gmane.org NNTP-Posting-Date: Sat, 7 May 2011 13:22:04 +0000 (UTC) To: emacs-devel@gnu.org Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Sat May 07 15:22:00 2011 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([140.186.70.17]) by lo.gmane.org with esmtp (Exim 4.69) (envelope-from ) id 1QIhSJ-0000W3-RK for ged-emacs-devel@m.gmane.org; Sat, 07 May 2011 15:22:00 +0200 Original-Received: from localhost ([::1]:60601 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QIhSI-0007Tv-Qw for ged-emacs-devel@m.gmane.org; Sat, 07 May 2011 09:21:58 -0400 Original-Received: from eggs.gnu.org ([140.186.70.92]:49684) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QIhSF-0007Td-0x for emacs-devel@gnu.org; Sat, 07 May 2011 09:21:56 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1QIhSD-00083P-Ge for emacs-devel@gnu.org; Sat, 07 May 2011 09:21:54 -0400 Original-Received: from bob75-9-88-181-0-232.fbx.proxad.net ([88.181.0.232]:59203 helo=Scofield.local) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QIhSC-00082I-ID for emacs-devel@gnu.org; Sat, 07 May 2011 09:21:53 -0400 Original-Received: by Scofield.local (Postfix, from userid 501) id 38185D08FDE; Fri, 6 May 2011 21:07:09 +0200 (CEST) User-Agent: Gnus/5.110011 (No Gnus v0.11) XEmacs/21.5-b31 (darwin) Face: iVBORw0KGgoAAAANSUhEUgAAADAAAAAwBAMAAAClLOS0AAAAGFBMVEWnezr7+/zCt7r7+f82 JCP6//+SJRv77NcWGFlPAAACC0lEQVQ4jaWUTYvbQAyGVWOm11WWwVdvCLvXpsbs1RTh+2B8H5ZB vdo+dP5+X/kjZNtADxXEwXmkV18zoXE3huFrON5pvCOPwdC0eDaPQGMP3u2/wZojfAbjCv6oygoN zz6MDBA+VcVcnSuQ0PpxbA/gIVtdpHvhvc074CcR+cF+rHZ0S37pepEvzDnPlaEDhFI1IYSX81u2 oA1AoVcH8lKRi+d868NATCrydnFauGJegQUO30UUYojSqLHIeQN+eAeIpUjnwIEMXNn78J56jUl6 JSNgZAvygU8mkqRLAKvoASYD6LFXtU9S4mcMlU+1ag+Qoq4BYsAWsBB04C9rAngAYJq+qp3ICiy1 M02A6xieqCC8dFtByTlJhO4C1y7XncguRDYdgDCfiPLUSbkCItQRlbD5+Rf9zN8wRTGdSMnaBMgV 0de8iETXO3Uxpg5q1DJPsczzZGBtINqsHLWheiVdCurTnjpiKpAaA5QwV1vU1nW0PEQjP0WHdLYH SKMCDAEN0XCd4jZpW3p0KPTVuqchlCjBKk02U4K6vSg17CydKPQQQYDaQ43aay3wK1OPOcYyQo2o pkTezljOy7lYznmhUj5q+JGgKjuUQPPMczUv9Rk/kgoNFgJU8WwO5rLkCVHHDefbbTev9VwFHu+s +fuq3RsA82P0L3DgwOsfxwYO2xyandwBv9ez2W+rQiUqNjP5BwAAAABJRU5ErkJggg== X-Face: compface: (warning) : excess data ignored Face: iVBORw0KGgoAAAANSUhEUgAAADAAAAAwBAMAAAClLOS0AAAAGFBMVEX7+f+kgSyYKB/70rH7 9vyxsqz5//8zKCKknkuFAAACWUlEQVQ4jXWUQW8iMQyFcxhxdwaUc9xd5UxLt1e0pLm3wPYaqdHc kxb57+9zpixU7UYCMflw/PzsjJkuKxsTzfnBXAHsL/J3YEpTTF9ANthNlz9dzjSxr69g+A/YDnFn ab/7LmIt1DafQMqplPLoqbmxTOkC9KvEFyKyb2VaXEBZ5BTX2KdQPx2VAXZCrpG0tChXyctUbiu5 +hTqr2uA35FWAET8x5R8Jbfck7XM7O0B+i7J0+uRHYeKkOUZpGFKJT4QhxZade4toi1QjBYkOCTO I0I8ySnC6A503RMTMrAj8bBRs5sad3f0RNWyZUEIx+2sSsY7q7Ux2xDEUth8eCWtSfO3zbsantWU wxkIs57gnVTY5cMyzQ0NOCSwFx/k/fFkffiR+gSYJjMgls1rtU7edSQAsMsMW507pSTNtbdU+lEq PzTb2C1TehEJNc2WqBWIQqpNjg/StPQZsIexKOFmF+Nv4brPiw9QR1cheQOwbnwTU+6WoDByWogd 745HVjC7axkgEAmLlSp82uftDBr7AAM91ImqEPUkD6aFuha26LbXuQJVTwatY6TmEQFGSMVhCb1l ayRA7g0mxKoMQid/bmIsEV6Rdx6bFvAegHjUpsJ2b7sr+CAiNE8rDUGjRLQnfZENIo1WB8h9rjBW yHaGtq+Oq+NxPyWDWYi7JwCBcEvSpwZjaLYG6kC192DLKWNfK98u9H6XPl2r5zFqj0zv1LZfp0Gv QknXt3a2f4ol6Zth3kXLcVw2/65unIo5gzgN8ysnYoyHNGliTYk3CJY+5KHrBOhK/gIH7z03MPLJ gAAAAABJRU5ErkJggg== X-Face: compface: (warning) : excess data ignored X-Attribution: dvl X-Web: http://www.xemacs.org X-Url: http://www.xemacs.org X-Home-Page: http://www.xemacs.org X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 88.181.0.232 X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Original-Sender: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.devel:139200 Archived-At: --=-=-= Hello, I have just applied a patch to XEmacs'version of cl-indent.el which improves the indentation of Common Lisp code. I'm attaching this patch and a ChangeLog entry below in case you're interested. A detailed description of the modifications is available in the following blog entry: http://www.didierverna.com/sciblog/index.php?post/2011/05/06/Common-Lisp-indentation-in-XEmacs For further discussion, please Cc: me directly, as I'm not a subscriber of emacs-devel@. 2011-05-06 Didier Verna Common Lisp indentation improvements on defmethod and lambda-lists. * cl-indent.el: Advertise the changes and remove obsolete TODO entries. * cl-indent.el (lisp-lambda-list-keyword-alignment): * cl-indent.el (lisp-lambda-list-keyword-parameter-indentation): * cl-indent.el (lisp-lambda-list-keyword-parameter-alignment): New customizable user options. * cl-indent.el (lisp-indent-defun-method): Improve docstring. * cl-indent.el (extended-loop-p): Fix comment. * cl-indent.el (lisp-indent-lambda-list-keywords-regexp): New variable. * cl-indent.el (lisp-indent-lambda-list): New function. * cl-indent.el (lisp-indent-259): Use it. * cl-indent.el (lisp-indent-defmethod): Support for more than one method qualifier and properly indent methods lambda-lists. * cl-indent.el: Provide a missing common-lisp-indent-function property for defgeneric. --=-=-= Content-Type: text/x-patch Content-Disposition: inline; filename=cl-indent.patch --- cl-indent.el.old 2011-05-06 20:35:49.000000000 +0200 +++ cl-indent.el.new 2011-05-06 20:41:23.000000000 +0200 @@ -31,20 +31,6 @@ ;; ;; (setq lisp-indent-function 'common-lisp-indent-function) -;;>> TODO -;; :foo -;; bar -;; :baz -;; zap -;; &key (like &body)?? - -;; &rest 1 in lambda-lists doesn't work -;; -- really want (foo bar -;; baz) -;; not (foo bar -;; baz) -;; Need something better than &rest for such cases - ;;; Code: (defgroup lisp-indent nil @@ -101,9 +87,55 @@ :type 'integer :group 'lisp-indent) +(defcustom lisp-lambda-list-keyword-alignment nil + "Whether to vertically align lambda-list keywords together. +If nil (the default), keyworded lambda-list parts are aligned +with the initial mandatory arguments, like this: + +\(defun foo (arg1 arg2 &rest rest + &key key1 key2) + #|...|#) + +If non-nil, alignment is done with the first keyword +\(or falls back to the previous case), as in: + +\(defun foo (arg1 arg2 &rest rest + &key key1 key2) + #|...|#)" + :type 'boolean + :group 'lisp-indent) + +(defcustom lisp-lambda-list-keyword-parameter-indentation 2 + "Indentation of lambda list keyword parameters. +See `lisp-lambda-list-keyword-parameter-alignment' +for more information." + :type 'integer + :group 'lisp-indent) + +(defcustom lisp-lambda-list-keyword-parameter-alignment nil + "Whether to vertically align lambda-list keyword parameters together. +If nil (the default), the parameters are aligned +with their corresponding keyword, plus the value of +`lisp-lambda-list-keyword-parameter-indentation', like this: + +\(defun foo (arg1 arg2 &key key1 key2 + key3 key4) + #|...|#) + +If non-nil, alignment is done with the first parameter +\(or falls back to the previous case), as in: + +\(defun foo (arg1 arg2 &key key1 key2 + key3 key4) + #|...|#)" + :type 'boolean + :group 'lisp-indent) + (defvar lisp-indent-defun-method '(4 &lambda &body) - "Indentation for function with `common-lisp-indent-function' property `defun'.") + "Defun-like indentation method. +This applies when the value of the `common-lisp-indent-function' property +is set to `defun'.") (defun extended-loop-p (loop-start) @@ -217,8 +249,7 @@ (let ((depth 0) ;; Path describes the position of point in terms of ;; list-structure with respect to containing lists. - ;; `foo' has a path of (0 4 1) in `((a b c (d foo) f) g)' - ;; (Surely (0 3 1)?). + ;; `foo' has a path of (0 3 1) in `((a b c (d foo) f) g)'. (path ()) ;; set non-nil when somebody works out the indentation to use calculated @@ -381,10 +412,74 @@ ;; Love those free variable references!! lisp-indent-error-function 'common-lisp-indent-function m)) + +;; Lambda-list indentation is now done in LISP-INDENT-LAMBDA-LIST. +;; See also `lisp-lambda-list-keyword-alignment', +;; `lisp-lambda-list-keyword-parameter-alignment' and +;; `lisp-lambda-list-keyword-parameter-indentation' -- dvl + +(defvar lisp-indent-lambda-list-keywords-regexp + "&\\(\ +optional\\|rest\\|key\\|allow-other-keys\\|aux\\|whole\\|body\\|environment\ +\\)\\([ \t]\\|$\\)" + "Regular expression matching lambda-list keywords.") + +(defun lisp-indent-lambda-list + (indent-point sexp-column containing-form-start) + (let (limit) + (cond ((save-excursion + (goto-char indent-point) + (beginning-of-line) + (skip-chars-forward " \t") + (setq limit (point)) + (looking-at lisp-indent-lambda-list-keywords-regexp)) + ;; We're facing a lambda-list keyword. + (if lisp-lambda-list-keyword-alignment + ;; Align to the first keyword if any, or to the beginning of + ;; the lambda-list. + (save-excursion + (goto-char containing-form-start) + (save-match-data + (if (re-search-forward + lisp-indent-lambda-list-keywords-regexp + limit t) + (progn + (goto-char (match-beginning 0)) + (current-column)) + (1+ sexp-column)))) + ;; Align to the beginning of the lambda-list. + (1+ sexp-column))) + (t + ;; Otherwise, align to the first argument of the last lambda-list + ;; keyword, the keyword itself, or the beginning of the + ;; lambda-list. + (save-excursion + (goto-char indent-point) + (forward-line -1) + (end-of-line) + (save-match-data + (if (re-search-backward lisp-indent-lambda-list-keywords-regexp + containing-form-start t) + (let* ((keyword-posn + (progn + (goto-char (match-beginning 0)) + (current-column))) + (indented-keyword-posn + (+ keyword-posn + lisp-lambda-list-keyword-parameter-indentation))) + (goto-char (match-end 0)) + (skip-chars-forward " \t") + (if (eolp) + indented-keyword-posn + (if lisp-lambda-list-keyword-parameter-alignment + (current-column) + indented-keyword-posn))) + (1+ sexp-column)))))))) + ;; Blame the crufty control structure on dynamic scoping ;; -- not on me! -(defun lisp-indent-259 (method path state indent-point - sexp-column normal-indent) +(defun lisp-indent-259 + (method path state indent-point sexp-column normal-indent) (catch 'exit (let ((p path) (containing-form-start (elt state 1)) @@ -452,8 +547,14 @@ (cond ((null p) (list (+ sexp-column 4) containing-form-start)) ((null (cdr p)) - (+ sexp-column 1)) - (t normal-indent)))) + ;; Indentation within a lambda-list. -- dvl + (list (lisp-indent-lambda-list + indent-point + sexp-column + containing-form-start) + containing-form-start)) + (t + normal-indent)))) ((integerp tem) (throw 'exit (if (null p) ;not in subforms @@ -523,19 +624,26 @@ path state indent-point sexp-column normal-indent))) -(defun lisp-indent-defmethod (path state indent-point sexp-column - normal-indent) - "Indentation function defmethod." - (lisp-indent-259 (if (and (>= (car path) 3) - (null (cdr path)) - (save-excursion (goto-char (elt state 1)) - (forward-char 1) - (forward-sexp 3) - (backward-sexp) - (looking-at ":\\|\\sw+"))) - '(4 4 (&whole 4 &rest 4) &body) - (get 'defun 'common-lisp-indent-function)) - path state indent-point sexp-column normal-indent)) +;; LISP-INDENT-DEFMETHOD now supports the presence of more than one method +;; qualifier and indents the method's lambda list properly. -- dvl +(defun lisp-indent-defmethod + (path state indent-point sexp-column normal-indent) + (lisp-indent-259 + (let ((nqual 0)) + (if (and (>= (car path) 3) + (save-excursion + (beginning-of-defun) + (forward-char 1) + (forward-sexp 2) + (skip-chars-forward " \t\n") + (while (looking-at "\\sw\\|\\s_") + (incf nqual) + (forward-sexp) + (skip-chars-forward " \t\n")) + (> nqual 0))) + (append '(4) (make-list nqual 4) '(&lambda &body)) + (get 'defun 'common-lisp-indent-function))) + path state indent-point sexp-column normal-indent)) (defun lisp-indent-function-lambda-hack (path state indent-point @@ -577,6 +685,7 @@ (define-modify-macro (4 &lambda &body)) (defsetf (4 &lambda 4 &body)) (defun (4 &lambda &body)) + (defgeneric (4 &lambda &body)) (define-setf-method . defun) (define-setf-expander . defun) (defmacro . defun) --=-=-= -- Resistance is futile. You will be jazzimilated. Scientific site: http://www.lrde.epita.fr/~didier Music (Jazz) site: http://www.didierverna.com --=-=-=--