unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* A simple implementation of context-sensitive keys
@ 2008-09-10  7:17 Tassilo Horn
  2008-09-10 10:36 ` Lennart Borgman (gmail)
                   ` (2 more replies)
  0 siblings, 3 replies; 36+ messages in thread
From: Tassilo Horn @ 2008-09-10  7:17 UTC (permalink / raw)
  To: emacs-devel

Hi all,

to get the full power out of emacs, I use quite a lot of different minor
modes with a ton of home-brewn functions.  To make them quickly
accessible, I've bound them to some key.  But "good" keys are rare, and
so I started writing special dispatching commands which DTRT dependend
on the context they're used in.  But that's quite cumbersome, because
ideally you have to recognize each command which would normally be bound
to the key, too.

So I've come up with this macro, which creates such a dispatching
command automagically.  If none of the context predicates match, the
default command bound to the key will be executed.

--8<---------------cut here---------------start------------->8---
(defmacro define-context-key (mode key preds-funs)
  "Bind KEY to an anonymous dispatching command in MODE.
PREDS-FUNS is an alist with elements of the form

    (PREDICATE . FUNCTION).

The dispatching command calls the first PREDICATE, and if that
returns non-nil, it'll call the associated FUNCTION.  If the
first PREDICATE returns nil, the next one will be tested and so
on.

If no PREDICATE matches and KEY is normally bound in MODE, the
corresponding command will be executed.

If KEY isn't normally bound in MODE, MODE will be disabled
temporally (to prevent an infinite recursion) and the function
which is then bound to KEY will be called."
  (let* ((keymap        (intern (concat (symbol-name mode) "-map")))
         (default-fun   (lookup-key (symbol-value keymap) (eval key)))
         (block-name    (gensym))
         (iter-var-name (gensym)))
    `(define-key ,keymap ,key
       (lambda ()	
         (interactive)
         (block ,block-name
           (dolist (,iter-var-name (quote ,preds-funs))
             (when (funcall (car ,iter-var-name))
               (call-interactively (cdr ,iter-var-name))
               (return-from ,block-name)))
           (if (quote ,default-fun)
               (call-interactively (quote ,default-fun))
             (let (,mode)
               (call-interactively (key-binding ,key)))))))))
--8<---------------cut here---------------end--------------->8---

Here's a usage example: I'm used to structure source code files with
`outline-minor-mode'.  But the default keys of this mode are too hard to
type and remember.  (I only use `outline-toggle-children' anyway.)  So
instead of binding that command to some other key, I use my macro to
make TAB context-sensitive:

--8<---------------cut here---------------start------------->8---
(defun outline-context-p ()
  (save-excursion
    (goto-char (line-beginning-position))
    (looking-at outline-regexp)))

(define-context-key outline-minor-mode
  (kbd "TAB")
  ((outline-context-p . outline-toggle-children)))
--8<---------------cut here---------------end--------------->8---
 
`outline-context-p' returns non-nil when point is on a outline heading.
Now the TAB key calls `outline-toggle-children' if I'm on such a
headline.  If not, `outline-minor-mode' will be disabled temporally
(cause `outline-minor-mode' doesn't define a command bound to TAB on its
own) and the next mode will get it's chance, i.e. the code will be
indented according to mode.

What do you think of it?

I use it for some hours now, so it's only very briefly tested, but it
seems to DTRT.  Of course, this cannot go into the emacs core because it
uses `cl' capabilities, but IMO a feature like that could be of great
benefit to users.

BTW: The idea and the mechanism how to get the command that would have
been executed normally is stolen from Carsten Dominik's fabulous
org-mode package (or more accurately `orgstruct-mode').  And there're
other packages (yasnippet comes into mind), which implement such a
feature on their own, too.  So a more general concept of context
sensitive keys seems sensible.

Bye,
Tassilo




^ permalink raw reply	[flat|nested] 36+ messages in thread

end of thread, other threads:[~2008-09-15 22:39 UTC | newest]

Thread overview: 36+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-09-10  7:17 A simple implementation of context-sensitive keys Tassilo Horn
2008-09-10 10:36 ` Lennart Borgman (gmail)
2008-09-10 10:57   ` Tassilo Horn
2008-09-10 16:43     ` Ted Zlatanov
2008-09-10 14:14 ` Sean O'Rourke
2008-09-10 14:48   ` Miles Bader
2008-09-10 14:53     ` Juanma Barranquero
2008-09-10 15:17       ` Sean O'Rourke
2008-09-10 15:32         ` Juanma Barranquero
2008-09-11  7:35     ` Tassilo Horn
2008-09-11  8:17       ` Miles Bader
2008-09-11  8:48         ` Tassilo Horn
2008-09-10 17:49 ` Stefan Monnier
2008-09-10 19:21   ` Tassilo Horn
2008-09-11  1:41     ` Stefan Monnier
2008-09-11  7:17       ` Tassilo Horn
2008-09-11 14:40         ` Ted Zlatanov
2008-09-11 15:53           ` Tassilo Horn
2008-09-11 13:41       ` Lennart Borgman (gmail)
2008-09-11 13:48         ` Lennart Borgman (gmail)
2008-09-11 14:22           ` Tassilo Horn
2008-09-11 20:38             ` Lennart Borgman (gmail)
2008-09-12  6:58               ` Tassilo Horn
2008-09-12  8:34                 ` Lennart Borgman (gmail)
2008-09-12  9:47                   ` Tassilo Horn
2008-09-12 11:00                     ` Lennart Borgman
2008-09-12 16:13                       ` Tassilo Horn
2008-09-12 23:46                         ` Lennart Borgman (gmail)
2008-09-13  7:28                           ` Tassilo Horn
2008-09-13  9:32                             ` Lennart Borgman (gmail)
2008-09-15  7:26                               ` Tassilo Horn
2008-09-15 22:39                                 ` Lennart Borgman (gmail)
2008-09-11 20:44         ` Stefan Monnier
2008-09-11 21:14           ` Lennart Borgman (gmail)
2008-09-12  1:33             ` Stefan Monnier
2008-09-12  8:29               ` Lennart Borgman (gmail)

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).