tags:

views:

197

answers:

6

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?

A: 

That behavior to me makes sense. The question is what kind of meaning does the current directory have to you? I always open a shell buffer with M-x shell. If you bind a shell to a key (e.g. F11) you can cd there. Then you can always switch to the shell and then open a file. Maybe that feels like a workaround, but give it a try. If I'm working in more then one place I create a second shell buffer.

something else: If you run your program with M-x compile you can run it again with M-x recompile (e.g. bound to F7). recompile remembers the directory.

Eddy Pronk
Well, I am using ruby on rails, so I open a model in app/model and then when I want to open a controller in app/controller I have to get out of the model directory first. 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 (if it wasn't for the obnoxious directory switching) than to use buffer switching. To me it makes sense that my current directory stays put unless I actually change it. In any case, I am pretty sure there is a setting somewhere in emacs that governs this behavior.
Mad Wombat
+2  A: 

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)
Trey Jackson
Thanks, this is not the behavior I wanted, but this gives me enough ideas to implement my own version.
Mad Wombat
A: 

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.

sly
Apparently there is a way.
Mad Wombat
Yes, well touche! Then again I am not surprised, hence why emacs is the best editor on earth
sly
+1  A: 

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...

bbbscarter
A: 

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.

offby1
A: 

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.

Ryan Thompson