Is Emacs supposed to have a hook.el file? - emacs

So I've got this file called hooks.el in my emacs.d with this kind of content:
(add-hook 'term-mode-hook ...)
(add-hook 'term-exec-mode-hook ...)
(add-hook 'python-mode-hook ...)
(add-hook 'ido-setup-hook ...)
(add-hook 'makefile-mode-hook ...)
(add-hook 'c-mode-common-hook ...)
(add-hook 'c-mode-hook ...)
(add-hook 'c++-mode-hook ...)
(add-hook 'dired-mode-hook
(lambda()
(define-key dired-mode-map "h" 'dired-previous-line)
(define-key dired-mode-map "j" 'ido-find-file)
;; ...
))
I was just wondering if I'm doing something weird here
or is this indeed the idiomatic way to assign shortcuts based on mode?
I mean here adding hooks instead of plainly writing:
(define-key dired-mode-map "h" 'dired-previous-line)
Of course, this won't work unless dired is loaded and dired-mode-map is defined,
hence the hook. And it's probably not the best thing to just load all the modes,
even if I'm not using them always, just to define the custom shortcuts.
But on the other hand, the hook is being run for every new buffer open -
and all these shortcuts are being redefined over and over, instead of just once.
What's your take one the matter? I'm sure there's something more optimal that I could switch to.
In the meantime, I can show off the bookmarklet for my hooks.el:
(defun goto-hook-file ()
"Opens hooks.el at point specific to current `major-mode'"
(interactive)
(let ((str-mode-hook (format "%s-hook" major-mode)))
(find-file (concat emacs.d "hooks.el"))
(goto-char (point-min))
(search-forward str-mode-hook nil t)))

You can use eval-after-load:
(eval-after-load 'dired
'(progn
(define-key dired-mode-map "h" 'dired-previous-line)
(define-key dired-mode-map "j" 'ido-find-file)))
That way, the keys are only defined once.

Related

Emacs ignoring setq for line numbers

I am trying to set up my .emacs to use relative line numbering, and so I have included:
(setq display-line-numbers 'relative)
to my .emacs, however this is being ignored on load. Line numbers appear, however they are simply absolute line numbers, as opposed to relative.
Interestingly, when I run M-x load-file .emacs, it actually evaluates this line (as well as the rest of the file) and the line numbers become relative, however this doesn't happen the first time.
Below is my entire .emacs, and the line in question is on line 95/96:
(package-initialize)
(load "~/.emacs.rc/rc.el")
(load "~/.emacs.rc/misc-rc.el")
(defun rc/get-default-font ()
(cond
((eq system-type 'windows-nt) "Consolas-13")
((eq system-type 'gnu/linux) "Iosevka-24")))
(add-to-list 'default-frame-alist `(font . ,(rc/get-default-font)))
(tool-bar-mode 0)
(menu-bar-mode 0)
(scroll-bar-mode 0)
(column-number-mode 1)
(show-paren-mode 1)
(rc/require-theme 'gruber-darker)
(custom-set-variables
;; custom-set-variables was added by Custom.
;; If you edit it by hand, you could mess it up, so be careful.
;; Your init file should contain only one such instance.
;; If there is more than one, they won't work right.
'(package-selected-packages
'(svelte-mode tramp-mode elixir-mode evil move-text nasm-mode company yasnippet multiple-cursors magit haskell-mode ido-completing-read+ smex gruber-darker-theme dash-functional dash)))
(custom-set-faces
;; custom-set-faces was added by Custom.
;; If you edit it by hand, you could mess it up, so be careful.
;; Your init file should contain only one such instance.
;; If there is more than one, they won't work right.
)
(eval-after-load 'zenburn
(set-face-attribute 'line-number nil :inherit 'default))
(rc/require 'smex 'ido-completing-read+)
(require 'ido-completing-read+)
(ido-mode 1)
(ido-everywhere 1)
(ido-ubiquitous-mode 1)
(global-set-key (kbd "M-x") 'smex)
(global-set-key (kbd "C-c C-c M-x") 'execute-extended-command)
;;; C mode
(setq-default c-basic-offset 4
c-default-style '((java-mode . "java")
(awk-mode . "awk")
(other . "bsd")))
(add-hook 'c-mode-hook (lambda ()
(interactive)
(c-toggle-comment-style -1)))
;;; Elisp
(add-hook 'emacs-lisp-mode-hook
'(lambda ()
(local-set-key (kbd "C-c C-j")
(quote eval-print-last-sexp))))
(add-to-list 'auto-mode-alist '("Cask" . emacs-lisp-mode))
;;; Haskell mode
(rc/require 'haskell-mode)
(setq haskell-process-type 'cabal-new-repl)
(setq haskell-process-log t)
(add-hook 'haskell-mode-hook 'haskell-ident-mode)
(add-hook 'haskell-mode-hook 'interactive-haskell-mode)
(add-hook 'haskell-mode-hook 'haskell-doc-mode)
(add-hook 'haskell-mode-hook 'hindent-mode)
;;; Whitespace mode
(defun rc/set-up-whitespace-handling ()
(interactive)
(whitespace-mode 1)
(add-to-list 'write-file-fucntions 'delete-trailing-whitespace))
(add-hook 'c++-mode-hook 'rc/set-up-whitespace-handling)
(add-hook 'java-mode-hook 'rc/set-up-whitespace-handling)
(add-hook 'emacs-lisp-mode 'rc/set-up-whitespace-handling)
(add-hook 'rust-mode-hook 'rc/set-up-whitespace-handling)
(add-hook 'haskell-mode-hook 'rc/set-up-whitespace-handling)
(add-hook 'python-mode-hook 'rc/set-up-whitespace-handling)
(add-hook 'erlang-mode-hook 'rc/set-up-whitespace-handling)
(add-hook 'asm-mode-hook 'rc/set-up-whitespace-handling)
(add-hook 'nasm-mode-hook 'rc/set-up-whitespace-handling)
(global-display-line-numbers-mode)
(setq display-line-numbers 'relative)
;;; Magit
(rc/require 'cl-lib)
(rc/require 'magit)
(setq magit-auto-revert-mode nil)
(global-set-key (kbd "C-c m s") 'magit-status)
(global-set-key (kbd "C-c m l") 'magit-log)
;;; Multiple Cursors
(rc/require 'multiple-cursors)
(global-set-key (kbd "C-S-c C-S-c") 'mc/edit-lines)
(global-set-key (kbd "C->") 'mc/mark-next-like-this)
(global-set-key (kbd "C-<") 'mc/mark-previous-like-this)
(global-set-key (kbd "C-c C-<") 'mc/mark-all-like-this)
(global-set-key (kbd "C-\"") 'mc/skip-to-next-like-this)
(global-set-key (kbd "C-:") 'mc/skip-to-previous-like-this)
;;; Dired
(require 'dired-x)
(setq dired-omit-files
(concat dired-omit-files "\\|^\\..+$"))
(setq-default dired-dwim-target t)
(setq dired-listing-switches "-alh")
;;; Yasnippet
(rc/require 'yasnippet)
(require 'yasnippet)
(setq yas/triggers-in-field nil)
(setq yas-snipped-dirs '("~/.emacs.snippets/"))
(yas-global-mode 1)
;;; Word-Wrap
(defun rc/enable-word-wrap ()
(interactive)
(toggle-word-wrap 1))
(add-hook 'markdown-mode-hook 'rc/enable-word-wrap)
;;; Company Mode
(rc/require 'company)
(require 'company)
(global-company-mode)
;;; NASM mode
(rc/require 'nasm-mode)
(add-to-list 'auto-mode-alist '("\\.asm\\'" . nasm-mode))
;;; TeX mode
(add-hook 'tex-mode-hook
(lambda ()
(interactive)
(add-to-list 'tex-verbatim-environments "code")))
;;; Move Text
(rc/require 'move-text)
(global-set-key (kbd "M-p") 'move-text-up)
(global-set-key (kbd "M-n") 'move-text-down)
(rc/require
'rust-mode
'markdown-mode
'elixir-mode
'svelte-mode
)
;;; Svelte Mode
(add-to-list 'auto-mode-alist '("\\.svelte\\'" . svelte-mode))
;;; Kill all buffers
(defun kill-all-buffers ()
(interactive)
(dolist (cur (buffer-list))
(kill-buffer cur)))
(defun close-current-buffer ()
(interactive)
(kill-buffer (buffer-name)))
(global-set-key (kbd "C-x K") 'kill-all-buffers)
(global-set-key (kbd "C-S-w") 'close-current-buffer)
(defun indent-whole-file ()
(interactive)
(indent-region (point-min) (point-max)))
(global-set-key (kbd "C-<tab>") 'indent-whole-file)
(global-set-key (kbd "C-=") 'text-scale-increase)
(global-set-key (kbd "C--") 'text-scale-decrease)
Did you read this part of the doc for display-line-numbers:
This variable automatically becomes buffer-local when set outside Custom.
However, setting it through Custom sets the default value.
You're using setq with a user option - not a great idea in general. Use M-x customize-option instead, or use function customize-set-variable or custom-set-variables.
Unless you do some tricky finagling, you can't depend on your setq being evaluated in any particular buffer. And anyway, you apparently want to set the default value of the option. setq-default sets the default value of a variable. But anyway, use one of the custom* functions or (even better), M-x customize-option.
You need to use display-line-numbers-type instead as per the documentation
"The command M-x display-line-numbers-mode provides a convenient way to turn on display of line numbers. This mode has a globalized variant, global-display-line-numbers-mode. The user option display-line-numbers-type controls which sub-mode of line-number display, described above, these modes will activate."
So following works.
(global-display-line-numbers-mode 1)
(setq display-line-numbers-type 'relative)

Evil Emacs: is there a way to disable vim-like keys in «insert» mode?

I like VIM idea of text objects, so I installed EVIL (a Emacs plugin to emulate VIM features). But I'd like «insert» mode to leave Emacs keybindings unchanged (except perhaps Escape which is to switch into «normal» mode). Any way to achieve this?
By the way: ATM «insert» mode have a mixed set of hotkeys, which isn't very comfortable either way. E.g. the «M-b» works as in Emacs, but the «C-o» works as in VIM.
In the #emacs IRC channel I was told that someone already solved a similar problem. Here's the modified version I use:
(require 'evil)
;; remove all keybindings from insert-state keymap
(setcdr evil-insert-state-map nil)
;; but [escape] should switch back to normal state
(define-key evil-insert-state-map [escape] 'evil-normal-state)
(define-key evil-normal-state-map (kbd "C-u") 'evil-scroll-up)
(define-key evil-normal-state-map (kbd "[ m") 'beginning-of-defun)
(define-key evil-normal-state-map (kbd "] m") 'end-of-defun)
(define-key evil-normal-state-map (kbd "k") 'evil-previous-visual-line)
(define-key evil-normal-state-map (kbd "j") 'evil-next-visual-line)
(evil-mode t)
(setq evil-jumps-cross-buffers nil) ;; for C-o and C-i to not cross buffers
(provide 'emvil)
The (provide 'emvil) is to allow require 'ing it in the configuration. I also found it useful to jump-to-definition in the next split screen unless the definition is in the buffer I'm currently in. Here's the code:
(defun evil-goto-definition-next-split ()
"If there's a free split, goto definition in this split,
otherwise use current one (except when a definition in the
current split)"
(interactive)
(let ((origin-spl (selected-window))
(origin-buf (current-buffer)))
(evil-goto-definition)
(when (and (eq origin-spl (selected-window)) ;; otherwise it's done
(not (eq origin-buf (current-buffer)))) ;; otherwise either definition not found, or
;; it's in the same buffer
(let ((defin-buf (current-buffer))
(defin-point (point)))
(switch-to-buffer origin-buf)
(other-window 1)
(switch-to-buffer defin-buf)
(goto-char defin-point)
))
))
(define-key evil-normal-state-map (kbd "g d") 'evil-goto-definition-next-split)

wrong type argument commandp with a custom function in emacs

I know this type of question have been asked by many people,
but I have read many similar posts and still have no idea
what to do. So here is the elisp code in .emacs:
;; send line to python console
(require 'python-mode)
(defun py-execute-line-down ()
"execute python line and move cursor down"
(progn
(py-execute-line)
(evil-next-line)))
(add-hook 'python-mode-hook
(lambda () (define-key python-mode-map (kbd "C-c C-j") 'py-execute-line-down)))
I also tried to add (interactive) into the function, it didn't work.
Just to keep the record here, this seemed to do the trick, not sure if it's optimal though:
;; send line to python console
(require 'python-mode)
(defun py-execute-line-down ()
"execute python line and move cursor down"
(interactive)
(py-execute-line)
(evil-next-line 1))
(defun kaiyin-pykeys ()
"python mode custome keys"
(local-set-key (kbd "C-c j") 'py-execute-line-down)
)
(add-hook 'python-mode-hook 'kaiyin-pykeys)
Taking Dan's advice, I changed the above into:
;; send line to python console
(require 'python-mode)
(defun py-execute-line-down ()
"execute python line and move cursor down"
(interactive)
(py-execute-line)
(forward-line 1))
(define-key python-mode-map (kbd "C-c j") 'py-execute-line-down)

How to unset a keybinding in a map locally to a mode?

I have set up a key binding for a function that modifies the behavior of Emacs auto-complete:
;; ISSUE: when I type the whole candidate string and then press [SPC],
;; Emacs will insert two spaces.
(define-key ac-menu-map (kbd "SPC")
(defun ac-complete-with-space ()
"Select the candidate and append a space. Save your time for typing space."
(interactive)
(ac-complete)
;; FIXME: this auto-inserts two spaces.
(insert " ")
))
... and I want to disable this key binding in ac-menu-map in org-mode only.
I have tried the following:
;; Avoid always selecting unwanted first candidate with auto-complete
;; when writing in org-mode.
(add-hook 'org-mode-hook
(lambda ()
;; (define-key ac-menu-map (kbd "SPC") nil)
;; (define-key ac-menu-map (kbd "SPC") 'self-insert-command)
;; (setq-local ac-menu-map (delq (kbd "SPC") ac-menu-map))
))
Unfortunately, this does not unset the key binding locally (i.e., only in org-mode). Instead, it removes the key binding from the ac-menu-map everywhere.
A different approach to solve your problem would be to check in ac-complete-with-space the mode. If org-mode, then call self-insert-command, else follow your current logic.
(defun ac-complete-with-space ()
"Select the candidate and append a space. save your time for typing space."
(interactive)
(ac-complete)
(insert " ")
)
;; NOTE: ac-completing-map is the parent map of ac-menu-map.
(define-key ac-completing-map (kbd "SPC") 'ac-complete-with-space)
(add-hook 'org-mode-hook
(lambda ()
(define-key ac-menu-map (kbd "SPC") 'self-insert-command)))

Emacs dired use the same buffer

I use the following code in .emacs:
(require 'dired+)
(toggle-diredp-find-file-reuse-dir 1)
So it won't create a buffer for every dir I visit. Then I decided to add some ergonomics:
(add-hook 'dired-mode-hook
(lambda ()
(define-key dired-mode-map (kbd "C-<up>") 'dired-up-directory)))
So when I click Ctrl-<up> it will move to the parent directory. But it opens the parent dir in a new buffer.
How to make it open in the same buffer?
The solution can be found there:
(add-hook 'dired-mode-hook
(lambda ()
(define-key dired-mode-map (kbd "C-<up>")
(lambda () (interactive) (find-alternate-file "..")))
; was dired-up-directory
))