unofficial mirror of help-gnu-emacs@gnu.org
 help / color / mirror / Atom feed
* Problems with catch and throw
@ 2007-10-04 16:16 Tassilo Horn
  2007-10-05  6:59 ` Barry Margolin
  0 siblings, 1 reply; 4+ messages in thread
From: Tassilo Horn @ 2007-10-04 16:16 UTC (permalink / raw)
  To: help-gnu-emacs

Hi,

I use a home-brewn function [1] instead of `execute-extended-command'
most of the time.  It uses `read-from-minibuffer' to get a command
abbrev from the user and then executes the command whose abbreviation
was given.

Now I'd like to bind TAB in my function so that it aborts
`read-from-minibuffer' and my function and falls back to
`execute-extended-command' where the current minibuffer contents are
inserted as initial input.

That sounds like a good candidate for catch/throw to me.  A minimal
working example is:

--8<---------------cut here---------------start------------->8---
(catch 'foo
  (read-from-minibuffer "test: " nil
                        (let ((map (copy-keymap minibuffer-local-map)))
                          (define-key map "\C-i" (lambda ()
                                                   (interactive)
                                                   (throw 'foo (minibuffer-contents))))
                          map)))
--8<---------------cut here---------------end--------------->8---

Hit `C-j' after the last closing paren and type "foobar" at the "test: "
prompt.  The form's result is "foobar" then.

So now here's my function with this mechanism applied.  But it doesn't
work like the minimal example.  (minibuffer-contents) always returns the
empty string "".  Why is that?

--8<---------------cut here---------------start------------->8---
(defun exec-abbrev-cmd (prefixarg)
  "Query for a command abbreviation like \"mbm\" and calculate a
list of all commands of the form \"m[^-]*-b[^-]*-m[^-]*$\".

If this list has only one item, this command will be executed
directly. If there a more choices, the user will be queried which
one to call.

The PREFIXARG is passed on to the invoked command.

With TAB fall back to `execute-extended-command'."
  (interactive "P")
  (let ((catch-val
         (catch 'escape-from-exec-abbrev-cmd
           (let* ((abbrev (read-from-minibuffer
                           "Command Abbrev: "
                           nil
                           (let ((map (copy-keymap minibuffer-local-map)))
                             (define-key map "\C-i"
                               (lambda ()
                                 (interactive)
                                 ;; WHY RETURN MINIBUFFER-CONTENTS ""
                                 ;; HERE, ALTHOUGH I TYPED FOOBAR AT THE
                                 ;; PROMPT???
                                 (message "cont = " (minibuffer-contents))
                                 (throw 'escape-from-exec-abbrev-cmd
                                        (minibuffer-contents))))
                             map)))
                  (regexp (concat "^"
                                  (let ((part-list (split-string abbrev "-")))
                                    (if (= 1 (length part-list))
                                        ;; abc => a*-b*-c*
                                        (mapconcat #'list abbrev "[^-]*-")
                                      ;; ahead-b-c => ahead*-b*-c*
                                      (mapconcat #'identity part-list "[^-]*-")))
                                  "[^-]*$"))
                  (commands (exec-abbrev-cmd-sort
                             (remove-if-not (lambda (string)
                                              (string-match regexp string))
                                            (let (c)
                                              (mapatoms
                                               (lambda (a)
                                                 (if (commandp a)
                                                     (push (symbol-name a) c))))
                                              c)))))
             (if (not commands)
                 (message "No such command.")
               (let ((c (cond ((> (length commands) 1)
                               (intern
                                (if (and (featurep 'ido) ido-mode)
                                    ;; ido is available and enabled, so use it.
                                    (ido-completing-read "Command: " commands)
                                  ;; fallback to normal completion with the
                                  ;; most frequently used command as default.
                                  (completing-read (concat "Command (defaults to `"
                                                           (car commands) "'): ")
                                                   commands
                                                   nil t nil nil (car commands)))))
                              (t (intern (car commands))))))
                 (call-interactively c t)
                 (when exec-abbrev-cmd-mode
                   (exec-abbrev-cmd-record c)))))
           ;; Always return nil so that an escape with TAB is the only thing
           ;; that makes `catch-val' non-nil.
           nil)))
    (when catch-val
      (message "catch-val = " catch-val)
      (execute-extended-command prefixarg)
      (insert catch-val))))
--8<---------------cut here---------------end--------------->8---

I guess it's something obvious, but I cannot see any principal
difference between the simple working example and the code of my
function.

Any pointers are highly welcome!

Bye,
Tassilo
__________
[1] http://www.tsdh.de/cgi-bin/wiki.pl/exec-abbrev-cmd.el

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

* Re: Problems with catch and throw
  2007-10-04 16:16 Problems with catch and throw Tassilo Horn
@ 2007-10-05  6:59 ` Barry Margolin
  2007-10-05  7:14   ` Tassilo Horn
  0 siblings, 1 reply; 4+ messages in thread
From: Barry Margolin @ 2007-10-05  6:59 UTC (permalink / raw)
  To: help-gnu-emacs

In article <87myuy26tn.fsf@baldur.tsdh.de>,
 Tassilo Horn <tassilo@member.fsf.org> wrote:

> Hi,
> 
> I use a home-brewn function [1] instead of `execute-extended-command'
> most of the time.  It uses `read-from-minibuffer' to get a command
> abbrev from the user and then executes the command whose abbreviation
> was given.
> 
> Now I'd like to bind TAB in my function so that it aborts
> `read-from-minibuffer' and my function and falls back to
> `execute-extended-command' where the current minibuffer contents are
> inserted as initial input.
> 
> That sounds like a good candidate for catch/throw to me.  A minimal
> working example is:
> 
> --8<---------------cut here---------------start------------->8---
> (catch 'foo
>   (read-from-minibuffer "test: " nil
>                         (let ((map (copy-keymap minibuffer-local-map)))
>                           (define-key map "\C-i" (lambda ()
>                                                    (interactive)
>                                                    (throw 'foo 
>                                 (minibuffer-contents))))
>                           map)))
> --8<---------------cut here---------------end--------------->8---
> 
> Hit `C-j' after the last closing paren and type "foobar" at the "test: "
> prompt.  The form's result is "foobar" then.
> 
> So now here's my function with this mechanism applied.  But it doesn't
> work like the minimal example.  (minibuffer-contents) always returns the
> empty string "".  Why is that?

