Emacs key-bindings: (dired) mode overwrites minor-mode key map? - emacs

Even after following all that was given in
Globally override key binding in Emacs
I still couldn't get it to work.
I bound M-o to other-window in my global key map like this:
(defvar my-keys-minor-mode-map (make-keymap) "my-keys-minor-mode keymap.")
(define-key my-keys-minor-mode-map "\M-o" 'other-window)
(define-minor-mode my-keys-minor-mode
"A minor mode so that my key settings override annoying major modes."
t " my-keys" 'my-keys-minor-mode-map)
(my-keys-minor-mode 1)
(defun my-minibuffer-setup-hook ()
(my-keys-minor-mode 0))
(add-hook 'minibuffer-setup-hook 'my-minibuffer-setup-hook)
;; Maintain the above keymap even after loading a new library
(defadvice load (after give-my-keybindings-priority)
"Try to ensure that my keybindings always have priority."
(if (not (eq (car (car minor-mode-map-alist)) 'my-keys-minor-mode))
(let ((mykeys (assq 'my-keys-minor-mode minor-mode-map-alist)))
(assq-delete-all 'my-keys-minor-mode minor-mode-map-alist)
(add-to-list 'minor-mode-map-alist mykeys))))
(ad-activate 'load)
but dired mode overrides this and remaps it to dired-omit-mode.
What am I missing ?

Your minor mode is defined to be buffer-local. You can Define it to be global, like this:
(define-minor-mode my-keys-minor-mode
"A minor mode so that my key settings override annoying major modes."
:global t
:lighter " my-keys")
But then your my-minibuffer-setup-hook will turn it off globally as well. Also if it's global and you basically always have it ON, you might prefer to not provide the :lighter " my-keys", so your mode-line isn't filled unnecessarily.

Related

Minor Mode Conditional Emacs Shortcuts

I have an emacs shortcut set up like so:
;; Adding the key mappings to minor mode.
(defvar my-keys-minor-mode-map (make-keymap) "my-keys-minor-mode keymap.")
;; Cancel with one press of escape instead of three.
(define-key my-keys-minor-mode-map (kbd "<escape>") 'keyboard-quit)
(my-keys-minor-mode 1)
(defconst my-minor-mode-alist (list (cons 'my-keys-minor-mode
my-keys-minor-mode-map)))
(setf emulation-mode-map-alists '(my-minor-mode-alist))
This works great to override a shortcut in a truly global way, superseding all other minor modes. However I need a way to have a shortcut behave differently in different minor modes. For example I would like the escape key to run helm-keyboard-quit when helm is running bu run keyboard-quit otherwise. Doing so like:
(eval-after-load "helm"
'(progn
(define-key helm-map (kbd "<escape>") 'helm-keyboard-quit)))
won't work because the global escape shortcut will override it. Is there a way to do this?
Why not use a simple lambda. Something like this (untested):
(global-set-key (kbd "<escape>")
(lambda()
(interactive)
(if helm-mode (helm-keyboard-quit)
(keyboard-quit))))

I cannot get structure members in auto-completion or tooltips

I want autocomplete or company to work with C code and I need structure context level autocomplete i.e if I have a struct:
typefdef struct HOST_ {
IP4_ADDRESS ip4;
IP6_ADDRESS ip6;
MAC_ADDRESS mac;
} HOST;
... and then I have code:
HOST host;
host->
Then if I hit tab then I should get a drop down menu giving me all the (and only the) three options.
This is what I did:
(defun my-tab-del-commands(key-map)
"This function sets the <tab> and <backspace> keymaps according to the special commands
that I have set. This needs to be set per mode keymap where it is needed. We cannot
use the global keymap because that would override command completion in minibuffer"
;; Set TAB in major-mode keymap to "tab-to-tab" stop
;; Use tab2tab stop and not just add +4 spaces (tab stop defined by tag-stop-list)
(define-key key-map (kbd "<tab>") 'tab-to-tab-stop)
;; Define Key for <backtab>
(define-key key-map (kbd "<S-tab>") 'backward-move-to-tab-stop)
(define-key key-map (kbd "<backtab>") 'backward-move-to-tab-stop)
;; Define C-tab as my-indent-system
(define-key key-map (kbd "<C-tab>") 'my-indent-system)
;; Also provide a duplicate "\C-ci" in case C-TAB is overridden by any minor mode
(define-key emacs-lisp-mode-map "\C-ci" 'my-indent-system)
;; Shift backspace moves by one tab stop till no more whitespace
(define-key key-map (kbd "<S-backspace>") 'backspace-whitespace-to-tab-stop)
;; Alt backspace is c-hungry-delete-backwards
(define-key key-map (kbd "<M-backspace>") 'c-hungry-delete-backwards)
)
;; Simple Backend of semantic with ede as project manager
;; Lets try semantic (CDET) backend for now only.
;; Later learn clang or rtags or other big stuff to handle the whole project
(defun backend:semantic-ede ()
"Setup for semantic-mode with ede as project management.
Simple stuff for starters"
(semantic-mode 1)
(global-semanticdb-minor-mode 1)
(global-semantic-idle-scheduler-mode 1)
(setq-mode-local c-mode semanticdb-find-default-throttle
'(project unloaded system recursive))
(semantic-add-system-include my-lp-build-path)
(semanticdb-enable-gnu-global-databases 'c-mode t)
(semanticdb-enable-gnu-global-databases 'c++-mode t)
(require 'ede)
(global-ede-mode)
(let ((makefile (format "%s/Makefile" my-mp-source-path)))
(when (file-exists-p makefile)
(ede-cpp-root-project "openflow" :file makefile)))
)
;; There are two "schools of thought" of intelligent autocomplete
;; (a) auto-complete package and (b) company package.
;; This is auto-complete
(defun completion:auto-complete ()
"Setup auto-complete with triggers. We still need to hook with C mode"
;; Then autocomplete
(require 'auto-complete)
(require 'auto-complete-config)
(global-auto-complete-mode t)
;; auto complete mod
;; should be loaded after yasnippet so that they can work together
(add-to-list 'ac-dictionary-directories "~/.emacs.d/ac-dict")
(ac-config-default)
(add-hook 'auto-complete-mode-hook 'ac-common-setup)
;; set the trigger key so that it can work together with yasnippet on tab key,
;; if the word exists in yasnippet, pressing tab will cause yasnippet to
;; activate, otherwise, auto-complete will
(ac-set-trigger-key "TAB")
(ac-set-trigger-key "<tab>")
(global-auto-complete-mode t)
)
(defun my-smart-c-auto-complete()
;; Now tie up autocomplete with semantic
;; Later hook it up to c-mode-hook via c-mode-config func
(require 'auto-complete-c-headers)
(add-to-list 'ac-sources 'ac-source-words-in-same-mode-buffers)
(add-to-list 'ac-sources 'ac-source-dictionary)
(add-to-list 'ac-sources 'ac-source-abbrev)
(add-to-list 'ac-sources 'ac-source-semantic)
(add-to-list 'ac-sources 'ac-source-c-headers)
)
;; This is company
(defun completion:company ()
"Setup comany mode"
(require 'company)
(add-hook 'after-init-hook 'global-company-mode)
)
(defun tab-side-story ()
(interactive)
;; First load and init Yasnippet - This sets the TAB first to Ysnippet
;; This will work on LISP & SHELL SCRIPTS also
;; (require 'yasnippet)
;; (yas-global-mode 1)
;; Second, use whatever completion mechanism you wanna use auto-complete or company
;; This will work on LISP also!
;;(completion:auto-complete)
(completion:company)
;; Then this function sets tab command
(my-tab-del-commands c-mode-base-map)
)
;; Completion mechanism needs a backend
(backend:semantic-ede)
(tab-side-story)
;; define My Great C style with linux as the parent style (choose google if you wish)
(c-add-style "my-great-c-style"
'("linux" ; use linux as parent style
(indent-tabs-mode . nil) ; tabs are spaces
(c-syntactic-indentation . t) ; auto-syntax
(c-syntactic-indentation-in-macros . t) ; ditto for macros
(c-tab-always-indent . nil) ; Otherwise our complex TAB will not work!
(tab-width . 4) ; if there is a <tab> expand to 4 spaces
(backward-delete-function . nil) ; DO NOT expand tabs when deleting
(c-continued-statement-offset . 4))) ;continued statement offset 4
(defun my-c-mode-config ()
(c-set-style "my-great-c-style")
(when (= emacs-major-version 23)
(gtags-mode 1))
(when (= emacs-major-version 24)
(tab-side-story)
;; (my-smart-c-auto-complete)
(ggtags-mode 1)
(setq ggtags-update-on-save nil))
(electric-indent-mode)
(setq c-basic-offset 4)
(setq c-tab-always-indent nil))
;; Needs to be hooked - do it here instead of common area
(add-hook 'c-mode-hook 'my-c-mode-config)
Sorry for the very long code but most of them are my comments and notes jotted down so far less "code" than it seems. In this I have set it for company mode though I have auto-complete.
Both are not working! Something is clashing with something.

Remove major mode key bindings in 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)))

Changing cursor color based on a minor mode

I have written a minor-mode, it defines some key bindings and does some initialization. The mode properly sets up Navi-mode and Navi-mode-map.
How do I enhance this minor-mode to change the color of the cursor when Navi-mode is enabled, and change it back whenever the mode is disabled? Can I use the hook Navi-mode-hook?
Try this:
(define-minor-mode foo-mode "doodad" :lighter ""
(if foo-mode
(setq cursor-type 'bar)
(setq cursor-type (default-value 'cursor-type))))
Or, if you anticipate cursor-type to already have a non-default value, you can save it when the mode is enabled and restore the saved value when it's disabled.
Either you have total control of the minor mode (because you wrote it), and you can embed this behaviour directly in your minor-mode function as explained in Dmitry's answer:
(define-minor-mode navi-mode
"Navi mode does wonderful things"
:lighter " Navi"
:global t
:init-value 0
(if navi-mode
(progn
(setq old-cursor-color (cdr (assoc 'cursor-color (frame-parameters))))
(set-cursor-color "red"))
(set-cursor-color old-cursor-color)))
Or you don't control the minor mode definition and you'll have to use a hook:
(defun navi-change-cursor-color ()
(if navi-mode
(progn
(setq old-cursor-color (cdr (assoc 'cursor-color (frame-parameters))))
(set-cursor-color "red"))
(set-cursor-color old-cursor-color)))
(add-hook 'navi-mode-hook 'navi-change-cursor-color)

Remapping SLIME keys

Slime remaps several keys I like to use and have set in global-set-key.
I'd like to avoid directly editing slime.el.
What's the routine to override keys in a given mode?
Update:
In your .emacs, set the mode-map directly:
(define-key slime-mode-map "\M-n" 'next-line)
(define-key slime-mode-map "\M-p" 'previous-line)
It's not too easy to redefine a key for a mode since it can provide several keymaps. And there can be many modes that grab my favorite keys.
I solved it this way: I defined a minor mode that doesn't do anything except it has it's own keymap. I put some keys there i want to be really global.
;; my minor mode for really global keybindings
(defvar my-keys-minor-mode-map (make-keymap) "my-keys-minor-mode keymap.")
(define-minor-mode my-keys-minor-mode
"My minor mode for global keybindings."
:init-value t :lighter "" :keymap 'my-keys-minor-mode-map)
(defun my-minibuffer-setup-hook ()
(my-keys-minor-mode 0))
(add-hook 'minibuffer-setup-hook 'my-minibuffer-setup-hook)
(my-keys-minor-mode 1)
;; for example
(define-key my-keys-minor-mode-map (kbd "C-a") 'mark-whole-buffer)
...