在Emacs中重构

时间:2011-12-22 06:18:04

标签: emacs refactoring

我正在努力将代码拆分成更小的文件并重构一下。请将以下代码视为我要提取的部分:

(require 'package)
(add-to-list 'package-archives
             '("marmalade" . "http://marmalade-repo.org/packages/") t)
(package-initialize)
(when (not package-archive-contents)
  (package-refresh-contents))

(defvar my-packages '(org magit)
  "A list of packages to ensure are installed at launch.")

(dolist (p my-packages)
  (when (not (package-installed-p p))
    (package-install p)))
  • 我想采用上面的部分并将其替换为(require `file-name)
  • 之类的内容
  • 然后替换文本并将其放在名为file-name.el
  • 的当前目录的新文件中
  • 然后在文件(provides `file-name)
  • 的顶部添加一行

如果我可以点击一个键盘然后输入一个名字就可以了。如果有一种简单的方法可以做到这一点,那么我很乐意听到可能的解决方案。

修改 我开始获得赏金,因为我认为这适用于比Lisp更多类型的代码,我希望有一些更普遍的东西,我可以扩展。

我考虑过yasnippet,但我认为它不足以执行手头的任务。基本上理想的工作流程是标记要提取的行,用适当的require或include指令替换它,并将文本发送到它自己的文件。理想情况下,一个命令和一些知道正在编辑的文件类型或至少是主要模式以便行为可以自定义的东西,yasnippet再次擅长在不同主要模式下编辑时执行不同的任务但是我不知道如何使这项工作或评估使其发挥作用的可能性。

如果您需要更多信息,请与我们联系。

4 个答案:

答案 0 :(得分:10)

此类问题的一般解决方案是keyboard macros(不要与(Emacs)LISP宏混淆)。基本上,Emacs允许您记录一系列击键并在之后“回放”。在编写自定义LISP代码似乎过度的情况下,这可能是一个非常方便的工具。

例如,您可以创建以下键盘宏(在左侧键入组合键,右侧显示每个键击的说明):

C-x (                            ; start recording a keyboard macro
C-x h                            ; mark whole buffer
C-w                              ; kill region
(require 'file-name)             ; insert a require statement into the buffer
C-x C-s                          ; save buffer
C-x C-f                          ; find file
file-name.el <RET>               ; specify the name of the file
M-<                              ; move to the beginning of the buffer
C-u C-y                          ; insert the previously killed text, leaving point where it is
(provide 'file-name) <RET> <RET> ; insert a provide statement into the buffer
C-x )                            ; stop recording the keyboard macro

现在,您可以通过键入 C-x e save it重新播放其他缓冲区中的宏以供日后使用。您也可以像处理函数一样将宏绑定到快捷方式。

但是,这种方法存在一个缺点:您希望能够实际指定文件名,而不是每次都使用字符串“file-name”。这有点困难 - 默认情况下,键盘宏没有提供查询用户的一般工具(除了非常小的 C-x q ,如文档here所示)。

Emacs Wiki有一些解决办法,但是,有时通过杀死当前行并将其文本保存到寄存器来启动宏,而不是在迷你缓冲区中提示用户。

C-x (
C-e C-<SPC> C-a    ; mark current line
C-x r s T          ; copy line to register T
C-k C-k            ; kill current line
...                ; actual macro
C-x )

现在,当您想要使用宏时,首先在空行中写入所需的文件名,然后在该行中执行 C-x e 。只要宏中需要文件名的值,您就可以从寄存器T中检索它:

C-x r i T          ; insert file-name into buffer

例如,对于上述宏中的provide语句,您可以编写:(提供'C-x r i T)。请注意,此技术(插入)也适用于迷你缓冲区,当然您可以将多行保存到不同的寄存器中。

可能听起来很复杂,但实际上很容易。

答案 1 :(得分:4)

经过轻微测试:

(defun extract-to-package (name start end)
  (interactive (list (read-string "Package name to create: ")
                     (region-beginning) (region-end)))
  (let ((snip (buffer-substring start end)))
    (delete-region start end)
    (insert (format "(require '%s)\n" name))
    (with-current-buffer (find-file-noselect (concat name ".el"))
      (insert snip)
      (insert (format "(provide '%s)\n" name))
      (save-buffer))))

答案 2 :(得分:1)

对于这样的事情,我使用以下代码段(with yasnippet)

;; `(buffer-name)`
;; Copyright (C) `(format-time-string "%Y")` name

;; Author: name <email>

;; This program is free software: you can redistribute it and/or
;; modify it under the terms of the GNU General Public License as
;; published by the Free Software Foundation, either version 3 of
;; the License, or (at your option) any later version.

;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License
;; along with this program.  If not, see <http://www.gnu.org/licenses/>.

$0

(provide '`(subseq (buffer-name) 0 (- (length (buffer-name)) 3))`)
  • 1st创建文件 C - x C - f file-name.el RET
  • 然后插入片段 C - c &amp; C - s
  • 并添加您想要的任何代码。

我还有以下钩子:

(add-hook 'after-save-hook 'autocompile)

(defun autocompile ()
  "Byte compile an elisp."
  (interactive)
  (require 'bytecomp)
  (let ((filename (buffer-file-name)))
    (if (string-match "\\.el$" filename)
        (byte-compile-file filename))))
每当我保存.elc时,

生成.el

答案 3 :(得分:0)

(defun region-to-file+require (beg end file append)
  "Move region text to FILE, and replace it with `(require 'FEATURE)'.
You are prompted for FILE, the name of an Emacs-Lisp file.  If FILE
does not yet exist then it is created.

With a prefix argument, the region text is appended to existing FILE.

FEATURE is the relative name of FILE, minus the extension `.el'."
  (interactive "@*r\nG\nP")
  (when (string= (expand-file-name (buffer-file-name)) (expand-file-name file))
    (error "Same file as current"))
  (unless (string-match-p ".+[.]el$" file)
    (error "File extension must be `.el' (Emacs-Lisp file)"))
  (unless (or (region-active-p)
              (y-or-n-p "Region is not active.  Use it anyway? "))
    (error "OK, canceled"))
  (unless (> (region-end) (region-beginning)) (error "Region is empty"))
  (unless (or (not append)
              (and (file-exists-p file) (file-readable-p file))
              (y-or-n-p (format "File `%s' does not exist.  Create it? " file)))
    (error "OK, canceled"))
  (write-region beg end file append nil nil (not append))
  (delete-region beg end)
  (let ((feature  (and (string-match "\\(.+\\)[.]el$" file)
                       (match-string 1 file))))
    (when feature
      (insert (format "(require '%s)\n" feature)))))