Как мне переименовать открытый файл в Emacs?

Есть ли способ переименовать открытый файл в Emacs? Пока смотрю? Что-то вроде save-as, но оригинал должен уйти.


person pupeno    schedule 21.12.2008    source источник


Ответы (12)


Попробуйте эту функцию из .emacs Стива Йегге:

;; source: http://steve.yegge.googlepages.com/my-dot-emacs-file
(defun rename-file-and-buffer (new-name)
  "Renames both current buffer and file it's visiting to NEW-NAME."
  (interactive "sNew name: ")
  (let ((name (buffer-name))
        (filename (buffer-file-name)))
    (if (not filename)
        (message "Buffer '%s' is not visiting a file!" name)
      (if (get-buffer new-name)
          (message "A buffer named '%s' already exists!" new-name)
        (progn
          (rename-file filename new-name 1)
          (rename-buffer new-name)
          (set-visited-file-name new-name)
          (set-buffer-modified-p nil))))))

Взгляните на эту страницу, там есть еще одна действительно полезная связанная функция, которая называется "файл-буфера-перемещения".

person Matt Curtis    schedule 21.12.2008
comment
Примечание: этот метод несовместим с (setq uniquify-buffer-name-style 'forward), что означает, что если у вас есть буфер с именем users\index.html (потому что у вас уже есть другой буфер для posts\index.html), переименование не удастся. - person dolzenko; 27.09.2012
comment
(set-buffer-modified-p nil) кажется ненужным. Если вы вызвали rename-file-and-buffer для измененного буфера, а затем попытались его убить, он с радостью сделает это, не предупреждая вас о несохраненных изменениях. - person roldugin; 11.07.2013
comment
Эта функция также (несколько раздражающе) попросит вас ввести новое имя перед проверкой, связан ли текущий буфер с файлом вообще (в этом случае он прерывается). - person Thomas; 11.09.2015

Да, в режиме dired вы можете:

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

Переименование эквивалентно оболочке mv, но оно также обновляет все открытые буферы и, в отличие от mv, не изменяет время доступа и изменения файла в файловой системе.

person Chris Conway    schedule 21.12.2008
comment
Это не переименование текущего файла напрямую. - person pupeno; 21.12.2008
comment
C-x b, и вы снова в исходном буфере. Вы могли бы написать для этого функцию Elisp, но я сомневаюсь, что с ее помощью вы сэкономите много нажатий клавиш. - person Chris Conway; 22.12.2008
comment
Кроме того, вместо C-x b вы можете нажать C-x k, чтобы вернуться в исходный буфер. - person Yoo; 14.10.2010
comment
О том, как пропустить поиск файла из dired-буфера, см. stackoverflow.com/questions/3933484/ - person Yoo; 15.10.2010
comment
Спасибо за этот ответ. Это проще, чем добавлять функции. Что касается того, что это не прямое переименование текущего файла, похоже, что это именно так. Файл переименовывается на диске и в буфере. - person titanofold; 08.08.2013
comment
C-x C-j не привязан по умолчанию для меня. Выполнение M-x load-library RET dired-x RET сначала делает его связанным. - person ntc2; 31.10.2013
comment
Для меня это лучший ответ, поскольку концепция прямого действия становится довольно расплывчатой, когда мы говорим о нескольких нажатиях клавиш. Обычно quit-window привязан к q, так что это просто вопрос C-x C-j R [filename] RET q. Насколько косвенно это на практике? - person Francesco Napolitano; 16.06.2016
comment
Другой альтернативой, если C-x C-j не привязан, просто выполнить M-x dired-jump в первый раз. Он автоматически загрузит dired-x (что также приведет к определению C-x C-j с этого момента). - person Fernando Basso; 11.08.2016
comment
Завершение шага dired-do-rename однозначно переименовывает файл. Я не уверен, против чего возражает @pupeno. - person ctpenrose; 04.12.2020

Просто для полноты, поскольку некоторые люди могут посетить эту страницу, думая, что они получат ответ на функцию Emacs «сохранить как», это C-x C-w для открытого файла.

person Jim G    schedule 10.10.2009
comment
C-x C-w или используйте меню File > Save as... - person Yoo; 14.10.2010
comment
Не совсем «сохранить как», поскольку файл, который вы редактируете, останется исходным. - person asmeurer; 22.06.2013
comment
@asmeurer Вы ошибаетесь! После сохранения вы будете редактировать новый файл. - person Joel G Mathew; 22.08.2013
comment
Опять же, почему нет возможности голосовать за комментарии ?! - person bearfriend; 05.02.2014
comment
Возможно, asmeurer имел в виду, что файл, который вы [редактировали], все еще будет [существовать]. Тогда это правильно? Я бы проверил, но тогда вы не можете отрицать мой комментарий, хахаха. - person Brady Trainor; 19.03.2014
comment
А потом стереть старую? - person Felipe; 21.06.2015
comment
Сохранить как не имеет отношения к переименованию. - person RichieHH; 02.01.2020

Мне больше всего нравится снимок от 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)))))))

