From c2a199b0de8d6b6cd56ceab00ec6cf607c713a24 Mon Sep 17 00:00:00 2001 From: Eshel Yaron Date: Sun, 23 Feb 2025 09:03:51 +0100 Subject: [PATCH] Few new elisp-mode commands --- lisp/emacs-lisp/bytecomp.el | 34 +++++---- lisp/emacs-lisp/lisp-mode.el | 140 +++++++++++++++++++++++++++++++++-- lisp/progmodes/elisp-mode.el | 5 ++ 3 files changed, 158 insertions(+), 21 deletions(-) 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!! - ;;;"" #'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) -- 2.39.5