¿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.

pupeno
fuente

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".

Matt Curtis
fuente
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.

Chris Conway
fuente
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.

Jim G
fuente
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.

El gato no divertido
fuente
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))
Shawn Hoover
fuente
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í .

Bozhidar Batsov
fuente
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

Rafael Nascimento
fuente
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)))))))
James Yang
fuente
É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.

Eric_Chen
fuente
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