如何在 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-j
(dired-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 你错了!保存后,您将编辑新文件。
再说一次,为什么没有对 cmets 投反对票的功能?!
也许正如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 中重命名打开的文件?的主要内容,如果未能解决你的问题,请参考以下文章