unofficial mirror of guile-user@gnu.org 
 help / color / mirror / Atom feed
From: Leo Prikler <leo.prikler@student.tugraz.at>
To: Maxim Cournoyer <maxim.cournoyer@gmail.com>, guile-user@gnu.org
Subject: Re: Lost input when using suspendable read-line
Date: Mon, 23 Aug 2021 23:45:19 +0200	[thread overview]
Message-ID: <04425a0337fa3d75f367d7e390c280ff5aa1bb1c.camel@student.tugraz.at> (raw)
In-Reply-To: <87mtp8vmap.fsf@gmail.com>

Hi,

Am Montag, den 23.08.2021, 00:04 -0400 schrieb Maxim Cournoyer:
> --8<---------------cut here---------------start------------->8---
> (use-modules (ice-9 match)
>              (ice-9 rdelim)
>              (ice-9 suspendable-ports))
> 
> (install-suspendable-ports!)
> 
> (define (read-line* port cont)
>         ;; Return, as a pair, the line and the terminated delimiter
> or end-of-file
>         ;; object.  When a line cannot be read, return the
> '(suspended
>         ;; . partial-continuation) pair, where partial-continuation
> can be
>         ;; evaluated in the future when the port is ready to be read.
>         (call-with-prompt 'continue
>           (lambda ()
>             (parameterize ((current-read-waiter
>                             (lambda (_)
>                               (abort-to-prompt 'continue))))
>               (if cont
>                   (cont)
>                   (read-line port 'split))))
>           (lambda (partial-continuation)
>             (cons 'suspended partial-continuation))))
> 
> (define (main)
>   [...]
>      (let loop ((cont #f))
>        (match (select (list (port->fdes port)) '() '())
>          (((fdes ..1) () ())
>           (let next-line ((line+delim (read-line* port cont)))
>             (match line+delim
>               (('suspended . partial-continuation)
>                (loop partial-continuation))
>               ((line . _)
>                (format #t "~a~%" line)
>                (next-line (read-line* port cont)))))))))))
> 
> (main)
> --8<---------------cut here---------------end--------------->8---
This main loop appears broken.  Look at the value of cont over time. 
On the first few lines, before suspending, you will read all the lines
just fine.  But afterwards it will be set to partial-continuation, even
if said continuation is no longer current.

This appears to be no issue if you need less than one continuation to
finish the line, but if you need two or more, the outer continuation
will cause you to redo the inner over and over again.

I tried to make this loop somewhat more sensible:

--8<---------------cut here---------------start------------->8---
     (define port (car child->parent-pipe))
     (define cont (make-parameter #f))
     (define do-read
       (lambda ()
         (match (select (list (port->fdes port)) '() '())
           (((fdes ..1) () ())
            (match (read-line* port (cont))
              (('suspended . partial-cont)
               partial-cont)
              ((line . _)
               (format #t "~a~%" line)
               #f))))))

     (let loop ((cont? (do-read)))
       (loop (parameterize ((cont cont?)) (do-read)))))))
--8<---------------cut here---------------end--------------->8---
Here, each continuation is used exactly once, and that is to finish the
current line.  With this, I typically get output of the style:

--8<---------------cut here---------------start------------->8---
Line 1
[wait for it...]
Line 2
Line 3
Done!
Line 1
[wait for it...]
--8<----------
-----cut here---------------end--------------->8---
So it's not perfect either, but it's somewhat better than what you have
currently.

I'd hazard a guess that there are simpler implementations that need not
make use of parameters, particularly because I kinda eliminated the
inner loop anyway.  A simpler fix, which retains your structure is to
use 
               (next-line (read-line* port #f)))))))))))
in the case where a line has already been read.  This also seems to
have the desired behaviour of waiting after the "Done!" line.

Regards,
Leo




  reply	other threads:[~2021-08-23 21:45 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-08-23  4:04 Lost input when using suspendable read-line Maxim Cournoyer
2021-08-23 21:45 ` Leo Prikler [this message]
2021-08-24  2:03   ` Maxim Cournoyer

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/guile/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=04425a0337fa3d75f367d7e390c280ff5aa1bb1c.camel@student.tugraz.at \
    --to=leo.prikler@student.tugraz.at \
    --cc=guile-user@gnu.org \
    --cc=maxim.cournoyer@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).