用 pcase 实现简单的代码重构

虽然有 el-search 这样强大的包,但如果目标明确,不想进行过多的交互操作。其实可以用 pcase 来完成一些重构的工作。

例如,只想把光标下的 (set (make-local-variable 'foo) 1) 替换成 (setq-local foo 1),并不需要进行全文搜索、替换和回答 Yes / No:

(defun pcase-refactor-at-point (from-pattern to-expr)
  "Refactor from FROM-PATTERN to TO-EXPR at point."
  (let* ((func `(lambda (sexp)
                  (pcase sexp
                    (,from-pattern ,to-expr))))
         (refc (funcall func (sexp-at-point))))
    (when refc
      (mark-sexp)
      (delete-region (region-beginning) (region-end))
      (insert (format "%S" refc)))))

(defun pcase-refactor-to-setq-local ()
  "Refactor from (set (make-local-variable 'sym) val) to (setq-local sym val)."
  (interactive)
  (pcase-refactor-at-point '`(set (make-local-variable ',sym) ,val)
                           '`(setq-local ,sym ,val)))

测试:

(with-temp-buffer
  (emacs-lisp-mode)
  (insert "(set (make-local-variable 'foo) 1)")
  (goto-char (point-min))
  
  (call-interactively 'pcase-refactor-to-setq-local)
  
  (buffer-string))
  ;; => "(setq-local foo 1)"

缺点:

  • 替换后的 form 会变成一行,原先的排版格式丢失。
  • 当定义了很多专门的 pcase-refactor-XXX 之后,每次按 M-x pcase-refactor 之后选择困难。 这个问题可参考 emacs-refactor,该包提供一个 emr-select-refactor 入口函数。每次只需调用这个入口函数,它会根据光标所处位置,过滤出适用于当前 form 的 refactor 函数,缩小选择范围。
4 个赞

el-search主要是缺乏快速输入pattern和实时高亮替换(类似anzu)的功能的问题

el-search 注释有介绍

Advanced usage: Replacement rules for semi-automatic code rewriting

还举了个 mapc → dolist 的例子。不过做复杂代码分析来优化代码,比较有希望的是 Elsa 。

1 个赞