Emacs .dir-locals.el - setting key bindings - emacs

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.

Related

How does the "pdf-tools" package overrides "dired-find-file" method?

After installing pdf-tools the dired mode opens the pdf file with PDFView mode as major mode.
(use-package pdf-tools
:ensure t
:config
(pdf-tools-install t))
How does the pdf-tools package be able to accomplish this?
The Help for RET key in dried buffer says it is bound to dired-find-file
RET (translated from ) runs the command dired-find-file (found
in dired-mode-map), which is an interactive compiled Lisp function.
I searched for dired-find-file in pdf-tools installed elisp files and could not find any advice-add's?
Also please explain how can one go about finding arbitrary key bindings like this one?
What it modified is not directly related to dired, but to how Emacs decides to open files in general. The part of the code that is responsible for that is in pdf-tools-install-noverify, itself called by pdf-tools-install. The first two lines of the function are:
(add-to-list 'auto-mode-alist pdf-tools-auto-mode-alist-entry)
(add-to-list 'magic-mode-alist pdf-tools-magic-mode-alist-entry)
the relevant variables pdf-tools-<auto/magic>-mode-alist-entry being constants defined earlier in the file pdf-tools.el.
You can check the relevant documentation for auto-mode-alist and magic-mode-alist, but to sum up, the former is a mapping from "filenames" (or more precisely, file patterns -- typically, regexps matching file extensions) to major modes, and the latter is a mapping from "beginning of a buffer" to a major mode (see also this wikipedia page on magic numbers/file signatures).
As to how one can determine that: because it is not directly related to key bindings/advices/redefinition of functions, the only "general" option is to explore the "call stack" ! The package tells you to put (pdf-tools-install) somewhere in your init file to activate the package, so you can try to see what this function actually does -- and going a bit further, you see that it is essentially a wrapper around pdf-tools-install-noverify, which does the real job of setting everything up.

How do I get a list of all the currently available commands and hotkeys?

To help me learn to work with various emacs modes, I would like to have a second monitor with a little HTML page that is used for showing me what sorts of things I can type or key-chord on whatever I'm currently looking at in emacs.
So how can I get a list of all the commands or key-chords available to me in my current mode?
Someone else will no doubt tell you how to get a cheatsheet such as you request (well, here is info about that too).
But if you want something that tells you dynamically what keys are available in the current context, no matter what it is, then this is what I have to offer:
C-h m tells you about the current (major) mode. C-h b tells you about currently available keys.
The Icicles feature key completion gives you access to all of the currently available key sequences, via key S-TAB. If you use a prefix key first, then S-TAB, then you see all the completions of that prefix key. You can move up and down the key hierarchy, including even menu items, to see all possible keys. You can use C-M-RET to get help (info about) any given key that is available. Here is some more about this feature of showing you all currently possible key bindings.
I would very much like to know good answer to this question myself! At present I am using this simple function to display key bindings for the current major mode in *Help on keys* buffer:
(defun describe-current-bindings (mode)
"Show key bindings for the current major mode in *Help on keys* buffer."
(interactive)
(with-current-buffer (get-buffer-create "*Help on keys*")
(erase-buffer)
(insert (documentation mode))))
And then use defadvice to call the function automatically whenever I switch buffers or windows:
(defadvice switch-to-buffer (after display-keys-buffer activate)
(describe-current-bindings major-mode))
(defadvice select-window (after display-keys-window activate)
(describe-current-bindings major-mode))
Now I can open *Help on keys* buffer in another frame and move that frame to my second monitor.
If you use other functions to switch windows (from windmove package, etc) you may need to add defadvice for them as well.
Try the pacakge help-fns+.el, there are some useful functions: describe-mode - "Display documentation of current major mode and minor modes.", describe-keymap - "Describe bindings in KEYMAP, a variable whose value is a keymap.", etc. For example,
(describe-keymap 'global-map) ;; global bindings
(describe-keymap 'emacs-lisp-mode-map) ;; major mode bindings
(describe-keymap 'smartparens-mode-map) ;; minor mode bindings

The major mode name of emacs-lisp

I want to load emacs init files faster, so I use the 'eval-after-load.
For example, when I load clojure file, I just put
(eval-after-load 'clojure-mode
'do-something)
It works.
But when I try
(eval-after-load 'emacs-lisp-mode
'do-something)
It doesn't work. I wonder to know the right major mode name of emacs-lisp.
Thanks.
Please read the documentation of eval-after-load:
eval-after-load LIBRARY FORM
This function arranges to evaluate form at the end of loading the file LIBRARY, each time LIBRARY is loaded. If LIBRARY is already loaded, it evaluates form right away. Don't forget to quote form!
[…] LIBRARY can also be a feature (i.e., a symbol), in which case form is evaluated at the end of any file where (provide LIBRARY) is called.
You have to pass the name of the file or library, which defines the major mode, as argument.
While some modes are defined in files of the same name (e.g. clojure-mode in clojure-mode.el), many files a different name, especially if the actually define multiple major modes.
emacs-lisp-mode is defined in lisp-mode.el, along with some other modes for Emacs Lisp editing (e.g. lisp-mode as a generic Lisp language mode, or lisp-interaction-mode for *scratch* buffers).
Hence, use (eval-after-load 'lisp-mode …)
Also, you have to give a single sexp as second argument, so you'll likely want to use (eval-after-load 'lisp-mode '(do-something)), to call the function do-something.
If you are using a snapshot build of Emacs, use with-eval-after-load, i.e. (with-eval-after-load 'lisp-mode (do-something)). It allows for more than a single form, and doesn't require quoting.
Just eval with M-: the variable major-mode. It actually is emacs-lisp-mode.
Note that *scratch* is actually in lisp-interaction-mode.
As to what you're trying to do, use (eval-after-load "lisp-mode").
As explained by #lunaryom, the arg passed to eval-after-load is not a function name but a feature name, which is basically a file name. So you need to find the name of the file from which the function is loaded.
We could provide a feature like eval-after-defun, and indeed it might be a good idea to do so. If you'd like such a thing, ask for it via M-x report-emacs-bug.

How to set default major mode in directory-local file?

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

Assign a keymap to a derived mode in emacs

How can I assign a keymap to a derived mode in emacs (I am using the define-derived-mode function). There is a derived-mode-set-keymap function but without examples or good documentation.
define-derived-mode itself creates a keymap with the name MODE-map, where MODE is the name of the keymap you've just defined. I'm not sure what derive-mode-set-keymap does that is not already done with define-derived-mode; looking at the source, they do similar things, and I'm unsure of the very low-level differences between the two (e.g. define-derived-mode leaves the parent-mode's keymap as the parent of the new keymap while `derive-mode-set-keymap also merges the keymaps; what's the functional difference between the two?).
If you do the following:
(define-derived-mode foobar-mode text-mode "foo")
Then the following variables will be defined:
foobar-mode-abbrev-table
foobar-mode-hook
foobar-mode-map
foobar-mode-syntax-table
You can then start manipulating any of these as you like.