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

Posted

技术标签:

【中文标题】如何在 Emacs 中重命名打开的文件?【英文标题】:How do I rename an open file in Emacs? 【发布时间】:2010-09-27 21:50:56 【问题描述】:

有没有办法在 Emacs 中重命名打开的文件?我在看的时候?类似另存为的东西,但原来的应该消失了。

【问题讨论】:

【参考方案1】:

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

C-x d打开目录 RET选择当前文件目录 C-x C-jdired-jump 为当前文件的名称,在 Dired 中) R 重命名文件(或dired-do-rename)。 q 回到(重命名的)文件缓冲区

重命名相当于一个shell mv,但它也会更新任何打开的缓冲区,并且与mv 不同,它不会改变文件系统中文件的访问和修改时间。

【讨论】:

那不是直接重命名当前文件。 C-x b 然后你又回到了原始缓冲区。你可以写一个 Elisp 函数来做这件事,但我怀疑你会用它节省很多击键。 另外,您可以按 C-x k 而不是 C-x b,返回原始缓冲区。 C-x C-j 默认情况下对我没有绑定。首先执行M-x load-library RET dired-x RET 使其绑定。 如果C-x C-j 未绑定,另一种选择是第一次执行M-x dired-jump。它将自动加载dired-x(这也将导致从此时开始定义C-x C-j)。【参考方案2】:

为了完整起见,因为有些人可能会访问此页面,认为他们会得到 Emacs 的“另存为”功能的答案,即打开文件的 C-x C-w。

【讨论】:

C-x C-w 或使用菜单File > Save as... 不完全是“另存为”,因为您正在编辑的文件仍然是原始文件。 @asmeurer 你错了!保存后,您将编辑新文件。 再说一次,为什么没有对 cme​​ts 投反对票的功能?! 也许正如meurer 的意思,“你[正在]编辑的文件仍然[存在]”。那么,这样对吗?我会检查,但是,你不能拒绝我的评论,哈哈哈。【参考方案3】:

从Steve Yegge's .emacs试试这个功能:

;;来源:http://steve.yegge.googlepages.com/my-dot-emacs-file (defun rename-file-and-buffer (new-name) “将当前缓冲区和它正在访问的文件重命名为 NEW-NAME。” (交互式“s新名称:”) (让((名称(缓冲区名称)) (文件名(缓冲区文件名))) (如果(不是文件名) (消息“缓冲区 '%s' 没有访问文件!”名称) (如果(获取缓冲区新名称) (消息“名为 '%s' 的缓冲区已存在!”新名称) (预测 (重命名文件文件名新名称1) (重命名缓冲区新名称) (设置访问文件名新名称) (set-buffer-modified-p nil))))))

看看那个页面,那里还有一个非常有用的相关函数,叫做“move-buffer-file”。

【讨论】:

注意:此方法与(setq uniquify-buffer-name-style 'forward) 不兼容,这意味着如果您有名为users\index.html 的缓冲区(因为您已经有另一个缓冲区用于posts\index.html)重命名将失败 (set-buffer-modified-p nil) 似乎没有必要。如果您在修改后的缓冲区上调用 rename-file-and-buffer 然后试图杀死它,它会很乐意这样做,而不会警告您未保存的更改。 这个函数也会(有点烦人)在检查当前缓冲区是否与文件相关联(在这种情况下会中止)之前 要求您输入一个新名称。 【参考方案4】:

我最喜欢的是 Magnars 的那个(emacs rocks screencasts 成名。)

与其他替代方案不同,您不必从头开始输入名称 - 您可以修改当前名称。

(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 提供正确的版本。

【讨论】:

这不能正常工作。这个在文件末尾添加了一个“/”。 感谢您为我发布该内容。 SO 方法是更正答案,而不是发布新的、稍加修改的答案。【参考方案5】:

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

【讨论】:

不错的一个。现在让我的functions.el感到不寒而栗。【参考方案6】:

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

您可以阅读更多关于它的信息here。

【讨论】:

【参考方案7】:

如果您使用的是Spacemacs,那么您可以免费获得此行为,因为它带有rename-current-buffer-file(基于magnars)的实现,默认绑定到SPC-f-R

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

【讨论】:

我刚刚在 Doom Emacs (v27.1) 中对此进行了测试,它也可以正常工作。谢谢。【参考方案8】:

有一个非常简单的方法,你按下命令Mx然后输入vc-rename-file,然后你只需要在目录,然后选择新名称。修改文件的buff会被刷新。

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

【讨论】:

这有(不一定需要)将新旧文件添加到版本控制中的副作用。但是 +1 因为它使用内置函数来(主要)回答 OP 的问题。 即使在今天也可以与 GNU Emacs 25.3.2(x86_64-pc-linux-gnu,GTK+ 版本 3.18.9)一起使用 当我使用vc-rename-file时得到了这个,请在​​移动它们之前更新文件`【参考方案9】:

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

【讨论】:

这个更好。上面给出的 magnars 版本不能正常工作。在末尾添加一个“/”字符【参考方案10】:

Emacs 26.3 (2020-04-03) 具有 rename-file 函数,可以使用 M-x rename-file 调用该函数以重命名当前文件或任何其他文件。

【讨论】:

在 Emacs 25 中,这不会更改缓冲区中文件的名称,即下一次写入将再次转到旧文件名。【参考方案11】:

出色的crux package 具有crux-rename-file-and-buffer(以及许多其他有用的功能)。

【讨论】:

【参考方案12】:

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

【讨论】:

您似乎是在 dired 模式下指的是“C”?那是复制文件,而不是重命名它,这(正如@ChrisConway 指出的)在 dired 中是用“R”完成的。此外,OP 要求重命名当前缓冲区。

以上是关于如何在 Emacs 中重命名打开的文件?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 .NET 中重命名文件?

如何在 C++ 中重命名文件

如何在 HIVE 的分区中重命名文件

如何在上传过程中重命名图像文件

如何在 JGit 中重命名文件

如何在 Visual Studio 2003 中重命名 C++ 源文件?