¿Cómo cambio el nombre de un archivo abierto en Emacs?


237

¿Hay alguna manera de cambiar el nombre de un archivo abierto en Emacs? Mientras lo estoy viendo? Algo así como guardar como, pero el original debería desaparecer.

Respuestas:


88

Pruebe esta función de .emacs de Steve Yegge :

;; fuente: http://steve.yegge.googlepages.com/my-dot-emacs-file
(defun rename-file-and-buffer (nombre-nuevo)
  "Renombra tanto el búfer actual como el archivo que está visitando a NEW-NAME".
  (interactivo "sNuevo nombre:")
  (let ((nombre (nombre del búfer))
        (nombre de archivo (nombre-archivo-búfer)))
    (if (no nombre de archivo)
        (mensaje "Buffer '% s' no está visitando un archivo!" nombre)
      (if (get-buffer new-name)
          (mensaje "¡Ya existe un buffer llamado '% s'!" new-name)
        (progn
          (renombrar-archivo nombrearchivo nuevo-nombre 1)
          (rename-buffer new-name)
          (nombre-archivo-visitado-nuevo nombre-nuevo)
          (set-buffer-modified-p nil))))))

Eche un vistazo a esa página, hay otra función relacionada realmente útil allí, llamada "move-buffer-file".


1
Nota: este método no es compatible con el (setq uniquify-buffer-name-style 'forward)significado si tiene un búfer llamado users\index.html(porque ya tiene otro búfer para posts\index.html), el cambio de nombre fallará
dolzenko

(set-buffer-modified-p nil)Parece innecesario Si solicitó rename-file-and-bufferun búfer modificado y luego intentó matarlo, lo haría felizmente sin advertirle sobre cambios no guardados.
roldugin

Esta función también le pedirá (algo molesto) un nuevo nombre antes de verificar si el búfer actual está asociado con un archivo (en cuyo caso se cancela).
Thomas

338

Sí, con el diredmodo, puedes:

  • C-x d abrir dired
  • RET para seleccionar el directorio del archivo actual
  • C-x C-j( dired-jumpal nombre del archivo actual, en Dired)
  • Rcambiar el nombre del archivo (o dired-do-rename).
  • q para volver al búfer de archivo (renombrado)

El cambio de nombre es equivalente a un shell mv, pero también actualizará cualquier búfer abierto y, a diferencia de mvesto, no cambiará el acceso ni modificará los tiempos del archivo en el sistema de archivos.


99
Eso no es renombrar directamente el archivo actual.
pupeno

44
Cx by estás de vuelta en el búfer original. Podrías escribir una función Elisp para hacerlo, pero dudo que guardes muchas pulsaciones de teclas con ella.
Chris Conway

66
Además, en lugar de Cx b, puede presionar Cx k para volver al búfer original.
Yoo

32
El C-x C-jno está vinculado por defecto para mí. Hacer M-x load-library RET dired-x RETprimero lo obliga.
ntc2

44
Otra alternativa si C-x C-jno está consolidada es simplemente hacerlo M-x dired-jumppor primera vez. Se cargará automáticamente dired-x(lo que también hará C-x C-jque se defina a partir de este punto).
Fernando Basso

120

Solo para completar, ya que algunas personas pueden visitar esta página pensando que obtendrán una respuesta para la función "guardar como" de Emacs, eso es Cx Cw para un archivo abierto.


Cx Cw o usa el menúFile > Save as...
Yoo

No exactamente "guardar como", ya que el archivo que está editando seguirá siendo el original.
Asmeurer

11
@asmeurer ¡Estás equivocado! Después de guardar, editará el nuevo archivo.
Joel G Mathew

3
Nuevamente, ¿por qué no hay una función para rechazar comentarios?
bearfriend

77
Quizás asmeurer quiso decir, "el archivo que [estabas] editando seguirá [existiendo]". Entonces, ¿es eso correcto? Lo comprobaría, pero no puedes rechazar mi comentario, jajaja.
Brady Trainor

25

Mi favorito es el de Magnars (de emacs rocks screencasts fame).

A diferencia de las otras alternativas, no tiene que escribir el nombre desde cero: obtiene el nombre actual para modificar.

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

Gracias a James Yang por una versión correcta.


Esto NO funciona correctamente. Este agrega un "/" al final del archivo.
mythicalcoder

2
Gracias por publicar eso para mí. La forma SO es corregir las respuestas, no publicar nuevas, ligeramente modificadas.
The Unfun Cat

15

Aquí hay una versión más robusta adaptada 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))

Buena esa. Ahora se relaja en mis funciones.
Felix D.

11

Aquí hay otra versión, que es bastante robusta y 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)))))))

Puedes leer más sobre esto aquí .



4

Hay una manera muy fácil, presionas el comando Mx y luego escribes vc-rename-file , después de eso solo necesitas seleccionar tu archivo actual en el directorio, y luego elegir el nuevo nombre. El beneficio que tiene el archivo modificado se actualizará.

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


1
Esto tiene el efecto secundario (no necesariamente deseable) de agregar los archivos antiguos y nuevos para confirmar en el control de versiones. Pero +1 porque usa una función integrada para (principalmente) responder la pregunta del OP.
dinosaurio

3

basado en la versión de Magnars, modifiqué como a continuación, arreglé la parte del nombre del archivo 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)))))))

Éste es mejor. La versión de magnars dada anteriormente NO funciona correctamente. Agregue un carácter "/" al final
mythicalcoder

-1

Se puede lograr mediante copia. shift + c en el archivo y emacs le pedirá que denote un nombre para la ruta, incluido el nombre del archivo, por lo que solo debe proporcionar el nuevo nombre e ingresar ... por supuesto, debe eliminar el anterior.


1
Parece que te refieres a "C" en el modo directo? Eso es copiar el archivo, no renombrarlo, lo que (como señaló @ChrisConway) en directo se hace con "R". Y además, OP solicitó un cambio de nombre del búfer actual.
Davor Cubranic
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.