all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
* Keybindings and minor modes
@ 2005-12-29  2:18 batkins57
  2005-12-29 19:23 ` Kevin Rodgers
                   ` (2 more replies)
  0 siblings, 3 replies; 7+ messages in thread
From: batkins57 @ 2005-12-29  2:18 UTC (permalink / raw)


I'd like to bind a command to tab in a minor mode I'm writing, but I'd
also like to preserve any command that might have been attached to that
key before making my binding (such as indentation).  In other words,
I'd like to add functionality to an existing keybinding without
completely overwriting the binding.

The solution I came up with was to simply store the currently bound
command in a buffer-local variable whenever the minor mode is invoked.
Then the keys are bound to functions that provide my additional
functionality and then funcall the old bindings.  This works, but I
wonder if there isn't a cleaner way to pass a keychord event on to the
next handler.  The code I have now is pretty ugly, since a key bound to
self-insert-command has to be handled separately so that
self-insert-command will get an argument of 0.

I've attached my code below in case it's useful.

Thanks,
Bill Atkins

--

;; ehinter.el - echo lambda-lists when editing emacs lisp code

(defvar ehinter--old-space)
(defvar ehinter--old-tab)
(defvar ehinter--old-ret)

(make-variable-buffer-local 'ehinter--old-space)
(make-variable-buffer-local 'ehinter--old-tab)
(make-variable-buffer-local 'ehinter--old-ret)

(defvar ehinter-mode-map
  (let ((keymap (make-sparse-keymap)))
    (define-key keymap " "     'ehinter--space-cmd)
    (define-key keymap "\t"    'ehinter--tab-cmd)
    (define-key keymap "\C-m"  'ehinter--ret-cmd)
    keymap)
  "Keymap for the Elisp Hinter minor mode")

(define-minor-mode ehinter-mode
    "A minor mode that echoes an arglist for whatever Elisp function is
being
called at point.

\\{ehinter-mode-map}"
  :lighter " EHinter"
  :init-value nil
  (setq ehinter--old-space (ehinter--old-binding " "))
  (setq ehinter--old-tab (ehinter--old-binding "\t"))
  (setq ehinter--old-ret (ehinter--old-binding "\C-m")))

(defun ehinter--old-binding (key)
  (or (lookup-key (current-local-map) key)
      (lookup-key (current-global-map) key)))

(defun ehinter--invoke-binding (binding)
  (if (eq binding 'self-insert-command)
      (self-insert-command 1)
      (funcall binding)))

(defun ehinter--space-cmd ()
  (interactive)
  (ehinter-hint)
  (ehinter--invoke-binding ehinter--old-space))

(defun ehinter--ret-cmd ()
  (interactive)
  (ehinter-hint)
  (ehinter--invoke-binding ehinter--old-ret))

(defun ehinter--tab-cmd ()
  (interactive)
  (ehinter-hint)
  (ehinter--invoke-binding ehinter--old-tab))

(defun ehinter-hint ()
  (interactive)
  (when (and (function-called-at-point)
	     (condition-case () (symbol-function (function-called-at-point))
	       (void-function nil)))
    (message "%s" (lambda-list (function-called-at-point))))
  (self-insert-command 0))

(defun strip-ends (str)
  (substring str 1 (1- (length str))))

(defun lambda-list (func)
  (let ((fn (symbol-function func)))
    (cond ((and (consp fn)
		(eq (car-safe fn) 'lambda))
	   (prin1-to-string (cons func (second fn))))
	  ((and (consp fn)
		(eq (car-safe fn) 'macro))
	   (prin1-to-string (cons func (svref (cdr fn) 0))))
	  ((subrp fn)
	   (strip-ends (downcase
			(prin1-to-string
			 (first (help-split-fundoc (documentation func)
						   func))))))
	  (t (error "%s" (type-of func))))))

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

* Keybindings and minor modes
@ 2005-12-29 15:52 Bill Atkins
  2005-12-29 18:41 ` Stefan Monnier
  0 siblings, 1 reply; 7+ messages in thread
From: Bill Atkins @ 2005-12-29 15:52 UTC (permalink / raw)


I apologize if this is the wrong place to post this, but it seemed
like the most appropriate list.

I'd like to bind a command to tab in a minor mode I'm writing, but I'd
also like to preserve any command that might have been attached to that
key before making my binding (such as indentation).  In other words,
I'd like to add functionality to an existing keybinding without
completely overwriting the binding.

The solution I came up with was to simply store the currently bound
command in a buffer-local variable whenever the minor mode is invoked.
Then the keys are bound to functions that provide my additional
functionality and then funcall the old bindings.  This works, but I
wonder if there isn't a cleaner way to pass a keychord event on to the
next handler.  The code I have now is pretty ugly, since a key bound to
self-insert-command has to be handled separately so that
self-insert-command will get an argument of 0.

I've attached my code below in case it's useful.

Thanks,
Bill Atkins

--

;; ehinter.el - echo lambda-lists when editing emacs lisp code

(defvar ehinter--old-space)
(defvar ehinter--old-tab)
(defvar ehinter--old-ret)

(make-variable-buffer-local 'ehinter--old-space)
(make-variable-buffer-local 'ehinter--old-tab)
(make-variable-buffer-local 'ehinter--old-ret)

(defvar ehinter-mode-map
  (let ((keymap (make-sparse-keymap)))
    (define-key keymap " "     'ehinter--space-cmd)
    (define-key keymap "\t"    'ehinter--tab-cmd)
    (define-key keymap "\C-m"  'ehinter--ret-cmd)
    keymap)
  "Keymap for the Elisp Hinter minor mode")

(define-minor-mode ehinter-mode
    "A minor mode that echoes an arglist for whatever Elisp function is
being
called at point.

\\{ehinter-mode-map}"
  :lighter " EHinter"
  :init-value nil
  (setq ehinter--old-space (ehinter--old-binding " "))
  (setq ehinter--old-tab (ehinter--old-binding "\t"))
  (setq ehinter--old-ret (ehinter--old-binding "\C-m")))

(defun ehinter--old-binding (key)
  (or (lookup-key (current-local-map) key)
      (lookup-key (current-global-map) key)))

(defun ehinter--invoke-binding (binding)
  (if (eq binding 'self-insert-command)
      (self-insert-command 1)
      (funcall binding)))

(defun ehinter--space-cmd ()
  (interactive)
  (ehinter-hint)
  (ehinter--invoke-binding ehinter--old-space))

(defun ehinter--ret-cmd ()
  (interactive)
  (ehinter-hint)
  (ehinter--invoke-binding ehinter--old-ret))

(defun ehinter--tab-cmd ()
  (interactive)
  (ehinter-hint)
  (ehinter--invoke-binding ehinter--old-tab))

(defun ehinter-hint ()
  (interactive)
  (when (and (function-called-at-point)
             (condition-case () (symbol-function (function-called-at-point))
               (void-function nil)))
    (message "%s" (lambda-list (function-called-at-point))))
  (self-insert-command 0))

(defun strip-ends (str)
  (substring str 1 (1- (length str))))

(defun lambda-list (func)
  (let ((fn (symbol-function func)))
    (cond ((and (consp fn)
                (eq (car-safe fn) 'lambda))
           (prin1-to-string (cons func (second fn))))
          ((and (consp fn)
                (eq (car-safe fn) 'macro))
           (prin1-to-string (cons func (svref (cdr fn) 0))))
          ((subrp fn)
           (strip-ends (downcase
                        (prin1-to-string
                         (first (help-split-fundoc (documentation func)
                                                   func))))))
          (t (error "%s" (type-of func))))))

--
Bill Atkins

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

* Re: Keybindings and minor modes
  2005-12-29 15:52 Bill Atkins
@ 2005-12-29 18:41 ` Stefan Monnier
  0 siblings, 0 replies; 7+ messages in thread
From: Stefan Monnier @ 2005-12-29 18:41 UTC (permalink / raw)
  Cc: emacs-devel

> I'd like to bind a command to tab in a minor mode I'm writing, but I'd
> also like to preserve any command that might have been attached to that
> key before making my binding (such as indentation).  In other words,
> I'd like to add functionality to an existing keybinding without
> completely overwriting the binding.

> The solution I came up with was to simply store the currently bound
> command in a buffer-local variable whenever the minor mode is invoked.
> Then the keys are bound to functions that provide my additional
> functionality and then funcall the old bindings.  This works, but I
> wonder if there isn't a cleaner way to pass a keychord event on to the
> next handler.  The code I have now is pretty ugly, since a key bound to
> self-insert-command has to be handled separately so that
> self-insert-command will get an argument of 0.

There's no supported way to do just that.  Among the possible ways to do
something similar:

- (call-interactively
   (let ((my-minor-mode nil)) (key-binding (this-command-keys))))

- don't change the key-bindings.  Instead put advice on the commands.

- do neither.  Use a post/pre-command-hook instead (and check this-command
  or somesuch to decide whether you should do something or not).

- another one I still haven't actually seen used:

   [...]
   (add-hook 'pre-command-hook 'my-pch-reenable)
   (setq my-minor-mode nil)
   (setq unread-command-events
         (nconc (mapcar 'identity (this-command-keys))
                unread-command-events))
   [...]

   (defun my-pch-reenable ()
     (setq my-minor-mode t)
     (remove-hook 'pre-command-hook 'my-pch-reenable))

> I've attached my code below in case it's useful.

Your code seems to do something similar to what eldoc-mode does.
Have you looked at eldoc-mode?


        Stefan

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

* Re: Keybindings and minor modes
  2005-12-29  2:18 Keybindings and minor modes batkins57
@ 2005-12-29 19:23 ` Kevin Rodgers
       [not found] ` <mailman.20813.1135884349.20277.help-gnu-emacs@gnu.org>
  2006-01-01 16:27 ` albrns
  2 siblings, 0 replies; 7+ messages in thread
From: Kevin Rodgers @ 2005-12-29 19:23 UTC (permalink / raw)


batkins57@gmail.com wrote:
 > I'd like to bind a command to tab in a minor mode I'm writing, but I'd
 > also like to preserve any command that might have been attached to that
 > key before making my binding (such as indentation).  In other words,
 > I'd like to add functionality to an existing keybinding without
 > completely overwriting the binding.
 >
 > The solution I came up with was to simply store the currently bound
 > command in a buffer-local variable whenever the minor mode is invoked.
 > Then the keys are bound to functions that provide my additional
 > functionality and then funcall the old bindings.  This works, but I
 > wonder if there isn't a cleaner way to pass a keychord event on to the
 > next handler.  The code I have now is pretty ugly, since a key bound to
 > self-insert-command has to be handled separately so that
 > self-insert-command will get an argument of 0.

I think you could avoid storing the command in a local variable by
accessing the local binding (defined by the major mode) or global
binding dynamically.  That would simplify things a little.

I'll admit, I don't understand the point of calling
(self-insert-command 0).

Perhaps a better approach altogether would be to add a pre-command-hook
that would check the key that was used to invoke it:

(defun ehinter-pre-command-hook ()
   "Run `ehinter-hint' in Ehinter Minor Mode, when invoked via SPC, TAB, 
or RET."
   (when (and ehinter-mode
              (let ((key (this-single-command-keys)))
                (and (= (length key 1))
                     (member (aref key 0) '(?  ?\t ?\r))))) ; SPC, TAB, 
or RET
     (ehinter-hint)))

(add-hook 'pre-command-hook 'ehinter-pre-command-hook)

Then the ehinter-mode function just needs to set or unset the
buffer-local ehinter-mode variable.

You could tweak that to have the ehinter-mode function add or remove
ehinter-pre-command-hook from the buffer-local pre-command-hook, to
avoid affecting other buffers.

-- 
Kevin Rodgers

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

* Re: Keybindings and minor modes
       [not found] ` <mailman.20813.1135884349.20277.help-gnu-emacs@gnu.org>
@ 2005-12-29 22:02   ` batkins57
  2006-01-01 16:26     ` albrns
  0 siblings, 1 reply; 7+ messages in thread
From: batkins57 @ 2005-12-29 22:02 UTC (permalink / raw)


Kevin Rodgers wrote:
> batkins57@gmail.com wrote:
> I'll admit, I don't understand the point of calling
> (self-insert-command 0).

self-insert-command requires an argument, so as a special case, I have
to call it with a 0; I can't simply do (funcall 'self-insert-commnand).

>
> Perhaps a better approach altogether would be to add a pre-command-hook
> that would check the key that was used to invoke it:
>
> (defun ehinter-pre-command-hook ()
>    "Run `ehinter-hint' in Ehinter Minor Mode, when invoked via SPC, TAB,
> or RET."
>    (when (and ehinter-mode
>               (let ((key (this-single-command-keys)))
>                 (and (= (length key 1))
>                      (member (aref key 0) '(?  ?\t ?\r))))) ; SPC, TAB,
> or RET
>      (ehinter-hint)))
>
> (add-hook 'pre-command-hook 'ehinter-pre-command-hook)
>
> Then the ehinter-mode function just needs to set or unset the
> buffer-local ehinter-mode variable.
>
> You could tweak that to have the ehinter-mode function add or remove
> ehinter-pre-command-hook from the buffer-local pre-command-hook, to
> avoid affecting other buffers.
>
> --
> Kevin Rodgers

I got a neat solution from the folks on emacs-devel.  Stefan Monnier
suggested the following:

   (call-interactively (let ((ehinter-mode nil))
                                       (key-binding
(this-command-keys))))

Bill

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

* Re: Keybindings and minor modes
  2005-12-29 22:02   ` batkins57
@ 2006-01-01 16:26     ` albrns
  0 siblings, 0 replies; 7+ messages in thread
From: albrns @ 2006-01-01 16:26 UTC (permalink / raw)


good and good

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

* Re: Keybindings and minor modes
  2005-12-29  2:18 Keybindings and minor modes batkins57
  2005-12-29 19:23 ` Kevin Rodgers
       [not found] ` <mailman.20813.1135884349.20277.help-gnu-emacs@gnu.org>
@ 2006-01-01 16:27 ` albrns
  2 siblings, 0 replies; 7+ messages in thread
From: albrns @ 2006-01-01 16:27 UTC (permalink / raw)


good and good

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

end of thread, other threads:[~2006-01-01 16:27 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-12-29  2:18 Keybindings and minor modes batkins57
2005-12-29 19:23 ` Kevin Rodgers
     [not found] ` <mailman.20813.1135884349.20277.help-gnu-emacs@gnu.org>
2005-12-29 22:02   ` batkins57
2006-01-01 16:26     ` albrns
2006-01-01 16:27 ` albrns
  -- strict thread matches above, loose matches on Subject: below --
2005-12-29 15:52 Bill Atkins
2005-12-29 18:41 ` Stefan Monnier

Code repositories for project(s) associated with this external index

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

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.