Acme-Parataxis

 view release on metacpan or  search on metacpan

eg/tui_bubbletea.pl  view on Meta::CPAN

    my $prev_h = $init_h;
    if ( $^O eq 'MSWin32' ) {
        while ( !$quit->count ) {
            Acme::Parataxis->await_sleep(100);    # 10 Hz polling
            my ( $w, $h ) = get_terminal_size();
            if ( $w != $prev_w || $h != $prev_h ) {
                ( $prev_w, $prev_h ) = ( $w, $h );
                $ch->put( MsgResize( $w, $h ) );
            }
        }
    }
    else {
        $SIG{WINCH} = sub { $RESIZE_FLAG = 1 };
        while ( !$quit->count ) {
            Acme::Parataxis->await_sleep(250);    # 4 Hz polling
            if ($RESIZE_FLAG) {
                $RESIZE_FLAG = 0;
                my ( $w, $h ) = get_terminal_size();
                if ( $w != $prev_w || $h != $prev_h ) {
                    ( $prev_w, $prev_h ) = ( $w, $h );
                    $ch->put( MsgResize( $w, $h ) );
                }
            }
        }
    }
}

# Fiber: periodic tick (1 Hz)
sub tick_fiber ( $ch, $quit ) {
    my $count = 0;
    while ( !$quit->count ) {
        Acme::Parataxis->await_sleep(1000);
        $count++;
        $ch->put( MsgTick($count) );
    }
}

# Main runtime
async {
    enable_raw_mode();
    hide_cursor();
    my $messages = Acme::Parataxis::Channel->new( capacity => 64 );

    # Shared quit signal -- broadcast() wakes all fibers checking it
    my $quit = Acme::Parataxis::Signal->new( count => 0 );

    # Query initial terminal size
    my ( $init_w, $init_h ) = get_terminal_size();

    # Initial model
    my $model = {
        cursor  => 0,
        ticks   => 0,
        toggled => {},
        width   => $init_w,
        height  => $init_h,
        items   => [
            'Async I/O via thread pool',
            'Fibers with cooperative scheduling',
            'Nonblocking reads on STDIN',
            'Concurrent tick timers',
            'Channel-based message passing',
            'SIGWINCH resize support',
            'No Term::ReadKey dependency'
        ],
    };

    # Spawn concurrent fibers (use `fiber` -- it has the & prototype)
    fiber { input_fiber( $messages, $quit ) };
    fiber { tick_fiber( $messages, $quit ) };
    fiber { resize_fiber( $messages, $quit, $init_w, $init_h ) };

    # Event loop
    clear_screen();
    while (1) {
        my $msg = $messages->get();
        my $cmd;
        ( $model, $cmd ) = Update( $model, $msg );
        if ( $cmd && $cmd->{type} eq 'quit' ) {
            last;
        }

        # Render.
        # await_write(STDOUT) uses select() which doesn't work on Windows
        # console handles -- skip it there.  stdout is always writable for
        # a console anyway.
        my $view = View($model);
        Acme::Parataxis->await_write( \*STDOUT, 50 ) if $^O ne 'MSWin32';
        clear_screen();
        print $view;
    }

    # Cleanup: signal all fibers to exit, then restore terminal
    $quit->send();    # sets $count = true so all fiber loops see it
    $messages->shutdown();
    show_cursor();
    clear_screen();
    move_to( 1, 1 );
    disable_raw_mode();
    say 'Goodbye!';
    Acme::Parataxis::stop();
};



( run in 1.037 second using v1.01-cache-2.11-cpan-ad66724bd6a )