Reputation: 287410
Is there a way to rename an open file in Emacs? While I'm viewing it? Something like save-as, but the original one should go away.
Upvotes: 282
Views: 95204
Reputation: 81
As of Emacs 29.1, the function rename-visited-file
does precisely what you're asking for.
As an aside, I'm going to retire my vc-rename-this
function because this does most of what I'm asking of it.
Upvotes: 0
Reputation: 10848
Emacs 29.1 added rename-visited-file
command which does exactly this, without a key binding though.
From its NEWS:
** New command 'rename-visited-file'. This command renames the file visited by the current buffer by moving it to a new name or location, and also makes the buffer visit this new file.
Upvotes: 8
Reputation: 31
I know the post is sooo old but in all the answer I have found, nothing is more simple that what said Emacs in their tutorial:
M-x Dired
(launch dired)
C-x C-q
(toggle read only in dired)
change the filename like if it was just a line in a text file:
prev:
/home/okiw4n/Documents/project/light_script:
total used in directory 20 available 339.2 GiB
drwxr-xr-x. 2 okiw4n okiw4n 4096 Sep 7 09:07 .
drwxr-xr-x. 3 okiw4n okiw4n 4096 Sep 4 10:03 ..
-rw-r--r--. 1 okiw4n okiw4n 3594 Sep 7 08:39 explication.org
-rw-r--r--. 1 okiw4n okiw4n 85 Sep 4 10:09 script.sh
-rw-r--r--. 1 okiw4n okiw4n 3594 Sep 5 20:08 tuc.org~
after:
/home/okiw4n/Documents/project/light_script:
total used in directory 20 available 339.2 GiB
drwxr-xr-x. 2 okiw4n okiw4n 4096 Sep 7 09:07 .
drwxr-xr-x. 3 okiw4n okiw4n 4096 Sep 4 10:03 ..
-rw-r--r--. 1 okiw4n okiw4n 3594 Sep 7 08:39 explication.org
-rw-r--r--. 1 okiw4n okiw4n 85 Sep 4 10:09 script.sh
-rw-r--r--. 1 okiw4n okiw4n 3594 Sep 5 20:08 TRUC.org~ (I have rewrite this file)
C-x C-s
(for save the changes)
C-x C-k
(kill the buffer and return to the file).
Upvotes: 3
Reputation: 81
I didn't find any of the proposed solutions sufficient for my needs (buffer selection, overwrite confirmation, fast response, actually working etc.), here's what I'm using:
(defun rename-buffer-and-file (buffer newname)
(interactive "bRename buffer and its visiting file: \nFNew name: ")
(let ((oldname (buffer-file-name)))
(if (not oldname)
(message "Buffer '%s' is not visiting a file" buffer)
(if (file-exists-p newname)
(if (file-directory-p newname)
;; Signal an error if the user specified the name of an
;; existing directory.
(error "%s is a directory" newname)
(unless (y-or-n-p (format-message
"File `%s' exists; overwrite? "
newname))
(error "Canceled"))))
;; Rename buffer and its visiting file
(set-visited-file-name newname)
;; Delete old file
(delete-file oldname)
(save-buffer))))
bound to C-x C-r
for convenience with
(global-set-key (kbd "C-x C-r") 'rename-buffer-and-file)
Upvotes: 0
Reputation: 162
The excellent crux
package has crux-rename-file-and-buffer
(along with many other useful functions).
Upvotes: 5
Reputation: 1888
Emacs 26.3 (2020-04-03) has rename-file
function which can be invoked using M-x rename-file
for renaming the current file or any other file for that matter.
Upvotes: 6
Reputation: 55989
Yes, with dired
mode, you can:
C-x d
to open diredRET
to select directory of current fileC-x C-j
(dired-jump
to the name of the current file, in Dired)R
to rename the file (or dired-do-rename
). q
to go back to the (renamed) file bufferThe rename is equivalent to a shell mv
, but it will also update any open buffers, and unlike mv
it will not change the access and modify times on the file in the filesystem.
Upvotes: 401
Reputation: 4665
If you're using Spacemacs then you get this behavior for free since it comes with an implementation of rename-current-buffer-file
(based on magnars) that by default bound to SPC-f-R
.
Upvotes: 11
Reputation: 91
There is a way very easy, you press the command M-x and than type vc-rename-file, after that you just need to select your current file at the directory, and than choose the new name. The buff that has the changed file will be refreshed.
Source:https://www.gnu.org/software/emacs/manual/html_node/emacs/VC-Delete_002fRename.html
Upvotes: 9
Reputation: 726
Here's a more robust version adapted from 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))
Upvotes: 15
Reputation: 31908
My favorite is the one from Magnars (of emacs rocks screencasts fame.)
Unlike the other alternatives, you don't have to type the name out from scratch - you get the current name to modify.
(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)))))))
Thanks to James Yang for a correct version.
Upvotes: 34
Reputation: 1416
based on magnars version, I modified as below, fixed the INIT file name part:
(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)))))))
Upvotes: 5
Reputation: 23624
Try this function from Steve Yegge's .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))))))
Take a look at that page, there's another really useful related function there, called "move-buffer-file".
Upvotes: 96
Reputation: 56595
Here's another version, that's pretty robust and VC aware:
(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)))))))
You can read more about it here.
Upvotes: 13
Reputation: 227
It can be achieved by copy. shift+c on the file and emacs will ask you to denote a name for the path including the file name, so you just provide the new name,and enter...of course, you have to Delete the former one.
Upvotes: -2
Reputation: 1363
Just for completeness, since some folks may visit this page thinking they will get an answer for the "save as" feature of Emacs, that's C-x C-w for an open file.
Upvotes: 133