Como renomear um arquivo aberto no Emacs?

237

Existe uma maneira de renomear um arquivo aberto no Emacs? Enquanto eu estou vendo? Algo como salvar como, mas o original deve desaparecer.

pupeno
fonte

Respostas:

88

Tente esta função no arquivo .emacs de Steve Yegge :

;; fonte: http://steve.yegge.googlepages.com/my-dot-emacs-file
(renomear arquivo-renomear-e-buffer (novo nome)
  "Renomeia o buffer atual e o arquivo que está visitando para NEW-NAME."
  (interativo "sNew name:")
  (let ((nome (nome do buffer)))
        (nome do arquivo (nome do arquivo-buffer)))
    (se (não o nome do arquivo)
        (mensagem "Buffer '% s' não está visitando um arquivo!" nome)
      (if (get-buffer new-name)
          (mensagem "Um buffer denominado '% s' já existe!" new-name)
        (progn
          (renomeie o arquivo nome do arquivo novo nome 1)
          (renomear-buffer novo nome)
          (nome do arquivo visitado-conjunto nome-novo)
          (conjunto-tampão-modificado-p nil))))))

Dê uma olhada nessa página, há outra função relacionada realmente útil, chamada "move-buffer-file".

Matt Curtis
fonte
1
Nota: este método não é compatível com o (setq uniquify-buffer-name-style 'forward)significado se você tiver um buffer nomeado users\index.html(porque você já possui outro buffer para posts\index.html) a renomeação falhará
dolzenko
(set-buffer-modified-p nil)parece desnecessário. Se você chamasse rename-file-and-bufferum buffer modificado e tentasse matá-lo, ele o faria feliz sem avisar sobre alterações não salvas.
Rdugin
Essa função também solicita (um pouco irritante) um novo nome antes de verificar se o buffer atual está associado a um arquivo (nesse caso, ele é abortado).
Thomas
338

Sim, com o diredmodo, você pode:

  • C-x d abrir dired
  • RET para selecionar o diretório do arquivo atual
  • C-x C-j( dired-jumppara o nome do arquivo atual, em Dired)
  • Rrenomear o arquivo (ou dired-do-rename).
  • q para voltar ao buffer de arquivo (renomeado)

A renomeação é equivalente a um shell mv, mas também atualiza os buffers abertos e, ao contrário mv, não altera os tempos de acesso e modificação no arquivo no sistema de arquivos.

Chris Conway
fonte
9
Isso não está renomeando diretamente o arquivo atual.
pupeno
4
Cx be você está de volta no buffer original. Você pode escrever uma função Elisp para fazer isso, mas duvido que você salve muitas teclas pressionadas com ela.
Chris Conway
6
Além disso, em vez de Cx b, você pode pressionar Cx k para voltar ao buffer original.
Yoo
32
O C-x C-jnão está vinculado por padrão para mim. Fazer M-x load-library RET dired-x RETprimeiro o torna vinculado.
Ntc2 31/10/2013
4
Outra alternativa, se C-x C-jnão estiver ligada, é apenas fazer M-x dired-jumpna primeira vez. Ele será carregado automaticamente dired-x(o que também fará C-x C-jcom que seja definido a partir deste ponto).
Fernando Basso
120

Apenas para completar, já que algumas pessoas podem visitar esta página pensando que receberão uma resposta para o recurso "salvar como" do Emacs, que é o Cx Cw para um arquivo aberto.

Jim G
fonte
Cx Cw ou use o menuFile > Save as...
Yoo
Não é "salvar como", pois o arquivo que você está editando ainda será o original.
asmeurer
11
@asmeurer Você está errado! Após salvar, você estará editando o novo arquivo.
Joel G Mathew
3
Mais uma vez, por que não há um recurso para votar com desconfiança ?!
bearfriend
7
Talvez como memeurer quis dizer, "o arquivo que você estava editando ainda existirá". Então, isso está correto? Eu verificaria, mas então, você não pode rebater meu comentário, hahaha.
Brady Trainor
25

O meu favorito é o de Magnars (da fama dos screencasts de rochas do emacs ).

Ao contrário das outras alternativas, você não precisa digitar o nome do zero - é necessário modificar o nome atual.

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

Obrigado a James Yang pela versão correta.

The Unfun Cat
fonte
Isso NÃO está funcionando corretamente. Este adiciona um "/" no final do arquivo.
mythicalcoder
2
Obrigado por postar isso para mim. A maneira SO é corrigir as respostas, não publicar novas e ligeiramente modificadas.
The Unfun Cat
15

Aqui está uma versão mais 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
fonte
Agradável. Agora relaxando em minhas funções.el.
Felix D.
11

Aqui está outra versão, bastante robusta e com conhecimento de 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)))))))

Você pode ler mais sobre isso aqui .

Bozhidar Batsov
fonte
4

Existe uma maneira muito fácil: você pressiona o comando Mx e , em seguida, digite vc-rename-file , depois basta selecionar o arquivo atual no diretório e escolher o novo nome. O buff que possui o arquivo alterado será atualizado.

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

Rafael Nascimento
fonte
1
Isso tem o efeito colateral (não necessariamente desejável) de adicionar os arquivos antigos e novos a serem confirmados no controle de versão. Mas +1 porque usa uma função interna para (principalmente) responder à pergunta do OP.
dinossauro
3

com base na versão magnars, modifiquei como abaixo, corrigi a parte do nome do arquivo 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
fonte
Este é melhor. A versão dos magnares fornecida acima NÃO está funcionando corretamente. Adicione um caractere "/" no final
mythicalcoder
-1

Pode ser conseguido por cópia. shift + c no arquivo e o emacs solicitará que você indique um nome para o caminho, incluindo o nome do arquivo, para que você apenas forneça o novo nome e insira ... é claro, você deve excluir o antigo.

Eric_Chen
fonte
1
Você parece estar se referindo a "C" no modo direcionado? Isso é copiar o arquivo, não renomeá-lo, o que (como @ChrisConway observou) em dired é feito com "R". Além disso, o OP pediu uma renomeação do buffer atual.
Davor Cubranic