diff -w -U3 -w -U3 /Users/johnw/Library/Emacs/site-lisp/paredit.el /Users/johnw/Library/Emacs/paredit.el --- /Users/johnw/Library/Emacs/site-lisp/paredit.el 2007-10-14 04:25:16.000000000 -0400 +++ /Users/johnw/Library/Emacs/paredit.el 2007-10-20 18:33:44.000000000 -0400 @@ -1,11 +1,105 @@ ;;; -*- Mode: Emacs-Lisp; outline-regexp: " \n;;;;+" -*- ;;;;;; Paredit: Parenthesis-Editing Minor Mode -;;;;;; Version 20 +;;;;;; Version 21 -;;; This code is written by Taylor R. Campbell (except where explicitly -;;; noted) and placed in the Public Domain. All warranties are -;;; disclaimed. + +;;; The following changes have been made to the original paredit.el mode by +;;; Taylor R. Campbell: +;;; +;;; - M-r is changed to M-g, since I use M-r constantly to reposition my +;;; cursor, but I never used M-g in Lisp mode. Think of 'g' as in "grab". +;;; +;;; - C-c C-M-l is now C-c C-l. +;;; +;;; - TAB completes the current symbol, after reindenting the line. +;;; +;;; - ) inserts a closing parenthesis if there is no top-level balancing +;;; parenthesis. Example: +;;; (defun foo()| ; if you enter ) here, ) gets inserted +;;; +;;; - If you press backspace and the closing parenthesis before point has no +;;; matching parenthesis, it is deleted (in paredit, the cursor would just +;;; move past it). This and the previous change are meant to facilitate +;;; cutting and pasting where properly matched parentheses might end up +;;; missing. +;;; +;;; - The behaviors of ) and M-) are reversed by default. This means M-) +;;; reformats your code, but ) won't. +;;; +;;; - There are new sexp manipulation functions. It may take using them to +;;; get the hang of it, but the reason they were created is that I needed +;;; them so often and found myself doing a tons of other keystrokes just to +;;; emulate them. +;;; +;;; Before: C-( backward slurp foo (|bar) => (foo |bar) +;;; C-) forward slurp (|foo) bar => (|foo bar) +;;; C-{ backward barf (foo |bar) => foo (|bar) +;;; C-} forward barf (|foo bar) => (|foo) bar +;;; +;;; Added: C-M-( backward join (foo) |bar => (foo |bar) +;;; C-M-) forward join |foo (bar) => (|foo bar) +;;; C-M-{ backward leave (|foo bar) => |foo (bar) +;;; C-M-} forward leave (foo |bar) => (foo) |bar +;;; +;;; C-M-, backward adopt (foo) (|bar) => (foo |bar) +;;; C-M-. forward adopt (|foo) (bar) => (|foo bar) +;;; C-M-< backward orphan (foo |bar) => (foo) (|bar) +;;; C-M-> forward orphan (|foo bar) => (|foo) (bar) +;;; +;;; One example of where backward joining comes in super handy: +;;; +;;; (let ((foo bar)) +;;; (some code)) +;;; (hello |) ; point is at the | +;;; +;;; Say you want is to reference `foo' in the call to `hello', so you need +;;; the hello form to be within the let form. Previously, this required +;;; typing: +;;; +;;; C-M-u C-M-k C-M-b C-M-n C-b RET C-y +;;; +;;; There are other key sequences that would be more efficient, surely, but +;;; that depends on context. If you think purely in terms of sexps, the +;;; above sequence always works. +;;; +;;; You can now accomplish all of this safely in this example by typing: +;;; +;;; C-M-( +;;; +;;; - New refactoring commands: +;;; +;;; C-c M-l refactor the current sexp into an enclosing let variable. +;;; with prefix arg, pull it out that many levels +;;; +;;; C-c M-f refactor the current sexp into an enclosing flet function. +;;; with prefix arg, pull it out that many levels +;;; +;;; C-c M-c convolute the current sexp outward. User is responsible +;;; for ensuring that this is a meaningful operation. It turns: +;;; +;;; (defun test-function () +;;; (let ((a "hello")) +;;; (while a| +;;; (hello-world)))) +;;; into: +;;; +;;; (defun test-function () +;;; |(while a +;;; (let ((a "hello")) +;;; (hello-world)))) +;;; +;;; By default, the body is extracted after the second inner +;;; element (after "while a"). Use a prefix argument to extract +;;; more, such as 3 with `multiple-value-bind'. +;;; +;;; - M-q is bound to `paredit-reindent-defun'. This calls the ordinary +;;; `fill-paragraph' if point is in a comment or string, otherwise it +;;; reindents the current defun. +;;; +;;; - The command `check-parens' is called after every save. This ensures you +;;; don't mistakenly save the file and then send it to the Lisp compiler +;;; expecting things to work. ;;; Add this to your .emacs after adding paredit.el to /path/to/elisp/: ;;; @@ -13,7 +111,7 @@ ;;; (autoload 'paredit-mode "paredit" ;;; "Minor mode for pseudo-structurally editing Lisp code." ;;; t) -;;; (add-hook '...-mode-hook (lambda () (paredit-mode +1))) +;;; (add-hook '...-mode-hook 'turn-on-paredit-mode) ;;; ;;; Usually the ... will be lisp or scheme or both. Alternatively, you ;;; can manually toggle this mode with M-x paredit-mode. Customization @@ -160,20 +234,22 @@ (paredit-warn "`check-parens' is not defined; %s" "be careful of malformed S-expressions.") (condition-case condition + (progn (check-parens) + (add-hook 'after-save-hook 'check-parens t t)) (error (setq paredit-mode nil) (signal (car condition) (cdr condition))))))) ;;; Old functions from when there was a different mode for emacs -nw. -(defun enable-paredit-mode () +(defun turn-on-paredit-mode () "Turn on pseudo-structural editing of Lisp code. Deprecated: use `paredit-mode' instead." (interactive) (paredit-mode +1)) -(defun disable-paredit-mode () +(defun turn-off-paredit-mode () "Turn off pseudo-structural editing of Lisp code. Deprecated: use `paredit-mode' instead." @@ -203,7 +279,8 @@ ;;; or a list of such strings. Entries in this list may also just be ;;; strings, in which case they are headings for the next entries. -(progn (setq paredit-commands +(progn + (setq paredit-commands `( "Basic Insertion Commands" ("(" paredit-open-parenthesis @@ -211,12 +288,12 @@ "(a b (|) c d)") ("(foo \"bar |baz\" quux)" "(foo \"bar (|baz\" quux)")) - (")" paredit-close-parenthesis-and-newline + ("M-)" paredit-close-parenthesis-and-newline ("(defun f (x| ))" "(defun f (x)\n |)") ("; (Foo.|" "; (Foo.)|")) - ("M-)" paredit-close-parenthesis + (")" paredit-close-parenthesis ("(a b |c )" "(a b c)|") ("; Hello,| world!" "; Hello,)| world!")) @@ -263,12 +340,15 @@ ("|(defun hello-world ...)" ";;; |\n(defun hello-world ...)")) - ("C-j" paredit-newline + ("RET" paredit-newline ("(let ((n (frobbotz))) |(display (+ n 1)\nport))" ,(concat "(let ((n (frobbotz)))" "\n |(display (+ n 1)" "\n port))"))) + ("TAB" paredit-indent-and-complete-symbol) + ("M-q" paredit-reindent-defun) + "Deleting & Killing" (("C-d" ,@paredit-forward-delete-keys) paredit-forward-delete @@ -343,7 +423,7 @@ paredit-splice-sexp-killing-forward ("(a (b c| d e) f)" "(a b c f)")) - ("M-r" paredit-raise-sexp + ("M-g" paredit-raise-sexp ("(dynamic-wind in (lambda () |body) out)" "(dynamic-wind in |body out)" "|body")) @@ -359,16 +439,36 @@ paredit-forward-barf-sexp ("(foo (bar |baz quux) zot)" "(foo (bar |baz) quux zot)")) + ("C-M-)" + paredit-forward-join-sexp + ("(foo (bar |baz) (quux) zot)" + "(foo (bar |baz quux) zot)") + ("(a b ((c| d)) (e) f)" + "(a b ((c| d) e) f)")) + ("C-M-}" + paredit-forward-leave-sexp + ("(foo (bar |baz quux) zot)" + "(foo (bar |baz) (quux) zot)")) (("C-(" "C-M-" "ESC C-") paredit-backward-slurp-sexp ("(foo bar (baz| quux) zot)" "(foo (bar baz| quux) zot)") ("(a b ((c| d)) e f)" "(a (b (c| d)) e f)")) + ("C-M-(" + paredit-backward-join-sexp + ("(foo (bar) (baz| quux) zot)" + "(foo (bar baz| quux) zot)") + ("(a (b) ((c| d)) e f)" + "(a (b (c| d)) e f)")) (("C-{" "C-M-" "ESC C-") paredit-backward-barf-sexp ("(foo (bar baz |quux) zot)" "(foo bar (baz |quux) zot)")) + ("C-M-{" + paredit-backward-leave-sexp + ("(foo (bar baz |quux) zot)" + "(foo (bar) (baz |quux) zot)")) "Miscellaneous Commands" ("M-S" paredit-split-sexp @@ -383,7 +483,10 @@ "\"Hello, |world!\"") ("hello-\n| world" "hello-|world")) - ("C-c C-M-l" paredit-recentre-on-sexp) + ("C-c M-l" paredit-refactor-let) + ("C-c M-f" paredit-refactor-flet) + ("C-c M-c" paredit-convolute-up-sexp) + ("C-c C-l" paredit-recentre-on-sexp) )) nil) ; end of PROGN @@ -575,8 +678,14 @@ (paredit-in-comment-p)) (insert close)) ((not (paredit-in-char-p)) + (if (save-excursion + (backward-up-list) + (condition-case err + (ignore (paredit-forward)) + (error t))) + (insert close) (paredit-move-past-close-and-reindent) - (paredit-blink-paren-match nil)))) + (paredit-blink-paren-match nil))))) (defun paredit-move-past-close-and-newline (close) (cond ((or (paredit-in-string-p) @@ -594,7 +703,8 @@ (insert (car comment.point))))) (lisp-indent-line) (paredit-ignore-sexp-errors (indent-sexp)) - (paredit-blink-paren-match t)))) + ;;(paredit-blink-paren-match t) + ))) (defun paredit-find-comment-on-line () "Find a margin comment on the current line. @@ -1041,7 +1151,12 @@ ((let ((syn (char-syntax (char-before)))) (or (eq syn ?\) ) (eq syn ?\" ))) - (backward-char)) + (if (save-excursion + (condition-case err + (ignore (paredit-backward)) + (error t))) + (backward-delete-char 1) + (backward-char))) ((and (eq (char-syntax (char-before)) ?\( ) (eq (char-after) (matching-paren (char-before)))) (backward-delete-char 1) ; Empty list -- delete both @@ -1476,7 +1591,7 @@ (paredit-forward-and-indent) (setq n (1- n))))))) -;;;; Slurpage & Barfage +;;;; Slurpage & Barfage, Adopting & Orphaning (defun paredit-forward-slurp-sexp () "Add the S-expression following the current list into that list @@ -1518,6 +1633,40 @@ (paredit-forward-for-quote (save-excursion (forward-sexp) (point))) (insert close))) +(defun paredit-forward-adopt-sexp () + "Add the contents of the S-expression following the current list into + that list by moving the closing delimiter and removing parentheses. +Automatically reindent the newly adopted S-expression with respect to + its new enclosing form. +If in a string, it is simply slurped." + (interactive) + (save-excursion + (cond ((or (paredit-in-comment-p) + (paredit-in-char-p)) + (error "Invalid context for adopting")) + ((paredit-in-string-p) + (paredit-forward-slurp-into-string)) + (t + (paredit-forward-adopt-into-list))))) + +(defun paredit-forward-adopt-into-list () + (up-list) ; Up to the end of the list to + (paredit-join-sexps)) + +(defun paredit-forward-join-sexp () + (interactive) + (save-excursion + (cond ((or (paredit-in-comment-p) + (paredit-in-char-p) + (paredit-in-string-p)) + (error "Invalid context for joining")) + (t + (save-excursion + (backward-up-list) + (forward-sexp) + (down-list) + (paredit-backward-slurp-sexp)))))) + (defun paredit-forward-barf-sexp () "Remove the last S-expression in the current list from that list by moving the closing delimiter. @@ -1539,6 +1688,30 @@ ;; Reindent all of the newly barfed S-expressions. (paredit-forward-and-indent))) +(defun paredit-forward-orphan-sexp () + "Remove the last S-expression in the current list from that list + by moving the closing delimiter and splicing its contents. +Automatically reindent the newly barfed S-expression with respect to + its new enclosing form." + (interactive) + (save-excursion + (up-list) ; Up to the end of the list to + (backward-char) + (paredit-backward) + (paredit-split-sexp))) + +(defun paredit-forward-leave-sexp () + (interactive) + (save-excursion + (cond ((or (paredit-in-comment-p) + (paredit-in-char-p) + (paredit-in-string-p)) + (error "Invalid context for joining")) + (t + (save-excursion + (backward-up-list 2) + (paredit-forward-barf-sexp)))))) + (defun paredit-backward-slurp-sexp () "Add the S-expression preceding the current list into that list by moving the closing delimiter. @@ -1587,6 +1760,45 @@ (insert open) (paredit-forward-for-quote target))) +(defun paredit-backward-adopt-sexp () + "Add the contents of the S-expression preceding the current list into + that list by moving the closing delimiter and removing parentheses. +Automatically reindent the whole form into which new S-expression was + slurped. +If in a string, do a regular slurp instead." + (interactive) + (save-excursion + (cond ((or (paredit-in-comment-p) + (paredit-in-char-p)) + (error "Invalid context for adopting")) + ((paredit-in-string-p) + (paredit-backward-slurp-into-string)) + (t + (paredit-backward-adopt-into-list))))) + +(defun paredit-backward-adopt-into-list () + (backward-up-list) + (paredit-join-sexps) + ;; Reindent the line at the beginning of wherever we inserted the + ;; opening parenthesis, and then indent the whole S-expression. + (backward-up-list) + (lisp-indent-line) + (indent-sexp)) + +(defun paredit-backward-join-sexp () + (interactive) + (save-excursion + (cond ((or (paredit-in-comment-p) + (paredit-in-char-p) + (paredit-in-string-p)) + (error "Invalid context for joining")) + (t + (save-excursion + (backward-up-list) + (backward-sexp) + (down-list) + (paredit-forward-slurp-sexp)))))) + (defun paredit-backward-barf-sexp () "Remove the first S-expression in the current list from that list by moving the closing delimiter. @@ -1613,6 +1825,33 @@ (lisp-indent-line) (indent-sexp))) +(defun paredit-backward-orphan-sexp () + "Remove the first S-expression in the current list from that list + by moving the closing delimiter. +Automatically reindent the barfed S-expression and the form from which + it was barfed." + (interactive) + (save-excursion + (backward-up-list) + (forward-char) + (paredit-forward) + (paredit-split-sexp) + (paredit-backward) + (lisp-indent-line) + (indent-sexp))) + +(defun paredit-backward-leave-sexp () + (interactive) + (save-excursion + (cond ((or (paredit-in-comment-p) + (paredit-in-char-p) + (paredit-in-string-p)) + (error "Invalid context for joining")) + (t + (save-excursion + (backward-up-list) + (paredit-backward-barf-sexp)))))) + ;;;; Splitting & Joining (defun paredit-split-sexp () @@ -1803,6 +2042,133 @@ (forward-sexp) (point)) +(defun paredit-indent-and-complete-symbol (&optional arg) + (interactive "p") + (if slime-mode + (call-interactively 'slime-indent-and-complete-symbol) + (call-interactively 'lisp-indent-line) + (unless (or (looking-back "^\\s-*") (bolp)) + (call-interactively 'lisp-complete-symbol)))) + +(defun paredit-reindent-defun (&optional arg) + (interactive "P") + (if (or (paredit-in-comment-p) + (paredit-in-string-p)) + (fill-paragraph arg) + (save-excursion + (mark-defun) + (indent-region (point) (mark))))) + +;;;; Refactoring + +(defun paredit-refactor-let (name &optional arg as-flet-p) + "Refactor the current sexp into a let variable. +Inserts the definition into an existing let form if one exists at +the desired level. Mark is left where you were, so use C-x C-x +if you don't want to edit the definition further." + (interactive "s`let' variable name: \np") + (set-mark (point)) + (unless (eq ?\( (char-after)) + (backward-up-list)) + (let* ((start (point)) + (end (save-excursion + (forward-sexp) + (point))) + (sexp (prog1 + (buffer-substring start end) + (delete-region start end)))) + (if as-flet-p + (insert ?\( name ?\)) + (insert name)) + (backward-up-list arg) + (let (maybe-top) + (save-excursion + (while (looking-at (if as-flet-p + "(let\\*?" + "(flet")) + (backward-up-list)) + (if (looking-at (if as-flet-p + "(flet" + "(let\\*?")) + (setq maybe-top (point)))) + (if maybe-top + (goto-char maybe-top))) + (if (looking-at (if as-flet-p + "(flet" + "(let\\*?")) + (progn + (down-list) + (forward-sexp 2) + (backward-char) + (insert "\n(" name " ") + (if as-flet-p + (insert "()\n")) + (save-excursion + (insert sexp ")") + (backward-up-list) + (lisp-indent-line) + (indent-sexp))) + (paredit-wrap-sexp) + (if as-flet-p + (insert "f")) + (insert "let ((" name " ") + (if as-flet-p + (insert "()\n")) + (save-excursion + (insert sexp "))\n") + (backward-up-list) + (lisp-indent-line) + (indent-sexp))) + (forward-char))) + +(defun paredit-refactor-flet (name &optional arg) + (interactive "s`flet' function name: \np") + (paredit-refactor-let name arg t)) + +(defun paredit-convolute-up-sexp (&optional arg) + (interactive "p") + (save-excursion + (let (body-begin body outer-sexp inner-sexp) + (unless (eq ?\( (char-after)) + (backward-up-list)) + (down-list) + (forward-sexp (or arg 2)) + (skip-chars-forward " \t\n") + (setq body-begin (point)) + (backward-up-list) + (forward-sexp) + (backward-char) + (setq body (prog1 + (buffer-substring body-begin (point)) + (delete-region body-begin (point)))) + (backward-up-list) + (setq inner-sexp + (let ((end (save-excursion + (forward-sexp) (point)))) + (prog1 + (buffer-substring (point) end) + (delete-region (point) end)))) + (backward-up-list) + (setq outer-sexp + (let ((end (save-excursion + (forward-sexp) (point)))) + (prog1 + (buffer-substring (point) end) + (delete-region (point) end)))) + (insert inner-sexp) + (backward-sexp) + (lisp-indent-line) + (indent-sexp) + (forward-sexp) + (backward-char) + (insert outer-sexp) + (backward-sexp) + (lisp-indent-line) + (indent-sexp) + (forward-sexp) + (backward-char) + (insert body)))) + ;;;; Initialization (paredit-define-keys) Diff finished. Sat Oct 20 18:34:01 2007