How to `'load-file'` the associated file for the current buffer? - emacs

How to 'load-file' the associated file for the current buffer?
After editing ~/.emacs.d/init.el, I want to reload it, so I issue the command M-x load-file.
The problem is however, that sometimes the prompt starts in a directory far away from ~/.emacs.d like C:/Users/....
Why does this starting place change, and how do I load the associated file for the current buffer fast?

If the currently-selected window is displaying the buffer which is visiting the file you wish to load, then you should be able to use:
M-x load-file RET RET
load-file will load the visited file if you do not type a file name at the prompt.
Note that you do not need to delete the default value (which is a directory path); simply type RET.
This is the case even if you have done something to change the buffer's default-directory (in which case the default value at the prompt may not actually be the parent directory of the visited file). When you just type RET Emacs uses the absolute path of buffer-file-name, making default-directory inconsequential.

load-file uses the current buffer's value of default-directory as the default directory. And if the current buffer is visiting a file, the directory containing that file serves as the default.
You can set it by:
(setq-local default-directory "~/.emacs.d/")
and set it for specified mode (if necessary):
(setq-mode-local jde-mode default-directory "~/.emacs.d/")

Related

How do cd, cd-absolute, and default-directory compare in GNU emacs?

How should I think about elisp functions cd and cd-absolute and the elisp variable default-directory when I'm customizing Emacs? My experience leads me to believe that cd-absolute changes the directory for the emacs process itself (a global setting across buffers where default-directory isn't set locally), while cd and default-directory are local to the buffer. The built-in help isn't sufficient to make me comfortable in my understanding, though, and I am seeing behavior that leads me to suspect cd-absolute is overriding default-directory in buffers I'm visiting.
End-edit
If I had received no answer here, I would have had to do my own research on the help-gnu-emacs list and, only as a last resort, I would have had to read the source code.
I think you are misunderstanding how default-directory works. Setting default-directory in your .emacs will have no effect on most buffers. The local value of default-directory for a buffer that is visiting a file is automatically set to the directory where the visited file is stored. This will over-ride any previously set value of default-directory.
If you change the current directory of a buffer via cd (or cd-absolute), this will set default-directory only for that buffer. If you then open a new file, default-directory for the new buffer gets set to the directory of the new file.
If you open a new buffer that is not visiting file, then the default-directory value of this new buffer will be the same as the value for the previous buffer. This is the only case where the result of cd will apply to a buffer other than the one it is called from.
cd-absolute is not intended for interactive use. As far as I can tell, it's a convenience function that differs from cd only in that the path is treated as an absolute, rather than relative, path.
Given all this, what are you trying to do?

Permanently add to emacs load path

I am trying to add "~/" to the emacs load path, because for whatever reason it is not there. I managed to find the command for adding to the emacs load path:
(add-to-list 'load-path "~/")
When I execute this command the load-path variable contains all the stuff it did before, and "~/" is added to the list. The problem is when I quit emacs, the next time it starts the "~/" had been removed from the list, the change is not persistent. How do I add something to the emacs load-path variable permanently?
Adding to the .emacs file won't work here, because the problem is that the .emacs file, which is in the ~/ directory, is not being loaded, so modifying the .emacs file won't fix this problem.
I guess there is a typo in phils' comment. The right way should be C-h v user-init-file RET. Maybe you customized this variable in some other places and you forgot. Try changing the value of this variable back to the default.

Emacs elisp configuration file doesn't recognize default-directory

I have my emacs configuration file under ~/.emacs with just one declaration:
(setq default-directory "/var/www/")
What I want to do is to C-x C-f and go directly to my apache directory. But I tried using C-x C-f and my current directory is HOME.
The file gets loaded, because I used this: (shell) and the shell gets opened. Anyone knows where my error is? I just want to set the start-up directory in htdocs.
default-directory does not do what you seem to think. C-h v
default-directory
default-directory is a variable defined in `buffer.c'.
Its value is "/"
Local in buffer stackoverflow.com/questions/14914353; global value is nil
Automatically becomes buffer-local when set in any fashion.
This variable is safe as a file local variable if its value
satisfies the predicate `stringp'.
Documentation:
Name of default directory of current buffer. Should end with slash.
To interactively change the default directory, use command `cd'.
It's a buffer-local (i.e. buffer specific) variable, meaning its value is
different depending on which buffer is currently active. So when you think you've set it to
"/var/www", you are simply visiting a file already in that directory.
If you want to open a file from "/var/www", you need to make your own command
that binds "/var/www" to default-directory.
Just in case someone is wondering how to do this:
As #Pacha was saying, when emacs starts, the welcome screen shows up and it will change your working directory to the command-line-default-directory
So, for example, If you want your default directory to be "~/", add this to your .emacs and you should be on track.
(setq command-line-default-directory "~/")
(setq default-directory "~/")
Solved it, it was a really weird problem.
Every time I try to open a file from the default buffer (*GNU Emacs*) it changes the default directory to ~/, but when I try to open a file from another buffer, it opens to the one I specified in my variable.

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