emacs - find-name-dired - how to change default directory - emacs

In emacs when you type M-x find-name-dired it will give you two prompts. The first is what directory path you want to search in, and the second is what the file pattern you would like to search for.
How do I change it (in my .emacs) so the first prompt is always a specific project directory?
Also, how do I make it so the file name search is case insensitive?

To get a different starting directory, you can advise the function to read the arguments using a different starting directory like so:
(defadvice find-name-dired (before find-name-dired-with-default-directory activate)
"change the argument reading"
(interactive
(let ((default-directory "/some/path"))
(call-interactively 'get-args-for-my-find-name-dired))))
(defun get-args-for-my-find-name-dired (dir pattern)
(interactive "DFind-name (directory): \nsFind-name (filename wildcard): ")
(list dir pattern))
And then you just call my-find-name-dired.
Regarding case insensitivity, you can customize the variable find-name-arg to be the case insensitive version:
(setq find-name-arg "-iname")

I suspect Trey's answer is probably elegant and preferred for some reasons that hurts my brain whenever I try to grok (defadvice) but I would take the brute force simple approach and use the following:
(setq my-dired-default-dir "/home/fred/lib")
(defun my-find-name-dired (pattern)
"My version of find-name-dired that always starts in my chosen folder"
(interactive "Find Name (file name wildcard): ")
(find-name-dired my-dired-default-dir pattern))
I'm guessing that I lose history with this approach so if that is important to you Trey's approach is better.
One of these days I have to wrap my head around (defadvice)

After I posted this I discovered another way of resolving this issue:
(add-hook 'find file-hook
(lambda ()
(setq default-directory command-line-default-directory)))
This left as a default the directory that I started emacs in (which is useful so you don't have to change your project directory in your emacs all the time).
In reality I think it is saying that every time you run find file, change the default directory to your starting command line directory.
Another thing could be to set some default directory:
(setq my-default-directory "/home/rob/whatever")
and replace command-line-default-directory with my-default-directory/

Related

How to get Dired to ignore files with specific extensions

I put the following in my .emacs file:
(require 'dired-x)
(add-hook 'dired-load-hook '(lambda () (require 'dired-x)))
(setq dired-omit-files-p t)
(setq dired-omit-files
(concat dired-omit-files "\\|^\\..+$\\|-t\\.tex$\\|-t\\.pdf$"))
But C-x d still shows me .pdf and .tex files. Did I get the syntax wrong in that last line?
Bonus question: Is there a way to get Dired to hide hidden directories, like .git folders?
A simple and very general solution which doesn't rely on any extras is to do C-u s to change the ls flags and immediately refresh (that is, C-u s takes care of refreshing also, so there is very little typing involved). Usually you will want to remove -a to hide dotfiles. But you can do everything you're already able to do in the shell console, which is far more than what a simple toggle mode could offer (at the cost of some extra keypressings). And there is a history of previous flags available, so "toggling" is pretty fast too.
Your regexp will match *-t.tex files, not *.tex ones.
With recent version of Emacs, it should be sufficient to add the following section to ~/.emacs to filter what you want:
(require 'dired-x)
(setq-default dired-omit-files-p t) ; this is buffer-local variable
(setq dired-omit-files
(concat dired-omit-files "\\|^\\..+$\\|\\.pdf$\\|\\.tex$"))
Update: by default, dired-omit-files regexp filters out special directories . and ... If you don't want this behavior, you can just override defaults (instead of inheriting them with concat):
(setq dired-omit-files "^\\.[^.]\\|\\.pdf$\\|\\.tex$")
The regexp ^\\.[^.] will match any string of length 2+ starting with a dot where second character is any character except the dot itself. It's not perfect (will not match filenames like "..foo"), but should be ok most of the time.

Emacs: Set tab indent for just one file on the fly

I work on an open source project where the creator sets his tab-indents to 2 spaces.
I'd like to just enable it on the fly for the one file I work on and not other files of the same type. There must be something like M-x set-tab-indent. It is a JavaScript file ending in .js.
I know I can use:
(setq-default tab-width int)
inside my .emacs file, but I rather just call an M-x command to set it and forget it during my duration of working on this file. I tried M-x apropos and Google but couldn't find the specific command.
Thanks.
You can make the variable js-indent-level local to the buffer using:
M-x make-variable-buffer-local <RET> js-indent-level <RET>
Then you can set that variable in the buffer using:
M-x set-variable <RET> js-indent-level <RET> 2
The easiest way to do this for a single buffer is to use M-x set-variable.
Type M-x set-variable and press enter
When prompted for the variable to set, set tab-width then press enter
You'll be prompted with the line Set tab-width (buffer-local) to value:.
Put the value you want, then hit enter
The buffer should instantly be updated with the new value.
You could also use file local variables to automate omrib's solution for that one file, by adding this to it:
// Local Variables:
// js-indent-level: 2
// indent-tabs-mode: nil
// End:
Create a file ".dir-locals.el" in the project's directory and fill it like this:
((nil . ((tab-width . 2))))
This will take care of setting tab-width automatically and you don't have to modify the actual file (which is likely version-controlled.)
See the manual for more information about the format. I believe this requires Emacs 23.
As indicated by others, one issue with the File Local Variables approach is that you need to modify the file, and that's not ideal if you need to keep those declarations out of version control.
If you want the variables to apply to all files under a given directory, then Directory Local Variables is obviously the way to go, and you can implement that with either a .dir-locals.el file, or by calling (dir-locals-set-directory-class):
http://www.emacswiki.org/emacs/DirectoryVariables
http://www.gnu.org/software/emacs/manual/html_node/emacs/Directory-Variables.html
I prefer the directory class approach myself, and I was thinking that it's a shame that there isn't an analogous approach for file local variables, but I found that the directory class code actually works perfectly with files, and the only issue is that dir-locals-set-directory-class calls file-name-as-directory on its argument, which prevents it from being matched, due to the trailing slash.
The following therefore is a way to configure directory local variables for a single file, without modifying the file itself, or affecting other files under the same parent directory.
(defun my-file-locals-set-directory-class (file class &optional mtime)
"Enable 'directory local' classes for individual files,
by allowing non-directories in `dir-locals-directory-cache'.
Adapted from `dir-locals-set-directory-class'."
(setq file (expand-file-name file))
(unless (assq class dir-locals-class-alist)
(error "No such class `%s'" (symbol-name class)))
(push (list file class mtime) dir-locals-directory-cache))
(dir-locals-set-class-variables
'my-javascript-class
'((nil . ((js-indent-level . 2)
(indent-tabs-mode . nil)))))
(my-file-locals-set-directory-class
"path/to/the/file.js" 'my-javascript-class)
I use a snippet of code in my init.el that tries to auto-detect files that use 2-space indents, and switch Emacs's indentation for that file to 2 spaces when it sees such files:
(add-hook 'js-mode-hook
(lambda ()
(when (string-match-p "^ [A-Za-z]" (buffer-string))
(make-variable-buffer-local 'js-indent-level)
(set-variable 'js-indent-level 2))))

How can I set a default path for interactive directory selection to start with in a elisp defun?

I want a function to interactively prompt for an existing directory, but instead of starting from default-directory, I would like a function local default path like '~/should/start/here/always/in/this/function' to start at when using (interactive "D") how can I achieve this? My first thought is to create another function which first sets default-dir and then calls my original function, but that doesn't seem right, and I am unsure of how interactive would be prompted in that case.
Since you're writing this yourself, you can do something like this:
(defun choose-directory (directory)
"sample that uses interactive to get a directory"
(interactive (list (read-directory-name "What directory? "
choose-directory-default-directory)))
(message "You chose %s." directory))
(defvar choose-directory-default-directory "/home/tjackson/work/data"
"Initial starting point.")
Which uses interactive with a lisp expression to call read-directory to get a directory name (you might want to add additional arguments, check the link/docs).
Your original hunch would work as well, though, as you thought, isn't quite as clean. But, it does work well when you don't want to, or cannot, modify the function whose behavior you want to change. I've included that solution below to show you how you'd achieve it (the only piece of the puzzle you didn't mention was call-interactively):
;; original version of choose-directory, calling (interactive "D")
(defun choose-directory (directory)
"sample that uses interactive to get a directory"
(interactive "DWhat directory? ")
(message "You chose %s." directory))
(defun wrap-choose-directory ()
(interactive)
(let ((default-directory choose-directory-default-directory))
(call-interactively 'choose-directory)))

Can I change Emacs find-file history?

When I call find-file to open a new file, it generally happens that the file I'm looking for is in one of the directories I've already loaded from.
Ideally, I'd like to scroll through the history using the up/down arrows.
The problem with this is that if I've already loaded 10 files from a directory, I first have to pass through those ten files, all in the same directory, before I see a new directory where my file might be.
In the end, I often just type in the directory again or cut/paste it from an xterm.
in the find-file command, can I change the behavior of the up/down arrows to iterate over directories instead of files.
Alternatively, can I change the file order to match the order of buffers most recently visited instead of when I loaded the file?
My first answer suffered from the behavior that TAB completion no longer worked as expected in 'find-file. But the technique still seems useful (and if you like it, preferable).
However, this solution has the same history behavior, but maintains the TAB completion as expected inside 'find-file.
I'd be interested to know if there were a way to avoid advising find-file, but I couldn't find any introspection that gave me the knowledge that 'find-file was called.
(defadvice find-file (around find-file-set-trigger-variable protect activate)
"bind a variable so that history command can do special behavior for find-file"
(interactive (let (inside-find-file-command) (find-file-read-args "Find file: " nil)))
ad-do-it)
(defadvice next-history-element (around next-history-element-special-behavior-for-find-file protect activate)
"when doing history for find-file, use the buffer-list as history"
(if (boundp 'inside-find-file-command)
(let ((find-file-history (delq nil (mapcar 'buffer-file-name (buffer-list))))
(minibuffer-history-variable 'find-file-history))
ad-do-it)
ad-do-it))
I suggest IDO. You can search in the buffer list or in find-file. When searching in find-file and it has no matches in the current folder it searches through history.
not what you want, but
have you tried (electric-buffer-list) Ctrl-x Ctrl-b?
or (dired)?
This will use the buffer-list's order for the history, which is what you want.
(setq read-file-name-function 'my-read-file-name)
(defun my-read-file-name (prompt dir default-filename mustmatch initial predicate)
(let ((default-directory dir)
(files (directory-files dir))
(history (delq nil (mapcar 'buffer-file-name (buffer-list)))))
(completing-read prompt files predicate mustmatch initial 'history)))
Hmmm... This changes the behavior of find-file's TAB completion because the TAB completes over the history (already opened files), and not over the files available in the directory you're specifying.
Getting both to work at the same time is a bit trickier...
With Icicles you can cycle among candidate file names, and you can sort them in many ways. You can access them in order of last use etc.
http://www.emacswiki.org/emacs/Icicles_-_History_Enhancements
http://www.emacswiki.org/emacs/Icicles_-_Sorting_Candidates
http://www.emacswiki.org/emacs/Icicles_-_File-Name_Input

goto-file in Emacs

Is there a substitute in emacs for the vi "gf" command?
meaning try to open the file which is under the cursor right now
if a real file name is in fact there.
Thanks
You want the find-file-at-point function (which is also aliased to ffap). It's not bound to a key by default, but you can use
M-x ffap
Or, you can put in your .emacs file:
(ffap-bindings)
This will replace many of the normal find-file key bindings (like C-x C-f) with ffap-based versions. See the commentary in ffap.el for details.
Thanks, it works quite well but somehow the vi (gf) version is
still somewhat smarter. I think it looks at some path variable for search paths.
I made something which is needlessly complicated but works for me (only in linux).
It uses the "locate" command to search for the path under the cursor.
I guess it could be made smarter by searching the relative path to the current file first.
sorry for my bad elisp skills...It can probably be achieved in a much nicer way.
put in your .emacs, then use with M-x goto-file
(defun shell-command-to-string (command)
"Execute shell command COMMAND and return its output as a string."
(with-output-to-string
(with-current-buffer standard-output
(call-process shell-file-name nil t nil shell-command-switch command))))
(defun goto-file ()
"open file under cursor"
(interactive)
(find-file (shell-command-to-string (concat "locate " (current-word) "|head -c -1" )) ))