Why are my mode specific .emacs hooks running for all modes? - emacs

I'm running the following code in my .emacs file:
(defun load-hooks ()
(add-hook 'after-save-hook 'my-hook))
(add-hook 'c-mode-hook 'load-hooks)
(defun my-hook () ... )
However, the content in my-hook is running on save even when I'm in a different mode. Am I missing a step?

You should use the LOCAL argument to add-hook, which will make sure that the hook only affects the current buffer:
(defun load-hooks ()
(add-hook 'after-save-hook 'my-hook nil t))
(add-hook 'c-mode-hook 'load-hooks)
(defun my-hook () ...)

I think that calling (add-hook 'after-save-hook 'my-hook) in load-hooks adds the hook to all modes. That is, once that function is called, after-save-hook is modified for every other buffer as well.
I suspect that your hook would not be run unless you open a c file. Try opening some file without having opened any c files and see if anything is run. If it isn't it just means that the function that runs for c files modifies the save hook for everything else.

Tikhon was correct about the 'after-save-hook affecting all modes - I am now relying on a check using the following functions:
(defun in-c-mode? ()
(string= (current-major-mode) "c-mode"))
(defun current-major-mode ()
(with-current-buffer (current-buffer) major-mode))

Related

emacs init - splitting window and opening files next to each other

