Can I change Emacs find-file history? - emacs

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

Related

in Emacs, how to enable automatic hiding of dired details?

I use a library called dired-details and dired-details+ to simplify dired's display, such that a line like this:
-rw-r--r--# 1 peter staff 22571 Apr 15 16:05 foo.txt
displays like this:
foo.txt
However, I have another function, which places all directories at the top of the list:
(defun mydired-sort ()
"Sort dired listings with directories first."
(save-excursion
(let (buffer-read-only)
(forward-line 2) ;; beyond dir. header
(sort-regexp-fields t "^.*$" "[ ]*." (point) (point-max)))
(set-buffer-modified-p nil)))
(defadvice dired-readin
(after dired-after-updating-hook first () activate)
"Sort dired listings with directories first before adding marks."
(mydired-sort))
and this second function interferes with dired-details, such that when I C-x d to open a dired buffer, the initial display shows the full extraneous details. Only by pressing g to revert-buffer to refresh the display do the directory details become hidden.
How do I enable hiding of dired details by default in all dired displays?
First, if you use Emacs 24.4 or later (or a developement version past 24.3), then you no longer need either dired-details.el or dired-details+.el. Starting with Emacs 24.4, Dired listing details are hidden by default. dired-hide-details-mode is the relevant mode.
If you use dired+.el (Dired+) then you can more easily take advantage of this new behavior -- it gives you all of the features offered by dired-details+.el. Use ( anytime to toggle this hiding. You can use Dired+ option
diredp-hide-details-initially-flag to change the default/initial state. See also option diredp-hide-details-propagate-flag.
If you use an Emacs version that is prior to Emacs 24.4 (so you need dired-details[+].el) then try loading dired-details+.el (which will load dired-details.el) after you have evaluated your code above. If that does not help, then try also adding this to your defadvice body, just after (mydired-sort): (dired-details-hide). If that does not work then we will need to look a bit further.
If you can upgrade your Emacs version then you will soon be able to use Emacs 24.4 (it is in pretest now), in which case you should be able to just load dired+.el and set option diredp-hide-details-initially-flag to non-nil.
Wrt sorting directories first: Are you on MS Windows? If so, consider using libraries dired-sort-menu.el and dired-sort-menu+.el. It lets you do that and much more.
UPDATE
The problem is that dired-details caches the list of overlays it uses to hide details. It has already done its job (because of dired-after-readin-hook), before your sorting is done, and that changes the buffer without updating the cache info. This will fix the problem (there is probably a more elegant way, but this will do):
(defadvice dired-readin
(after dired-after-updating-hook first () activate)
"Sort dired listings with directories first before adding marks."
(mydired-sort)
(let ((dired-details-internal-overlay-list ())) (dired-details-hide)))

Emacs file edit history

Is there an emacs extension that takes periodic snapshots (once a minute, once every x keystrokes, whatever) of a file while it is being edited similar to the change history in Eclipse or the edit history in Google Docs and other programs?
I'm hoping for something that'll let me easy navigate through the changes I've made from day to day - Is there anything like this already written?
Edit
I should be more specific - I'm not looking for a VCS. I'm looking for a minor-mode or something similar I can just switch on and have hard copies of the revisions on disk.
There's a built-in feature called autosave that saves after N keystrokes (and maybe after M seconds, I'm not sure). I generally use this if Emacs crashes, not for looking at what edits I've made; undo is better for that. Here's my config:
(setq autosave-dir (concat user-emacs-directory "autosaves/")
auto-save-list-file-prefix (concat emacs-persistence-directory
"autosave-list"))
(if (not (file-exists-p autosave-dir))
(make-directory autosave-dir t))
(add-to-list 'auto-save-file-name-transforms
`("\\`/?\\([^/]*/\\)*\\([^/]*\\)\\'" ,(concat autosave-dir "\\2") t))
;; tramp autosaves
(setq tramp-auto-save-directory (concat user-emacs-directory "tramp-autosaves/"))
(if (not (file-exists-p tramp-auto-save-directory))
(make-directory tramp-auto-save-directory))
There's also a backup system that creates a copy after every save (not autosave). I use this for what I think you're asking for - looking at history since my last VCS commit. Here's my config:
(setq make-backup-files t
vc-make-backup-files t
version-control t
kept-new-versions 256
kept-old-versions 0
delete-old-versions t
backup-by-copying t)
(setq backup-dir (concat user-emacs-directory "backup/"))
(if (not (file-exists-p backup-dir))
(make-directory backup-dir))
(add-to-list 'backup-directory-alist
`(".*" . ,backup-dir))
(defun force-backup-of-buffer ()
(setq buffer-backed-up nil))
(add-hook 'before-save-hook 'force-backup-of-buffer)
;; this is what tramp uses
(setq tramp-backup-directory-alist backup-directory-alist)
(add-to-path "backup-walker")
(autoload 'backup-walker-start "backup-walker"
"start walking with the latest backup" t)
I use the excellent backup-walker to navigate through the backups.
The best solution I have found for this is undo-tree, which is the Emacs equivalent to gundo for vim: it lets you visualise the tree of undo/redo, navigate through the changes and go back and forth between different versions.
undo-tree can be installed using ELPA; once it is installed, add the following to .emacs:
(require 'undo-tree)
(global-undo-tree-mode)
The undo tree can then be visualised using Ctrl-x u (undo-tree-visualize). The different “versions” can be navigated in a very intuitive manner, using arrow keys.
The history can also be made persistent using undo-tree-save-history.
If you really value keeping your changes, I would highly recommend starting to use git. It will work for your windows and linux coding environments. I use it to port changes from code back and forth. It does a great job of fixing all the little line endings and merging changes.
If you really just want it to keep old versions, then emacs can create a new backup every time that you save. It just creates another file right next to your current one. That way you can control how often it makes a new backup (every time you save).
Here's a good page that talks about the options:
ftp://ftp.gnu.org/pub/old-gnu/Manuals/emacs-20.7/html_chapter/emacs_18.html#SEC109
Try http://www.emacswiki.org/emacs/BackupEachSave
It has saved me a number of times allowing me to backtrack.

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.

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

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/

Don't show uninteresting files in Emacs completion window

How do I prevent Emacs from showing me all the files I'm not interested in (such as ~ backup files, .pyc files, or .orig files) when I: C-x C-f TAB ?
It is working in one respect: if I know the file I want to open begins with foo and I type foo TAB then the mini-buffer correctly autocompletes all the way to foo.py. It correctly ignored foo~ and foo.pyc, because both ~ and .pyc are in completion-ignored-extensions. It also correctly lets me open either ignored file if I really want to by typing in all the letters my self.
However, if I just hit TAB to to bring up the completion list buffer then that list includes files with extensions in completion-ignored-extensions, which makes it very difficult to find what I'm looking for.
Clearly the code to ignore uninteresting files is there and working. How do I get the completion list buffer to respect completion-ignored-extensions?
(by-the-by, can I make dired behave similarly?)
This piece of advice filters out files with extensions listed in 'completion-ignored-extensions:
(defadvice completion--file-name-table (after
ignoring-backups-f-n-completion
activate)
"Filter out results when they match `completion-ignored-extensions'."
(let ((res ad-return-value))
(if (and (listp res)
(stringp (car res))
(cdr res)) ; length > 1, don't ignore sole match
(setq ad-return-value
(completion-pcm--filename-try-filter res)))))
Note: This doesn't affect dired.
For the dired issue, add this to your .emacs
(eval-after-load "dired"
'(require 'dired-x))
(add-hook 'dired-mode-hook
(lambda ()
(dired-omit-mode 1)))
Read the documentation for dired-x to get an idea of what's available there.
I would recommend using ido-mode to ignore files; it comes with Emacs by default and adds many other useful enhancements that you'll quickly learn to love. The Ignorance is Bliss section from this Mastering Emacs blog post covers how to ignore files, directories, and buffers:
ido-ignore-buffers Takes a list of buffers to ignore in C-x b
ido-ignore-directories Takes a list of directories to ignore in C-x d and C-x C-f
ido-ignore-files Takes a list of files to ignore in C-x C-f
Icicles does what you expect by default. It always respects completion-ignored-extensions for file-name completion, including for buffer *Completions*. And you can toggle this ignoring on/off at anytime, by hitting C-. in the minibuffer.
In addition, if you use library completion-ignored-build.el by Kevin Ryde, then Icicles automatically takes advantage of that library's dynamic adjustment of ignored file extensions. (Just load completion-ignored-build.el -- do not enable its minor mode or advice.)
I don't know of an answer for completion, I'm afraid. I think this is by design - when you know the name you're looking for, you probably don't want e.g. the backup file. But when you don't know, it's probably better to have a list of all of the files.
However, for dired, you can load the 'dired-x' package on startup (in your .emacs), and this provides dired-omit-mode:
(load "dired-x")
You can use 'M-x customize-variable<RET>dired-omit-files' to set the actual patterns to ignore. Then when you are in dired mode you can use M-O (the letter, not the number) to toggle 'omission' on and off.