Aminal: Golang terminal emulator from scratch
github.com
github.com
• [1988] http://www.vt100.net/docs/vt3xx-gp/chapter14.html
• [1990] http://www.digiater.nl/openvms/decus/vax90b1/krypton-nasa/al...
It is one of the reasons why iTerm2 got so popular: https://iterm2.com/documentation-images.html
Personally I use terminology which I am satisfied with. https://www.enlightenment.org/about-terminology.md
Nowadays I just use terminal in gvim. It solved like all of my problems. Should've known Vim would save me again haha.
That said... pretty cool. I don't know if there already existed VT100 emulation written in Go, but it doesn't hurt to have that. Plenty of applications might want to embed a terminal or otherwise have terminal emulation.
Subpixel rendering is tricky, but should be possible to do with shaders. You could just render to a normal single channel texture at 3x the horizontal spatial resolution (basically, stretched 3x horizontally) then when rendering move 1 pixel across the glyph rendering for each subpixel, alpha blending individually.
Subpixel renderering with shaders is a neat idea, is it something that has been done before?
How do you figure? As I imagine it you would stream the buffer to the GPU and render it with a pixel shader. Even if layout or glyph calculation is done on the CPU it should be highly cacheable.
Of course it's all pixels. You can do it all in pixel shaders. But of course, it's a lot more complicated than it seems. Supporting RTL requires some pretty advanced layout logic. Supporting OpenType ligatures also requires some pretty complicated, stateful logic. And you probably want to support "wide" glyphs even for a fixed width font, which are present in terminals where you are dealing with, for example, kanji.
If you want subpixel AA, that's another complicated issue. If you want to be able to do subpixel AA where glyphs are not locked to the pixel grid, you will need to do more work.
If you want to be able to render glyphs on the GPU purely, you'll need to upload all of the geometries in some usable form. Most GPUs don't render curves, so you will probably turn them into triangles or quads. That's a lot of work to do and memory to utilize for an entire font of glyphs.
You also might think you could utilize GPUs to perform anti-aliasing, but the quality will be pretty bad if done naively, as GPUs don't tend to take very many samples when downsampling.
Since a lot of the work is stateful and difficult to parallelize, doing it on CPU will probably be faster, that way you only pay the latency to jump to the GPU once.
You can still easily cache the glyphs post processed, especially if you don’t use subpixel AA. There isn’t that much state to a scrollback buffer post glyph processing.
I don’t get the resistance to this type of rendering when at this point there are at least three major monospace glyph rendering libraries implemented for the GPU, and I bet there are dozens I don’t know about.
https://github.com/liamg/aminal/blob/master/glfont/font.go#L...
Speaking of the main loop, for every columm and every row:
cx := uint(gui.terminal.GetLogicalCursorX())
which in turn calls another function -- move that outside of the loop and do it once. Generally buffer values that don't change and get used in loops, instead of fetching them by calling functions on each iteration.Also, while it may not matter much in this case unless there are other sources of GC churn, just because I noticed it: don't create an array for the vertices for every character to then throw it away and recreate it, have one and keep reusing that.
In practice, you will be re-using the same areas of memory.
In this case, I also doubt it would make a difference by itself, but I haven't looked at all of the source, so I just mentioned it as something to maybe watch out for. Also, every bit of GC you can super easily avoid "buys" you room for GC that would make the code more complicated to avoid. Waste not, want not :)
See the comment by kibwen (https://news.ycombinator.com/item?id=18551218) for some good pointers to more concepts.
> Alacritty is the fastest terminal emulator in existence. Using the GPU for rendering enables optimizations that simply aren't possible in other emulators.
I wonder though why people need fast terminal emulators (?) I'm using "xterm" and I haven't found any issues with speed.
One thing that I thought would justify this is that they don't support scrolling text by themselves and to have it you're required to rely on tmux or screen.
Another approach is to run "screen", which has several advantages: (1) not all text needs to be written to the terminal, only the text when you actually look, (2) you can open the computation on a different computer later (e.g. perhaps at home to check if everything is ok), and (3) if you accidentally close the terminal the computation keeps running.
In both cases, my terminal emulator does not need to be fast, really.
My biggest issue with speed in the terminal comes from network latency (which is difficult to fix).
Oh, and while you are at it, have a look at mosh as well. Mosh bills itself as the ssh alternative for mobile, intermittent connections but it does take the idea of 'not all text needs to be written to the terminal, only the text when you actually look' even further.
Mosh also has lots of network latency hiding tricks up its sleeve.
Without acceleration it's a blur.
There's at least one other terminal emulator that does things akin to the image-catting and viewing colors when you click them, namely terminology [0].
There's also at least one other that uses opengl for faster rendering (alacritty [1]).
I don't know of any other that do both these things; use opengl for speed and also innovate in interactivity.
This is why there are separate commands like `icat` which will output ANSI escape sequences for rendering a PNG. Unfortunately a great many of these are terminal specific (iterm, terminology, kitty and VT200/VT300 (sixel) all have their own unique escape sequences. The closest to a standard we have is sixel and, frankly, I don't think it's that good on modern systems[1]). So you end up with different command for each "standard" you want rendered.
The approach I've taken in my own $SHELL is to have a builtin command like `cat` (I call it `open`) and that auto-detects which terminal emulator you're running and picks the right encoding to match what is supported by the terminal (if no standard can be auto-detected, then it falls back to ANSI art using coloured blocks). However the issue with that is now people need to run new custom shell instead Bash / Zsh / whatever. But the logic behind the auto-detection is really quite simple so that could be written it's own standalone tool.
[1] sixel re-encodes images in character blocks of 6 pixels. Where as iTerm, Kitty and Terminology send the image as is over the terminal via a base64 encoded string. All those solutions are inlined via ANSI escape sequences though.
This is not what I am talking about. I mean the binary headers inside png, jpg, tiff files, etc. These binary sequences can be easily interpreted as terminal control sequences, and they are very unlikely to appear otherwise. For pnm files I agree that the situation is a bit more delicate, as these sequences are likely to appear in the wild (e.g., in the pnm man page for example).
I'm very tempted to fork Aminal and have a play with your idea.
Notice that you do not even need to use sixels in your case. Since you control the rendering, you can simply put the pixels of the image on a rectangle (that allows paning and zooming, for example), and move the cursor below it.
But a larger question, at what point do we focus on the novelty of the project, not that it was written in a specific language?
That is the novelty:) Don't worry; we'll tire of Go in 1-50 years;)
In fact, since this is for a developer audience, I’d wonder why you wouldn’t say what language something is in.
Note: I work for Microsoft but I have never touched anything to do with ConPty.
I want to know what is difficult to support this.
I assume they're open to contribution if someone wants to add Metal support for mac osx.
Nowadays, terminals within vim/emacs is what's closer, feature wise. Not quite dumb though.
Also, to the other commmentator- be glad its not written in "modern web technology". I keep 20 terminals open usually.
I prefer tmux windows; I have 1-3 terminal emulators and 10-30ish windows/tabs (not counting splits/panes), all on 1 tmux session via `tmux new-session -t $SESSION`. Acceptably navigatable via prefix-[1-9] and prefix-w (which gives a list to jump to).
VTE based terminals are actually multithreaded globally, so you only ever have one process regardless of number of tabs/windows open.
But I agree, VTE is something I avoid ever since the scrollback fiasco. (For the uninitiated: the library wrote all scrollback to disk, which is not something end-users might expect security wise. Scrollback is encrypted now, but it appears you still cannot disable writing to disk, as e.g. the output of dmesg, consisting of 62210 bytes of output on my machine, causes 5-digits of bytes to be written each time on any VTE-based terminal I've tried even with "infinite" scrollback disabled. And none appear to honor TMPDIR).
https://github.com/GNOME/vte/blob/65d67f6f814df4f4ab800898bb...
Perhaps a terminal emulator is unable to read variables exported in .bashrc, as the terminal is started prior to executing the shell.
Can you please add some details on Unicode support? Most terminals claim to have it but fail miserably on Asian (Asia continent) fonts.
1) RTL for west Asia
2) Indic fonts and dependent vowels
3) Double width cjk.
I genuinely believe that without all 3, no terminal emulator deserves to claim Unicode support.