emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[nongnu] elpa/paredit 8be6d99 001/224: Initial revision.


From: ELPA Syncer
Subject: [nongnu] elpa/paredit 8be6d99 001/224: Initial revision.
Date: Sat, 7 Aug 2021 09:22:05 -0400 (EDT)

branch: elpa/paredit
commit 8be6d99412d0d4a313c8ce3925a78bd8d6cdb3fa
Author: Taylor R Campbell <campbell@mumble.net>
Commit: Taylor R Campbell <campbell@mumble.net>

    Initial revision.
    
    darcs-hash:20080928131127-00fcc-7af7487ee9835f4f8a88b30a93ef8fe43a60e59c
---
 paredit.el | 348 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 348 insertions(+)

diff --git a/paredit.el b/paredit.el
new file mode 100644
index 0000000..abc29e9
--- /dev/null
+++ b/paredit.el
@@ -0,0 +1,348 @@
+;;; -*- mode: emacs-lisp -*-
+
+;;;;;; paredit: Parenthesis editing minor mode
+;;;;;; Version 1
+
+;;; Taylor Campbell wrote this code; he places it in the public domain.
+
+;;; Add this to your .emacs after adding paredit.el to /path/to/elisp/:
+;;;
+;;;   (add-to-list 'load-path "/path/to/elisp/")
+;;;   (require 'paredit)
+;;;   (add-hook '...-mode-hook (lambda () (paredit-mode 1)))
+;;;
+;;; Usually the ... will be lisp or scheme or both.
+
+;;; This assumes Unix-style LF line endings.
+
+(defconst paredit-version 1)
+
+(defvar paredit-mode-map
+  (let ((keymap (make-sparse-keymap)))
+    (define-key keymap "(" 'paredit-open-list)
+    (define-key keymap ")" 'paredit-close-list)
+    (define-key keymap "\"" 'paredit-doublequote)
+    (define-key keymap (kbd "M-\"") 'paredit-insert-doublequote)
+
+    (define-key keymap (kbd "RET") 'newline-and-indent)
+    (define-key keymap (kbd "DEL") 'paredit-backspace)
+    
+    (define-key keymap (kbd "C-k") 'paredit-kill)
+
+    ;; In case something broke and you really, really need to insert a
+    ;; literal parenthesis.  Don't use these often.
+    (define-key keymap (kbd "C-M-(")
+      (lambda () (interactive) (insert "(")))
+    (define-key keymap (kbd "C-M-)")
+      (lambda () (interactive) (insert ")")))
+
+    ;; C-up & C-down are by default useless paragraph commands, while
+    ;; C-M-up & C-M-down are BACKWARD-UP-LIST & BACKWARD-DOWN-LIST.
+    (define-key keymap (kbd "<C-up>") 'up-list)
+    (define-key keymap (kbd "<C-down>") 'down-list)
+
+    (define-key keymap (kbd "M-(") 'forward-wrap-sexp)
+    (define-key keymap (kbd "M-)") 'backward-wrap-sexp)
+    (define-key keymap (kbd "M-/") 'splice-sexp)
+    (define-key keymap (kbd "M-\\") 'join-sexps)
+
+    (define-key keymap (kbd "C-)") 'forward-slurp-sexp)
+    (define-key keymap (kbd "C-}") 'forward-barf-sexp)
+    (define-key keymap (kbd "C-(") 'backward-slurp-sexp)
+    (define-key keymap (kbd "C-{") 'backward-barf-sexp)
+    
+    keymap)
+  "Keymap for paredit minor mode.")
+
+(define-minor-mode paredit-mode
+  "Minor mode for pseudo-structurally editing Lisp code."
+  :lighter " Paredit")
+
+
+
+;;; ----------------
+;;; Basic editing commands
+
+(defun paredit-open-list ()
+  "Inserts a balanced parenthesis pair.
+If in string, comment, or character literal, inserts a single opening
+parenthesis."
+  (interactive)
+  (if (or (paredit-in-comment-p)
+          (paredit-in-string-p)
+          (eq (char-before) ?\\ ))
+      (insert "(")
+    (insert-parentheses 0)))
+
+(defun paredit-close-list ()
+  "Moves past one closing parenthesis and reindents.
+If in a string, comment, or character literal, inserts a single closing
+parenthesis."
+  (interactive)
+  (if (or (paredit-in-comment-p)
+          (paredit-in-string-p)
+          (eq (char-before) ?\\ ))
+      (insert ")")
+    (move-past-close-and-reindent)))
+
+(defun paredit-doublequote ()
+  "Inserts a pair of double-quotes.
+Inside a comment or character literal, inserts a literal double-quote.
+Inside a string, moves to the end of the string."
+  (interactive)
+  (cond ((or (paredit-in-comment-p)
+             (eq (char-before) ?\\ ))
+         ;; Special case for when we're on character literals, just to
+         ;; be convenient.
+         (insert "\""))
+        ((paredit-in-string-p)
+         (while (not (eq (char-after) ?\" ))
+           (forward-char)
+           (if (eq (char-after) ?\\ )   ; Skip escaped characters.
+               (forward-char)))
+         (forward-char))
+        (t (insert-pair 0 ?\" ?\"))))
+
+(defun paredit-insert-doublequote (&optional n)
+  "Inserts a single literal double-quote.
+Inside a string, inserts an escaped double-quote: \\\"
+Outside of a string, comment, or character literal, displays a message
+to the user and inserts a single literal double-quote nevertheless."
+  (interactive "p")
+  (let ((string
+         (cond ((or (paredit-in-comment-p)
+                    (eq (char-before) ?\\ ))
+                "\"")                   ; plain doublequote
+               ((paredit-in-string-p)
+                "\\\"")                 ; escaped doublequote
+               (t (message "Inserting naked doublequote%s..."
+                           (if (> n 1) "s" ""))
+                  "\""))))              ; plain doublequote
+    (while (< 0 n)
+      (insert string)
+      (setq n (1- n)))))
+
+(defun paredit-backspace ()
+  "Deletes a character backward or moves backward over a delimiter.
+If at the start of an empty string literal, deletes the whole string,
+including both delimiters.  If at the start of a non-empty string
+literal, moves back outside of the string literal.  If anywhere else in
+a string literal, deletes a single character.
+If on a closing parenthesis, moves backward one character.
+If on an opening parenthesis followed by a closing parenthesis, deletes
+both parentheses.
+If on any other opening parenthesis, does nothing.
+Anywhere else, deletes a character backward."
+  (interactive)
+  (cond ((paredit-in-comment-p)
+         (backward-delete-char 1))
+        ((paredit-in-string-p)
+         (if (and (eq (char-after) ?\" )
+                  (eq (char-before) ?\" )
+                  (not (eq (char-before (1- (point)))
+                           ?\\ )))
+             (progn (backward-char)
+                    (kill-sexp))
+           (backward-delete-char 1)))
+        ((and (or (eq (char-before) ?\) )
+                  (eq (char-before) ?\" ))
+              (not (eq (char-before (1- (point)))
+                       ?\\ )))
+         (backward-char))
+        ;++ This should test more thoroughly, e.g. for (   ).
+        ((and (eq (char-before) ?\( )
+              (eq (char-after)  ?\) ))
+         (backward-char)
+         (kill-sexp))
+        ;; Delete it, unless it's an opening parenthesis not preceded
+        ;; by a backslash (i.e. not a character literal).
+        ((or (not (eq (char-before) ?\( ))
+             (eq (char-before (1- (point)))
+                 ?\\ ))
+         (backward-delete-char-untabify 1))))
+
+(defun paredit-kill ()
+  "Kills a line or S-expression.
+If an S-expression starts on the same line as the point, kills that
+S-expression; otherwise, behaves as `kill-line'."
+  (interactive)
+  (cond ((or (eq (char-after) ?\n )
+             (paredit-in-comment-p)
+             (save-excursion
+               (skip-chars-forward " \t\n" (point-at-eol))
+               (or (eq (point) (point-at-eol))
+                   (eq (char-after) ?\; ))))
+         (kill-line))
+        ((paredit-in-string-p)
+         (if (eq (char-after) ?\n )
+             ;; Delete the newline only if we're at the end of the
+             ;; line.  (The ordinary Emacs behaviour is to do this also
+             ;; if there's only whitespace following, but I hate that
+             ;; behaviour.)
+             (delete-char)
+           (while (not (or (eq (char-after) ?\n )
+                           (eq (char-after) ?\" )))
+             (cond ((eq (char-after) ?\\ )
+                    (delete-char)
+                    ;; The one after the backslash is escaped, so eat
+                    ;; it (most importantly if it's a doublequote),
+                    ;; unless it's a newline.
+                    (if (not (eq (char-after (1+ point))
+                                 ?\n ))
+                        (delete-char)))
+                   (t (delete-char))))))
+        (t (kill-sexp))))
+
+
+
+;;; ----------------
+;;; Wrappage, splicage, & joinage
+
+(defun forward-wrap-sexp (&optional n)
+  "Wraps the following S-expression in a list.
+If a prefix argument N is given, N S-expressions are contained in the
+list."
+  (interactive "p")
+  (insert-parentheses (or n 1))
+  (save-excursion (beginning-of-defun)
+                  (indent-sexp)))
+
+(defun backward-wrap-sexp (&optional n)
+  "Wraps the preceding S-expression in a list.
+If a prefix argument N is given, N S-expressions are contained in the
+list."
+  (interactive "p")
+  (insert-parentheses (- (or n 1)))
+  (save-excursion (beginning-of-defun)
+                  (indent-sexp)))
+
+(defun splice-sexp ()
+  "Splices the list the point is on by removing its delimiters."
+  (interactive)
+  (save-excursion
+    (backward-up-list)                  ; Go up to the beginning...
+    (save-excursion
+      (forward-sexp)                    ; Go forward an expression, to
+      (backward-delete-char 1))         ;   delete the end delimiter.
+    (delete-char 1)                     ; ...to delete the open char.
+    (beginning-of-defun)                ; Reindent, now that the
+    (indent-sexp)))                     ;   structure has changed.
+
+(defun join-sexps ()
+  "Joins two adjacent S-expressions into one S-expression."
+  (interactive)
+  (save-excursion
+    (backward-sexp)                     ; Go to the end of the
+    (forward-sexp)                      ;   preceding expression.
+    (backward-delete-char 1)            ; Delete the closing delimiter.
+    (forward-sexp)                      ; Go to the start of the
+    (backward-sexp)                     ;   following expression.
+    (delete-char 1)                     ; Delete the opening delimiter.
+    (beginning-of-defun)                ; Reindent the whole defun, now
+    (indent-sexp)))                     ;   that its structure changed.
+
+
+
+;;; ----------------
+;;; Slurpage & barfage
+
+;;; This shouldn't be here.
+
+(defmacro ignore-errors (&rest body)
+  `(condition-case nil (progn ,@body)
+     (error nil)))
+
+(defun forward-slurp-sexp (&optional n)
+  "Adds the S-expression following the current list into that list by
+moving the closing delimiter.
+If a prefix argument N is given, N S-expressions are slurped into the
+current list."
+  (interactive "p")
+  (save-excursion
+    (up-list)                           ; Up to the end of the list to
+    (let ((close (char-before)))        ;   save and delete the closing
+      (backward-delete-char 1)          ;   delimiter.
+      (ignore-errors (forward-sexp n))  ; Go to the end of the last exp
+      (insert close))                   ;   to insert that delimiter.
+    (beginning-of-defun)                ; Reindent the form, now that
+    (indent-sexp)))                     ;   the structure has changed.
+
+(defun forward-barf-sexp (&optional n)
+  "Removes the last S-expression in the current list from that list by
+moving the closing delimiter.
+If a prefix argument N is given, the last N S-expressions are barfed
+out of the current list."
+  (interactive "p")
+  (save-excursion
+    (up-list)                           ; Up to the end of the list to
+    (let ((close (char-before)))        ;   save and delete the closing
+      (backward-delete-char 1)          ;   delimiter.
+      (ignore-errors (backward-sexp n)) ; Go back to where we want to
+      (skip-chars-backward " \t\n")     ;   insert the delimiter.
+      (if (eq (point) (point-min))
+          (error "Barfing all subexpressions with no open-paren?")
+        (insert close)))
+    (beginning-of-defun)                ; Reindent: structure has
+    (indent-sexp)))                     ;   changed.
+
+(defun backward-slurp-sexp (&optional n)
+  "Adds the S-expression preceding the current list into that list by
+moving the closing delimiter.
+If a prefix argument N is given, N S-expressions are slurped into the
+current list."
+  (interactive "p")
+  (save-excursion
+    (backward-up-list)
+    (let ((open (char-after)))
+      (delete-char 1)
+      (ignore-errors (backward-sexp n))
+      (insert open))
+    (beginning-of-defun)
+    (indent-sexp)))
+
+(defun backward-barf-sexp (&optional n)
+  "Removes the first S-expression in the current list from that list by
+moving the closing delimiter.
+If a prefix argument N is given, the first N S-expressions are barfed
+out of the current list."
+  (interactive "p")
+  (save-excursion
+    (backward-up-list)
+    (let ((open (char-after)))
+      (delete-char 1)
+      (ignore-errors (forward-sexp n))
+      (skip-chars-forward " \t\n")
+      (if (eq (point) (point-max))
+          (error "Barfing all subexpressions with no close-paren?")
+        (insert open)))
+    (beginning-of-defun)
+    (indent-sexp)))
+
+
+
+;;; ----------------
+;;; Two utility functions
+
+(defun paredit-in-comment-p ()
+  "True if the point is within a Lisp line comment."
+  ;++ Make this work on block comments?
+  (save-excursion
+    ;; The third T argument to SEARCH-BACKWARD says to return NIL,
+    ;; not to signal an error, if no match is found.
+    (and (search-backward ";" (point-at-bol) t)
+         (not (eq (char-before) ?\\ ))
+         t)))
+
+;;; Taken roughly from thingatpt.el.
+
+(defun paredit-in-string-p ()
+  "True if the point is within a double-quote-delimited string."
+  (let ((orig (point)))
+    (save-excursion
+      (beginning-of-defun)
+      (eq (nth 3 (parse-partial-sexp (point) orig))
+          ?\" ))))
+
+
+
+(provide 'paredit)



reply via email to

[Prev in Thread] Current Thread [Next in Thread]