Pablo Fernandez
Pablo Fernandez

Reputation: 287410

How do I rename an open file in Emacs?

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

Answers (16)

stribb
stribb

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

Laurynas Biveinis
Laurynas Biveinis

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

0kiw4n
0kiw4n

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

zacho314
zacho314

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

Alan
Alan

Reputation: 162

The excellent crux package has crux-rename-file-and-buffer (along with many other useful functions).

Upvotes: 5

Jay Rajput
Jay Rajput

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

Chris Conway
Chris Conway

Reputation: 55989

Yes, with dired mode, you can:

  • C-x d to open dired
  • RET to select directory of current file
  • C-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 buffer

The 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

Jason Axelson
Jason Axelson

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.

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

Upvotes: 11

Rafael Nascimento
Rafael Nascimento

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

Shawn Hoover
Shawn Hoover

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

The Unfun Cat
The Unfun Cat

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

James Yang
James Yang

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

Matt Curtis
Matt Curtis

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

Bozhidar Batsov
Bozhidar Batsov

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

Eric_Chen
Eric_Chen

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

Jim G
Jim G

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

Related Questions