2011-12-22 8 views
6

Pracuję nad dzieleniem kodu na mniejsze pliki i trochę go refaktoryzuję. Rozważmy następujący kod poniżej w sekcji chcę wyodrębnić:Refaktoryzacja w Emacs

(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))) 
  • chcę wziąć sekcję powyżej i zastąpić go czymś takim (require `file-name)
  • Następnie podejmuje tekst zastępuje i umieścić, że w nowym plik w bieżącym katalogu o nazwie file-name.el
  • a następnie dodać linię do początku pliku (provides `file-name)

byłoby wspaniale gdybym mógł uderzyć w keychord, a następnie wpisać imię i tak się stało. Jeśli jest to prosty sposób, to chciałbym usłyszeć możliwe rozwiązania.

Edit: Zaczynam bounty, ponieważ myślę, że odnosi się to do większej liczby typów kodu niż Lisp i chciałbym mieć coś nieco bardziej ogólne, że można rozszerzać.

Rozważałem Yasnippet, ale nie sądzę, że jest wystarczająco silny, aby wykonać zadanie pod ręką. Zasadniczo idealnym przepływem pracy byłoby zaznaczenie linii do wyodrębnienia, zastąpienie jej odpowiednią dyrektywą wymagającą lub włączającą i wysłanie tekstu do własnego pliku. Idealnie jedna komenda i coś, co jest świadome rodzaju edytowanego pliku lub co najmniej trybu głównego, więc zachowanie można dostosować, ponownie yasnippet jest dobry w wykonywaniu różnych zadań podczas edycji w różnych głównych trybach jednak nie mam pojęcia, jak wykonać tę pracę lub ocenić możliwość jej działania.

Daj mi znać, jeśli potrzebujesz więcej informacji.

Odpowiedz

4

lekko badane:

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

Zdaję sobie sprawę, że jest to dość stare, ale tylko sugestia; Osobiście przeniosłem '' (delete-region ...) (insert) 'wywołania * po * bloku' 'with-current-buffer '', więc jeśli np. Wystąpił błąd podczas tworzenia pliku (być może katalog tylko do odczytu lub coś takiego), funkcja przerwie działanie bez "uszkodzenia" oryginalnego pliku. – BRFennPocock

1

Przez taką rzeczą, którą za pomocą następującej fragment (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))`) 
  • 1-ty utworzyć plik C - xC - Ffile-name.elRET
  • następnie wstaw fragment z numerem C - c&C - s
  • i dodać dowolny fragment kodu, który chcesz.

Mam również haczyk:

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

do wytworzenia .elc ilekroć zapisać .el.

10

Ogólne rozwiązanie tego typu problemów są keyboard macros (nie mylić z (makr emacs) LISP). Zasadniczo Emacs pozwala nagrywać sekwencję klawiszy i "odtwarzać je" później. Może to być bardzo przydatne narzędzie w sytuacjach, w których pisanie niestandardowego kodu LISP wydaje się przesadzone.

Na przykład można utworzyć następujące makro klawiatury (typ kombinacji klawiszy na lewej stronie, po prawej stronie strony pokazuje wyjaśnienia każdym naciśnięciu klawisza):

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 

Teraz można ponownie zagrania, makro w innym buforze, wpisując Cx e lub save it do późniejszego wykorzystania. Można również powiązać makro ze skrótem, podobnie jak funkcję.

Jednak w tym podejściu występuje jedna słabość: użytkownik chce w rzeczywistości określić nazwę pliku, a nie używać po prostu ciągu "nazwa-pliku" za każdym razem. To jest trochę trudne - domyślnie makra klawiaturowe nie zapewniają ogólnej możliwości sprawdzania użytkownika (z wyjątkiem bardzo minimalnego C-x q, jak udokumentowano here).

W tym celu można wykonać pewne obejścia, jednak zamiast monitować użytkownika w minibuforze, czasami może wystarczyć uruchomienie makra przez zabicie bieżącego wiersza i zapisanie jego tekstu w rejestrze.

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) 

Teraz, gdy chcemy korzystać z makra, należy najpierw wpisać żądane nazwy pliku w pustej linii, a następnie zrobić C-x e w tej linii. Ilekroć wartość nazwa-pliku jest potrzebna w makro można pobrać go z rejestru T:

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

Na przykład, na rachunku w powyższym makro provide, można napisać: (podać 'Cx ri T). Zauważ, że ta technika (wstawianie) działa również w minibuforze, i oczywiście możesz zapisać wiele linii do różnych rejestrów.

Może wydawać się skomplikowane, ale w rzeczywistości jest dość łatwe w praktyce.

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