Jak zmienić nazwę otwartego pliku w Emacsie?

237

Czy istnieje sposób zmiany nazwy otwartego pliku w Emacsie? Podczas oglądania? Coś jak save-as, ale oryginalny powinien odejść.

pupeno
źródło

Odpowiedzi:

88

Wypróbuj tę funkcję z .emacs Steve'a Yegge :

;; źródło: http://steve.yegge.googlepages.com/my-dot-emacs-file
(unikaj zmiany nazwy pliku i bufora (nowa nazwa)
  „Zmienia nazwę zarówno bieżącego bufora, jak i pliku, który odwiedza na NEW-NAME”.
  (interaktywny „sNew name:”)
  (let ((nazwa (nazwa bufora))
        (nazwa pliku (nazwa-pliku-bufora)))
    (jeśli (nie nazwa pliku)
        (nazwa „Bufor '% s' nie odwiedza pliku!”)
      (if (get-buffer new-name)
          (komunikat „Bufor o nazwie„% s ”już istnieje!” new-name)
        (progn
          (zmień nazwę pliku nazwa_pliku nowa-nazwa 1)
          (rename-buffer new-name)
          (set-visit-file-name new-name)
          (set-buffer-zmodyfikowany-p zero))))))

Spójrz na tę stronę, jest tam jeszcze jedna bardzo przydatna pokrewna funkcja, zwana „plikiem bufora ruchu”.

