Tattoy: a text-based terminal compositor
46 points by tombh
46 points by tombh
Whereas this is mostly a terminal eye-candy project to get you street cred, it does have some serious aspects.
Firstly it solves the age-old problem of low-contrast text, like when you ls
a broken symlink and the red background colour is too near your current theme’s foreground colour. Tattoy solves this by using none other than the web’s WCAG 2.1 contrast algorithm for accessible text.
Secondly, an explicit design goal is that Tattoy should be able to polyfill new terminal protocols, the xwayland
of the TTY if you will. Say if we want to experiment with completely deprecating ANSI codes, then any application that uses a new protocol can be run in Tattoy which itself runs in any ANSI-standard terminal emulator as normal. You can read more about this idea here: https://tattoy.sh/news/an-end-to-terminal-ansi-codes/
But ultimately this has been something more akin to an art project, something to enjoy for the sheer aesthetic pleasure.
Firstly it solves the age-old problem of low-contrast text
Nice. This is one of the two big reasons why I wrote my own terminal emulator (the other being shift+page up not working in nested things. i think mainstream emulators allow this now too tho thanks to those kitty (like) keyboard protocols).
Art projects are fun but I think a lot of people forget that the key point of a regular use terminal is to read the text!
Thank you. Is your terminal emulator public? I was thinking that I’ll fork a terminal emulator one day to make Tattoy native. How did you solve the nested SHIFT+PAGEUP issue!?
Right, it’s all about the text!
Yes it is public, but it is very much a “works for me, you’re on your own” thing, even the makefile hardcodes paths on my computer (and it is all written in D with my custom libraries, and D isn’t exactly a mainstream popular language either), so it is unlikely to be of much value for you.
that said the code is https://github.com/adamdruppe/terminal-emulator and it depends on my main library collection here: https://github.com/adamdruppe/arsd notably notice terminalemulator.d in that library repo which is the in-memory representation, then the terminal-emulator repo puts uis on it.
How did you solve the nested SHIFT+PAGEUP issue!?
The solution here though was very simple: when the alternate screen is active, it sends it to the application with similar escape sequence to other modified keys. So it sends \e[5;2~
and \e[6;2~
… or something like that, i forget the specific and my code is kinda ugly lol. But it uses the same modifier encoding as other keys combined with normal page up/down codes .
But the magic is just when the alt screen is active, it treats page up/down like an application key, since scrolling back the alt screen is pretty meaningless anyway unless the application helps. So a nested terminal can simply switch to alt screen - which it probably does anyway - and then receive the key and handle scrollback itself.
Wow your terminal emulator isn’t actually that much code. I know it’s not feature complete but still, it inspires me to try my own. Maybe we should all try to make our own terminals!
Ah yes the alternate screen, I do some of that in Tattoy too. There are some edge cases thought like I think in say a less
pager which doesn’t set alternate screen but I still want to scroll it and not the scrollback.
Wow your terminal emulator isn’t actually that much code.
Yeah, there’s a lot of things you can skip because it isn’t actually used in practice. My terminal emulator has been my daily driver for a solid ten years now, it has proven to be good enough (for me). Instead of following a spec, I took a few programs I cared about (vim, mutt, etc.) and just kept implementing bits they used until they worked. The result is sometimes buggy when new things cross me but… meh, my habits are pretty set in their ways.
fun fact, my thing loses big on most throughput tests, but does solidly ok on input latency tests. I made zero effort on this, I think it is just because I do the gui side of it old school xlib XDrawText calls most the time (this implementation is inside the simpledisplay.d file). That’d probably not work so well for your shader fun though lol.
Now this justifies all the new GPU-accelerated terminals. Very cool project, thanks for sharing it!
Currently the protocol is JSON over
STDIN
andSTDOUT
.
Why did this hit me? I mean, if more things said this, the world would be a pretty interesting place.
In a good way? I just went for the simplest for now. If the plugins gain popularity then I can look into adding better protocols.
I hit me in a good way. The concept of doing something as simply as possible, or in the most straightforward way that is obvious, just resonates in my head. In this case the JSON seem critical. You probably couldn’t exchange plain text, it’d get too unformatted and too mixed up, you need a data structure format. And nowadays what’s the most obvious one? It reminds me of another article that went to the top of lobsters recently about the tigerbeetle database written in zig. The author was saying how their decision to just use the raw bytes in their data structure in memory as the “universal” interchange format sounded similar. He said they use it in memory for the zig code (my impression is that’s where it comes from), but then also to write to disk, and also to send over network connections. There’s probably a little leakage where things from one concern show up, when they aren’t always needed everywhere, I don’t know. But the simplicity of “we have one byte layout for this data, and we use it everywhere” feels similar to this “we have two processes that need to share structured data”.
Oh, yes that was exactly my thinking! Just go for the most obvious and straightforward approach to begin with. I didn’t see that Zig article, and I must admit I’d never heard of that idea, just passing around bytes exactly as they are in memory. That’s even more straightforward than JSON over STDIN/OUT!
I wonder if it would be possible to alter layer 0 as well to put additional information. It may not work in any applications, but for CLI-based apps, I think it would be OK. This would allow to solve IP addresses and the like for example. Alternatively, we could have a hotkey that would layer up the information.
Oh yes absolutely! This is very much part of Tattoy’s design goals. I personally haven’t implemented anything like that yet just because I’ve to get the framework solid first.