From: Eshel Yaron <me@eshelyaron.com>
Date: Sun, 23 Feb 2025 08:03:51 +0000 (+0100)
Subject: Few new elisp-mode commands
X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=c2a199b0de8d6b6cd56ceab00ec6cf607c713a24;p=emacs.git

Few new elisp-mode commands
---

diff --git a/lisp/emacs-lisp/bytecomp.el b/lisp/emacs-lisp/bytecomp.el
index efd9f1f604f..3484374be3f 100644
--- a/lisp/emacs-lisp/bytecomp.el
+++ b/lisp/emacs-lisp/bytecomp.el
@@ -3855,21 +3855,25 @@ VAR must not be lexically bound.
 ARG is a position argument, used by `byte-compile-warn-x'.
 If optional argument ASSIGNMENT is non-nil, this is treated as an
 assignment (i.e. `setq')."
-  (unless (or (not (byte-compile-warning-enabled-p 'free-vars var))
-              (boundp var)
-              (memq var byte-compile-bound-variables)
-              (memq var (if assignment
-                            byte-compile-free-assignments
-                          byte-compile-free-references)))
-    (let* ((varname (prin1-to-string var))
-           (desc (if assignment "assignment" "reference"))
-           (suggestions (help-uni-confusable-suggestions varname)))
-      (byte-compile-warn-x arg "%s to free variable `%s'%s"
-                           desc var
-                           (if suggestions (concat "\n  " suggestions) "")))
-    (push var (if assignment
-                  byte-compile-free-assignments
-                byte-compile-free-references))))
+  (if (eq var '{})
+      (byte-compile-warn-with-fix
+       '("Delete" elisp-delete-hole)
+       arg "hole")
+    (unless (or (not (byte-compile-warning-enabled-p 'free-vars var))
+                (boundp var)
+                (memq var byte-compile-bound-variables)
+                (memq var (if assignment
+                              byte-compile-free-assignments
+                            byte-compile-free-references)))
+      (let* ((varname (prin1-to-string var))
+             (desc (if assignment "assignment" "reference"))
+             (suggestions (help-uni-confusable-suggestions varname)))
+        (byte-compile-warn-x arg "%s to free variable `%s'%s"
+                             desc var
+                             (if suggestions (concat "\n  " suggestions) "")))
+      (push var (if assignment
+                    byte-compile-free-assignments
+                  byte-compile-free-references)))))
 
 (defun byte-compile-variable-ref (var)
   "Generate code to push the value of the variable VAR on the stack."
diff --git a/lisp/emacs-lisp/lisp-mode.el b/lisp/emacs-lisp/lisp-mode.el
index 3663556d76e..8692402c4fc 100644
--- a/lisp/emacs-lisp/lisp-mode.el
+++ b/lisp/emacs-lisp/lisp-mode.el
@@ -768,17 +768,145 @@ font-lock keywords will not be case sensitive."
 	(buffer-substring-no-properties (point)
 					(progn (forward-sexp 1)
 					       (point)))))))
