C-x C-e (eval-last-sexp
) 支持
;; (+ 1 2 3)
却不支持
;; (+ 1
;; 2
;; 3)
之前遇到这种情况就只能取消注释、执行、加上注释,有点儿烦。刚刚想了个一步到位的办法:
(define-advice elisp--preceding-sexp (:around (old-fun) multiline-comment)
"Support sexp in multiline comment."
(condition-case err
(funcall old-fun)
(scan-error
(if (nth 4 (syntax-ppss))
(let ((work-buffer (current-buffer))
(temp-buffer (generate-new-buffer " *temp*"))
found sexp error)
(with-current-buffer temp-buffer
(delay-mode-hooks (emacs-lisp-mode)))
(save-excursion
(comment-normalize-vars)
(while (and (comment-beginning)
(not found))
(let ((code (buffer-substring-no-properties
(point) (line-end-position))))
(with-current-buffer temp-buffer
(goto-char (point-min))
(insert code ?\n)
(goto-char (point-max))
(condition-case err
(setq sexp (funcall old-fun)
found t)
(scan-error (setq error err)))))
(when (= -1 (forward-line -1))
(error "elisp--preceding-sexp@multiline-comment error"))
(goto-char (line-end-position))))
(cond (found sexp)
(error (signal (car error) (cdr error)))
(t (error "elisp--preceding-sexp@multiline-comment error"))))
(signal (car err) (cdr err))))))
5 个赞
刚才在做测试的时候想到这个帖子,现在可以用 separedit
来实现:
(defun separedit/eval-last-sexp-in-comment ()
(interactive)
(let ((separedit-default-mode 'emacs-lisp-mode))
(with-current-buffer (separedit)
(prog1 (call-interactively #'eval-last-sexp)
(execute-kbd-macro (kbd "C-c C-k"))))))
6 个赞
决定把这个函数纳入日常配置:
(keymap!
:mode emacs-lisp-mode
:prefix "C-x"
"C-e" (lambda ()
(interactive)
(call-interactively
(if (separedit--point-at-comment)
#'separedit/eval-last-sexp-in-comment
#'eval-last-sexp)))))
1 个赞
zqso
7
这个功能还挺有用的,我挖下坟
在 docstring 因为引号需要 escape, 单引号从 Emacs 29 起还需要 \='
,内含的 example 无法直接 eval,不知道 separedit 有无自动处理的方案?
比如这样:
(defun test ()
"testing DOC:
(global-set-key (kbd \"C-c y\") \\='company-yasnippet)"
#'ignore)
(defun separedit/eval-last-sexp-in-comment ()
(interactive)
(let ((separedit-default-mode 'emacs-lisp-mode)
(separedit-inhibit-edit-window-p t)
(strp (separedit--point-at-string)))
(with-current-buffer (separedit)
(when strp
(save-excursion
(while (re-search-backward "\\\\\\{2\\}='" nil t)
(unless (separedit--point-at-string)
(replace-match "'" nil t)))))
(unwind-protect (call-interactively #'eval-last-sexp)
(edit-indirect-abort)))))
"(apply \\='(1+ 1))"
;; => 2
"(prog1 \"\\='(1+ 1)\")"
;; => "\\='(1+ 1)"
1 个赞
zqso
9
感谢大佬。
合并一下:
;; SRC 2023-02-20: https://emacs-china.org/t/7760
(defun separedit/eval-last-sexp-in-comment ()
"`eval-last-sexp' in comment."
;; test:
;; (+ 1 2 3)
;; (+ 1
;; 2
;; 3)
(interactive)
(let ((separedit-default-mode 'emacs-lisp-mode)
(separedit-inhibit-edit-window-p t))
(with-current-buffer (separedit)
(unwind-protect (call-interactively #'eval-last-sexp)
(separedit-abort)))))
;; SRC 2023-02-20: https://emacs-china.org/t/7760/8
(defun separedit/eval-last-sexp-in-docstring ()
"`eval-last-sexp' in docstring.
test:
(apply \\='(1+ 1))
(prog1 \"\\='(1+ 1)\")"
(interactive)
(let ((separedit-default-mode 'emacs-lisp-mode)
(separedit-inhibit-edit-window-p t)
(strp (separedit--point-at-string)))
(with-current-buffer (separedit)
(when strp
(save-excursion
(while (re-search-backward "\\\\\\{2\\}='" nil t)
(unless (separedit--point-at-string)
(replace-match "'" nil t)))))
(unwind-protect (call-interactively #'eval-last-sexp)
(edit-indirect-abort)))))
(defun z/eval-last-sexp ()
"Make eval-last-sexp also work in comment and docstring."
(interactive)
(require 'separedit)
(call-interactively
(cond ((separedit--point-at-comment) #'separedit/eval-last-sexp-in-comment)
((separedit--point-at-string) #'separedit/eval-last-sexp-in-docstring)
(t #'eval-last-sexp))))
(define-key emacs-lisp-mode-map (kbd "C-x C-e") #'z/eval-last-sexp)