Comment renommer un fichier ouvert dans Emacs?

237

Existe-t-il un moyen de renommer un fichier ouvert dans Emacs? Pendant que je le regarde? Quelque chose comme enregistrer sous, mais l'original devrait disparaître.

pupeno
la source

Réponses:

88

Essayez cette fonction du .emacs de Steve Yegge :

;; source: http://steve.yegge.googlepages.com/my-dot-emacs-file
(defun rename-file-and-buffer (nouveau-nom)
  "Renomme à la fois le tampon actuel et le fichier visité par NEW-NAME."
  (interactif "sNouveau nom:")
  (let ((nom (nom-tampon))
        (nom de fichier (nom-fichier-tampon)))
    (si (pas le nom de fichier)
        (message "Le tampon '% s' ne visite pas un fichier!" nom)
      (if (get-buffer new-name)
          (message "Un tampon nommé '% s' existe déjà!" nouveau-nom)
        (progn
          (rename-file nom de fichier nouveau-nom 1)
          (nouveau nom du tampon de renommage)
          (nom-de-fichier-ensemble-nouveau-nom)
          (set-buffer-modified-p nil))))))

Jetez un oeil à cette page, il y a une autre fonction connexe vraiment utile, appelée "move-buffer-file".

Matt Curtis
la source
1
Remarque: cette méthode n'est pas compatible avec le (setq uniquify-buffer-name-style 'forward)sens si vous avez un tampon nommé users\index.html(car vous avez déjà un autre tampon pour posts\index.html) le changement de nom échouera
dolzenko
(set-buffer-modified-p nil)semble inutile. Si vous avez appelé rename-file-and-bufferun tampon modifié puis tenté de le tuer, il le ferait avec plaisir sans vous avertir des modifications non enregistrées.
roldugin
Cette fonction vous demandera également (un peu ennuyeux) un nouveau nom avant de vérifier si le tampon actuel est associé à un fichier (auquel cas il abandonne).
Thomas
338

Oui, avec le diredmode, vous pouvez:

  • C-x d ouvrir dired
  • RET pour sélectionner le répertoire du fichier actuel
  • C-x C-j( dired-jumpau nom du fichier actuel, en Dired)
  • Rpour renommer le fichier (ou dired-do-rename).
  • q pour revenir au tampon de fichiers (renommé)

Le renommage équivaut à un shell mv, mais il mettra également à jour tous les tampons ouverts, et contrairement à mvcela, il ne changera pas les accès et les heures de modification du fichier dans le système de fichiers.

Chris Conway
la source
9
Ce n'est pas renommer directement le fichier actuel.
pupeno
4
Cx b et vous êtes de retour dans le tampon d'origine. Vous pouvez écrire une fonction Elisp pour le faire, mais je doute que vous économisiez de nombreuses frappes avec.
Chris Conway
6
De plus, plutôt que Cx b, vous pouvez appuyer sur Cx k pour revenir dans le tampon d'origine.
Yoo
32
Le C-x C-jn'est pas lié par défaut pour moi. Faire d' M-x load-library RET dired-x RETabord le rend lié.
ntc2
4
Une autre alternative si C-x C-jnon lié est de le faire M-x dired-jumpla première fois. Il se chargera automatiquement dired-x(ce qui entraînera également C-x C-jsa définition à partir de ce moment).
Fernando Basso
120

Juste pour être complet, puisque certaines personnes peuvent visiter cette page en pensant qu'elles obtiendront une réponse pour la fonction "enregistrer sous" d'Emacs, c'est Cx Cw pour un fichier ouvert.

Jim G
la source
Cx Cw ou utilisez le menuFile > Save as...
Yoo
Pas tout à fait "enregistrer sous", car le fichier que vous éditez sera toujours l'original.
asmeurer
11
@asmeurer Vous vous trompez! Après l'enregistrement, vous éditez le nouveau fichier.
Joel G Mathew
3
Encore une fois, pourquoi n'y a-t-il pas de fonction pour réduire les commentaires?!
bearfriend
7
Peut-être asmeurer voulait-il dire, "le fichier que vous [éditiez] éditera toujours [existera]". Alors, c'est bien ça? Je voudrais vérifier, mais alors, vous ne pouvez pas dévaloriser mon commentaire, hahaha.
Brady Trainor
25

Mon préféré est celui de Magnars (of emacs rocks screencasts fame.)

Contrairement aux autres alternatives, vous n'avez pas à taper le nom à partir de zéro - vous obtenez le nom actuel à modifier.

(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)))))))

Merci à James Yang pour une version correcte.

Le chat unfun
la source
Cela ne fonctionne PAS correctement. Celui-ci ajoute un "/" à la fin du fichier.
mythicalcoder
2
Merci d'avoir posté ça pour moi. La manière SO consiste à corriger les réponses, pas à en publier de nouvelles, légèrement modifiées.
The Unfun Cat
15

Voici une version plus robuste adaptée de 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))
Shawn Hoover
la source
Joli. Maintenant refroidir dans mes fonctions.el.
Felix D.18
11

Voici une autre version, assez robuste et compatible 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)))))))

Vous pouvez en lire plus ici .

Bozhidar Batsov
la source
4

Il existe un moyen très simple, vous appuyez sur la commande Mx et tapez vc-rename-file , après cela il vous suffit de sélectionner votre fichier actuel dans le répertoire, puis de choisir le nouveau nom. Le buff contenant le fichier modifié sera actualisé.

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

Rafael Nascimento
la source
1
Cela a pour effet secondaire (pas nécessairement souhaitable) d'ajouter les anciens et les nouveaux fichiers à valider dans le contrôle de version. Mais +1 car il utilise une fonction intégrée pour (principalement) répondre à la question de l'OP.
dinosaure
3

basé sur la version de magnars, j'ai modifié comme ci-dessous, corrigé la partie du nom de fichier 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)))))))
James Yang
la source
Celui ci est mieux. La version Magnars indiquée ci-dessus ne fonctionne PAS correctement. Ajouter un caractère "/" à la fin
mythicalcoder
-1

Il peut être réalisé par copie. shift + c sur le fichier et emacs vous demandera d'indiquer un nom pour le chemin d'accès, y compris le nom du fichier, vous devez donc simplement fournir le nouveau nom et entrer ... bien sûr, vous devez supprimer l'ancien.

Eric_Chen
la source
1
Vous semblez faire référence à "C" en mode Dired? C'est copier le fichier, pas le renommer, ce qui (comme l'a noté @ChrisConway) en dired se fait avec "R". Et d'ailleurs, OP a demandé un changement de nom du tampon actuel.
Davor Cubranic