summaryrefslogtreecommitdiff
path: root/paredit.el
diff options
context:
space:
mode:
authorTaylor R Campbell <campbell@mumble.net>2008-09-28 13:32:48 +0000
committerTaylor R Campbell <campbell@mumble.net>2008-09-28 13:32:48 +0000
commit760ae70a9ddb23fe91cc5bf827e4205a00b17467 (patch)
treea7fdc32b2fe1685abb2a27676174c4a90d50cfbd /paredit.el
parentf349cc5f0bab2c2453a9642cd29d4fb6852cc124 (diff)
Changes for version 8.v8
- Added paredit-terminal-mode, which is like paredit-mode but which provides key bindings that work in terminals, while paredit-mode contains many (such as controlled brackets) that do not work in terminals. Thanks to Jorgen Schaefer for suggesting many of the terminal key bindings. - Exchanged RET and C-j: RET now inserts the fancy newline with auto- indentation, while C-j inserts a literal line feed. While this defies convention, and some people prefer not to do this, I have found that it is more convenient for RET to have the behaviour of the common case, where auto-indentation is desired, and for C-j to insert the uncommon exact, literal line feed. You can always customize the key bindings yourself, of course. - Rearranged arrow key bindings. - Implemented paredit-close-list-and-newline, which is like paredit-close-list followed by RET (paredit-newline); and M-" (paredit-close-string-and-newline), which is similar but for strings. The closing round bracket character now inserts the newline, while the meta modifier inhibits this. - Overhauled paredit-kill. - Extended slurpage and barfage to permit their operation across arbitrary depth changes. - Fixed bizarre bug with backward barfage. I apologize for the alliteration. - Fixed a number of other small bugs. - Prefixed `paredit-' to the remaining functions defined in the file that did not already have the prefix. - Defined backward-down-list, which for some reason is not provided by lisp.el, although up-list, down-list, & backward-up-list all are. (This is the sole exception to the above item. It deserves no prefix because it ought to be defined in lisp.el with this name anyway.) darcs-hash:20080928133248-00fcc-cff6c6ab1db5bb274d4b53bf702b99804dc33ebd
Diffstat (limited to 'paredit.el')
-rw-r--r--paredit.el554
1 files changed, 356 insertions, 198 deletions
diff --git a/paredit.el b/paredit.el
index 13bf99b..55fa97f 100644
--- a/paredit.el
+++ b/paredit.el
@@ -1,7 +1,7 @@
;;; -*- mode: emacs-lisp -*-
;;;;;; paredit: Parenthesis editing minor mode
-;;;;;; Version 7
+;;;;;; Version 8
;;; Taylor Campbell wrote this code; he places it in the public domain.
@@ -14,6 +14,12 @@
;;; Usually the ... will be lisp or scheme or both. Alternatively, you
;;; can manually toggle this mode with M-x paredit-mode.
;;;
+;;; This is written for GNU Emacs. It is known not to work in XEmacs.
+;;; The author wrote it with GNU Emacs 22.0.50, but it should work in
+;;; earlier versions as well. An alternative set of keybindings is
+;;; available in PAREDIT-TERMINAL-MODE that works in Emacs under Unix
+;;; terminals with the -nw option (implied or otherwise).
+;;;
;;; This mode changes the keybindings for (, ), and ", most notably;
;;; if you really, really want a literal one of those, use C-q.
;;;
@@ -54,46 +60,106 @@
;;; This assumes Unix-style LF line endings.
-(defconst paredit-version 7)
+(defconst paredit-version 8)
+
+(define-minor-mode paredit-mode
+ "Minor mode for pseudo-structurally editing Lisp code.
+Uses keybindings that will not work under a Unix terminal; see
+`paredit-terminal-mode' for an alternative set of keybindings that will
+work in `emacs -nw' running under a Unix terminal."
+ :lighter " Paredit"
+ (if (and paredit-mode paredit-terminal-mode)
+ (paredit-terminal-mode -1)))
+
+(define-minor-mode paredit-terminal-mode
+ "Minor mode for pseudo-structurally editing Lisp code.
+Uses alternative keybindings that work in `emacs -nw' running under
+Unix terminals."
+ :lighter " Paredit(nw)"
+ (if (and paredit-mode paredit-terminal-mode)
+ (paredit-mode -1)))
(defvar paredit-mode-map
(let ((keymap (make-sparse-keymap)))
- (define-key keymap "(" 'paredit-open-list)
- (define-key keymap ")" 'paredit-close-list)
- (define-key keymap "\"" 'paredit-doublequote)
- (define-key keymap "\\" 'paredit-backslash)
- (define-key keymap (kbd "C-j") 'paredit-newline)
+ (define-key keymap "(" 'paredit-open-list)
+ (define-key keymap ")" 'paredit-close-list-and-newline)
+ (define-key keymap (kbd "M-)") 'paredit-close-list)
+ (define-key keymap (kbd "M-\"") 'paredit-close-string-and-newline)
+ (define-key keymap "\"" 'paredit-doublequote)
+ (define-key keymap "\\" 'paredit-backslash)
+
+ ;; This defies ordinary conventions, but I believe it is justified
+ ;; and more convenient this way, to have RET be fancy and C-j
+ ;; insert a vanilla newline. You can always change this in your
+ ;; .emacs if you want the conventional configuration, however.
+ (define-key keymap (kbd "RET") 'paredit-newline)
+ (define-key keymap (kbd "C-j") 'newline)
(define-key keymap (kbd "C-d") 'paredit-forward-delete)
(define-key keymap (kbd "DEL") 'paredit-backward-delete)
(define-key keymap (kbd "C-k") 'paredit-kill)
- ;; C-up & C-down are by default useless paragraph commands, while
- ;; C-M-up & C-M-down are BACKWARD-UP-LIST & BACKWARD-DOWN-LIST.
- ;; C-left & C-right are by default word movement commands, but as
- ;; are M-left & M-right, so I think it's OK to override them.
- (define-key keymap (kbd "<C-up>") 'up-list)
- (define-key keymap (kbd "<C-down>") 'down-list)
- (define-key keymap (kbd "<C-right>") 'forward-sexp)
- (define-key keymap (kbd "<C-left>") 'backward-sexp)
-
- (define-key keymap (kbd "M-(") 'forward-wrap-sexp)
- (define-key keymap (kbd "M-)") 'backward-wrap-sexp)
- (define-key keymap (kbd "M-/") 'splice-sexp)
- (define-key keymap (kbd "M-\\") 'join-sexps)
-
- (define-key keymap (kbd "C-)") 'forward-slurp-sexp)
- (define-key keymap (kbd "C-}") 'forward-barf-sexp)
- (define-key keymap (kbd "C-(") 'backward-slurp-sexp)
- (define-key keymap (kbd "C-{") 'backward-barf-sexp)
+ ;; The default keybindings in this area are:
+ ;; C-up forward-paragraph
+ ;; C-down backward-paragraph
+ ;; C-M-up backward-up-list
+ ;; C-M-down down-list
+ ;; C-right M-right forward-word
+ ;; C-left M-left backward-word
+ ;; This all seems rather inconsistent to me. I'm not worried about
+ ;; overriding C-up & C-down here, because paragraph commands are
+ ;; not very useful in Lisp code, and C-left & C-right, because they
+ ;; already have aliases with meta instead of control.
+ ;;
+ ;; Chosen here is for C-up to go up a list backward (because that
+ ;; will usually mean going up a line, as one might logically expect
+ ;; with the up key), C-down to go down a list (forward, for a
+ ;; similar reason), an added meta to go in the other direction.
+ (define-key keymap (kbd "<C-up>") 'backward-up-list)
+ (define-key keymap (kbd "<C-down>") 'down-list)
+ (define-key keymap (kbd "<C-M-up>") 'up-list)
+ (define-key keymap (kbd "<C-M-down>") 'backward-down-list)
+ (define-key keymap (kbd "<C-right>") 'forward-sexp)
+ (define-key keymap (kbd "<C-left>") 'backward-sexp)
+
+ (define-key keymap (kbd "M-(") 'paredit-wrap-sexp)
+ (define-key keymap (kbd "M-/") 'paredit-splice-sexp)
+ (define-key keymap (kbd "M-\\") 'paredit-join-sexps)
+
+ (define-key keymap (kbd "C-)") 'paredit-forward-slurp-sexp)
+ (define-key keymap (kbd "C-}") 'paredit-forward-barf-sexp)
+ (define-key keymap (kbd "C-(") 'paredit-backward-slurp-sexp)
+ (define-key keymap (kbd "C-{") 'paredit-backward-barf-sexp)
keymap)
- "Keymap for the paredit minor mode.")
+ "Keymap for the paredit minor mode.
+Does not work in `emacs -nw' running under Unix terminals, only in
+Emacs with a window system.")
-(define-minor-mode paredit-mode
- "Minor mode for pseudo-structurally editing Lisp code."
- :lighter " Paredit")
+(defvar paredit-terminal-mode-map
+ (let ((keymap (make-sparse-keymap)))
+ (set-keymap-parent keymap paredit-mode-map)
+
+ ;; Bizarre terminal sequences for M-right, M-left, C-M-right, &
+ ;; C-M-left, respectively.
+ (define-key keymap (kbd "ESC <right>") 'paredit-forward-slurp-sexp)
+ (define-key keymap (kbd "ESC <left>") 'paredit-forward-barf-sexp)
+ (define-key keymap (kbd "ESC M-O d") 'paredit-backward-slurp-sexp)
+ (define-key keymap (kbd "ESC M-O c") 'paredit-backward-barf-sexp)
+
+ ;; Terminal sequences for C-up, C-down, C-M-left, & C-M-down,
+ ;; respectively. (These are the same as in the regular mode map,
+ ;; except that Emacs doesn't recognize the correlation between what
+ ;; the terminal sends it and what (KBD "<C-up>") &c. return.
+ (define-key keymap (kbd "ESC O a") 'backward-up-list)
+ (define-key keymap (kbd "ESC O b") 'down-list)
+ (define-key keymap (kbd "ESC M-O a") 'up-list)
+ (define-key keymap (kbd "ESC M-O b") 'backward-down-list)
+
+ keymap)
+ "Keymap for the paredit minor mode.
+Works in `emacs -nw' running under Unix terminals.")
@@ -125,13 +191,34 @@ unintentionally."
(insert ")"))
((not (paredit-in-char-p))
(paredit-move-past-close-and-reindent)
- (if blink-matching-paren
- (condition-case nil
- (save-excursion
- (backward-sexp)
- (forward-sexp)
- (blink-matching-open))
- (scan-error nil))))))
+ (paredit-blink-paren-match nil))))
+
+(defun paredit-close-list-and-newline ()
+ "Moves past one closing delimiter, adds a newline, and reindents."
+ (interactive)
+ (cond ((or (paredit-in-string-p)
+ (paredit-in-comment-p))
+ (insert ")"))
+ (t (if (paredit-in-char-p) (forward-char))
+ (paredit-move-past-close-and-reindent)
+ (insert ?\n )
+ (lisp-indent-line)
+ (condition-case () (indent-sexp)
+ (scan-error nil))
+ (paredit-blink-paren-match t))))
+
+(defun paredit-close-string-and-newline ()
+ "Moves to the end of the string, inserts a newline, and indents.
+If not in a string, acts as `paredit-doublequote'."
+ (interactive)
+ (if (not (paredit-in-string-p))
+ (paredit-doublequote)
+ (let ((start+end (paredit-string-start+end-points)))
+ (goto-char (1+ (cdr start+end)))
+ (insert ?\n )
+ (lisp-indent-line)
+ (condition-case () (indent-sexp)
+ (scan-error nil)))))
(defun paredit-move-past-close-and-reindent ()
"Moves one character past the next closing parenthesis.
@@ -142,7 +229,7 @@ line after the comment and indented appropriately."
(interactive)
(let ((orig (point)))
(up-list)
- (if (catch 'exit ; This CATCH returns T if it
+ (if (catch 'return ; This CATCH returns T if it
(while t ; should delete leading spaces
(save-excursion ; and NIL if not.
(let ((before-paren (1- (point))))
@@ -151,7 +238,7 @@ line after the comment and indented appropriately."
;; Can't call PAREDIT-DELETE-LEADING-WHITESPACE
;; here -- we must return from SAVE-EXCURSION
;; first.
- (throw 'exit t))
+ (throw 'return t))
((save-excursion (previous-line)
(end-of-line)
(paredit-in-comment-p))
@@ -161,18 +248,25 @@ line after the comment and indented appropriately."
;; and abort the loop, telling its continuation
;; that no leading whitespace should be deleted.
(lisp-indent-line)
- (throw 'exit nil))
+ (throw 'return nil))
(t (delete-indentation)))))))
- (paredit-delete-leading-whitespace)))
- (condition-case nil (indent-sexp)
- (scan-error nil)))
+ (paredit-delete-leading-whitespace))))
+
+(defun paredit-blink-paren-match (absolutely-p)
+ (if (or absolutely-p blink-matching-paren)
+ (condition-case ()
+ (save-excursion
+ (backward-sexp)
+ (forward-sexp)
+ (blink-matching-open))
+ (scan-error nil))))
(defun paredit-delete-leading-whitespace ()
;; This assumes that we're on the closing parenthesis already.
(save-excursion
(backward-char)
(while (let ((syn (char-syntax (char-before))))
- (and (or (eq syn ?\ ) (eq syn ?-)) ; whitespace syntax
+ (and (or (eq syn ?\ ) (eq syn ?-)) ; whitespace syntax
;; The above line is a perfect example of why the
;; following test is necessary.
(not (paredit-in-char-p (1- (point))))))
@@ -254,7 +348,7 @@ Moves forward one character first if on an escaped character."
;; Indent the following S-expression, but don't signal an error if
;; there's only a closing parenthesis after the point, not a full
;; S-expression.
- (condition-case nil (indent-sexp)
+ (condition-case () (indent-sexp)
(scan-error nil)))
(defun paredit-forward-delete (&optional arg)
@@ -266,33 +360,32 @@ S-expression is empty, in which case the whole S-expression is deleted.
With a prefix argument, simply deletes a character forward, without
regard for delimiter balancing."
(interactive "P")
- (if arg ; I'd pass the argument to DELETE-CHAR,
- (delete-char 1) ; but I don't know how to do it right.
- (cond ((paredit-in-string-p)
- (paredit-forward-delete-in-string))
- ((paredit-in-comment-p)
- ;++ What to do here? This could move a partial S-expression
- ;++ into a comment and thereby invalidate the file's form,
- ;++ or move random text out of a comment.
- (delete-char 1))
- ((paredit-in-char-p) ; Escape -- delete both chars.
- (backward-delete-char 1)
- (delete-char 1))
- ((eq (char-after) ?\\ ) ; ditto
- (delete-char 2))
- ((or (eq (char-after) ?\( )
- (eq (char-after) ?\" ))
- (forward-char))
- ((and (eq (char-before) ?\( )
- (not (paredit-in-char-p (1- (point))))
- (eq (char-after) ?\) ))
- (backward-delete-char 1)
- (delete-char 1))
- ;; Just delete a single character, if it's not a closing
- ;; parenthesis. (The character literal case is already
- ;; handled by now.)
- ((not (eq (char-after) ?\) ))
- (delete-char 1)))))
+ (cond (arg (delete-char 1)) ; I'd pass the arg if I knew how.
+ ((paredit-in-string-p)
+ (paredit-forward-delete-in-string))
+ ((paredit-in-comment-p)
+ ;++ What to do here? This could move a partial S-expression
+ ;++ into a comment and thereby invalidate the file's form,
+ ;++ or move random text out of a comment.
+ (delete-char 1))
+ ((paredit-in-char-p) ; Escape -- delete both chars.
+ (backward-delete-char 1)
+ (delete-char 1))
+ ((eq (char-after) ?\\ ) ; ditto
+ (delete-char 2))
+ ((or (eq (char-after) ?\( )
+ (eq (char-after) ?\" ))
+ (forward-char))
+ ((and (eq (char-before) ?\( )
+ (not (paredit-in-char-p (1- (point))))
+ (eq (char-after) ?\) ))
+ (backward-delete-char 1)
+ (delete-char 1))
+ ;; Just delete a single character, if it's not a closing
+ ;; parenthesis. (The character literal case is already
+ ;; handled by now.)
+ ((not (eq (char-after) ?\) ))
+ (delete-char 1))))
(defun paredit-forward-delete-in-string ()
(let ((start+end (paredit-string-start+end-points)))
@@ -326,31 +419,30 @@ S-expression is empty, in which case the whole S-expression is deleted.
With a prefix argument, simply deletes a character backward, without
regard for delimiter balancing."
(interactive "P")
- (if arg
- (backward-delete-char 1) ;++ should this untabify?
- (cond ((paredit-in-string-p)
- (paredit-backward-delete-in-string))
- ((paredit-in-comment-p)
- (backward-delete-char 1))
- ((paredit-in-char-p) ; Escape -- delete both chars.
- (backward-delete-char 1)
- (delete-char 1))
- ((paredit-in-char-p (1- (point)))
- (backward-delete-char 2)) ; ditto
- ((and (or (eq (char-before) ?\) )
- (eq (char-before) ?\" ))
- (not (paredit-in-char-p (1- (point)))))
- (backward-char))
- ;++ This should test more thoroughly, e.g. for ( ).
- ((and (eq (char-before) ?\( )
- (not (paredit-in-char-p (1- (point))))
- (eq (char-after) ?\) ))
- (backward-delete-char 1)
- (delete-char 1))
- ;; Delete it, unless it's an opening parenthesis. The case
- ;; of character literals is already handled by now.
- ((not (eq (char-before) ?\( ))
- (backward-delete-char-untabify 1)))))
+ (cond (arg (backward-delete-char 1)) ;++ should this untabify?
+ ((paredit-in-string-p)
+ (paredit-backward-delete-in-string))
+ ((paredit-in-comment-p)
+ (backward-delete-char 1))
+ ((paredit-in-char-p) ; Escape -- delete both chars.
+ (backward-delete-char 1)
+ (delete-char 1))
+ ((paredit-in-char-p (1- (point)))
+ (backward-delete-char 2)) ; ditto
+ ((and (or (eq (char-before) ?\) )
+ (eq (char-before) ?\" ))
+ (not (paredit-in-char-p (1- (point)))))
+ (backward-char))
+ ;++ This should test more thoroughly, e.g. for ( ).
+ ((and (eq (char-before) ?\( )
+ (not (paredit-in-char-p (1- (point))))
+ (eq (char-after) ?\) ))
+ (backward-delete-char 1)
+ (delete-char 1))
+ ;; Delete it, unless it's an opening parenthesis. The case
+ ;; of character literals is already handled by now.
+ ((not (eq (char-before) ?\( ))
+ (backward-delete-char-untabify 1))))
(defun paredit-backward-delete-in-string ()
(let ((start+end (paredit-string-start+end-points)))
@@ -375,57 +467,114 @@ regard for delimiter balancing."
(backward-delete-char 1)
(delete-char 1)))))
-(defun paredit-kill ()
- "Kills a line or S-expression.
-If an S-expression starts on the same line as the point, kills that
-S-expression; otherwise, behaves as `kill-line', except won't kill a
-closing string delimiter."
- (interactive)
- (cond ((paredit-in-string-p)
- (paredit-kill-in-string))
- ((or (eq (char-after) ?\n )
- (paredit-in-comment-p)
+(defun paredit-kill (&optional arg)
+ "Kills a line as if with `kill-line', but respecting delimiters.
+In a string, acts exactly as `kill-line' but will not kill past the
+closing string delimiter.
+On a line with no S-expressions on it starting after the point or
+within a comment, acts exactly as `kill-line'.
+Otherwise, kills all S-expressions that start after the point."
+ (interactive "P")
+ (cond (arg (kill-line))
+ ((paredit-in-string-p)
+ (paredit-kill-line-in-string))
+ ((or (paredit-in-comment-p)
(save-excursion
(skip-chars-forward " \t\n" (point-at-eol))
- (or (eq (point) (point-at-eol))
- (eq (char-after) ?\; ))))
- (if (eq (char-before (point-at-eol))
- ?\\ )
- ;++ This is a crock: we don't want to kill an incomplete
- ;++ escape sequence, so we include the newline. This
- ;++ won't work on the last line of the buffer, however, if
- ;++ it is not followed by one empty line.
- (progn (kill-region (point) (1+ (point-at-eol)))
- (insert ?\n ))
- (kill-line)))
- (t (kill-sexp))))
-
-(defun paredit-kill-in-string ()
- (if (eq (char-after) ?\n )
- ;; Delete the newline only if we're at the end of the line. (The
- ;; ordinary Emacs behaviour is to do this also if there's only
- ;; whitespace following, but I hate that behaviour.)
- (kill-region (point) (1+ (point)))
- ;; Skip ahead to the end of the line or the double-quote. Kill
- ;; that region.
+ (or (eq (char-after) ?\; )
+ (eolp))))
+ ;** Be careful about trailing backslashes.
+ (kill-line))
+ (t (paredit-kill-sexps-on-line))))
+
+(defun paredit-kill-line-in-string ()
+ (if (save-excursion (skip-chars-forward " \t\n" (point-at-eol))
+ (eolp))
+ (kill-line)
(save-excursion
- ;; Make sure not to split an escaped character sequence.
+ ;; Be careful not to split an escape sequence.
(if (paredit-in-string-escape-p)
(backward-char))
(let ((beg (point)))
- (while (not (memq (char-after) '(?\n ?\" )))
+ (while (not (or (eolp)
+ (eq (char-after) ?\" )))
(forward-char)
;; Skip past escaped characters.
(if (eq (char-before) ?\\ )
(forward-char)))
(kill-region beg (point))))))
+(defun paredit-kill-sexps-on-line ()
+ (if (paredit-in-char-p) ; Move past the \ and prefix.
+ (backward-char 2)) ; (# in Scheme/CL, ? in elisp)
+ (let ((beg (point))
+ (eol (point-at-eol))
+ (end-of-list-p nil))
+ ;; Move to the end of the last S-expression that started on this
+ ;; line, or to the closing delimiter if the last S-expression in
+ ;; this list is on the line.
+ (catch 'return
+ (while (save-excursion
+ (condition-case ()
+ (forward-sexp)
+ ;++ I wrote here:
+ ;++ ;++ THIS IS BROKEN -- FIX
+ ;++ But now I don't remember what was broken and needs
+ ;++ fixing. This whole thing, notably END-OF-LIST-P,
+ ;++ was a crock to fix a corner case that I also don't
+ ;++ remember now...
+ (scan-error
+ (up-list)
+ (setq end-of-list-p (eq (point-at-eol) eol))
+ (throw 'return nil)))
+ (and (not (eobp))
+ (progn (backward-sexp)
+ (eq (point-at-eol) eol))))
+ (forward-sexp)))
+ (if (not kill-whole-line)
+ (kill-region beg
+ ;; If all of the S-expressions were on one line,
+ ;; i.e. we're still on that line after moving past
+ ;; the last one, kill the whole line, including
+ ;; any comments; otherwise just kill to the end of
+ ;; the last S-expression we found. Be sure,
+ ;; though, not to kill any closing parentheses.
+ (if (and (not end-of-list-p)
+ (eq (point-at-eol) eol))
+ eol
+ (point)))
+ (kill-region beg
+ (or (save-excursion ; Delete indentation forward...
+ (skip-chars-forward " \n\t")
+ (and (not (eq (char-after) ?\; ))
+ (point)))
+ ;; ...or just use the point past the newline, if
+ ;; we encounter a comment.
+ (point-at-eol)))
+ (cond ((save-excursion (skip-chars-backward " \n\t"
+ (point-at-bol))
+ (bolp))
+ ;; Nothing but indentation before the point, so indent it.
+ (lisp-indent-line))
+ ;; If there is something before the point, make sure we
+ ;; don't join things that shouldn't be joined.
+ ((let ((syn-before (char-syntax (char-before)))
+ (syn-after (char-syntax (char-after))))
+ (or (and (eq syn-before ?\) ) ; Separate opposing
+ (eq syn-after ?\( )) ; parentheses,
+ (and (eq syn-before ?\" ) ; string delimiter
+ (eq syn-after ?\" )) ; pairs,
+ (and (memq syn-before '(?_ ?w)) ; or word or symbol
+ (memq syn-after '(?_ ?w))) ; constituents.
+ ))
+ (insert " "))))))
+
;;; ----------------
-;;; Wrappage, splicage, & joinage
+;;; Wrappage, splicage, joinage, & inversion
-(defun forward-wrap-sexp (&optional n)
+(defun paredit-wrap-sexp (&optional n)
"Wraps the following S-expression in a list.
If a prefix argument N is given, N S-expressions are contained in the
list.
@@ -434,16 +583,7 @@ Automatically indents the newly wrapped S-expression."
(insert-parentheses (or n 1))
(save-excursion (backward-up-list) (indent-sexp)))
-(defun backward-wrap-sexp (&optional n)
- "Wraps the preceding S-expression in a list.
-If a prefix argument N is given, N S-expressions are contained in the
-list.
-Automatically indents the newly wrapped S-expression."
- (interactive "p")
- (insert-parentheses (- (or n 1)))
- (save-excursion (backward-up-list) (indent-sexp)))
-
-(defun splice-sexp ()
+(defun paredit-splice-sexp ()
"Splices the list the point is on by removing its delimiters."
(interactive)
(save-excursion
@@ -455,7 +595,7 @@ Automatically indents the newly wrapped S-expression."
(backward-up-list) ; Reindent, now that the
(indent-sexp))) ; structure has changed.
-(defun join-sexps ()
+(defun paredit-join-sexps ()
"Joins two adjacent S-expressions into one S-expression."
(interactive)
(save-excursion
@@ -473,59 +613,63 @@ Automatically indents the newly wrapped S-expression."
;;; ----------------
;;; Slurpage & barfage
-(defun forward-slurp-sexp (&optional n)
+(defun paredit-forward-slurp-sexp ()
"Adds the S-expression following the current list into that list by
moving the closing delimiter.
-If a prefix argument N is given, N S-expressions are slurped into the
-current list.
Automatically reindents the newly slurped S-expressions with respect to
their new enclosing form."
- (interactive "p")
+ (interactive)
(save-excursion
(up-list) ; Up to the end of the list to
(let ((close (char-before))) ; save and delete the closing
(backward-delete-char 1) ; delimiter.
- (condition-case nil ; Go to the end of the last
- (paredit-forward-and-indent n); S-expression,
- (scan-error nil)) ; (ignoring going too far)
+ (catch 'return ; Go to the end of the desired
+ (while t ; S-expression, going up a
+ (condition-case () ; list if it's not in this,
+ (progn (paredit-forward-and-indent)
+ (throw 'return nil))
+ (scan-error (up-list)))))
(insert close)))) ; to insert that delimiter.
-(defun forward-barf-sexp (&optional n)
+(defun paredit-forward-barf-sexp ()
"Removes the last S-expression in the current list from that list by
moving the closing delimiter.
-If a prefix argument N is given, the last N S-expressions are barfed
-out of the current list.
Automatically reindents all of the newly barfed S-expressions with
respect to their new enclosing form."
- (interactive "p")
+ (interactive)
(save-excursion
(up-list) ; Up to the end of the list to
(let ((close (char-before))) ; save and delete the closing
(backward-delete-char 1) ; delimiter.
- (condition-case nil ; Go back to where we want to
- (backward-sexp n) ; insert the delimiter.
+ (condition-case () ; Go back to where we want to
+ (backward-sexp) ; insert the delimiter.
(scan-error nil)) ; Ignore scan errors, and
(skip-chars-backward " \t\n") ; skip leading whitespace.
- (if (bobp)
- (message "Barfing all subexpressions with no open-paren?"))
+ (cond ((bobp)
+ (message
+ "Barfing all subexpressions with no open-paren?"))
+ ((paredit-in-comment-p) ; Don't put the close-paren in
+ (newline-and-indent))) ; a comment.
(insert close))
;; Reindent all of the newly barfed S-expressions.
- (paredit-forward-and-indent n)))
+ (paredit-forward-and-indent)))
-(defun backward-slurp-sexp (&optional n)
+(defun paredit-backward-slurp-sexp ()
"Adds the S-expression preceding the current list into that list by
moving the closing delimiter.
-If a prefix argument N is given, N S-expressions are slurped into the
-current list.
-Automatically reindents the whole form into which new S-expressions
-were slurped."
- (interactive "p")
+Automatically reindents the whole form into which new S-expression was
+slurped."
+ (interactive)
(save-excursion
(backward-up-list)
(let ((open (char-after)))
(delete-char 1)
- (condition-case nil (backward-sexp n)
- (scan-error nil))
+ (catch 'return
+ (while t
+ (condition-case ()
+ (progn (backward-sexp)
+ (throw 'return nil))
+ (scan-error (backward-up-list)))))
(insert open))
;; Reindent the line at the beginning of wherever we inserted the
;; opening parenthesis, and then indent the whole S-expression.
@@ -533,27 +677,36 @@ were slurped."
(lisp-indent-line)
(indent-sexp)))
-(defun backward-barf-sexp (&optional n)
+(defun paredit-backward-barf-sexp ()
"Removes the first S-expression in the current list from that list by
moving the closing delimiter.
-If a prefix argument N is given, the first N S-expressions are barfed
-out of the current list.
-Automatically reindents all of the barfed S-expressions and the form
-from which they were barfed."
- (interactive "p")
- (save-excursion
- (backward-up-list)
- (let ((open (char-after)))
- (delete-char 1)
- (condition-case nil (paredit-forward-and-indent n)
- (scan-error nil))
- (skip-chars-forward " \t\n") ;++ should handle comments
- (if (eobp)
- (message "Barfing all subexpressions with no close-paren?"))
- (insert open))
- (backward-up-list)
- (lisp-indent-line)
- (indent-sexp)))
+Automatically reindents the barfed S-expression and the form from which
+it was barfed."
+ (interactive)
+ ;; SAVE-EXCURSION here does the wrong thing, but manually saving and
+ ;; restoring the point does the right thing. Here's an example of
+ ;; how SAVE-EXCURSION breaks:
+ ;; (foo|) C-{
+ ;; foo|()
+ ;; It should be:
+ ;; foo(|)
+ (let ((beg (point)))
+ (unwind-protect
+ (progn
+ (backward-up-list)
+ (let ((open (char-after)))
+ (delete-char 1)
+ (condition-case () (paredit-forward-and-indent)
+ (scan-error nil))
+ (skip-chars-forward " \t\n") ;++ should handle comments
+ (if (eobp)
+ (message
+ "Barfing all subexpressions with no close-paren?"))
+ (insert open))
+ (backward-up-list)
+ (lisp-indent-line)
+ (indent-sexp))
+ (goto-char beg))))
@@ -565,11 +718,9 @@ from which they were barfed."
(save-excursion
(let ((orig (point)))
(beginning-of-defun)
- ;; Item 3 of the list PARSE-PARTIAL-SEXP returns is the string
- ;; delimiter if the point at the second argument is in a string;
- ;; otherwise it's nil.
- (eq (nth 3 (parse-partial-sexp (point) orig))
- ?\" ))))
+ ;; Item 3 of the list PARSE-PARTIAL-SEXP returns is true if the
+ ;; point at the second argument is in a string, otherwise false.
+ (nth 3 (parse-partial-sexp (point) orig)))))
(defun paredit-string-start+end-points ()
"Returns a cons of the points of the open and quotes of this string.
@@ -626,16 +777,23 @@ and Common Lisp.)"
(not (eq (char-before (1- arg))
?\\ )))))
-(defun paredit-forward-and-indent (n)
- "Move forward N S-expressions, indenting them all fully with
+(defun paredit-forward-and-indent ()
+ "Move forward an S-expression, indenting it fully with both
`lisp-indent-line' and then `indent-sexp'."
- (while (< 0 n)
- (forward-sexp) ; Find the beginning of this
- (backward-sexp) ; next S-expression.
+ (forward-sexp) ; Go forward, and then find the
+ (save-excursion ; beginning of this next
+ (backward-sexp) ; S-expression.
(lisp-indent-line) ; Indent its opening line, and
- (indent-sexp) ; the rest of it.
- (forward-sexp) ; Advance past it.
- (setq n (1- n))))
+ (indent-sexp))) ; the rest of it.
+
+;;; Why is this not in lisp.el?
+
+(defun backward-down-list (&optional arg)
+ "Move backward and descend into one level of parentheses.
+With ARG, do this that many times.
+A negative argument means move forward but still descend a level."
+ (interactive "p")
+ (down-list (- (or arg 1))))