Bagaimana cara saya mengganti nama file yang terbuka di Emacs?

237

Apakah ada cara untuk mengganti nama file yang terbuka di Emacs? Saat saya melihatnya? Sesuatu seperti save-as, tetapi yang asli harus pergi.

pupeno
sumber

Jawaban:

88

Coba fungsi ini dari .emacs Steve Yegge :

;; sumber: http://steve.yegge.googlepages.com/my-dot-emacs-file
(defun rename-file-and-buffer (nama-baru)
  "Mengganti nama buffer saat ini dan mengajukan kunjungan ke NEW-NAME."
  (interaktif "sNew name:")
  (let ((nama (nama penyangga)))
        (nama file (nama file buffer))))
    (jika (bukan nama file)
        (pesan "Buffer '% s' tidak mengunjungi file!" nama)
      (if (get-buffer-new-name)
          (pesan "Buffer bernama '% s' sudah ada!" nama baru)
        (progn
          (ganti nama file nama file nama baru 1)
          (ganti nama-buffer nama-baru)
          (set-visited-file-nama-nama baru)
          (set-buffer-modified-p nil))))))

Lihatlah halaman itu, ada fungsi terkait yang sangat berguna di sana, yang disebut "move-buffer-file".

Matt Curtis
sumber
1
Catatan: metode ini tidak kompatibel dengan (setq uniquify-buffer-name-style 'forward)makna jika Anda memiliki penyangga bernama users\index.html(karena Anda sudah memiliki penyangga lainnya posts\index.html) pengubahan nama akan gagal
dolzenko
(set-buffer-modified-p nil)sepertinya tidak perlu. Jika Anda memanggil rename-file-and-bufferbuffer yang dimodifikasi dan kemudian mencoba membunuhnya, ia akan dengan senang hati melakukannya tanpa memperingatkan Anda tentang perubahan yang belum disimpan.
roldugin
Fungsi ini juga akan (agak mengganggu) meminta Anda untuk nama baru sebelum memeriksa apakah buffer saat ini terkait dengan file sama sekali (dalam hal ini dibatalkan).
Thomas
338

Ya, dengan diredmode, Anda dapat:

  • C-x d untuk membuka dired
  • RET untuk memilih direktori file saat ini
  • C-x C-j( dired-jumpke nama file saat ini, dalam Dired)
  • Runtuk mengganti nama file (atau dired-do-rename).
  • q untuk kembali ke buffer file (diganti namanya)

Ganti nama sama dengan shell mv, tetapi itu juga akan memperbarui buffer terbuka, dan tidak seperti mvitu tidak akan mengubah akses dan memodifikasi waktu pada file di sistem file.

Chris Conway
sumber
9
Itu tidak secara langsung mengganti nama file saat ini.
pupeno
4
Cx b dan Anda kembali ke buffer asli. Anda dapat menulis fungsi Elisp untuk melakukannya, tetapi saya ragu Anda akan menghemat banyak penekanan tombol dengannya.
Chris Conway
6
Selain itu, daripada Cx b, Anda dapat menekan Cx k untuk kembali ke buffer asli.
Yoo
32
Secara C-x C-jdefault tidak terikat untuk saya. Melakukan M-x load-library RET dired-x RETlebih dulu membuatnya terikat.
ntc2
4
Alternatif lain jika C-x C-jtidak terikat hanya dilakukan M-x dired-jumppada saat pertama. Ini akan secara otomatis memuat dired-x(yang juga akan menyebabkan C-x C-jdidefinisikan sejak saat ini).
Fernando Basso
120

Hanya untuk kelengkapan, karena beberapa orang dapat mengunjungi halaman ini dengan berpikir bahwa mereka akan mendapatkan jawaban untuk fitur "save as" dari Emacs, itu Cx Cw untuk file yang terbuka.

Jim G
sumber
Cx Cw atau gunakan menuFile > Save as...
Yoo
Tidak cukup "simpan sebagai", karena file yang Anda edit masih akan menjadi yang asli.
penanggung jawab
11
@asmeurer Anda salah! Setelah menyimpan, Anda akan mengedit file baru.
Joel G Mathew
3
Sekali lagi, mengapa tidak ada fitur untuk menurunkan komentar ?!
Bearfriend
7
Mungkin asmeurer berarti, "file yang sedang Anda edit masih akan [ada]". Lalu, apakah itu benar? Saya akan memeriksa, tetapi kemudian, Anda tidak dapat menurunkan komentar saya, hahaha.
Brady Trainor
25

Favorit saya adalah yang dari Magnar (dari emacs rocks screencasts fame.)

Berbeda dengan alternatif lain, Anda tidak perlu mengetikkan nama dari awal - Anda dapat mengubah nama saat ini.

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

Terima kasih kepada James Yang untuk versi yang benar.

Kucing Unfun
sumber
Ini TIDAK berfungsi dengan baik. Yang ini menambahkan "/" di akhir file.
mitos pembuat
2
Terima kasih telah mengirimkannya untuk saya. Cara SO adalah mengoreksi jawaban, bukan memposting yang baru, yang sedikit dimodifikasi.
The Unfun Cat
15

Inilah versi yang lebih kuat yang diadaptasi dari 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
sumber
Bagus Sekarang dinginkan di functions.el saya.
Felix D.
11

Ini versi lain, cukup tangguh dan VC sadar:

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

Anda dapat membaca lebih lanjut di sini .

Bozhidar Batsov
sumber
4

Ada cara yang sangat mudah, Anda menekan perintah Mx dan dari ketik vc-rename-file , setelah itu Anda hanya perlu memilih file Anda saat ini di direktori, dan daripada memilih nama baru. Buff yang memiliki file yang diubah akan di-refresh.

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

Rafael Nascimento
sumber
1
Ini memiliki efek samping (tidak selalu diinginkan) dengan menambahkan file lama dan baru untuk dikomit ke dalam kontrol versi. Tapi +1 karena ia menggunakan fungsi bawaan untuk (kebanyakan) menjawab pertanyaan OP.
dinosaurus
3

berdasarkan versi magnars, saya memodifikasi seperti di bawah ini, memperbaiki bagian nama file 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
sumber
Yang ini lebih baik. Versi magnars yang diberikan di atas TIDAK berfungsi dengan baik. Tambahkan "/" karakter pada akhir
mythicalcoder
-1

Itu bisa dicapai dengan copy. shift + c pada file dan emacs akan meminta Anda untuk menunjukkan nama untuk path termasuk nama file, jadi Anda cukup memberikan nama baru, dan masukkan ... tentu saja, Anda harus Hapus yang sebelumnya.

Eric_Chen
sumber
1
Anda tampaknya merujuk ke "C" dalam mode dired? Itu menyalin file, bukan mengganti nama, yang (seperti dicatat @ChrisConway) di dired dilakukan dengan "R". Dan selain itu, OP meminta nama penyangga saat ini.
Davor Cubranic