Рефакторинг в Emacs - PullRequest
       18

Рефакторинг в Emacs

7 голосов
/ 22 декабря 2011

Я работаю над разбиением кода на файлы меньшего размера и его рефакторингом.Рассмотрим следующий код как раздел, который я хочу извлечь:

(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)

Было бы здоровоесли бы я мог нажать на брелок, а затем ввести имя и это произойдет.Если есть простой способ сделать это, то я хотел бы услышать возможные решения.

Редактировать: Я начинаю вознаграждение, потому что я думаю, что это относится к большему количеству типов кода, чем Лиспи я хотел бы иметь что-то более общее, на чем я мог бы остановиться.

Я рассмотрел Ясниппет, но я не думаю, что он достаточно мощный, чтобы выполнить задачу под рукой.По сути, идеальным рабочим процессом было бы пометить извлекаемые строки, заменив их соответствующей директивой require или include и отправив текст в свой собственный файл.В идеале одна команда и что-то, что знает о типе редактируемого файла или, по крайней мере, основной режим, чтобы поведение можно было настраивать, опять же, yasnippet хорош в выполнении разных задач при редактировании в различных основных режимах, однако я бы понятия не имел, каксделайте эту работу или оцените возможность заставить ее работать.

Дайте мне знать, если вам нужна дополнительная информация.

Ответы [ 4 ]

10 голосов
/ 22 декабря 2011

Общим решением проблемы этого типа являются клавиатурные макросы (не путать с (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 или , сохраните его для дальнейшего использования. Вы также можете привязать макрос к ярлыку, как функция.

Однако у этого подхода есть один недостаток: вы хотите иметь возможность фактически указывать имя файла, а не просто использовать строку «имя-файла» каждый раз. Это немного сложно - по умолчанию клавиатурные макросы не предоставляют общих возможностей для запросов пользователя (за исключением очень минимального C-x q , как описано здесь ).

В 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) . Обратите внимание, что этот метод (вставка) также работает в минибуфере, и, конечно, вы можете сохранить несколько строк в разных регистрах.

Может показаться сложным, но на практике это довольно легко.

4 голосов
/ 22 декабря 2011

Слегка протестировано:

(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))))
1 голос
/ 22 декабря 2011

Для такой вещи я использую следующий фрагмент (с 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))`)
  • 1-й создать файл C - x C - f file-name.el RET
  • затем вставьте фрагмент с C - c & 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.

0 голосов
/ 23 августа 2013
(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)))))
...