]> git.eshelyaron.com Git - emacs.git/commitdiff
* lisp/kmacro.el: Use OClosure instead of messing with internals
authorStefan Monnier <monnier@iro.umontreal.ca>
Mon, 13 Dec 2021 21:43:58 +0000 (16:43 -0500)
committerStefan Monnier <monnier@iro.umontreal.ca>
Mon, 13 Dec 2021 21:43:58 +0000 (16:43 -0500)
* test/lisp/progmodes/elisp-mode-tests.el
(xref-elisp-generic-co-located-default): Silence warnings.

* test/lisp/kmacro-tests.el (kmacro-tests--cl-print): New test.

* lisp/kmacro.el (kmacro-function): New OClosure type.
(kmacro-lambda-form): Use it.
(kmacro-extract-lambda, kmacro-p): Simplify/rewrite accordingly.
(cl-print-object): New method.

* lisp/emacs-lisp/oclosure.el (oclosure-make): Keep interactive specs before the
function's code.

* lisp/edmacro.el (edmacro-finish-edit): Prefer `kmacro-p`.

lisp/edmacro.el
lisp/emacs-lisp/oclosure.el
lisp/kmacro.el
test/lisp/kmacro-tests.el
test/lisp/progmodes/elisp-mode-tests.el

index 29900a9595cdb4be886459b5bcdb5164c73408d3..be92cd03fb461b58c93453cbd8da3d8f02916945 100644 (file)
@@ -260,7 +260,7 @@ or nil, use a compact 80-column format."
                          (push key keys)
                          (let ((b (key-binding key)))
                            (and b (commandp b) (not (arrayp b))
-                                (not (kmacro-extract-lambda b))
+                                (not (kmacro-p b))
                                 (or (not (fboundp b))
                                     (not (or (arrayp (symbol-function b))
                                              (get b 'kmacro))))
index debb26bc8ad15f4457f92cc0556f58a30e104363..a18713616820febbbcc9b71fdd346f768a019b51 100644 (file)
            parent-names))
          (slotdescs (append
                      parent-slots
+                     ;; FIXME: Catch duplicate slot names.
                      (mapcar (lambda (field)
                                (cl--make-slot-descriptor field nil nil
                                                          '((:read-only . t))))
   ;; FIXME: Provide the fields in the order specified by `type'.
   (let* ((class (cl--find-class type))
          (slots (oclosure--class-slots class))
+         (prebody '())
          (slotbinds (nreverse
                      (mapcar (lambda (slot)
                                (list (cl--slot-descriptor-name slot)))
                              (setcdr bind (list temp))
                              (cons temp (cdr field)))))))
                      fields)))
+    ;; FIXME: Since we use the docstring internally to store the
+    ;; type we can't handle actual docstrings.  We could fix this by adding
+    ;; a docstring slot to OClosures.
+    (while (memq (car-safe (car-safe body)) '(interactive declare))
+      (push (pop body) prebody))
     ;; FIXME: Optimize temps away when they're provided in the right order!
     ;; FIXME: Slots not specified in `fields' tend to emit "Variable FOO left
     ;; uninitialized"!
          (oclosure--fix-type
           (lambda ,args
             (:documentation ',type)
+            ,@prebody
             ;; Add dummy code which accesses the field's vars to make sure
             ;; they're captured in the closure.
             (if t nil ,@(mapcar #'car fields))
index 3f492a851eab737f2fcee22a614934c4dd9625b5..0fd693950ef6bafafda1c6d78e1218ff0faf2190 100644 (file)
@@ -811,6 +811,10 @@ If kbd macro currently being defined end it before activating it."
 ;; letters and digits, provided that we inhibit the keymap while
 ;; executing the macro later on (but that's controversial...)
 
+(oclosure-define kmacro-function
+  "Function form of keyboard macros."
+  mac)
+
 ;;;###autoload
 (defun kmacro-lambda-form (mac &optional counter format)
   "Create lambda form for macro bound to symbol or key."
@@ -819,34 +823,40 @@ If kbd macro currently being defined end it before activating it."
   ;; or only `mac' is provided, as a list (MAC COUNTER FORMAT).
   ;; The first is used from `insert-kbd-macro' and `edmacro-finish-edit',
   ;; while the second is used from within this file.
-  (let ((mac (if counter (list mac counter format) mac)))
-    ;; FIXME: This should be a "funcallable struct"!
-    (lambda (&optional arg)
-      "Keyboard macro."
-      ;; We put an "unused prompt" as a special marker so
-      ;; `kmacro-extract-lambda' can see it's "one of us".
-      (interactive "pkmacro")
-      (if (eq arg 'kmacro--extract-lambda)
-          (cons 'kmacro--extract-lambda mac)
-        (kmacro-exec-ring-item mac arg)))))
+  (oclosure-make kmacro-function ((mac (if counter (list mac counter format) mac)))
+            (&optional arg)
+    (interactive "p")
+    (kmacro-exec-ring-item mac arg)))
 
 (defun kmacro-extract-lambda (mac)
   "Extract kmacro from a kmacro lambda form."
-  (let ((mac (cond
-              ((eq (car-safe mac) 'lambda)
-               (let ((e (assoc 'kmacro-exec-ring-item mac)))
-                 (car-safe (cdr-safe (car-safe (cdr-safe e))))))
-              ((and (functionp mac)
-                    (equal (interactive-form mac) '(interactive "pkmacro")))
-               (let ((r (funcall mac 'kmacro--extract-lambda)))
-                 (and (eq (car-safe r) 'kmacro--extract-lambda) (cdr r)))))))
-    (and (consp mac)
-         (= (length mac) 3)
-         (arrayp (car mac))
-         mac)))
-
-(defalias 'kmacro-p #'kmacro-extract-lambda
-  "Return non-nil if MAC is a kmacro keyboard macro.")
+  (when (kmacro-p mac)
+    (let ((mac (kmacro-function--mac mac)))
+      (and (consp mac)
+           (= (length mac) 3)
+           (arrayp (car mac))
+           mac))))
+
+(defun kmacro-p (x)
+  "Return non-nil if MAC is a kmacro keyboard macro."
+  (cl-typep x 'kmacro-function))
+
+(cl-defmethod cl-print-object ((object kmacro-function) stream)
+  (princ "#<kmacro " stream)
+  (require 'macros)
+  (declare-function macros--insert-vector-macro "macros" (definition))
+  (pcase-let ((`(,vecdef ,counter ,format)
+               (kmacro-extract-lambda object)))
+    (princ
+     (with-temp-buffer
+       (macros--insert-vector-macro vecdef)
+       (buffer-string))
+     stream)
+    (princ " " stream)
+    (prin1 counter stream)
+    (princ " " stream)
+    (prin1 format stream)
+    (princ ">" stream)))
 
 (defun kmacro-bind-to-key (_arg)
   "When not defining or executing a macro, offer to bind last macro to a key.
index ecd3d5fc22b625a54732232117f6310254695db0..51108e033b00a819da52eae8af6088dc3991922c 100644 (file)
@@ -825,6 +825,11 @@ This is a regression for item 7 in Bug#24991."
                                 :macro-result "x")
     (kmacro-tests-simulate-command '(beginning-of-line))))
 
+(ert-deftest kmacro-tests--cl-print ()
+  (should (equal (cl-prin1-to-string
+                  (kmacro-lambda-form [?a ?b backspace backspace] 0 "%d"))
+                 "#<kmacro [?a ?b backspace backspace] 0 \"%d\">")))
+
 (cl-defun kmacro-tests-run-step-edit
     (macro &key events sequences result macro-result)
   "Set up and run a test of `kmacro-step-edit-macro'.
index 9dc5e8cadcf0711d10676e3e0b23b5ea5715588d..b6161c367e4a5262b555e0319ff5e08d6b341459 100644 (file)
@@ -449,12 +449,15 @@ to (xref-elisp-test-descr-to-target xref)."
   ;; dispatching code.
   )
 
-(cl-defgeneric xref-elisp-generic-co-located-default (arg1 arg2)
+(cl-defgeneric xref-elisp-generic-co-located-default (_arg1 _arg2)
   "Doc string generic co-located-default."
   "co-located default")
 
 (cl-defmethod xref-elisp-generic-co-located-default ((this xref-elisp-root-type) arg2)
   "Doc string generic co-located-default xref-elisp-root-type."
+  ;; The test needs the above line to contain "this" and "arg2"
+  ;; without underscores, so we silence the warning with `ignore'.
+  (ignore this arg2)
   "non-default for co-located-default")
 
 (cl-defgeneric xref-elisp-generic-separate-default (arg1 arg2)