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 "&nbsp;&nbsp;&nbsp;&nbsp;---&gt;"
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 ?\<) "&lt;")
524 ((eq c ?\>) "&gt;")
525 ((eq c ?\&) "&amp;")
526 ((eq c ?\') "&apos;")
527 ((eq c ?\") "&quot;")
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)