I made a post about my UI engine CoshUI once before that never really gained any traction, so if this does well and people need an idea on what I m talking about, here s the previous post:https://news.ycombinator.com/item?id=48607858Now back to topic, I ve been working on a markup language for CoshUI specifically to make text easier to style. To set the stage, here s an example of how it works: cui.RichLabel(id= title , text= [bold color=(255, 0, 0) font_size=48]You Died![blue italic] Haha![/][/] , strikethrough=True) This renders You Died in bold, red, and a font size of 48 with Haha! being overridden to blue and having italic on top of the bold and font size, then the entire text gets a strikethrough due to it being set on RichLabel.Before this update, I had a basic Label widget that had styling parameters and would render whatever was on the `text` field. Of course, as you can imagine, it s extremely limiting.So I set out to create a system that fit with CoshUI s backend-agnostic-ness while also making it easy and viable to use. So I got to reworking how the text system worked.My inspiration, Godot s RichTextLabel node, exposes BBCode. Which is the direct inspiration for CoshML , the markup language for CoshUI s text. But one thing I didn t like about BBCode is that it only accepts one style per tag. So I looked at HTML and saw the concept of multiple calls directly in a single tag and sought to follow something similar.When it comes to the implementation, I originally went with something like: [color=(255, 0, 0)]Hello[/color] Which is pretty obvious, but see, if I sought to create multiple styles in one tag (e.g. [color=(255, 0, 0) font_size=28]), I d need a universal closing tag instead of the named closing tag like BBCode or HTML.The implementation I landed on was a stack system. It would put each style into a class, and append that class to the stack, then when the parser sees [/] (or the universal closing tag), it ll pop that style out of the stack in a LIFO manner. Basically: style_stack = [TextStyle(default_values), TextStyle(text_color=(255, 0, 0), font_size=28, inherited_values_from_higher_style)] Then, each time there s text, it would just look towards the topmost style in the style stack, and append those styles to itself.That s basically the surface-level explanation of how the parser works. What was tough was how to render text. Because CoshUI is backend-agnostic, I needed a unified way to render text in every backend. So what I did was separate text that had different styling to something called a TextRun .At least at the time, the idea was to render each TextRun in the backends. They d iterate through each run, and they d render them. It became more complicated once I remembered text wrapping and alignment.The solution was to make another class called LineLayout which holds TextFragment classes. TextFragments would hold all the necessary styles for that specific text, while LineLayout would hold all the TextFragments for that line. It would all be derived based on the styles in TextRun. So an example would be:2 lines, with 2 TextRuns. The text in the first TextRun goes from 0-39 in letter position, the second is 40-81. The first line is from 0-46 in letter positions, so it will create 2 TextFragments that have the styles in run 0-39, and 40-46. Then the second line will have a TextFragment from 47-81.So with that, backends just iterate through LineLayout and render those TextFragments.Now, is it perfect? No, very much no. But it doesn t stop me from being proud of what it can do. I ve learned a lot while making this and I d really like some advice and feedback on the project as a whole.