for some complex reason, I would like to open files in certain directory (can have any name, no extension) in C mode, and I don't want to modify them for Emacs (file-local variables are out). I am struggling with Emacs to do it, however. I tried to put this into my dir-locals.el:
((nil . ((major-mode . c-mode))))
Although the major-mode variable is indeed overridden to c-mode when I open file from that directory, the C mode is not enabled on the buffer. What's going on and how do I make it apply?
Alternatively, I could add to the auto-mode-alist just for this directory, but I don't know how to do that via directory locals.
Also, is there some easy way to cause execution of code from dir-locals.el? I know it's unsafe, but it could even be the code that is in config - the point is to call it only when variables from dir-locals are processed (opening a file).
Thanks for help.
Apart from eval, there is also another special variable named mode which can help you. It is the same variable used by file-local variables. You could also write:
((nil . ((mode . c))))
In .dir-locals.el you can only set variables to a certain value. What your code does is set the major-mode variable to the c-mode value. However, this is not the way a mode is activated. To activate it you need to call the function c-mode. There is a special variable that you can set in .dir-locals.el to run a function: eval.
Therefore, the following code works:
((nil . ((eval . (c-mode)))))
i can't answer your first question (and in fact, will like to hear the answer for that myself) but fir the auto-mode-alist you can have
(setq auto-mode-alist (cons '("<your dir path here>\." . c-mode) auto-mode-alist))`
this should give you the result you want
Related
I have files with a .new extension that contain LaTeX code (they are the output of a program that does things on the original .tex source).
In order to check them I need that they have the LaTeX syntax highlighted and that they can be opened in read-only mode to avoid introducing errors. So I put these lines in my .emacs:
(setq auto-mode-alist
(append '(("\\.new\\'" . read-only-mode)
("\\.new\\'" . latex-mode))
auto-mode-alist))
But it does not work as expected because only the first mode is applied. How can I force emacs to apply both read-only-mode and latex-mode to the same file extension?
An easy solution is to associate your file extension with a custom derived major mode:
(define-derived-mode read-only-latex-mode latex-mode "LaTeX"
"Major mode for viewing files of input for LaTeX."
(read-only-mode 1))
(add-to-list 'auto-mode-alist '("\\.new\\'" . read-only-latex-mode))
The new read-only-latex-mode does everything that latex-mode does (including running latex-mode-hook if you're already using that), but it additionally enables read-only-mode after all of the parent mode's actions have taken place.
Any other code which cares about the major mode being latex-mode should already be testing that using the standard approach of (derived-mode-p 'latex-mode) which is still true for this new mode; so in principle this approach should Just Work.
Not sure I can really provide an answer, but here's some things to consider:
read-only-mode is a minor mode, while
auto-mode-alist is meant to turn on major modes. For major modes, it makes sense that you can have only one.
You can put something like -*- buffer-read-only: t; -*- on your first line in the file (possibly behind some comments or shebangs, depending on the file type) which would turn on read-only-mode. Maybe automate this using auto-insert-alist and match the .new filename pattern.
There's some good suggestions over at https://www.reddit.com/r/emacs/comments/jqxgiz/how_can_i_make_some_files_automatically_readonly/ , namely try file local variables and use find-file-hook
Hope some of that helps.
I use a custom version of org-mode called lawlist-org-mode -- every function and variable have the prefix lawlist- and the modified version has many custom features that are not available in the stock version. Occasionally, I like to use the stock org-mode version -- however, that requires manually modifying the auto-mode-alist and then restarting Emacs. This is necessary due to the function and variable org-agenda-files and the check that org-mode performs to verify that the proper major-mode is present. Is there an efficient method to modify this programmatically depending upon the function being called?
The stock org-mode needs this entry:
(add-to-list 'auto-mode-alist '("\\.todo\\'" . org-mode))
The custom version called lawlist-org-mode needs this entry:
(add-to-list 'auto-mode-alist '("\\.todo\\'" . lawlist-org-mode))
Examples:
If I call M-x org-agenda, the .todo files needs to be in org-mode.
If I call M-x lawlist-org-agenda, the .todo file needs to be in lawlist-org-mode.
Some Ideas: The org-agenda-files are generally accessed by org-agenda functions using the following lines of code -- (org-agenda-files nil 'ifmode) . . . (while (setq file (pop files)). Perhaps modifying the function org-agenda-files would be an option?
The FUNCTION part of an auto-mode-alist entry (i.e., the cdr) is just a function. It is called, in principle to set up a major mode. But it can do anything.
In particular, you could have an entry ("\\.todo\\'" . foo), where function foo conditionally calls either lawlist-org-mode or org-mode.
E.g, it could use lawlist-org-mode when the moon is full and org-mode otherwise. Or it could test a global variable, which you set when you want to switch from one to the other. And so on.
At least that's my reading of the auto-mode-alist doc string. I've never tried it.
I'm not sure this is possible, but I'd like to setup some project specific key bindings by using .dir-locals.el
Of course .dir-locals.el has to contain a special list of settings, so I can't do:
(global-set-key [24 down] 'move-text-down)
Is there any way I can inject a lambda to run arbitrary code or some other way to set key bindings in .dir-locals.el?
The eval pseudo-variable enables you to specify arbitrary elisp for evaluation with your local variables.
e.g. https://stackoverflow.com/a/7340962/324105
See EmacsWiki for more details.
Note that this is not a particularly useful mechanism for setting key bindings, as every buffer using the keymap in question will be affected. You would probably be better off using the dir-local config to enable a minor mode with the specific keymap for that project. Alternatively, you might adapt this approach to file-local bindings (but a minor mode would be nicer).
That being said...
A fairly minimal form is ((nil . ((eval . (progn BODY))))) with BODY being the expressions to be evaluated. Of course if BODY is only a single expression, you do not need progn.
The following therefore displays a message when you visit any file (under the directory in question):
((nil . ((eval . (message "hello")))))
The car of each list in the dir-locals form is generally a major mode symbol, or nil (as in the above example) in which case the settings apply in any major mode.
The car can also specify a sub-directory string, in which case the cdr is another dir-locals form with settings applicable to that sub-dir.
Is there a possibility to set a specific color theme or just to hook on a specific project to run custom elisp?
So the idea is to automatically set a color theme or background-color when I open a file from a specific project (path)? E.g. I can work with multiple projects in different frames and instantly know where I am. May be this can written in .projectile file somehow ?
Here by frame I mean Frame not just a buffer.
You can't do this as of now but there is a discussion going on here for something similar in the
Projectile issue list. However you can use a .dir-locals.el file to get this done. I am guessing something similar would be implemented for projectile using .projectile file in the future once the devs decide upon it.
dir-locals.el is intended to set local variables for all files in that particular directory you could checkout the docs or this blog post for the details. It's not particularly designed to run elisp code (setting a theme is a load-theme function call I believe) for good reason. However you can use eval variable to work around this and emacs will ask you whether to run the code.
((nil . ((eval . (load-theme 'molokai
)
))))
or you could do something even fancier according to the major modes.
((nil . ((indent-tabs-mode . t)
(tab-width . 4)
(fill-column . 80)))
;; Warn about spaces used for indentation:
(haskell-mode . ((eval . (highlight-regexp "^ *"))))
(c-mode . ((c-file-style . "BSD")))
(java-mode . ((c-file-style . "BSD")))
("src/imported"
. ((nil . ((change-log-default-name . "ChangeLog.local"))))))
The latest projectile (projectile-20140716.416) now supports hooking in arbitrary elisp after project switch, elisp such as:
(load-theme 'zenburn t)
An example script that exploits the hook is here: http://github.com/jfeltz/projectile-load-settings
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))))