Open xsebek opened 1 year ago
@xsebek Right now there is something kinda close to this in the library: Brick.Main.renderWidget
(docs here). It was added somewhat recently by someone who wanted to be able to write tests. It's more involved than what you're asking for here, though, because the Brick renderer needs to know some things in order to run. The function I linked to does not require an attribute map, but it does require a display region size (since that governs much of how UI rendering is done). It also outputs a Picture
, which is of course much richer than just plain text.
One thing I want to highlight about your use case is that it assumes that the only things you'll be testing are things that have Fixed
horizontal and vertical size policies. That covers a lot of things, but I wanted to make sure to point that out (since any documentation for any newly-added functionality would need to also document that assumption and the function would also need to have a good way of dealing with -- rejecting? -- widgets that declare infinite size).
Given the function in the library today,
renderWidget :: (Ord n) => Maybe AttrMap -> [Widget n] -> DisplayRegion -> Picture
I think the task would be to write a wrapper, something like this:
renderWidgetPlain :: (Ord n) => Widget n -> Text
renderWidgetPlain w = pictureToText $ renderWidget Nothing [w] (1000, 1000)
pictureToText :: Picture -> Text
pictureToText = ???
It seems to me that pictureToText
is the thing that would need to be written (and the assumptions encoded in the body of renderWidgetPlain
would need to be documented emphatically as being only for testing purposes).
I don't have much time right now to look into what that would entail, but I'd be happy to review a patch if you or someone else wants to take a shot at it. I think pictureToText
would go in the vty
package if that happens. If someone does undertake this, I would strongly recommend doing it in a way that re-uses the Vty logic for image rendering. That could be tricky because Vty emits bytes, not Text, and escape sequences of various kinds would need to be either scrubbed (not my preference) or just omitted entirely at rendering time (what I'd hope we could do instead). I believe Vty has a mock output backend for testing that it uses in its test suite (that I didn't write and am not super familiar with). That might actually be the best place to start looking since perhaps it gets very close to what renderWidgetPlain
will ultimately want anyway.
Thanks for the detailed response and tips, @jtdaugherty! 👍 I am glad to hear I was not missing some obvious way to do this. 😅
I don't think I have encountered widgets with infinite size requirements, but I assume there has to be a way to wrap them and display them in a finite region which is what the mock function would do. 🙂
I'll take a look at the vty
source and tests and see how hard this would be.
@xsebek I took a quick look and it looks like the implementation in Graphics.Vty.Output.Mock
is close to what would be needed; it just needs to be duplicated and adjusted in a new backend that doesn't emit the metacharacters that the current mock backend emits. At that point renderWidgetPlain
would need to be put into IO
so that it can initialize Vty with the desired backend and then read from the place the backend writes (such as the IORef
approach taken by the current mock backend).
@xsebek is this something you are still interested in working on? I'd like to close this ticket if this is dormant for now, and re-open it or open new ones later if you get into the work and have questions. Let me know!
Just noting that I'm actively interested in this as well. I'm going to play around with Graphics.Vty.Output.Mock
and see how it works for tests with the extra metacharacters, but if that doesn't do what I need very well, I'll likely make an attempt at implementing a pictureToText
in the next few months if no one else has done it by then.
I would like to be able to render widgets to
Text
.The documentation of
renderWidget
suggests using theVty
library to renderPicture
, but it is not obvious to me how to do that.What I would like is a function like this:
For example in the Swarm game we have recipes like this:
Connecting widgets by lines looks really nice, but I would also like to print this to the
stdout
and save it on Wiki so that I don't have to run the game to see the recipes.Another use case would be to doctest the UI functions. Something like:
@jtdaugherty would you be interested in having such function in brick? :slightly_smiling_face:
Or maybe this is really simple and could just be added as a code snippet to the documentation.