Conflicting keyboard shortcuts in two Emacs minor modes - emacs

I have an ErgoEmacs minor mode turned on globally, which defines many custom keyboard shortcuts for basic editing. However when I open any lisp file, slime-mode turns on automatically and overrides M-p and M-n with its own commands. However I want M-p and M-n to be always defined by ergoemacs-mode. How do I set up order in which minor modes load and define keybindings? Or how do I raise ergoemacs-mode keybindings priority?

How do I set up order in which minor modes load and define keybindings? Or how do I raise ergoemacs-mode keybindings priority?
I think you need to ensure that ErgoEmacs appears before slime-mode in the variable minor-mode-map-alist. There's probably a much better way, but the code below should achieve this. Let me know if it does what you want.
(require 'cl)
(add-hook
'slime-mode-hook
(lambda ()
(let ((elem (first
(remove-if-not
(lambda (item) (equal 'ergoemacs-mode (car item)))
minor-mode-map-alist))))
(setq minor-mode-map-alist (remove elem minor-mode-map-alist))
(add-to-list 'minor-mode-map-alist elem))))

Maybe a simpler solution is to remove Slime's bindings:
(add-hook 'slime-mode-hook
(lambda ()
(define-key slime-mode-map [?\M-p] nil)
(define-key slime-mode-map [?\M-n] nil)))
Beware: guarantedd 100% untested, the variable's name might be different from slime-mode-map (and it probably will only exist after loading slime-mode).

Related

How to remap a function to another in Emacs?

In coffee-mode RET is bound to coffee-newline-and-indent which works fine.
I also use evil-mode to have Vim emulation. evil-mode uses the standard newline-and-indent so the indentation is not correct for some vim commands such as o or O.
What would be the best way to rebind newline-and-indent to coffee-newline-and-indent ?
I'm still a newbie in ELisp and tried the line below but it doesn't work.
(add-hook 'coffee-mode-hook
(lambda ()
(setq newline-and-indent '(funcall coffee-newline-and-indent))))
Here's my attempt. It should work, but I don't really like it.
(add-hook
'coffee-mode-hook
(lambda ()
(defalias
'newline-and-indent
(lambda()
(interactive)
(if (eq major-mode 'coffee-mode)
(coffee-newline-and-indent)
(delete-horizontal-space t)
(newline)
(indent-according-to-mode))))))
I wish I could use something more elegant that just copying the source
of newline-and-indent, but make-variable-buffer-local doesn't work for this case,
and I couldn't get a deep copy for symbol-function either.
I'd be happy to see a better method.
The standard way to accomplish what you seem to be asking for is
(autoload 'coffee-newline-and-indent "coffee-mode") ; (or whatever)
(define-key evil-mode-map (kbd "RET") 'coffee-newline-and-indent)
EDIT: to enable coffee-newline-and-indent only in coffee-mode:
(define-key evil-mode-map (kbd "RET")
(lambda ()
(interactive)
(if (eq major-mode 'coffee-mode)
(coffee-newline-and-indent)
(newline-and-indent))))
Try the following:
(define-key evil-mode-map (kbd "RET") nil)
I know it looks overly simple, but if evil-mode works the way I think it does then it should work.
This will wipe the ret key from your evil-mode-map, which will let the binding of coffee-mode-map shine through.
In non-coffee buffers, the ret key will still work, because it's still bind in the global map.
I found the solution.
Evil-mode actually uses coffee-indent-line. The problem comes from coffee-indent-line which doesn't indent correctly. Evil-mode works correctly after patching it to behave like coffee-newline-and-indent:
(defadvice coffee-indent-line (after wants-indent activate)
(let ((tabs-needed (- (/ (coffee-previous-indent) coffee-tab-width) 1)))
(when (> tabs-needed 0)
(insert-tab tabs-needed)))
(when(coffee-line-wants-indent)
(insert-tab)))
if you want to remap a func, but only if some major mode is active
- create a func which defines an alias
and run the func (A)
- another func (B) calls (A)
- finally, a major mode can advice the func A to set the correct
func. It has to test major mode.
let's say A is define-my-indent-f
then it says (defalias my-indent 'newline-and-indent)
the func b runs A then run command my-indent.
finally coffe mode does defadice A to say
(if eq major mode coffee defalais my-indent 'coffe-newline-and-indent)
of course this is super heavy to define, but then
- each major mode can add its piece
- only loaded major mode will advice

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)

Enable auto-complete in Emacs minibuffer

I'm trying to turn auto-complete in the minibuffer:
(add-hook 'minibuffer-setup-hook 'auto-complete-mode)
What I get is auto-complete working in the first instance of minibuffer, but no longer. That is the full minibuffer-setup-hook after loading:
(auto-complete-mode turn-on-visual-line-mode ido-minibuffer-setup rfn-eshadow-setup-minibuffer minibuffer-history-isearch-setup minibuffer-history-initialize)
How to turn auto-complete on persistently?
You rarely ever want to add a function symbol to a hook variable if that function acts as a toggle (which will be the case for most minor modes).
minibuffer-setup-hook runs "just after entry to minibuffer", which means that you would be enabling auto complete mode the first time you enter the minibuffer; disabling it the second time; enabling it the third time; etc...
Typically you would either look to see if there's a pre-defined turn-on-autocomplete-mode type of function, or define your own:
(defun my-turn-on-auto-complete-mode ()
(auto-complete-mode 1)) ;; an argument of 1 will enable most modes
(add-hook 'minibuffer-setup-hook 'my-turn-on-auto-complete-mode)
I can't test that, because you haven't linked to the autocomplete-mode you are using.
The creator of "auto-complete-mode" explicitly excludes the minibuffer for use with auto completion. The definition for the minor mode is:
(define-global-minor-mode global-auto-complete-mode
auto-complete-mode auto-complete-mode-maybe
:group 'auto-complete)
so the "turn mode on" function is "auto-complete-mode-maybe" - the definition of that function is:
(defun auto-complete-mode-maybe ()
"What buffer `auto-complete-mode' prefers."
(if (and (not (minibufferp (current-buffer)))
(memq major-mode ac-modes))
(auto-complete-mode 1)))
This function explicitly tests in the if statement if the current-buffer is the minibuffer and doesn't turn on the auto-complete-mode if it is.
If you want to use auto-complete-mode in the minibuffer, you should probably contact the maintainer of the mode and ask him why he excluded the minibuffer and what programming changes he feels are necessary to enable the mode in the minibuffer.
Zev called to my attention auto-complete-mode-maybe, and that is the required modifications (file auto-complete.el, all changes have comments):
;; Add this variable
(defcustom ac-in-minibuffer t
"Non-nil means expand in minibuffer."
:type 'boolean
:group 'auto-complete)
...
(defun ac-handle-post-command ()
(condition-case var
(when (and ac-triggered
(not (ido-active)) ;; Disable auto pop-up in ido mode
(or ac-auto-start
ac-completing)
(not isearch-mode))
(setq ac-last-point (point))
(ac-start :requires (unless ac-completing ac-auto-start))
(ac-inline-update))
(error (ac-error var))))
...
(defun auto-complete-mode-maybe ()
"What buffer `auto-complete-mode' prefers."
(if (or (and (minibufferp (current-buffer)) ac-in-minibuffer) ;; Changed
(memq major-mode ac-modes))
(auto-complete-mode 1)))
And .emacs:
(add-hook 'minibuffer-setup-hook 'auto-complete-mode)
Certainly, there are binding conflicts but it is possible to solve them.

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]))

emacs: visual-line-mode and fill-paragraph

I am now using Emacs 23 with visual-line-mode turned of for text editing but keep hitting M-q out of habit (thus adding hard-wrapping line endings...). I wonder if there is a way to add a conditional to disable fill-paragraph (or remove the binding to M-q) for modes in which visual-line-mode is turned on, but to re-enable it for those in which I am still using the auto-fill-mode? Thanks!
(defun maybe-fill-paragraph (&optional justify region)
"Fill paragraph at or after point (see `fill-paragraph').
Does nothing if `visual-line-mode' is on."
(interactive (progn
(barf-if-buffer-read-only)
(list (if current-prefix-arg 'full) t)))
(or visual-line-mode
(fill-paragraph justify region)))
;; Replace M-q with new binding:
(global-set-key "\M-q" 'maybe-fill-paragraph)
Instead of using global-set-key, you can also rebind M-q only in specific modes. (Or, you could change the global binding, and then bind M-q back to fill-paragraph in a specific mode.) Note that many modes are autoloaded, so their keymap may not be defined until the mode is activated. To set a mode-specific binding, I usually use a function like this:
(add-hook 'text-mode-hook
(defun cjm-fix-text-mode ()
(define-key text-mode-map "\M-q" 'maybe-fill-paragraph)
(remove-hook 'text-mode-hook 'cjm-fix-text-mode)))
(The remove-hook isn't strictly necessary, but the function only needs to run once.)
you can use an advise for this.
For your .emacs:
(defadvice fill-paragraph (around disable-for-visual-line-mode activate)
(unless visual-line-mode
ad-do-it))
This will change fill-paragraph to do nothing when visual-line-mode is on. You can also add an error if you prefer that.
visual-line-mode has its own keymap: visual-line-mode-map. I recommend rebinding M-q only in that keymap.
The map is defined as part of startup, so you don’t need eval-after-load. Just disable the binding in that mode:
(define-key visual-line-mode-map [remap fill-paragraph] 'ignore)