[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[nongnu] elpa/with-simulated-input ea666ecab7 064/134: Remove hacky clos
From: |
ELPA Syncer |
Subject: |
[nongnu] elpa/with-simulated-input ea666ecab7 064/134: Remove hacky closure modification |
Date: |
Mon, 10 Jan 2022 23:00:05 -0500 (EST) |
branch: elpa/with-simulated-input
commit ea666ecab70a116df6d1b0b41696aa655e7655bc
Author: Nikita Bloshchanevich <nikblos@outlook.com>
Commit: Nikita Bloshchanevich <nikblos@outlook.com>
Remove hacky closure modification
Rewrite `with-simulated-input' to expand more cleanly: return `lambda'
forms so
that correct closures are created at run-time, and make it hiegienic by
using
`make-symbol' for local variables.
Breaking change: remove `wsi-current-lexical-environment' and
`wsi-make-closure'
since they cannot be made to work reliably and rely on Emacs implementation
details. `wsi-next-action' is no longer temporarily defined.
---
with-simulated-input.el | 158 +++++++++++-------------------------------------
1 file changed, 36 insertions(+), 122 deletions(-)
diff --git a/with-simulated-input.el b/with-simulated-input.el
index a70e7eb523..e72c727cde 100644
--- a/with-simulated-input.el
+++ b/with-simulated-input.el
@@ -5,7 +5,7 @@
;; Filename: with-simulated-input.el
;; Author: Ryan C. Thompson
;; Created: Thu Jul 20 11:56:23 2017 (-0700)
-;; Version: 2.4
+;; Version: 3.4
;; Package-Requires: ((emacs "24.4"))
;; URL: https://github.com/DarwinAwardWinner/with-simulated-input
;; Keywords: lisp, tools, extensions
@@ -99,35 +99,6 @@ to check.
do (cl-return-from findkey bind))
finally do (error "Could not find an unbound key with the specified
modifiers")))
-(defmacro wsi-current-lexical-environment ()
- "Return the current lexical environment.
-
-If `lexical-binding' is not enabled, return nil.
-
-This macro expands to a Lisp form that evaluates to the current
-lexical environment. It works by creating a closure and then
-extracting and returning its lexical environment.
-
-This can be used to manually construct closures in that
-environment."
- `(let ((temp-closure (lambda () t)))
- (unless (listp temp-closure)
- (error "Cannot capture lexical environment from byte-compiled code"))
- (when (eq (car temp-closure) 'closure)
- (cadr temp-closure))))
-
-(defun wsi-make-closure (expr env)
- "Construct a closure from EXPR and ENV.
-
-Returns a zero-argument function that, when called, evaluates
-EXPR in lexical environment ENV and returns the result."
- (if env
- `(closure ,env () ,expr)
- `(lambda () ,expr)))
-
-(defconst wsi--canary-sym (cl-gensym "wsi-canary-")
- "A unique symbol.")
-
;;;###autoload
(defmacro with-simulated-input (keys &rest body)
"Eval BODY forms with KEYS as simulated input.
@@ -164,100 +135,43 @@ are propagated normally.
The return value is the last form in BODY, as if it was wrapped
in `progn'."
(declare (indent 1))
- `(cl-letf*
- ((lexenv (wsi-current-lexical-environment))
- (correct-current-buffer (current-buffer))
- (next-action-key (wsi-get-unbound-key))
- (result wsi--canary-sym)
- (thrown-error nil)
- (body-form
- '(throw 'wsi-body-finished (progn ,@body)))
- (end-of-actions-form
- (list 'throw
- '(quote wsi-body-finished)
- (list 'quote wsi--canary-sym)))
- ;; Ensure KEYS is a list, and put the body form as the first
- ;; item and `C-g' as the last item
- (keylist ,keys)
- (keylist (if (listp keylist)
- keylist
- (list keylist)))
- ;; Build the full action list, which includes everything in
- ;; KEYS, as well as some additional setup beforehand and
- ;; cleanup afterward.
- (action-list
- (nconc
- (list
- ;; First we switch back to the correct buffer (since
- ;; `execute-kbd-macro' switches to the wrong one).
- (list 'switch-to-buffer correct-current-buffer)
- ;; Then we run the body form
- body-form)
- ;; Then we run each of the actions specified in KEYS
- (cl-loop
- for action in keylist
- if (not (stringp action))
- collect action)
- ;; Finally we throw the canary if we read past the end of
- ;; the input.
- (list end-of-actions-form)))
- ;; Wrap each action in a lexical closure so it can refer to
- ;; variables from the caller.
- (action-closures
- (cl-loop
- for action in action-list
- collect (wsi-make-closure action lexenv)))
- ;; Replace non-strings with `next-action-key' and concat
- ;; everything together
- (full-key-sequence
- (cl-loop
- for action in keylist
- if (stringp action)
- collect action into key-sequence-list
- else
- collect next-action-key into key-sequence-list
- finally return
- ;; Prepend and append `next-action-key' as appropriate to
- ;; switch buffer, run body, and throw canary.
- (concat
- ;; Switch to correct buffer
- next-action-key " "
- ;; Start executing body
- next-action-key " "
- ;; Execute the actual key sequence
- (mapconcat #'identity key-sequence-list " ")
- ;; Throw the canary if BODY reads past the provided input
- " " next-action-key)))
- ;; Define the next action command with lexical scope so it can
- ;; access `action-closures'.
- ((symbol-function 'wsi-run-next-action)
+ (pcase keys
+ (`(quote ,x) (setq keys x))
+ ((guard (not (listp keys))) (cl-callf list keys)))
+ (let ((key-sym (make-symbol "unbound-key"))
+ (actions-sym (make-symbol "actions"))
+ (result-sym (make-symbol "result"))
+ (error-sym (make-symbol "wsi-error")))
+ `(let ((,key-sym (wsi-get-unbound-key))
+ (overriding-terminal-local-map
+ (if overriding-terminal-local-map
+ (copy-keymap overriding-terminal-local-map)
+ (make-sparse-keymap)))
+ (,actions-sym
+ ;; The lambdas must be evaluated at run-time for the closures to be
+ ;; built correctly, so we must use `list' instead of something like
+ ;; '.
+ (list (lambda ()
+ (throw ',result-sym ,(macroexp-progn body)))
+ ,@(cl-loop for key in keys unless (stringp key)
+ collect `(lambda () ,key)))))
+ (define-key overriding-terminal-local-map (kbd ,key-sym)
(lambda ()
(interactive)
- (condition-case err
- (if action-closures
- (let ((next-action (pop action-closures)))
- (funcall next-action))
- (error "`with-simulated-input' reached end of action list
without returning"))
- (error (throw 'wsi-threw-error err)))))
- ;; Set up the temporary keymap
- (action-map (make-sparse-keymap)))
- ;; Finish setting up the keymap for the temp command
- (define-key action-map (kbd next-action-key) 'wsi-run-next-action)
- (setq
- thrown-error
- (catch 'wsi-threw-error
- (setq
- result
- (catch 'wsi-body-finished
- (let ((overriding-terminal-local-map action-map))
- (execute-kbd-macro (kbd full-key-sequence)))))
- ;; If we got here, then no error
- (throw 'wsi-threw-error nil)))
- (when thrown-error
- (signal (car thrown-error) (cdr thrown-error)))
- (if (eq result wsi--canary-sym)
- (error "Reached end of simulated input while evaluating body")
- result)))
+ (unless ,actions-sym
+ (throw ',error-sym "Reached end of simulated input while
simulating body"))
+ (funcall (pop ,actions-sym))))
+ ;; If there is a result, `error' won't be called. Otherwise, there must
+ ;; be an error (Reached end of simulated input).
+ (catch ',result-sym
+ (error
+ (catch ',error-sym
+ (execute-kbd-macro
+ ;; We can't compute this at compile-time because we don't know
what key
+ ;; will be free.
+ (kbd (string-join (list ,key-sym ,@(cl-loop for key in keys
collect
+ (if (stringp key) key
key-sym)))
+ " ")))))))))
(defvar wsi-simulated-idle-time nil
"The current simulated idle time.
- [nongnu] elpa/with-simulated-input d0f7795942 034/134: Update buttercup, (continued)
- [nongnu] elpa/with-simulated-input d0f7795942 034/134: Update buttercup, ELPA Syncer, 2022/01/10
- [nongnu] elpa/with-simulated-input af9a38ce28 036/134: Add LICENSE file, ELPA Syncer, 2022/01/10
- [nongnu] elpa/with-simulated-input 3b847dec31 037/134: Add tests for wsi-get-unbound-key, ELPA Syncer, 2022/01/10
- [nongnu] elpa/with-simulated-input a718d66c5d 039/134: Don't generate a new canary for each call, ELPA Syncer, 2022/01/10
- [nongnu] elpa/with-simulated-input e8738fe72c 040/134: Fix issue #4 and add a test for it, ELPA Syncer, 2022/01/10
- [nongnu] elpa/with-simulated-input 011183121d 042/134: Remove Emacs 26.3 from Travis config, ELPA Syncer, 2022/01/10
- [nongnu] elpa/with-simulated-input d66b8b853f 041/134: Test in Emacs 26 on Travis, ELPA Syncer, 2022/01/10
- [nongnu] elpa/with-simulated-input 3d88179352 044/134: Version 2.4, ELPA Syncer, 2022/01/10
- [nongnu] elpa/with-simulated-input b030953ca0 050/134: Fix a bug with actually-wait, and add tests for it, ELPA Syncer, 2022/01/10
- [nongnu] elpa/with-simulated-input a71ecf18f7 051/134: Fix a bug in current-idle-time advice and add a test for it, ELPA Syncer, 2022/01/10
- [nongnu] elpa/with-simulated-input ea666ecab7 064/134: Remove hacky closure modification,
ELPA Syncer <=
- [nongnu] elpa/with-simulated-input cc15ccfe5a 062/134: Switch CI to Github Actions, ELPA Syncer, 2022/01/10
- [nongnu] elpa/with-simulated-input af15d1a1f5 068/134: Remove interpolation test, ELPA Syncer, 2022/01/10
- [nongnu] elpa/with-simulated-input 6ac56316df 074/134: Revert version change, ELPA Syncer, 2022/01/10
- [nongnu] elpa/with-simulated-input 057946280f 070/134: Greeting test: don't use dynamic forms, ELPA Syncer, 2022/01/10
- [nongnu] elpa/with-simulated-input 214ca2c4b1 087/134: Improve test coverage for current-idle-time advice, ELPA Syncer, 2022/01/10
- [nongnu] elpa/with-simulated-input 1a610d6587 089/134: Reorganize test suite, ELPA Syncer, 2022/01/10
- [nongnu] elpa/with-simulated-input c8389984e6 088/134: Update Eldev file, ELPA Syncer, 2022/01/10
- [nongnu] elpa/with-simulated-input 15581a4459 076/134: (symbol ...) KEYS are now function-call strings, ELPA Syncer, 2022/01/10
- [nongnu] elpa/with-simulated-input 38454eae74 086/134: Improve test coverage for wsi-get-unbound-key, ELPA Syncer, 2022/01/10
- [nongnu] elpa/with-simulated-input 82f8bada42 077/134: Fix tests, ELPA Syncer, 2022/01/10