Emacs'de yeni bir dosya oluştururken bulunmayan dizinler oluşturabilir miyim?


29

Emacs'de Cx Cf ile ziyaret ederek bir dosya oluşturuyorum. Diyelim ki oluşturmak istiyorum /home/myself/new_directory/file.txt.

Eğer new_directory henüz mevcut değilse, file.txtherhangi bir ilave adım atılmadan yaratılması için bir yol var mı? ( -pBayrakları mkdirLinux'ta kullanmak gibi bir şey düşünüyorum .)

Bunu yapabilen Cx Cf yerine farklı bir tuş vuruşu olduğunu hissediyorum, ancak ne olduğunu hatırlayamıyorum.


Düzenleme işlemi sırasında emacs komutunu aşmak için eşdeğer yoktur ?? :!mkdir -p ~/new_dir/to/some/crazy/path
vi'de

3
@DaveParillo: Tabii ki var M-!.
Nikana Reklawyks,

Prelude ( github.com/bbatsov/prelude ) eklentisini kullanıyorum. Ne zaman yukarıdaki gibi dosyalar oluştursam, bana "Dizin oluştur ..." komutunu veriyor. Sadece "y" yi seçebilirim. Sonra, bana "Dosya yok, oluştur? (Y veya n))" diye sordu. Yeni bir dosya oluşturan y'yi seçiyorum. Dosyayı kaydettiğimde yukarıdaki bilgileri içeren dosyayı oluşturur.
Pramod

Yanıtlar:


25

Ayrıca, find-filegerekli dizinleri şeffaf bir şekilde oluşturma fonksiyonunu da önerebilirsiniz .

(defadvice find-file (before make-directory-maybe (filename &optional wildcards) activate)
  "Create parent directory if not exists while visiting file."
  (unless (file-exists-p filename)
    (let ((dir (file-name-directory filename)))
      (unless (file-exists-p dir)
        (make-directory dir)))))

Bunu bir yerinize koyun .emacsve C-x C-fher zamanki gibi kullanın .


2
Harika bir çözüm. Küçük şeyleri iyileştirmenin, emacs'a işleri daha iyi hale getirebilmesi için yepyeni bir ipucu dünyasını nasıl açabileceğini seviyorum (evet, daha defadviceönce bilmiyordum ).
Nikana Reklawyks

18

Varolmayan bir bileşeni olan bir yol adı sağladığımda , find-file(yani Cx Cf ),

Dizini ve ailesini oluşturmak için Mx make-directory RET RET kullanın.

Tamponu ilk alana kadar dosya oluşturulmadığından make-directory, yeni tampon belleğiniz ortaya çıktıktan hemen sonra çalıştırılabilir veya dosyayı kaydetmeden önce başka bir zaman yapabilirsiniz. Sonra bir dizine ihtiyaç duyan arabellekten Mx make-directory RET RET yazın (dizinin yaratılmasını isteyecektir (varsayılan arabellek yolundan türetilir); ikinci RET varsayılanı kabul eder).


14

Ido modu sağlayan ido-find-fileBunun yerine geçer find-fileve size çok daha fazla özellik sunar. Örneğin, bu arada dosyayı açarken yeni bir dizin oluşturmanıza izin verir.

  • Tip C-x C-f(ki tekrar-eşlenmektedir zamanki gibi ido-find-file,)

  • var olmayan yolu sağlamak,

  • Basın M-myeni dizin oluşturmak için istemde bulunur,

  • ve sonra yeni oluşturulan dizinde ziyaret edilecek dosya adını belirtin.


Anlayamadım: neden M-mbir noktada basın ve C-x C-feğer bu her şeyi otomatik olarak yaratmıyorsa? Dizinin oluşturulması istenirse M-! mkdirveya yönlendirilirse , adil bir iş
çıkarır

ido-find-fileDizini otomatik olarak oluşturmanın bir yolu var mı? Ya da daha iyisi, oluşturmak isteyip istemediğimi sor. Török Gábor'un cevabındaki tavsiyeyi kullanmayı denedim, ancak hangi işlevi uygulayacağını bulamadım (ido find-filedoğrudan aramadığı için .
Troy Daniels

1

Benim çözümüm bir bonusla birlikte geliyor: arabelleği kaydetmeden öldürürseniz, Emacs oluşturulmuş boş dizinleri silmeyi teklif eder (ancak siz çağırmadan önce mevcut değilse find-file):

;; Automatically create any nonexistent parent directories when
;; finding a file. If the buffer for the new file is killed without
;; being saved, then offer to delete the created directory or
;; directories.

(defun radian--advice-find-file-automatically-create-directory
    (original-function filename &rest args)
  "Automatically create and delete parent directories of files.
This is an `:override' advice for `find-file' and friends. It
automatically creates the parent directory (or directories) of
the file being visited, if necessary. It also sets a buffer-local
variable so that the user will be prompted to delete the newly
created directories if they kill the buffer without saving it."
  ;; The variable `dirs-to-delete' is a list of the directories that
  ;; will be automatically created by `make-directory'. We will want
  ;; to offer to delete these directories if the user kills the buffer
  ;; without saving it.
  (let ((dirs-to-delete ()))
    ;; If the file already exists, we don't need to worry about
    ;; creating any directories.
    (unless (file-exists-p filename)
      ;; It's easy to figure out how to invoke `make-directory',
      ;; because it will automatically create all parent directories.
      ;; We just need to ask for the directory immediately containing
      ;; the file to be created.
      (let* ((dir-to-create (file-name-directory filename))
             ;; However, to find the exact set of directories that
             ;; might need to be deleted afterward, we need to iterate
             ;; upward through the directory tree until we find a
             ;; directory that already exists, starting at the
             ;; directory containing the new file.
             (current-dir dir-to-create))
        ;; If the directory containing the new file already exists,
        ;; nothing needs to be created, and therefore nothing needs to
        ;; be destroyed, either.
        (while (not (file-exists-p current-dir))
          ;; Otherwise, we'll add that directory onto the list of
          ;; directories that are going to be created.
          (push current-dir dirs-to-delete)
          ;; Now we iterate upwards one directory. The
          ;; `directory-file-name' function removes the trailing slash
          ;; of the current directory, so that it is viewed as a file,
          ;; and then the `file-name-directory' function returns the
          ;; directory component in that path (which means the parent
          ;; directory).
          (setq current-dir (file-name-directory
                             (directory-file-name current-dir))))
        ;; Only bother trying to create a directory if one does not
        ;; already exist.
        (unless (file-exists-p dir-to-create)
          ;; Make the necessary directory and its parents.
          (make-directory dir-to-create 'parents))))
    ;; Call the original `find-file', now that the directory
    ;; containing the file to found exists. We make sure to preserve
    ;; the return value, so as not to mess up any commands relying on
    ;; it.
    (prog1 (apply original-function filename args)
      ;; If there are directories we want to offer to delete later, we
      ;; have more to do.
      (when dirs-to-delete
        ;; Since we already called `find-file', we're now in the buffer
        ;; for the new file. That means we can transfer the list of
        ;; directories to possibly delete later into a buffer-local
        ;; variable. But we pushed new entries onto the beginning of
        ;; `dirs-to-delete', so now we have to reverse it (in order to
        ;; later offer to delete directories from innermost to
        ;; outermost).
        (setq-local radian--dirs-to-delete (reverse dirs-to-delete))
        ;; Now we add a buffer-local hook to offer to delete those
        ;; directories when the buffer is killed, but only if it's
        ;; appropriate to do so (for instance, only if the directories
        ;; still exist and the file still doesn't exist).
        (add-hook 'kill-buffer-hook
                  #'radian--kill-buffer-delete-directory-if-appropriate
                  'append 'local)
        ;; The above hook removes itself when it is run, but that will
        ;; only happen when the buffer is killed (which might never
        ;; happen). Just for cleanliness, we automatically remove it
        ;; when the buffer is saved. This hook also removes itself when
        ;; run, in addition to removing the above hook.
        (add-hook 'after-save-hook
                  #'radian--remove-kill-buffer-delete-directory-hook
                  'append 'local)))))

;; Add the advice that we just defined.
(advice-add #'find-file :around
            #'radian--advice-find-file-automatically-create-directory)

;; Also enable it for `find-alternate-file' (C-x C-v).
(advice-add #'find-alternate-file :around
            #'radian--advice-find-file-automatically-create-directory)

;; Also enable it for `write-file' (C-x C-w).
(advice-add #'write-file :around
            #'radian--advice-find-file-automatically-create-directory)

(defun radian--kill-buffer-delete-directory-if-appropriate ()
  "Delete parent directories if appropriate.
This is a function for `kill-buffer-hook'. If
`radian--advice-find-file-automatically-create-directory' created
the directory containing the file for the current buffer
automatically, then offer to delete it. Otherwise, do nothing.
Also clean up related hooks."
  (when (and
         ;; Stop if there aren't any directories to delete (shouldn't
         ;; happen).
         radian--dirs-to-delete
         ;; Stop if `radian--dirs-to-delete' somehow got set to
         ;; something other than a list (shouldn't happen).
         (listp radian--dirs-to-delete)
         ;; Stop if the current buffer doesn't represent a
         ;; file (shouldn't happen).
         buffer-file-name
         ;; Stop if the buffer has been saved, so that the file
         ;; actually exists now. This might happen if the buffer were
         ;; saved without `after-save-hook' running, or if the
         ;; `find-file'-like function called was `write-file'.
         (not (file-exists-p buffer-file-name)))
    (cl-dolist (dir-to-delete radian--dirs-to-delete)
      ;; Ignore any directories that no longer exist or are malformed.
      ;; We don't return immediately if there's a nonexistent
      ;; directory, because it might still be useful to offer to
      ;; delete other (parent) directories that should be deleted. But
      ;; this is an edge case.
      (when (and (stringp dir-to-delete)
                 (file-exists-p dir-to-delete))
        ;; Only delete a directory if the user is OK with it.
        (if (y-or-n-p (format "Also delete directory `%s'? "
                              ;; The `directory-file-name' function
                              ;; removes the trailing slash.
                              (directory-file-name dir-to-delete)))
            (delete-directory dir-to-delete)
          ;; If the user doesn't want to delete a directory, then they
          ;; obviously don't want to delete any of its parent
          ;; directories, either.
          (cl-return)))))
  ;; It shouldn't be necessary to remove this hook, since the buffer
  ;; is getting killed anyway, but just in case...
  (radian--remove-kill-buffer-delete-directory-hook))

(defun radian--remove-kill-buffer-delete-directory-hook ()
  "Clean up directory-deletion hooks, if necessary.
This is a function for `after-save-hook'. Remove
`radian--kill-buffer-delete-directory-if-appropriate' from
`kill-buffer-hook', and also remove this function from
`after-save-hook'."
  (remove-hook 'kill-buffer-hook
               #'radian--kill-buffer-delete-directory-if-appropriate
               'local)
  (remove-hook 'after-save-hook
               #'radian--remove-kill-buffer-delete-directory-hook
               'local))

Kanonik versiyonu burada .


0

@Chris'in Mx make-directory önerisine ek olarak, find-file ve sonra make-directory yapacak kısa bir elisp işlevi yazabilirsiniz ... Bunu deneyebilirsiniz:

(defun bp-find-file(filename &optional wildcards)
  "finds a file, and then creates the folder if it doesn't exist"

  (interactive (find-file-read-args "Find file: " nil))
  (let ((value (find-file-noselect filename nil nil wildcards)))
    (if (listp value)
    (mapcar 'switch-to-buffer (nreverse value))
      (switch-to-buffer value)))
  (when (not (file-exists-p default-directory))
       (message (format "Creating  %s" default-directory))
       (make-directory default-directory t))
  )

Güzel değil ve "Dizini oluştur ..." demeden önce "it MX make-dizini ...." u yanıp söner, ancak başka bir şey yoksa, size bir başlangıç ​​yapmalıdır.


2
Bu yaklaşım durumunda, find-fileyeni bir tanım tanımlamak yerine orijinal fonksiyona tavsiyede bulunmak daha iyidir, böylece find-filedoğrudan çağrı yapan diğer fonksiyonlar değiştirilmiş davranıştan bile faydalanabilir.
Török Gábor

ancak find-file bunu yapmak için söyleyebilecek herhangi bir argüman almıyor gibi görünüyor ... find-file-hook'larda yapabileceğiniz yararlı bir şey olmadığı sürece ...
Brian Postow


0
(make-directory "~/bunch/of/dirs" t)

Dizinleriniz zaten varsa, sadece bir uyarı verecektir.

( C-h f make-directory RET) Kılavuzundan:

make-directory etkileşimli bir derlenmiş Lisp işlevidir.

(make-directory DIR &optional PARENTS)

Dizini DIRve isteğe bağlı olarak mevcut olmayan üst dizinleri oluşturun. Eğer DIRzaten bir dizin olarak mevcutsa, PARENTSsıfır olmadıkça bir hatayı işaretleyin .

Etkileşimsel olarak, oluşturulacak varsayılan dizin seçimi, geçerli arabelleğin varsayılan dizinidir. Varolmayan bir dizindeki bir dosyayı ziyaret ettiğinizde bu kullanışlıdır.

Geçişsiz olarak, ikinci (isteğe bağlı) argüman PARENTS, eğer sıfır değilse, var olmayan üst dizinlerin yaratılıp yaratılmayacağını söyler. Etkileşimsel olarak, bu varsayılan olarak gerçekleşir.

Dizin veya dizin oluşturma işlemi başarısız olursa, bir hata ortaya çıkar.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.