recursively remove subdir from emacs dired - emacs

I often look at dired structures, showing the entire directory recursively, via: (dired dir "-lR"). This works great most of the time.
However, some times, there are huge sub-directory structures that Idon't want to look at. Is there a way to recursively kill a subdirectory in a dired buffer with a complete tree in it?

I use find-dired for the same purpose. To exclude a subdirectory, I enter something like this at the Run find (with args): prompt: -path ./exclude_me -prune -o true, which will give me a recursive listing of the directory excluding the one directory exclude_me. This only works if you're using a Unix-like with a function version of find though.
Edit: Another way to remove the tree is to simply toggle the dired buffer to readable (C-x C-q) and edit the buffer.

Ok, I just wrote the following elisp:
(defun bp-kill-directory-rec()
(interactive )
(let (
(i (point))
(cur-dir (dired-current-directory)))
(beginning-of-buffer)
(while (search-forward cur-dir nil t)
(dired-kill-subdir))
(goto-char i)))
Start with the cursor in the directory that you want to kill, and it will kill all subdirs of that directory. The trick is that (dired-current-directory) gives the entire path, so searching for that should only give the directories you want to kill. If you have a directory structure, where you have something like /home/a/b and also /home/c/d/home/a/b then bad things could happen. But you'd have to be kind of crazy to do that, no?

Use Dired+, command diredp-kill-this-tree.
Just put the cursor in a subdir that you want to remove from the listing, and invoke the command. That inserted subdir and all its descendents that are also inserted (listed) are removed.
You can invoke this command also in either of these ways, after putting point within a subdir listing:
Click mouse-3 and choose item Remove This Inserted Subdir and Lower.
Choose menu-bar menu Single (called Immediate in vanilla Emacs), item Remove This Inserted Subdir and Lower.

Related

How to go to a file quickly in Emacs Dired?

