Subject: Re: bug#23430: 25.0.93; iter-defun does not support special form save-current-buffer

From: Dmitry Gutov <[email-masked]>
Date: Fri, 6 May 2016 01:46:54 +0300

On 05/03/2016 04:31 AM, Dmitry Gutov wrote:

> The above example seemed to me to be the prime use case for generator.el
> (e.g. lazily parsing output from an asynchronous process), so this
> is disappointing.

Actually, I take this back.

- generator.el doesn't seem useful for parsing output from an 
asynchronous process because it has no way to indicate whether the 
process has new output, or to return control back to Emacs while the 
process is still running but has no new output. It seems to call for a 
different abstraction.

- with-current-buffer turned out not to be so essential. Nor 
save-excursion. I've reimplemented xref--buf-pairs-iterator using 
iter-lambda but couldn't get the full benefit of the package because 
that function also needs a way to reliably clean up resources. The 
result is a bit more comprehensible, but also longer, so I'm hesitant to 
use it (attached).

So sum up, maybe this bug can be closed, but I'd like to see Daniel's 
opinion. Supporting with-current-buffer might turn out to be more 
essential in other cases.
diff --git a/lisp/progmodes/xref.el b/lisp/progmodes/xref.el
index f651dc9..f8b3c85 100644
--- a/lisp/progmodes/xref.el
+++ b/lisp/progmodes/xref.el
@@ -71,6 +71,7 @@
 (require 'ring)
 (require 'pcase)
 (require 'project)
+(require 'generator)
 
 (eval-when-compile
   (require 'semantic/symref)) ;; for hit-lines slot
@@ -534,19 +535,12 @@ xref-query-replace-in-results
       (funcall iter :cleanup))))
 
 (defun xref--buf-pairs-iterator (xrefs)
-  (let (chunk-done item next-pair file-buf pairs all-pairs)
-    (lambda (action)
-      (pcase action
-        (:next
-         (when (or xrefs next-pair)
-           (setq chunk-done nil)
-           (when next-pair
-             (setq file-buf (marker-buffer (car next-pair))
-                   pairs (list next-pair)
-                   next-pair nil))
-           (while (and (not chunk-done)
-                       (setq item (pop xrefs)))
-             (save-excursion
+  (let* (item
+         file-buf pairs all-pairs
+         (iter
+          (funcall
+           (iter-lambda ()
+             (while (setq item (pop xrefs))
                (let* ((loc (xref-item-location item))
                       (beg (xref-location-marker loc))
                       (end (move-marker (make-marker)
@@ -568,9 +562,19 @@ xref--buf-pairs-iterator
                       ((equal file-buf (marker-buffer beg))
                        (push pair pairs))
                       (t
-                       (setq chunk-done t
-                             next-pair pair))))))))
-           (cons file-buf (nreverse pairs))))
+                       (iter-yield (cons file-buf (nreverse pairs)))
+                       (setq file-buf (marker-buffer beg)
+                             pairs (list pair)))))))
+               (when (null xrefs)
+                 (iter-yield (cons file-buf (nreverse pairs)))))))))
+    (lambda (action)
+      (pcase action
+        (:next
+         (condition-case nil
+             (save-excursion
+               (iter-next iter))
+           (iter-end-of-sequence
+            nil)))
         (:cleanup
          (dolist (pair all-pairs)
            (move-marker (car pair) nil)