Спасибо Джеймсу Яну за правильную версию.

person The Unfun Cat    schedule 08.08.2014
comment
Это НЕ работает должным образом. Этот добавляет / в конце файла. - person mythicalcoder; 23.03.2017
comment
Спасибо, что разместили это для меня. Способ SO - исправлять ответы, а не публиковать новые, слегка измененные. - person The Unfun Cat; 24.03.2017

Вот более надежная версия, адаптированная от Stevey.

;; 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))
person Shawn Hoover    schedule 02.12.2009
comment
Хороший. Теперь расслабляюсь в моих functions.el. - person Felix D.; 18.06.2014

Вот еще одна версия, довольно надежная и поддерживающая 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)))))))

Подробнее об этом можно узнать здесь.

person Bozhidar Batsov    schedule 30.05.2013

Если вы используете Spacemacs, вы получаете это поведение бесплатно, поскольку оно поставляется с реализацией rename-current-buffer-file (на основе магнаров) который по умолчанию привязан к SPC-f-R.

person Jason Axelson    schedule 04.06.2018

comment
Я только что протестировал это в Doom Emacs (v27.1), и он тоже работает. Спасибо. - person flarkmarup; 23.02.2021

Есть очень простой способ: вы нажимаете команду Mx и затем набираете vc-rename-file, после чего вам просто нужно выбрать текущий файл в каталоге, и чем выбрать новое имя. Бафф с измененным файлом будет обновлен.

Источник: https://www.gnu.org/software/emacs/manual/html_node/emacs/VC-Delete_002fRename.html

person Rafael Nascimento    schedule 02.08.2017
comment
У этого есть (не обязательно желательный) побочный эффект добавления старых и новых файлов для фиксации в системе контроля версий. Но +1, потому что он использует встроенную функцию (в основном) для ответа на вопрос OP. - person dinosaur; 28.08.2017
comment
Работает даже сегодня с GNU Emacs 25.3.2 (x86_64-pc-linux-gnu, GTK + Version 3.18.9) - person agent18; 28.09.2020

на основе версии 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)))))))
person James Yang    schedule 26.05.2016
comment
Этот лучше. Приведенная выше версия magnars НЕ работает должным образом. Добавить символ / в конце - person mythicalcoder; 23.03.2017

Превосходный crux пакет имеет crux-rename-file-and-buffer (наряду со многими другими полезными функциями).

person Alan    schedule 13.02.2021

Emacs 26.3 (2020-04-03) имеет функцию rename-file, которую можно вызвать с помощью M-x rename-file для переименования текущего файла или любого другого файла, если на то пошло.

person Jay Rajput    schedule 04.11.2020

Этого можно добиться копированием. shift + c в файле, и emacs попросит вас указать имя для пути, включая имя файла, поэтому вы просто указываете новое имя и вводите ... конечно, вы должны удалить прежнее.

person Eric_Chen    schedule 27.05.2013
comment
Вы, кажется, имеете в виду C в режиме dired? Это копирование файла, а не его переименование, что (как отметил @ChrisConway) в dired выполняется с помощью R. Кроме того, OP запросил переименование текущего буфера. - person Davor Cubranic; 13.01.2015