add a function with parameters to a hook - emacs

I want to run a function according to the programming language when I open a source code file using the following. I have to pass the language-specific str to the foo function. How can do it in the add-hook statement?
(defun foo (str)
(blahblah...))
(add-hook 'prog-mode-hook 'foo)

Use the built-in apply-partially:
(add-hook 'prog-mode-hook (apply-partially #'foo "spam with eggs"))

This is described in the manual (first hit on Google for "emacs add-hook"):
(add-hook 'prog-mode-hook (lambda () (foo "foobarbaz")))

The bad news is that mode hooks usually don't have any arguments. The good news is that here's what (emacs) Hooks section of manual has to say about your situation:
Most major modes run one or more "mode hooks" as the last step of initialization.
So, I didn't test it myself, but I'm pretty sure you can write a generic hook that will inspect major-mode variable and do the mode-specific actions instead.

Related

Add several functions as hooks in Emacs

How could I simplify something like the following code in my init.el file?
(add-hook 'org-mode-hook 'turn-on-auto-revert-mode)
(add-hook 'org-mode-hook 'turn-on-org-cdlatex)
(add-hook 'org-mode-hook 'smartparens-mode)
(add-hook 'org-mode-hook 'abbrev-mode)
I have several other rows like this, including some lambda functions added to org-mode-hook...
Personally, I would strongly advice against adding lambda functions to hooks. The main reason is that if you change the content and reevaluate the add-hook expression, the hook contains both the old and new lambda expression. The second reason is that it looks bad when you inspect a hook -- it's better to see a function name compared to a large lambda expression.
Instead, I would suggest using:
(defun my-org-mode-hook ()
(turn-on-auto-revert-mode)
(turn-on-org-cdlatex)
(smartparens-mode 1)
(abbrev-mode 1)))
(add-hook 'org-mode-hook 'my-org-mode-hook)
A side note: You can use global-auto-revert-mode to enable auto-revert on all buffers, that way you don't have to enable it for all major modes.
I use a simple dolist:
(dolist (fn '(turn-on-auto-revert-mode
turn-on-org-cdlatex
smartparens-mode
abbrev-mode))
(add-hook 'org-mode-hook fn))
This let's you still remove individual hooks afterwards, with remove-hook or from the customize interface.

emacs only delete-trailing-whitespace while saving in programming mode

following line removes all training white space while saving.
(add-hook 'write-file-hooks 'delete-trailing-whitespace)
but I want to hook this feature only when i'm in programming mode, so i did
(defun nuke_traling ()
(add-hook 'write-file-hooks 'delete-trailing-whitespace)
)
(add-hook 'prog-mode-hook 'nuke_traling)
which doesn't is not stopping which are not in programming mode.
Making the hook variable buffer-local has been mentioned. Don't do that. Or rather, don't do it using make-local-variable.
The normal hook mechanisms have buffer-local support built in -- that's the purpose of the LOCAL argument to add-hook. When the hook is run, it runs both the global and the buffer-local values.
So taking the example code in the question, you could change it to use:
(add-hook 'write-file-hooks 'delete-trailing-whitespace nil t)
And then delete-trailing-whitespace would be called whenever write-file-hooks was run, but only in the buffers in which prog-mode-hook had run.
However there are better ways to achieve this.
I agree with Drew that you are better to test whether your mode is derived from prog-mode, and with juanleon that before-save-hook is a better hook to use. So you might do something like:
(add-hook 'before-save-hook 'my-prog-nuke-trailing-whitespace)
(defun my-prog-nuke-trailing-whitespace ()
(when (derived-mode-p 'prog-mode)
(delete-trailing-whitespace)))
But what I actually recommend is using either ws-trim or ws-butler to take care of this in a smarter way.
Blindly removing all trailing whitespace from a file is a great way to wind up committing loads of unrelated lines to a version-control repository. Both of the libraries mentioned will ensure that your own commits are free of trailing whitespace, without also introducing unwanted modifications elsewhere in the file.
write-file-hooks is obsolete since Emacs-22, replaced by write-file-functions. But this hook is a bit delicate to use (because it can also be used to perform the write), so I recommend you use before-save-hook instead. And to make it apply only to the current buffer, just pass a non-nil value for the local argument of add-hook, as in:
(defun nuke_traling ()
(add-hook 'before-save-hook #'delete-trailing-whitespace nil t))
(add-hook 'prog-mode-hook #'nuke_traling)
Yes, because as soon as you enter a prog-mode mode, you add the function to write-file-hooks, where it remains. And that hook applies to writing any file, regardless of the mode of its buffer.
Instead of putting that simple function on the hook, you can add a function that tests the mode and only does the whitespace deletion when it is a mode where you want to do that.
Or else you would need to make write-file-hooks buffer-local (which I doubt you would want want to do --- the hook is used more generally).
Bad way:
(add-to-list 'write-file-functions 'delete-trailing-whitespace)
Better way is using ws-butler:
(straight-use-package 'ws-butler)
(add-hook 'prog-mode-hook #'ws-butler-mode)
ws-butler-mode remove spaces only on changed lines.
You would need to make the variable buffer local:
(defun nuke_traling ()
(make-variable-buffer-local 'write-file-hooks)
(add-hook 'write-file-hooks 'delete-trailing-whitespace))
But I would recommend using before-save-hook instead:
(defun nuke_traling ()
(add-to-list 'before-save-hook 'delete-trailing-whitespace))
write-file-hooks may be risky if used as a file-local variable, and documentation recomends using before-save-hook instead for thing like you want to do.
In emacs 21 or later you can add this hook to a perticular mode like this:
(add-hook 'prog-mode-hook
(lambda () (add-to-list 'write-file-functions 'delete-trailing-whitespace)))

emacs autoload modes

I am a newbie.
Now I want to
auto start yasnippet auto-complete gtags flymake modes
when I opening a (php/java/el/...) file.
What Should I put in my emacs config file ?
As liu says, you use add-hook to specify that an action be run when a particular mode is started. Documentation here. Hooks are analogous to events in C#, or the observer pattern in OOP.
Every mode should define a hook that is run when that mode is started, eg. for a mode named java-mode there is a corresponding hook called java-mode-hook. add-hook lets you wire an action to this hook:
(add-hook 'java-mode-hook 'my-action)
You can use anonymous lambda functions to define the action in-place, like so:
(add-hook 'java-mode-hook (lambda () (message "hello from java-mode")))
This will print a message whenever you start up java mode.
It is usually better to define a named function for the purpose. If you use named functions, add-hook will ensure the same function is not called multiple times.
(defun hello ()
(message "hello from java-mode"))
(add-hook 'java-mode-hook 'hello)
Language editing modes are derived from prog-mode. If you want to run an action when you start up any programming language mode, you add your function to prog-mode-hook.
You need to manually configure autocomplete mode for each mode you want to use it in. For each mode, add that mode to the ac-modes list:
(add-to-list 'ac-modes 'java-mode)
As a side note, you will want to use flyspell-prog-mode for programming language modes, so you only receive spelling suggestions in comments and string literals.
(defun on-prog-mode ()
(flyspell-prog-mode t))
(add-hook 'prog-mode-hook 'on-prog-mode)
And you will probably want to use flycheck instead of the older flymake. Flycheck is under active development and has checkers for php.
you can add just like below:
(global-auto-complete-mode t)
(yas-global-mode 1)
then update below accordingly:
(add-hook 'php-mode-hook (lambda () (flyspell-mode 1)))
(add-hook 'php-mode-hook (lambda()(gtags-mode 1)))

How does the following statement is interpreted by emacs

https://stackoverflow.com/a/663636/391104
(defun my-c++-mode-hook ()
(setq c-basic-offset 4)
(c-set-offset 'substatement-open 0))
(add-hook 'c++-mode-hook 'my-c++-mode-hook)
Based on my investigation, I just need to add the above code into my .emacs and then it works magically.
Q1> What does defun my-c++-mode-hook () mean? a function definition in lisp?
Q2> What is the usage of following line? where should I trigger it or it is run automatically by emacs
(add-hook 'c++-mode-hook 'my-c++-mode-hook)
Thank you
Q1: Yes, this is a function definition (hence defun). The second symbol is the name, which has the suffix '-hook' to indicate to humans that it is intended to be used as a hook. It could be given (almost) any arbitrary name without changing its behaviour. The empty () indicates the function takes no arguments. Everything else is the body of the function.
Q2: Basically, this adds a pointer to the previous function to the list of functions that are called when ever c++-mode is started. Whenever you start a mode, the Emacs looks for the mode hook, running all the functions in it. Both the function definition and the add-hook line need to go in your .emacs, and they will be run automatically when you start emacs.
To wrap your head around elisp, the introduction is highly recommended. It ships with emacs, and can be accessed from the info system: C-h i, then look for Elisp Introduction.

How can I apply a hook to multiple Emacs modes at once?

I was reading an article about well-formatted Git commits, and I was wondering how I could apply some of the rules to the Magit log mode.
It seems to use 3 major modes simultaneously: Magit, Log, Edit.
So how would I get just those modes, when used together, to hard-wrap at 72 characters automatically?
In answer to the original stated question, if you have a single function to add to numerous hook variables, you could do it like this:
(defun my-add-to-multiple-hooks (function hooks)
(mapc (lambda (hook)
(add-hook hook function))
hooks))
(defun my-turn-on-auto-fill ()
(setq fill-column 72)
(turn-on-auto-fill))
(my-add-to-multiple-hooks
'my-turn-on-auto-fill
'(text-mode-hook
magit-log-edit-mode-hook
change-log-mode-hook))
Not the best example, perhaps, but I have something similar for some common behaviours I want enabled in programming modes, of which there are a great many more to list.
Emacs modes have "base modes" which is to say bade modes. For example python-mode extends prog-mode which itself extends fundamental-mode. All modes extend fundamental-mode. So to hook python-mode plus c-mode but not text-mode, you could hook prog-mode.
There can be only one major mode in Emacs buffer (unless you are using something like MMM or MuMaMo). In your case that one major mode is magit-log-edit-mode, whose name consists of three words ("Magit Log Edit"). You can just add to it whatever hook you like:
(defun my-turn-on-auto-fill ()
(setq fill-column 72)
(turn-on-auto-fill))
(add-hook 'magit-log-edit-mode-hook 'my-turn-on-auto-fill)
In general, you could define your own function, say my-common-hook and add it to all the major modes, for example:
(defun my-common-hook ()
... do stuff ...
)
(add-hook 'one-mode-hook 'my-common-hook)
(add-hook 'another-mode-hook 'my-common-hook)
(add-hook 'a-third-mode-hook 'my-common-hook)
Just seeing this now, but here's what I've done. The end result is that i want to do the following:
(hook-up-modes my-lisps 'standard-lisp-environment).
To do this, i define the following defvars.
(defvar my-lisps "clojure lisp emacs-lisp cider-repl")
(defun standard-lisp-environment ()
(paredit-mode 1)
(rainbow-delimiters-mode 1)
(eldoc-mode 1))
I want to have lisp append -mode-hook to the lisps i use so i have the following:
(defun append-suffix (suffix phrases)
"take SUFFIX and append it to each of the PHRASES."
(mapcar #'(lambda (phrase) (concat phrase suffix)) phrases))
so that ("clojure" "lisp") => ("clojure-mode-hook" "lisp-mode-hook").
Now that we could easily have these, we need their reader symbols, which we easily get from
(defun symbols-from-strings (strings)
"Given a list of strings, get their symbol values"
(mapcar #'intern strings))
And then finally we have the similar form posted above:
(defun multiple-mode-add-hook (modes hook)
"Given a list of x-mode-hook symbols in MODE, add the HOOK to them."
(mapc (lambda (mode) (add-hook mode hook)) modes))
These all operate on the type that makes sense for them, list of strings, list of symbols 'blah-mode-hook, etc. So now we need a nice user facing function that we can work with.
(defun hook-up-modes (strings hook)
(let ((modes (symbols-from-strings
(append-suffix "-mode-hook" (split-string strings)))))
(multiple-mode-add-hook modes hook)))
Now this should be pretty legible: We create our modes from a space delimited list of strings and apply the hook to it. Also, since I've defined a standard-lisp-environment, all my lisps behave similarly, and I can easily remove the hook later if I like. Then the code that actually does work is the super simple phrase
(hook-up-modes my-lisps 'standard-lisp-environment).
(dolist (mode-hook '(org-mode-hook
term-mode-hook))
(add-hook mode-hook (lambda () (display-line-numbers-mode 0))))