If a directory contains many files and I want to go to files(or subdirectories) with name starting with a letter (or a string), is there any good way to do it? I know in Far File Manager people can press Alt and start typing the name and the cursor will move as you type, I am wondering if Emacs has something similar.
The fastest way to answer this question is copying a section from the emacs info files.
To get to this text type C-h i d m emacs ret and then isearch for an appropriate substring ignoring the first Failing I-search or just go to info with C-h i and then directly go to the info node mentioned below with g and then typing the node name followed by ret.
The first from the info-node (emacs) Dired and Find works whether one is in a dired buffer or not:
To search for files with names matching a wildcard pattern use `M-x
find-name-dired'. It reads arguments DIRECTORY and PATTERN, and
chooses all the files in DIRECTORY or its subdirectories whose
individual names match PATTERN.
The second from the info-node (emacs) Dired Navigation works in dired buffers but only applies to the currently listed files. But, note that you can list subdirectories with i before.
`M-s f C-s' (`dired-isearch-filenames') performs a forward
incremental search in the Dired buffer, looking for matches only
amongst the file names and ignoring the rest of the text in the buffer.
`M-s f M-C-s' (`dired-isearch-filenames-regexp') does the same, using a
regular expression search. If you change the variable
`dired-isearch-filenames' to `t', then the usual search commands also
limit themselves to the file names; for instance, `C-s' behaves like
`M-s f C-s'. If the value is `dwim', then search commands match the
file names only when point was on a file name initially. *Note
Search::, for information about incremental search.
EDIT:
To isearch a directory recursively you may first list it recursively.
You can list sub-directories recursively by calling dired with prefix-arg and adding R to the list of switches.
The following snippet for the emacs initialization file would even simplify this task:
(defun dired-noselect-maybe-recursive (dir-or-list &optional switches)
"Like `dired-noselect' but lists sub-directories when last character is ?/."
(if (and (null switches)
(= (aref dir-or-list (1- (length dir-or-list))) ?/))
(dired-noselect dir-or-list "-alR")
(dired-noselect dir-or-list switches)
))
(setq find-directory-functions (subst 'dired-noselect-maybe-recursive 'dired-noselect find-directory-functions))
With this snippet you get a normal listing of directories if you call find-file (C-x C-f) for a directory without a slash at the end and you get a recursive listing if you call it with a slash at the end.
But be careful. Recursive directory listing can take its time. If you get nervous you can always quit with C-g.
isearch will do that. control-s, then start typing.
Since it's emacs' general-purpose search function, it could start out matching other things in the buffer until you get enough of the name in.
I just want to add a trick that I like to use that's
somewhat related to your question:
(add-hook
'dired-mode-hook
(lambda()
(define-key dired-mode-map "j" 'ido-find-file)))
Obviously it works for just one file, and it opens it, instead
of offering a multitude of things that dired can do to a file,
but at least it's fast.
#Tobias and #jl8e have both answered your question directly: use C-s (incremental search). Nothing to add to that.
But if you are going to be using a subset of the listed files multiple times, or you are going to perform the same operation on a subset of the files, and if that subset can be identified by a file-name pattern (e.g. same prefix), then you can use %m to mark all files matching a regexp. Once marked, you can do all kinds of things on the set of files marked (or on the set of those unmarked).
(One of the things you can do is just omit the marked or unmarked file names from the listing, and hence from operations.)
Dired is really mostly about examining and operating on sets of files. The singleton set is a special case, and all operations (keys) that operate on the marked files also operate on the current line's file only, if none are marked.

How do I find-file recursively in directories

Often, I know the file name but don't remember or find it cumbersome to specify the exactly directory. I'd like to be able to do:
find-file x/y/*/some_file.txt
where * would allow searching in recursive directories instead of just the current one.
As described here:
M-x find-name-dired
After you provide the directory and the pattern the matching files will be displayed in a Dired buffer. You can navigate the file list (C-n, C-p, etc.) and open files as you wish (Ret).
I've long looked for that feature and I'm now satisfied with what I found: I'm using helm-projectile.
Projectile is a project interaction library. Projects are VCS directories or directories containing a .projectile file. It is based on GNU find (but offers a pure emacs lisp implementation too)
https://github.com/bbatsov/projectile
(you can install it with packages.el). You can use it alone: call projectile-find-file (or projectile-mode and C-c p f). It uses ido for the completion by default, but in that case I prefer the interface of helm-projectile.
My colleagues kept telling me to use Sublime Text because of that feature. Fortunately, I found projectile :)
ido-find-file does this: when the filename that you enter doesn't match
anything in the current directory, it uses something like locate to match
what you wrote against all files on your system.
The setup is just one line:
(ido-mode)
After this, C-x C-f will call ido-find-file.
Also, I usually add:
(setq ido-enable-flex-matching t)
because I like it, but with it you will locate more results,
i.e. foo will also match froo.
In case of files in a project directory, I have used Fiplr that uses a fuzzy search library by the same author.
https://github.com/d11wtq/fiplr
This is available from MELPA.
Other solution that I haven't tried is https://github.com/technomancy/find-file-in-project
edit: I found much better with projectile, see my other answer.
There is find-recursive.el : http://www.webweavertech.com/ovidiu/emacs/find-recursive.txt
Download it, put it in your load path and require it in your .emacs: (it isn't available through ELPA or el-get)
(require 'find-recursive)
now when you call M-x find-recursive, it will ask for a file name to search for recursively, a base directory, then you have to select one file among a result list. It isn't integrated into ido unfortunately, but I like it, it is useful sometimes.
Here is a solution that gives you selectivity over the files and subdirectories searched. To use it you need both Dired+ and Icicles.
The command, used only in Dired, is icicle-visit-marked-file-of-content-recursive (or the -other-window version of it). It is bound to M-+ C-F (for other window, use M-+ C-O -- and yes, those are uppercase F and O).
What it does:
It provides, as candidates for completion, all of the files marked in the current Dired directory, pslus all of those in any marked subdirectories that have Dired buffers, and so on recursively.
You can visit any number of such candidates that match your minibuffer input, including all of them. You can visit some that match a minibuffer input pattern, then change the pattern to match and visit others --- all in the same command invocation.
"Matching" your input can mean either or both:
Matching the file name
Matching the file content
That is, your input can be two-part (separated by hitting C-M-j: a file-name part and a file-content part. Narrow the choices by matching file names, and narrow further by matching text in those files. This search is fast -- it succeeds as soon as it finds a single match in the file.
You can omit either part: match only file names (fast) or only file contents (slower, naturally).
You can combine input patterns -- progressive completion. It is much easier to add additional patterns to match, incrementally and interactively, than it is to try to come up with a single regexp that does just what you want.
Each input pattern (each part of a two-part pattern) can be a regexp. Fuzzy matching is also available.
You can alternatively just insert subdirectories in your Dired buffer, instead of having them as separate Dired buffers. Any files and subdirs marked in a Dired buffer are handled the same way.
If you do not want to descend into subdirs that are marked, you can use the non-recursive version of the command, icicle-visit-marked-file-of-content, bound to C-F (C-O for other-window).
If you also use Bookmark+ then you can bookmark a Dired buffer or a set of Dired buffers. The bookmark records which files and subdirectories are marked, which subdirectories are inserted, and which files and subdirectories are omitted. Jumping to such a bookmark restores all of these things. This gives you a way to snapshot a project, which you can then search using M-+ C-F etc.
A lot of options listed, I'm using next command:
find-file-in-current-directory
You can put it in your .emacs like this:
;; Find file in current directory:
(global-set-key (kbd "C-M-,") 'find-file-in-current-directory)
Interface looks very familiar to those who use fsf tools (https://github.com/junegunn/fzf)
If you have helm, you can use this:
(defun my/helm-find-file-recursively ()
"Recursively find files in glob manner, in the specified directory."
(interactive)
(helm-find 'ask-for-dir))
(global-set-key (kbd "C-c o f") 'my/helm-find-file-recursively)
Icicles command icicle-locate (or icicle-locate-file, if you do not have a locate program for your OS) is made for that. Locate a file anywhere under a given directory (including ~HOME or the root directory).
You can match against any parts of the absolute file name (i.e., the path and the file name). You can use several kinds of matching, including regexp, substring, and fuzzy matching.
For a more programmatic approach (using the built-in files library):
(directory-files-recursively "~/assignments/" "[0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\}.org")
;; ("~/assignments/a/b/2022-05-18.org"
;; "~/assignments/c/d/2022-07-15.org"
;; "~/assignments/e/f/2022-08-08.org")
Here's a thin wrapper around that function which reads a filename from the minibuffer and returns a list of matching directories (starting from the current directory), from which you select an entry which will then be visited:
(defun my/find-directory ()
"Find the directory containing FILE."
(interactive)
(let ((matches (directory-files-recursively default-directory (read-from-minibuffer "Filename: "))))
(if matches
(find-file
(completing-read
"Pick a directory: "
(mapcar 'file-name-directory matches))))
(message "No matching directories.")))

Emacs: what are good tactics for navigating directories and opening files?

Last week, infuriated (again) by having to cope with different IDEs for R and Perl, neither of which I like or use enough to get really comfortable in, I decided to try Emacs. This decision was not made without a certain trepidation on my part. My main use is for Perl with cperl and for R with ESS. My environment is Windows 7 Ultimate 64-bit and I am running v23.4.1, which I think is what the ESS package installed on my behalf.
Nearly a week in and so far it has been surprisingly painless, no more involved than any other significant piece of software. I have remapped my ctrl key to caps-lock, changed default folders, messed around with .emacs and made some additions such as auto-install, yasnippet, color-theme, icicles and a few others. Clearly there is some very sophisticated stuff out there. In addition of course certain features of base Emacs are immediately very powerful and useful, such as isearching up and down. On the whole I have been pleasantly surprised and reassured.
One thing that is cruder than I was expecting is the process of finding and opening files. After a cursory read of various tutorials I had this image of quasi-magical file location and filename auto-completion. The main directories in my setup have paths like g:/roaming/code/perl or g:/roaming/code/R/ but I often need to branch into completely different paths like g:/pricedata/support files/sector/project01/ and so on.
Currently I laboriously delete the file path when I need to take a different fork, then use auto-complete to move deeper into that branch of the filesystem. It kinda takes me back to running a bash shell on the Amiga twenty years ago.
What had I expected? Something like (using the above example) typing 'project01' to skip immediately into the folder at the bottom of the path. For some reason I had got the idea in my head that Emacs would preload directories. So maybe this wasn't realistic.
My guess is that my difficulties probably stem from my own lack of familiarity rather than a structural shortcoming in Emacs and leads on to my questions. I can't complain that there is not enough documentation; rather there is abundant information that it is scattered around rather haphazardly. Icicles has a similar problem - if anything there's too much.
1) What is the best tactic for moving around different branches of the file tree when trying to open files in the minibuffer or using some other method? Are there aliases that can be used to shortcut from one place to another or can one specify directories to be preloaded? Do people just cd around a lot? Or am I coming at this from completely the wrong angle and need to adopt a different strategy?
2) With additional setup, can auto-complete be used to find files in (say) the project01 directly above by prefixing with wildcards etc? What should I focus on to become more efficient here? Am I not tapping the power of add-ons like icicles, anything etc?
I realise these questions veer dangerously close the deprecated category of not having clear answers. My defence is that some tips/guidance at this stage before I commit myself to bad habits or a poor long-term solution would be welcome and I suspect the answers will benefit others who might be considering the switch. I am happy to withdraw or rephrase if there are problems.
helm (formerly known as anything) might suit you. You can install it manually, or using a auto-install extension.
For the auto-install way: download it, put in Your load-path, then add to .emacs:
(add-to-list 'load-path "~/.emacs.d/site-lisp/auto-install")
(require 'auto-install)
(setq auto-install-directory "~/.emacs.d/site-lisp/auto-install/")
Then do M-x auto-install-batch anything. After that is done, put in .emacs:
(require 'anything)
(require 'anything-match-plugin)
(require 'anything-config)
(require 'anything-show-completion)
Then do M-x anything for anything.
Also give a try to ECB (stands for Emacs Code Browser). If you're on Linux, you probably have it available in a standard repository.
You could benefit from using ido-mode, which greatly enhances autocompletion nearly everywhere in emacs (especially when finding files or buffers)
(setq ido-enable-flex-matching t
ido-auto-merge-work-directories-length -1
ido-create-new-buffer 'always
ido-use-filename-at-point 'guess
ido-everywhere t
ido-default-buffer-method 'selected-window)
(ido-mode 1)
(put 'ido-exit-minibuffer 'disabled nil)
(when (require 'ido-ubiquitous nil t)
(ido-ubiquitous-mode 1))
While this might help you quickly finding files "not far away", it probably won't help you much finding files in entirely different locations.
If find that one way to begin tackling this problem is using recentf-mode to quickly jump to recent locations (if you have only a small number of usual project directories, this might do the trick). recentf can be coupled with ido using something like this (I'm not sure where I got this snippet from):
(recentf-mode 1)
(setq recentf-max-saved-items 50)
(defun ido-recentf-open ()
"Use `ido-completing-read' to \\[find-file] a recent file"
(interactive)
(if (find-file (ido-completing-read "Find recent file: " recentf-list))
(message "Opening file...")
(message "Aborting")))
(global-set-key (kbd "C-x C-r") 'ido-recentf-open)
With this, you can use C-x C-f (ido-find-file) to look for files near you current location, and C-x C-r (ido-recentf-open) to look for recently opened files (hoping one of them is not too far away from where you want to go).
There are various approaches. File name cache is a built in solution. Opening files from recent files is also very effective, especially if you set the stored files to a high number (e.g. 1000). There are also packages for opening files from anywhere on the file system. And there are meta solutions like anything.el which can show you file completions from multiple sources (history, project files, etc.) in a common interface.
You should investigate the different options to find out which is the most suitable for you.
In addition to IDO and recetf you can use the following methods:
Open the directory recursively.
(defun op-i:dired (rec)
"customized dired: will display directory recursively when called with an argument"
(interactive "P")
(let ((dir (car (find-file-read-args "Dired: " nil)))
(opts (if rec (read-string "options: " "-lhAR") "-lhA")))
(if (file-directory-p dir) (dired dir opts))))
(define-key (current-global-map) (kbd "C-x C-d") 'op-i:dired)
Then you can navigate in the directory buffer as in any other buffer using a (wildcard) search.
Use Emacs registers to point to often used directories. You can initialize them in your .emacs
(set-register ?0 (cons 'file "c:/path/to/my-project0"))
(set-register ?1 (cons 'file "c:/path/to/my-project1"))
Then jump to register using C-x r j
Other people have already mentioned anything, suffice it to say, I believe it solves all your problems. :)
Calling out one specific feature of anything is anything-locate. On *nix systems, this uses the DB created by the locate command to quickly find files. On Windows, I believe it works with "Everything", which should give you near instantaneous search results across all your files. I mean all.
Tom has mentioned file-cache. Anything works with that.
Just as a side note, Dired is an absolute monster once you get used to it. You should read the emacswiki pages related to it. In particular dired-x, which comes with Emacs binds C-x C-j, jumps to current buffer in Dired was a revelation for me. Also dired-find, wdired.
Edit: some details on why C-x C-j is awesome.
When you pop the current buffer in a Dired buffer, you can modify it, i.e. rename, delete, etc. And Emacs is aware of what you've done, and adjusts accordingly.
Other possibilities:
Bookmarks. If you use Bookmark+ then you can also:
Bookmark Dired buffers, which remembers their inserted subdirs, their markings, and their file omissions. You can have a bookmark that opens Dired to a specific set of files that need not be in the same directory or even the same directory tree.
From Dired you can hit a key to create a separate bookmark to each marked file or subdir.
Bookmark files automatically (autofiles).
Tag bookmarks and files (autofile bookmarks) with arbitrary-text tags. (Tags can even be non-text Lisp objects). Use tags to organize, search, etc. different categories of bookmarks.
Bookmark sets of bookmarks or bookmark files or Emacs desktops. Jump to such a bookmark to restore a given project state/context.
Icicles.
Define temporary or persistent sets of files on the fly, even from different directories. Operate on the files in a set in various ways. (Use Emacs filesets, less powerful, the same way.)
Complete against file names from such saved sets during any completion command, not just file-finding.
Act in different ways on candidate files during completion.
Search bookmarked objects or saved sets of files or buffers.
Dired+.
Additional navigation, including i bouncing between a subdirectory listing and the subdirectory's line in the parent listing.
Refs:
http://www.emacswiki.org/cgi-bin/wiki/BookmarkPlus
http://www.emacswiki.org/emacs/Icicles_-_Support_for_Projects
http://www.emacswiki.org/emacs/Icicles_-_File-Name_Input
http://www.emacswiki.org/cgi-bin/wiki/DiredPlus

How to make emacs stay in the current directory

When I start working on a project in emacs, I use M-x cd to get into the project root directory. But every time I use C-x C-f to open a file in one of the subdirectories (like app/model/Store.rb) emacs changes current directory to that of the file. Is there a way to make emacs stay at the root?
How about this? It replaces the regular find-file command with your own which always starts in some "root" directory (customize the find-file-root-dir variable):
(defvar find-file-root-dir "~/"
"Directory from which to start all find-file's")
(defun find-file-in-root ()
"Make find-file always start at some root directory."
(interactive)
(let ((default-directory find-file-root-dir))
(call-interactively 'find-file)))
(global-set-key (kbd "C-x C-f") 'find-file-in-root)
Assuming that you want the working directory of a file to be set to whatever the working directory was before you executed find-file, you could try the following:
(defmacro disallow-cd-in-function (fun)
"Prevent FUN (or any function that FUN calls) from changing directory."
`(defadvice ,fun (around dissallow-cd activate)
(let ((old-dir default-directory) ; Save old directory
(new-buf ad-do-it)) ; Capture new buffer
;; If FUN returns a buffer, operate in that buffer in addition
;; to current one.
(when (bufferp new-buf)
(set-buffer new-buf)
(setq default-directory old-dir))
;; Set default-directory in the current buffer
(setq default-directory old-dir))))
Armed with this macro, go search for operations that set the variable default-directory: M-x find-library files; M-x occur (setq default-directory. After some investigation, you discover that the desired function is called find-file-noselect-1. Also, it looks like set-visited-file-name is also a candidate. So:
(disallow-cd-in-function find-file-noselect-1)
(disallow-cd-in-function set-visited-file-name)
Note
Note that (disallow-cd-in-function find-file) would work just fine, but then if you switched to ido-mode, you'd be opening files with ido-find-file instead of find-file. Both of these functions ultimately use find-file-noselect-1, so hitting that with the macro is a more univeral solution.
Is there a way to make emacs stay at the root?
No, there isn't. C-x C-f always visits starting from the default directory of the buffer you are already vising. The default directory, by default, is the same directory as the file. You can change these (separately for every buffer) using M-x cd.
But that is not what you want. What you should do is C-x b to *scratch* (whose default directory is the same as where you launched Emacs from -- in your words "root"), and then visit a new file. And if you need to do this frequently, just open up a dired in there and work your way thru.
I appreciate I'm not answering your question directly, but I noticed you were more specific in your requirements in one of your comments: "I don't use compile or recompile, I just tend to close files I am not working on, since it takes fewer keystrokes to open a file again".
Have you got ido turned on for buffer switching? If you exclude the directory thing for a moment, switching files or buffers with ido is an identical number of keystrokes (C-x C-f vs C-x b, followed by a few characters in the file name). If you include the directory thing, switching files is more tricky for the precisely the reasons you mention. Sticking with buffers is much easier.
Going a step further, with the help of 'anything.el' it's quite easy to abstract away whether a given file is in a buffer or in a file using the file cache. For example, if you do the following:
(file-cache-add-directory-recursively "/my/ruby/project") ".*\\.rb$")
and run 'anything-for-files' (I have it bound to C-x f) all your open buffers are listed, along with all of the files you've just added to the file cache; isolating a given file usually only takes one or two more characters.
Any file in your project is thus 4 or 5 key presses away, and the directory they are in or whether or not they are in a buffer becomes irrelevant.
Hope that's helpful...
Sorry I haven't worked out the details, but you might be able to add a function to find-file-hook that resets the default directory to whatever you want.

What's the best way to handle multiple like-named files in emacs?

One problem that I have with emacs is that it doesn't seem to handle like-named files in different directories very well. For example, if I'm not careful, I'll end up with 20 __init__.py buffers open. What I've been doing is using M-x rename-buffer and renaming it to indicate what package it's within. However, doing this manually is somewhat tedious.
Does anyone have any strategies for attacking this problem?
I like uniquify, which comes with Emacs:
(require 'uniquify)
(setq uniquify-buffer-name-style 'reverse)
(setq uniquify-separator "/")
(setq uniquify-after-kill-buffer-p t) ; rename after killing uniquified
(setq uniquify-ignore-buffers-re "^\\*") ; don't muck with special buffers (or Gnus mail buffers)
With those settings, the directory gets added to the buffer name, giving you an indication of where the file is. For example, loading the files /some/path/to/Makefile and /some/path/to/different/Makefile would result in the following buffer names:
Makefile/to (which is /some/path/to/Makefile)
and
Makefile/different (which is /some/path/to/different/Makefile)
uniquify also handles updating the buffer names when buffers are deleted, so when one of the two Makefile buffers is deleted, the other gets renamed to simply Makefile.
If you want full control you can redefine create-file-buffer.
If you want the full filename it could be as simple as
(defun create-file-buffer (filename)
"Create a suitably named buffer for visiting FILENAME, and return it."
(generate-new-buffer filename))
See files.el for reference.