[HN Gopher] Anatomy of a Terminal Emulator
___________________________________________________________________
Anatomy of a Terminal Emulator
Author : imsnif
Score : 244 points
Date : 2021-11-02 13:01 UTC (9 hours ago)
(HTM) web link (www.poor.dev)
(TXT) w3m dump (www.poor.dev)
| admin786 wrote:
| Thanks top message
| blamod wrote:
| damn dude this was such a good article until i got to rust
| code...
| dundarious wrote:
| Casey Muratori's refterm video series is a great example of how
| to do application design. It focuses on writing a terminal
| emulator for Windows, but almost all the concepts apply to nixes
| as well -- even down to the level of OS primitives like memory
| mappings to create a ring buffer, etc. He builds a nearly
| complete terminal that appears to better support unicode and
| escape sequences than windows-terminal, in drastically less code
| and with literally orders of magnitude better performance.
|
| In particular, I like his focus on experimentation to figure out
| a reasonable upper bound on performance (so you can measure
| success/failure), "non-pessimisation" (don't do things extrinsic
| to the actual task), understanding the actual machine and its
| capabilities (he doesn't use the term, but sometimes called
| "mechanical sympathy"), and tactics for isolating "bad code" that
| you probably have to use (at least to get started).
|
| https://www.youtube.com/watch?v=pgoetgxecw8
| michaelsbradley wrote:
| For those interested in learning more about terminal emulators
| and character graphics, checkout Nick Black's book _Hacking the
| Planet (with Notcurses): A Guide to TUIs and Character Graphics_
| [1].
|
| While the overall focus of the book is on programming with
| Notcurses[2], the author shares a wealth of related info and
| history throughout its pages.
|
| [1] https://nick-black.com/htp-notcurses.pdf
|
| [2] https://github.com/dankamongmen/notcurses#readme
| nothrowaways wrote:
| The domain name is hilarious
| leph wrote:
| While I was an economics student, I somehow landed a job to build
| out an elevator monitoring system at my college. Figured out that
| terminal emulators could connect to the elevator controller and
| that the output spec was called Wyse-60. My first "professional"
| program was written in Python using ncurses to parse the serial
| output [0].
|
| The program is very cringe but it was my best attempt at the time
| as I couldn't find any literature on terminal emulators (what
| actually happened was that I didn't know what to search for)
|
| Anyways, I've successfully pivoted my career away from economics
| and into software development which was the goal when I took the
| job in college.
|
| [0]: https://github.com/lee-pham/Pyse-60
| doctor_eval wrote:
| I used to use a white phosphor Wyse 60 as my daily driver. It
| was connected to a DG AViiON running DG/UX - most of the tools
| were GNU.
|
| Those were the days!
| doodpants wrote:
| One thing I've been wondering for a long time (and my Google-fu
| is apparently too weak to find on my own): how do certain console
| applications change the output color _without_ inserting ANSI
| escape sequences into the output stream? The specific case I have
| in mind is when writing console programs in C# /.NET, and using
| the System.Console.ForegroundColor property to vary output colors
| on the fly. The resulting output text does not have ANSI escape
| characters in it, yet the colors are displayed properly in the
| terminal.
| saulr wrote:
| On Linux, .NET does write ANSI escape sequences to stdout for
| you. ConsolePal.Unix.cs (Pal in this context referring to
| 'platform abstraction layer') does the work for you behind the
| scenes:
| https://github.com/dotnet/runtime/blob/10eb1a9ff1c09de4a2a1f...
| imsnif wrote:
| Personally I'm not a C#/.NET developer so wouldn't know where
| to look for the source code, but to check you can run the
| program in the examples of the post with the compiled binary on
| the other side (in place of the SHELL) and see what output you
| get.
|
| I'm 99% sure it's inserting ANSI escape codes (I'm maintaining
| a terminal emulator myself, and really that's how everything
| works), but I could of course be wrong.
| mattowen_uk wrote:
| WAY back in the DOS days Qbasic and command.com could both
| change foreground and background colours via system hooks
| (INT bios calls) without using ANSI. I know this because
| Qbasic console apps could be colourful without having to load
| ansi.sys in config.sys
|
| I am thinking that .foregroundColor and .backgroundColor do
| the same thing via legacy emulation in conhost.
| queuebert wrote:
| Turbo Pascal had a Crt library that did this.
| yardshop wrote:
| True, but you could also get the address of the screen
| buffer and define a structured type to overlayed it that
| allowed you to put values directly into memory.
|
| Each screen location was two bytes, one byte for the
| character value, and one for the character attributes
| which were a set of bits that controlled red, green, blue
| and intensity for both the foreground color and
| background color.
|
| Then you could write routines that would fill in a
| rectangular region with a color, scroll the text of a
| region up or down, and do all sorts of other windowy
| things. There were also interrupt routines you could call
| that did some of these, and certainly routines in Crt
| that did some of this. Then you were on your way to
| developing your own TUI library!
|
| Alternatively, you would issue an interrupt call to put
| the screen into 320x200 256 color mode, get the address
| of that buffer ($B800 if memory serves), similarly
| overlay it with a typed grid, then start poking byte
| values in and getting all sorts of nice colors out of it.
| Super fun!!
| imsnif wrote:
| This comment wins.
| JonathonW wrote:
| The Windows console is a bit more sophisticated than the
| traditional *nix "shuffle text back and forth" approach; the
| Windows Command Line blog goes into some detail here (and in
| the rest of this series):
| https://devblogs.microsoft.com/commandline/windows-
| command-l...
|
| Short version: there is support for ANSI and VT sequences in
| the Windows console (which relatively recently got
| substantially expanded), but that's not what it speaks
| "natively"-- for Win32 console applications, there's a native
| console API that works by passing IOCTLs back and forth
| between the app and console driver.
|
| (If you're writing a terminal emulator for Windows, you don't
| necessarily see this-- the new ConPTY mechanism you use to
| build these as of Windows 10 abstracts away the Windows
| specifics so you see text and VT sequences just as you would
| on *nix.)
| ensiferum wrote:
| Is this on Windows? If so Windows provides a typical Win32 type
| of HANDLE API for the console which can be used to change the
| properties of the console among other things.
| doodpants wrote:
| To clarify: .NET being cross platform, I write console apps
| that I run on both Windows and MacOS, and in both cases if I
| redirect the color output to a .txt file and open it in an
| editor, there are no ANSI escape sequences in the file. So I
| was wondering if there is some other standard for sending
| control codes to a terminal that is independent of the output
| stream.
|
| Or is there some voodoo by which the ANSI sequences get
| stripped from the output when redirected to a file?
| irishsultan wrote:
| > Or is there some voodoo by which the ANSI sequences get
| stripped from the output when redirected to a file?
|
| Not quite, but programs in general use some voodoo to
| detect when they are being redirected and won't output ANSI
| codes when they detect that.
|
| Often there will be a flag to enable/disable color, or let
| it detect when color is desired. On Linux ls accepts the
| --color=WHEN parameter, where WHEN can be always (`ls
| --color=always > ls-with-ansi-codes.txt` will output color
| codes), it can be never (just don't output ANSI codes, no
| matter whether you detect output redirection) or it can be
| auto (will show colors when you execute `ls --color=auto`
| but not when you do `ls --color=auto > ls-without-ansi-
| codes.txt`).
| imsnif wrote:
| They are sometimes stripped when redirecting. Maybe try
| executing it headless and reading the output?
| ninkendo wrote:
| Are you manually inserting the ANSI sequences into the
| stream? Or are you using a library that does this for you?
|
| Often times libraries that let you specify output color
| will helpfully query the capabilities of the output device,
| and avoid writing the control codes if it's (for example) a
| plain text file.
| yumaikas wrote:
| On windows, there are APIs for setting color that could be
| ignored if STDOUT isn't a terminal.
|
| On posix platforms, there's an API to check if a given file
| handle is a tty or not. https://github.com/corasaurus-
| hex/isatty/blob/main/isatty.c is an example of using the
| API, in a Janet context.
|
| I assume that .NET's support for Linux/macOS is using that
| API decide if it should strip color codes or not.
| ensiferum wrote:
| Well yes like I said on Windows you can access the terminal
| and set its properties without encoding terminal escape
| sequences in the output stream. On Linux afaik escape
| sequences are the only way. On MacOS i have no idea.
| Generally speaking the escape sequences aren't "standard"
| but different terminals (and these days terminal emulators)
| all have their own codes. Hence ncurses which tries to
| encapsulate this and provide a uniform API so that the
| application doesn't have to deal with these murky details.
|
| Have you double checked with s hex editor what is in the
| txt file? Suppose it could also be your text editor that
| doesn't want to render those codes.
| dekhn wrote:
| I absolutely love terminals. But, just about the time I could
| have learned curses, I switched to GUIs. Now I've switched back
| and uses curses to make UIs (so I can ssh into remote computers
| with low bandwidth and CPU). It's so funny how terminals are
| controlled and all the edge cases of each implementation.
| eatonphil wrote:
| Well done guide! Was visually enjoyable to read/watch as well as
| being well-written.
| timw4mail wrote:
| Why do I have to click a link to read the article? I don't
| understand why it's a thing to add a "fold" to a web article.
|
| More on topic, this does seem like a decent overview.
| Uberphallus wrote:
| Not a design/advertising guy, but often times I think it's to
| be able to display an ad at the bottom without the user to
| fully read the article, and without putting it ahead of the
| article (which is ugly IMO).
|
| Here though I don't think it's the case.
| imsnif wrote:
| There are no ads on my blog and will never be. That's a
| promise :)
| mongol wrote:
| That is why you are a poor dev :-)
| PaulHoule wrote:
| Ads on dev blogs pay peanuts, if that. It's a way to stay
| poor.
| imsnif wrote:
| Sorry about that! The SVGs are a bit on the heavy side and the
| various social preview crawlers didn't appreciate it.
| forrestthewoods wrote:
| I put my heavy blog content on BunnyCDN. It's impossibly
| cheap. I'm happy to pay a few quarters if a blog post happens
| to blow up.
| hwc wrote:
| Would a `<details>` block also work?
| ggerganov wrote:
| Hey, I really like the animated diagrams in your posts. Could
| you share a few tips about how you create them?
| imsnif wrote:
| Thanks! I use Inkscape to create the SVGs and then animate
| them with javascript and greensock. I still haven't quite
| found the right layer of abstraction for this, so it is a
| tedious process that takes a lot of time. Once I do, I
| might release a tool that will help with it.
| davemp wrote:
| Great article. Terminal emulators / shells are an area where we
| haven't seen much improvement for years. I can't help but think
| there could be a much nicer command-line-esque interface other
| than a classic psuedoterminal and shell. At the same time, I
| doubt any improvements could really be large enough to gain
| adoption.
| matheusmoreira wrote:
| Can terminals even be improved without breaking everything?
| Even maintenance work and fixing bugs has historically caused
| problems:
|
| https://lwn.net/Articles/343828/
| vidarh wrote:
| There have been _many_ attempts. Sixel and ReGIS being among
| the oldest attempt at augmenting terminals with graphics. But
| most modern apps that run in terminals don 't even push the
| limits of what terminals can do, and that makes it kind-of hard
| to justify putting effort into adding more capabilities to
| terminals.
|
| Part of the challenge is to find capabilities to add that are
| sufficiently simple and compelling to use in command line apps
| vs. as a web app or native GUI app that'd be more widely
| accessible than a new terminal capability.
| imsnif wrote:
| IMO the issue is not the capabilities of the terminal, but
| rather the culture around it. It is very often seen as a
| "leet" platform for hackers and advanced users. Its users
| looked at with respect and envy. Which is unhealthy for the
| kind of adoption one would wish for in their apps.
|
| Really, I think this mostly requires imagination from those
| of us developing for this platform. We have all the
| capabilities we need. We just need to create apps that don't
| require you to look up cheat sheets and man pages to use, and
| provide powerful alternatives to existing GUIs. There's a bit
| of a renaissance in this area as of late, but I feel this is
| just the beginning.
| lakecresva wrote:
| Could not agree more with this. Thanks for the interesting
| article and your work on zellij.
| vidarh wrote:
| I think we're looking for very different things.
|
| I use my own text editor. I expect to remain its only user,
| and that's fine. It's not intentional. It just isn't a
| priority for me to make it usable for anyone else (though I
| do separate out parts of it into libraries / gems as
| functionality matures).
|
| As such, I'm looking for improved terminals not to make
| things that doesn't require cheat sheets (because to use my
| editor you'd have to be comfortable with reading the
| source). It's fine that others want other things, but I
| think this is part of the challenge with improving
| terminals: A lot of the user base _are_ advanced users who
| want to improve their own workflows, not write something
| user friendly, and who wants tools that are easy to combine
| and chain, where the priority is not something user
| friendly.
|
| The balance is fine in that if you're looking for something
| particularly user friendly in the sense of friendly to less
| advanced users, targeting a GUI framework or the web is
| very quickly going to provide a better experience.
|
| EDIT: I saw zellij mentioned in a sibling, and looked at
| it, and incidentally it's quite similar to my setup, except
| I use bspwm and scripts to manipulate the tiling so that
| e.g. doing a vertical or horizontal split in my editor
| results in a new editor instance in a new tiled window
| rather than in a new pane in a single terminal. That way I
| can treat the few GUI apps I use exactly the same way
| (mostly Chrome). I'd love it if there was a standard API to
| split panes and start apps in a given pane, so both
| terminal multiplexers and tiling wms could be targeted with
| a single standard mechanism.
| imsnif wrote:
| I agree that's how things are today. I get where you're
| coming from and I'm certainly not trying to take this
| away from you.
|
| My experience has taught me that tools become better the
| more people use them and are able to participate in their
| creation and maintenance. The more user friendly a tool
| is, the more users you'll have. Personally, I think a
| tool can be very user friendly and still powerful enough
| for advanced users.
|
| I used a very similar setup to yours before I started
| Zellij! The reason I started the project was in order to
| be able to formalize such a setup (for me it was
| implemented as a soup of bash scripts which I dreaded
| moving to another machine, not to mention handing to
| another user).
|
| One of the things we want to do with Zellij is port it to
| the web and maybe even in the future to use it as a sort
| of "backend" to power tiling window managers. I'd be
| totally open to do this in a standardized way if
| maintainers of other tiling managers are game.
| vidarh wrote:
| > My experience has taught me that tools become better
| the more people use them and are able to participate in
| their creation and maintenance. The more user friendly a
| tool is, the more users you'll have. Personally, I think
| a tool can be very user friendly and still powerful
| enough for advanced users.
|
| I've taken the approach that rather than try to shoehorn
| my use into a full app, I aim for my text editor to be as
| small as possible, by reusing external tools whenever
| possible, as I do agree with you that it's worthwhile to
| have as much as possible of the code used by other
| people. But at the same time I realised there are editors
| smaller than my old Emacs config. So e.g. my editor
| relies on bspwm to split panes, and on rofi (or anything
| that can take a list of things to choose from and return
| the chosen thing) to select files or themes or buffers,
| Rouge for syntax highlighting, and anything that I can
| make generic enough I'm splitting into gems (the editor
| itself is written in Ruby). The way I see it, I want the
| editor to be a tiny little core that's mostly configuring
| other components. Currently it's about ~2.6kloc, but much
| of that is code that can be split out or will disappear
| as I clean some things up. I don't want it to get much
| bigger than that - preferably it'll get smaller.
|
| > I used a very similar setup to yours before I started
| Zellij! The reason I started the project was in order to
| be able to formalize such a setup (for me it was
| implemented as a soup of bash scripts which I dreaded
| moving to another machine, not to mention handing to
| another user).
|
| The big limiting factor for me with something like Zellij
| over my current setup would be having it work alongside
| e.g. Chrome and the occasional other gui app.
|
| > One of the things we want to do with Zellij is port it
| to the web and maybe even in the future to use it as a
| sort of "backend" to power tiling window managers. I'd be
| totally open to do this in a standardized way if
| maintainers of other tiling managers are game.
|
| If you provide a mechanism that allows a client to split
| panes already, then maybe the easiest starting point is
| for someone to just pick a config location/format tools
| can look for a command line to do splits in. E.g. on
| bspwm, the command given to split horizontally might
| simply be sh -c 'bspc node -p east ; exec #{cmd}' &. On
| i3wm, the same would be i3-msg 'split horizontal; exec
| #{cmd}'. Currently my editor just blindly executes
| "split-horizontal re --buffer numeric-id-of-the-buffer",
| and I have a "split-horizontal" script in my ~/bin. It'd
| be trivial enough to have it read a config file to find
| out what command to execute instead.
| 0235005 wrote:
| I think that for sure something line the Plan9 shell woukd be
| something cooler to have
| MisterTea wrote:
| As in graphics in the terminal? The way that works is through
| the draw(3) kernel device which is a 2d engine with an rpc
| interface. You load text and bitmaps into the draw device and
| then issue rendering commands. The kernel terminal device,
| cons(3) is where the terminal text is written to and cons
| sends that to to draw. When you start a graphical program, it
| overwrites the window graphics from cons(3) until the
| graphical program exits or the window deleted. There is no in
| band cursor control in plan 9 as it is a graphics oriented
| OS.
|
| So its not just porting a terminal. It's the entire OS. Of
| course there is p9p, plan 9 port, which is a port of the core
| plan 9 user space tools to Unix systems. It does offer a draw
| server that can be mounted.
| vidarh wrote:
| A lot of terminals supports at least somewhat similar
| functionality via Sixel (bitmaps) and ReGIS (vector
| graphics). It's limited and certainly could be improved a
| lot, though.
| uuddlrlr wrote:
| TempleOS comes to mind.
| imsnif wrote:
| I totally agree. I'm actively working in that direction.
| 0xdky wrote:
| Very well written article, thank you.
|
| Especially when my daughter is taking a course on Unix and the
| instructor is superficially touching in these fundamental topics
| (due to their own limited understanding), I am going to use this
| to teach the underlying concepts.
| hawski wrote:
| I recommend going through st source:
| https://git.suckless.org/st/file/st.c.html
|
| I may have fallen out of love to suckless.org, but the code is
| usually simple so one can at least learn from it.
| matheusmoreira wrote:
| I recommend it as well. It's the simplest terminal emulator
| I've found, other projects I've explored were a lot more
| complex.
| dudik wrote:
| Why have you fallen out of love to suckless? I recently
| switched from dwm back to bspwm and I was also looking for a st
| replacement, but couldn't find one. Which is ok, but were you
| able to find something "better" in the terminal emulator or
| window manager space?
| hawski wrote:
| I wanted/tried to be a part of the community. I could say I
| was not a cultural fit.
|
| As much as I sympathize with cutting things down and making
| frugal software I am too messy to make it all work for my
| advantage. I now prefer to mix and match and not attaching
| myself to any group. But I am fond of the actual code. It is
| refreshingly simple and easy to track. I was using dwm the
| most from all of the projects and I still think of going back
| to it. Though currently I'm getting tired of software all
| together.
___________________________________________________________________
(page generated 2021-11-02 23:00 UTC)