如何在Emacs中重命名打开的文件?


237

有没有办法在Emacs中重命名打开的文件?在查看时?类似于另存为,但原始的应该会消失。

Answers:


88

Steve Yegge的.emacs尝试以下功能:

;; 来源:http://steve.yegge.googlepages.com/my-dot-emacs-file
(defun重命名文件和缓冲区(新名称)
  “重命名当前缓冲区和文件以访问NEW-NAME。”
  (交互式“ sNew名称:”)
  (让[{name(buffer-name))
        (文件名(缓冲文件名)))
    (如果(不是文件名)
        (消息“缓冲区'%s'不在访问文件!”名称)
      (如果(获取缓冲区新名称)
          (消息“已存在名为'%s'的缓冲区!”新名称)
        (前进
          (重命名文件文件名新名称1)
          (重命名缓冲区新名称)
          (访问文件集的新名称)
          (set-buffer-modified-p nil))))))

看一下该页面,那里还有另一个非常有用的相关功能,称为“ move-buffer-file”。


1
注意:(setq uniquify-buffer-name-style 'forward)如果您命名了缓冲区users\index.html(因为您已经有另一个缓冲区posts\index.html),则此方法与含义不兼容,重命名将失败
dolzenko 2012年

(set-buffer-modified-p nil)似乎没有必要。如果您调用rename-file-and-buffer了已修改的缓冲区,然后尝试杀死它,它将很乐意执行此操作,而不会警告您未保存的更改。
roldugin

检查当前缓冲区是否与文件相关联(在这种情况下它将中止)之前,此功能还将(有些令人讨厌)要求您提供新名称。
托马斯

338

是的,使用dired模式,您可以:

  • C-x d 打开骰子
  • RET 选择当前文件的目录
  • C-x C-jdired-jump到当前文件的名称,以Dired表示)
  • R重命名文件(或dired-do-rename)。
  • q 返回(重命名)文件缓冲区

重命名等效于shell mv,但它还将更新所有打开的缓冲区,并且与重命名不同,mv它不会更改文件系统中文件的访问和修改时间。


9
那不是直接重命名当前文件。
pupeno

4
Cx b,您又回到了原始缓冲区中。您可以编写一个Elisp函数来执行此操作,但是我怀疑您会使用它保存许多按键。
克里斯·康威

6
另外,您可以按Cx k而不是Cx b来返回原始缓冲区。
Yoo 2010年

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 2013年

11
@asmeurer你错了!保存后,您将在编辑新文件。
乔尔·马修

3
再次,为什么不具有对评论进行否决的功能?
bearfriend 2014年

7
也许asmeurer的意思是“您正在编辑的文件仍将存在”。那是正确的吗?我会检查的,但是您不能拒绝我的评论,哈哈哈。
Brady Trainor 2014年

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

感谢James Yang的正确版本。


这不能正常工作。此文件的末尾添加一个“ /”。
mythicalcoder

2
感谢您为我发布。SO的方法是纠正答案,而不是发布新的,稍作修改的答案。
Unfun Cat

15

这是来自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))

好一个。现在让我的功能放松。
Felix D.

11

这是另一个版本,它非常健壮并且支持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)))))))

您可以在此处了解更多信息。



4

有一种非常简单的方法,您可以按命令Mx,然后键入vc-rename-file,然后只需要在目录中选择当前文件,然后选择新名称即可。文件已更改的buff将被刷新。

来源:https : //www.gnu.org/software/emacs/manual/html_node/emacs/VC-Delete_002fRename.html


1
这具有将要提交的旧文件和新文件添加到版本控制中的副作用(不一定令人满意)。但是+1是因为它使用内置函数来(大部分)回答OP的问题。
恐龙

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

这个比较好。上面给出的magnar版本无法正常运行。在末尾添加“ /”字符
mythicalcoder,

-1

可以通过复制来实现。在文件上使用shift + c,emacs会要求您为包含文件名的路径指定一个名称,因此,您只需提供新名称,然后输入...当然,您必须删除前一个。


1
您似乎是在偏干模式下指的是“ C”?那是复制文件,而不是重命名文件,这(如@ChrisConway指出的那样)用“ R”完成。此外,OP要求重命名当前缓冲区。
Davor Cubranic 2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.