+(defun lisp-open (arg)
+  (interactive "P")
+  (let ((ppss (syntax-ppss)))
+    (if (or (nth 8 ppss) (nth 5 ppss))
+        (self-insert-command (prefix-numeric-value arg))
+      (insert-pair arg))))
+
+(defun lisp-delete-backward-1 ()
+  (delete-char -1)
+  (when (nth 5 (syntax-ppss))
+    (delete-char -1)
+    (when (and (eq ?? (char-before)) (not (nth 4 (syntax-ppss))))
+      ;; Also delete preceding `?'.
+      (delete-char -1))))
+
+(defun lisp-delete-backward (n)
+  "Delete or move over previous N characters."
+  (interactive "p")
+  (if (minusp n) (lisp-delete-forward (- n))
+    (dotimes (_ n)
+      (when (bobp) (signal 'beginning-of-buffer nil))
+      (cl-case (char-syntax (char-before))
+        ((?\s ?- ?w ?_ ?. ?' ?<) (lisp-delete-backward-1))
+        (?\(
+         (if (not (nth 8 (syntax-ppss)))
+             (if (save-excursion (nth 5 (syntax-ppss (1- (point)))))
+                 (lisp-delete-backward-1)
+               (if (eq (char-after) (matching-paren (char-before)))
+                   (delete-region (1- (point)) (1+ (point)))
+                 (user-error "Beginning of list")))
+           (delete-char -1)
+           (when (nth 5 (syntax-ppss)) (delete-char -1))))
+        (?\) (backward-char))
+        (?\"
+         (if (nth 3 (syntax-ppss))
+             ;; In a string.
+             (if (eq (point) (1+ (nth 8 (syntax-ppss))))
+                 ;; Previous character is the opening quote.
+                 (if (eq (char-after) ?\")
+                     ;; Next character is the closing quote.  Delete both.
+                     (delete-region (1- (point)) (1+ (point)))
+                   ;; Complain and refuse.
+                   (user-error "Beginning of string"))
+               ;; Previous character is escaped.
+               (delete-char -2))
+           ;; Not in a string.
+           (lisp-delete-backward-1)))
+        (?\\
+         (if (nth 5 (syntax-ppss))
+             (delete-region (1- (point)) (1+ (point)))
+           (if (nth 8 (syntax-ppss))
+               (delete-char -2)
+             (lisp-delete-backward-1))))
+        (?>
+         (if (nth 4 (save-excursion (syntax-ppss (1- (point)))))
+             (backward-char)
+           (delete-char -1)))))))
+
+;; (defun lisp-delete-forward-1 ()
+;;   (delete-char 1)
+;;   (when (nth 5 (syntax-ppss))
+;;     (delete-char -1)
+;;     (when (and (eq ?? (char-before)) (not (nth 4 (syntax-ppss))))
+;;       ;; Also delete preceding `?'.
+;;       (delete-char -1))))
+
+;; (defun lisp-delete-forward (n)
+;;   "Delete or move over next N characters."
+;;   (interactive "p")
+;;   (if (minusp n) (lisp-delete-backward (- n))
+;;     (dotimes (_ n)
+;;       (when (eobp) (signal 'end-of-buffer nil))
+;;       (cl-case (char-syntax (char-after))
+;;         ((?\s ?- ?w ?_ ?. ?') (lisp-delete-forward-1))
+;;         (?\)
+;;          (if (eq (char-before) (matching-paren (char-after)))
+;;              (delete-region (1- (point)) (1+ (point)))
+;;            (user-error "End of list")))
+;;         (?\( (forward-char))
+;;         ;; (?\"
+;;         ;;  (if (nth 3 (syntax-ppss))
+;;         ;;      ;; In a string.
+;;         ;;      (if (eq (point) (1+ (nth 8 (syntax-ppss))))
+;;         ;;          ;; Empty string.  Delete it.
+;;         ;;          (delete-region (1- (point)) (1+ (point)))
+;;         ;;        (delete-char -2))
+;;         ;;    ;; Not in a string.
+;;         ;;    (lisp-delete-backward-1)))
+;;         ;; (?\\
+;;         ;;  (if (nth 5 (syntax-ppss))
+;;         ;;      (delete-region (1- (point)) (1+ (point)))
+;;         ;;    (lisp-delete-backward-1)))
+;;         ;; (?>
+;;         ;;  (if (nth 4 (save-excursion (syntax-ppss (1- (point)))))
+;;         ;;      (backward-char)
+;;         ;;    (delete-char -1)))
+;;         ;; (?< ...)
+;;         ))))
+
+(defun lisp-doublequote (&optional arg)
+  (interactive "P")
+  (cond
+   ((nth 3 (syntax-ppss))
+    (if (and (not (nth 5 (syntax-ppss))) (eq (char-after) ?\")) (forward-char)
+      (when (nth 5 (syntax-ppss)) (forward-char))
+      (insert "\\\"")))
+   ((nth 4 (syntax-ppss)) (insert "\""))
+   (t (insert-pair arg))))
+
+(defun lisp-escape ()
+  (interactive)
+  (when (and (nth 5 (syntax-ppss)) (not (eobp))) (forward-char))
+  (insert "\\" (read-char "Escape: ")))
+
+(defun lisp-character ()
+  (interactive)
+  (if (nth 8 (syntax-ppss))
+      (insert "?")
+    (let ((char (read-char "Character: ")))
+      (if (eq char ?\\)
+          (insert "?\\" (read-char "Character: "))
+        (insert "?" char)))))
 
 (defvar-keymap lisp-mode-shared-map
   :doc "Keymap for commands shared by all sorts of Lisp modes."
   :parent prog-mode-map
   "C-M-q" #'indent-sexp
-  "DEL"   #'backward-delete-char-untabify
-  ;; This gets in the way when viewing a Lisp file in view-mode.  As
-  ;; long as [backspace] is mapped into DEL via the
-  ;; function-key-map, this should remain disabled!!
-  ;;;"<backspace>" #'backward-delete-char-untabify
-  )
+  "DEL"   #'lisp-delete-backward
+  ;; "C-d"   #'lisp-delete-forward
+  ;; "C-k"   #'lisp-kill
+  ;; "M-d"   #'lisp-kill-word-forward
+  ;; "M-DEL" #'lisp-kill-word-backward
+  "?"     #'lisp-character
+  "("     #'lisp-open
+  "["     #'lisp-open
+  ;; "]"     #'lisp-close
+  ;; ")"     #'lisp-close
+  "\""   #'lisp-doublequote
+  "\\"   #'lisp-escape)
 
 (defcustom lisp-mode-hook nil
   "Hook run when entering Lisp mode."
diff --git a/lisp/progmodes/elisp-mode.el b/lisp/progmodes/elisp-mode.el
index 6a1e67b3cbe..65c3a416aa3 100644
--- a/lisp/progmodes/elisp-mode.el
+++ b/lisp/progmodes/elisp-mode.el
@@ -2573,6 +2573,11 @@ of TARGET."
     (prog-indent-sexp 'defun)
     (goto-char pos)))
 
+(defun elisp-delete-hole ()
+  "Delete hole (`{}') at point."
+  (let ((bounds (bounds-of-thing-at-point 'symbol)))
+    (delete-region (car bounds) (cdr bounds))))
+
 
 (put 'read-symbol-shorthands 'safe-local-variable #'consp)