diff options
-rw-r--r-- | paredit.el | 135 |
1 files changed, 66 insertions, 69 deletions
@@ -1662,104 +1662,101 @@ With a numeric prefix argument N, do `kill-line' that many times." (t (point)))))))) -;;;; Safe Region Killing/Copying - -;;; This is an experiment. It's not enough: `paredit-kill-ring-save' -;;; is always safe; it's `yank' that's not safe, but even trickier to -;;; implement than `paredit-kill-region'. Also, the heuristics for -;;; `paredit-kill-region' are slightly too conservative -- they will -;;; sometimes reject killing regions that would be safe to kill. -;;; (Consider, e,g., a region that starts in a comment and ends in the -;;; middle of a symbol at the end of a line: that's safe to kill, but -;;; `paredit-kill-region' won't allow it.) I don't know whether they -;;; are too liberal: I haven't constructed a region that is unsafe to -;;; kill but which `paredit-kill-region' will kill, but I haven't ruled -;;; out the possibility either. - -(defun paredit-kill-ring-save (beginning end) - "Save the balanced region, but don't kill it, like `kill-ring-save'. -If the text of the region is unbalanced, signal an error instead. -With a prefix argument, disregard any imbalance." +;;;; Deleting Regions + +(defun paredit-delete-region (start end) + "Delete the text between point and mark, like `delete-region'. +If that text is unbalanced, signal an error instead. +With a prefix argument, skip the balance check." (interactive "r") - (if (not current-prefix-arg) - (paredit-check-region beginning end)) - (setq this-command 'kill-ring-save) - (kill-ring-save beginning end)) - -(defun paredit-kill-region (beginning end) - "Kill balanced text between point and mark, like `kill-region'. -If that text is unbalanced, signal an error instead." + (if (and start end (not current-prefix-arg)) + (paredit-check-region-for-delete start end)) + (setq this-command 'delete-region) + (delete-region start end)) + +(defun paredit-kill-region (start end) + "Kill the text between point and mark, like `kill-region'. +If that text is unbalanced, signal an error instead. +With a prefix argument, skip the balance check." (interactive "r") - (if (and beginning end) - ;; Check that region begins and ends in a sufficiently similar - ;; state, so that deleting it will leave the buffer balanced. - (save-excursion - (goto-char beginning) - (let* ((state (paredit-current-parse-state)) - (state* (parse-partial-sexp beginning end nil nil state))) - (paredit-check-region-state state state*)))) + (if (and start end (not current-prefix-arg)) + (paredit-check-region-for-delete start end)) (setq this-command 'kill-region) - (kill-region beginning end)) - -(defun paredit-check-region-state (beginning-state end-state) - "Signal an error if the two parse-partial-sexp states differ. -This guarantees that excising the text between the two states' - points from the buffer will leave the buffer balanced." - (paredit-check-region-state-depth beginning-state end-state) - (paredit-check-region-state-string beginning-state end-state) - (paredit-check-region-state-comment beginning-state end-state) - (paredit-check-region-state-char-quote beginning-state end-state)) - -(defun paredit-check-region-state-depth (beginning-state end-state) - (let ((beginning-depth (nth 0 beginning-state)) + (kill-region start end)) + +(defun paredit-check-region-for-delete (start end) + "Signal an error deleting text between `start' and `end' is unsafe." + (save-excursion + (goto-char start) + (let* ((start-state (paredit-current-parse-state)) + (end-state (parse-partial-sexp start end nil nil start-state))) + (paredit-check-region-for-delete:depth start start-state end end-state) + (paredit-check-region-for-delete:string start start-state end end-state) + (paredit-check-region-for-delete:comment start start-state end end-state) + (paredit-check-region-for-delete:char-quote start start-state + end end-state)))) + +(defun paredit-check-region-for-delete:depth (start start-state end end-state) + (let ((start-depth (nth 0 start-state)) (end-depth (nth 0 end-state))) - (if (not (= beginning-depth end-depth)) + (if (not (= start-depth end-depth)) (error "Mismatched parenthesis depth: %S at start, %S at end." - beginning-depth + start-depth end-depth)))) -(defun paredit-check-region-state-string (beginning-state end-state) - (let ((beginning-string-p (nth 3 beginning-state)) +(defun paredit-check-region-for-delete:string (start start-state end end-state) + (let ((start-string-p (nth 3 start-state)) (end-string-p (nth 3 end-state))) - (if (not (eq beginning-string-p end-string-p)) + (if (not (eq start-string-p end-string-p)) (error "Mismatched string state: start %sin string, end %sin string." - (if beginning-string-p "" "not ") + (if start-string-p "" "not ") (if end-string-p "" "not "))))) - -(defun paredit-check-region-state-comment (beginning-state end-state) - (let ((beginning-comment-state (nth 4 beginning-state)) + +(defun paredit-check-region-for-delete:comment + (start start-state end end-state) + (let ((start-comment-state (nth 4 start-state)) (end-comment-state (nth 4 end-state))) - (if (not (or (eq beginning-comment-state end-comment-state) - (and (eq beginning-comment-state nil) - (eq end-comment-state t) - (eolp)))) + (if (not (or (eq start-comment-state end-comment-state) + ;; If we are moving text into or out of a line + ;; comment, make sure that the text is balanced. (The + ;; comment state may be a number, not t or nil at all, + ;; for nestable comments, which are not handled by + ;; this heuristic (or any of paredit, really).) + (and (or (eq start-comment-state nil) + (eq end-comment-state t)) + (or (eq start-comment-state t) + (eq end-comment-state nil)) + (save-excursion + (goto-char end) + (paredit-region-ok-p (point) (point-at-eol)))))) (error "Mismatched comment state: %s" - (cond ((and (integerp beginning-comment-state) + (cond ((and (integerp start-comment-state) (integerp end-comment-state)) (format "depth %S at start, depth %S at end." - beginning-comment-state + start-comment-state end-comment-state)) - ((integerp beginning-comment-state) + ((integerp start-comment-state) "start in nested comment, end otherwise.") ((integerp end-comment-state) "end in nested comment, start otherwise.") - (beginning-comment-state + (start-comment-state "start in comment, end not in comment.") (end-comment-state "end in comment, start not in comment.") (t (format "start %S, end %S." - beginning-comment-state + start-comment-state end-comment-state))))))) -(defun paredit-check-region-state-char-quote (beginning-state end-state) - (let ((beginning-char-quote (nth 5 beginning-state)) +(defun paredit-check-region-for-delete:char-quote + (start start-state end end-state) + (let ((start-char-quote (nth 5 start-state)) (end-char-quote (nth 5 end-state))) - (if (not (eq beginning-char-quote end-char-quote)) + (if (not (eq start-char-quote end-char-quote)) (let ((phrase "character quotation")) (error "Mismatched %s: start %sin %s, end %sin %s." phrase - (if beginning-char-quote "" "not ") + (if start-char-quote "" "not ") phrase (if end-char-quote "" "not ") phrase))))) |