The problem isn't with minibuffer-contents, it's with

(message "cont = " (minibuffer-contents))

The first argument to message is a format string, and the remaining 
arguments will be substituted for the % codes in the string.  Since you 
don't have any % codes, it never displays the minibuffer contents.  So 
that should be:

(message "cont = %s" (minibuffer-contents))

> 
> --8<---------------cut here---------------start------------->8---
> (defun exec-abbrev-cmd (prefixarg)
>   "Query for a command abbreviation like \"mbm\" and calculate a
> list of all commands of the form \"m[^-]*-b[^-]*-m[^-]*$\".
> 
> If this list has only one item, this command will be executed
> directly. If there a more choices, the user will be queried which
> one to call.
> 
> The PREFIXARG is passed on to the invoked command.
> 
> With TAB fall back to `execute-extended-command'."
>   (interactive "P")
>   (let ((catch-val
>          (catch 'escape-from-exec-abbrev-cmd
>            (let* ((abbrev (read-from-minibuffer
>                            "Command Abbrev: "
>                            nil
>                            (let ((map (copy-keymap minibuffer-local-map)))
>                              (define-key map "\C-i"
>                                (lambda ()
>                                  (interactive)
>                                  ;; WHY RETURN MINIBUFFER-CONTENTS ""
>                                  ;; HERE, ALTHOUGH I TYPED FOOBAR AT THE
>                                  ;; PROMPT???
>                                  (message "cont = " (minibuffer-contents))
>                                  (throw 'escape-from-exec-abbrev-cmd
>                                         (minibuffer-contents))))
>                              map)))
>                   (regexp (concat "^"
>                                   (let ((part-list (split-string abbrev 
>                                 "-")))
>                                     (if (= 1 (length part-list))
>                                         ;; abc => a*-b*-c*
>                                         (mapconcat #'list abbrev "[^-]*-")
>                                       ;; ahead-b-c => ahead*-b*-c*
>                                       (mapconcat #'identity part-list 
>                                 "[^-]*-")))
>                                   "[^-]*$"))
>                   (commands (exec-abbrev-cmd-sort
>                              (remove-if-not (lambda (string)
>                                               (string-match regexp string))
>                                             (let (c)
>                                               (mapatoms
>                                                (lambda (a)
>                                                  (if (commandp a)
>                                                      (push (symbol-name a) 
>                                 c))))
>                                               c)))))
>              (if (not commands)
>                  (message "No such command.")
>                (let ((c (cond ((> (length commands) 1)
>                                (intern
>                                 (if (and (featurep 'ido) ido-mode)
>                                     ;; ido is available and enabled, so use 
>                                 it.
>                                     (ido-completing-read "Command: " 
>                                 commands)
>                                   ;; fallback to normal completion with the
>                                   ;; most frequently used command as default.
>                                   (completing-read (concat "Command (defaults 
>                                 to `"
>                                                            (car commands) 
>                                 "'): ")
>                                                    commands
>                                                    nil t nil nil (car 
>                                 commands)))))
>                               (t (intern (car commands))))))
>                  (call-interactively c t)
>                  (when exec-abbrev-cmd-mode
>                    (exec-abbrev-cmd-record c)))))
>            ;; Always return nil so that an escape with TAB is the only thing
>            ;; that makes `catch-val' non-nil.
>            nil)))
>     (when catch-val
>       (message "catch-val = " catch-val)
>       (execute-extended-command prefixarg)
>       (insert catch-val))))
> --8<---------------cut here---------------end--------------->8---
> 
> I guess it's something obvious, but I cannot see any principal
> difference between the simple working example and the code of my
> function.
> 
> Any pointers are highly welcome!
> 
> Bye,
> Tassilo
> __________
> [1] http://www.tsdh.de/cgi-bin/wiki.pl/exec-abbrev-cmd.el

-- 
Barry Margolin, barmar@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
*** PLEASE don't copy me on replies, I'll read them in the group ***

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

* Re: Problems with catch and throw
  2007-10-05  6:59 ` Barry Margolin