Matt Curtis
źródło
1
Uwaga: ta metoda nie jest zgodna ze (setq uniquify-buffer-name-style 'forward)znaczeniem, jeśli masz bufor o nazwie users\index.html(ponieważ masz już inny bufor posts\index.html), zmiana nazwy nie powiedzie się
dolzenko
(set-buffer-modified-p nil)wydaje się niepotrzebne. Jeśli wywołałeś rename-file-and-bufferzmodyfikowany bufor, a następnie próbowałeś go zabić, chętnie zrobiłby to bez ostrzeżenia o niezapisanych zmianach.
roldugin
Ta funkcja również (nieco irytująco) poprosi cię o nową nazwę przed sprawdzeniem, czy bieżący bufor jest w ogóle skojarzony z plikiem (w którym to przypadku jest przerywany).
Thomas
338

Tak, w diredtrybie możesz:

  • C-x d otworzyć dired
  • RET aby wybrać katalog bieżącego pliku
  • C-x C-j( dired-jumpdo nazwy bieżącego pliku, w Dired)
  • Rzmienić nazwę pliku (lub dired-do-rename).
  • q wrócić do bufora pliku (o zmienionej nazwie)

Zmiana nazwy jest równoważna powłoce mv, ale zaktualizuje również wszystkie otwarte bufory i, w przeciwieństwie do mvtego, nie zmieni czasu dostępu ani modyfikacji pliku w systemie plików.

Chris Conway
źródło
9
Nie zmienia to bezpośrednio nazwy bieżącego pliku.
pupeno
4
Cx b i wróciłeś do pierwotnego bufora. Możesz napisać funkcję Elisp, aby to zrobić, ale wątpię, czy zaoszczędzisz dzięki temu wiele naciśnięć klawiszy.
Chris Conway,
6
Ponadto, zamiast Cx b, możesz nacisnąć Cx k, aby powrócić do pierwotnego bufora.
Yoo
32
Nie C-x C-jjest to dla mnie domyślnie związane. Robienie tego M-x load-library RET dired-x RETnajpierw wiąże.
ntc2
4
Inną alternatywą, jeśli C-x C-jjest niezwiązana, jest po prostu M-x dired-jumpza pierwszym razem. Zostanie automatycznie załadowany dired-x(co również spowoduje, C-x C-jże zostanie zdefiniowane od tego momentu).
Fernando Basso,
120

Dla kompletności, ponieważ niektórzy ludzie mogą odwiedzić tę stronę, myśląc, że otrzymają odpowiedź na funkcję „zapisz jako” Emacsa, to Cx Cw dla otwartego pliku.

Jim G.
źródło
Cx Cw lub skorzystaj z menuFile > Save as...
Yoo 14.10
Niezupełnie „zapisz jako”, ponieważ edytowany plik nadal będzie oryginalny.
asmeurer
11
@asmeurer Mylisz się! Po zapisaniu będziesz edytować nowy plik.
Joel G Mathew
3
Znowu, dlaczego nie ma funkcji głosowania komentarzy ?!
niedźwiedź
7
Być może asmeurer miał na myśli: „plik, który edytujesz, nadal będzie istniał”. Czy to prawda? Sprawdziłbym, ale nie możesz głosować za moim komentarzem, hahaha.
Brady Trainor
25

Moim ulubionym jest ten z Magnars (sławnych screencastów z Emacsa Rocka ).

W przeciwieństwie do innych alternatyw, nie musisz wpisywać nazwy od zera - musisz zmienić obecną nazwę.

(defun rename-current-buffer-file ()
  "Renames current buffer and file it is visiting."
  (interactive)
  (let* ((name (buffer-name))
        (filename (buffer-file-name))
        (basename (file-name-nondirectory filename)))
    (if (not (and filename (file-exists-p filename)))
        (error "Buffer '%s' is not visiting a file!" name)
      (let ((new-name (read-file-name "New name: " (file-name-directory filename) basename nil basename)))
        (if (get-buffer new-name)
            (error "A buffer named '%s' already exists!" new-name)
          (rename-file filename new-name 1)
          (rename-buffer new-name)
          (set-visited-file-name new-name)
          (set-buffer-modified-p nil)
          (message "File '%s' successfully renamed to '%s'"
                   name (file-name-nondirectory new-name)))))))

Dzięki Jamesowi Yangowi za poprawną wersję.

The Unfun Cat
źródło
To NIE działa poprawnie. Ten dodaje „/” na końcu pliku.
mityczny
2
Dzięki za opublikowanie tego dla mnie. Takim sposobem jest poprawianie odpowiedzi, a nie publikowanie nowych, nieco zmodyfikowanych.
Unfun Cat
15

Oto bardziej solidna wersja zaadaptowana ze Steveya.

;; Originally from stevey, adapted to support moving to a new directory.
(defun rename-file-and-buffer (new-name)
  "Renames both current buffer and file it's visiting to NEW-NAME."
  (interactive
   (progn
     (if (not (buffer-file-name))
         (error "Buffer '%s' is not visiting a file!" (buffer-name)))
     ;; Disable ido auto merge since it too frequently jumps back to the original
     ;; file name if you pause while typing. Reenable with C-z C-z in the prompt.
     (let ((ido-auto-merge-work-directories-length -1))
       (list (read-file-name (format "Rename %s to: " (file-name-nondirectory
                                                       (buffer-file-name))))))))
  (if (equal new-name "")
      (error "Aborted rename"))
  (setq new-name (if (file-directory-p new-name)
                     (expand-file-name (file-name-nondirectory
                                        (buffer-file-name))
                                       new-name)
                   (expand-file-name new-name)))
  ;; Only rename if the file was saved before. Update the
  ;; buffer name and visited file in all cases.
  (if (file-exists-p (buffer-file-name))
      (rename-file (buffer-file-name) new-name 1))
  (let ((was-modified (buffer-modified-p)))
    ;; This also renames the buffer, and works with uniquify
    (set-visited-file-name new-name)
    (if was-modified
        (save-buffer)
      ;; Clear buffer-modified flag caused by set-visited-file-name
      (set-buffer-modified-p nil)))

  (setq default-directory (file-name-directory new-name))

  (message "Renamed to %s." new-name))
Shawn Hoover
źródło
Niezłe. Teraz odpoczywam w moich funkcjach. El.
Felix D.
11

Oto kolejna wersja, która jest dość solidna i świadoma VC:

(defun rename-file-and-buffer ()
  "Rename the current buffer and file it is visiting."
  (interactive)
  (let ((filename (buffer-file-name)))
    (if (not (and filename (file-exists-p filename)))
        (message "Buffer is not visiting a file!")
      (let ((new-name (read-file-name "New name: " filename)))
        (cond
         ((vc-backend filename) (vc-rename-file filename new-name))
         (t
          (rename-file filename new-name t)
          (set-visited-file-name new-name t t)))))))

Możesz przeczytać więcej na ten temat tutaj .

Bozhidar Batsov
źródło
4

Jest bardzo prosty sposób, naciśnij komendę Mx i wpisz vc-rename-file , po czym musisz tylko wybrać swój aktualny plik w katalogu, a następnie wybrać nową nazwę. Buff, który ma zmieniony plik zostanie odświeżony.

Źródło: https://www.gnu.org/software/emacs/manual/html_node/emacs/VC-Delete_002fRename.html

Rafael Nascimento
źródło
1
Ma to (niekoniecznie pożądany) efekt uboczny polegający na dodaniu starych i nowych plików, które zostaną zatwierdzone do kontroli wersji. Ale +1, ponieważ używa wbudowanej funkcji, aby (głównie) odpowiedzieć na pytanie PO.
dinozaur
3

w oparciu o wersję magnars, zmodyfikowałem jak poniżej, naprawiłem część nazwy pliku INIT:

(defun rename-current-buffer-file ()
  "Renames current buffer and file it is visiting."
  (interactive)
  (let* ((name (buffer-name))
        (filename (buffer-file-name))
        (basename (file-name-nondirectory filename)))
    (if (not (and filename (file-exists-p filename)))
        (error "Buffer '%s' is not visiting a file!" name)
      (let ((new-name (read-file-name "New name: " (file-name-directory filename) basename nil basename)))
        (if (get-buffer new-name)
            (error "A buffer named '%s' already exists!" new-name)
          (rename-file filename new-name 1)
          (rename-buffer new-name)
          (set-visited-file-name new-name)
          (set-buffer-modified-p nil)
          (message "File '%s' successfully renamed to '%s'"
                   name (file-name-nondirectory new-name)))))))
James Yang
źródło
Ten jest lepszy. Podana powyżej wersja Magnars nie działa poprawnie. Dodaj znak „/” na końcu
mityczny
-1

Można to osiągnąć przez kopiowanie. Shift + C na pliku, a emacs poprosi cię o wskazanie nazwy ścieżki, w tym nazwy pliku, więc po prostu podaj nową nazwę i wpisz ... oczywiście, musisz usunąć poprzednią.

Eric_Chen
źródło
1
Wygląda na to, że masz na myśli „C” w trybie dired? To kopiowanie pliku, a nie zmiana jego nazwy, co (jak zauważył @ChrisConway) w dired odbywa się za pomocą „R”. Poza tym OP poprosił o zmianę nazwy bieżącego bufora.
Davor Cubranic,