TheEmeraldBee / widgetui

A bevy systems like widget system for ratatui and crossterm
MIT License
37 stars 5 forks source link

Async support #2

Closed barsoosayque closed 7 months ago

barsoosayque commented 7 months ago

As a bevy enjoyer myself, I've been interested in its ergonomics for a TUI library. Widgetui seems really nice and simple, but I wanted to use async code. As far as I understand, ratatui can work in async environment, but I'm not sure if this library can ? Would it be possible ?

TheEmeraldBee commented 7 months ago

I am happy to look into this! I'm not very sure myself how adding optional async to a library works but it is definitely possible! I'll try to get some concepts written at some point tomorrow, and start working on getting this working. Hopefully, since it is built off of ratatui, not many changes should be required.

TheEmeraldBee commented 7 months ago

Could you give me an example of what you would like to see with this support? I assume you want async systems, is that correct?

barsoosayque commented 7 months ago

I assume you want async systems, is that correct?

Yes, I'm not really sure how exactly at the moment, since I'm not very versed in async/tokio, but basically I would need App::run to be async so I can run it on tokio::main, and then to have async systems that can do something in background. As far as I understand systems now are tied to widgets, and those widget systems are blocking because they are just forming a ratatui frame. But I would like to have a system that I can just:

  1. Run in a background every second or other duration
  2. Run on event

(Kinda like run_if or just custom schedulers work in bevy)

My use-case is I'm building a small mpd player, and the client library is async. So I would need a system that queries a playback status every second and update some state, which is then used by a widget system to render info about the current song. And then I need to handle hotkeys to enable "single" mode, for example, which is also an async function of the client library that just sends a command and I would need to re-query playback status right away.

barsoosayque commented 7 months ago

Though, of course doing await in widget systems would work too, because this is exactly what I do at the moment in my code which uses just basic ratatui. I was mostly outlining the most ergonomic solution I could think of, but the basic implementation of just widget systems but async and without any fancy scheduling would be perfectly fine too.

TheEmeraldBee commented 7 months ago

I'll work on starting with just async systems, and eventually, I would love to be able to use scheduling, but I need to do some more research on how it works.

TheEmeraldBee commented 7 months ago

I am currently struggling with getting the type system and the way I've implemented systems to allow this. I'll continue to struggle my way through this, but it will probably take longer than expected.

barsoosayque commented 7 months ago

No worries, thanks for looking into it. I though about the whole thing again yesterday, and my conclusion was that async widget systems are probably the only thing I'll need. If I really would need other complex features like schedulers and run conditions it would be better to just directly use bevy_ecs (thanks to its modularity) and somehow plug ratatui into it

TheEmeraldBee commented 7 months ago

As I've done more research, it seems that async systems would not be possible. Bevy actually at this time does not have async systems either. What I would do if I were you, I would simply use the futures crate, and write a system that, blocks on a future, or runs a thread through tokio. The async runtime really shouldn't be necessary for your goals.

fn test(frame: &mut WidgetFrame, mut data: RefMut<Data>) -> WidgetResult {
   block_on(async move {
      data.field += 1;
      future().await;
   });
   Ok(())
}

If I get to a point where I can figure out how to allow for async systems, I would love to, but at this time, my understanding of the type system, and the knowledge that this doesn't really exist yet means I don't have a reference to write this from.