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

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

【问题讨论】:

    标签: 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 要求重命名当前缓冲区。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-10-17
        • 1970-01-01
        • 1970-01-01
        • 2017-06-11
        • 2011-06-21
        • 1970-01-01
        相关资源
        最近更新 更多