Mercurial > dotfiles
comparison .elisp/paredit.el @ 7:9541f7e47514
Some edits to .emacs after my playing with Clojure, also added Clojure support files.
| author | Augie Fackler <durin42@gmail.com> |
|---|---|
| date | Sun, 30 Nov 2008 20:50:18 -0600 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 6:66f8fcaee427 | 7:9541f7e47514 |
|---|---|
| 1 ;;; -*- Mode: Emacs-Lisp; outline-regexp: "\n;;;;+" -*- | |
| 2 | |
| 3 ;;;;;; Paredit: Parenthesis-Editing Minor Mode | |
| 4 ;;;;;; Version 20 | |
| 5 | |
| 6 ;;; This code is written by Taylor R. Campbell (except where explicitly | |
| 7 ;;; noted) and placed in the Public Domain. All warranties are | |
| 8 ;;; disclaimed. | |
| 9 | |
| 10 ;;; Add this to your .emacs after adding paredit.el to /path/to/elisp/: | |
| 11 ;;; | |
| 12 ;;; (add-to-list 'load-path "/path/to/elisp/") | |
| 13 ;;; (autoload 'paredit-mode "paredit" | |
| 14 ;;; "Minor mode for pseudo-structurally editing Lisp code." | |
| 15 ;;; t) | |
| 16 ;;; (add-hook '...-mode-hook (lambda () (paredit-mode +1))) | |
| 17 ;;; | |
| 18 ;;; Usually the ... will be lisp or scheme or both. Alternatively, you | |
| 19 ;;; can manually toggle this mode with M-x paredit-mode. Customization | |
| 20 ;;; of paredit can be accomplished with `eval-after-load': | |
| 21 ;;; | |
| 22 ;;; (eval-after-load 'paredit | |
| 23 ;;; '(progn ...redefine keys, &c....)) | |
| 24 ;;; | |
| 25 ;;; This should run in GNU Emacs 21 or later and XEmacs 21.5 or later. | |
| 26 ;;; It is highly unlikely to work in earlier versions of GNU Emacs, and | |
| 27 ;;; it may have obscure problems in earlier versions of XEmacs due to | |
| 28 ;;; the way its syntax parser reports conditions, as a result of which | |
| 29 ;;; the code that uses the syntax parser must mask *all* error | |
| 30 ;;; conditions, not just those generated by the syntax parser. | |
| 31 | |
| 32 ;;; This mode changes the keybindings for a number of simple keys, | |
| 33 ;;; notably (, ), ", \, and ;. The bracket keys (round or square) are | |
| 34 ;;; defined to insert parenthesis pairs and move past the close, | |
| 35 ;;; respectively; the double-quote key is multiplexed to do both, and | |
| 36 ;;; also insert an escape if within a string; backslashes prompt the | |
| 37 ;;; user for the next character to input, because a lone backslash can | |
| 38 ;;; break structure inadvertently; and semicolons ensure that they do | |
| 39 ;;; not accidentally comment valid structure. (Use M-; to comment an | |
| 40 ;;; expression.) These all have their ordinary behaviour when inside | |
| 41 ;;; comments, and, outside comments, if truly necessary, you can insert | |
| 42 ;;; them literally with C-q. | |
| 43 ;;; | |
| 44 ;;; These keybindings are set up for my preference. One particular | |
| 45 ;;; preference which I've seen vary greatly from person to person is | |
| 46 ;;; whether the command to move past a closing delimiter ought to | |
| 47 ;;; insert a newline. Since I find this behaviour to be more common | |
| 48 ;;; than that which inserts no newline, I have ) bound to it, and the | |
| 49 ;;; more involved M-) to perform the less common action. This bothers | |
| 50 ;;; some users, though, and they prefer the other way around. This | |
| 51 ;;; code, which you can use `eval-after-load' to put in your .emacs, | |
| 52 ;;; will exchange the bindings: | |
| 53 ;;; | |
| 54 ;;; (define-key paredit-mode-map (kbd ")") | |
| 55 ;;; 'paredit-close-parenthesis) | |
| 56 ;;; (define-key paredit-mode-map (kbd "M-)") | |
| 57 ;;; 'paredit-close-parenthesis-and-newline) | |
| 58 ;;; | |
| 59 ;;; Paredit also changes the bindings of keys for deleting and killing, | |
| 60 ;;; so that they will not destroy any S-expression structure by killing | |
| 61 ;;; or deleting only one side of a bracket or quote pair. If the point | |
| 62 ;;; is on a closing bracket, DEL will move left over it; if it is on an | |
| 63 ;;; opening bracket, C-d will move right over it. Only if the point is | |
| 64 ;;; between a pair of brackets will C-d or DEL delete them, and in that | |
| 65 ;;; case it will delete both simultaneously. M-d and M-DEL kill words, | |
| 66 ;;; but skip over any S-expression structure. C-k kills from the start | |
| 67 ;;; of the line, either to the line's end, if it contains only balanced | |
| 68 ;;; expressions; to the first closing bracket, if the point is within a | |
| 69 ;;; form that ends on the line; or up to the end of the last expression | |
| 70 ;;; that starts on the line after the point. | |
| 71 ;;; | |
| 72 ;;; Automatic reindentation is performed as locally as possible, to | |
| 73 ;;; ensure that Emacs does not interfere with custom indentation used | |
| 74 ;;; elsewhere in some S-expression. It is performed only by the | |
| 75 ;;; advanced S-expression frobnication commands, and only on the forms | |
| 76 ;;; that were immediately operated upon (& their subforms). | |
| 77 ;;; | |
| 78 ;;; This code is written for clarity, not efficiency. S-expressions | |
| 79 ;;; are frequently walked over redundantly. If you have problems with | |
| 80 ;;; some of the commands taking too long to execute, tell me, but first | |
| 81 ;;; make sure that what you're doing is reasonable: it is stylistically | |
| 82 ;;; bad to have huge, long, hideously nested code anyway. | |
| 83 ;;; | |
| 84 ;;; Questions, bug reports, comments, feature suggestions, &c., can be | |
| 85 ;;; addressed to the author via mail on the host mumble.net to campbell | |
| 86 ;;; or via IRC on irc.freenode.net in the #paredit channel under the | |
| 87 ;;; nickname Riastradh. | |
| 88 | |
| 89 ;;; This assumes Unix-style LF line endings. | |
| 90 | |
| 91 (defconst paredit-version 20) | |
| 92 | |
| 93 (eval-and-compile | |
| 94 | |
| 95 (defun paredit-xemacs-p () | |
| 96 ;; No idea I got this definition from. Edward O'Connor (hober on | |
| 97 ;; IRC) suggested the current definition. | |
| 98 ;; (and (boundp 'running-xemacs) | |
| 99 ;; running-xemacs) | |
| 100 (featurep 'xemacs)) | |
| 101 | |
| 102 (defun paredit-gnu-emacs-p () | |
| 103 (not (paredit-xemacs-p))) | |
| 104 | |
| 105 (defmacro xcond (&rest clauses) | |
| 106 "Exhaustive COND. | |
| 107 Signal an error if no clause matches." | |
| 108 `(cond ,@clauses | |
| 109 (t (error "XCOND lost.")))) | |
| 110 | |
| 111 (defalias 'paredit-warn (if (fboundp 'warn) 'warn 'message)) | |
| 112 | |
| 113 (defvar paredit-sexp-error-type | |
| 114 (with-temp-buffer | |
| 115 (insert "(") | |
| 116 (condition-case condition | |
| 117 (backward-sexp) | |
| 118 (error (if (eq (car condition) 'error) | |
| 119 (paredit-warn "%s%s%s%s" | |
| 120 "Paredit is unable to discriminate" | |
| 121 " S-expression parse errors from" | |
| 122 " other errors. " | |
| 123 " This may cause obscure problems. " | |
| 124 " Please upgrade Emacs.")) | |
| 125 (car condition))))) | |
| 126 | |
| 127 (defmacro paredit-handle-sexp-errors (body &rest handler) | |
| 128 `(condition-case () | |
| 129 ,body | |
| 130 (,paredit-sexp-error-type ,@handler))) | |
| 131 | |
| 132 (put 'paredit-handle-sexp-errors 'lisp-indent-function 1) | |
| 133 | |
| 134 (defmacro paredit-ignore-sexp-errors (&rest body) | |
| 135 `(paredit-handle-sexp-errors (progn ,@body) | |
| 136 nil)) | |
| 137 | |
| 138 (put 'paredit-ignore-sexp-errors 'lisp-indent-function 0) | |
| 139 | |
| 140 nil) | |
| 141 | |
| 142 ;;;; Minor Mode Definition | |
| 143 | |
| 144 (defvar paredit-mode-map (make-sparse-keymap) | |
| 145 "Keymap for the paredit minor mode.") | |
| 146 | |
| 147 (define-minor-mode paredit-mode | |
| 148 "Minor mode for pseudo-structurally editing Lisp code. | |
| 149 \\<paredit-mode-map>" | |
| 150 :lighter " Paredit" | |
| 151 ;; If we're enabling paredit-mode, the prefix to this code that | |
| 152 ;; DEFINE-MINOR-MODE inserts will have already set PAREDIT-MODE to | |
| 153 ;; true. If this is the case, then first check the parentheses, and | |
| 154 ;; if there are any imbalanced ones we must inhibit the activation of | |
| 155 ;; paredit mode. We skip the check, though, if the user supplied a | |
| 156 ;; prefix argument interactively. | |
| 157 (if (and paredit-mode | |
| 158 (not current-prefix-arg)) | |
| 159 (if (not (fboundp 'check-parens)) | |
| 160 (paredit-warn "`check-parens' is not defined; %s" | |
| 161 "be careful of malformed S-expressions.") | |
| 162 (condition-case condition | |
| 163 (check-parens) | |
| 164 (error (setq paredit-mode nil) | |
| 165 (signal (car condition) (cdr condition))))))) | |
| 166 | |
| 167 ;;; Old functions from when there was a different mode for emacs -nw. | |
| 168 | |
| 169 (defun enable-paredit-mode () | |
| 170 "Turn on pseudo-structural editing of Lisp code. | |
| 171 | |
| 172 Deprecated: use `paredit-mode' instead." | |
| 173 (interactive) | |
| 174 (paredit-mode +1)) | |
| 175 | |
| 176 (defun disable-paredit-mode () | |
| 177 "Turn off pseudo-structural editing of Lisp code. | |
| 178 | |
| 179 Deprecated: use `paredit-mode' instead." | |
| 180 (interactive) | |
| 181 (paredit-mode -1)) | |
| 182 | |
| 183 (defvar paredit-backward-delete-key | |
| 184 (xcond ((paredit-xemacs-p) "BS") | |
| 185 ((paredit-gnu-emacs-p) "DEL"))) | |
| 186 | |
| 187 (defvar paredit-forward-delete-keys | |
| 188 (xcond ((paredit-xemacs-p) '("DEL")) | |
| 189 ((paredit-gnu-emacs-p) '("<delete>" "<deletechar>")))) | |
| 190 | |
| 191 ;;;; Paredit Keys | |
| 192 | |
| 193 ;;; Separating the definition and initialization of this variable | |
| 194 ;;; simplifies the development of paredit, since re-evaluating DEFVAR | |
| 195 ;;; forms doesn't actually do anything. | |
| 196 | |
| 197 (defvar paredit-commands nil | |
| 198 "List of paredit commands with their keys and examples.") | |
| 199 | |
| 200 ;;; Each specifier is of the form: | |
| 201 ;;; (key[s] function (example-input example-output) ...) | |
| 202 ;;; where key[s] is either a single string suitable for passing to KBD | |
| 203 ;;; or a list of such strings. Entries in this list may also just be | |
| 204 ;;; strings, in which case they are headings for the next entries. | |
| 205 | |
| 206 (progn (setq paredit-commands | |
| 207 `( | |
| 208 "Basic Insertion Commands" | |
| 209 ("(" paredit-open-parenthesis | |
| 210 ("(a b |c d)" | |
| 211 "(a b (|) c d)") | |
| 212 ("(foo \"bar |baz\" quux)" | |
| 213 "(foo \"bar (|baz\" quux)")) | |
| 214 (")" paredit-close-parenthesis-and-newline | |
| 215 ("(defun f (x| ))" | |
| 216 "(defun f (x)\n |)") | |
| 217 ("; (Foo.|" | |
| 218 "; (Foo.)|")) | |
| 219 ("M-)" paredit-close-parenthesis | |
| 220 ("(a b |c )" "(a b c)|") | |
| 221 ("; Hello,| world!" | |
| 222 "; Hello,)| world!")) | |
| 223 ("[" paredit-open-bracket | |
| 224 ("(a b |c d)" | |
| 225 "(a b [|] c d)") | |
| 226 ("(foo \"bar |baz\" quux)" | |
| 227 "(foo \"bar [baz\" quux)")) | |
| 228 ("]" paredit-close-bracket | |
| 229 ("(define-key keymap [frob| ] 'frobnicate)" | |
| 230 "(define-key keymap [frob]| 'frobnicate)") | |
| 231 ("; [Bar.|" | |
| 232 "; [Bar.]|")) | |
| 233 ("\"" paredit-doublequote | |
| 234 ("(frob grovel |full lexical)" | |
| 235 "(frob grovel \"|\" full lexical)") | |
| 236 ("(foo \"bar |baz\" quux)" | |
| 237 "(foo \"bar \\\"|baz\" quux)")) | |
| 238 ("M-\"" paredit-meta-doublequote | |
| 239 ("(foo \"bar |baz\" quux)" | |
| 240 "(foo \"bar baz\"\n |quux)") | |
| 241 ("(foo |(bar #\\x \"baz \\\\ quux\") zot)" | |
| 242 ,(concat "(foo \"|(bar #\\\\x \\\"baz \\\\" | |
| 243 "\\\\ quux\\\")\" zot)"))) | |
| 244 ("\\" paredit-backslash | |
| 245 ("(string #|)\n ; Escaping character... (x)" | |
| 246 "(string #\\x|)") | |
| 247 ("\"foo|bar\"\n ; Escaping character... (\")" | |
| 248 "\"foo\\\"|bar\"")) | |
| 249 (";" paredit-semicolon | |
| 250 ("|(frob grovel)" | |
| 251 ";|\n(frob grovel)") | |
| 252 ("(frob grovel) |" | |
| 253 "(frob grovel) ;|")) | |
| 254 ("M-;" paredit-comment-dwim | |
| 255 ("(foo |bar) ; baz" | |
| 256 "(foo bar) ; |baz") | |
| 257 ("(frob grovel)|" | |
| 258 "(frob grovel) ;|") | |
| 259 (" (foo bar)\n|\n (baz quux)" | |
| 260 " (foo bar)\n ;; |\n (baz quux)") | |
| 261 (" (foo bar) |(baz quux)" | |
| 262 " (foo bar)\n ;; |\n (baz quux)") | |
| 263 ("|(defun hello-world ...)" | |
| 264 ";;; |\n(defun hello-world ...)")) | |
| 265 | |
| 266 ("C-j" paredit-newline | |
| 267 ("(let ((n (frobbotz))) |(display (+ n 1)\nport))" | |
| 268 ,(concat "(let ((n (frobbotz)))" | |
| 269 "\n |(display (+ n 1)" | |
| 270 "\n port))"))) | |
| 271 | |
| 272 "Deleting & Killing" | |
| 273 (("C-d" ,@paredit-forward-delete-keys) | |
| 274 paredit-forward-delete | |
| 275 ("(quu|x \"zot\")" "(quu| \"zot\")") | |
| 276 ("(quux |\"zot\")" | |
| 277 "(quux \"|zot\")" | |
| 278 "(quux \"|ot\")") | |
| 279 ("(foo (|) bar)" "(foo | bar)") | |
| 280 ("|(foo bar)" "(|foo bar)")) | |
| 281 (,paredit-backward-delete-key | |
| 282 paredit-backward-delete | |
| 283 ("(\"zot\" q|uux)" "(\"zot\" |uux)") | |
| 284 ("(\"zot\"| quux)" | |
| 285 "(\"zot|\" quux)" | |
| 286 "(\"zo|\" quux)") | |
| 287 ("(foo (|) bar)" "(foo | bar)") | |
| 288 ("(foo bar)|" "(foo bar|)")) | |
| 289 ("C-k" paredit-kill | |
| 290 ("(foo bar)| ; Useless comment!" | |
| 291 "(foo bar)|") | |
| 292 ("(|foo bar) ; Useful comment!" | |
| 293 "(|) ; Useful comment!") | |
| 294 ("|(foo bar) ; Useless line!" | |
| 295 "|") | |
| 296 ("(foo \"|bar baz\"\n quux)" | |
| 297 "(foo \"|\"\n quux)")) | |
| 298 ("M-d" paredit-forward-kill-word | |
| 299 ("|(foo bar) ; baz" | |
| 300 "(| bar) ; baz" | |
| 301 "(|) ; baz" | |
| 302 "() ;|") | |
| 303 (";;;| Frobnicate\n(defun frobnicate ...)" | |
| 304 ";;;|\n(defun frobnicate ...)" | |
| 305 ";;;\n(| frobnicate ...)")) | |
| 306 (,(concat "M-" paredit-backward-delete-key) | |
| 307 paredit-backward-kill-word | |
| 308 ("(foo bar) ; baz\n(quux)|" | |
| 309 "(foo bar) ; baz\n(|)" | |
| 310 "(foo bar) ; |\n()" | |
| 311 "(foo |) ; \n()" | |
| 312 "(|) ; \n()")) | |
| 313 | |
| 314 "Movement & Navigation" | |
| 315 ("C-M-f" paredit-forward | |
| 316 ("(foo |(bar baz) quux)" | |
| 317 "(foo (bar baz)| quux)") | |
| 318 ("(foo (bar)|)" | |
| 319 "(foo (bar))|")) | |
| 320 ("C-M-b" paredit-backward | |
| 321 ("(foo (bar baz)| quux)" | |
| 322 "(foo |(bar baz) quux)") | |
| 323 ("(|(foo) bar)" | |
| 324 "|((foo) bar)")) | |
| 325 ;;;("C-M-u" backward-up-list) ; These two are built-in. | |
| 326 ;;;("C-M-d" down-list) | |
| 327 ("C-M-p" backward-down-list) ; Built-in, these are FORWARD- | |
| 328 ("C-M-n" up-list) ; & BACKWARD-LIST, which have | |
| 329 ; no need given C-M-f & C-M-b. | |
| 330 | |
| 331 "Depth-Changing Commands" | |
| 332 ("M-(" paredit-wrap-sexp | |
| 333 ("(foo |bar baz)" | |
| 334 "(foo (|bar) baz)")) | |
| 335 ("M-[" paredit-bracket-wrap-sexp | |
| 336 ("(foo |bar baz)" | |
| 337 "(foo [|bar] baz)")) | |
| 338 ("M-s" paredit-splice-sexp | |
| 339 ("(foo (bar| baz) quux)" | |
| 340 "(foo bar| baz quux)")) | |
| 341 (("M-<up>" "ESC <up>") | |
| 342 paredit-splice-sexp-killing-backward | |
| 343 ("(foo (let ((x 5)) |(sqrt n)) bar)" | |
| 344 "(foo (sqrt n) bar)")) | |
| 345 (("M-<down>" "ESC <down>") | |
| 346 paredit-splice-sexp-killing-forward | |
| 347 ("(a (b c| d e) f)" | |
| 348 "(a b c f)")) | |
| 349 ("M-r" paredit-raise-sexp | |
| 350 ("(dynamic-wind in (lambda () |body) out)" | |
| 351 "(dynamic-wind in |body out)" | |
| 352 "|body")) | |
| 353 | |
| 354 "Barfage & Slurpage" | |
| 355 (("C-)" "C-<right>") | |
| 356 paredit-forward-slurp-sexp | |
| 357 ("(foo (bar |baz) quux zot)" | |
| 358 "(foo (bar |baz quux) zot)") | |
| 359 ("(a b ((c| d)) e f)" | |
| 360 "(a b ((c| d) e) f)")) | |
| 361 (("C-}" "C-<left>") | |
| 362 paredit-forward-barf-sexp | |
| 363 ("(foo (bar |baz quux) zot)" | |
| 364 "(foo (bar |baz) quux zot)")) | |
| 365 (("C-(" "C-M-<left>" "ESC C-<left>") | |
| 366 paredit-backward-slurp-sexp | |
| 367 ("(foo bar (baz| quux) zot)" | |
| 368 "(foo (bar baz| quux) zot)") | |
| 369 ("(a b ((c| d)) e f)" | |
| 370 "(a (b (c| d)) e f)")) | |
| 371 (("C-{" "C-M-<right>" "ESC C-<right>") | |
| 372 paredit-backward-barf-sexp | |
| 373 ("(foo (bar baz |quux) zot)" | |
| 374 "(foo bar (baz |quux) zot)")) | |
| 375 | |
| 376 "Miscellaneous Commands" | |
| 377 ("M-S" paredit-split-sexp | |
| 378 ("(hello| world)" | |
| 379 "(hello)| (world)") | |
| 380 ("\"Hello, |world!\"" | |
| 381 "\"Hello, \"| \"world!\"")) | |
| 382 ("M-J" paredit-join-sexps | |
| 383 ("(hello)| (world)" | |
| 384 "(hello| world)") | |
| 385 ("\"Hello, \"| \"world!\"" | |
| 386 "\"Hello, |world!\"") | |
| 387 ("hello-\n| world" | |
| 388 "hello-|world")) | |
| 389 ("C-c C-M-l" paredit-recentre-on-sexp) | |
| 390 )) | |
| 391 nil) ; end of PROGN | |
| 392 | |
| 393 ;;;;; Command Examples | |
| 394 | |
| 395 (eval-and-compile | |
| 396 (defmacro paredit-do-commands (vars string-case &rest body) | |
| 397 (let ((spec (nth 0 vars)) | |
| 398 (keys (nth 1 vars)) | |
| 399 (fn (nth 2 vars)) | |
| 400 (examples (nth 3 vars))) | |
| 401 `(dolist (,spec paredit-commands) | |
| 402 (if (stringp ,spec) | |
| 403 ,string-case | |
| 404 (let ((,keys (let ((k (car ,spec))) | |
| 405 (cond ((stringp k) (list k)) | |
| 406 ((listp k) k) | |
| 407 (t (error "Invalid paredit command %s." | |
| 408 ,spec))))) | |
| 409 (,fn (cadr ,spec)) | |
| 410 (,examples (cddr ,spec))) | |
| 411 ,@body))))) | |
| 412 | |
| 413 (put 'paredit-do-commands 'lisp-indent-function 2)) | |
| 414 | |
| 415 (defun paredit-define-keys () | |
| 416 (paredit-do-commands (spec keys fn examples) | |
| 417 nil ; string case | |
| 418 (dolist (key keys) | |
| 419 (define-key paredit-mode-map (read-kbd-macro key) fn)))) | |
| 420 | |
| 421 (defun paredit-function-documentation (fn) | |
| 422 (let ((original-doc (get fn 'paredit-original-documentation)) | |
| 423 (doc (documentation fn 'function-documentation))) | |
| 424 (or original-doc | |
| 425 (progn (put fn 'paredit-original-documentation doc) | |
| 426 doc)))) | |
| 427 | |
| 428 (defun paredit-annotate-mode-with-examples () | |
| 429 (let ((contents | |
| 430 (list (paredit-function-documentation 'paredit-mode)))) | |
| 431 (paredit-do-commands (spec keys fn examples) | |
| 432 (push (concat "\n\n" spec "\n") | |
| 433 contents) | |
| 434 (let ((name (symbol-name fn))) | |
| 435 (if (string-match (symbol-name 'paredit-) name) | |
| 436 (push (concat "\n\n\\[" name "]\t" name | |
| 437 (if examples | |
| 438 (mapconcat (lambda (example) | |
| 439 (concat | |
| 440 "\n" | |
| 441 (mapconcat 'identity | |
| 442 example | |
| 443 "\n --->\n") | |
| 444 "\n")) | |
| 445 examples | |
| 446 "") | |
| 447 "\n (no examples)\n")) | |
| 448 contents)))) | |
| 449 (put 'paredit-mode 'function-documentation | |
| 450 (apply 'concat (reverse contents)))) | |
| 451 ;; PUT returns the huge string we just constructed, which we don't | |
| 452 ;; want it to return. | |
| 453 nil) | |
| 454 | |
| 455 (defun paredit-annotate-functions-with-examples () | |
| 456 (paredit-do-commands (spec keys fn examples) | |
| 457 nil ; string case | |
| 458 (put fn 'function-documentation | |
| 459 (concat (paredit-function-documentation fn) | |
| 460 "\n\n\\<paredit-mode-map>\\[" (symbol-name fn) "]\n" | |
| 461 (mapconcat (lambda (example) | |
| 462 (concat "\n" | |
| 463 (mapconcat 'identity | |
| 464 example | |
| 465 "\n ->\n") | |
| 466 "\n")) | |
| 467 examples | |
| 468 ""))))) | |
| 469 | |
| 470 ;;;;; HTML Examples | |
| 471 | |
| 472 (defun paredit-insert-html-examples () | |
| 473 "Insert HTML for a paredit quick reference table." | |
| 474 (interactive) | |
| 475 (let ((insert-lines (lambda (&rest lines) | |
| 476 (mapc (lambda (line) (insert line) (newline)) | |
| 477 lines))) | |
| 478 (html-keys (lambda (keys) | |
| 479 (mapconcat 'paredit-html-quote keys ", "))) | |
| 480 (html-example | |
| 481 (lambda (example) | |
| 482 (concat "<table><tr><td><pre>" | |
| 483 (mapconcat 'paredit-html-quote | |
| 484 example | |
| 485 (concat "</pre></td></tr><tr><td>" | |
| 486 " --->" | |
| 487 "</td></tr><tr><td><pre>")) | |
| 488 "</pre></td></tr></table>"))) | |
| 489 (firstp t)) | |
| 490 (paredit-do-commands (spec keys fn examples) | |
| 491 (progn (if (not firstp) | |
| 492 (insert "</table>\n") | |
| 493 (setq firstp nil)) | |
| 494 (funcall insert-lines | |
| 495 (concat "<h3>" spec "</h3>") | |
| 496 "<table border=\"1\" cellpadding=\"1\">" | |
| 497 " <tr>" | |
| 498 " <th>Command</th>" | |
| 499 " <th>Keys</th>" | |
| 500 " <th>Examples</th>" | |
| 501 " </tr>")) | |
| 502 (let ((name (symbol-name fn))) | |
| 503 (if (string-match (symbol-name 'paredit-) name) | |
| 504 (funcall insert-lines | |
| 505 " <tr>" | |
| 506 (concat " <td><tt>" name "</tt></td>") | |
| 507 (concat " <td align=\"center\">" | |
| 508 (funcall html-keys keys) | |
| 509 "</td>") | |
| 510 (concat " <td>" | |
| 511 (if examples | |
| 512 (mapconcat html-example examples | |
| 513 "<hr>") | |
| 514 "(no examples)") | |
| 515 "</td>") | |
| 516 " </tr>"))))) | |
| 517 (insert "</table>\n")) | |
| 518 | |
| 519 (defun paredit-html-quote (string) | |
| 520 (with-temp-buffer | |
| 521 (dotimes (i (length string)) | |
| 522 (insert (let ((c (elt string i))) | |
| 523 (cond ((eq c ?\<) "<") | |
| 524 ((eq c ?\>) ">") | |
| 525 ((eq c ?\&) "&") | |
| 526 ((eq c ?\') "'") | |
| 527 ((eq c ?\") """) | |
| 528 (t c))))) | |
| 529 (buffer-string))) | |
| 530 | |
| 531 ;;;; Delimiter Insertion | |
| 532 | |
| 533 (eval-and-compile | |
| 534 (defun paredit-conc-name (&rest strings) | |
| 535 (intern (apply 'concat strings))) | |
| 536 | |
| 537 (defmacro define-paredit-pair (open close name) | |
| 538 `(progn | |
| 539 (defun ,(paredit-conc-name "paredit-open-" name) (&optional n) | |
| 540 ,(concat "Insert a balanced " name " pair. | |
| 541 With a prefix argument N, put the closing " name " after N | |
| 542 S-expressions forward. | |
| 543 If the region is active, `transient-mark-mode' is enabled, and the | |
| 544 region's start and end fall in the same parenthesis depth, insert a | |
| 545 " name " pair around the region. | |
| 546 If in a string or a comment, insert a single " name ". | |
| 547 If in a character literal, do nothing. This prevents changing what was | |
| 548 in the character literal to a meaningful delimiter unintentionally.") | |
| 549 (interactive "P") | |
| 550 (cond ((or (paredit-in-string-p) | |
| 551 (paredit-in-comment-p)) | |
| 552 (insert ,open)) | |
| 553 ((not (paredit-in-char-p)) | |
| 554 (paredit-insert-pair n ,open ,close 'goto-char)))) | |
| 555 (defun ,(paredit-conc-name "paredit-close-" name) () | |
| 556 ,(concat "Move past one closing delimiter and reindent. | |
| 557 \(Agnostic to the specific closing delimiter.) | |
| 558 If in a string or comment, insert a single closing " name ". | |
| 559 If in a character literal, do nothing. This prevents changing what was | |
| 560 in the character literal to a meaningful delimiter unintentionally.") | |
| 561 (interactive) | |
| 562 (paredit-move-past-close ,close)) | |
| 563 (defun ,(paredit-conc-name "paredit-close-" name "-and-newline") () | |
| 564 ,(concat "Move past one closing delimiter, add a newline," | |
| 565 " and reindent. | |
| 566 If there was a margin comment after the closing delimiter, preserve it | |
| 567 on the same line.") | |
| 568 (interactive) | |
| 569 (paredit-move-past-close-and-newline ,close)) | |
| 570 (defun ,(paredit-conc-name "paredit-" name "-wrap-sexp") (&optional n) | |
| 571 ,(concat "Wrap a pair of " name " around a sexp") | |
| 572 (interactive "P") | |
| 573 (paredit-wrap-sexp n ,open ,close))))) | |
| 574 | |
| 575 (define-paredit-pair ?\( ?\) "parenthesis") | |
| 576 (define-paredit-pair ?\[ ?\] "bracket") | |
| 577 (define-paredit-pair ?\{ ?\} "brace") | |
| 578 (define-paredit-pair ?\< ?\> "brocket") | |
| 579 | |
| 580 (defun paredit-move-past-close (close) | |
| 581 (cond ((or (paredit-in-string-p) | |
| 582 (paredit-in-comment-p)) | |
| 583 (insert close)) | |
| 584 ((not (paredit-in-char-p)) | |
| 585 (paredit-move-past-close-and-reindent) | |
| 586 (paredit-blink-paren-match nil)))) | |
| 587 | |
| 588 (defun paredit-move-past-close-and-newline (close) | |
| 589 (cond ((or (paredit-in-string-p) | |
| 590 (paredit-in-comment-p)) | |
| 591 (insert close)) | |
| 592 (t (if (paredit-in-char-p) (forward-char)) | |
| 593 (paredit-move-past-close-and-reindent) | |
| 594 (let ((comment.point (paredit-find-comment-on-line))) | |
| 595 (newline) | |
| 596 (if comment.point | |
| 597 (save-excursion | |
| 598 (forward-line -1) | |
| 599 (end-of-line) | |
| 600 (indent-to (cdr comment.point)) | |
| 601 (insert (car comment.point))))) | |
| 602 (lisp-indent-line) | |
| 603 (paredit-ignore-sexp-errors (indent-sexp)) | |
| 604 (paredit-blink-paren-match t)))) | |
| 605 | |
| 606 (defun paredit-find-comment-on-line () | |
| 607 "Find a margin comment on the current line. | |
| 608 If such a comment exists, delete the comment (including all leading | |
| 609 whitespace) and return a cons whose car is the comment as a string | |
| 610 and whose cdr is the point of the comment's initial semicolon, | |
| 611 relative to the start of the line." | |
| 612 (save-excursion | |
| 613 (catch 'return | |
| 614 (while t | |
| 615 (if (search-forward ";" (point-at-eol) t) | |
| 616 (if (not (or (paredit-in-string-p) | |
| 617 (paredit-in-char-p))) | |
| 618 (let* ((start (progn (backward-char) ;before semicolon | |
| 619 (point))) | |
| 620 (comment (buffer-substring start | |
| 621 (point-at-eol)))) | |
| 622 (paredit-skip-whitespace nil (point-at-bol)) | |
| 623 (delete-region (point) (point-at-eol)) | |
| 624 (throw 'return | |
| 625 (cons comment (- start (point-at-bol)))))) | |
| 626 (throw 'return nil)))))) | |
| 627 | |
| 628 (defun paredit-insert-pair (n open close forward) | |
| 629 (let* ((regionp (and (paredit-region-active-p) | |
| 630 (paredit-region-safe-for-insert-p))) | |
| 631 (end (and regionp | |
| 632 (not n) | |
| 633 (prog1 (region-end) | |
| 634 (goto-char (region-beginning)))))) | |
| 635 (let ((spacep (paredit-space-for-delimiter-p nil open))) | |
| 636 (if spacep (insert " ")) | |
| 637 (insert open) | |
| 638 (save-excursion | |
| 639 ;; Move past the desired region. | |
| 640 (cond (n (funcall forward | |
| 641 (save-excursion | |
| 642 (forward-sexp (prefix-numeric-value n)) | |
| 643 (point)))) | |
| 644 (regionp (funcall forward (+ end (if spacep 2 1))))) | |
| 645 (insert close) | |
| 646 (if (paredit-space-for-delimiter-p t close) | |
| 647 (insert " ")))))) | |
| 648 | |
| 649 (defun paredit-region-safe-for-insert-p () | |
| 650 (save-excursion | |
| 651 (let ((beginning (region-beginning)) | |
| 652 (end (region-end))) | |
| 653 (goto-char beginning) | |
| 654 (let* ((beginning-state (paredit-current-parse-state)) | |
| 655 (end-state (parse-partial-sexp beginning end | |
| 656 nil nil beginning-state))) | |
| 657 (and (= (nth 0 beginning-state) ; 0. depth in parens | |
| 658 (nth 0 end-state)) | |
| 659 (eq (nth 3 beginning-state) ; 3. non-nil if inside a | |
| 660 (nth 3 end-state)) ; string | |
| 661 (eq (nth 4 beginning-state) ; 4. comment status, yada | |
| 662 (nth 4 end-state)) | |
| 663 (eq (nth 5 beginning-state) ; 5. t if following char | |
| 664 (nth 5 end-state))))))) ; quote | |
| 665 | |
| 666 (defun paredit-space-for-delimiter-p (endp delimiter) | |
| 667 ;; If at the buffer limit, don't insert a space. If there is a word, | |
| 668 ;; symbol, other quote, or non-matching parenthesis delimiter (i.e. a | |
| 669 ;; close when want an open the string or an open when we want to | |
| 670 ;; close the string), do insert a space. | |
| 671 (and (not (if endp (eobp) (bobp))) | |
| 672 (memq (char-syntax (if endp | |
| 673 (char-after) | |
| 674 (char-before))) | |
| 675 (list ?w ?_ ?\" | |
| 676 (let ((matching (matching-paren delimiter))) | |
| 677 (and matching (char-syntax matching))))))) | |
| 678 | |
| 679 (defun paredit-move-past-close-and-reindent () | |
| 680 (let ((orig (point))) | |
| 681 (up-list) | |
| 682 (if (catch 'return ; This CATCH returns T if it | |
| 683 (while t ; should delete leading spaces | |
| 684 (save-excursion ; and NIL if not. | |
| 685 (let ((before-paren (1- (point)))) | |
| 686 (back-to-indentation) | |
| 687 (cond ((not (eq (point) before-paren)) | |
| 688 ;; Can't call PAREDIT-DELETE-LEADING-WHITESPACE | |
| 689 ;; here -- we must return from SAVE-EXCURSION | |
| 690 ;; first. | |
| 691 (throw 'return t)) | |
| 692 ((save-excursion (forward-line -1) | |
| 693 (end-of-line) | |
| 694 (paredit-in-comment-p)) | |
| 695 ;; Moving the closing parenthesis any further | |
| 696 ;; would put it into a comment, so we just | |
| 697 ;; indent the closing parenthesis where it is | |
| 698 ;; and abort the loop, telling its continuation | |
| 699 ;; that no leading whitespace should be deleted. | |
| 700 (lisp-indent-line) | |
| 701 (throw 'return nil)) | |
| 702 (t (delete-indentation))))))) | |
| 703 (paredit-delete-leading-whitespace)))) | |
| 704 | |
| 705 (defun paredit-delete-leading-whitespace () | |
| 706 ;; This assumes that we're on the closing parenthesis already. | |
| 707 (save-excursion | |
| 708 (backward-char) | |
| 709 (while (let ((syn (char-syntax (char-before)))) | |
| 710 (and (or (eq syn ?\ ) (eq syn ?-)) ; whitespace syntax | |
| 711 ;; The above line is a perfect example of why the | |
| 712 ;; following test is necessary. | |
| 713 (not (paredit-in-char-p (1- (point)))))) | |
| 714 (backward-delete-char 1)))) | |
| 715 | |
| 716 (defun paredit-blink-paren-match (another-line-p) | |
| 717 (if (and blink-matching-paren | |
| 718 (or (not show-paren-mode) another-line-p)) | |
| 719 (paredit-ignore-sexp-errors | |
| 720 (save-excursion | |
| 721 (backward-sexp) | |
| 722 (forward-sexp) | |
| 723 ;; SHOW-PAREN-MODE inhibits any blinking, so we disable it | |
| 724 ;; locally here. | |
| 725 (let ((show-paren-mode nil)) | |
| 726 (blink-matching-open)))))) | |
| 727 | |
| 728 (defun paredit-doublequote (&optional n) | |
| 729 "Insert a pair of double-quotes. | |
| 730 With a prefix argument N, wrap the following N S-expressions in | |
| 731 double-quotes, escaping intermediate characters if necessary. | |
| 732 If the region is active, `transient-mark-mode' is enabled, and the | |
| 733 region's start and end fall in the same parenthesis depth, insert a | |
| 734 pair of double-quotes around the region, again escaping intermediate | |
| 735 characters if necessary. | |
| 736 Inside a comment, insert a literal double-quote. | |
| 737 At the end of a string, move past the closing double-quote. | |
| 738 In the middle of a string, insert a backslash-escaped double-quote. | |
| 739 If in a character literal, do nothing. This prevents accidentally | |
| 740 changing a what was in the character literal to become a meaningful | |
| 741 delimiter unintentionally." | |
| 742 (interactive "P") | |
| 743 (cond ((paredit-in-string-p) | |
| 744 (if (eq (cdr (paredit-string-start+end-points)) | |
| 745 (point)) | |
| 746 (forward-char) ; We're on the closing quote. | |
| 747 (insert ?\\ ?\" ))) | |
| 748 ((paredit-in-comment-p) | |
| 749 (insert ?\" )) | |
| 750 ((not (paredit-in-char-p)) | |
| 751 (paredit-insert-pair n ?\" ?\" 'paredit-forward-for-quote)))) | |
| 752 | |
| 753 (defun paredit-meta-doublequote (&optional n) | |
| 754 "Move to the end of the string, insert a newline, and indent. | |
| 755 If not in a string, act as `paredit-doublequote'; if no prefix argument | |
| 756 is specified and the region is not active or `transient-mark-mode' is | |
| 757 disabled, the default is to wrap one S-expression, however, not | |
| 758 zero." | |
| 759 (interactive "P") | |
| 760 (if (not (paredit-in-string-p)) | |
| 761 (paredit-doublequote (or n | |
| 762 (and (not (paredit-region-active-p)) | |
| 763 1))) | |
| 764 (let ((start+end (paredit-string-start+end-points))) | |
| 765 (goto-char (1+ (cdr start+end))) | |
| 766 (newline) | |
| 767 (lisp-indent-line) | |
| 768 (paredit-ignore-sexp-errors (indent-sexp))))) | |
| 769 | |
| 770 (defun paredit-forward-for-quote (end) | |
| 771 (let ((state (paredit-current-parse-state))) | |
| 772 (while (< (point) end) | |
| 773 (let ((new-state (parse-partial-sexp (point) (1+ (point)) | |
| 774 nil nil state))) | |
| 775 (if (paredit-in-string-p new-state) | |
| 776 (if (not (paredit-in-string-escape-p)) | |
| 777 (setq state new-state) | |
| 778 ;; Escape character: turn it into an escaped escape | |
| 779 ;; character by appending another backslash. | |
| 780 (insert ?\\ ) | |
| 781 ;; Now the point is after both escapes, and we want to | |
| 782 ;; rescan from before the first one to after the second | |
| 783 ;; one. | |
| 784 (setq state | |
| 785 (parse-partial-sexp (- (point) 2) (point) | |
| 786 nil nil state)) | |
| 787 ;; Advance the end point, since we just inserted a new | |
| 788 ;; character. | |
| 789 (setq end (1+ end))) | |
| 790 ;; String: escape by inserting a backslash before the quote. | |
| 791 (backward-char) | |
| 792 (insert ?\\ ) | |
| 793 ;; The point is now between the escape and the quote, and we | |
| 794 ;; want to rescan from before the escape to after the quote. | |
| 795 (setq state | |
| 796 (parse-partial-sexp (1- (point)) (1+ (point)) | |
| 797 nil nil state)) | |
| 798 ;; Advance the end point for the same reason as above. | |
| 799 (setq end (1+ end))))))) | |
| 800 | |
| 801 ;;;; Escape Insertion | |
| 802 | |
| 803 (defun paredit-backslash () | |
| 804 "Insert a backslash followed by a character to escape." | |
| 805 (interactive) | |
| 806 (insert ?\\ ) | |
| 807 ;; This funny conditional is necessary because PAREDIT-IN-COMMENT-P | |
| 808 ;; assumes that PAREDIT-IN-STRING-P already returned false; otherwise | |
| 809 ;; it may give erroneous answers. | |
| 810 (if (or (paredit-in-string-p) | |
| 811 (not (paredit-in-comment-p))) | |
| 812 (let ((delp t)) | |
| 813 (unwind-protect (setq delp | |
| 814 (call-interactively 'paredit-escape)) | |
| 815 ;; We need this in an UNWIND-PROTECT so that the backlash is | |
| 816 ;; left in there *only* if PAREDIT-ESCAPE return NIL normally | |
| 817 ;; -- in any other case, such as the user hitting C-g or an | |
| 818 ;; error occurring, we must delete the backslash to avoid | |
| 819 ;; leaving a dangling escape. (This control structure is a | |
| 820 ;; crock.) | |
| 821 (if delp (backward-delete-char 1)))))) | |
| 822 | |
| 823 ;;; This auxiliary interactive function returns true if the backslash | |
| 824 ;;; should be deleted and false if not. | |
| 825 | |
| 826 (defun paredit-escape (char) | |
| 827 ;; I'm too lazy to figure out how to do this without a separate | |
| 828 ;; interactive function. | |
| 829 (interactive "cEscaping character...") | |
| 830 (if (eq char 127) ; The backslash was a typo, so | |
| 831 t ; the luser wants to delete it. | |
| 832 (insert char) ; (Is there a better way to | |
| 833 nil)) ; express the rubout char? | |
| 834 ; ?\^? works, but ugh...) | |
| 835 | |
| 836 ;;; The placement of this function in this file is totally random. | |
| 837 | |
| 838 (defun paredit-newline () | |
| 839 "Insert a newline and indent it. | |
| 840 This is like `newline-and-indent', but it not only indents the line | |
| 841 that the point is on but also the S-expression following the point, | |
| 842 if there is one. | |
| 843 Move forward one character first if on an escaped character. | |
| 844 If in a string, just insert a literal newline." | |
| 845 (interactive) | |
| 846 (if (paredit-in-string-p) | |
| 847 (newline) | |
| 848 (if (and (not (paredit-in-comment-p)) (paredit-in-char-p)) | |
| 849 (forward-char)) | |
| 850 (newline-and-indent) | |
| 851 ;; Indent the following S-expression, but don't signal an error if | |
| 852 ;; there's only a closing parenthesis after the point. | |
| 853 (paredit-ignore-sexp-errors (indent-sexp)))) | |
| 854 | |
| 855 ;;;; Comment Insertion | |
| 856 | |
| 857 (defun paredit-semicolon (&optional n) | |
| 858 "Insert a semicolon, moving any code after the point to a new line. | |
| 859 If in a string, comment, or character literal, insert just a literal | |
| 860 semicolon, and do not move anything to the next line. | |
| 861 With a prefix argument N, insert N semicolons." | |
| 862 (interactive "P") | |
| 863 (if (not (or (paredit-in-string-p) | |
| 864 (paredit-in-comment-p) | |
| 865 (paredit-in-char-p) | |
| 866 ;; No more code on the line after the point. | |
| 867 (save-excursion | |
| 868 (paredit-skip-whitespace t (point-at-eol)) | |
| 869 (or (eolp) | |
| 870 ;; Let the user prefix semicolons to existing | |
| 871 ;; comments. | |
| 872 (eq (char-after) ?\;))))) | |
| 873 ;; Don't use NEWLINE-AND-INDENT, because that will delete all of | |
| 874 ;; the horizontal whitespace first, but we just want to move the | |
| 875 ;; code following the point onto the next line while preserving | |
| 876 ;; the point on this line. | |
| 877 ;++ Why indent only the line? | |
| 878 (save-excursion (newline) (lisp-indent-line))) | |
| 879 (insert (make-string (if n (prefix-numeric-value n) 1) | |
| 880 ?\; ))) | |
| 881 | |
| 882 (defun paredit-comment-dwim (&optional arg) | |
| 883 "Call the Lisp comment command you want (Do What I Mean). | |
| 884 This is like `comment-dwim', but it is specialized for Lisp editing. | |
| 885 If transient mark mode is enabled and the mark is active, comment or | |
| 886 uncomment the selected region, depending on whether it was entirely | |
| 887 commented not not already. | |
| 888 If there is already a comment on the current line, with no prefix | |
| 889 argument, indent to that comment; with a prefix argument, kill that | |
| 890 comment. | |
| 891 Otherwise, insert a comment appropriate for the context and ensure that | |
| 892 any code following the comment is moved to the next line. | |
| 893 At the top level, where indentation is calculated to be at column 0, | |
| 894 insert a triple-semicolon comment; within code, where the indentation | |
| 895 is calculated to be non-zero, and on the line there is either no code | |
| 896 at all or code after the point, insert a double-semicolon comment; | |
| 897 and if the point is after all code on the line, insert a single- | |
| 898 semicolon margin comment at `comment-column'." | |
| 899 (interactive "*P") | |
| 900 (require 'newcomment) | |
| 901 (comment-normalize-vars) | |
| 902 (cond ((paredit-region-active-p) | |
| 903 (comment-or-uncomment-region (region-beginning) | |
| 904 (region-end) | |
| 905 arg)) | |
| 906 ((paredit-comment-on-line-p) | |
| 907 (if arg | |
| 908 (comment-kill (if (integerp arg) arg nil)) | |
| 909 (comment-indent))) | |
| 910 (t (paredit-insert-comment)))) | |
| 911 | |
| 912 (defun paredit-comment-on-line-p () | |
| 913 (save-excursion | |
| 914 (beginning-of-line) | |
| 915 (let ((comment-p nil)) | |
| 916 ;; Search forward for a comment beginning. If there is one, set | |
| 917 ;; COMMENT-P to true; if not, it will be nil. | |
| 918 (while (progn (setq comment-p | |
| 919 (search-forward ";" (point-at-eol) | |
| 920 ;; t -> no error | |
| 921 t)) | |
| 922 (and comment-p | |
| 923 (or (paredit-in-string-p) | |
| 924 (paredit-in-char-p (1- (point)))))) | |
| 925 (forward-char)) | |
| 926 comment-p))) | |
| 927 | |
| 928 (defun paredit-insert-comment () | |
| 929 (let ((code-after-p | |
| 930 (save-excursion (paredit-skip-whitespace t (point-at-eol)) | |
| 931 (not (eolp)))) | |
| 932 (code-before-p | |
| 933 (save-excursion (paredit-skip-whitespace nil (point-at-bol)) | |
| 934 (not (bolp))))) | |
| 935 (if (and (bolp) | |
| 936 ;; We have to use EQ 0 here and not ZEROP because ZEROP | |
| 937 ;; signals an error if its argument is non-numeric, but | |
| 938 ;; CALCULATE-LISP-INDENT may return nil. | |
| 939 (eq (let ((indent (calculate-lisp-indent))) | |
| 940 (if (consp indent) | |
| 941 (car indent) | |
| 942 indent)) | |
| 943 0)) | |
| 944 ;; Top-level comment | |
| 945 (progn (if code-after-p (save-excursion (newline))) | |
| 946 (insert ";;; ")) | |
| 947 (if code-after-p | |
| 948 ;; Code comment | |
| 949 (progn (if code-before-p | |
| 950 ;++ Why NEWLINE-AND-INDENT here and not just | |
| 951 ;++ NEWLINE, or PAREDIT-NEWLINE? | |
| 952 (newline-and-indent)) | |
| 953 (lisp-indent-line) | |
| 954 (insert ";; ") | |
| 955 ;; Move the following code. (NEWLINE-AND-INDENT will | |
| 956 ;; delete whitespace after the comment, though, so use | |
| 957 ;; NEWLINE & LISP-INDENT-LINE manually here.) | |
| 958 (save-excursion (newline) | |
| 959 (lisp-indent-line))) | |
| 960 ;; Margin comment | |
| 961 (progn (indent-to comment-column | |
| 962 1) ; 1 -> force one leading space | |
| 963 (insert ?\; )))))) | |
| 964 | |
| 965 ;;;; Character Deletion | |
| 966 | |
| 967 (defun paredit-forward-delete (&optional arg) | |
| 968 "Delete a character forward or move forward over a delimiter. | |
| 969 If on an opening S-expression delimiter, move forward into the | |
| 970 S-expression. | |
| 971 If on a closing S-expression delimiter, refuse to delete unless the | |
| 972 S-expression is empty, in which case delete the whole S-expression. | |
| 973 With a prefix argument, simply delete a character forward, without | |
| 974 regard for delimiter balancing." | |
| 975 (interactive "P") | |
| 976 (cond ((or arg (eobp)) | |
| 977 (delete-char 1)) | |
| 978 ((paredit-in-string-p) | |
| 979 (paredit-forward-delete-in-string)) | |
| 980 ((paredit-in-comment-p) | |
| 981 ;++ What to do here? This could move a partial S-expression | |
| 982 ;++ into a comment and thereby invalidate the file's form, | |
| 983 ;++ or move random text out of a comment. | |
| 984 (delete-char 1)) | |
| 985 ((paredit-in-char-p) ; Escape -- delete both chars. | |
| 986 (backward-delete-char 1) | |
| 987 (delete-char 1)) | |
| 988 ((eq (char-after) ?\\ ) ; ditto | |
| 989 (delete-char 2)) | |
| 990 ((let ((syn (char-syntax (char-after)))) | |
| 991 (or (eq syn ?\( ) | |
| 992 (eq syn ?\" ))) | |
| 993 (forward-char)) | |
| 994 ((and (not (paredit-in-char-p (1- (point)))) | |
| 995 (eq (char-syntax (char-after)) ?\) ) | |
| 996 (eq (char-before) (matching-paren (char-after)))) | |
| 997 (backward-delete-char 1) ; Empty list -- delete both | |
| 998 (delete-char 1)) ; delimiters. | |
| 999 ;; Just delete a single character, if it's not a closing | |
| 1000 ;; parenthesis. (The character literal case is already | |
| 1001 ;; handled by now.) | |
| 1002 ((not (eq (char-syntax (char-after)) ?\) )) | |
| 1003 (delete-char 1)))) | |
| 1004 | |
| 1005 (defun paredit-forward-delete-in-string () | |
| 1006 (let ((start+end (paredit-string-start+end-points))) | |
| 1007 (cond ((not (eq (point) (cdr start+end))) | |
| 1008 ;; If it's not the close-quote, it's safe to delete. But | |
| 1009 ;; first handle the case that we're in a string escape. | |
| 1010 (cond ((paredit-in-string-escape-p) | |
| 1011 ;; We're right after the backslash, so backward | |
| 1012 ;; delete it before deleting the escaped character. | |
| 1013 (backward-delete-char 1)) | |
| 1014 ((eq (char-after) ?\\ ) | |
| 1015 ;; If we're not in a string escape, but we are on a | |
| 1016 ;; backslash, it must start the escape for the next | |
| 1017 ;; character, so delete the backslash before deleting | |
| 1018 ;; the next character. | |
| 1019 (delete-char 1))) | |
| 1020 (delete-char 1)) | |
| 1021 ((eq (1- (point)) (car start+end)) | |
| 1022 ;; If it is the close-quote, delete only if we're also right | |
| 1023 ;; past the open-quote (i.e. it's empty), and then delete | |
| 1024 ;; both quotes. Otherwise we refuse to delete it. | |
| 1025 (backward-delete-char 1) | |
| 1026 (delete-char 1))))) | |
| 1027 | |
| 1028 (defun paredit-backward-delete (&optional arg) | |
| 1029 "Delete a character backward or move backward over a delimiter. | |
| 1030 If on a closing S-expression delimiter, move backward into the | |
| 1031 S-expression. | |
| 1032 If on an opening S-expression delimiter, refuse to delete unless the | |
| 1033 S-expression is empty, in which case delete the whole S-expression. | |
| 1034 With a prefix argument, simply delete a character backward, without | |
| 1035 regard for delimiter balancing." | |
| 1036 (interactive "P") | |
| 1037 (cond ((or arg (bobp)) | |
| 1038 (backward-delete-char 1)) ;++ should this untabify? | |
| 1039 ((paredit-in-string-p) | |
| 1040 (paredit-backward-delete-in-string)) | |
| 1041 ((paredit-in-comment-p) | |
| 1042 (backward-delete-char 1)) | |
| 1043 ((paredit-in-char-p) ; Escape -- delete both chars. | |
| 1044 (backward-delete-char 1) | |
| 1045 (delete-char 1)) | |
| 1046 ((paredit-in-char-p (1- (point))) | |
| 1047 (backward-delete-char 2)) ; ditto | |
| 1048 ((let ((syn (char-syntax (char-before)))) | |
| 1049 (or (eq syn ?\) ) | |
| 1050 (eq syn ?\" ))) | |
| 1051 (backward-char)) | |
| 1052 ((and (eq (char-syntax (char-before)) ?\( ) | |
| 1053 (eq (char-after) (matching-paren (char-before)))) | |
| 1054 (backward-delete-char 1) ; Empty list -- delete both | |
| 1055 (delete-char 1)) ; delimiters. | |
| 1056 ;; Delete it, unless it's an opening parenthesis. The case | |
| 1057 ;; of character literals is already handled by now. | |
| 1058 ((not (eq (char-syntax (char-before)) ?\( )) | |
| 1059 (backward-delete-char-untabify 1)))) | |
| 1060 | |
| 1061 (defun paredit-backward-delete-in-string () | |
| 1062 (let ((start+end (paredit-string-start+end-points))) | |
| 1063 (cond ((not (eq (1- (point)) (car start+end))) | |
| 1064 ;; If it's not the open-quote, it's safe to delete. | |
| 1065 (if (paredit-in-string-escape-p) | |
| 1066 ;; If we're on a string escape, since we're about to | |
| 1067 ;; delete the backslash, we must first delete the | |
| 1068 ;; escaped char. | |
| 1069 (delete-char 1)) | |
| 1070 (backward-delete-char 1) | |
| 1071 (if (paredit-in-string-escape-p) | |
| 1072 ;; If, after deleting a character, we find ourselves in | |
| 1073 ;; a string escape, we must have deleted the escaped | |
| 1074 ;; character, and the backslash is behind the point, so | |
| 1075 ;; backward delete it. | |
| 1076 (backward-delete-char 1))) | |
| 1077 ((eq (point) (cdr start+end)) | |
| 1078 ;; If it is the open-quote, delete only if we're also right | |
| 1079 ;; past the close-quote (i.e. it's empty), and then delete | |
| 1080 ;; both quotes. Otherwise we refuse to delete it. | |
| 1081 (backward-delete-char 1) | |
| 1082 (delete-char 1))))) | |
| 1083 | |
| 1084 ;;;; Killing | |
| 1085 | |
| 1086 (defun paredit-kill (&optional arg) | |
| 1087 "Kill a line as if with `kill-line', but respecting delimiters. | |
| 1088 In a string, act exactly as `kill-line' but do not kill past the | |
| 1089 closing string delimiter. | |
| 1090 On a line with no S-expressions on it starting after the point or | |
| 1091 within a comment, act exactly as `kill-line'. | |
| 1092 Otherwise, kill all S-expressions that start after the point." | |
| 1093 (interactive "P") | |
| 1094 (cond (arg (kill-line)) | |
| 1095 ((paredit-in-string-p) | |
| 1096 (paredit-kill-line-in-string)) | |
| 1097 ((or (paredit-in-comment-p) | |
| 1098 (save-excursion | |
| 1099 (paredit-skip-whitespace t (point-at-eol)) | |
| 1100 (or (eq (char-after) ?\; ) | |
| 1101 (eolp)))) | |
| 1102 ;** Be careful about trailing backslashes. | |
| 1103 (kill-line)) | |
| 1104 (t (paredit-kill-sexps-on-line)))) | |
| 1105 | |
| 1106 (defun paredit-kill-line-in-string () | |
| 1107 (if (save-excursion (paredit-skip-whitespace t (point-at-eol)) | |
| 1108 (eolp)) | |
| 1109 (kill-line) | |
| 1110 (save-excursion | |
| 1111 ;; Be careful not to split an escape sequence. | |
| 1112 (if (paredit-in-string-escape-p) | |
| 1113 (backward-char)) | |
| 1114 (let ((beginning (point))) | |
| 1115 (while (not (or (eolp) | |
| 1116 (eq (char-after) ?\" ))) | |
| 1117 (forward-char) | |
| 1118 ;; Skip past escaped characters. | |
| 1119 (if (eq (char-before) ?\\ ) | |
| 1120 (forward-char))) | |
| 1121 (kill-region beginning (point)))))) | |
| 1122 | |
| 1123 (defun paredit-kill-sexps-on-line () | |
| 1124 (if (paredit-in-char-p) ; Move past the \ and prefix. | |
| 1125 (backward-char 2)) ; (# in Scheme/CL, ? in elisp) | |
| 1126 (let ((beginning (point)) | |
| 1127 (eol (point-at-eol))) | |
| 1128 (let ((end-of-list-p (paredit-forward-sexps-to-kill beginning eol))) | |
| 1129 ;; If we got to the end of the list and it's on the same line, | |
| 1130 ;; move backward past the closing delimiter before killing. (This | |
| 1131 ;; allows something like killing the whitespace in ( ).) | |
| 1132 (if end-of-list-p (progn (up-list) (backward-char))) | |
| 1133 (if kill-whole-line | |
| 1134 (paredit-kill-sexps-on-whole-line beginning) | |
| 1135 (kill-region beginning | |
| 1136 ;; If all of the S-expressions were on one line, | |
| 1137 ;; i.e. we're still on that line after moving past | |
| 1138 ;; the last one, kill the whole line, including | |
| 1139 ;; any comments; otherwise just kill to the end of | |
| 1140 ;; the last S-expression we found. Be sure, | |
| 1141 ;; though, not to kill any closing parentheses. | |
| 1142 (if (and (not end-of-list-p) | |
| 1143 (eq (point-at-eol) eol)) | |
| 1144 eol | |
| 1145 (point))))))) | |
| 1146 | |
| 1147 ;;; Please do not try to understand this code unless you have a VERY | |
| 1148 ;;; good reason to do so. I gave up trying to figure it out well | |
| 1149 ;;; enough to explain it, long ago. | |
| 1150 | |
| 1151 (defun paredit-forward-sexps-to-kill (beginning eol) | |
| 1152 (let ((end-of-list-p nil) | |
| 1153 (firstp t)) | |
| 1154 ;; Move to the end of the last S-expression that started on this | |
| 1155 ;; line, or to the closing delimiter if the last S-expression in | |
| 1156 ;; this list is on the line. | |
| 1157 (catch 'return | |
| 1158 (while t | |
| 1159 ;; This and the `kill-whole-line' business below fix a bug that | |
| 1160 ;; inhibited any S-expression at the very end of the buffer | |
| 1161 ;; (with no trailing newline) from being deleted. It's a | |
| 1162 ;; bizarre fix that I ought to document at some point, but I am | |
| 1163 ;; too busy at the moment to do so. | |
| 1164 (if (and kill-whole-line (eobp)) (throw 'return nil)) | |
| 1165 (save-excursion | |
| 1166 (paredit-handle-sexp-errors (forward-sexp) | |
| 1167 (up-list) | |
| 1168 (setq end-of-list-p (eq (point-at-eol) eol)) | |
| 1169 (throw 'return nil)) | |
| 1170 (if (or (and (not firstp) | |
| 1171 (not kill-whole-line) | |
| 1172 (eobp)) | |
| 1173 (paredit-handle-sexp-errors | |
| 1174 (progn (backward-sexp) nil) | |
| 1175 t) | |
| 1176 (not (eq (point-at-eol) eol))) | |
| 1177 (throw 'return nil))) | |
| 1178 (forward-sexp) | |
| 1179 (if (and firstp | |
| 1180 (not kill-whole-line) | |
| 1181 (eobp)) | |
| 1182 (throw 'return nil)) | |
| 1183 (setq firstp nil))) | |
| 1184 end-of-list-p)) | |
| 1185 | |
| 1186 (defun paredit-kill-sexps-on-whole-line (beginning) | |
| 1187 (kill-region beginning | |
| 1188 (or (save-excursion ; Delete trailing indentation... | |
| 1189 (paredit-skip-whitespace t) | |
| 1190 (and (not (eq (char-after) ?\; )) | |
| 1191 (point))) | |
| 1192 ;; ...or just use the point past the newline, if | |
| 1193 ;; we encounter a comment. | |
| 1194 (point-at-eol))) | |
| 1195 (cond ((save-excursion (paredit-skip-whitespace nil (point-at-bol)) | |
| 1196 (bolp)) | |
| 1197 ;; Nothing but indentation before the point, so indent it. | |
| 1198 (lisp-indent-line)) | |
| 1199 ((eobp) nil) ; Protect the CHAR-SYNTAX below against NIL. | |
| 1200 ;; Insert a space to avoid invalid joining if necessary. | |
| 1201 ((let ((syn-before (char-syntax (char-before))) | |
| 1202 (syn-after (char-syntax (char-after)))) | |
| 1203 (or (and (eq syn-before ?\) ) ; Separate opposing | |
| 1204 (eq syn-after ?\( )) ; parentheses, | |
| 1205 (and (eq syn-before ?\" ) ; string delimiter | |
| 1206 (eq syn-after ?\" )) ; pairs, | |
| 1207 (and (memq syn-before '(?_ ?w)) ; or word or symbol | |
| 1208 (memq syn-after '(?_ ?w))))) ; constituents. | |
| 1209 (insert " ")))) | |
| 1210 | |
| 1211 ;;;;; Killing Words | |
| 1212 | |
| 1213 ;;; This is tricky and asymmetrical because backward parsing is | |
| 1214 ;;; extraordinarily difficult or impossible, so we have to implement | |
| 1215 ;;; killing in both directions by parsing forward. | |
| 1216 | |
| 1217 (defun paredit-forward-kill-word () | |
| 1218 "Kill a word forward, skipping over intervening delimiters." | |
| 1219 (interactive) | |
| 1220 (let ((beginning (point))) | |
| 1221 (skip-syntax-forward " -") | |
| 1222 (let* ((parse-state (paredit-current-parse-state)) | |
| 1223 (state (paredit-kill-word-state parse-state 'char-after))) | |
| 1224 (while (not (or (eobp) | |
| 1225 (eq ?w (char-syntax (char-after))))) | |
| 1226 (setq parse-state | |
| 1227 (progn (forward-char 1) (paredit-current-parse-state)) | |
| 1228 ;; (parse-partial-sexp (point) (1+ (point)) | |
| 1229 ;; nil nil parse-state) | |
| 1230 ) | |
| 1231 (let* ((old-state state) | |
| 1232 (new-state | |
| 1233 (paredit-kill-word-state parse-state 'char-after))) | |
| 1234 (cond ((not (eq old-state new-state)) | |
| 1235 (setq parse-state | |
| 1236 (paredit-kill-word-hack old-state | |
| 1237 new-state | |
| 1238 parse-state)) | |
| 1239 (setq state | |
| 1240 (paredit-kill-word-state parse-state | |
| 1241 'char-after)) | |
| 1242 (setq beginning (point))))))) | |
| 1243 (goto-char beginning) | |
| 1244 (kill-word 1))) | |
| 1245 | |
| 1246 (defun paredit-backward-kill-word () | |
| 1247 "Kill a word backward, skipping over any intervening delimiters." | |
| 1248 (interactive) | |
| 1249 (if (not (or (bobp) | |
| 1250 (eq (char-syntax (char-before)) ?w))) | |
| 1251 (let ((end (point))) | |
| 1252 (backward-word 1) | |
| 1253 (forward-word 1) | |
| 1254 (goto-char (min end (point))) | |
| 1255 (let* ((parse-state (paredit-current-parse-state)) | |
| 1256 (state | |
| 1257 (paredit-kill-word-state parse-state 'char-before))) | |
| 1258 (while (and (< (point) end) | |
| 1259 (progn | |
| 1260 (setq parse-state | |
| 1261 (parse-partial-sexp (point) (1+ (point)) | |
| 1262 nil nil parse-state)) | |
| 1263 (or (eq state | |
| 1264 (paredit-kill-word-state parse-state | |
| 1265 'char-before)) | |
| 1266 (progn (backward-char 1) nil))))) | |
| 1267 (if (and (eq state 'comment) | |
| 1268 (eq ?\# (char-after (point))) | |
| 1269 (eq ?\| (char-before (point)))) | |
| 1270 (backward-char 1))))) | |
| 1271 (backward-kill-word 1)) | |
| 1272 | |
| 1273 ;;; Word-Killing Auxiliaries | |
| 1274 | |
| 1275 (defun paredit-kill-word-state (parse-state adjacent-char-fn) | |
| 1276 (cond ((paredit-in-comment-p parse-state) 'comment) | |
| 1277 ((paredit-in-string-p parse-state) 'string) | |
| 1278 ((memq (char-syntax (funcall adjacent-char-fn)) | |
| 1279 '(?\( ?\) )) | |
| 1280 'delimiter) | |
| 1281 (t 'other))) | |
| 1282 | |
| 1283 ;;; This optionally advances the point past any comment delimiters that | |
| 1284 ;;; should probably not be touched, based on the last state change and | |
| 1285 ;;; the characters around the point. It returns a new parse state, | |
| 1286 ;;; starting from the PARSE-STATE parameter. | |
| 1287 | |
| 1288 (defun paredit-kill-word-hack (old-state new-state parse-state) | |
| 1289 (cond ((and (not (eq old-state 'comment)) | |
| 1290 (not (eq new-state 'comment)) | |
| 1291 (not (paredit-in-string-escape-p)) | |
| 1292 (eq ?\# (char-before)) | |
| 1293 (eq ?\| (char-after))) | |
| 1294 (forward-char 1) | |
| 1295 (paredit-current-parse-state) | |
| 1296 ;; (parse-partial-sexp (point) (1+ (point)) | |
| 1297 ;; nil nil parse-state) | |
| 1298 ) | |
| 1299 ((and (not (eq old-state 'comment)) | |
| 1300 (eq new-state 'comment) | |
| 1301 (eq ?\; (char-before))) | |
| 1302 (skip-chars-forward ";") | |
| 1303 (paredit-current-parse-state) | |
| 1304 ;; (parse-partial-sexp (point) (save-excursion | |
| 1305 ;; (skip-chars-forward ";")) | |
| 1306 ;; nil nil parse-state) | |
| 1307 ) | |
| 1308 (t parse-state))) | |
| 1309 | |
| 1310 ;;;; Cursor and Screen Movement | |
| 1311 | |
| 1312 (eval-and-compile | |
| 1313 (defmacro defun-saving-mark (name bvl doc &rest body) | |
| 1314 `(defun ,name ,bvl | |
| 1315 ,doc | |
| 1316 ,(xcond ((paredit-xemacs-p) | |
| 1317 '(interactive "_")) | |
| 1318 ((paredit-gnu-emacs-p) | |
| 1319 '(interactive))) | |
| 1320 ,@body))) | |
| 1321 | |
| 1322 (defun-saving-mark paredit-forward () | |
| 1323 "Move forward an S-expression, or up an S-expression forward. | |
| 1324 If there are no more S-expressions in this one before the closing | |
| 1325 delimiter, move past that closing delimiter; otherwise, move forward | |
| 1326 past the S-expression following the point." | |
| 1327 (paredit-handle-sexp-errors | |
| 1328 (forward-sexp) | |
| 1329 ;++ Is it necessary to use UP-LIST and not just FORWARD-CHAR? | |
| 1330 (if (paredit-in-string-p) (forward-char) (up-list)))) | |
| 1331 | |
| 1332 (defun-saving-mark paredit-backward () | |
| 1333 "Move backward an S-expression, or up an S-expression backward. | |
| 1334 If there are no more S-expressions in this one before the opening | |
| 1335 delimiter, move past that opening delimiter backward; otherwise, move | |
| 1336 move backward past the S-expression preceding the point." | |
| 1337 (paredit-handle-sexp-errors | |
| 1338 (backward-sexp) | |
| 1339 (if (paredit-in-string-p) (backward-char) (backward-up-list)))) | |
| 1340 | |
| 1341 ;;; Why is this not in lisp.el? | |
| 1342 | |
| 1343 (defun backward-down-list (&optional arg) | |
| 1344 "Move backward and descend into one level of parentheses. | |
| 1345 With ARG, do this that many times. | |
| 1346 A negative argument means move forward but still descend a level." | |
| 1347 (interactive "p") | |
| 1348 (down-list (- (or arg 1)))) | |
| 1349 | |
| 1350 ;;; Thanks to Marco Baringer for suggesting & writing this function. | |
| 1351 | |
| 1352 (defun paredit-recentre-on-sexp (&optional n) | |
| 1353 "Recentre the screen on the S-expression following the point. | |
| 1354 With a prefix argument N, encompass all N S-expressions forward." | |
| 1355 (interactive "P") | |
| 1356 (save-excursion | |
| 1357 (forward-sexp n) | |
| 1358 (let ((end-point (point))) | |
| 1359 (backward-sexp n) | |
| 1360 (let* ((start-point (point)) | |
| 1361 (start-line (count-lines (point-min) (point))) | |
| 1362 (lines-on-sexps (count-lines start-point end-point))) | |
| 1363 (goto-line (+ start-line (/ lines-on-sexps 2))) | |
| 1364 (recenter))))) | |
| 1365 | |
| 1366 ;;;; Depth-Changing Commands: Wrapping, Splicing, & Raising | |
| 1367 | |
| 1368 (defun paredit-wrap-sexp (&optional n open close) | |
| 1369 "Wrap the following S-expression in a list. | |
| 1370 If a prefix argument N is given, wrap N S-expressions. | |
| 1371 Automatically indent the newly wrapped S-expression. | |
| 1372 As a special case, if the point is at the end of a list, simply insert | |
| 1373 a pair of parentheses, rather than insert a lone opening parenthesis | |
| 1374 and then signal an error, in the interest of preserving structure." | |
| 1375 (interactive "P") | |
| 1376 (let ((open (or open ?\()) | |
| 1377 (close (or close ?\)))) | |
| 1378 (paredit-handle-sexp-errors | |
| 1379 (paredit-insert-pair (or n | |
| 1380 (and (not (paredit-region-active-p)) | |
| 1381 1)) | |
| 1382 open close | |
| 1383 'goto-char) | |
| 1384 (insert close) | |
| 1385 (backward-char)) | |
| 1386 (save-excursion (backward-up-list) (indent-sexp)))) | |
| 1387 | |
| 1388 ;;; Thanks to Marco Baringer for the suggestion of a prefix argument | |
| 1389 ;;; for PAREDIT-SPLICE-SEXP. (I, Taylor R. Campbell, however, still | |
| 1390 ;;; implemented it, in case any of you lawyer-folk get confused by the | |
| 1391 ;;; remark in the top of the file about explicitly noting code written | |
| 1392 ;;; by other people.) | |
| 1393 | |
| 1394 (defun paredit-splice-sexp (&optional arg) | |
| 1395 "Splice the list that the point is on by removing its delimiters. | |
| 1396 With a prefix argument as in `C-u', kill all S-expressions backward in | |
| 1397 the current list before splicing all S-expressions forward into the | |
| 1398 enclosing list. | |
| 1399 With two prefix arguments as in `C-u C-u', kill all S-expressions | |
| 1400 forward in the current list before splicing all S-expressions | |
| 1401 backward into the enclosing list. | |
| 1402 With a numerical prefix argument N, kill N S-expressions backward in | |
| 1403 the current list before splicing the remaining S-expressions into the | |
| 1404 enclosing list. If N is negative, kill forward. | |
| 1405 This always creates a new entry on the kill ring." | |
| 1406 (interactive "P") | |
| 1407 (save-excursion | |
| 1408 (paredit-kill-surrounding-sexps-for-splice arg) | |
| 1409 (backward-up-list) ; Go up to the beginning... | |
| 1410 (save-excursion | |
| 1411 (forward-sexp) ; Go forward an expression, to | |
| 1412 (backward-delete-char 1)) ; delete the end delimiter. | |
| 1413 (delete-char 1) ; ...to delete the open char. | |
| 1414 (paredit-ignore-sexp-errors | |
| 1415 (backward-up-list) ; Reindent, now that the | |
| 1416 (indent-sexp)))) ; structure has changed. | |
| 1417 | |
| 1418 (defun paredit-kill-surrounding-sexps-for-splice (arg) | |
| 1419 (cond ((paredit-in-string-p) (error "Splicing illegal in strings.")) | |
| 1420 ((or (not arg) (eq arg 0)) nil) | |
| 1421 ((or (numberp arg) (eq arg '-)) | |
| 1422 ;; Kill ARG S-expressions before/after the point by saving | |
| 1423 ;; the point, moving across them, and killing the region. | |
| 1424 (let* ((arg (if (eq arg '-) -1 arg)) | |
| 1425 (saved (paredit-point-at-sexp-boundary (- arg)))) | |
| 1426 (paredit-ignore-sexp-errors (backward-sexp arg)) | |
| 1427 (kill-region-new saved (point)))) | |
| 1428 ((consp arg) | |
| 1429 (let ((v (car arg))) | |
| 1430 (if (= v 4) ; one prefix argument | |
| 1431 ;; Move backward until we hit the open paren; then | |
| 1432 ;; kill that selected region. | |
| 1433 (let ((end (paredit-point-at-sexp-start))) | |
| 1434 (paredit-ignore-sexp-errors | |
| 1435 (while (not (bobp)) | |
| 1436 (backward-sexp))) | |
| 1437 (kill-region-new (point) end)) | |
| 1438 ;; Move forward until we hit the close paren; then | |
| 1439 ;; kill that selected region. | |
| 1440 (let ((beginning (paredit-point-at-sexp-end))) | |
| 1441 (paredit-ignore-sexp-errors | |
| 1442 (while (not (eobp)) | |
| 1443 (forward-sexp))) | |
| 1444 (kill-region-new beginning (point)))))) | |
| 1445 (t (error "Bizarre prefix argument: %s" arg)))) | |
| 1446 | |
| 1447 (defun paredit-splice-sexp-killing-backward (&optional n) | |
| 1448 "Splice the list the point is on by removing its delimiters, and | |
| 1449 also kill all S-expressions before the point in the current list. | |
| 1450 With a prefix argument N, kill only the preceding N S-expressions." | |
| 1451 (interactive "P") | |
| 1452 (paredit-splice-sexp (if n | |
| 1453 (prefix-numeric-value n) | |
| 1454 '(4)))) | |
| 1455 | |
| 1456 (defun paredit-splice-sexp-killing-forward (&optional n) | |
| 1457 "Splice the list the point is on by removing its delimiters, and | |
| 1458 also kill all S-expressions after the point in the current list. | |
| 1459 With a prefix argument N, kill only the following N S-expressions." | |
| 1460 (interactive "P") | |
| 1461 (paredit-splice-sexp (if n | |
| 1462 (- (prefix-numeric-value n)) | |
| 1463 '(16)))) | |
| 1464 | |
| 1465 (defun paredit-raise-sexp (&optional n) | |
| 1466 "Raise the following S-expression in a tree, deleting its siblings. | |
| 1467 With a prefix argument N, raise the following N S-expressions. If N | |
| 1468 is negative, raise the preceding N S-expressions." | |
| 1469 (interactive "p") | |
| 1470 ;; Select the S-expressions we want to raise in a buffer substring. | |
| 1471 (let* ((bound (save-excursion (forward-sexp n) (point))) | |
| 1472 (sexps (save-excursion ;++ Is this necessary? | |
| 1473 (if (and n (< n 0)) | |
| 1474 (buffer-substring bound | |
| 1475 (paredit-point-at-sexp-end)) | |
| 1476 (buffer-substring (paredit-point-at-sexp-start) | |
| 1477 bound))))) | |
| 1478 ;; Move up to the list we're raising those S-expressions out of and | |
| 1479 ;; delete it. | |
| 1480 (backward-up-list) | |
| 1481 (delete-region (point) (save-excursion (forward-sexp) (point))) | |
| 1482 (save-excursion (insert sexps)) ; Insert & reindent the sexps. | |
| 1483 (save-excursion (let ((n (abs (or n 1)))) | |
| 1484 (while (> n 0) | |
| 1485 (paredit-forward-and-indent) | |
| 1486 (setq n (1- n))))))) | |
| 1487 | |
| 1488 ;;;; Slurpage & Barfage | |
| 1489 | |
| 1490 (defun paredit-forward-slurp-sexp () | |
| 1491 "Add the S-expression following the current list into that list | |
| 1492 by moving the closing delimiter. | |
| 1493 Automatically reindent the newly slurped S-expression with respect to | |
| 1494 its new enclosing form. | |
| 1495 If in a string, move the opening double-quote forward by one | |
| 1496 S-expression and escape any intervening characters as necessary, | |
| 1497 without altering any indentation or formatting." | |
| 1498 (interactive) | |
| 1499 (save-excursion | |
| 1500 (cond ((or (paredit-in-comment-p) | |
| 1501 (paredit-in-char-p)) | |
| 1502 (error "Invalid context for slurpage")) | |
| 1503 ((paredit-in-string-p) | |
| 1504 (paredit-forward-slurp-into-string)) | |
| 1505 (t | |
| 1506 (paredit-forward-slurp-into-list))))) | |
| 1507 | |
| 1508 (defun paredit-forward-slurp-into-list () | |
| 1509 (up-list) ; Up to the end of the list to | |
| 1510 (let ((close (char-before))) ; save and delete the closing | |
| 1511 (backward-delete-char 1) ; delimiter. | |
| 1512 (catch 'return ; Go to the end of the desired | |
| 1513 (while t ; S-expression, going up a | |
| 1514 (paredit-handle-sexp-errors ; list if it's not in this, | |
| 1515 (progn (paredit-forward-and-indent) | |
| 1516 (throw 'return nil)) | |
| 1517 (insert close) | |
| 1518 (up-list) | |
| 1519 (setq close (char-before)) | |
| 1520 (backward-delete-char 1)))) | |
| 1521 (insert close))) ; to insert that delimiter. | |
| 1522 | |
| 1523 (defun paredit-forward-slurp-into-string () | |
| 1524 (goto-char (1+ (cdr (paredit-string-start+end-points)))) | |
| 1525 ;; Signal any errors that we might get first, before mucking with the | |
| 1526 ;; buffer's contents. | |
| 1527 (save-excursion (forward-sexp)) | |
| 1528 (let ((close (char-before))) | |
| 1529 (backward-delete-char 1) | |
| 1530 (paredit-forward-for-quote (save-excursion (forward-sexp) (point))) | |
| 1531 (insert close))) | |
| 1532 | |
| 1533 (defun paredit-forward-barf-sexp () | |
| 1534 "Remove the last S-expression in the current list from that list | |
| 1535 by moving the closing delimiter. | |
| 1536 Automatically reindent the newly barfed S-expression with respect to | |
| 1537 its new enclosing form." | |
| 1538 (interactive) | |
| 1539 (save-excursion | |
| 1540 (up-list) ; Up to the end of the list to | |
| 1541 (let ((close (char-before))) ; save and delete the closing | |
| 1542 (backward-delete-char 1) ; delimiter. | |
| 1543 (paredit-ignore-sexp-errors ; Go back to where we want to | |
| 1544 (backward-sexp)) ; insert the delimiter. | |
| 1545 (paredit-skip-whitespace nil) ; Skip leading whitespace. | |
| 1546 (cond ((bobp) | |
| 1547 (error "Barfing all subexpressions with no open-paren?")) | |
| 1548 ((paredit-in-comment-p) ; Don't put the close-paren in | |
| 1549 (newline-and-indent))) ; a comment. | |
| 1550 (insert close)) | |
| 1551 ;; Reindent all of the newly barfed S-expressions. | |
| 1552 (paredit-forward-and-indent))) | |
| 1553 | |
| 1554 (defun paredit-backward-slurp-sexp () | |
| 1555 "Add the S-expression preceding the current list into that list | |
| 1556 by moving the closing delimiter. | |
| 1557 Automatically reindent the whole form into which new S-expression was | |
| 1558 slurped. | |
| 1559 If in a string, move the opening double-quote backward by one | |
| 1560 S-expression and escape any intervening characters as necessary, | |
| 1561 without altering any indentation or formatting." | |
| 1562 (interactive) | |
| 1563 (save-excursion | |
| 1564 (cond ((or (paredit-in-comment-p) | |
| 1565 (paredit-in-char-p)) | |
| 1566 (error "Invalid context for slurpage")) | |
| 1567 ((paredit-in-string-p) | |
| 1568 (paredit-backward-slurp-into-string)) | |
| 1569 (t | |
| 1570 (paredit-backward-slurp-into-list))))) | |
| 1571 | |
| 1572 (defun paredit-backward-slurp-into-list () | |
| 1573 (backward-up-list) | |
| 1574 (let ((open (char-after))) | |
| 1575 (delete-char 1) | |
| 1576 (catch 'return | |
| 1577 (while t | |
| 1578 (paredit-handle-sexp-errors | |
| 1579 (progn (backward-sexp) | |
| 1580 (throw 'return nil)) | |
| 1581 (insert open) | |
| 1582 (backward-char 1) | |
| 1583 (backward-up-list) | |
| 1584 (setq open (char-after)) | |
| 1585 (delete-char 1)))) | |
| 1586 (insert open)) | |
| 1587 ;; Reindent the line at the beginning of wherever we inserted the | |
| 1588 ;; opening parenthesis, and then indent the whole S-expression. | |
| 1589 (backward-up-list) | |
| 1590 (lisp-indent-line) | |
| 1591 (indent-sexp)) | |
| 1592 | |
| 1593 (defun paredit-backward-slurp-into-string () | |
| 1594 (goto-char (car (paredit-string-start+end-points))) | |
| 1595 ;; Signal any errors that we might get first, before mucking with the | |
| 1596 ;; buffer's contents. | |
| 1597 (save-excursion (backward-sexp)) | |
| 1598 (let ((open (char-after)) | |
| 1599 (target (point))) | |
| 1600 (message "open = %S" open) | |
| 1601 (delete-char 1) | |
| 1602 (backward-sexp) | |
| 1603 (insert open) | |
| 1604 (paredit-forward-for-quote target))) | |
| 1605 | |
| 1606 (defun paredit-backward-barf-sexp () | |
| 1607 "Remove the first S-expression in the current list from that list | |
| 1608 by moving the closing delimiter. | |
| 1609 Automatically reindent the barfed S-expression and the form from which | |
| 1610 it was barfed." | |
| 1611 (interactive) | |
| 1612 (save-excursion | |
| 1613 (backward-up-list) | |
| 1614 (let ((open (char-after))) | |
| 1615 (delete-char 1) | |
| 1616 (paredit-ignore-sexp-errors | |
| 1617 (paredit-forward-and-indent)) | |
| 1618 (while (progn (paredit-skip-whitespace t) | |
| 1619 (eq (char-after) ?\; )) | |
| 1620 (forward-line 1)) | |
| 1621 (if (eobp) | |
| 1622 (error | |
| 1623 "Barfing all subexpressions with no close-paren?")) | |
| 1624 ;** Don't use `insert' here. Consider, e.g., barfing from | |
| 1625 ;** (foo|) | |
| 1626 ;** and how `save-excursion' works. | |
| 1627 (insert-before-markers open)) | |
| 1628 (backward-up-list) | |
| 1629 (lisp-indent-line) | |
| 1630 (indent-sexp))) | |
| 1631 | |
| 1632 ;;;; Splitting & Joining | |
| 1633 | |
| 1634 (defun paredit-split-sexp () | |
| 1635 "Split the list or string the point is on into two." | |
| 1636 (interactive) | |
| 1637 (cond ((paredit-in-string-p) | |
| 1638 (insert "\"") | |
| 1639 (save-excursion (insert " \""))) | |
| 1640 ((or (paredit-in-comment-p) | |
| 1641 (paredit-in-char-p)) | |
| 1642 (error "Invalid context for `paredit-split-sexp'")) | |
| 1643 (t (let ((open (save-excursion (backward-up-list) | |
| 1644 (char-after))) | |
| 1645 (close (save-excursion (up-list) | |
| 1646 (char-before)))) | |
| 1647 (delete-horizontal-space) | |
| 1648 (insert close) | |
| 1649 (save-excursion (insert ?\ ) | |
| 1650 (insert open) | |
| 1651 (backward-char) | |
| 1652 (indent-sexp)))))) | |
| 1653 | |
| 1654 (defun paredit-join-sexps () | |
| 1655 "Join the S-expressions adjacent on either side of the point. | |
| 1656 Both must be lists, strings, or atoms; error if there is a mismatch." | |
| 1657 (interactive) | |
| 1658 ;++ How ought this to handle comments intervening symbols or strings? | |
| 1659 (save-excursion | |
| 1660 (if (or (paredit-in-comment-p) | |
| 1661 (paredit-in-string-p) | |
| 1662 (paredit-in-char-p)) | |
| 1663 (error "Invalid context in which to join S-expressions.") | |
| 1664 (let ((left-point (save-excursion (paredit-point-at-sexp-end))) | |
| 1665 (right-point (save-excursion | |
| 1666 (paredit-point-at-sexp-start)))) | |
| 1667 (let ((left-char (char-before left-point)) | |
| 1668 (right-char (char-after right-point))) | |
| 1669 (let ((left-syntax (char-syntax left-char)) | |
| 1670 (right-syntax (char-syntax right-char))) | |
| 1671 (cond ((>= left-point right-point) | |
| 1672 (error "Can't join a datum with itself.")) | |
| 1673 ((and (eq left-syntax ?\) ) | |
| 1674 (eq right-syntax ?\( ) | |
| 1675 (eq left-char (matching-paren right-char)) | |
| 1676 (eq right-char (matching-paren left-char))) | |
| 1677 ;; Leave intermediate formatting alone. | |
| 1678 (goto-char right-point) | |
| 1679 (delete-char 1) | |
| 1680 (goto-char left-point) | |
| 1681 (backward-delete-char 1) | |
| 1682 (backward-up-list) | |
| 1683 (indent-sexp)) | |
| 1684 ((and (eq left-syntax ?\" ) | |
| 1685 (eq right-syntax ?\" )) | |
| 1686 ;; Delete any intermediate formatting. | |
| 1687 (delete-region (1- left-point) | |
| 1688 (1+ right-point))) | |
| 1689 ((and (memq left-syntax '(?w ?_)) ; Word or symbol | |
| 1690 (memq right-syntax '(?w ?_))) | |
| 1691 (delete-region left-point right-point)) | |
| 1692 (t | |
| 1693 (error "Mismatched S-expressions to join."))))))))) | |
| 1694 | |
| 1695 ;;;; Utilities | |
| 1696 | |
| 1697 (defun paredit-in-string-escape-p () | |
| 1698 "True if the point is on a character escape of a string. | |
| 1699 This is true only if the character is preceded by an odd number of | |
| 1700 backslashes. | |
| 1701 This assumes that `paredit-in-string-p' has already returned true." | |
| 1702 (let ((oddp nil)) | |
| 1703 (save-excursion | |
| 1704 (while (eq (char-before) ?\\ ) | |
| 1705 (setq oddp (not oddp)) | |
| 1706 (backward-char))) | |
| 1707 oddp)) | |
| 1708 | |
| 1709 (defun paredit-in-char-p (&optional arg) | |
| 1710 "True if the point is immediately after a character literal. | |
| 1711 A preceding escape character, not preceded by another escape character, | |
| 1712 is considered a character literal prefix. (This works for elisp, | |
| 1713 Common Lisp, and Scheme.) | |
| 1714 Assumes that `paredit-in-string-p' is false, so that it need not handle | |
| 1715 long sequences of preceding backslashes in string escapes. (This | |
| 1716 assumes some other leading character token -- ? in elisp, # in Scheme | |
| 1717 and Common Lisp.)" | |
| 1718 (let ((arg (or arg (point)))) | |
| 1719 (and (eq (char-before arg) ?\\ ) | |
| 1720 (not (eq (char-before (1- arg)) ?\\ ))))) | |
| 1721 | |
| 1722 (defun paredit-forward-and-indent () | |
| 1723 "Move forward an S-expression, indenting it fully. | |
| 1724 Indent with `lisp-indent-line' and then `indent-sexp'." | |
| 1725 (forward-sexp) ; Go forward, and then find the | |
| 1726 (save-excursion ; beginning of this next | |
| 1727 (backward-sexp) ; S-expression. | |
| 1728 (lisp-indent-line) ; Indent its opening line, and | |
| 1729 (indent-sexp))) ; the rest of it. | |
| 1730 | |
| 1731 (defun paredit-skip-whitespace (trailing-p &optional limit) | |
| 1732 "Skip past any whitespace, or until the point LIMIT is reached. | |
| 1733 If TRAILING-P is nil, skip leading whitespace; otherwise, skip trailing | |
| 1734 whitespace." | |
| 1735 (funcall (if trailing-p 'skip-chars-forward 'skip-chars-backward) | |
| 1736 " \t\n" ; This should skip using the syntax table, but LF | |
| 1737 limit)) ; is a comment end, not newline, in Lisp mode. | |
| 1738 | |
| 1739 (defalias 'paredit-region-active-p | |
| 1740 (xcond ((paredit-xemacs-p) 'region-active-p) | |
| 1741 ((paredit-gnu-emacs-p) | |
| 1742 (lambda () | |
| 1743 (and mark-active transient-mark-mode))))) | |
| 1744 | |
| 1745 (defun kill-region-new (start end) | |
| 1746 "Kill the region between START and END. | |
| 1747 Do not append to any current kill, and | |
| 1748 do not let the next kill append to this one." | |
| 1749 (interactive "r") ;Eh, why not? | |
| 1750 ;; KILL-REGION sets THIS-COMMAND to tell the next kill that the last | |
| 1751 ;; command was a kill. It also checks LAST-COMMAND to see whether it | |
| 1752 ;; should append. If we bind these locally, any modifications to | |
| 1753 ;; THIS-COMMAND will be masked, and it will not see LAST-COMMAND to | |
| 1754 ;; indicate that it should append. | |
| 1755 (let ((this-command nil) | |
| 1756 (last-command nil)) | |
| 1757 (kill-region start end))) | |
| 1758 | |
| 1759 ;;;;; S-expression Parsing Utilities | |
| 1760 | |
| 1761 ;++ These routines redundantly traverse S-expressions a great deal. | |
| 1762 ;++ If performance issues arise, this whole section will probably have | |
| 1763 ;++ to be refactored to preserve the state longer, like paredit.scm | |
| 1764 ;++ does, rather than to traverse the definition N times for every key | |
| 1765 ;++ stroke as it presently does. | |
| 1766 | |
| 1767 (defun paredit-current-parse-state () | |
| 1768 "Return parse state of point from beginning of defun." | |
| 1769 (let ((point (point))) | |
| 1770 (beginning-of-defun) | |
| 1771 ;; Calling PARSE-PARTIAL-SEXP will advance the point to its second | |
| 1772 ;; argument (unless parsing stops due to an error, but we assume it | |
| 1773 ;; won't in paredit-mode). | |
| 1774 (parse-partial-sexp (point) point))) | |
| 1775 | |
| 1776 (defun paredit-in-string-p (&optional state) | |
| 1777 "True if the parse state is within a double-quote-delimited string. | |
| 1778 If no parse state is supplied, compute one from the beginning of the | |
| 1779 defun to the point." | |
| 1780 ;; 3. non-nil if inside a string (the terminator character, really) | |
| 1781 (and (nth 3 (or state (paredit-current-parse-state))) | |
| 1782 t)) | |
| 1783 | |
| 1784 (defun paredit-string-start+end-points (&optional state) | |
| 1785 "Return a cons of the points of open and close quotes of the string. | |
| 1786 The string is determined from the parse state STATE, or the parse state | |
| 1787 from the beginning of the defun to the point. | |
| 1788 This assumes that `paredit-in-string-p' has already returned true, i.e. | |
| 1789 that the point is already within a string." | |
| 1790 (save-excursion | |
| 1791 ;; 8. character address of start of comment or string; nil if not | |
| 1792 ;; in one | |
| 1793 (let ((start (nth 8 (or state (paredit-current-parse-state))))) | |
| 1794 (goto-char start) | |
| 1795 (forward-sexp 1) | |
| 1796 (cons start (1- (point)))))) | |
| 1797 | |
| 1798 (defun paredit-in-comment-p (&optional state) | |
| 1799 "True if parse state STATE is within a comment. | |
| 1800 If no parse state is supplied, compute one from the beginning of the | |
| 1801 defun to the point." | |
| 1802 ;; 4. nil if outside a comment, t if inside a non-nestable comment, | |
| 1803 ;; else an integer (the current comment nesting) | |
| 1804 (and (nth 4 (or state (paredit-current-parse-state))) | |
| 1805 t)) | |
| 1806 | |
| 1807 (defun paredit-point-at-sexp-boundary (n) | |
| 1808 (cond ((< n 0) (paredit-point-at-sexp-start)) | |
| 1809 ((= n 0) (point)) | |
| 1810 ((> n 0) (paredit-point-at-sexp-end)))) | |
| 1811 | |
| 1812 (defun paredit-point-at-sexp-start () | |
| 1813 (forward-sexp) | |
| 1814 (backward-sexp) | |
| 1815 (point)) | |
| 1816 | |
| 1817 (defun paredit-point-at-sexp-end () | |
| 1818 (backward-sexp) | |
| 1819 (forward-sexp) | |
| 1820 (point)) | |
| 1821 | |
| 1822 ;;;; Initialization | |
| 1823 | |
| 1824 (paredit-define-keys) | |
| 1825 (paredit-annotate-mode-with-examples) | |
| 1826 (paredit-annotate-functions-with-examples) | |
| 1827 | |
| 1828 (provide 'paredit) |
