unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* interactive closure — variables not bound
@ 2016-09-28  6:21 Ricardo Wurmus
  2016-09-28 12:41 ` Stefan Monnier
  0 siblings, 1 reply; 5+ messages in thread
From: Ricardo Wurmus @ 2016-09-28  6:21 UTC (permalink / raw)
  To: Emacs developers

Hi emacs-devel,

I’m currently attempting to rewrite some of the procedures and commands
in xwidget.el to do without the “title hack”.  Currently, the return
value of any JavaScript snippet that is run in WebKit is stored in the
title and then read out by running JavaScript to retrieve the title.

With the WebKit2 API all JavaScript is run asynchronously.  I’ve changed
“xwidget-webkit-execute-script” such that it takes an optional third
argument holding a Lisp callback, which is invoked with the return value
from JavaScript using “call1”.  This works fine for the most part,
although using callbacks is a little less convenient than doing things
synchronously (which is not supported by WebKit2).

Now there is at least one instance where things aren’t as smooth.  Take
“xwidget-webkit-insert-string” for example.  It is a command using
either “read-string” or “read-passwd” dependent on the input field
type.  The input field type is retrieved using JavaScript.  Using the
title hack this can be implemented in a faux synchronous fashion:

 (defun xwidget-webkit-insert-string (xw str)
   …
  (interactive
   (let* ((xww …)
          (field-value …)
          (field-type (xwidget-webkit-execute-script-rv
                       xww
                       "findactiveelement(document).type;")))
     (list xww
           (cond ((equal "text" field-type)
                  (read-string "Text: " field-value))
                 ((equal "password" field-type)
                  (read-passwd "Password: " nil field-value))
                 ((equal "textarea" field-type)
                  …)))))
   … ; do things with “xw” and “str”
   )

Using callbacks instead we have a problem, because the return value of
the JavaScript is only available in the callback procedure, not in the
“interactive” form.  To go around this problem I’m now trying to split
up “xwidget-webkit-insert-string” in two parts:

* “xwidget-webkit-insert-string”, which remains the interactive command
  exposed to the user.  It runs the JavaScript expression and in the
  callback passes the return value to …

* … a second interactive command, which takes care of prompting the user
  for a string to input.

This looks something like this:

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
(defun xwidget-webkit-insert-string ()
  (interactive)
  (let ((xww (xwidget-webkit-current-session)))
    (xwidget-webkit-execute-script
     xww
     (concat xwidget-webkit-activeelement-js
             "var res = findactiveelement(document); [res.value, res.type];")

     ;; This is called with “call1” from within “xwidget.c” when the
     ;; JavaScript return value is available
     (lambda (field)
       (let* ((field-value (car field))
              (field-type  (cadr field)))
         (call-interactively
          (lambda (str)
            (interactive
             (list (cond ((equal "text" field-type)
                          (read-string "Text: " field-value))
                         ((equal "password" field-type)
                          (read-passwd "Password: " nil field-value))
                         ((equal "textarea" field-type)
                          (xwidget-webkit-begin-edit-textarea xww field-value)))))
            (xwidget-webkit-execute-script
             xww
             (format "findactiveelement(document).value='%s'" str)))))))))
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The problem with this definition is that it doesn’t work (the other
problem is that I’m replacing one ugly hack with another).  At runtime
Emacs says that “field-type” is undefined.  At compile time Emacs says
that in the callback “xww”, “field-value”, and “field-type” are
references to free variables.

But why?  Isn’t this a closure?  “field-value” and “field-type” are
let-bound inside of the callback, so they should be available in the
scope of the interactive lambda’s “cond”.

I’ve also tried to do without “interactive” and just use “read-string”
directly, but while this gives me a prompt at runtime it also freezes
Emacs and eats up all my memory (which might be normal when using
“read-string” in a lambda that’s called from C with “call1”, dunno).

~~ Ricardo


PS: I’ve sent an email to assign@gnu.org a week ago with a completed
request form template, but haven’t received any response yet.




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

end of thread, other threads:[~2016-09-29  9:09 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-09-28  6:21 interactive closure — variables not bound Ricardo Wurmus
2016-09-28 12:41 ` Stefan Monnier
2016-09-28 21:12   ` Ricardo Wurmus
2016-09-29  0:07     ` Stefan Monnier
2016-09-29  9:09       ` Ricardo Wurmus

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