From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Barry OReilly Newsgroups: gmane.emacs.devel Subject: [RFC] Editing Lisp through changing indentation Date: Thu, 18 Jul 2013 23:23:47 -0400 Message-ID: NNTP-Posting-Host: plane.gmane.org Mime-Version: 1.0 Content-Type: multipart/alternative; boundary=001a11c2e1dad0197c04e1d4da98 X-Trace: ger.gmane.org 1374204234 26284 80.91.229.3 (19 Jul 2013 03:23:54 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Fri, 19 Jul 2013 03:23:54 +0000 (UTC) To: emacs-devel@gnu.org Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Fri Jul 19 05:23:57 2013 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by plane.gmane.org with esmtp (Exim 4.69) (envelope-from ) id 1V01IR-0002P6-Gc for ged-emacs-devel@m.gmane.org; Fri, 19 Jul 2013 05:23:55 +0200 Original-Received: from localhost ([::1]:43351 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1V01IQ-0004Cx-Sm for ged-emacs-devel@m.gmane.org; Thu, 18 Jul 2013 23:23:54 -0400 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:46838) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1V01IM-0004Cq-BO for emacs-devel@gnu.org; Thu, 18 Jul 2013 23:23:53 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1V01IK-0003wb-Aw for emacs-devel@gnu.org; Thu, 18 Jul 2013 23:23:50 -0400 Original-Received: from mail-ob0-x22e.google.com ([2607:f8b0:4003:c01::22e]:57501) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1V01IK-0003wU-20 for emacs-devel@gnu.org; Thu, 18 Jul 2013 23:23:48 -0400 Original-Received: by mail-ob0-f174.google.com with SMTP id wd20so4648973obb.19 for ; Thu, 18 Jul 2013 20:23:47 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:date:message-id:subject:from:to:content-type; bh=koSPOc758V19aerFeJ21WX3BYCikG2itFL14l3N+O9A=; b=Ra6aL20DwhlvAAWf3rSnSDdeYUw9SRDaIpIU2nap4YDdxPmKMatDwpu4HKsWHVZbpm cVzZwzoHwmwMj/H+5IK2YfVYbCp9qWyhYqD37oyacL5mN5nuUXESp1ZBeNpl2wCJ3gRV z0N1DN3vaXYurrgrceVByNg2ho9x2+XQ7ACo+gURlP1oQl9QeKCKrfImYUseoZOaGvSD vhoVr+z7g2VxBHAeIyNKzeesB8BO1I0JzOaQWEJLbp/E4hJZjXZiil98ZjviWdhnBKEI e0D0kxPf5HlQcj1zve0PFSTBpYqo7/Lu3B8JinO9TQorfU41cjdZfHn9gsj6taoYQzxt WJIQ== X-Received: by 10.60.44.10 with SMTP id a10mr13735003oem.10.1374204227228; Thu, 18 Jul 2013 20:23:47 -0700 (PDT) Original-Received: by 10.76.122.79 with HTTP; Thu, 18 Jul 2013 20:23:47 -0700 (PDT) X-detected-operating-system: by eggs.gnu.org: Error: Malformed IPv6 address (bad octet value). X-Received-From: 2607:f8b0:4003:c01::22e 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:162007 Archived-At: --001a11c2e1dad0197c04e1d4da98 Content-Type: text/plain; charset=ISO-8859-1 To follow up on [1], I implemented some commands to demonstrate my idea for editing Lisp. The motivating idea is this: When reading Lisp, I find I pay attention to open parens (because foo is not (foo) is not ((foo))) and just the close parens whose opener is on the same line. When a sexp spans more than one line, I deduce the close paren from indentation. If that's how we read Lisp, then why not edit Lisp that way: change the indentation and let the close parens adjust themselves to be consistent. This would create an editing experience somewhat like python-mode. There are differences because lisp-mode knows a bit more due to existing parens. In the code to follow, I need to address the TODO items as well as your welcome feedback at this stage. To try it out on some Lisp code: M-x lisp-indent-adjust-sexps M-x lisp-dedent-adjust-sexps [1] http://lists.gnu.org/archive/html/help-gnu-emacs/2013-07/msg00177.html (defun last-sexp-with-relative-depth (from-pos to-pos rel-depth) "Parsing sexps from FROM-POS (inclusive) to TO-POS (exclusive), return the position of the last sexp that had depth REL-DEPTH relative to FROM-POS. Returns nil if REL-DEPTH is not reached. Examples: Region: a (b c (d)) e (f g (h i)) j Evaluate: (last-sexp-with-relative-depth pos-a (1+ pos-j) 0) Returns: position of j Evaluate: (last-sexp-with-relative-depth pos-a (1+ pos-j) -1) Returns: position of (h i) This function assumes FROM-POS is not in a string or comment." (save-excursion (goto-char from-pos) (let (the-last-pos (parse-state '(0 nil nil nil nil nil nil nil nil))) (while (< (point) to-pos) (setq parse-state (parse-partial-sexp (point) to-pos nil t ; Stop before sexp parse-state)) (and (not (eq (point) to-pos)) (eq (car parse-state) rel-depth) (setq the-last-pos (point))) ;; The previous parse may not advance. To advance and maintain ;; correctness of depth, we parse over the next char. (setq parse-state (parse-partial-sexp (point) (1+ (point)) nil nil parse-state))) the-last-pos))) (defun adjust-close-paren-for-indent (num-close-parens) "Adjust NUM-CLOSE-PARENS number of close parentheses of a sexp so as lisp-indent-adjust-sexps can indent that many levels. [TODO: Reword paragraph when num-close-parens implemented.] If a close paren was moved, returns a two element list of positions: where the close paren was moved from and the position following where it moved to. This allows the caller to know what region potentially needs reindentation. If no close parens were moved, returns nil." (save-excursion (let ((deleted-paren-pos (save-excursion (beginning-of-line) (backward-sexp) ;; If the sexp at point is a list, ;; delete its closing paren (when (eq (scan-lists (point) 1 0) (scan-sexps (point) 1)) (forward-sexp) (delete-char -1) (point))))) (when deleted-paren-pos (let ((sexp-to-close (last-sexp-with-relative-depth (point) (progn (end-of-line) (point)) 0))) (when sexp-to-close (goto-char sexp-to-close) (forward-sexp)) ;; Note: when no sexp-to-close found, line is empty. So put ;; close paren after point. (insert ")") (list deleted-paren-pos (point))))))) ;; TODO: When the code settles, consider consolidating with ;; adjust-close-paren-for-indent (defun adjust-close-paren-for-dedent (num-close-parens) (save-excursion (let ((deleted-paren-pos (save-excursion (when (< (point) (progn (up-list) (point))) (delete-char -1) (point))))) (when deleted-paren-pos (let ((sexp-to-close (progn (backward-sexp) (point)))) (when sexp-to-close (goto-char sexp-to-close) (forward-sexp)) ;; Note: when no sexp-to-close found, line is empty. So put ;; close paren after point. (insert ")") ;; The insertion makes deleted-paren-pos off by 1 (list (1+ deleted-paren-pos) (point))))))) ;; TODO: Look into how to hook into indent-for-tab-command ;; TODO: Take a region interactively: Example of expected region ;; behavior ({} indicates region boundaries) ;; (let ((x 10) (y (some-func 20))) ;; { (a 1) ;; (b 2))} ;; becomes: ;; (let ((x 10) (y (some-func 20)) ;; (a 1) ;; (b 2))) ;; TODO: Process the prefix arg: indent that many levels, negative to ;; mean dedent ;; TODO: Write tests (defun lisp-indent-adjust-sexps (&optional prefix-arg) "Indent Lisp code to the next level while adjusting sexp balanced expressions to be consistent. Not intended for assignment to the indent-line-function variable. " (interactive "P") (let ((orig-pos (point))) (back-to-indentation) (if (> orig-pos (point)) ;; Effectively don't do anything so as to not obstruct TAB ;; completion (goto-char orig-pos) (let ((close-paren-movement (adjust-close-paren-for-indent prefix-arg))) (when close-paren-movement (apply 'indent-region close-paren-movement) ;; Like indent-for-tab-command, this command will leave ;; point at "back to indentation". This call is necessary ;; because indent-region's save-excursion marker can get ;; moved to the beginning of line due to how the indentation ;; whitespace is inserted. (back-to-indentation)))))) ;; TODO: Investigate how to invoke this with DEL key and get old DEL ;; behavior when not dedenting (ie not in the indentation). Introduce ;; a dedent-for-del-command? ;; Note: Dedent will not take a region because: ;; - Don't want to conflict with delete-selection-mode ;; - Doesn't need it as much as indent with TAB does ;; TODO: Fix duplication when the code settles more (defun lisp-dedent-adjust-sexps (&optional prefix-arg) (interactive "P") (let ((orig-pos (point))) (back-to-indentation) (if (> orig-pos (point)) ;; Effectively don't do anything, hope to allow ordinary DEL (goto-char orig-pos) (let ((close-paren-movement (adjust-close-paren-for-dedent prefix-arg))) (when close-paren-movement (apply 'indent-region (nreverse close-paren-movement)) (back-to-indentation)))))) --001a11c2e1dad0197c04e1d4da98 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable To follow up on [1], I implemented some commands to demonstrate my idea for= editing Lisp.

The motivating idea is this: When reading Lisp, I fin= d I pay attention to open parens (because foo is not (foo) is not ((foo))) = and just the close parens whose opener is on the same line. When a sexp spa= ns more than one line, I deduce the close paren from indentation. If that&#= 39;s how we read Lisp, then why not edit Lisp that way: change the indentat= ion and let the close parens adjust themselves to be consistent.

This would create an editing experience somewhat like python-mode. Ther= e are differences because lisp-mode knows a bit more due to existing parens= .

In the code to follow, I need to address the TODO items as well as= your welcome feedback at this stage.

To try it out on some Lisp code:
=A0 M-x lisp-indent-adjust-sexps=A0 M-x lisp-dedent-adjust-sexps

[1] http://lists.gnu.org/a= rchive/html/help-gnu-emacs/2013-07/msg00177.html

(defun last-sexp-with= -relative-depth (from-pos to-pos rel-depth)
=A0 "Parsing sexps from= FROM-POS (inclusive) to TO-POS (exclusive),
return the position of the = last sexp that had depth REL-DEPTH relative
to FROM-POS. Returns nil if REL-DEPTH is not reached.

Examples:
= =A0 Region:=A0=A0 a (b c (d)) e (f g (h i)) j

=A0 Evaluate: (last-se= xp-with-relative-depth pos-a (1+ pos-j) 0)
=A0 Returns:=A0 position of j=

=A0 Evaluate: (last-sexp-with-relative-depth pos-a (1+ pos-j) -1) =A0 Returns:=A0 position of (h i)

This function assumes FROM-POS is = not in a string or comment."
=A0 (save-excursion
=A0=A0=A0 (goto= -char from-pos)
=A0=A0=A0 (let (the-last-pos
=A0=A0=A0=A0=A0=A0=A0=A0= =A0 (parse-state '(0 nil nil nil nil nil nil nil nil)))
=A0=A0=A0=A0=A0 (while (< (point) to-pos)
=A0=A0=A0=A0=A0=A0=A0 (setq= parse-state
=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 (parse-partial-sexp= (point)
=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 to-pos
=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 ni= l
=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 t ; Stop before sexp
=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0 parse-state))
=A0=A0=A0=A0=A0=A0=A0 (and (not (= eq (point) to-pos))
=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 (eq (car parse-= state) rel-depth)
=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 (setq the-last-po= s (point)))
=A0=A0=A0=A0=A0=A0=A0 ;; The previous parse may not advance.= To advance and maintain
=A0=A0=A0=A0=A0=A0=A0 ;; correctness of depth, we parse over the next char.=
=A0=A0=A0=A0=A0=A0=A0 (setq parse-state
=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0 (parse-partial-sexp (point)
=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 (1+ (= point))
=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 nil
=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0 nil
=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 parse-state)))=A0=A0=A0=A0=A0 the-last-pos)))

(defun adjust-close-paren-for-inden= t (num-close-parens)
=A0 "Adjust NUM-CLOSE-PARENS number of close p= arentheses of a sexp so as
lisp-indent-adjust-sexps can indent that many levels.

=A0[TODO: Rewo= rd paragraph when num-close-parens implemented.]
If a close paren was mo= ved, returns a two element list of positions:
where the close paren was = moved from and the position following where
it moved to. This allows the caller to know what region potentially
need= s reindentation.

If no close parens were moved, returns nil."=A0 (save-excursion
=A0=A0=A0 (let ((deleted-paren-pos
=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0 (save-excursion
=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 (beginning-of-line)
=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0 (backward-sexp)
=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0 ;; If the sexp at point is a list,
=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0 ;; delete its closing paren
=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 (wh= en (eq (scan-lists (point) 1 0)
=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0 (scan-sexps (point) 1))
=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 (forward-sexp)
=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 (delete-char -1)
=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0 (point)))))
=A0=A0=A0=A0=A0 (when deleted-paren-pos=A0=A0=A0=A0=A0=A0=A0 (let ((sexp-to-close
=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0 (last-sexp-with-relative-depth (point)
=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 (progn (end-of-line)
=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0 (point))
=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0 0)))
=A0=A0=A0=A0=A0=A0=A0=A0=A0 (when sexp-to-close
=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0 (goto-char sexp-to-close)
=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0 (forward-sexp))
=A0=A0=A0=A0=A0=A0=A0=A0=A0 ;; Note: when no sexp-to-close found, line is e= mpty. So put
=A0=A0=A0=A0=A0=A0=A0=A0=A0 ;; close paren after point.
= =A0=A0=A0=A0=A0=A0=A0=A0=A0 (insert ")")
=A0=A0=A0=A0=A0=A0=A0= =A0=A0 (list deleted-paren-pos (point)))))))

;; TODO: When the code = settles, consider consolidating with
;; adjust-close-paren-for-indent
(defun adjust-close-paren-for-dedent (n= um-close-parens)
=A0 (save-excursion
=A0=A0=A0 (let ((deleted-paren-p= os
=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 (save-excursion
=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0 (when (< (point)
=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 (progn (up-list)
=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0 (point)))
=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 (delete-c= har -1)
=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 (point)))))
=A0=A0= =A0=A0=A0 (when deleted-paren-pos
=A0=A0=A0=A0=A0=A0=A0 (let ((sexp-to-c= lose
=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 (progn
=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 (backward-sexp)
=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 (point))))
=A0=A0=A0=A0= =A0=A0=A0=A0=A0 (when sexp-to-close
=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 (g= oto-char sexp-to-close)
=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 (forward-sexp)= )
=A0=A0=A0=A0=A0=A0=A0=A0=A0 ;; Note: when no sexp-to-close found, line= is empty. So put
=A0=A0=A0=A0=A0=A0=A0=A0=A0 ;; close paren after point= .
=A0=A0=A0=A0=A0=A0=A0=A0=A0 (insert ")")
=A0=A0=A0=A0=A0=A0=A0= =A0=A0 ;; The insertion makes deleted-paren-pos off by 1
=A0=A0=A0=A0=A0= =A0=A0=A0=A0 (list (1+ deleted-paren-pos)
=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0 (point)))))))

;; TODO: Look into how to hook into in= dent-for-tab-command
;; TODO: Take a region interactively: Example of expected region
;; beha= vior ({} indicates region boundaries)
;;=A0=A0=A0=A0 (let ((x 10) (y (so= me-func 20)))
;; {=A0=A0=A0=A0 (a 1)
;;=A0=A0=A0=A0=A0=A0 (b 2))}
= ;; becomes:
;;=A0=A0=A0=A0 (let ((x 10) (y (some-func 20))
;;=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 (a 1)
;;=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 = (b 2)))
;; TODO: Process the prefix arg: indent that many levels, negati= ve to
;; mean dedent
;; TODO: Write tests
(defun lisp-indent-adjus= t-sexps (&optional prefix-arg)
=A0 "Indent Lisp code to the next level while adjusting sexp balanced<= br>expressions to be consistent.

Not intended for assignment to the = indent-line-function variable. "
=A0 (interactive "P") =A0 (let ((orig-pos (point)))
=A0=A0=A0 (back-to-indentation)
=A0=A0= =A0 (if (> orig-pos (point))
=A0=A0=A0=A0=A0=A0=A0 ;; Effectively don= 't do anything so as to not obstruct TAB
=A0=A0=A0=A0=A0=A0=A0 ;; co= mpletion
=A0=A0=A0=A0=A0=A0=A0 (goto-char orig-pos)
=A0=A0=A0=A0=A0 (let ((close-paren-movement
=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0 (adjust-close-paren-for-indent prefix-arg)))
=A0=A0=A0=A0=A0= =A0=A0 (when close-paren-movement
=A0=A0=A0=A0=A0=A0=A0=A0=A0 (apply = 9;indent-region close-paren-movement)
=A0=A0=A0=A0=A0=A0=A0=A0=A0 ;; Lik= e indent-for-tab-command, this command will leave
=A0=A0=A0=A0=A0=A0=A0=A0=A0 ;; point at "back to indentation". Th= is call is necessary
=A0=A0=A0=A0=A0=A0=A0=A0=A0 ;; because indent-regio= n's save-excursion marker can get
=A0=A0=A0=A0=A0=A0=A0=A0=A0 ;; mov= ed to the beginning of line due to how the indentation
=A0=A0=A0=A0=A0=A0=A0=A0=A0 ;; whitespace is inserted.
=A0=A0=A0=A0=A0= =A0=A0=A0=A0 (back-to-indentation))))))

;; TODO: Investigate how to = invoke this with DEL key and get old DEL
;; behavior when not dedenting = (ie not in the indentation). Introduce
;; a dedent-for-del-command?
;; Note: Dedent will not take a region beca= use:
;;=A0=A0 - Don't want to conflict with delete-selection-mode;;=A0=A0 - Doesn't need it as much as indent with TAB does
;; TODO:= Fix duplication when the code settles more
(defun lisp-dedent-adjust-sexps (&optional prefix-arg)
=A0 (interact= ive "P")
=A0 (let ((orig-pos (point)))
=A0=A0=A0 (back-to-i= ndentation)
=A0=A0=A0 (if (> orig-pos (point))
=A0=A0=A0=A0=A0=A0= =A0 ;; Effectively don't do anything, hope to allow ordinary DEL
=A0=A0=A0=A0=A0=A0=A0 (goto-char orig-pos)
=A0=A0=A0=A0=A0 (let ((close-= paren-movement
=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 (adjust-close-paren-= for-dedent prefix-arg)))
=A0=A0=A0=A0=A0=A0=A0 (when close-paren-movemen= t
=A0=A0=A0=A0=A0=A0=A0=A0=A0 (apply 'indent-region (nreverse close-= paren-movement))
=A0=A0=A0=A0=A0=A0=A0=A0=A0 (back-to-indentation))))))

--001a11c2e1dad0197c04e1d4da98--