Як перейменувати відкритий файл у Emacs?


237

Чи є спосіб перейменувати відкритий файл у Emacs? Поки я його переглядаю? Щось схоже на збереження, але оригінальне повинне піти.

Відповіді:


88

Спробуйте цю функцію від .emacs Стіва Йегге :

;; джерело: http://steve.yegge.googlepages.com/my-dot-emacs-file
(розблокувати перейменувати файл-і-буфер (нове ім'я)
  "Перейменує поточний буфер і файл, який він відвідує, в NEW-NAME."
  (інтерактивне "sNew name:")
  (нехай ((ім'я (ім'я буфера))
        (ім'я файлу (буфер-ім’я файлу)))
    (якщо (не ім'я файлу)
        (повідомлення "Буфер"% s "не відвідує файл!")
      (якщо (get-buffer new-name)
          (повідомлення "Буфер з назвою"% s "вже існує!")
        (прогн
          (перейменувати-ім'я файлу new-name 1)
          (перейменувати буфер нового імені)
          (set-visit-file-name new-name)
          (набір-буфер-змінено-p nil))))))

Погляньте на цю сторінку, там є ще одна справді корисна пов'язана функція, яка називається "move-buffer-file".


1
Примітка: цей метод не сумісний зі (setq uniquify-buffer-name-style 'forward)значенням, якщо у вас є ім'я буфера users\index.html(оскільки у вас вже є інший буфер posts\index.html), перейменування не вдасться
dolzenko

(set-buffer-modified-p nil)здається непотрібним. Якщо ви запустили rename-file-and-bufferмодифікований буфер, а потім спробували його вбити, він із задоволенням зробить це, не попереджаючи вас про незбережені зміни.
roldugin

Ця функція також (дещо дратівливо) запитає вас про нове ім'я, перш ніж перевірити, чи пов’язаний поточний буфер із файлом взагалі (у такому разі він перериває).
Томас

338

Так, за допомогою diredрежиму ви можете:

  • C-x d відкрити дір
  • RET вибрати каталог поточного файлу
  • C-x C-j( dired-jumpдо імені поточного файлу в Dired)
  • Rперейменувати файл (або dired-do-rename).
  • q щоб повернутися до (перейменованого) файлового буфера

Перейменування еквівалентно оболонці mv, але воно також оновить будь-які відкриті буфери, і на відміну від mvцього не змінить доступ та змінить час файлу у файловій системі.


9
Це не перейменування безпосередньо поточного файлу.
pupeno

4
Cx b, і ви знову в оригінальному буфері. Ви можете написати функцію Elisp для цього, але я сумніваюся, що ви збережете багато натискань клавіш.
Кріс Конвей

6
Крім того, замість Cx b, ви можете натиснути Cx k, щоб повернутися в початковий буфер.
Yoo

32
Меню C-x C-jза замовчуванням не пов'язане. Роблячи M-x load-library RET dired-x RETперший робить це неминуче.
ntc2

4
Ще одна альтернатива, якщо C-x C-jвона не пов'язана - це просто зробити M-x dired-jumpз першого разу. Він автоматично завантажується dired-x(що також C-x C-jбуде визначено з цього моменту).
Фернандо Бассо

120

Просто для повноти, оскільки деякі люди можуть завітати на цю сторінку, думаючи, що вони отримають відповідь за функцію "зберегти як" Emacs, це Cx Cw для відкритого файлу.


Cx Cw або скористайтеся менюFile > Save as...
Yoo

Не зовсім "зберегти як", оскільки файл, який ви редагуєте, все ще буде оригінальним.
asmeurer

11
@asmeurer Ви помиляєтесь! Після збереження ви будете редагувати новий файл.
Джоель Г Матвій

3
Знову ж, чому немає функції зворотного коментаря ?!
ведмедиця

7
Можливо, asmeurer означав, що "файл, який ви [редагували], все ще буде [існувати]". Тоді, чи правильно? Я би перевірив, але тоді ви не можете спростувати мій коментар, хахаха.
Тренер Брейді

25

Мій улюблений - той із Magnars (про екрани слави екранів Emacs .)

На відміну від інших альтернатив, вам не доведеться вводити ім’я з нуля - ви отримуєте поточне ім’я для зміни.

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

Дякуємо Джеймсу Ян за правильну версію.


Це НЕ працює належним чином. Цей додає "/" в кінці файлу.
mythicalcoder

2
Дякую, що виклали це за мене. Шлях - це виправлення відповідей, а не публікація нових, трохи змінених.
The Unfun Cat

15

Ось більш надійна версія, адаптована зі стеві.

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

Хороший. Тепер охолодження в моїх функціях.el.
Фелікс Д.

11

Ось ще одна версія, яка є досить надійною і знає:

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

Більше про це можна прочитати тут .


7

Якщо ви використовуєте Spacemacs, ви отримуєте таку поведінку безкоштовно, оскільки вона реалізується з реалізацією rename-current-buffer-file(заснованої на магнарах), до якої за замовчуванням прив’язана SPC-f-R.

https://github.com/syl20bnr/spacemacs/blob/bd7ef98e4c35fd87538dd2a81356cc83f5fd02f3/layers/%2Bdistributions/spacemacs-base/funcs.el#L294


4

Є спосіб дуже простий, ти натискаєш команду Mx і потім набираєш набираєш vc-rename-файл , після чого потрібно просто вибрати поточний файл у каталозі, а потім вибрати нове ім'я. Баф із зміненим файлом буде оновлений.

Джерело: https://www.gnu.org/software/emacs/manual/html_node/emacs/VC-Delete_002fRename.html


1
Це має (не обов'язково бажаний) побічний ефект додавання старих і нових файлів, які потрібно ввести в контроль версій. Але +1, оскільки він використовує вбудовану функцію для (в основному) відповіді на питання ОП.
динозавр

3

На основі версії Magnars я змінив, як показано нижче, виправив частину імені файлу 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)))))))

Цей краще. Наведена вище версія магнарів НЕ працює належним чином. Додайте символ "/" наприкінці
mythicalcoder

-1

Це можна досягти за допомогою копії. shift + c у файлі, а emacs попросить вас позначити ім'я для шляху, включаючи ім'я файлу, тому ви просто вкажете нове ім'я та введіть ... звичайно, вам потрібно видалити попереднє.


1
Ви начебто посилаєтесь на "С" у переведеному режимі? Це копіювання файлу, а не перейменування його, що (як зазначає @ChrisConway) у розділеному файлі робиться з "R". Крім того, ОП попросив перейменувати поточний буфер.
Давор Кубраніч
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.