I am trying to customize my Emacs init file in such a way that Emacs opens with two windows split and the ansi-term opened in one side and my init file on the other side. Now, the function I wrote (switch-to-next-window) works perfectly if Emacs is open already.
I was hoping to make the cursor switch to the other window and then open my init file there. However, if I try to run this upon start-up (actually after start up, at least this is what I am thinking) I get the following error: window-live-p, nil
I am gessing that there is no "next window". But I just don't know a work around here since I do think that I am only calling my function after Emacs has fully started up? If anyone could point me to where I am going wrong in my logic, that would be great!
(split-window-horizontally)
(setq initial-buffer-choice "*ansi-term*")
(defun switch-to-next-window ()
(interactive)
(let* ((next-window (get-buffer-window (other-buffer (current-buffer) t))))
(select-window next-window)))
(add-hook 'emacs-startup-hook (lambda ()(ansi-term "/bin/bash")))
(with-eval-after-load "~/.emacs.d/init.el"
(switch-to-next-window)
(setq initial-buffer-choice "~/.emacs.d/init.el"))
Changing initial-buffer-choice after the initial buffer has been opened won't have any effect.
What helps is putting everything into the emacs-startup-hook and using the find-file-other-window function:
(add-hook 'emacs-startup-hook
(lambda ()
(ansi-term "/bin/bash")
(split-window-horizontally)
(find-file-other-window "~/.emacs.d/init.el")))

add a hook in prog-mode except a particular mode

i have a function
(defun a--before-test-save-hook()
"Test of before save hook"
(message "foobar"))
and i want to run it in prog-mode except python-mode,
but i have no clue now
and i just add-hook in prog-mode including python-mode
(add-hook 'prog-mode (lambda ()
(add-hook 'before-save-hook 'a-test-before-save-hook t t)))
i have try
(defun a-test-before-save-hook()
"Test of before save hook"
(unless (eq major-mode 'python-mode)
(message "foobar")))
but i want a better try,any solution will be appreciated.
Not sure if it's better, but you could do:
(add-hook 'prog-mode-hook
(lambda ()
(unless (derived-mode-p 'python-mode)
(add-hook 'before-save-hook
#'a-test-before-save-hook t t))))
Of course, my own reflex is to ask "what makes Python special?". The answer might let you replace the (derived-mode-p 'python-mode) test with something that goes more directly at the heart of the issue (e.g. maybe the issue is related to indentation-significance and would hence also apply to Coffeescript and Haskell and maybe you could check electric-indent-inhibit instead).

Emacs: load-file .emacs when saved

I'm new to emacs and lisp.
I wanted to auto-load the dot file when it was saved. Meaning, when I save my .emacs file, it would automatically call load-file on it (thus letting me know right away if I messed up).
But I can't seen to be able to find a comprehensive tutorial on hooks in emacs.
This is what I've come up with:
(defun load-init-after-save ()
"After saving this file, load it"
(if (eq bname this) ('load-file this) (nil))
)
(add-hook 'after-save-hook 'load-init-after-save)
Of course, this is incorrect: bname and this are just placeholders. And I don't want this function to run on all saves, just when the .emacs file is saved.
Does anyone know how to do this? Is there a better, easier way?
The following code loads your .emacs or ~/.emacs.d/init.el file after save:
(defun my-load-user-init-file-after-save ()
(when (string= (file-truename user-init-file)
(file-truename (buffer-file-name)))
(let ((debug-on-error t))
(load (buffer-file-name)))))
(add-hook 'after-save-hook #'my-load-user-init-file-after-save)
Since your intended use is error-checking, the code also enables the debugger while loading the init file, so that you get a nice backtrace in case of errors.
For error checking of your init file you may also find Flycheck useful. It checks your init file on the fly with the byte compiler, highlights any errors and warnings in the buffer, and—optionally—gives you a list of all errors and warnings.
Disclaimer: I'm the maintainer of this library.
Way 1
One way of doing is to install auto-compile-mode from MELPA, and enable it:
(defun my-emacs-lisp-hook ()
(auto-compile-mode 1))
(add-hook 'emacs-lisp-mode-hook 'my-emacs-lisp-hook)
Now each time you save an Elisp file that's byte-compiled, it will be
re-compiled. Compilation will usually catch some bad errors.
To compile any Elisp file, select it in dired (C-x d)
and press B (dired-do-byte-compile).
Way 2
Use this custom code I wrote.
(defun test-emacs ()
(interactive)
(require 'async)
(async-start
(lambda () (shell-command-to-string "emacs --batch --eval \"(condition-case e (progn (load \\\"~/.emacs\\\") (message \\\"-OK-\\\")) (error (message \\\"ERROR!\\\") (signal (car e) (cdr e))))\""))
`(lambda (output)
(if (string-match "-OK-" output)
(when ,(called-interactively-p 'any)
(message "All is well"))
(switch-to-buffer-other-window "*startup error*")
(delete-region (point-min) (point-max))
(insert output)
(search-backward "ERROR!")))))
(defun auto-test-emacs ()
(when (eq major-mode 'emacs-lisp-mode))
(test-emacs))
(add-hook 'after-save-hook 'auto-test-emacs)
This will start a new Emacs instance in the background each time you
save a file. If something goes wrong, it will complain.
The second approach uses async.
If you really want to do this just for .emacs user this:
(defun auto-test-emacs ()
(when (and (eq major-mode 'emacs-lisp-mode)
(equal (file-truename user-init-file)
(expand-file-name
buffer-file-truename)))
(test-emacs)))

why mode isn't enabled?

I've got an emacs configuration file whatever.el :
(abbrev-mode +1)
(provide 'whatever)
and in my init.el :
(require 'whatever)
but when i start emacs, abbrev-mode isn't enabled. why ?
thank you
Quoting from http://emacswiki.org/emacs/AbbrevMode:
You can also put the following in your ~/.emacs file if you want it
always on:
(setq default-abbrev-mode t)
If you only want it on in text and derived modes, you could do
something like this:
(add-hook 'text-mode-hook (lambda () (abbrev-mode 1)))
For multiple modes, use something like the following:
(dolist (hook '(erc-mode-hook
emacs-lisp-mode-hook
text-mode-hook))
(add-hook hook (lambda () (abbrev-mode 1))))
Abbrev-mode is enabled per-buffer.
One way is to create a hook function that you could add to the major mode hooks you will want to use it in.
For example:
(defun my-enable-abbrev-mode ()
(abbrev-mode 1))
(add-hook 'c-mode-hook 'my-enable-abbrev-hook)
(add-hook 'java-mode-hook 'my-enable-abbrev-hook)
Another approach is to use change-major-mode-hook.
While others explained how to get what you presumably want, I'll just point out that w.r.t to your actual question ("Why?"), the reason is simple: abbrev-mode is a buffer-local minor-mode, so when you run (abbrev-mode +1) at startup it will just enable abbrev-mode in the buffer that happens to be current during evaluation of the ~/.emacs (typically scratch) but not in subsequent buffers.

How to call a function in a user defined function im Emacs?

I use defun to define a function in my .emacs file:
(defun myfun ()
"i am already loaded the color-theme lib"
(color-theme-initialize)
(color-theme-darkblue))
Then I want to use this function in my mode-hook:
(add-hook 'python-mode-hook
'(lambda ()
(myfun)
(...)))
But I got an error saying that the color-theme-initialize function is void.
P.S. my ~/.emacs snippet
(progn (require 'color-theme)
(color-theme-initialize))
(progn (setq-default indent-tabs-mode nil)
(setq-default tab-width 2)
(setq indent-line-function 'insert-tab))
(add-hook 'emacs-lisp-mode-hook
'(lambda ()
(color-theme-resolve)
(show-paren-mode t)
(linum-mode t)))
You need to require (or otherwise load) the library which provides color-theme-initialize. I'm guessing (require 'color-theme).
Read the error, it's not your function that cannot be called, but the
function named color-theme-initialize. This function has been
removed some times ago but can still be present in some older version
of color-theme. Thus, check your version of color-theme and see if
there is a function called color-theme-initialize (with
C-hfcolor-theme-initializeRET). If
the function is present then you have to (require 'color-theme),
otherwise you don't need to call this function.