Pierre Thierry
Pierre Thierry

Reputation: 5129

How can I create a file in a sub-directory in Emacs Dired?

I use dired to browse a directory and its sub-directories with i (dired-maybe-insert-subdir)

When the cursor is in a sub-directory, and I do C-x C-f, the default directory is the root of my buffer, is there a way to change that?

So if I visit /foo/bar and then I insert in bar's buffer the content of /foo/bar/baz and have my cursor there, get a mini-buffer with /foo/bar/baz/ when I ask to visit a file (with the default keybinding or another, that doesn't matter to me).

Upvotes: 2

Views: 870

Answers (3)

Lei Zhao
Lei Zhao

Reputation: 1156

The following is my own solution.

(defun dired-subdir-aware (orig-fun &rest args)
  (if (eq major-mode 'dired-mode)
      (let ((default-directory (dired-current-directory)))
        (apply orig-fun args))
    (apply orig-fun args)))

(advice-add 'find-file-read-args :around 'dired-subdir-aware)

I just learned how to use the advice function to augment existing functions (and macros). See (elisp) Advising Functions.

Now if you go to a subdir under dired and run C-x C-f, you will be prompted with a correct path.

Update:

Recently, I began to play with (ido) Top. With dired-subdir-aware defined, I easily extend ido-find-file to recognize subdir with the following code.

(dolist (fun '(find-file-read-args ido-expand-directory))
  (advice-add fun :around 'dired-subdir-aware))

Upvotes: 2

Pierre Thierry
Pierre Thierry

Reputation: 5129

I refined Drew's answer to a function that does exactly what I wanted:

(defun dired-find-file ()
  "Find a file in the current dired directory"
  (interactive)
  (let ((default-directory (dired-current-directory)))
    (find-file (read-file-name "Find file:"))))

I then bound this function to a convenient key combination:

(add-hook 'dired-mode-hook
   (lambda ()
     (local-set-key (kbd "C-x M-f") 'dired-find-file)))

Upvotes: 0

Drew
Drew

Reputation: 30701

No, default-directory is local to a buffer, not just part of a buffer. This is by design, and there is no way to change it.

But you could of course define a command that picks up the subdir directory and then binds default-directory to that while it reads a file name to visit, etc.).

For example, this command will read a file name with the default directory being what you want, and then visit that file:

(defun foo (file)
  "..."
  (interactive
   (let ((default-directory  (dired-current-directory)))
     (list (read-file-name "File: "))))
  (find-file file))

And, out of the box, you can certainly visit the subdir in another Dired buffer, where default-directory is what you want. Commands such as dired-do-find-marked-files (F) and dired-display-file (C-o) do that.

But why do you want default-directory to reflect the subdir whose listing you are in? What's your use case?

Upvotes: 1

Related Questions