@ 2007-10-05  7:14   ` Tassilo Horn
  2007-10-05  8:11     ` Tassilo Horn
  0 siblings, 1 reply; 4+ messages in thread
From: Tassilo Horn @ 2007-10-05  7:14 UTC (permalink / raw)
  To: help-gnu-emacs

Barry Margolin <barmar@alum.mit.edu> writes:

Hi Barry,

> The problem isn't with minibuffer-contents, it's with
>
> (message "cont = " (minibuffer-contents))
>
> The first argument to message is a format string, and the remaining
> arguments will be substituted for the % codes in the string.  Since
> you don't have any % codes, it never displays the minibuffer contents.
> So that should be:
>
> (message "cont = %s" (minibuffer-contents))

Oh my god, that's more than awkward.  That happens when you use `insert'
and `message' in parallel. :-P

Ok, then the real question is: How can I invoke
`execute-extended-command' with an initial input string?

Bye,
Tassilo

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

* Re: Problems with catch and throw
  2007-10-05  7:14   ` Tassilo Horn
@ 2007-10-05  8:11     ` Tassilo Horn
  0 siblings, 0 replies; 4+ messages in thread
From: Tassilo Horn @ 2007-10-05  8:11 UTC (permalink / raw)
  To: help-gnu-emacs

Tassilo Horn <tassilo@member.fsf.org> writes:

Hi,

> Ok, then the real question is: How can I invoke
> `execute-extended-command' with an initial input string?

For the record:  That seems to be not possible, but you can mimic its
behavior like this:

--8<---------------cut here---------------start------------->8---
(let ((command (completing-read "M-x "
                                (let (commands)
                                  (mapatoms (lambda (a)
                                              (when (commandp a)
                                                (push (symbol-name a)
                                                      commands))))
                                  commands)
                                nil t catch-val)))
  (command-execute (intern command) t nil t))
--8<---------------cut here---------------end--------------->8---

Bye,
Tassilo

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

end of thread, other threads:[~2007-10-05  8:11 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-10-04 16:16 Problems with catch and throw Tassilo Horn
2007-10-05  6:59 ` Barry Margolin
2007-10-05  7:14   ` Tassilo Horn
2007-10-05  8:11     ` Tassilo Horn

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