paredit.el (127752B)
1 ;;; paredit.el --- minor mode for editing parentheses -*- Mode: Emacs-Lisp -*- 2 3 ;; Copyright (C) 2005--2022 Taylor R. Campbell 4 5 ;; Author: Taylor R. Campbell <campbell@paredit.org> 6 ;; Version: 26 7 ;; Created: 2005-07-31 8 ;; Keywords: lisp 9 10 ;; Paredit is free software: you can redistribute it and/or modify it 11 ;; under the terms of the GNU General Public License as published by 12 ;; the Free Software Foundation, either version 3 of the License, or 13 ;; (at your option) any later version. 14 ;; 15 ;; Paredit is distributed in the hope that it will be useful, but 16 ;; WITHOUT ANY WARRANTY; without even the implied warranty of 17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 ;; GNU General Public License for more details. 19 ;; 20 ;; You should have received a copy of the GNU General Public License 21 ;; along with paredit. If not, see <http://www.gnu.org/licenses/>. 22 23 ;;; Paredit - https://paredit.org 24 ;;; 25 ;;; Latest release: https://paredit.org/paredit.el 26 ;;; Current development version: https://paredit.org/paredit-beta.el 27 ;;; Release notes: https://paredit.org/NEWS 28 29 ;;; Install paredit by placing `paredit.el' in `/path/to/elisp', a 30 ;;; directory of your choice, and adding to your .emacs file: 31 ;;; 32 ;;; (add-to-list 'load-path "/path/to/elisp") 33 ;;; (autoload 'enable-paredit-mode "paredit" 34 ;;; "Turn on pseudo-structural editing of Lisp code." 35 ;;; t) 36 ;;; 37 ;;; Start Paredit Mode on the fly with `M-x enable-paredit-mode RET', 38 ;;; or always enable it in a major mode `M' (e.g., `lisp') with: 39 ;;; 40 ;;; (add-hook 'M-mode-hook 'enable-paredit-mode) 41 ;;; 42 ;;; Customize paredit using `eval-after-load': 43 ;;; 44 ;;; (eval-after-load 'paredit 45 ;;; '(progn 46 ;;; (define-key paredit-mode-map (kbd "ESC M-A-C-s-)") 47 ;;; 'paredit-dwim))) 48 ;;; 49 ;;; Send questions, bug reports, comments, feature suggestions, &c., 50 ;;; via email to the author's surname at paredit.org. 51 ;;; 52 ;;; Paredit should run in GNU Emacs 21 or later and XEmacs 21.5.28 or 53 ;;; later. 54 55 ;;; The paredit minor mode, Paredit Mode, binds common character keys, 56 ;;; such as `(', `)', `"', and `\', to commands that carefully insert 57 ;;; S-expression structures in the buffer: 58 ;;; 59 ;;; ( inserts `()', leaving the point in the middle; 60 ;;; ) moves the point over the next closing delimiter; 61 ;;; " inserts `""' if outside a string, or inserts an escaped 62 ;;; double-quote if in the middle of a string, or moves over the 63 ;;; closing double-quote if at the end of a string; and 64 ;;; \ prompts for the character to escape, to avoid inserting lone 65 ;;; backslashes that may break structure. 66 ;;; 67 ;;; In comments, these keys insert themselves. If necessary, you can 68 ;;; insert these characters literally outside comments by pressing 69 ;;; `C-q' before these keys, in case a mistake has broken the 70 ;;; structure. 71 ;;; 72 ;;; These key bindings are designed so that when typing new code in 73 ;;; Paredit Mode, you can generally type exactly the same sequence of 74 ;;; keys you would have typed without Paredit Mode. 75 ;;; 76 ;;; Paredit Mode also binds common editing keys, such as `DEL', `C-d', 77 ;;; and `C-k', to commands that respect S-expression structures in the 78 ;;; buffer: 79 ;;; 80 ;;; DEL deletes the previous character, unless it is a delimiter: DEL 81 ;;; will move the point backward over a closing delimiter, and 82 ;;; will delete a delimiter pair together if between an open and 83 ;;; closing delimiter; 84 ;;; 85 ;;; C-d deletes the next character in much the same manner; and 86 ;;; 87 ;;; C-k kills all S-expressions that begin anywhere between the point 88 ;;; and the end of the line or the closing delimiter of the 89 ;;; enclosing list, whichever is first. 90 ;;; 91 ;;; If necessary, you can delete a character, kill a line, &c., 92 ;;; irrespective of S-expression structure, by pressing `C-u' before 93 ;;; these keys, in case a mistake has broken the structure. 94 ;;; 95 ;;; Finally, Paredit Mode binds some keys to complex S-expression 96 ;;; editing operations. For example, `C-<right>' makes the enclosing 97 ;;; list slurp up an S-expression to its right (here `|' denotes the 98 ;;; point): 99 ;;; 100 ;;; (foo (bar | baz) quux) C-<right> (foo (bar | baz quux)) 101 ;;; 102 ;;; Note: Paredit Mode is not compatible with Electric Indent Mode. 103 ;;; Use one or the other, not both. If you want RET to auto-indent and 104 ;;; C-j to just insert newline in Paredit Mode, simply rebind the keys 105 ;;; with the following fragment in your .emacs file: 106 ;;; 107 ;;; (eval-after-load 'paredit 108 ;;; '(progn 109 ;;; (define-key paredit-mode-map (kbd "RET") 'paredit-newline) 110 ;;; (define-key paredit-mode-map (kbd "C-j") nil))) 111 ;;; 112 ;;; Some paredit commands automatically reindent code. When they do, 113 ;;; they try to indent as locally as possible, to avoid interfering 114 ;;; with any indentation you might have manually written. Only the 115 ;;; advanced S-expression manipulation commands automatically reindent, 116 ;;; and only the forms that they immediately operated upon (and their 117 ;;; subforms). 118 ;;; 119 ;;; This code is written for clarity, not efficiency. It frequently 120 ;;; walks over S-expressions redundantly. If you have problems with 121 ;;; the time it takes to execute some of the commands, let me know. 122 123 ;;; This assumes Unix-style LF line endings. 124 125 (defconst paredit-version 26) 126 (defconst paredit-beta-p nil) 127 128 (eval-and-compile 129 130 (defun paredit-xemacs-p () 131 ;; No idea where I got this definition from. Edward O'Connor 132 ;; (hober in #emacs) suggested the current definition. 133 ;; (and (boundp 'running-xemacs) 134 ;; running-xemacs) 135 (featurep 'xemacs)) 136 137 (defun paredit-gnu-emacs-p () 138 ;++ This could probably be improved. 139 (not (paredit-xemacs-p))) 140 141 (defmacro xcond (&rest clauses) 142 "Exhaustive COND. 143 Signal an error if no clause matches." 144 `(cond ,@clauses 145 (t (error "XCOND lost.")))) 146 147 (defalias 'paredit-warn (if (fboundp 'warn) 'warn 'message)) 148 149 (defvar paredit-sexp-error-type 150 (with-temp-buffer 151 (insert "(") 152 (condition-case condition 153 (backward-sexp) 154 (error (if (eq (car condition) 'error) 155 (paredit-warn "%s%s%s%s%s" 156 "Paredit is unable to discriminate" 157 " S-expression parse errors from" 158 " other errors. " 159 " This may cause obscure problems. " 160 " Please upgrade Emacs.")) 161 (car condition))))) 162 163 (defmacro paredit-handle-sexp-errors (body &rest handler) 164 `(condition-case () 165 ,body 166 (,paredit-sexp-error-type ,@handler))) 167 168 (put 'paredit-handle-sexp-errors 'lisp-indent-function 1) 169 170 (defmacro paredit-ignore-sexp-errors (&rest body) 171 `(paredit-handle-sexp-errors (progn ,@body) 172 nil)) 173 174 (put 'paredit-ignore-sexp-errors 'lisp-indent-function 0) 175 176 (defmacro paredit-preserving-column (&rest body) 177 "Evaluate BODY and restore point to former column, relative to code. 178 Assumes BODY will change only indentation. 179 If point was on code, it moves with the code. 180 If point was on indentation, it stays in indentation." 181 (let ((column (make-symbol "column")) 182 (indentation (make-symbol "indentation"))) 183 `(let ((,column (paredit-current-column)) 184 (,indentation (paredit-current-indentation))) 185 (let ((value (progn ,@body))) 186 (paredit-restore-column ,column ,indentation) 187 value)))) 188 189 (put 'paredit-preserving-column 'lisp-indent-function 0) 190 191 nil) 192 193 ;;;; Minor Mode Definition 194 195 (defvar paredit-lighter " Paredit" 196 "Mode line lighter Paredit Mode.") 197 198 (defvar paredit-mode-map (make-sparse-keymap) 199 "Keymap for the paredit minor mode.") 200 201 (defvar paredit-override-check-parens-function 202 (lambda (condition) (declare ignore condition) nil) 203 "Function to tell whether unbalanced text should inhibit Paredit Mode.") 204 205 ;;;###autoload 206 (define-minor-mode paredit-mode 207 "Minor mode for pseudo-structurally editing Lisp code. 208 With a prefix argument, enable Paredit Mode even if there are 209 unbalanced parentheses in the buffer. 210 Paredit behaves badly if parentheses are unbalanced, so exercise 211 caution when forcing Paredit Mode to be enabled, and consider 212 fixing unbalanced parentheses instead. 213 \\<paredit-mode-map>" 214 :lighter paredit-lighter 215 ;; Setting `paredit-mode' to false here aborts enabling Paredit Mode. 216 (if (and paredit-mode 217 (not current-prefix-arg)) 218 (condition-case condition 219 (check-parens) 220 (error 221 (if (not (funcall paredit-override-check-parens-function condition)) 222 (progn (setq paredit-mode nil) 223 (signal (car condition) (cdr condition)))))))) 224 225 (defun paredit-override-check-parens-interactively (condition) 226 (y-or-n-p (format "Enable Paredit Mode despite condition %S? " condition))) 227 228 ;;;###autoload 229 (defun enable-paredit-mode () 230 "Turn on pseudo-structural editing of Lisp code." 231 (interactive) 232 (paredit-mode +1)) 233 234 (defun disable-paredit-mode () 235 "Turn off pseudo-structural editing of Lisp code." 236 (interactive) 237 (paredit-mode -1)) 238 239 (defvar paredit-backward-delete-key 240 (xcond ((paredit-xemacs-p) "BS") 241 ((paredit-gnu-emacs-p) "DEL"))) 242 243 (defvar paredit-forward-delete-keys 244 (xcond ((paredit-xemacs-p) '("DEL")) 245 ((paredit-gnu-emacs-p) '("<delete>" "<deletechar>")))) 246 247 ;;;; Paredit Keys 248 249 ;;; Separating the definition and initialization of this variable 250 ;;; simplifies the development of paredit, since re-evaluating DEFVAR 251 ;;; forms doesn't actually do anything. 252 253 (defvar paredit-commands nil 254 "List of paredit commands with their keys and examples.") 255 256 ;;; Each specifier is of the form: 257 ;;; (key[s] function (example-input example-output) ...) 258 ;;; where key[s] is either a single string suitable for passing to KBD 259 ;;; or a list of such strings. Entries in this list may also just be 260 ;;; strings, in which case they are headings for the next entries. 261 262 (progn (setq paredit-commands 263 `( 264 "Basic Insertion Commands" 265 ("(" paredit-open-round 266 ("(a b |c d)" 267 "(a b (|) c d)") 268 ("(foo \"bar |baz\" quux)" 269 "(foo \"bar (|baz\" quux)")) 270 (")" paredit-close-round 271 ("(a b |c )" "(a b c)|") 272 ("; Hello,| world!" 273 "; Hello,)| world!")) 274 ("M-)" paredit-close-round-and-newline 275 ("(defun f (x| ))" 276 "(defun f (x)\n |)") 277 ("; (Foo.|" 278 "; (Foo.)|")) 279 ("[" paredit-open-square 280 ("(a b |c d)" 281 "(a b [|] c d)") 282 ("(foo \"bar |baz\" quux)" 283 "(foo \"bar [|baz\" quux)")) 284 ("]" paredit-close-square 285 ("(define-key keymap [frob| ] 'frobnicate)" 286 "(define-key keymap [frob]| 'frobnicate)") 287 ("; [Bar.|" 288 "; [Bar.]|")) 289 290 ("\"" paredit-doublequote 291 ("(frob grovel |full lexical)" 292 "(frob grovel \"|\" full lexical)" 293 "(frob grovel \"\"| full lexical)") 294 ("(foo \"bar |baz\" quux)" 295 "(foo \"bar \\\"|baz\" quux)") 296 ("(frob grovel) ; full |lexical" 297 "(frob grovel) ; full \"|lexical")) 298 ("M-\"" paredit-meta-doublequote 299 ("(foo \"bar |baz\" quux)" 300 "(foo \"bar baz\"| quux)") 301 ("(foo |(bar #\\x \"baz \\\\ quux\") zot)" 302 ,(concat "(foo \"|(bar #\\\\x \\\"baz \\\\" 303 "\\\\ quux\\\")\" zot)"))) 304 ("\\" paredit-backslash 305 ("(string #|)\n ; Character to escape: x" 306 "(string #\\x|)") 307 ("\"foo|bar\"\n ; Character to escape: \"" 308 "\"foo\\\"|bar\"")) 309 (";" paredit-semicolon 310 ("|(frob grovel)" 311 ";|(frob grovel)") 312 ("(frob |grovel)" 313 "(frob ;|grovel\n )") 314 ("(frob |grovel (bloit\n zargh))" 315 "(frob ;|grovel\n (bloit\n zargh))") 316 ("(frob grovel) |" 317 "(frob grovel) ;|")) 318 ("M-;" paredit-comment-dwim 319 ("(foo |bar) ; baz" 320 "(foo bar) ; |baz") 321 ("(frob grovel)|" 322 "(frob grovel) ;|") 323 ("(zot (foo bar)\n|\n (baz quux))" 324 "(zot (foo bar)\n ;; |\n (baz quux))") 325 ("(zot (foo bar) |(baz quux))" 326 "(zot (foo bar)\n ;; |\n (baz quux))") 327 ("|(defun hello-world ...)" 328 ";;; |\n(defun hello-world ...)")) 329 330 (() paredit-newline 331 ("(let ((n (frobbotz))) |(display (+ n 1)\nport))" 332 ,(concat "(let ((n (frobbotz)))" 333 "\n |(display (+ n 1)" 334 "\n port))"))) 335 ("RET" paredit-RET) 336 ("C-j" paredit-C-j) 337 338 "Deleting & Killing" 339 (,paredit-forward-delete-keys 340 paredit-forward-delete 341 ("(quu|x \"zot\")" "(quu| \"zot\")") 342 ("(quux |\"zot\")" 343 "(quux \"|zot\")" 344 "(quux \"|ot\")") 345 ("(foo (|) bar)" "(foo | bar)") 346 ("|(foo bar)" "(|foo bar)")) 347 (,paredit-backward-delete-key 348 paredit-backward-delete 349 ("(\"zot\" q|uux)" "(\"zot\" |uux)") 350 ("(\"zot\"| quux)" 351 "(\"zot|\" quux)" 352 "(\"zo|\" quux)") 353 ("(foo (|) bar)" "(foo | bar)") 354 ("(foo bar)|" "(foo bar|)")) 355 ("C-d" paredit-delete-char 356 ("(quu|x \"zot\")" "(quu| \"zot\")") 357 ("(quux |\"zot\")" 358 "(quux \"|zot\")" 359 "(quux \"|ot\")") 360 ("(foo (|) bar)" "(foo | bar)") 361 ("|(foo bar)" "(|foo bar)")) 362 ("C-k" paredit-kill 363 ("(foo bar)| ; Useless comment!" 364 "(foo bar)|") 365 ("(|foo bar) ; Useful comment!" 366 "(|) ; Useful comment!") 367 ("|(foo bar) ; Useless line!" 368 "|") 369 ("(foo \"|bar baz\"\n quux)" 370 "(foo \"|\"\n quux)")) 371 ("M-d" paredit-forward-kill-word 372 ("|(foo bar) ; baz" 373 "(| bar) ; baz" 374 "(|) ; baz" 375 "() ;|") 376 (";;;| Frobnicate\n(defun frobnicate ...)" 377 ";;;|\n(defun frobnicate ...)" 378 ";;;\n(| frobnicate ...)")) 379 (,(concat "M-" paredit-backward-delete-key) 380 paredit-backward-kill-word 381 ("(foo bar) ; baz\n(quux)|" 382 "(foo bar) ; baz\n(|)" 383 "(foo bar) ; |\n()" 384 "(foo |) ; \n()" 385 "(|) ; \n()")) 386 387 "Movement & Navigation" 388 ("C-M-f" paredit-forward 389 ("(foo |(bar baz) quux)" 390 "(foo (bar baz)| quux)") 391 ("(foo (bar)|)" 392 "(foo (bar))|")) 393 ("C-M-b" paredit-backward 394 ("(foo (bar baz)| quux)" 395 "(foo |(bar baz) quux)") 396 ("(|(foo) bar)" 397 "|((foo) bar)")) 398 ("C-M-u" paredit-backward-up) 399 ("C-M-d" paredit-forward-down) 400 ("C-M-p" paredit-backward-down) ; Built-in, these are FORWARD- 401 ("C-M-n" paredit-forward-up) ; & BACKWARD-LIST, which have 402 ; no need given C-M-f & C-M-b. 403 404 "Depth-Changing Commands" 405 ("M-(" paredit-wrap-round 406 ("(foo |bar baz)" 407 "(foo (|bar) baz)")) 408 ("M-s" paredit-splice-sexp 409 ("(foo (bar| baz) quux)" 410 "(foo bar| baz quux)")) 411 (("M-<up>" "ESC <up>") 412 paredit-splice-sexp-killing-backward 413 ("(foo (let ((x 5)) |(sqrt n)) bar)" 414 "(foo |(sqrt n) bar)")) 415 (("M-<down>" "ESC <down>") 416 paredit-splice-sexp-killing-forward 417 ("(a (b c| d e) f)" 418 "(a b c| f)")) 419 ("M-r" paredit-raise-sexp 420 ("(dynamic-wind in (lambda () |body) out)" 421 "(dynamic-wind in |body out)" 422 "|body")) 423 ("M-?" paredit-convolute-sexp 424 ("(let ((x 5) (y 3)) (frob |(zwonk)) (wibblethwop))" 425 "(frob |(let ((x 5) (y 3)) (zwonk) (wibblethwop)))")) 426 427 "Barfage & Slurpage" 428 (("C-)" "C-<right>") 429 paredit-forward-slurp-sexp 430 ("(foo (bar |baz) quux zot)" 431 "(foo (bar |baz quux) zot)") 432 ("(a b ((c| d)) e f)" 433 "(a b ((c| d) e) f)")) 434 (("C-}" "C-<left>") 435 paredit-forward-barf-sexp 436 ("(foo (bar |baz quux) zot)" 437 "(foo (bar |baz) quux zot)")) 438 (("C-(" "C-M-<left>" "ESC C-<left>") 439 paredit-backward-slurp-sexp 440 ("(foo bar (baz| quux) zot)" 441 "(foo (bar baz| quux) zot)") 442 ("(a b ((c| d)) e f)" 443 "(a (b (c| d)) e f)")) 444 (("C-{" "C-M-<right>" "ESC C-<right>") 445 paredit-backward-barf-sexp 446 ("(foo (bar baz |quux) zot)" 447 "(foo bar (baz |quux) zot)")) 448 449 "Miscellaneous Commands" 450 ("M-S" paredit-split-sexp 451 ("(hello| world)" 452 "(hello)| (world)") 453 ("\"Hello, |world!\"" 454 "\"Hello, \"| \"world!\"")) 455 ("M-J" paredit-join-sexps 456 ("(hello)| (world)" 457 "(hello| world)") 458 ("\"Hello, \"| \"world!\"" 459 "\"Hello, |world!\"") 460 ("hello-\n| world" 461 "hello-|world")) 462 ("C-c C-M-l" paredit-recenter-on-sexp) 463 ("M-q" paredit-reindent-defun) 464 )) 465 nil) ; end of PROGN 466 467 ;;;;; Command Examples 468 469 (eval-and-compile 470 (defmacro paredit-do-commands (vars string-case &rest body) 471 (let ((spec (nth 0 vars)) 472 (keys (nth 1 vars)) 473 (fn (nth 2 vars)) 474 (examples (nth 3 vars))) 475 `(dolist (,spec paredit-commands) 476 (if (stringp ,spec) 477 ,string-case 478 (let ((,keys (let ((k (car ,spec))) 479 (cond ((stringp k) (list k)) 480 ((listp k) k) 481 (t (error "Invalid paredit command %s." 482 ,spec))))) 483 (,fn (cadr ,spec)) 484 (,examples (cddr ,spec))) 485 ,@body))))) 486 487 (put 'paredit-do-commands 'lisp-indent-function 2)) 488 489 (defun paredit-define-keys () 490 (paredit-do-commands (spec keys fn examples) 491 nil ; string case 492 (dolist (key keys) 493 (define-key paredit-mode-map (read-kbd-macro key) fn)))) 494 495 (defun paredit-function-documentation (fn) 496 (let ((original-doc (get fn 'paredit-original-documentation)) 497 (doc (documentation fn 'function-documentation))) 498 (or original-doc 499 (progn (put fn 'paredit-original-documentation doc) 500 doc)))) 501 502 (defun paredit-annotate-mode-with-examples () 503 (let ((contents 504 (list (paredit-function-documentation 'paredit-mode)))) 505 (paredit-do-commands (spec keys fn examples) 506 (push (concat "\n\n" spec "\n") 507 contents) 508 (let ((name (symbol-name fn))) 509 (if (string-match (symbol-name 'paredit-) name) 510 (push (concat "\n\n\\[" name "]\t" name 511 (if examples 512 (mapconcat (lambda (example) 513 (concat 514 "\n" 515 (mapconcat 'identity 516 example 517 "\n --->\n") 518 "\n")) 519 examples 520 "") 521 "\n (no examples)\n")) 522 contents)))) 523 (put 'paredit-mode 'function-documentation 524 (apply 'concat (reverse contents)))) 525 ;; PUT returns the huge string we just constructed, which we don't 526 ;; want it to return. 527 nil) 528 529 (defun paredit-annotate-functions-with-examples () 530 (paredit-do-commands (spec keys fn examples) 531 nil ; string case 532 (put fn 'function-documentation 533 (concat (paredit-function-documentation fn) 534 "\n\n\\<paredit-mode-map>\\[" (symbol-name fn) "]\n" 535 (mapconcat (lambda (example) 536 (concat "\n" 537 (mapconcat 'identity 538 example 539 "\n ->\n") 540 "\n")) 541 examples 542 ""))))) 543 544 ;;;;; HTML Examples 545 546 (defun paredit-insert-html-examples () 547 "Insert HTML for a paredit quick reference table." 548 (interactive) 549 (let ((insert-lines 550 (lambda (&rest lines) (dolist (line lines) (insert line) (newline)))) 551 (initp nil)) 552 (paredit-do-commands (spec keys fn examples) 553 (progn (if initp 554 (funcall insert-lines "</table>") 555 (setq initp t)) 556 (funcall insert-lines (concat "<h3>" spec "</h3>")) 557 (funcall insert-lines "<table>")) 558 (let ((name (symbol-name fn)) 559 (keys 560 (mapconcat (lambda (key) 561 (concat "<tt>" (paredit-html-quote key) "</tt>")) 562 keys 563 ", "))) 564 (funcall insert-lines "<tr>") 565 (funcall insert-lines (concat " <th align=\"left\">" keys "</th>")) 566 (funcall insert-lines (concat " <th align=\"left\">" name "</th>")) 567 (funcall insert-lines "</tr>") 568 (funcall insert-lines 569 "<tr><td colspan=\"2\"><table cellpadding=\"5\"><tr>") 570 (dolist (example examples) 571 (let ((prefix "<td><table border=\"1\"><tr><td><table><tr><td><pre>") 572 (examples 573 (mapconcat 'paredit-html-quote 574 example 575 (concat "</pre></td></tr>" 576 "<tr><th>↓</th></tr>" 577 "<tr><td><pre>"))) 578 (suffix "</pre></td></tr></table></td></tr></table></td>")) 579 (funcall insert-lines (concat prefix examples suffix)))) 580 (funcall insert-lines "</tr></table></td></tr>"))) 581 (funcall insert-lines "</table>"))) 582 583 (defun paredit-html-quote (string) 584 (with-temp-buffer 585 (dotimes (i (length string)) 586 (insert (let ((c (elt string i))) 587 (cond ((eq c ?\<) "<") 588 ((eq c ?\>) ">") 589 ((eq c ?\&) "&") 590 ((eq c ?\') "'") 591 ((eq c ?\") """) 592 (t c))))) 593 (buffer-string))) 594 595 ;;;; Delimiter Insertion 596 597 (eval-and-compile 598 (defun paredit-conc-name (&rest strings) 599 (intern (apply 'concat strings))) 600 601 (defmacro define-paredit-pair (open close name) 602 `(progn 603 (defun ,(paredit-conc-name "paredit-open-" name) (&optional n) 604 ,(concat "Insert a balanced " name " pair. 605 With a prefix argument N, put the closing " name " after N 606 S-expressions forward. 607 If the region is active, `transient-mark-mode' is enabled, and the 608 region's start and end fall in the same parenthesis depth, insert a 609 " name " pair around the region. 610 If in a string or a comment, insert a single " name ". 611 If in a character literal, do nothing. This prevents changing what was 612 in the character literal to a meaningful delimiter unintentionally.") 613 (interactive "P") 614 (cond ((or (paredit-in-string-p) 615 (paredit-in-comment-p)) 616 (insert ,open)) 617 ((not (paredit-in-char-p)) 618 (paredit-insert-pair n ,open ,close 'goto-char) 619 (save-excursion (backward-up-list) (indent-sexp))))) 620 (defun ,(paredit-conc-name "paredit-close-" name) () 621 ,(concat "Move past one closing delimiter and reindent. 622 \(Agnostic to the specific closing delimiter.) 623 If in a string or comment, insert a single closing " name ". 624 If in a character literal, do nothing. This prevents changing what was 625 in the character literal to a meaningful delimiter unintentionally.") 626 (interactive) 627 (paredit-move-past-close ,close)) 628 (defun ,(paredit-conc-name "paredit-close-" name "-and-newline") () 629 ,(concat "Move past one closing delimiter, add a newline," 630 " and reindent. 631 If there was a margin comment after the closing delimiter, preserve it 632 on the same line.") 633 (interactive) 634 (paredit-move-past-close-and-newline ,close)) 635 (defun ,(paredit-conc-name "paredit-wrap-" name) 636 (&optional argument) 637 ,(concat "Wrap the following S-expression. 638 See `paredit-wrap-sexp' for more details.") 639 (interactive "P") 640 (paredit-wrap-sexp argument ,open ,close)) 641 (add-to-list 'paredit-wrap-commands 642 ',(paredit-conc-name "paredit-wrap-" name))))) 643 644 (defvar paredit-wrap-commands '(paredit-wrap-sexp) 645 "List of paredit commands that wrap S-expressions. 646 Used by `paredit-yank-pop'; for internal paredit use only.") 647 648 (define-paredit-pair ?\( ?\) "round") 649 (define-paredit-pair ?\[ ?\] "square") 650 (define-paredit-pair ?\{ ?\} "curly") 651 (define-paredit-pair ?\< ?\> "angled") 652 653 ;;; Aliases for the old names. 654 655 (defalias 'paredit-open-parenthesis 'paredit-open-round) 656 (defalias 'paredit-close-parenthesis 'paredit-close-round) 657 (defalias 'paredit-close-parenthesis-and-newline 658 'paredit-close-round-and-newline) 659 660 (defalias 'paredit-open-bracket 'paredit-open-square) 661 (defalias 'paredit-close-bracket 'paredit-close-square) 662 (defalias 'paredit-close-bracket-and-newline 663 'paredit-close-square-and-newline) 664 665 (defun paredit-move-past-close (close) 666 (paredit-move-past-close-and close 667 (lambda () 668 (paredit-blink-paren-match nil)))) 669 670 (defun paredit-move-past-close-and-newline (close) 671 (paredit-move-past-close-and close 672 (lambda () 673 (let ((comment.point (paredit-find-comment-on-line))) 674 (newline) 675 (if comment.point 676 (save-excursion 677 (forward-line -1) 678 (end-of-line) 679 (indent-to (cdr comment.point)) 680 (insert (car comment.point))))) 681 (lisp-indent-line) 682 (paredit-ignore-sexp-errors (indent-sexp)) 683 (paredit-blink-paren-match t)))) 684 685 (defun paredit-move-past-close-and (close if-moved) 686 (if (or (paredit-in-string-p) 687 (paredit-in-comment-p)) 688 (insert close) 689 (if (paredit-in-char-p) (forward-char)) 690 (paredit-move-past-close-and-reindent close) 691 (funcall if-moved))) 692 693 (defun paredit-find-comment-on-line () 694 "Find a margin comment on the current line. 695 Return nil if there is no such comment or if there is anything but 696 whitespace until such a comment. 697 If such a comment exists, delete the comment (including all leading 698 whitespace) and return a cons whose car is the comment as a string 699 and whose cdr is the point of the comment's initial semicolon, 700 relative to the start of the line." 701 (save-excursion 702 (paredit-skip-whitespace t (point-at-eol)) 703 (and (eq ?\; (char-after)) 704 (not (eq ?\; (char-after (1+ (point))))) 705 (not (or (paredit-in-string-p) 706 (paredit-in-char-p))) 707 (let* ((start ;Move to before the semicolon. 708 (progn (backward-char) (point))) 709 (comment 710 (buffer-substring start (point-at-eol)))) 711 (paredit-skip-whitespace nil (point-at-bol)) 712 (delete-region (point) (point-at-eol)) 713 (cons comment (- start (point-at-bol))))))) 714 715 (defun paredit-insert-pair (n open close forward) 716 (let* ((regionp 717 (and (paredit-region-active-p) 718 (paredit-region-safe-for-insert-p))) 719 (end 720 (and regionp 721 (not n) 722 (prog1 (region-end) (goto-char (region-beginning)))))) 723 (let ((spacep (paredit-space-for-delimiter-p nil open))) 724 (if spacep (insert " ")) 725 (insert open) 726 (save-excursion 727 ;; Move past the desired region. 728 (cond (n 729 (funcall forward 730 (paredit-scan-sexps-hack (point) 731 (prefix-numeric-value n)))) 732 (regionp 733 (funcall forward (+ end (if spacep 2 1))))) 734 ;; The string case can happen if we are inserting string 735 ;; delimiters. The comment case may happen by moving to the 736 ;; end of a buffer that has a comment with no trailing newline. 737 (if (and (not (paredit-in-string-p)) 738 (paredit-in-comment-p)) 739 (newline)) 740 (insert close) 741 (if (paredit-space-for-delimiter-p t close) 742 (insert " ")))))) 743 744 ;++ This needs a better name... 745 746 (defun paredit-scan-sexps-hack (point n) 747 (save-excursion 748 (goto-char point) 749 (let ((direction (if (< 0 n) +1 -1)) 750 (magnitude (abs n)) 751 (count 0)) 752 (catch 'exit 753 (while (< count magnitude) 754 (let ((p 755 (paredit-handle-sexp-errors (scan-sexps (point) direction) 756 nil))) 757 (if (not p) (throw 'exit nil)) 758 (goto-char p)) 759 (setq count (+ count 1))))) 760 (point))) 761 762 (defun paredit-region-safe-for-insert-p () 763 (save-excursion 764 (let ((beginning (region-beginning)) 765 (end (region-end))) 766 (goto-char beginning) 767 (let* ((beginning-state (paredit-current-parse-state)) 768 (end-state 769 (parse-partial-sexp beginning end nil nil beginning-state))) 770 (and (= (nth 0 beginning-state) ; 0. depth in parens 771 (nth 0 end-state)) 772 (eq (nth 3 beginning-state) ; 3. non-nil if inside a 773 (nth 3 end-state)) ; string 774 (eq (nth 4 beginning-state) ; 4. comment status, yada 775 (nth 4 end-state)) 776 (eq (nth 5 beginning-state) ; 5. t if following char 777 (nth 5 end-state))))))) ; quote 778 779 (defvar paredit-space-for-delimiter-predicates nil 780 "List of predicates for whether to put space by delimiter at point. 781 Each predicate is a function that is is applied to two arguments, ENDP 782 and DELIMITER, and that returns a boolean saying whether to put a 783 space next to the delimiter -- before/after the delimiter if ENDP is 784 false/true, respectively. 785 If any predicate returns false, no space is inserted: every predicate 786 has veto power. 787 Each predicate may assume that the point is not at the beginning/end of 788 the buffer, and that the point is preceded/followed by a word 789 constituent, symbol constituent, string quote, or delimiter matching 790 DELIMITER, if ENDP is false/true, respectively. 791 Each predicate should examine only text before/after the point if ENDP is 792 false/true, respectively.") 793 794 (defun paredit-space-for-delimiter-p (endp delimiter) 795 ;; If at the buffer limit, don't insert a space. If there is a word, 796 ;; symbol, other quote, or non-matching parenthesis delimiter (i.e. a 797 ;; close when want an open the string or an open when we want to 798 ;; close the string), do insert a space. 799 (and (not (if endp (eobp) (bobp))) 800 (memq (char-syntax (if endp (char-after) (char-before))) 801 (list ?w ?_ ?\" 802 (let ((matching (matching-paren delimiter))) 803 (and matching (char-syntax matching))) 804 (and (not endp) 805 (eq ?\" (char-syntax delimiter)) 806 ?\) ))) 807 (catch 'exit 808 (dolist (predicate paredit-space-for-delimiter-predicates) 809 (if (not (funcall predicate endp delimiter)) 810 (throw 'exit nil))) 811 t))) 812 813 (defun paredit-move-past-close-and-reindent (close) 814 (let ((open (paredit-missing-close))) 815 (if open 816 (if (eq close (matching-paren open)) 817 (save-excursion 818 (message "Missing closing delimiter: %c" close) 819 (insert close)) 820 (error "Mismatched missing closing delimiter: %c ... %c" 821 open close)))) 822 (up-list) 823 (if (catch 'return ; This CATCH returns T if it 824 (while t ; should delete leading spaces 825 (save-excursion ; and NIL if not. 826 (let ((before-paren (1- (point)))) 827 (back-to-indentation) 828 (cond ((not (eq (point) before-paren)) 829 ;; Can't call PAREDIT-DELETE-LEADING-WHITESPACE 830 ;; here -- we must return from SAVE-EXCURSION 831 ;; first. 832 (throw 'return t)) 833 ((save-excursion (forward-line -1) 834 (end-of-line) 835 (paredit-in-comment-p)) 836 ;; Moving the closing delimiter any further 837 ;; would put it into a comment, so we just 838 ;; indent the closing delimiter where it is and 839 ;; abort the loop, telling its continuation that 840 ;; no leading whitespace should be deleted. 841 (lisp-indent-line) 842 (throw 'return nil)) 843 (t (delete-indentation))))))) 844 (paredit-delete-leading-whitespace))) 845 846 (defun paredit-missing-close () 847 (save-excursion 848 (paredit-handle-sexp-errors (backward-up-list) 849 (error "Not inside a list.")) 850 (let ((open (char-after))) 851 (paredit-handle-sexp-errors (progn (forward-sexp) nil) 852 open)))) 853 854 (defun paredit-delete-leading-whitespace () 855 ;; This assumes that we're on the closing delimiter already. 856 (save-excursion 857 (backward-char) 858 (while (let ((syn (char-syntax (char-before)))) 859 (and (or (eq syn ?\ ) (eq syn ?-)) ; whitespace syntax 860 ;; The above line is a perfect example of why the 861 ;; following test is necessary. 862 (not (paredit-in-char-p (1- (point)))))) 863 (delete-char -1)))) 864 865 (defun paredit-blink-paren-match (another-line-p) 866 (if (and blink-matching-paren 867 (or (not show-paren-mode) another-line-p)) 868 (paredit-ignore-sexp-errors 869 (save-excursion 870 (backward-sexp) 871 (forward-sexp) 872 ;; SHOW-PAREN-MODE inhibits any blinking, so we disable it 873 ;; locally here. 874 (let ((show-paren-mode nil)) 875 (blink-matching-open)))))) 876 877 (defun paredit-doublequote (&optional n) 878 "Insert a pair of double-quotes. 879 With a prefix argument N, wrap the following N S-expressions in 880 double-quotes, escaping intermediate characters if necessary. 881 If the region is active, `transient-mark-mode' is enabled, and the 882 region's start and end fall in the same parenthesis depth, insert a 883 pair of double-quotes around the region, again escaping intermediate 884 characters if necessary. 885 Inside a comment, insert a literal double-quote. 886 At the end of a string, move past the closing double-quote. 887 In the middle of a string, insert a backslash-escaped double-quote. 888 If in a character literal, do nothing. This prevents accidentally 889 changing a what was in the character literal to become a meaningful 890 delimiter unintentionally." 891 (interactive "P") 892 (cond ((paredit-in-string-p) 893 (if (eq (point) (- (paredit-enclosing-string-end) 1)) 894 (forward-char) ; Just move past the closing quote. 895 ;; Don't split a \x into an escaped backslash and a string end. 896 (if (paredit-in-string-escape-p) (forward-char)) 897 (insert ?\\ ?\" ))) 898 ((paredit-in-comment-p) 899 (insert ?\" )) 900 ((not (paredit-in-char-p)) 901 (paredit-insert-pair n ?\" ?\" 'paredit-forward-for-quote)))) 902 903 (defun paredit-meta-doublequote (&optional n) 904 "Move to the end of the string. 905 If not in a string, act as `paredit-doublequote'; if not prefix argument 906 is specified and the region is not active or `transient-mark-mode' is 907 disabled, the default is to wrap one S-expression, however, not zero." 908 (interactive "P") 909 (if (not (paredit-in-string-p)) 910 (paredit-doublequote (or n (and (not (paredit-region-active-p)) 1))) 911 (goto-char (paredit-enclosing-string-end)))) 912 913 (defun paredit-meta-doublequote-and-newline (&optional n) 914 "Move to the end of the string, insert a newline, and indent. 915 If not in a string, act as `paredit-doublequote'; if not prefix argument 916 is specified and the region is not active or `transient-mark-mode' is 917 disabled, the default is to wrap one S-expression, however, not zero." 918 (interactive "P") 919 (if (not (paredit-in-string-p)) 920 (paredit-doublequote (or n (and (not (paredit-region-active-p)) 1))) 921 (progn (goto-char (paredit-enclosing-string-end)) 922 (newline) 923 (lisp-indent-line) 924 (paredit-ignore-sexp-errors (indent-sexp))))) 925 926 (defun paredit-forward-for-quote (end) 927 (let ((state (paredit-current-parse-state))) 928 (while (< (point) end) 929 (let ((new-state (parse-partial-sexp (point) (1+ (point)) 930 nil nil state))) 931 (if (paredit-in-string-p new-state) 932 (if (not (paredit-in-string-escape-p)) 933 (setq state new-state) 934 ;; Escape character: turn it into an escaped escape 935 ;; character by appending another backslash. 936 (insert ?\\ ) 937 ;; Now the point is after both escapes, and we want to 938 ;; rescan from before the first one to after the second 939 ;; one. 940 (setq state 941 (parse-partial-sexp (- (point) 2) (point) 942 nil nil state)) 943 ;; Advance the end point, since we just inserted a new 944 ;; character. 945 (setq end (1+ end))) 946 ;; String: escape by inserting a backslash before the quote. 947 (backward-char) 948 (insert ?\\ ) 949 ;; The point is now between the escape and the quote, and we 950 ;; want to rescan from before the escape to after the quote. 951 (setq state 952 (parse-partial-sexp (1- (point)) (1+ (point)) 953 nil nil state)) 954 ;; Advance the end point for the same reason as above. 955 (setq end (1+ end))))))) 956 957 ;;;; Escape Insertion 958 959 (defun paredit-backslash () 960 "Insert a backslash followed by a character to escape." 961 (interactive) 962 (cond ((paredit-in-string-p) (paredit-backslash-interactive)) 963 ((paredit-in-comment-p) (insert ?\\)) 964 ((paredit-in-char-p) (forward-char) (paredit-backslash-interactive)) 965 (t (paredit-backslash-interactive)))) 966 967 (defun paredit-backslash-interactive () 968 (insert ?\\ ) 969 ;; Read a character to insert after the backslash. If anything 970 ;; goes wrong -- the user hits delete (entering the rubout 971 ;; `character'), aborts with C-g, or enters non-character input 972 ;; -- then delete the backslash to avoid a dangling escape. 973 (let ((delete-p t)) 974 (unwind-protect 975 (let ((char (read-char "Character to escape: " t))) 976 (if (not (eq char ?\^?)) 977 (progn (message "Character to escape: %c" char) 978 (insert char) 979 (setq delete-p nil)))) 980 (if delete-p 981 (progn (message "Deleting escape.") 982 (delete-char -1)))))) 983 984 (defun paredit-newline () 985 "Insert a newline and indent it. 986 This is like `newline-and-indent', but it not only indents the line 987 that the point is on but also the S-expression following the point, 988 if there is one. 989 Move forward one character first if on an escaped character. 990 If in a string, just insert a literal newline. 991 If in a comment and if followed by invalid structure, call 992 `indent-new-comment-line' to keep the invalid structure in a 993 comment." 994 (interactive) 995 (cond ((paredit-in-string-p) 996 (newline)) 997 ((paredit-in-comment-p) 998 (if (paredit-region-ok-p (point) (point-at-eol)) 999 (progn (newline-and-indent) 1000 (paredit-ignore-sexp-errors (indent-sexp))) 1001 (indent-new-comment-line))) 1002 (t 1003 (if (paredit-in-char-p) 1004 (forward-char)) 1005 (newline-and-indent) 1006 ;; Indent the following S-expression, but don't signal an 1007 ;; error if there's only a closing delimiter after the point. 1008 (paredit-ignore-sexp-errors (indent-sexp))))) 1009 1010 (defun paredit-electric-indent-mode-p () 1011 "True if Electric Indent Mode is on, false if not. 1012 Electric Indent Mode is generally not compatible with paredit and 1013 users are advised to disable it, since paredit does essentially 1014 everything it tries to do better. 1015 However, to mitigate the negative user experience of combining 1016 Electric Indent Mode with paredit, the default key bindings for 1017 RET and C-j in paredit are exchanged depending on whether 1018 Electric Indent Mode is enabled." 1019 (and (boundp 'electric-indent-mode) 1020 electric-indent-mode)) 1021 1022 (defun paredit-RET () 1023 "Default key binding for RET in Paredit Mode. 1024 Normally, inserts a newline, like traditional Emacs RET. 1025 With Electric Indent Mode enabled, inserts a newline and indents 1026 the new line, as well as any subexpressions of it on subsequent 1027 lines." 1028 (interactive) 1029 (if (paredit-electric-indent-mode-p) 1030 (let ((electric-indent-mode nil)) 1031 (paredit-newline)) 1032 (newline))) 1033 1034 (defun paredit-C-j () 1035 "Default key binding for C-j in Paredit Mode. 1036 Normally, inserts a newline and indents 1037 the new line, as well as any subexpressions of it on subsequent 1038 lines. 1039 With Electric Indent Mode enabled, inserts a newline, like 1040 traditional Emacs RET." 1041 (interactive) 1042 (if (paredit-electric-indent-mode-p) 1043 (let ((electric-indent-mode nil)) 1044 (newline)) 1045 (paredit-newline))) 1046 1047 (defun paredit-reindent-defun (&optional argument) 1048 "Reindent the definition that the point is on. 1049 If the point is in a string or a comment, fill the paragraph instead, 1050 and with a prefix argument, justify as well." 1051 (interactive "P") 1052 (if (or (paredit-in-string-p) 1053 (paredit-in-comment-p)) 1054 (if (memq fill-paragraph-function '(t nil)) 1055 (lisp-fill-paragraph argument) 1056 (funcall fill-paragraph-function argument)) 1057 (paredit-preserving-column 1058 (save-excursion 1059 (end-of-defun) 1060 (beginning-of-defun) 1061 (indent-sexp))))) 1062 1063 ;;;; Comment Insertion 1064 1065 (defun paredit-semicolon (&optional n) 1066 "Insert a semicolon. 1067 With a prefix argument N, insert N semicolons. 1068 If in a string, do just that and nothing else. 1069 If in a character literal, move to the beginning of the character 1070 literal before inserting the semicolon. 1071 If the enclosing list ends on the line after the point, break the line 1072 after the last S-expression following the point. 1073 If a list begins on the line after the point but ends on a different 1074 line, break the line after the last S-expression following the point 1075 before the list." 1076 (interactive "p") 1077 (if (or (paredit-in-string-p) (paredit-in-comment-p)) 1078 (insert (make-string (or n 1) ?\; )) 1079 (if (paredit-in-char-p) 1080 (backward-char 2)) 1081 (let ((line-break-point (paredit-semicolon-find-line-break-point))) 1082 (if line-break-point 1083 (paredit-semicolon-with-line-break line-break-point (or n 1)) 1084 (insert (make-string (or n 1) ?\; )))))) 1085 1086 (defun paredit-semicolon-find-line-break-point () 1087 (and (not (eolp)) ;Implies (not (eobp)). 1088 (let ((eol (point-at-eol))) 1089 (save-excursion 1090 (catch 'exit 1091 (while t 1092 (let ((line-break-point (point))) 1093 (cond ((paredit-handle-sexp-errors (progn (forward-sexp) t) 1094 nil) 1095 ;; Successfully advanced by an S-expression. 1096 ;; If that S-expression started on this line 1097 ;; and ended on another one, break here. 1098 (cond ((not (eq eol (point-at-eol))) 1099 (throw 'exit 1100 (and (save-excursion 1101 (backward-sexp) 1102 (eq eol (point-at-eol))) 1103 line-break-point))) 1104 ((eobp) 1105 (throw 'exit nil)))) 1106 ((save-excursion 1107 (paredit-skip-whitespace t (point-at-eol)) 1108 (or (eolp) (eobp) (eq (char-after) ?\;))) 1109 ;; Can't move further, but there's no closing 1110 ;; delimiter we're about to clobber -- either 1111 ;; it's on the next line or we're at the end of 1112 ;; the buffer. Don't break the line. 1113 (throw 'exit nil)) 1114 (t 1115 ;; Can't move because we hit a delimiter at the 1116 ;; end of this line. Break here. 1117 (throw 'exit line-break-point)))))))))) 1118 1119 (defun paredit-semicolon-with-line-break (line-break-point n) 1120 (let ((line-break-marker (make-marker))) 1121 (set-marker line-break-marker line-break-point) 1122 (set-marker-insertion-type line-break-marker t) 1123 (insert (make-string (or n 1) ?\; )) 1124 (save-excursion 1125 (goto-char line-break-marker) 1126 (set-marker line-break-marker nil) 1127 (newline) 1128 (lisp-indent-line) 1129 ;; This step is redundant if we are inside a list, but even if we 1130 ;; are at the top level, we want at least to indent whatever we 1131 ;; bumped off the line. 1132 (paredit-ignore-sexp-errors (indent-sexp)) 1133 (paredit-indent-sexps)))) 1134 1135 ;;; This is all a horrible, horrible hack, primarily for GNU Emacs 21, 1136 ;;; in which there is no `comment-or-uncomment-region'. 1137 1138 (autoload 'comment-forward "newcomment") 1139 (autoload 'comment-normalize-vars "newcomment") 1140 (autoload 'comment-region "newcomment") 1141 (autoload 'comment-search-forward "newcomment") 1142 (autoload 'uncomment-region "newcomment") 1143 1144 (defun paredit-initialize-comment-dwim () 1145 (require 'newcomment) 1146 (if (not (fboundp 'comment-or-uncomment-region)) 1147 (defalias 'comment-or-uncomment-region 1148 (lambda (beginning end &optional argument) 1149 (interactive "*r\nP") 1150 (if (save-excursion (goto-char beginning) 1151 (comment-forward (point-max)) 1152 (<= end (point))) 1153 (uncomment-region beginning end argument) 1154 (comment-region beginning end argument))))) 1155 (defalias 'paredit-initialize-comment-dwim 'comment-normalize-vars) 1156 (comment-normalize-vars)) 1157 1158 (defvar paredit-comment-prefix-toplevel ";;; " 1159 "String of prefix for top-level comments aligned at the left margin.") 1160 1161 (defvar paredit-comment-prefix-code ";; " 1162 "String of prefix for comments indented at the same depth as code.") 1163 1164 (defvar paredit-comment-prefix-margin ";" 1165 "String of prefix for comments on the same line as code in the margin.") 1166 1167 (defun paredit-comment-dwim (&optional argument) 1168 "Call the Lisp comment command you want (Do What I Mean). 1169 This is like `comment-dwim', but it is specialized for Lisp editing. 1170 If transient mark mode is enabled and the mark is active, comment or 1171 uncomment the selected region, depending on whether it was entirely 1172 commented not not already. 1173 If there is already a comment on the current line, with no prefix 1174 argument, indent to that comment; with a prefix argument, kill that 1175 comment. 1176 Otherwise, insert a comment appropriate for the context and ensure that 1177 any code following the comment is moved to the next line. 1178 At the top level, where indentation is calculated to be at column 0, 1179 insert a triple-semicolon comment; within code, where the indentation 1180 is calculated to be non-zero, and on the line there is either no code 1181 at all or code after the point, insert a double-semicolon comment; 1182 and if the point is after all code on the line, insert a single- 1183 semicolon margin comment at `comment-column'." 1184 (interactive "*P") 1185 (paredit-initialize-comment-dwim) 1186 (cond ((paredit-region-active-p) 1187 (comment-or-uncomment-region (region-beginning) 1188 (region-end) 1189 argument)) 1190 ((paredit-comment-on-line-p) 1191 (if argument 1192 (comment-kill (if (integerp argument) argument nil)) 1193 (comment-indent))) 1194 (t (paredit-insert-comment)))) 1195 1196 (defun paredit-comment-on-line-p () 1197 "True if there is a comment on the line following point. 1198 This is expected to be called only in `paredit-comment-dwim'; do not 1199 call it elsewhere." 1200 (save-excursion 1201 (beginning-of-line) 1202 (let ((comment-p nil)) 1203 ;; Search forward for a comment beginning. If there is one, set 1204 ;; COMMENT-P to true; if not, it will be nil. 1205 (while (progn 1206 (setq comment-p ;t -> no error 1207 (comment-search-forward (point-at-eol) t)) 1208 (and comment-p 1209 (or (paredit-in-string-p) 1210 (paredit-in-char-p (1- (point)))))) 1211 (forward-char)) 1212 comment-p))) 1213 1214 (defun paredit-insert-comment () 1215 (let ((code-after-p 1216 (save-excursion (paredit-skip-whitespace t (point-at-eol)) 1217 (not (eolp)))) 1218 (code-before-p 1219 (save-excursion (paredit-skip-whitespace nil (point-at-bol)) 1220 (not (bolp))))) 1221 (cond ((and (bolp) 1222 (let ((indent 1223 (let ((indent (calculate-lisp-indent))) 1224 (if (consp indent) (car indent) indent)))) 1225 (and indent (zerop indent)))) 1226 ;; Top-level comment 1227 (if code-after-p (save-excursion (newline))) 1228 (insert paredit-comment-prefix-toplevel)) 1229 ((or code-after-p (not code-before-p)) 1230 ;; Code comment 1231 (if code-before-p 1232 (newline-and-indent) 1233 (lisp-indent-line)) 1234 (insert paredit-comment-prefix-code) 1235 (if code-after-p 1236 (save-excursion 1237 (newline) 1238 (lisp-indent-line) 1239 (paredit-indent-sexps)))) 1240 (t 1241 ;; Margin comment 1242 (indent-to comment-column 1) ; 1 -> force one leading space 1243 (insert paredit-comment-prefix-margin))))) 1244 1245 ;;;; Character Deletion 1246 1247 (defun paredit-delete-char (&optional argument) 1248 "Delete a character forward or move forward over a delimiter. 1249 If on an opening S-expression delimiter, move forward into the 1250 S-expression. 1251 If on a closing S-expression delimiter, refuse to delete unless the 1252 S-expression is empty, in which case delete the whole S-expression. 1253 With a numeric prefix argument N, delete N characters forward. 1254 With a `C-u' prefix argument, simply delete a character forward, 1255 without regard for delimiter balancing. 1256 1257 Like `delete-char', ignores `delete-active-region'." 1258 (interactive "P") 1259 (let ((delete-active-region nil)) 1260 (paredit-forward-delete argument))) 1261 1262 (defun paredit-delete-active-region-p () 1263 "True if the region is active and to be deleted." 1264 (and (paredit-region-active-p) 1265 (boundp 'delete-active-region) 1266 (eq delete-active-region t))) 1267 1268 (defun paredit-kill-active-region-p () 1269 "True if the region is active and to be killed." 1270 (and (paredit-region-active-p) 1271 (boundp 'delete-active-region) 1272 (eq delete-active-region 'kill))) 1273 1274 (defun paredit-forward-delete (&optional argument) 1275 "Delete a character forward or move forward over a delimiter. 1276 If on an opening S-expression delimiter, move forward into the 1277 S-expression. 1278 If on a closing S-expression delimiter, refuse to delete unless the 1279 S-expression is empty, in which case delete the whole S-expression. 1280 With a numeric prefix argument N, delete N characters forward. 1281 With a `C-u' prefix argument, simply delete a character forward, 1282 without regard for delimiter balancing. 1283 1284 If `delete-active-region' is enabled and the mark is active and 1285 no prefix argument is specified, act as `paredit-delete-region' 1286 or `paredit-kill-region' as appropriate instead." 1287 (interactive "P") 1288 (cond ((consp argument) 1289 (delete-char +1)) 1290 ((integerp argument) 1291 (let ((delete-active-region nil)) 1292 (if (< argument 0) 1293 (paredit-backward-delete argument) 1294 (while (> argument 0) 1295 (paredit-forward-delete) 1296 (setq argument (- argument 1)))))) 1297 ((paredit-delete-active-region-p) 1298 (paredit-delete-region (region-beginning) (region-end))) 1299 ((paredit-kill-active-region-p) 1300 (paredit-kill-region (region-beginning) (region-end))) 1301 ((eobp) 1302 (delete-char +1)) 1303 ((paredit-in-string-p) 1304 (paredit-forward-delete-in-string)) 1305 ((paredit-in-comment-p) 1306 (paredit-forward-delete-in-comment)) 1307 ((paredit-in-char-p) ; Escape -- delete both chars. 1308 (delete-char -1) 1309 (delete-char +1)) 1310 ((eq (char-after) ?\\ ) ; ditto 1311 (delete-char +2)) 1312 ((let ((syn (char-syntax (char-after)))) 1313 (or (eq syn ?\( ) 1314 (eq syn ?\" ))) 1315 (if (save-excursion 1316 (paredit-handle-sexp-errors (progn (forward-sexp) t) 1317 nil)) 1318 (forward-char) 1319 (message "Deleting spurious opening delimiter.") 1320 (delete-char +1))) 1321 ((and (not (paredit-in-char-p (1- (point)))) 1322 (eq (char-syntax (char-after)) ?\) ) 1323 (eq (char-before) (matching-paren (char-after)))) 1324 (delete-char -1) ; Empty list -- delete both 1325 (delete-char +1)) ; delimiters. 1326 ((eq ?\; (char-after)) 1327 (paredit-forward-delete-comment-start)) 1328 ((eq (char-syntax (char-after)) ?\) ) 1329 (if (paredit-handle-sexp-errors 1330 (save-excursion (forward-char) (backward-sexp) t) 1331 nil) 1332 (message "End of list!") 1333 (progn 1334 (message "Deleting spurious closing delimiter.") 1335 (delete-char +1)))) 1336 ;; Just delete a single character, if it's not a closing 1337 ;; delimiter. (The character literal case is already handled 1338 ;; by now.) 1339 (t (delete-char +1)))) 1340 1341 (defun paredit-forward-delete-in-string () 1342 (let ((start+end (paredit-string-start+end-points))) 1343 (cond ((not (eq (point) (cdr start+end))) 1344 ;; If it's not the close-quote, it's safe to delete. But 1345 ;; first handle the case that we're in a string escape. 1346 (cond ((paredit-in-string-escape-p) 1347 ;; We're right after the backslash, so backward 1348 ;; delete it before deleting the escaped character. 1349 (delete-char -1)) 1350 ((eq (char-after) ?\\ ) 1351 ;; If we're not in a string escape, but we are on a 1352 ;; backslash, it must start the escape for the next 1353 ;; character, so delete the backslash before deleting 1354 ;; the next character. 1355 (delete-char +1))) 1356 (delete-char +1)) 1357 ((eq (1- (point)) (car start+end)) 1358 ;; If it is the close-quote, delete only if we're also right 1359 ;; past the open-quote (i.e. it's empty), and then delete 1360 ;; both quotes. Otherwise we refuse to delete it. 1361 (delete-char -1) 1362 (delete-char +1))))) 1363 1364 (defun paredit-check-forward-delete-in-comment () 1365 ;; Point is in a comment, possibly at eol. We are about to delete 1366 ;; some characters forward; if we are at eol, we are about to delete 1367 ;; the line break. Refuse to do so if if moving the next line into 1368 ;; the comment would break structure. 1369 (if (eolp) 1370 (let ((next-line-start (point-at-bol 2)) 1371 (next-line-end (point-at-eol 2))) 1372 (paredit-check-region next-line-start next-line-end)))) 1373 1374 (defun paredit-forward-delete-in-comment () 1375 (paredit-check-forward-delete-in-comment) 1376 (delete-char +1)) 1377 1378 (defun paredit-forward-delete-comment-start () 1379 ;; Point precedes a comment start (not at eol). Refuse to delete a 1380 ;; comment start if the comment contains unbalanced junk. 1381 (paredit-check-region (+ (point) 1) (point-at-eol)) 1382 (delete-char +1)) 1383 1384 (defun paredit-backward-delete (&optional argument) 1385 "Delete a character backward or move backward over a delimiter. 1386 If on a closing S-expression delimiter, move backward into the 1387 S-expression. 1388 If on an opening S-expression delimiter, refuse to delete unless the 1389 S-expression is empty, in which case delete the whole S-expression. 1390 With a numeric prefix argument N, delete N characters backward. 1391 With a `C-u' prefix argument, simply delete a character backward, 1392 without regard for delimiter balancing. 1393 1394 If `delete-active-region' is enabled and the mark is active and 1395 no prefix argument is specified, act as `paredit-delete-region' 1396 or `paredit-kill-region' as appropriate instead." 1397 (interactive "P") 1398 (cond ((consp argument) 1399 ;++ Should this untabify? 1400 (delete-char -1)) 1401 ((integerp argument) 1402 (let ((delete-active-region nil)) 1403 (if (< argument 0) 1404 (paredit-forward-delete (- 0 argument)) 1405 (while (> argument 0) 1406 (paredit-backward-delete) 1407 (setq argument (- argument 1)))))) 1408 ((paredit-delete-active-region-p) 1409 (paredit-delete-region (region-beginning) (region-end))) 1410 ((paredit-kill-active-region-p) 1411 (paredit-kill-region (region-beginning) (region-end))) 1412 ((bobp) 1413 (delete-char -1)) 1414 ((paredit-in-string-p) 1415 (paredit-backward-delete-in-string)) 1416 ((paredit-in-comment-p) 1417 (paredit-backward-delete-in-comment)) 1418 ((paredit-in-char-p) ; Escape -- delete both chars. 1419 (delete-char -1) 1420 (delete-char +1)) 1421 ((paredit-in-char-p (1- (point))) 1422 (delete-char -2)) ; ditto 1423 ((let ((syn (char-syntax (char-before)))) 1424 (or (eq syn ?\) ) 1425 (eq syn ?\" ))) 1426 (if (save-excursion 1427 (paredit-handle-sexp-errors (progn (backward-sexp) t) 1428 nil)) 1429 (backward-char) 1430 (message "Deleting spurious closing delimiter.") 1431 (delete-char -1))) 1432 ((and (eq (char-syntax (char-before)) ?\( ) 1433 (eq (char-after) (matching-paren (char-before)))) 1434 (delete-char -1) ; Empty list -- delete both 1435 (delete-char +1)) ; delimiters. 1436 ((bolp) 1437 (paredit-backward-delete-maybe-comment-end)) 1438 ((eq (char-syntax (char-before)) ?\( ) 1439 (if (paredit-handle-sexp-errors 1440 (save-excursion (backward-char) (forward-sexp) t) 1441 nil) 1442 (message "Beginning of list!") 1443 (progn 1444 (message "Deleting spurious closing delimiter.") 1445 (delete-char -1)))) 1446 ;; Delete it, unless it's an opening delimiter. The case of 1447 ;; character literals is already handled by now. 1448 (t 1449 ;; Turn off the @#&*&!^&(%^ botch in GNU Emacs 24 that changed 1450 ;; `backward-delete-char' and `backward-delete-char-untabify' 1451 ;; semantically so that they delete the region in transient 1452 ;; mark mode. 1453 (let ((delete-active-region nil)) 1454 (backward-delete-char-untabify +1))))) 1455 1456 (defun paredit-backward-delete-in-string () 1457 (let ((start+end (paredit-string-start+end-points))) 1458 (cond ((not (eq (1- (point)) (car start+end))) 1459 ;; If it's not the open-quote, it's safe to delete. 1460 (if (paredit-in-string-escape-p) 1461 ;; If we're on a string escape, since we're about to 1462 ;; delete the backslash, we must first delete the 1463 ;; escaped char. 1464 (delete-char +1)) 1465 (delete-char -1) 1466 (if (paredit-in-string-escape-p) 1467 ;; If, after deleting a character, we find ourselves in 1468 ;; a string escape, we must have deleted the escaped 1469 ;; character, and the backslash is behind the point, so 1470 ;; backward delete it. 1471 (delete-char -1))) 1472 ((eq (point) (cdr start+end)) 1473 ;; If it is the open-quote, delete only if we're also right 1474 ;; past the close-quote (i.e. it's empty), and then delete 1475 ;; both quotes. Otherwise we refuse to delete it. 1476 (delete-char -1) 1477 (delete-char +1))))) 1478 1479 (defun paredit-backward-delete-in-comment () 1480 ;; Point is in a comment, possibly just after the comment start. 1481 ;; Refuse to delete a comment start if the comment contains 1482 ;; unbalanced junk. 1483 (if (save-excursion 1484 (backward-char) 1485 ;; Must call `paredit-in-string-p' before 1486 ;; `paredit-in-comment-p'. 1487 (not (or (paredit-in-string-p) (paredit-in-comment-p)))) 1488 (paredit-check-region (point) (point-at-eol))) 1489 (backward-delete-char-untabify +1)) 1490 1491 (defun paredit-backward-delete-maybe-comment-end () 1492 ;; Point is at bol, possibly just after a comment end (i.e., the 1493 ;; previous line may have had a line comment). Refuse to delete a 1494 ;; comment end if moving the current line into the previous line's 1495 ;; comment would break structure. 1496 (if (save-excursion 1497 (backward-char) 1498 (and (not (paredit-in-string-p)) (paredit-in-comment-p))) 1499 (paredit-check-region (point-at-eol) (point-at-bol))) 1500 (delete-char -1)) 1501 1502 ;;;; Killing 1503 1504 (defun paredit-kill (&optional argument) 1505 "Kill a line as if with `kill-line', but respecting delimiters. 1506 In a string, act exactly as `kill-line' but do not kill past the 1507 closing string delimiter. 1508 On a line with no S-expressions on it starting after the point or 1509 within a comment, act exactly as `kill-line'. 1510 Otherwise, kill all S-expressions that start after the point. 1511 With a `C-u' prefix argument, just do the standard `kill-line'. 1512 With a numeric prefix argument N, do `kill-line' that many times." 1513 (interactive "P") 1514 (cond (argument 1515 (kill-line (if (integerp argument) argument 1))) 1516 ((paredit-in-string-p) 1517 (paredit-kill-line-in-string)) 1518 ((paredit-in-comment-p) 1519 (paredit-kill-line-in-comment)) 1520 ((save-excursion (paredit-skip-whitespace t (point-at-eol)) 1521 (or (eolp) (eq (char-after) ?\; ))) 1522 ;** Be careful about trailing backslashes. 1523 (if (paredit-in-char-p) 1524 (backward-char)) 1525 (kill-line)) 1526 (t (paredit-kill-sexps-on-line)))) 1527 1528 (defun paredit-kill-line-in-string () 1529 (if (save-excursion (paredit-skip-whitespace t (point-at-eol)) 1530 (eolp)) 1531 (kill-line) 1532 (save-excursion 1533 ;; Be careful not to split an escape sequence. 1534 (if (paredit-in-string-escape-p) 1535 (backward-char)) 1536 (kill-region (point) 1537 (min (point-at-eol) 1538 (cdr (paredit-string-start+end-points))))))) 1539 1540 (defun paredit-kill-line-in-comment () 1541 ;; The variable `kill-whole-line' is not relevant: the point is in a 1542 ;; comment, and hence not at the beginning of the line. 1543 (paredit-check-forward-delete-in-comment) 1544 (kill-line)) 1545 1546 (defun paredit-kill-sexps-on-line () 1547 (if (paredit-in-char-p) ; Move past the \ and prefix. 1548 (backward-char 2)) ; (# in Scheme/CL, ? in elisp) 1549 (let ((beginning (point)) 1550 (eol (point-at-eol))) 1551 (let ((end-of-list-p (paredit-forward-sexps-to-kill beginning eol))) 1552 ;; If we got to the end of the list and it's on the same line, 1553 ;; move backward past the closing delimiter before killing. (This 1554 ;; allows something like killing the whitespace in ( ).) 1555 (if end-of-list-p (progn (up-list) (backward-char))) 1556 (if kill-whole-line 1557 (paredit-kill-sexps-on-whole-line beginning) 1558 (kill-region beginning 1559 ;; If all of the S-expressions were on one line, 1560 ;; i.e. we're still on that line after moving past 1561 ;; the last one, kill the whole line, including 1562 ;; any comments; otherwise just kill to the end of 1563 ;; the last S-expression we found. Be sure, 1564 ;; though, not to kill any closing parentheses. 1565 (if (and (not end-of-list-p) 1566 (eq (point-at-eol) eol)) 1567 eol 1568 (point))))))) 1569 1570 ;;; Please do not try to understand this code unless you have a VERY 1571 ;;; good reason to do so. I gave up trying to figure it out well 1572 ;;; enough to explain it, long ago. 1573 1574 (defun paredit-forward-sexps-to-kill (beginning eol) 1575 (let ((end-of-list-p nil) 1576 (firstp t)) 1577 ;; Move to the end of the last S-expression that started on this 1578 ;; line, or to the closing delimiter if the last S-expression in 1579 ;; this list is on the line. 1580 (catch 'return 1581 (while t 1582 ;; This and the `kill-whole-line' business below fix a bug that 1583 ;; inhibited any S-expression at the very end of the buffer 1584 ;; (with no trailing newline) from being deleted. It's a 1585 ;; bizarre fix that I ought to document at some point, but I am 1586 ;; too busy at the moment to do so. 1587 (if (and kill-whole-line (eobp)) (throw 'return nil)) 1588 (save-excursion 1589 (paredit-handle-sexp-errors (forward-sexp) 1590 (up-list) 1591 (setq end-of-list-p (eq (point-at-eol) eol)) 1592 (throw 'return nil)) 1593 (if (or (and (not firstp) 1594 (not kill-whole-line) 1595 (eobp)) 1596 (paredit-handle-sexp-errors 1597 (progn (backward-sexp) nil) 1598 t) 1599 (not (eq (point-at-eol) eol))) 1600 (throw 'return nil))) 1601 (forward-sexp) 1602 (if (and firstp 1603 (not kill-whole-line) 1604 (eobp)) 1605 (throw 'return nil)) 1606 (setq firstp nil))) 1607 end-of-list-p)) 1608 1609 (defun paredit-kill-sexps-on-whole-line (beginning) 1610 (kill-region beginning 1611 (or (save-excursion ; Delete trailing indentation... 1612 (paredit-skip-whitespace t) 1613 (and (not (eq (char-after) ?\; )) 1614 (point))) 1615 ;; ...or just use the point past the newline, if 1616 ;; we encounter a comment. 1617 (point-at-eol))) 1618 (cond ((save-excursion (paredit-skip-whitespace nil (point-at-bol)) 1619 (bolp)) 1620 ;; Nothing but indentation before the point, so indent it. 1621 (lisp-indent-line)) 1622 ((eobp) nil) ; Protect the CHAR-SYNTAX below against NIL. 1623 ;; Insert a space to avoid invalid joining if necessary. 1624 ((let ((syn-before (char-syntax (char-before))) 1625 (syn-after (char-syntax (char-after)))) 1626 (or (and (eq syn-before ?\) ) ; Separate opposing 1627 (eq syn-after ?\( )) ; parentheses, 1628 (and (eq syn-before ?\" ) ; string delimiter 1629 (eq syn-after ?\" )) ; pairs, 1630 (and (memq syn-before '(?_ ?w)) ; or word or symbol 1631 (memq syn-after '(?_ ?w))))) ; constituents. 1632 (insert " ")))) 1633 1634 ;;;;; Killing Words 1635 1636 ;;; This is tricky and asymmetrical because backward parsing is 1637 ;;; extraordinarily difficult or impossible, so we have to implement 1638 ;;; killing in both directions by parsing forward. 1639 1640 (defun paredit-forward-kill-word (&optional argument) 1641 "Kill a word forward, skipping over intervening delimiters." 1642 (interactive "p") 1643 (let ((argument (or argument 1))) 1644 (if (< argument 0) 1645 (paredit-backward-kill-word (- argument)) 1646 (dotimes (i argument) 1647 (let ((beginning (point))) 1648 (skip-syntax-forward " -") 1649 (let* ((parse-state (paredit-current-parse-state)) 1650 (state (paredit-kill-word-state parse-state 'char-after))) 1651 (while (not (or (eobp) 1652 (eq ?w (char-syntax (char-after))))) 1653 (setq parse-state 1654 (progn (forward-char 1) (paredit-current-parse-state)) 1655 ;; XXX Why did I comment this out? 1656 ;; (parse-partial-sexp (point) (1+ (point)) 1657 ;; nil nil parse-state) 1658 ) 1659 (let* ((old-state state) 1660 (new-state 1661 (paredit-kill-word-state parse-state 'char-after))) 1662 (cond ((not (eq old-state new-state)) 1663 (setq parse-state 1664 (paredit-kill-word-hack old-state 1665 new-state 1666 parse-state)) 1667 (setq state 1668 (paredit-kill-word-state parse-state 1669 'char-after)) 1670 (setq beginning (point))))))) 1671 (goto-char beginning) 1672 (kill-word 1)))))) 1673 1674 (defun paredit-backward-kill-word (&optional argument) 1675 "Kill a word backward, skipping over any intervening delimiters." 1676 (interactive "p") 1677 (let ((argument (or argument 1))) 1678 (if (< argument 0) 1679 (paredit-forward-kill-word (- argument)) 1680 (dotimes (i argument) 1681 (if (not (or (bobp) 1682 (eq (char-syntax (char-before)) ?w))) 1683 (let ((end (point))) 1684 (backward-word 1) 1685 (forward-word 1) 1686 (goto-char (min end (point))) 1687 (let* ((parse-state (paredit-current-parse-state)) 1688 (state 1689 (paredit-kill-word-state parse-state 'char-before))) 1690 (while (and (< (point) end) 1691 (progn 1692 (setq parse-state 1693 (parse-partial-sexp (point) (1+ (point)) 1694 nil nil parse-state)) 1695 (or (eq state 1696 (paredit-kill-word-state parse-state 1697 'char-before)) 1698 (progn (backward-char 1) nil))))) 1699 (if (and (eq state 'comment) 1700 (eq ?\# (char-after (point))) 1701 (eq ?\| (char-before (point)))) 1702 (backward-char 1))))) 1703 (backward-kill-word 1))))) 1704 1705 ;;;;;; Word-Killing Auxiliaries 1706 1707 (defun paredit-kill-word-state (parse-state adjacent-char-fn) 1708 (cond ((paredit-in-comment-p parse-state) 'comment) 1709 ((paredit-in-string-p parse-state) 'string) 1710 ((memq (char-syntax (funcall adjacent-char-fn)) 1711 '(?\( ?\) )) 1712 'delimiter) 1713 (t 'other))) 1714 1715 ;;; This optionally advances the point past any comment delimiters that 1716 ;;; should probably not be touched, based on the last state change and 1717 ;;; the characters around the point. It returns a new parse state, 1718 ;;; starting from the PARSE-STATE parameter. 1719 1720 (defun paredit-kill-word-hack (old-state new-state parse-state) 1721 (cond ((and (not (eq old-state 'comment)) 1722 (not (eq new-state 'comment)) 1723 (not (paredit-in-string-escape-p)) 1724 (eq ?\# (char-before)) 1725 (eq ?\| (char-after))) 1726 (forward-char 1) 1727 (paredit-current-parse-state) 1728 ;; (parse-partial-sexp (point) (1+ (point)) 1729 ;; nil nil parse-state) 1730 ) 1731 ((and (not (eq old-state 'comment)) 1732 (eq new-state 'comment) 1733 (eq ?\; (char-before))) 1734 (skip-chars-forward ";") 1735 (paredit-current-parse-state) 1736 ;; (parse-partial-sexp (point) (save-excursion 1737 ;; (skip-chars-forward ";")) 1738 ;; nil nil parse-state) 1739 ) 1740 (t parse-state))) 1741 1742 (defun paredit-copy-as-kill () 1743 "Save in the kill ring the region that `paredit-kill' would kill." 1744 (interactive) 1745 (cond ((paredit-in-string-p) 1746 (paredit-copy-as-kill-in-string)) 1747 ((paredit-in-comment-p) 1748 (copy-region-as-kill (point) (point-at-eol))) 1749 ((save-excursion (paredit-skip-whitespace t (point-at-eol)) 1750 (or (eolp) (eq (char-after) ?\; ))) 1751 ;** Be careful about trailing backslashes. 1752 (save-excursion 1753 (if (paredit-in-char-p) 1754 (backward-char)) 1755 (copy-region-as-kill (point) (point-at-eol)))) 1756 (t (paredit-copy-sexps-as-kill)))) 1757 1758 (defun paredit-copy-as-kill-in-string () 1759 (save-excursion 1760 (if (paredit-in-string-escape-p) 1761 (backward-char)) 1762 (copy-region-as-kill (point) 1763 (min (point-at-eol) 1764 (cdr (paredit-string-start+end-points)))))) 1765 1766 (defun paredit-copy-sexps-as-kill () 1767 (save-excursion 1768 (if (paredit-in-char-p) 1769 (backward-char 2)) 1770 (let ((beginning (point)) 1771 (eol (point-at-eol))) 1772 (let ((end-of-list-p (paredit-forward-sexps-to-kill beginning eol))) 1773 (if end-of-list-p (progn (up-list) (backward-char))) 1774 (copy-region-as-kill beginning 1775 (cond (kill-whole-line 1776 (or (save-excursion 1777 (paredit-skip-whitespace t) 1778 (and (not (eq (char-after) ?\; )) 1779 (point))) 1780 (point-at-eol))) 1781 ((and (not end-of-list-p) 1782 (eq (point-at-eol) eol)) 1783 eol) 1784 (t 1785 (point)))))))) 1786 1787 ;;;; Deleting Regions 1788 1789 (defun paredit-delete-region (start end) 1790 "Delete the text between point and mark, like `delete-region'. 1791 If that text is unbalanced, signal an error instead. 1792 With a prefix argument, skip the balance check." 1793 (interactive "r") 1794 (if (and start end (not current-prefix-arg)) 1795 (paredit-check-region-for-delete start end)) 1796 (setq this-command 'delete-region) 1797 (delete-region start end)) 1798 1799 (defun paredit-kill-region (start end) 1800 "Kill the text between point and mark, like `kill-region'. 1801 If that text is unbalanced, signal an error instead. 1802 With a prefix argument, skip the balance check." 1803 (interactive "r") 1804 (if (and start end (not current-prefix-arg)) 1805 (paredit-check-region-for-delete start end)) 1806 (setq this-command 'kill-region) 1807 (kill-region start end)) 1808 1809 (defun paredit-check-region-for-delete (start end) 1810 "Signal an error deleting text between START and END is unsafe." 1811 (save-excursion 1812 (goto-char start) 1813 (let* ((start-state (paredit-current-parse-state)) 1814 (end-state (parse-partial-sexp start end nil nil start-state))) 1815 (paredit-check-region-for-delete:depth start start-state end end-state) 1816 (paredit-check-region-for-delete:string start start-state end end-state) 1817 (paredit-check-region-for-delete:comment start start-state end end-state) 1818 (paredit-check-region-for-delete:char-quote start start-state 1819 end end-state)))) 1820 1821 (defun paredit-check-region-for-delete:depth (start start-state end end-state) 1822 (let ((start-depth (nth 0 start-state)) 1823 (end-depth (nth 0 end-state))) 1824 (if (not (= start-depth end-depth)) 1825 (error "Mismatched parenthesis depth: %S at start, %S at end." 1826 start-depth 1827 end-depth)))) 1828 1829 (defun paredit-check-region-for-delete:string (start start-state end end-state) 1830 (let ((start-string-p (nth 3 start-state)) 1831 (end-string-p (nth 3 end-state))) 1832 (if (not (eq start-string-p end-string-p)) 1833 (error "Mismatched string state: start %sin string, end %sin string." 1834 (if start-string-p "" "not ") 1835 (if end-string-p "" "not "))))) 1836 1837 (defun paredit-check-region-for-delete:comment 1838 (start start-state end end-state) 1839 (let ((start-comment-state (nth 4 start-state)) 1840 (end-comment-state (nth 4 end-state))) 1841 (if (not (or (eq start-comment-state end-comment-state) 1842 ;; If we are moving text into or out of a line 1843 ;; comment, make sure that the text is balanced. (The 1844 ;; comment state may be a number, not t or nil at all, 1845 ;; for nestable comments, which are not handled by 1846 ;; this heuristic (or any of paredit, really).) 1847 (and (or (and (eq start-comment-state nil) 1848 (eq end-comment-state t)) 1849 (and (eq start-comment-state t) 1850 (eq end-comment-state nil))) 1851 (save-excursion 1852 (goto-char end) 1853 (paredit-region-ok-p (point) (point-at-eol)))))) 1854 (error "Mismatched comment state: %s" 1855 (cond ((and (integerp start-comment-state) 1856 (integerp end-comment-state)) 1857 (format "depth %S at start, depth %S at end." 1858 start-comment-state 1859 end-comment-state)) 1860 ((integerp start-comment-state) 1861 "start in nested comment, end otherwise.") 1862 ((integerp end-comment-state) 1863 "end in nested comment, start otherwise.") 1864 (start-comment-state 1865 "start in comment, end not in comment.") 1866 (end-comment-state 1867 "end in comment, start not in comment.") 1868 (t 1869 (format "start %S, end %S." 1870 start-comment-state 1871 end-comment-state))))))) 1872 1873 (defun paredit-check-region-for-delete:char-quote 1874 (start start-state end end-state) 1875 (let ((start-char-quote (nth 5 start-state)) 1876 (end-char-quote (nth 5 end-state))) 1877 (if (not (eq start-char-quote end-char-quote)) 1878 (let ((phrase "character quotation")) 1879 (error "Mismatched %s: start %sin %s, end %sin %s." 1880 phrase 1881 (if start-char-quote "" "not ") 1882 phrase 1883 (if end-char-quote "" "not ") 1884 phrase))))) 1885 1886 ;;;; Point Motion 1887 1888 (eval-and-compile 1889 (defmacro defun-motion (name bvl doc &rest body) 1890 `(defun ,name ,bvl 1891 ,doc 1892 ,(xcond ((paredit-xemacs-p) 1893 '(interactive "_")) 1894 ((paredit-gnu-emacs-p) 1895 ;++ Not sure this is sufficient for the `^'. 1896 (if (fboundp 'handle-shift-selection) 1897 '(interactive "^p") 1898 '(interactive "p")))) 1899 ,@body))) 1900 1901 (defun-motion paredit-forward (&optional arg) 1902 "Move forward an S-expression, or up an S-expression forward. 1903 If there are no more S-expressions in this one before the closing 1904 delimiter, move past that closing delimiter; otherwise, move forward 1905 past the S-expression following the point." 1906 (let ((n (or arg 1))) 1907 (cond ((< 0 n) (dotimes (i n) (paredit-move-forward))) 1908 ((< n 0) (dotimes (i (- n)) (paredit-move-backward)))))) 1909 1910 (defun-motion paredit-backward (&optional arg) 1911 "Move backward an S-expression, or up an S-expression backward. 1912 If there are no more S-expressions in this one before the opening 1913 delimiter, move past that opening delimiter backward; otherwise, move 1914 move backward past the S-expression preceding the point." 1915 (let ((n (or arg 1))) 1916 (cond ((< 0 n) (dotimes (i n) (paredit-move-backward))) 1917 ((< n 0) (dotimes (i (- n)) (paredit-move-forward)))))) 1918 1919 (defun paredit-move-forward () 1920 (cond ((paredit-in-string-p) 1921 (let ((end (paredit-enclosing-string-end))) 1922 ;; `forward-sexp' and `up-list' may move into the next string 1923 ;; in the buffer. Don't do that; move out of the current one. 1924 (if (paredit-handle-sexp-errors 1925 (progn (paredit-handle-sexp-errors (forward-sexp) 1926 (up-list)) 1927 (<= end (point))) 1928 t) 1929 (goto-char end)))) 1930 ((paredit-in-char-p) 1931 (forward-char)) 1932 (t 1933 (paredit-handle-sexp-errors (forward-sexp) 1934 (up-list))))) 1935 1936 (defun paredit-move-backward () 1937 (cond ((paredit-in-string-p) 1938 (let ((start (paredit-enclosing-string-start))) 1939 (if (paredit-handle-sexp-errors 1940 (progn (paredit-handle-sexp-errors (backward-sexp) 1941 (backward-up-list)) 1942 (<= (point) start)) 1943 t) 1944 (goto-char start)))) 1945 ((paredit-in-char-p) 1946 ;++ Corner case: a buffer of `\|x'. What to do? 1947 (backward-char 2)) 1948 (t 1949 (paredit-handle-sexp-errors (backward-sexp) 1950 (backward-up-list))))) 1951 1952 ;;;; Window Positioning 1953 1954 (defalias 'paredit-recentre-on-sexp 'paredit-recenter-on-sexp) 1955 1956 (defun paredit-recenter-on-sexp (&optional n) 1957 "Recenter the screen on the S-expression following the point. 1958 With a prefix argument N, encompass all N S-expressions forward." 1959 (interactive "P") 1960 (let* ((p (point)) 1961 (end-point (progn (forward-sexp n) (point))) 1962 (start-point (progn (goto-char end-point) (backward-sexp n) (point)))) 1963 ;; Point is at beginning of first S-expression. 1964 (let ((p-visible nil) (start-visible nil)) 1965 (save-excursion 1966 (forward-line (/ (count-lines start-point end-point) 2)) 1967 (recenter) 1968 (setq p-visible (pos-visible-in-window-p p)) 1969 (setq start-visible (pos-visible-in-window-p start-point))) 1970 (cond ((not start-visible) 1971 ;; Implies (not p-visible). Put the start at the top of 1972 ;; the screen. 1973 (recenter 0)) 1974 (p-visible 1975 ;; Go back to p if we can. 1976 (goto-char p)))))) 1977 1978 (defun paredit-recenter-on-defun () 1979 "Recenter the screen on the definition at point." 1980 (interactive) 1981 (save-excursion 1982 (beginning-of-defun) 1983 (paredit-recenter-on-sexp))) 1984 1985 (defun paredit-focus-on-defun () 1986 "Moves display to the top of the definition at point." 1987 (interactive) 1988 (beginning-of-defun) 1989 (recenter 0)) 1990 1991 ;;;; Generalized Upward/Downward Motion 1992 1993 (defun paredit-up/down (n vertical-direction) 1994 (let ((horizontal-direction (if (< 0 n) +1 -1))) 1995 (while (/= n 0) 1996 (goto-char 1997 (paredit-next-up/down-point horizontal-direction vertical-direction)) 1998 (setq n (- n horizontal-direction))))) 1999 2000 (defun paredit-next-up/down-point (horizontal-direction vertical-direction) 2001 (let ((state (paredit-current-parse-state)) 2002 (scan-lists 2003 (lambda () 2004 (scan-lists (point) horizontal-direction vertical-direction)))) 2005 (cond ((paredit-in-string-p state) 2006 (let ((start+end (paredit-string-start+end-points state))) 2007 (if (< 0 vertical-direction) 2008 (if (< 0 horizontal-direction) 2009 (+ 1 (cdr start+end)) 2010 (car start+end)) 2011 ;; We could let the user try to descend into lists 2012 ;; within the string, but that would be asymmetric 2013 ;; with the up case, which rises out of the whole 2014 ;; string and not just out of a list within the 2015 ;; string, so this case will just be an error. 2016 (error "Can't descend further into string.")))) 2017 ((< 0 vertical-direction) 2018 ;; When moving up, just try to rise up out of the list. 2019 (or (funcall scan-lists) 2020 (buffer-end horizontal-direction))) 2021 ((< vertical-direction 0) 2022 ;; When moving down, look for a string closer than a list, 2023 ;; and use that if we find it. 2024 (let* ((list-start 2025 (paredit-handle-sexp-errors (funcall scan-lists) nil)) 2026 (string-start 2027 (paredit-find-next-string-start horizontal-direction 2028 list-start))) 2029 (if (and string-start list-start) 2030 (if (< 0 horizontal-direction) 2031 (min string-start list-start) 2032 (max string-start list-start)) 2033 (or string-start 2034 ;; Scan again: this is a kludgey way to report the 2035 ;; error if there really was one. 2036 (funcall scan-lists) 2037 (buffer-end horizontal-direction))))) 2038 (t 2039 (error "Vertical direction must be nonzero in `%s'." 2040 'paredit-up/down))))) 2041 2042 (defun paredit-find-next-string-start (horizontal-direction limit) 2043 (let ((buffer-limit-p (if (< 0 horizontal-direction) 'eobp 'bobp)) 2044 (next-char (if (< 0 horizontal-direction) 'char-after 'char-before)) 2045 (pastp (if (< 0 horizontal-direction) '> '<))) 2046 (paredit-handle-sexp-errors 2047 (save-excursion 2048 (catch 'exit 2049 (while t 2050 (if (or (funcall buffer-limit-p) 2051 (and limit (funcall pastp (point) limit))) 2052 (throw 'exit nil)) 2053 (forward-sexp horizontal-direction) 2054 (save-excursion 2055 (backward-sexp horizontal-direction) 2056 (if (eq ?\" (char-syntax (funcall next-char))) 2057 (throw 'exit (+ (point) horizontal-direction))))))) 2058 nil))) 2059 2060 (defun-motion paredit-forward-down (&optional argument) 2061 "Move forward down into a list. 2062 With a positive argument, move forward down that many levels. 2063 With a negative argument, move backward down that many levels." 2064 (paredit-up/down (or argument +1) -1)) 2065 2066 (defun-motion paredit-backward-up (&optional argument) 2067 "Move backward up out of the enclosing list. 2068 With a positive argument, move backward up that many levels. 2069 With a negative argument, move forward up that many levels. 2070 If in a string initially, that counts as one level." 2071 (paredit-up/down (- 0 (or argument +1)) +1)) 2072 2073 (defun-motion paredit-forward-up (&optional argument) 2074 "Move forward up out of the enclosing list. 2075 With a positive argument, move forward up that many levels. 2076 With a negative argument, move backward up that many levels. 2077 If in a string initially, that counts as one level." 2078 (paredit-up/down (or argument +1) +1)) 2079 2080 (defun-motion paredit-backward-down (&optional argument) 2081 "Move backward down into a list. 2082 With a positive argument, move backward down that many levels. 2083 With a negative argument, move forward down that many levels." 2084 (paredit-up/down (- 0 (or argument +1)) -1)) 2085 2086 ;;;; Depth-Changing Commands: Wrapping, Splicing, & Raising 2087 2088 (defun paredit-wrap-sexp (&optional argument open close) 2089 "Wrap the following S-expression. 2090 If a `C-u' prefix argument is given, wrap all S-expressions following 2091 the point until the end of the buffer or of the enclosing list. 2092 If a numeric prefix argument N is given, wrap N S-expressions. 2093 Automatically indent the newly wrapped S-expression. 2094 As a special case, if the point is at the end of a list, simply insert 2095 a parenthesis pair, rather than inserting a lone opening delimiter 2096 and then signalling an error, in the interest of preserving 2097 structure. 2098 By default OPEN and CLOSE are round delimiters." 2099 (interactive "P") 2100 (paredit-lose-if-not-in-sexp 'paredit-wrap-sexp) 2101 (let ((open (or open ?\( )) 2102 (close (or close ?\) ))) 2103 (paredit-handle-sexp-errors 2104 ((lambda (n) (paredit-insert-pair n open close 'goto-char)) 2105 (cond ((integerp argument) argument) 2106 ((consp argument) (paredit-count-sexps-forward)) 2107 ((paredit-region-active-p) nil) 2108 (t 1))) 2109 (insert close) 2110 (backward-char))) 2111 (save-excursion (backward-up-list) (indent-sexp))) 2112 2113 (defun paredit-yank-pop (&optional argument) 2114 "Replace just-yanked text with the next item in the kill ring. 2115 If this command follows a `yank', just run `yank-pop'. 2116 If this command follows a `paredit-wrap-sexp', or any other paredit 2117 wrapping command (see `paredit-wrap-commands'), run `yank' and 2118 reindent the enclosing S-expression. 2119 If this command is repeated, run `yank-pop' and reindent the enclosing 2120 S-expression. 2121 2122 The argument is passed on to `yank' or `yank-pop'; see their 2123 documentation for details." 2124 (interactive "*p") 2125 (cond ((eq last-command 'yank) 2126 (yank-pop argument)) 2127 ((memq last-command paredit-wrap-commands) 2128 (yank argument) 2129 ;; `yank' futzes with `this-command'. 2130 (setq this-command 'paredit-yank-pop) 2131 (save-excursion (backward-up-list) (indent-sexp))) 2132 ((eq last-command 'paredit-yank-pop) 2133 ;; Pretend we just did a `yank', so that we can use 2134 ;; `yank-pop' without duplicating its definition. 2135 (setq last-command 'yank) 2136 (yank-pop argument) 2137 ;; Return to our original state. 2138 (setq last-command 'paredit-yank-pop) 2139 (setq this-command 'paredit-yank-pop) 2140 (save-excursion (backward-up-list) (indent-sexp))) 2141 (t (error "Last command was not a yank or a wrap: %s" last-command)))) 2142 2143 (defun paredit-splice-sexp (&optional argument) 2144 "Splice the list that the point is on by removing its delimiters. 2145 With a prefix argument as in `C-u', kill all S-expressions backward in 2146 the current list before splicing all S-expressions forward into the 2147 enclosing list. 2148 With two prefix arguments as in `C-u C-u', kill all S-expressions 2149 forward in the current list before splicing all S-expressions 2150 backward into the enclosing list. 2151 With a numerical prefix argument N, kill N S-expressions backward in 2152 the current list before splicing the remaining S-expressions into the 2153 enclosing list. If N is negative, kill forward. 2154 Inside a string, unescape all backslashes, or signal an error if doing 2155 so would invalidate the buffer's structure." 2156 (interactive "P") 2157 (if (paredit-in-string-p) 2158 (paredit-splice-string argument) 2159 (if (paredit-in-comment-p) 2160 (error "Can't splice comment.")) 2161 (paredit-handle-sexp-errors (paredit-enclosing-list-start) 2162 (error "Can't splice top level.")) 2163 (paredit-kill-surrounding-sexps-for-splice argument) 2164 (let ((delete-start (paredit-enclosing-list-start)) 2165 (delete-end 2166 (let ((limit 2167 (save-excursion 2168 (paredit-ignore-sexp-errors (forward-sexp) (backward-sexp)) 2169 (point)))) 2170 (save-excursion 2171 (backward-up-list) 2172 (forward-char +1) 2173 (paredit-skip-whitespace t limit) 2174 (point))))) 2175 (let ((end-marker (make-marker))) 2176 (save-excursion 2177 (up-list) 2178 (delete-char -1) 2179 (set-marker end-marker (point))) 2180 (delete-region delete-start delete-end) 2181 (paredit-splice-reindent delete-start (marker-position end-marker)))))) 2182 2183 (defun paredit-splice-reindent (start end) 2184 (paredit-preserving-column 2185 ;; If we changed the first subform of the enclosing list, we must 2186 ;; reindent the whole enclosing list. 2187 (if (paredit-handle-sexp-errors 2188 (save-excursion 2189 (backward-up-list) 2190 (down-list) 2191 (paredit-ignore-sexp-errors (forward-sexp)) 2192 (< start (point))) 2193 nil) 2194 (save-excursion (backward-up-list) (indent-sexp)) 2195 (paredit-indent-region start end)))) 2196 2197 (defun paredit-kill-surrounding-sexps-for-splice (argument) 2198 (cond ((or (paredit-in-string-p) 2199 (paredit-in-comment-p)) 2200 (error "Invalid context for splicing S-expressions.")) 2201 ((or (not argument) (eq argument 0)) nil) 2202 ((or (numberp argument) (eq argument '-)) 2203 ;; Kill S-expressions before/after the point by saving the 2204 ;; point, moving across them, and killing the region. 2205 (let* ((argument (if (eq argument '-) -1 argument)) 2206 (saved (paredit-point-at-sexp-boundary (- argument)))) 2207 (goto-char saved) 2208 (paredit-ignore-sexp-errors (backward-sexp argument)) 2209 (paredit-hack-kill-region saved (point)))) 2210 ((consp argument) 2211 (let ((v (car argument))) 2212 (if (= v 4) ;One `C-u'. 2213 ;; Move backward until we hit the open paren; then 2214 ;; kill that selected region. 2215 (let ((end (point))) 2216 (paredit-ignore-sexp-errors 2217 (while (not (bobp)) 2218 (backward-sexp))) 2219 (paredit-hack-kill-region (point) end)) 2220 ;; Move forward until we hit the close paren; then 2221 ;; kill that selected region. 2222 (let ((beginning (point))) 2223 (paredit-ignore-sexp-errors 2224 (while (not (eobp)) 2225 (forward-sexp))) 2226 (paredit-hack-kill-region beginning (point)))))) 2227 (t (error "Bizarre prefix argument `%s'." argument)))) 2228 2229 (defun paredit-splice-sexp-killing-backward (&optional n) 2230 "Splice the list the point is on by removing its delimiters, and 2231 also kill all S-expressions before the point in the current list. 2232 With a prefix argument N, kill only the preceding N S-expressions." 2233 (interactive "P") 2234 (paredit-splice-sexp (if n 2235 (prefix-numeric-value n) 2236 '(4)))) 2237 2238 (defun paredit-splice-sexp-killing-forward (&optional n) 2239 "Splice the list the point is on by removing its delimiters, and 2240 also kill all S-expressions after the point in the current list. 2241 With a prefix argument N, kill only the following N S-expressions." 2242 (interactive "P") 2243 (paredit-splice-sexp (if n 2244 (- (prefix-numeric-value n)) 2245 '(16)))) 2246 2247 (defun paredit-raise-sexp (&optional argument) 2248 "Raise the following S-expression in a tree, deleting its siblings. 2249 With a prefix argument N, raise the following N S-expressions. If N 2250 is negative, raise the preceding N S-expressions. 2251 If the point is on an S-expression, such as a string or a symbol, not 2252 between them, that S-expression is considered to follow the point." 2253 (interactive "P") 2254 (save-excursion 2255 ;; Select the S-expressions we want to raise in a buffer substring. 2256 (let* ((bound 2257 (if (and (not argument) (paredit-region-active-p)) 2258 (progn (if (< (mark) (point)) 2259 (paredit-check-region (mark) (point)) 2260 (paredit-check-region (point) (mark))) 2261 (mark)) 2262 (cond ((paredit-in-string-p) 2263 (goto-char (car (paredit-string-start+end-points)))) 2264 ((paredit-in-char-p) 2265 (backward-sexp)) 2266 ((paredit-in-comment-p) 2267 (error "No S-expression to raise in comment."))) 2268 (scan-sexps (point) (prefix-numeric-value argument)))) 2269 (sexps 2270 (if (< bound (point)) 2271 (buffer-substring bound (paredit-point-at-sexp-end)) 2272 (buffer-substring (paredit-point-at-sexp-start) bound)))) 2273 ;; Move up to the list we're raising those S-expressions out of and 2274 ;; delete it. 2275 (backward-up-list) 2276 (delete-region (point) (scan-sexps (point) 1)) 2277 (let* ((indent-start (point)) 2278 (indent-end (save-excursion (insert sexps) (point)))) 2279 ;; If the expression spans multiple lines, its indentation is 2280 ;; probably broken, so reindent it -- but don't reindent 2281 ;; anything that we didn't touch outside the expression. 2282 ;; 2283 ;; XXX What if the *column* of the starting point was preserved 2284 ;; too? Should we avoid reindenting in that case? 2285 (if (not (eq (save-excursion (goto-char indent-start) (point-at-eol)) 2286 (save-excursion (goto-char indent-end) (point-at-eol)))) 2287 (indent-region indent-start indent-end nil)))))) 2288 2289 ;;; The effects of convolution on the surrounding whitespace are pretty 2290 ;;; random. If you have better suggestions, please let me know. 2291 2292 (defun paredit-convolute-sexp (&optional n) 2293 "Convolute S-expressions. 2294 Save the S-expressions preceding point and delete them. 2295 Splice the S-expressions following point. 2296 Wrap the enclosing list in a new list prefixed by the saved text. 2297 With a prefix argument N, move up N lists before wrapping." 2298 (interactive "p") 2299 (paredit-lose-if-not-in-sexp 'paredit-convolute-sexp) 2300 ;; Make sure we can move up before destroying anything. 2301 (save-excursion (backward-up-list n) (backward-up-list)) 2302 (let (open close) ;++ Is this a good idea? 2303 (let ((prefix 2304 (let ((end (point))) 2305 (paredit-ignore-sexp-errors 2306 (while (not (bobp)) (backward-sexp))) 2307 (prog1 (buffer-substring (point) end) 2308 (backward-up-list) 2309 (save-excursion (forward-sexp) 2310 (setq close (char-before)) 2311 (delete-char -1)) 2312 (setq open (char-after)) 2313 (delete-region (point) end) 2314 ;; I'm not sure this makes sense... 2315 (if (not (eolp)) (just-one-space)))))) 2316 (backward-up-list n) 2317 (paredit-insert-pair 1 open close 'goto-char) 2318 (insert prefix) 2319 ;; I'm not sure this makes sense either... 2320 (if (not (eolp)) (just-one-space)) 2321 (save-excursion 2322 (backward-up-list) 2323 (paredit-ignore-sexp-errors (indent-sexp)))))) 2324 2325 (defun paredit-splice-string (argument) 2326 (let ((original-point (point)) 2327 (start+end (paredit-string-start+end-points))) 2328 (let ((start (car start+end)) 2329 (end (cdr start+end))) 2330 ;; START and END both lie before the respective quote 2331 ;; characters, which we want to delete; thus we increment START 2332 ;; by one to extract the string, and we increment END by one to 2333 ;; delete the string. 2334 (let* ((escaped-string 2335 (cond ((not (consp argument)) 2336 (buffer-substring (1+ start) end)) 2337 ((= 4 (car argument)) 2338 (buffer-substring original-point end)) 2339 (t 2340 (buffer-substring (1+ start) original-point)))) 2341 (unescaped-string 2342 (paredit-unescape-string escaped-string))) 2343 (if (not unescaped-string) 2344 (error "Unspliceable string.") 2345 (save-excursion 2346 (goto-char start) 2347 (delete-region start (1+ end)) 2348 (insert unescaped-string)) 2349 (if (not (and (consp argument) 2350 (= 4 (car argument)))) 2351 (goto-char (- original-point 1)))))))) 2352 2353 (defun paredit-unescape-string (string) 2354 (with-temp-buffer 2355 (insert string) 2356 (goto-char (point-min)) 2357 (while (and (not (eobp)) 2358 ;; nil -> no bound; t -> no errors. 2359 (search-forward "\\" nil t)) 2360 (delete-char -1) 2361 (forward-char)) 2362 (paredit-handle-sexp-errors 2363 (progn (scan-sexps (point-min) (point-max)) 2364 (buffer-string)) 2365 nil))) 2366 2367 ;;;; Slurpage & Barfage 2368 2369 (defun paredit-forward-slurp-sexp (&optional argument) 2370 "Add the S-expression following the current list into that list 2371 by moving the closing delimiter. 2372 Automatically reindent the newly slurped S-expression with respect to 2373 its new enclosing form. 2374 If in a string, move the opening double-quote forward by one 2375 S-expression and escape any intervening characters as necessary, 2376 without altering any indentation or formatting." 2377 (interactive "P") 2378 (save-excursion 2379 (cond ((paredit-in-comment-p) 2380 (error "Invalid context for slurping S-expressions.")) 2381 ((numberp argument) 2382 (if (< argument 0) 2383 (paredit-forward-barf-sexp (- 0 argument)) 2384 (while (< 0 argument) 2385 (paredit-forward-slurp-sexp) 2386 (setq argument (- argument 1))))) 2387 ((paredit-in-string-p) 2388 ;; If there is anything to slurp into the string, take that. 2389 ;; Otherwise, try to slurp into the enclosing list. 2390 (if (save-excursion 2391 (goto-char (paredit-enclosing-string-end)) 2392 (paredit-handle-sexp-errors (progn (forward-sexp) nil) 2393 t)) 2394 (progn 2395 (goto-char (paredit-enclosing-string-end)) 2396 (paredit-forward-slurp-into-list argument)) 2397 (paredit-forward-slurp-into-string argument))) 2398 (t 2399 (paredit-forward-slurp-into-list argument))))) 2400 2401 (defun paredit-forward-slurp-into-list (&optional argument) 2402 (let ((nestedp nil)) 2403 (save-excursion 2404 (up-list) ; Up to the end of the list to 2405 (let ((close (char-before))) ; save and delete the closing 2406 (delete-char -1) ; delimiter. 2407 (let ((start (point))) 2408 (catch 'return ; Go to the end of the desired 2409 (while t ; S-expression, going up a 2410 (paredit-handle-sexp-errors ; list if it's not in this, 2411 (progn (forward-sexp) 2412 (if argument 2413 (paredit-ignore-sexp-errors 2414 (while (not (eobp)) 2415 (forward-sexp)))) 2416 (throw 'return nil)) 2417 (setq nestedp t) 2418 (up-list) 2419 (setq close ; adjusting for mixed 2420 (prog1 (char-before) ; delimiters as necessary, 2421 (delete-char -1) 2422 (insert close)))))) 2423 (insert close) ; to insert that delimiter. 2424 (indent-region start (point) nil)))) 2425 (if (and (not nestedp) 2426 (eq (save-excursion (paredit-skip-whitespace nil) (point)) 2427 (save-excursion (backward-up-list) (forward-char) (point))) 2428 (eq (save-excursion (forward-sexp) (backward-sexp) (point)) 2429 (save-excursion (paredit-skip-whitespace t) (point)))) 2430 (delete-region (save-excursion (paredit-skip-whitespace nil) (point)) 2431 (save-excursion (paredit-skip-whitespace t) (point)))))) 2432 2433 (defun paredit-forward-slurp-into-string (&optional argument) 2434 (let ((start (paredit-enclosing-string-start)) 2435 (end (paredit-enclosing-string-end))) 2436 (goto-char end) 2437 ;; Signal any errors that we might get first, before mucking with 2438 ;; the buffer's contents. 2439 (save-excursion (forward-sexp)) 2440 (let ((close (char-before))) 2441 ;; Skip intervening whitespace if we're slurping into an empty 2442 ;; string. XXX What about nonempty strings? 2443 (if (and (= (+ start 2) end) 2444 (eq (save-excursion (paredit-skip-whitespace t) (point)) 2445 (save-excursion (forward-sexp) (backward-sexp) (point)))) 2446 (delete-region (- (point) 1) 2447 (save-excursion (paredit-skip-whitespace t) (point))) 2448 (delete-char -1)) 2449 (paredit-forward-for-quote 2450 (save-excursion 2451 (forward-sexp) 2452 (if argument 2453 (while (paredit-handle-sexp-errors (progn (forward-sexp) t) nil))) 2454 (point))) 2455 (insert close)))) 2456 2457 (defun paredit-forward-barf-sexp (&optional argument) 2458 "Remove the last S-expression in the current list from that list 2459 by moving the closing delimiter. 2460 Automatically reindent the newly barfed S-expression with respect to 2461 its new enclosing form." 2462 (interactive "P") 2463 (paredit-lose-if-not-in-sexp 'paredit-forward-barf-sexp) 2464 (if (and (numberp argument) (< argument 0)) 2465 (paredit-forward-slurp-sexp (- 0 argument)) 2466 (let ((start (point)) (end nil)) 2467 (save-excursion 2468 (up-list) ; Up to the end of the list to 2469 (let ((close (char-before))) ; save and delete the closing 2470 (delete-char -1) ; delimiter. 2471 (setq end (point)) 2472 (paredit-ignore-sexp-errors ; Go back to where we want to 2473 (if (or (not argument) ; insert the delimiter. 2474 (numberp argument)) 2475 (backward-sexp argument) 2476 (while (paredit-handle-sexp-errors 2477 (save-excursion (backward-sexp) (<= start (point))) 2478 nil) 2479 (backward-sexp)))) 2480 (paredit-skip-whitespace nil) ; Skip leading whitespace. 2481 (cond ((bobp) 2482 ;++ We'll have deleted the close, but there's no open. 2483 ;++ Is that OK? 2484 (error "Barfing all subexpressions with no open-paren?")) 2485 ((paredit-in-comment-p) ; Don't put the close-paren in 2486 (newline))) ; a comment. 2487 (insert close)) 2488 ;; Reindent all of the newly barfed S-expressions. Start at the 2489 ;; start of the first barfed S-expression, not at the close we 2490 ;; just inserted. 2491 (forward-sexp) 2492 (backward-sexp) 2493 (if (or (not argument) (numberp argument)) 2494 (paredit-forward-and-indent argument) 2495 (indent-region (point) end)))))) 2496 2497 (defun paredit-backward-slurp-sexp (&optional argument) 2498 "Add the S-expression preceding the current list into that list 2499 by moving the closing delimiter. 2500 Automatically reindent the whole form into which new S-expression was 2501 slurped. 2502 If in a string, move the opening double-quote backward by one 2503 S-expression and escape any intervening characters as necessary, 2504 without altering any indentation or formatting." 2505 (interactive "P") 2506 (save-excursion 2507 (cond ((paredit-in-comment-p) 2508 (error "Invalid context for slurping S-expressions.")) 2509 ((numberp argument) 2510 (if (< argument 0) 2511 (paredit-backward-barf-sexp (- 0 argument)) 2512 (while (< 0 argument) 2513 (paredit-backward-slurp-sexp) 2514 (setq argument (- argument 1))))) 2515 ((paredit-in-string-p) 2516 ;; If there is anything to slurp into the string, take that. 2517 ;; Otherwise, try to slurp into the enclosing list. 2518 (if (save-excursion 2519 (goto-char (paredit-enclosing-string-start)) 2520 (paredit-handle-sexp-errors (progn (backward-sexp) nil) 2521 t)) 2522 (progn 2523 (goto-char (paredit-enclosing-string-start)) 2524 (paredit-backward-slurp-into-list argument)) 2525 (paredit-backward-slurp-into-string argument))) 2526 (t 2527 (paredit-backward-slurp-into-list argument))))) 2528 2529 (defun paredit-backward-slurp-into-list (&optional argument) 2530 (let ((nestedp nil)) 2531 (save-excursion 2532 (backward-up-list) 2533 (let ((open (char-after))) 2534 (delete-char +1) 2535 (catch 'return 2536 (while t 2537 (paredit-handle-sexp-errors 2538 (progn (backward-sexp) 2539 (if argument 2540 (paredit-ignore-sexp-errors 2541 (while (not (bobp)) 2542 (backward-sexp)))) 2543 (throw 'return nil)) 2544 (setq nestedp t) 2545 (backward-up-list) 2546 (setq open 2547 (prog1 (char-after) 2548 (save-excursion (insert open) (delete-char +1))))))) 2549 (insert open)) 2550 ;; Reindent the line at the beginning of wherever we inserted the 2551 ;; opening delimiter, and then indent the whole S-expression. 2552 (backward-up-list) 2553 (lisp-indent-line) 2554 (indent-sexp)) 2555 ;; If we slurped into an empty list, don't leave dangling space: 2556 ;; (foo |). 2557 (if (and (not nestedp) 2558 (eq (save-excursion (paredit-skip-whitespace nil) (point)) 2559 (save-excursion (backward-sexp) (forward-sexp) (point))) 2560 (eq (save-excursion (up-list) (backward-char) (point)) 2561 (save-excursion (paredit-skip-whitespace t) (point)))) 2562 (delete-region (save-excursion (paredit-skip-whitespace nil) (point)) 2563 (save-excursion (paredit-skip-whitespace t) (point)))))) 2564 2565 (defun paredit-backward-slurp-into-string (&optional argument) 2566 (let ((start (paredit-enclosing-string-start)) 2567 (end (paredit-enclosing-string-end))) 2568 (goto-char start) 2569 ;; Signal any errors that we might get first, before mucking with 2570 ;; the buffer's contents. 2571 (save-excursion (backward-sexp)) 2572 (let ((open (char-after)) 2573 (target (point))) 2574 ;; Skip intervening whitespace if we're slurping into an empty 2575 ;; string. XXX What about nonempty strings? 2576 (if (and (= (+ start 2) end) 2577 (eq (save-excursion (paredit-skip-whitespace nil) (point)) 2578 (save-excursion (backward-sexp) (forward-sexp) (point)))) 2579 (delete-region (save-excursion (paredit-skip-whitespace nil) (point)) 2580 (+ (point) 1)) 2581 (delete-char +1)) 2582 (backward-sexp) 2583 (if argument 2584 (paredit-ignore-sexp-errors 2585 (while (not (bobp)) 2586 (backward-sexp)))) 2587 (insert open) 2588 (paredit-forward-for-quote target)))) 2589 2590 (defun paredit-backward-barf-sexp (&optional argument) 2591 "Remove the first S-expression in the current list from that list 2592 by moving the closing delimiter. 2593 Automatically reindent the barfed S-expression and the form from which 2594 it was barfed." 2595 (interactive "P") 2596 (paredit-lose-if-not-in-sexp 'paredit-backward-barf-sexp) 2597 (if (and (numberp argument) (< argument 0)) 2598 (paredit-backward-slurp-sexp (- 0 argument)) 2599 (let ((end (make-marker))) 2600 (set-marker end (point)) 2601 (save-excursion 2602 (backward-up-list) 2603 (let ((open (char-after))) 2604 (delete-char +1) 2605 (paredit-ignore-sexp-errors 2606 (paredit-forward-and-indent 2607 (if (or (not argument) (numberp argument)) 2608 argument 2609 (let ((n 0)) 2610 (save-excursion 2611 (while (paredit-handle-sexp-errors 2612 (save-excursion 2613 (forward-sexp) 2614 (<= (point) end)) 2615 nil) 2616 (forward-sexp) 2617 (setq n (+ n 1)))) 2618 n)))) 2619 (while (progn (paredit-skip-whitespace t) (eq (char-after) ?\; )) 2620 (forward-line 1)) 2621 (if (eobp) 2622 ;++ We'll have deleted the close, but there's no open. 2623 ;++ Is that OK? 2624 (error "Barfing all subexpressions with no close-paren?")) 2625 ;** Don't use `insert' here. Consider, e.g., barfing from 2626 ;** (foo|) 2627 ;** and how `save-excursion' works. 2628 (insert-before-markers open)) 2629 (backward-up-list) 2630 (lisp-indent-line) 2631 (indent-sexp))))) 2632 2633 ;;;; Splitting & Joining 2634 2635 (defun paredit-split-sexp () 2636 "Split the list or string the point is on into two." 2637 (interactive) 2638 (cond ((paredit-in-string-p) 2639 (insert "\"") 2640 (save-excursion (insert " \""))) 2641 ((or (paredit-in-comment-p) 2642 (paredit-in-char-p)) 2643 (error "Invalid context for splitting S-expression.")) 2644 (t 2645 (let ((open (save-excursion (backward-up-list) (char-after))) 2646 (close (save-excursion (up-list) (char-before)))) 2647 (delete-horizontal-space) 2648 (insert close) 2649 (save-excursion 2650 (insert ?\ ) 2651 (insert open) 2652 (backward-char) 2653 (indent-sexp)))))) 2654 2655 (defun paredit-join-sexps () 2656 "Join the S-expressions adjacent on either side of the point. 2657 Both must be lists, strings, or atoms; error if there is a mismatch." 2658 (interactive) 2659 (cond ((paredit-in-comment-p) (error "Can't join S-expressions in comment.")) 2660 ((paredit-in-string-p) (error "Nothing to join in a string.")) 2661 ((paredit-in-char-p) (error "Can't join characters."))) 2662 (let ((left-point (paredit-point-at-sexp-end)) 2663 (right-point (paredit-point-at-sexp-start))) 2664 (let ((left-char (char-before left-point)) 2665 (right-char (char-after right-point))) 2666 (let ((left-syntax (char-syntax left-char)) 2667 (right-syntax (char-syntax right-char))) 2668 (cond ((< right-point left-point) 2669 (error "Can't join a datum with itself.")) 2670 ((and (eq left-syntax ?\) ) 2671 (eq right-syntax ?\( ) 2672 (eq left-char (matching-paren right-char)) 2673 (eq right-char (matching-paren left-char))) 2674 (paredit-join-lists-internal left-point right-point) 2675 (paredit-preserving-column 2676 (save-excursion 2677 (backward-up-list) 2678 (indent-sexp)))) 2679 ((and (eq left-syntax ?\" ) 2680 (eq right-syntax ?\" )) 2681 ;; Delete any intermediate formatting. 2682 (delete-region (1- left-point) (1+ right-point))) 2683 ((and (memq left-syntax '(?w ?_)) ; Word or symbol 2684 (memq right-syntax '(?w ?_))) 2685 (delete-region left-point right-point)) 2686 (t (error "Mismatched S-expressions to join."))))))) 2687 2688 (defun paredit-join-lists-internal (left-point right-point) 2689 (save-excursion 2690 ;; Leave intermediate formatting alone. 2691 (goto-char right-point) 2692 (delete-char +1) 2693 (goto-char left-point) 2694 (delete-char -1) 2695 ;; Kludge: Add an extra space in several conditions. 2696 (if (or 2697 ;; (foo)| ;x\n(bar) => (foo | ;x\nbar), not (foo| ;x\nbar). 2698 (and (not (eolp)) 2699 (save-excursion 2700 (paredit-skip-whitespace t (point-at-eol)) 2701 (eq (char-after) ?\;))) 2702 ;; (foo)|(bar) => (foo| bar), not (foo|bar). 2703 (and (= left-point right-point) 2704 (not (or (eq ?\ (char-syntax (char-before))) 2705 (eq ?\ (char-syntax (char-after))))))) 2706 (insert ?\ )))) 2707 2708 ;++ How ought paredit-join to handle comments intervening symbols or strings? 2709 ;++ Idea: 2710 ;++ 2711 ;++ "foo" | ;bar 2712 ;++ "baz" ;quux 2713 ;++ 2714 ;++ => 2715 ;++ 2716 ;++ "foo|baz" ;bar 2717 ;++ ;quux 2718 ;++ 2719 ;++ The point should stay where it is relative to the comments, and the 2720 ;++ the comments' columns should all be preserved, perhaps. Hmmmm... 2721 ;++ What about this? 2722 ;++ 2723 ;++ "foo" ;bar 2724 ;++ | ;baz 2725 ;++ "quux" ;zot 2726 2727 ;++ Should rename: 2728 ;++ paredit-point-at-sexp-start -> paredit-start-of-sexp-after-point 2729 ;++ paredit-point-at-sexp-end -> paredit-end-of-sexp-before-point 2730 2731 ;;;; Variations on the Lurid Theme 2732 2733 ;;; I haven't the imagination to concoct clever names for these. 2734 2735 (defun paredit-add-to-previous-list () 2736 "Add the S-expression following point to the list preceding point." 2737 (interactive) 2738 (paredit-lose-if-not-in-sexp 'paredit-add-to-previous-list) 2739 (save-excursion 2740 (down-list -1) ;++ backward-down-list... 2741 (paredit-forward-slurp-sexp))) 2742 2743 (defun paredit-add-to-next-list () 2744 "Add the S-expression preceding point to the list following point. 2745 If no S-expression precedes point, move up the tree until one does." 2746 (interactive) 2747 (paredit-lose-if-not-in-sexp 'paredit-add-to-next-list) 2748 (save-excursion 2749 (down-list) 2750 (paredit-backward-slurp-sexp))) 2751 2752 (defun paredit-join-with-previous-list () 2753 "Join the list the point is on with the previous list in the buffer." 2754 (interactive) 2755 (paredit-lose-if-not-in-sexp 'paredit-join-with-previous-list) 2756 (save-excursion 2757 (while (paredit-handle-sexp-errors (save-excursion (backward-sexp) nil) 2758 (backward-up-list) 2759 t)) 2760 (paredit-join-sexps))) 2761 2762 (defun paredit-join-with-next-list () 2763 "Join the list the point is on with the next list in the buffer." 2764 (interactive) 2765 (paredit-lose-if-not-in-sexp 'paredit-join-with-next-list) 2766 (save-excursion 2767 (while (paredit-handle-sexp-errors (save-excursion (forward-sexp) nil) 2768 (up-list) 2769 t)) 2770 (paredit-join-sexps))) 2771 2772 ;;;; Utilities 2773 2774 (defun paredit-in-string-escape-p () 2775 "True if the point is on a character escape of a string. 2776 This is true only if the character is preceded by an odd number of 2777 backslashes. 2778 This assumes that `paredit-in-string-p' has already returned true." 2779 (let ((oddp nil)) 2780 (save-excursion 2781 (while (eq (char-before) ?\\ ) 2782 (setq oddp (not oddp)) 2783 (backward-char))) 2784 oddp)) 2785 2786 (defun paredit-in-char-p (&optional position) 2787 "True if point is on a character escape outside a string." 2788 (save-excursion 2789 (goto-char (or position (point))) 2790 (paredit-in-string-escape-p))) 2791 2792 (defun paredit-skip-whitespace (trailing-p &optional limit) 2793 "Skip past any whitespace, or until the point LIMIT is reached. 2794 If TRAILING-P is nil, skip leading whitespace; otherwise, skip trailing 2795 whitespace." 2796 (funcall (if trailing-p 'skip-chars-forward 'skip-chars-backward) 2797 " \t\n" ; This should skip using the syntax table, but LF 2798 limit)) ; is a comment end, not newline, in Lisp mode. 2799 2800 (defalias 'paredit-region-active-p 2801 (xcond ((paredit-xemacs-p) 'region-active-p) 2802 ((paredit-gnu-emacs-p) 2803 (lambda () 2804 (and mark-active transient-mark-mode))))) 2805 2806 (defun paredit-hack-kill-region (start end) 2807 "Kill the region between START and END. 2808 Do not append to any current kill, and 2809 do not let the next kill append to this one." 2810 (interactive "r") ;Eh, why not? 2811 ;; KILL-REGION sets THIS-COMMAND to tell the next kill that the last 2812 ;; command was a kill. It also checks LAST-COMMAND to see whether it 2813 ;; should append. If we bind these locally, any modifications to 2814 ;; THIS-COMMAND will be masked, and it will not see LAST-COMMAND to 2815 ;; indicate that it should append. 2816 (let ((this-command nil) 2817 (last-command nil)) 2818 (kill-region start end))) 2819 2820 ;;;;; Reindentation utilities 2821 2822 ;++ Should `paredit-indent-sexps' and `paredit-forward-and-indent' use 2823 ;++ `paredit-indent-region' rather than `indent-region'? 2824 2825 (defun paredit-indent-sexps () 2826 "If in a list, indent all following S-expressions in the list." 2827 (let* ((start (point)) 2828 (end (paredit-handle-sexp-errors (progn (up-list) (point)) nil))) 2829 (if end 2830 (indent-region start end nil)))) 2831 2832 (defun paredit-forward-and-indent (&optional n) 2833 "Move forward by N S-expressions, indenting them with `indent-region'." 2834 (let ((start (point))) 2835 (forward-sexp n) 2836 (indent-region start (point) nil))) 2837 2838 (defun paredit-indent-region (start end) 2839 "Indent the region from START to END. 2840 Don't reindent the line starting at START, however." 2841 (if (not (<= start end)) 2842 (error "Incorrectly related points: %S, %S" start end)) 2843 (save-excursion 2844 (goto-char start) 2845 (let ((bol (point-at-bol))) 2846 ;; Skip all S-expressions that end on the starting line, but 2847 ;; don't go past `end'. 2848 (if (and (save-excursion (goto-char end) (not (eq bol (point-at-bol)))) 2849 (paredit-handle-sexp-errors 2850 (catch 'exit 2851 (while t 2852 (save-excursion 2853 (forward-sexp) 2854 (if (not (eq bol (point-at-bol))) 2855 (throw 'exit t)) 2856 (if (not (< (point) end)) 2857 (throw 'exit nil))) 2858 (forward-sexp))) 2859 nil)) 2860 (progn 2861 ;; Point is still on the same line, but precedes an 2862 ;; S-expression that ends on a different line. 2863 (if (not (eq bol (point-at-bol))) 2864 (error "Internal error -- we moved forward a line!")) 2865 (goto-char (+ 1 (point-at-eol))) 2866 (if (not (<= (point) end)) 2867 (error "Internal error -- we frobnitzed the garfnut!")) 2868 (indent-region (point) end nil)))))) 2869 2870 ;;;;; S-expression Parsing Utilities 2871 2872 ;++ These routines redundantly traverse S-expressions a great deal. 2873 ;++ If performance issues arise, this whole section will probably have 2874 ;++ to be refactored to preserve the state longer, like paredit.scm 2875 ;++ does, rather than to traverse the definition N times for every key 2876 ;++ stroke as it presently does. 2877 2878 (defun paredit-current-parse-state () 2879 "Return parse state of point from beginning of defun." 2880 (let ((point (point))) 2881 (beginning-of-defun) 2882 ;; Calling PARSE-PARTIAL-SEXP will advance the point to its second 2883 ;; argument (unless parsing stops due to an error, but we assume it 2884 ;; won't in paredit-mode). 2885 (parse-partial-sexp (point) point))) 2886 2887 (defun paredit-in-string-p (&optional state) 2888 "True if the parse state is within a double-quote-delimited string. 2889 If no parse state is supplied, compute one from the beginning of the 2890 defun to the point." 2891 ;; 3. non-nil if inside a string (the terminator character, really) 2892 (and (nth 3 (or state (paredit-current-parse-state))) 2893 t)) 2894 2895 (defun paredit-string-start+end-points (&optional state) 2896 "Return a cons of the points of open and close quotes of the string. 2897 The string is determined from the parse state STATE, or the parse state 2898 from the beginning of the defun to the point. 2899 This assumes that `paredit-in-string-p' has already returned true, i.e. 2900 that the point is already within a string." 2901 (save-excursion 2902 ;; 8. character address of start of comment or string; nil if not 2903 ;; in one 2904 (let ((start (nth 8 (or state (paredit-current-parse-state))))) 2905 (goto-char start) 2906 (forward-sexp 1) 2907 (cons start (1- (point)))))) 2908 2909 (defun paredit-enclosing-string-start () 2910 (car (paredit-string-start+end-points))) 2911 2912 (defun paredit-enclosing-string-end () 2913 (+ 1 (cdr (paredit-string-start+end-points)))) 2914 2915 (defun paredit-enclosing-list-start () 2916 (save-excursion 2917 (backward-up-list) 2918 (point))) 2919 2920 (defun paredit-enclosing-list-end () 2921 (save-excursion 2922 (up-list) 2923 (point))) 2924 2925 (defun paredit-in-comment-p (&optional state) 2926 "True if parse state STATE is within a comment. 2927 If no parse state is supplied, compute one from the beginning of the 2928 defun to the point." 2929 ;; 4. nil if outside a comment, t if inside a non-nestable comment, 2930 ;; else an integer (the current comment nesting) 2931 (and (nth 4 (or state (paredit-current-parse-state))) 2932 t)) 2933 2934 (defun paredit-prefix-numeric-value (argument) 2935 ;++ Kludgerific. 2936 (cond ((integerp argument) argument) 2937 ((eq argument '-) -1) 2938 ((consp argument) 2939 (cond ((equal argument '(4)) (paredit-count-sexps-forward)) ;C-u 2940 ((equal argument '(16)) (paredit-count-sexps-backward)) ;C-u C-u 2941 (t (error "Invalid prefix argument: %S" argument)))) 2942 ((paredit-region-active-p) 2943 (save-excursion 2944 (save-restriction 2945 (narrow-to-region (region-beginning) (region-end)) 2946 (cond ((= (point) (point-min)) (paredit-count-sexps-forward)) 2947 ((= (point) (point-max)) (paredit-count-sexps-backward)) 2948 (t 2949 (error "Point %S is not start or end of region: %S..%S" 2950 (point) (region-beginning) (region-end))))))) 2951 (t 1))) 2952 2953 (defun paredit-count-sexps-forward () 2954 (save-excursion 2955 (let ((n 0) (p nil)) ;hurk 2956 (paredit-ignore-sexp-errors 2957 (while (setq p (scan-sexps (point) +1)) 2958 (goto-char p) 2959 (setq n (+ n 1)))) 2960 n))) 2961 2962 (defun paredit-count-sexps-backward () 2963 (save-excursion 2964 (let ((n 0) (p nil)) ;hurk 2965 (paredit-ignore-sexp-errors 2966 (while (setq p (scan-sexps (point) -1)) 2967 (goto-char p) 2968 (setq n (+ n 1)))) 2969 n))) 2970 2971 (defun paredit-point-at-sexp-boundary (n) 2972 (cond ((< n 0) (paredit-point-at-sexp-start)) 2973 ((= n 0) (point)) 2974 ((> n 0) (paredit-point-at-sexp-end)))) 2975 2976 (defun paredit-point-at-sexp-start () 2977 (save-excursion 2978 (forward-sexp) 2979 (backward-sexp) 2980 (point))) 2981 2982 (defun paredit-point-at-sexp-end () 2983 (save-excursion 2984 (backward-sexp) 2985 (forward-sexp) 2986 (point))) 2987 2988 (defun paredit-lose-if-not-in-sexp (command) 2989 (if (or (paredit-in-string-p) 2990 (paredit-in-comment-p) 2991 (paredit-in-char-p)) 2992 (error "Invalid context for command `%s'." command))) 2993 2994 (defun paredit-check-region (start end) 2995 "Signal an error if text between `start' and `end' is unbalanced." 2996 ;; `narrow-to-region' will move the point, so avoid calling it if we 2997 ;; don't need to. We don't want to use `save-excursion' because we 2998 ;; want the point to move if `check-parens' reports an error. 2999 (if (not (paredit-region-ok-p start end)) 3000 (save-restriction 3001 (narrow-to-region start end) 3002 (check-parens)))) 3003 3004 (defun paredit-region-ok-p (start end) 3005 "Return true iff the region between `start' and `end' is balanced. 3006 This is independent of context -- it doesn't check what state the 3007 text at `start' is in." 3008 (save-excursion 3009 (paredit-handle-sexp-errors 3010 (progn 3011 (save-restriction 3012 (narrow-to-region start end) 3013 (scan-sexps (point-min) (point-max))) 3014 t) 3015 nil))) 3016 3017 (defun paredit-current-column () 3018 ;; Like current-column, but respects field boundaries in interactive 3019 ;; modes like ielm. For use only with paredit-restore-column, which 3020 ;; works relative to point-at-bol. 3021 (- (point) (point-at-bol))) 3022 3023 (defun paredit-current-indentation () 3024 (save-excursion 3025 (back-to-indentation) 3026 (paredit-current-column))) 3027 3028 (defun paredit-restore-column (column indentation) 3029 ;; Preserve the point's position either in the indentation or in the 3030 ;; code: if on code, move with the code; if in indentation, leave it 3031 ;; in the indentation, either where it was (if still on indentation) 3032 ;; or at the end of the indentation (if the code moved far enough 3033 ;; left). 3034 (let ((indentation* (paredit-current-indentation))) 3035 (goto-char 3036 (+ (point-at-bol) 3037 (cond ((not (< column indentation)) 3038 (+ column (- indentation* indentation))) 3039 ((<= indentation* column) indentation*) 3040 (t column)))))) 3041 3042 ;;;; Initialization 3043 3044 (paredit-define-keys) 3045 (paredit-annotate-mode-with-examples) 3046 (paredit-annotate-functions-with-examples) 3047 3048 (provide 'paredit) 3049 3050 ;;; Local Variables: 3051 ;;; outline-regexp: "\n;;;;+" 3052 ;;; End: 3053 3054 ;;; paredit.el ends here