Remove major mode key bindings in emacs - emacs

I installed a new major mode (sunrise commander), and I want to reset all its predefined key bindings.
Although I can use
(add-hook 'sr-mode-hook
'(lambda ()
(define-key sr-mode-map "KEY" nil)
...
))
this mode have so many bindings, it's a tag tedious to my taste.
Is there a way to completely reset the key bindings of this major mode in a one-liner or few-liners?
EDIT #1:
I tried using these methods as described below:
(eval-after-load "sunrise"
'(setq sr-mode-map (make-sparse-keymap)))
OR
(add-hook 'sr-mode-hook
(lambda ()
(setq sr-mode-map (make-sparse-keymap))))
Sadly, neither of them seems to work.
Do I actually need to define a new, empty keymap?
E.g. using
(defvar sunrise-keys-mode-map (make-keymap) "sunrise-keys-mode keymap.")
(define-minor-mode sunrise-keys-mode
"A minor mode so that my key settings override sunrise major mode keymap."
t " my-keys" 'sunrise-keys-mode-map)
(sunrise-keys-mode 1)
(eval-after-load "sunrise" ;; Fix this line to include the correct library name
'(setq sr-mode-map (sunrise-keys-mode)))
EDIT #2:
After a bit of tinkering in the sunrise commander code, I noticed that the sr-mode-map is based on the dired mode map. I disabled both, and it worked perfectly.
(eval-after-load "sunrise-commander"
'(setq sr-mode-map (make-sparse-keymap)
dired-mode-map (make-sparse-keymap)))
For future reference - the above is the only code needed.
make-sparse-keymap is a function that returns an empty keymap (unless provided with an argument, apparently).

You cound bind sr-mode-map to a newly-created, empty keymap:
(setq sr-mode-map (make-sparse-keymap))
You might need to delay this until after sunrise commander is loaded:
(eval-after-load "sc" ;; Fix this line to include the correct library name
'(setq sr-mode-map (make-sparse-keymap)))

Related

Define key-chord key with specific mode

How do you define a key-chord key only in specific mode, for example I want to bind a cider repl to a specific key only in clojure-mode or cider-mode. I can only find an example that activates the key globally.
Thanks for your help.
EDIT:
(require 'evil)
(require 'key-chord)
(evil-mode 1)
(key-chord-mode 1)
(key-chord-define evil-insert-state-map "jk" 'evil-normal-state)
(key-chord-define-global "gt" 'other-window)
(key-chord-define clojure-mode-hook "gj" 'cider-jack-in)
;; error : Wrong type argument: keymapp, (rainbow-delimiters-mode)
(provide 'init-evil)
Defining mode-specific key bindings
Here is an example of how to do this:
(define-key clojure-mode-map (kbd "C-c r") 'cider-repl)
... where of course you would have to replace cider-repl with the specific command you want to bind. Note that the quote ' before the command name is required.
To generalize:
(define-key <mode-map> <key-binding> '<command>)
key-chord-specific instructions
You need to change the line where you're trying to set up the clojure-mode-specific key binding to
(add-hook 'clojure-mode-hook
(lambda () (key-chord-define clojure-mode-map "gj" 'cider-jack-in)))
Appendix: Making sure mode-maps are defined before modifying them
In order for modifications to clojure-mode-map to work properly, you have to make sure it is defined when you call define-key as described above.
If you are using the Emacs Package Manager, you are likely to have this line
(package-initialize)
somewhere in your .emacs file (which takes care of loading packages installed via package-install). Make sure you call define-key somewhere below this line.
Alternatively you can add the call to define-key to the hook that is run when clojure-mode is enabled:
(defun clojure-set-up-key-bindings ()
(define-key clojure-mode-map (kbd "C-c r") 'cider-repl)
;; If necessary, add more calls to `define-key' here ...
)
(add-hook 'clojure-mode-hook 'clojure-set-up-key-bindings)

Emacs: Translating C-h to DEL, M-h to M-DEL

I want my C/M-h keys to be a binding for delete.
The usual solution of global-set-key doesn't work for me, as I want these keys to behave as delete everywhere including the minibuffer and various modes, and be able to work between my various Linux/OS X/Windows emacs installations.
I have the following near solution:
(when (>= emacs-major-version 23)
(setq help-char (string-to-char "<f1>")) ;; Bind ONLY F1 to help, not C-h
(define-key input-decode-map (kbd "C-h") (kbd "DEL")) ;; Translate C-h to DEL ;; FIXME: Should be in emacs 22, doens't work.
(define-key input-decode-map (kbd "M-h") (kbd "M-<DEL>")) ;; Translate M-h to M-DEL
;; (define-key input-decode-map (kbd "<backspace>") 'version) ;; Stop me using backspace for a while
)
But this obviously only works with Emacs > 22, due to input-decode-map.
Would someone be able to help me find a solution that works in 22, maybe even 21? (Not a priority however). Cheers!
Edit: My Solution:
It's not quite there yet, but this has solved most of my issues:
(setq help-char [f1]) ;; I don't want help when I'm just trying to backspace!
(define-key isearch-mode-map "\C-h" 'isearch-delete-char)
;; (define-key isearch-mode-map "\M-h" 'my-isearch-delete-word)
(defvar my-overriding-binding-mode-map
(let ((map (make-sparse-keymap)))
(define-key map [?\C-h] 'delete-backward-char)
(define-key map [?\M-h] 'backward-kill-word)
map))
(define-minor-mode my-overriding-binding-mode
"Personal global key-bindings."
:global t)
(my-overriding-binding-mode 1)
There's probably some caveats for some misbehaving modes that need to be written - I'll do that as I come across them. The only real problem now seems to be M-h in isearch, which I'll post as a seperate question.
Thanks again guys, you've been a great help.
Here's the first, and most important, part of the answer, with the explanations all given in the elisp comments. This has been tested mostly in X11 environments, but including with a Mac keyboard. It has been tested starting with v19.28, and up to and including v23.3. I think it works with v24, but I have not yet used v24 very much.
You can find my complete (though not always 100% up-to-date) ~/.emacs.el in the following repository of initialization and configuration files:
https://github.com/robohack/dotfiles
and so specifically ~/.emacs.el is at:
https://github.com/robohack/dotfiles/blob/master/.emacs.el
;;; first off, we do some fancy stuff to make C-h work "properly," but still
;;; have good access to the help functions!
;;;
;;; Using C-h for "help" might seem OK to some folks, but since it's also the
;;; ASCII standard value for the "backspace" character, one typically used ever
;;; since the days of the typewriter to move the cursor backwards one position
;;; and in computing normally to erase any character backed over, a vast amount
;;; of stupidity is needed in emacs to continue to (ab)use as the "help"
;;; character. Instead it is still quite intuitive, and often much easier in
;;; zillions of environments, to use M-? for help.
;;;
;;; So, we can set C-h and C-? and friends to sensible bindings...
;;
;; Remember to call override-local-key-settings in the appropriate hooks to fix
;; up modes which violate global user preferences....
;;
(global-set-key "\C-h" 'delete-backward-char)
(global-set-key "\C-?" 'delete-char)
(global-set-key "\e\C-h" 'backward-kill-word)
(global-set-key "\e\C-?" 'kill-word)
;;; and then we diddle with help to make it work again....
;;
;; Oddly, the help interface in emacs is extremely scatter-brained, with
;; several slightly different ways of doing the same thing. This is probably
;; due to the fact that several different programmers have implemented various
;; bits and pieces of the help systems. See help.el and help-macro.el, but try
;; not to tear your hair out when you find out help-event-list in 19.34 is
;; essentially bogus, since it is simply an extension to a "standard" list.
;;
;; Remember to call override-local-key-settings in the appropriate hooks to fix
;; up modes which violate global user preferences....
;;
(global-set-key [f1] 'help-command) ; first do this for 19.28.
(global-set-key "\e?" 'help-command) ; this is the first step to set up help
(global-set-key "\e?F" 'view-emacs-FAQ) ; in 19.34 it needs more help...
;; should help-char be just ? instead?
(setq help-char ?\M-?) ; this should "fix" the rest.
;; one more handy help-related binding...
;;
(define-key help-map "?" 'describe-key-briefly) ; also C-x? for Jove compat
;;; Now for function key mappings...
;;;
;;; I USUALLY EXPECT THE BACKSPACE KEY TO WORK LIKE AN ASCII BACKSPACE!
;;
;; For some entirely un-fathomable reason the default function bindings make
;; the 'backspace' and 'delete' keys synonymous!
;;
;; NOTE: this *should* work by simply reading termio for current erase char.
;;
;; As of emacs-21.2 a note was added to the NEWS file which says "** On
;; terminals whose erase-char is ^H (Backspace), Emacs now uses
;; normal-erase-is-backspace-mode." Unfortunately this does EXACTLY the WRONG
;; thing, and in a totally bizzare, disruptive, subversive, and stupid
;; backwards way. With every major release it's gotten worse and worse and
;; worse; more convoluted, and ugly.
;;
;; So, we must do something to kill that horrible stupid broken poor
;; useless excuse for a feature, normal-erase-is-backspace-mode....
;;
;; seems 23.1 changes function-key-map radically....
;;
;; Unfortunately 23.1 also still has function-key-map so we can't make that
;; (function-key-map) an alias for the new local-function-key-map that we need
;; to use in 23.1 to modify key translations. Sigh.
;;
;; Instead make a new alias that can be used transparently as the desired map.
;;
(eval-and-compile
(if (functionp 'defvaralias) ; since 22.1
(if (boundp 'local-function-key-map)
(defvaralias 'my-function-key-map 'local-function-key-map
"Special variable alias to allow transparent override of
`local-function-key-map' for 23.1 vs 22.3(?).")
(defvaralias 'my-function-key-map 'function-key-map
"Special variable alias to allow transparent override
of `function-key-map' for 22.3(?) vs. older,"))
;; XXX is this right? it works (maybe?)
(defvar my-function-key-map function-key-map)))
;;
;; First undo (local-)function-key-map weirdness.
;;
;; luckily on Mac OS-X X11, at least with the mini-wireless keyboard and on the
;; large USB keyboard, the big "delete" key on the main block is actually
;; sending <backspace> by default, else one would have to first change the X11
;; keyboard map!
;;
(define-key my-function-key-map [delete] [?\C-?])
(define-key my-function-key-map [S-delete] [?\C-h])
(define-key my-function-key-map [M-delete] [?\C-\M-?])
(define-key my-function-key-map [kp-delete] [?\C-?])
(define-key my-function-key-map [backspace] [?\C-h])
(define-key my-function-key-map [S-backspace] [?\C-?])
;;(define-key my-function-key-map [C-backspace] [?\C-h]) ; sometimes *is* DEL....
(define-key my-function-key-map [M-backspace] [?\e?\C-h])
(define-key my-function-key-map [M-S-backspace] [?\e?\C-?])
(define-key my-function-key-map [kp-backspace] [?\C-h])
;;
;; Next, zap the keyboard translate table, set up by
;; normal-erase-is-backspace-mode (in simple.el), which can do nothing
;; but confuse!
;;
(setq keyboard-translate-table nil)
;;
;; Finally, kill, Kill, KILL! the input-decode-map added in 23.x, and set
;; up by normal-erase-is-backspace-mode (in simple.el) which can do
;; nothing but confuse!
;;
;; This is TRULY _E_V_I_L_!!!! HORRID!!! MASSIVELY STUPID!!!!
;;
;; input-decode-map is poorly documented, and causes things above and
;; below to fail with the most confusing errors!
;;
;; (This probably only needs to be blown away on window systems, and
;; perhaps only for X, but doing it here now is apparently early enough
;; to allow for terminal mode specific settings to be re-applied to it
;; and so it seems safe to just blow away the asinine stupid attempt to
;; transpose backspace and delete. RMS is a pedantic idiot on this!)
;;
(if (boundp 'input-decode-map)
(setq input-decode-map (make-sparse-keymap)))
;; finally here's a little function to help fix up modes which don't honour default
;; bindings in sensible ways. Use this in any init hooks for modes which cause problems
;;
(defun override-local-key-settings ()
"User defined function. Intended to be called within various hooks to
override the value of buffer-local key map settings which may have been
overridden without consideration by the major mode."
(local-set-key "\C-?" 'delete-char) ; many modes
(local-set-key "\C-h" 'delete-backward-char) ; sh-mode
;; the rest are *not* overridden by cc-mode, but are by c-mode
(local-set-key "\e\C-h" 'backward-kill-word) ; text-mode
(local-set-key "\e?" 'help-command) ; nroff-mode
(local-set-key "\eh" 'mark-c-function)
(local-set-key "\e\C-?" 'kill-word)
(local-set-key "\e\C-e" 'compile)
;; try this on for size...
(local-set-key "\C-x\e\C-e" 'recompile)
)
(add-hook 'isearch-mode-hook
(function
(lambda ()
"Private isearch-mode fix for C-h."
(define-key isearch-mode-map "\C-h" 'isearch-delete-char))))
;;; OK, that's the end of the stuff to fix GNU Emacs' C-h brain damage. Phew!
Then I recommend you use a minor-mode:
(defvar my-overriding-binding-mode-map
(let ((map (make-sparse-keymap)))
(define-key map [?\C-h] 'delete-backward-char)
(define-key map [?\M-h] 'backward-kill-word)
map))
(define-minor-mode my-overriding-binding-mode
"Personal global key-bindings."
:global t)
(my-overriding-binding-mode 1)

eval-after-load vs. mode hook

Is there a difference between setting things for a mode using eval-after-load and using the mode hook?
I've seen some code where define-key is used inside a major mode hook, and some other code where define-key is used in eval-after-load form.
Update:
For better understanding, here is an example of using eval-after-load and mode hooks with org-mode. The code can run before (load "org") or (require 'org) or (package-initialize).
;; The following two lines of code set some org-mode options.
;; Usually, these can be outside (eval-after-load ...) and work.
;; In cases that doesn't work, try using setq-default or set-variable
;; and putting them in (eval-after-load ...), if the
;; doc for the variables don't say what to do.
;; Or use Customize interface.
(setq org-hide-leading-stars t)
(setq org-return-follows-link t)
;; "org" because C-h f org-mode RET says that org-mode is defined in org.el
(eval-after-load "org"
'(progn
;; Establishing your own keybindings for org-mode.
;; Variable org-mode-map is available only after org.el or org.elc is loaded.
(define-key org-mode-map (kbd "<C-M-return>") 'org-insert-heading-respect-content)
(define-key org-mode-map (kbd "<M-right>") nil) ; erasing a keybinding.
(define-key org-mode-map (kbd "<M-left>") nil) ; erasing a keybinding.
(defun my-org-mode-hook ()
;; The following two lines of code is run from the mode hook.
;; These are for buffer-specific things.
;; In this setup, you want to enable flyspell-mode
;; and run org-reveal for every org buffer.
(flyspell-mode 1)
(org-reveal))
(add-hook 'org-mode-hook 'my-org-mode-hook)))
Code wrapped in eval-after-load will be executed only once, so it is typically used to perform one-time setup such as setting default global values and behaviour. An example might be setting up a default keymap for a particular mode. In eval-after-load code, there's no notion of the "current buffer".
Mode hooks execute once for every buffer in which the mode is enabled, so they're used for per-buffer configuration. Mode hooks are therefore run later than eval-after-load code; this lets them take actions based upon such information as whether other modes are enabled in the current buffer.

How to set a keybinding which is valid in all modes in Emacs [duplicate]

This question already has answers here:
Globally override key binding in Emacs
(8 answers)
Closed 8 years ago.
I've configured my emacs to use M-j as backward-char by
(global-set-key (kbd "M-j") 'backward-char) ; was indent-new-comment-line
in my .emacs file. This works fine in many modes (text/org/lisp).
But in c++-mode & php-mode it is bound to the default c-indent-new-comment-line
How can I bind M-j to use backward-char in these modes too.
And in general for ALL modes.
Thanks,
AnotherEmacsLearner
There are policies about which keys are supposed to be mode-dependent and which not. You can overrule bindings changed by a specific mode, but it is a hassle and has to be done for every mode you will be using. It is smarter to keep your own cross-cutting neato bindings to keys that major modes will not touch out of principle. I particularly like the F1-F12 keys for that, or the Sun Function keys when I can get them. The C-c + letter sequences are also explicitly reserved for user-defined commands and will not be rebound by major modes. (See: Key Binding Conventions)
I unset keys that are in the way for specific modes like this:
(add-hook 'gnus-summary-mode-hook
(function (lambda ()
(local-unset-key '[M-down])
(local-unset-key '[M-up]))))
(add-hook 'org-mode-hook
(function (lambda ()
(local-unset-key '[S-down])
(local-unset-key '[S-left])
(local-unset-key '[S-right])
(local-unset-key '[S-up]))))
This issue was addressed in this question. The way to do this is to create a minor mode with your bindings. Your minor mode bindings will shadow any major mode's bindings.
I like your example, since just within the last couple of weeks, I rebound M-h,j,k,l to their equivalent vim movements, and made a minor mode to do it (It turned out to be a great idea. Emacs's default bindings really are terrible). Here's a sample of some of my code:
(defvar kirkland-minor-mode-map (make-keymap) "kirkland-minor-mode keymap.")
(define-key kirkland-minor-mode-map (kbd "M-h") 'backward-char)
(define-key kirkland-minor-mode-map (kbd "M-l") 'forward-char)
(define-key kirkland-minor-mode-map (kbd "M-j") 'next-line)
(define-key kirkland-minor-mode-map (kbd "M-k") 'previous-line)
(define-minor-mode kirkland-minor-mode
"A minor mode so that my key settings aren't shadowed by other major/minor modes"
t " kirkland" 'kirkland-minor-mode-map)
One other thing I should mention is that while this will override any major mode bindings, it can still be overridden by other minor modes which are loaded later.
Nothing can stop any mode from redefining any key any way it wants and it always shadows the global-set-key. So you have to redefine it for every mode that redefines it:
(defun redefine-cc-mode-keys ()
(define-key c-mode-base-map "M-J" 'backward-char))
(add-hook 'c-initialization-hook 'redefine-cc-mode-keys)
or similar.

Code completion key bindings in Emacs

When doing a M-x describe-mode in a .el file, I noticed that the Emacs-Lisp mode actually does code completion. However, lisp-complete-symbol is bound to M-TAB. In Windows, this key binding is taken by Windows for switching the active window. Most IDE's use C-SPC, but that's taken in Emacs as well. What is a good, fairly common key binding for code completion?
If you like completion of all kinds, I recommend M-/ and binding that to hippie-expand.
(global-set-key (kbd "M-/") 'hippie-expand)
It does a variety of completions, which are controlled by the variable hippie-expand-try-functions-list. In the .el files, you can set that to do the 'try-complete-lisp-symbol first to get the behavior you're asking for above, along with all the other expansions hippie-expand provides.
This would do that for you:
(add-hook 'emacs-lisp-mode-hook 'move-lisp-completion-to-front)
(defun move-lisp-completion-to-front ()
"Adjust hippie-expand-try-functions-list to have lisp completion at the front."
(make-local-variable 'hippie-expand-try-functions-list)
(setq hippie-expand-try-functions-list
(cons 'try-complete-lisp-symbol
(delq 'try-complete-lisp-symbol hippie-expand-try-functions-list)))
(setq hippie-expand-try-functions-list
(cons 'try-complete-lisp-symbol-partially
(delq 'try-complete-lisp-symbol-partially hippie-expand-try-functions-list))))
As Trey Jackson mentioned, hippie-expand is the way to go, but along with binding it to M-/, I also like having the TAB key do all my completion work for me. So I have this from the Emacs-Wiki in my .emacs file:
;;function to implement a smarter TAB (EmacsWiki)
(defun smart-tab ()
"This smart tab is minibuffer compliant: it acts as usual in
the minibuffer. Else, if mark is active, indents region. Else if
point is at the end of a symbol, expands it. Else indents the
current line."
(interactive)
(if (minibufferp)
(unless (minibuffer-complete)
(hippie-expand nil))
(if mark-active
(indent-region (region-beginning)
(region-end))
(if (looking-at "\\_>")
(hippie-expand nil)
(indent-for-tab-command)))))
(global-set-key (kbd "TAB") 'smart-tab)
You could have hippie expand settings as follows:
;;settings for hippie-expand
(setq hippie-expand-try-functions-list
'(try-complete-lisp-symbol
try-complete-lisp-symbol-partially
try-expand-dabbrev
try-expand-dabbrev-from-kill
try-expand-dabbrev-all-buffers
try-expand-line
try-complete-file-name-partially
try-complete-file-name))
C-M-i; no customization required.
I use:
(define-key function-key-map [(control tab)] [?\M-\t])
I use M-. and M-/ for the 2 completion modes - hippie-expand and the standard emacs one.
Put this in your .emacs to make Windows give Emacs the use of M-TAB:
(when (fboundp 'w32-register-hot-key) (w32-register-hot-key [M-tab]))