From dcb8ae312805b85530c0a79a0e0a245879d07670 Mon Sep 17 00:00:00 2001 From: Eshel Yaron Date: Thu, 16 Jan 2025 21:07:27 +0100 Subject: [PATCH] New command 'elisp-extract-local-variable' --- lisp/progmodes/elisp-mode.el | 58 ++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/lisp/progmodes/elisp-mode.el b/lisp/progmodes/elisp-mode.el index 82c92593d2a..ad65e0700aa 100644 --- a/lisp/progmodes/elisp-mode.el +++ b/lisp/progmodes/elisp-mode.el @@ -58,6 +58,7 @@ All commands in `lisp-mode-shared-map' are inherited by this map." "C-c C-b" #'elisp-byte-compile-buffer "C-M-q" #'indent-pp-sexp "C-c M-e" #'macrostep-expand + "C-c C-l" #'elisp-extract-to-local-variable "C-c C-n" #'elisp-next-occurrence "C-c C-p" #'elisp-prev-occurrence) @@ -2366,6 +2367,63 @@ interactively, this is the prefix argument." "C-n" #'elisp-next-occurrence "C-p" #'elisp-prev-occurrence) +(defvar avy-action) + +(defvar elisp-extract-local-variable-name-history nil) + +(defun elisp-extract-to-local-variable (beg end target var) + "Extract BEG to END region to local VAR bound at TARGET." + (interactive + (let ((beg (region-beginning)) + (end (region-end)) + (max 0) + (targets nil)) + (save-excursion + (goto-char beg) + (beginning-of-defun-raw) + (scope (lambda (type sbeg len bin) + (and (<= sbeg beg) + (memq type '(function macro special-form top-level)) + (push (save-excursion (nth 1 (syntax-ppss sbeg))) targets)) + (let ((send (+ sbeg len))) + (and (<= beg sbeg send end) (numberp bin) (< bin beg) + (setq max (max max bin))))))) + (let* ((target + (if-let ((avy-action #'ignore) + (targets (seq-drop-while + (apply-partially #'> max) + (sort (seq-intersection + (nth 9 (syntax-ppss)) targets #'=))))) + (or (avy-process targets) (keyboard-quit)) + (user-error "No valid targets"))) + (tarend (save-excursion (goto-char target) (scan-sexps (point) 1))) + (ovbeg (make-overlay target (1+ target))) + (ovend (make-overlay tarend (1+ tarend)))) + (overlay-put ovbeg 'face 'show-paren-match) + (overlay-put ovend 'face 'show-paren-match) + (list beg end target + (unwind-protect + (read-string (format-prompt "Extract region to local var called" "v") + nil 'elisp-extract-local-variable-name-history "v") + (delete-overlay ovbeg) + (delete-overlay ovend))))) + emacs-lisp-mode) + (let ((reg (delete-and-extract-region beg end))) + (goto-char beg) + (insert var) + (let ((pos (copy-marker (point)))) + (goto-char target) + (pcase (save-excursion (read (current-buffer))) + (`(,(or 'let 'let* 'if-let* 'when-let* 'while-let*) . ,_) + (down-list 2) + (insert "(" var " " reg ")\n")) + (_ + (insert "(let ((" var " " reg "))\n") + (goto-char (scan-sexps (point) 1)) + (insert ")"))) + (prog-indent-sexp 'defun) + (goto-char pos)))) + (put 'read-symbol-shorthands 'safe-local-variable #'consp) -- 2.39.5