No current version, but I'm preparing it. But actually, to see a really ridiculously minimalist start, this was my starting point, which used a tiny C extension to do the X rendering (though it optimistically included a dummy class intended to be the start for the Ruby X backend). It's awfully limited, and awfully broken, but it shows how little it takes to be able to start writing:
It's totally useless for anything other that testing or expanding on, but it was the starting point for the terminal I now run every day, and I'll be updating that repo as I clean up my current version at some point.
The current version uses this for a pure Ruby (no Xlib) X11 client implementation:
And this pure-Ruby TrueType font renderer (I did the Ruby conversion; the C code it's based on was not mine, and is a beautiful example of compact C - look up libschrift) as I got tired of using the bitmap fonts and didn't want to add a FreeType dependency (the renderer is ~500 lines of code):
i look forward to seeing it! the simple, approachable truetype implementation is very exciting already! i didn't know about libschrift, but one third the code makes Skrift three times as approachable
Also to add that one thing that really inspired me with libschrift is the realization that Trutetype is conceptually really simple. Most of the code is parsing the annoying format. The actual rendering - as long as you don't deal with hinting, is just a matter of rasterising lines and quadratic bezier curves.
Handly OpenType then adds cubic bezier.
If, on the other hand, you want colour emojis, you need to implement a subset of SVG (though the subset is small).. Yikes.
You get 90% for 10% of the effort... As usual, I guess. Part of me want to see how far down full emoji font support can be golfed, but another part of me feels that's downright masochism.
i guess hinting is less important today than it was in the days of monochrome 1152×900 21" monitors and sub-mebibyte framebuggers where you couldn't do antialiasing
(and maybe you can do a decent job of blind "hinting" with smarter dsp algorithms, gradient descent, and orders of magnitude more cpu, and just ignore the tt hints virtual machine)
well-defined subsets of svg are a pretty interesting thing; i feel like a smol computing system might benefit from using something like that as its base graphical layer for things like fonts and windows; then a font engine can delegate the rasterizing down to the svg layer
parsing annoying formats is what https://github.com/abiggerhammer/hammer is for; we were able to get it to parse pdf. unfortunately it's not pure ruby. the smallest i've been able to get a peg parser library is http://canonical.org/~kragen/sw/dev3/tack.py which is 27 lines of python, but i'm not sure it can be reasonably extended to do the kind of binary parsing that hammer does without balooning in size
Similar thoughts on hinting - it's "good enough" for me on full HD w/just the antialiasing. With respect to automatic hinting, as I understand it Freetype has autohinting based on heuristics as hints in the fonts are often poor, but I haven't looked at how complex the auto hinter is.
Thanks for the nile and gezira link - it'd be fun to handle the emoji fonts too, at least as an addon...
Hammer looks interesting. I'm right in the middle of yet another parser combinator library in Ruby, but focused on text (it annoyed me that the Ruby Toml parser pulled in a 1500 line dependency for several hundreds of lines of excessively verbose parser definition for a grammar that can be defined in ca 50 lines) and frankly more an excuse to toy with refinements to see if I can get closer to BNF for specifying it.
I might have a look at hammer for inspiration for ways to shrink the ttf parser later.
yeah, hammer is maybe small for a c parsing library but in absolute terms isn't that small (about 10 kloc if you leave out the bindings) but it might be good as a reference point for api design
because i'm not a fan of excessively verbose things, i've been tossing around ideas for a new non-parser-combinator-based peg parsing system called 'the monkey's paw' whose grammars look like this
which you can make even more bnf-like if you want by putting <digits> and <var> on their own lines
based on my experience with peg-bootstrap i suspect i can probably implement this metacircularly in about 100 lines of code in something like lua, js, or ruby, but getting it built in a non-self-referential way will take another 100 or so. i wasn't planning on doing hammer-style bitfields and stuff, and though i might end up with hammer-style parser combinators for bootstrapping, the idea is to use a host-language-independent grammar syntax as the main way to define grammars
I really should just reproduce that output in its entirety for direct comparison.
If it does not produce pixel for pixel identical output it's a bug. But here is the first pass of code that uses the same approach to integrate it with X and use Xrender to output the rendered glyphs:
(EDIT: Fixed the issue below)
Note that the example contains a hard coded visual. I need to push a fix for that - it was last updated before I added support to the X11 client to look up the visual. In it's current form it probably won't work for you. Will see if I can push a fix for that today.
nice! probably magenta on a red background is undesirable, though; maybe switch to colors with better contrasts, or add a border or drop shadow, or just postprocess with a zero-phase high-pass filter
what do you think an idiomatic ruby binding for yeso would look like? so far i only have lua, c, and python bindings, which are described in https://gitlab.com/kragen/bubbleos/blob/master/yeso/README.m.... my ruby experience is both limited (only a few thousand lines of code) and over a decade ago
Yeah, the colour choices were pretty random, I need to clean it up.
X11 visuals are severely annoying. I get they made sense in the 80's and 90's - I spent time in computer labs where the machines ranged from monochrome to SGI Indy's, with 8-bit palette, and 15 and 16 bit direct color displays in between, but I'm all for just assuming 32-bit bgra is available these days.
Any server supporting XRender needs to support it anyway as it's one of the standard formats for XRender. (I don't know if you've looked at the XRender library code, though, but one of the things that made me facepalm was that even though it requires a handful of standard visuals, the new Xrender call that returns the visuals for Xrender does not just return a list of the handful of standard formats as part of the response - you need to filter the full list of visuals and match them to depths and bit masks... Not that it's a lot of code, but it just so aggravatingly pointless)
> what do you think an idiomatic ruby binding for yeso would look like?
I think a bit of a mix between the Python and Lua would get you pretty close. Don't look at "my" X11 client for idiomatic Ruby :) It was "inherited" from an older client, and it's very closely following the protocol more so than idiomatic Ruby, and I'll eventually try to massage it into something nicer.
To take your examples, we'd probably want to use blocks. E.g. I could see the munching squares example looking something like this in
Ruby:
def munch(t, fb)
fb.each_row do |y|
fb.each_col do |x|
fb[x,y] = ...
end
end
end
You could also use the approach you use more directly, and I'm sure nobody would think that was weird either:
def much (t,fb)
fb.each_row do |y, p|
fb.each_col do |x|
p[x] = ...
end
end
end
For the main bit, "new" will always directly return the window,
but it's not unreasonable to then either `yield self if block_given?` in the constructor to allow similar code to your Python version:
Yeso::Window.new(...) do |w| .. and so on; end
or wrap that in a class method:
Yeso::Window.create(...) do |w|
(0..).each {|t| w.frame {|fb| much(t,fb) } }
end
(Endless infinite range is "new" since 2.6)
The class method vs. constructor only really buys you that you can make it slightly harder to accidentally keep the object around since you can prevent it from being directly returned. I think overall that's probably the most common approach even when the constructor
supports taking a block directly.
https://github.com/vidarh/rubyterm
It's totally useless for anything other that testing or expanding on, but it was the starting point for the terminal I now run every day, and I'll be updating that repo as I clean up my current version at some point.
The current version uses this for a pure Ruby (no Xlib) X11 client implementation:
https://github.com/vidarh/ruby-x11
And this pure-Ruby TrueType font renderer (I did the Ruby conversion; the C code it's based on was not mine, and is a beautiful example of compact C - look up libschrift) as I got tired of using the bitmap fonts and didn't want to add a FreeType dependency (the renderer is ~500 lines of code):
https://github.com/vidarh/skrift