I'm trying to write a custom tab completion implementation which tries a bunch of different completions depending on where the point is. However, if none of the conditions for completions are met I would like tab to do what ever the current mode originally intended it to do.
Something like this:
(defun my-custom-tab-completion ()
(interactive)
(cond
(some-condition
(do-something))
(some-other-condition
(do-something-else))
(t
(do-whatever-tab-is-supposed-to-do-in-the-current-mode))) ;; How do I do this?
Currently I'm checking for specific modes and doing the right thing for that mode, but I really would like a solution that just does the right thing without me having to explicitly add a condition for that specific mode.
Any ideas of how to do this?
Thanks! /Erik
BTW, here is another solution:
Here is a macro I wrote based on Emacs key binding fallback to define a keybinding conditionally. It adds the keybinding to the specified minor mode but if the condition is not true, the previously assigned action is executed:
Then I can do things like the following to use the special binding for TAB only when I am on a header in outline-minor-mode. Otherwise my default action (I have both indent and yasnippets) is executed:
It's possible that you could achieve this without any special workarounds at all. In most modes
TAB
just does indentation by default, but if you set the global variabletab-always-indent
to'complete
it will try to do completion first, and indent if no completion is possible. This usually works really well, although ifTAB
is bound to another command in one of your major modes you might be out of luck.If that works in the modes you need, you'll just need to add your custom completion function to the front of the list
completion-at-point-functions
in all applicable buffers (maybe using a mode hook). Thecompletion-at-point
command calls each function listed incompletion-at-point-functions
until one of them returns non-nil
, so all you need to do to have your custom completion function "fall through" to the existing behavior is returnnil
from it.This isn't a 100% answer to the question, but if the major modes you're working with are written according to the normal guidelines it might be the cleanest way.
You could use functions such as
key-binding
(or its more specific variantsglobal-key-binding
,minor-mode-key-binding
andlocal-key-binding
) to probe active keymaps for bindings.For example:
One way to avoid infinite loops if your command is bound to TAB could be to put your binding in a minor mode, and temporarily disable its keymap while looking for the TAB binding:
define-key
can accept quoted string or interactive lambdas like in this example.Lambda's can be replaced with named functions like my-tab-completion and used more effectively.
From define-key's docstring (Emacs 25)