Ncurses has always been on my list of cool things I wanted to learn but couldn't invest the time to actually build something with.
Then I found Textual (Python library, https://textual.textualize.io/) which feels like its modern and prettier child. Not gonna lie, it's still not a turnkey solution that transformed my clumsy scripts into a beautiful TUI without work but it's close!
> Not gonna lie, it's still not a turnkey solution that transformed my clumsy scripts into a beautiful TUI without work but it's close!
Can you elaborate on that? Are your "clumsy scripts" written in Python, shell or another language? Have you tried Textual-based tools like Trogon [1] and Moulti? [2]
Rereading myself it looks like I'm blaming Textual for being too much work to use but it's not the case! I wanted to say that powerful (T)UIs have inherent complexity coming with the territory: async, events, UI thread, reactivity, render frames, debugging... Works great, but it's UI work on top of the script.
Speaking from experiences, it's kind of amazing how much work you have to do in order to talk to a modern VGA or xterm terminal using ncurses. You really feel each layer of crust that ncurses has accumulated over the entire history of the personal computer since it was first written in order to allow people to play rogue on their personal VT-100 terminals.
Tunneling through the layer of crust accumulated in order to support Unicode (several layers of crust as Unicode evolved) was probably the most interesting of all.
Generating ANSI escape sequences to program a display is significantly more clunky than just directly addressing the text framebuffer that existed in early PCs (and often still does, albeit emulated by the GPU). You have an 80x25 array of words. Low word is the ASCII character, high word’s low nibble the foreground colour, high nibble the background. Character set is fixed to CP437 which had a reasonable choice of graphics, math symbol, and other characters.
A competent programmer could fit the whole charset in their head and easily write a TUI from scratch in a day. But they didn’t need to: plenty of great libraries existed.
It's stranger than that. The Linux terminal runs VGA adapters in an EGA mode that is rarely if ever used in DOS/WIndows systems. The mode provides up to 512 characters. One of the high-byte bits if each word is sacrificed to select from the first or second set of 256 characters; and another is sacrificed to specify underline on or off. That leaves 8 foreground and background colors, instead of the 16 foreground and background characters that you would get on a PC. Linux doesn't appear to have any concept of code-page. Which characters can be displayed on the terminal depends entirely on which EGA font is loaded. And that is determined (by default) by the currently configured locale, although the choice of font can be manually overridden. Having 512 characters to choose from allows the Linux VGA terminal to include a superset of characters that would be provided in a DOS/Windows codepage, while also guaranteeing at least the single-line line-drawing characters in CP437.There are, for example, fonts that allow display of glyphs in all Eastern European codepages, and fonts that provide a superset of European codepages and Cyrillic.
ncurses renders to an underlying framebuffer which contains 32-bit Unicode characters, plus attributes (FG/BG color pair, and 8 additional attributes like underline, bold, blink). I'm not sure which layer of crust this framebuffer belongs to -- something related to TERMINFO, I think. The intermediate framebuffer is then rendered to the actual VGA framebuffer in a separate pass, which maps 32-bit unicode characters onto glyph indexes in the currently-loaded VGA font.
There are some provisions for Asian character sets (Vietnamese, for example, is plausibly supported). I'm not sure if Chinese or Japanese VGA terminals were ever adequately supported in Linux.
One thing that made an impression on me when reading the 1991 Blue Book About GW-BASIC (1991) earlier this year was the chapter on making a text-mode user interface, that recommended drawing a characters+attributes interface 80x25 using an external editor, save that as a raw 4 kB file, and then from the BASIC program just BLOAD the file straight into graphics memory to render the screen in one line.
Everything is so much easier when you have standardized hardware instead of layers upon layers of abstractions supporting all sorts of weird things, like we have to put up with this century.
It is, of course, a very simple system if you never plan to render anything that isn't an ASCII character, or a value in US dollars. Things get complicated pretty quickly in DOS/Windows world once you wander outside the ASCII character set range. And there are strange and wonderful things in EGA and VGA hardware (standard, non-standard, and outright genius-level hackery) that are ridiculously complicated that are hardly ever used if you are fortunate enough to be an American who never uses anything but DOS.
Turbo TUIs were easy to make. You could make them asynchronous, non-blocking, include sound, and if you were using Borland's C compiler, all of that was built-in for you.
They probably went to efforts to make it work an ancient system. But you really didn't have to.
I’ve happily used python-dialog, a wrapper for dialog (and dialog-compatible alternatives) which provides the very basics but is extremely easy to work with.
Always thought of (N)curses as the conceptual React framework for terminal applications. You tell it what the screen should look like and it figures out how to efficiently write just the changes needed to achieve that on the terminal.
I always liked that on SuSE, I had my choice with YaST of either the Ncurses interface or the GUI X Window System. The functionality was identical, but sometimes a GUI is pleasant.
This is rather timely—I started playing with PDCurses after being inspired by Zed Shaw’s “Rogue is the Best Project”. It has been an interesting experience
I mentally bin TUI applications in the same category as 2D video games.
Not all of them are good, but there are way better chances that I like it than the 'other one' (3D game / GUI).
I think the reasons are similar. When you don't have to focus so hard on what it should look like you spend more time on whether it is a pleasure to use.
This is a great comment. I still reminisce about some rock solid TUI apps because they were extremely user friendly and productive.
The moment the GUI came along and the mouse became part of the picture, plus the focus on looking pretty, effective interactions went out the window.
Ages ago on a mini I use to program, there was a very simple library I could call to format a screen. You told it modifiable field type and its text plus position on the screen. The screen was fixed at 80x24 plus no popups.
I wish there was a simple wrapper for curses like that :)
In the DOS Days, zortech c had a nice set of functions for screen input, disp_*, those were easy for my simple mind to understand to.
I always love the look of a well laid out TUI. In uni there were color IBM terminals everywhere and that bright, colorful UI is burned into my mind.
What I would like is a (n)curses library that uses a graphics back end instead of a TTY, preferably written in Go. I want a GTUI (Graphical-Text User Interface 8-)
Side note, Anyone know a site that curates a list of TUI designs? And not just good ones but examples of bad and weird.
I remember writing something a few decades ago using NCurses. I don't even remember what the program was, but I remember having to go back and forth tweaking the window sizes to make things fit together and look right.
With short code snippets, you arguably don’t need a license. Only if it’s notable enough to get copyright protection do you need permission to use it, right? I can copy hello world examples from websites and do whatever I want with them, I think.
I don't necessarily disagree (I am not a lawyer), my point is that reading an AGPL license at the bottom of the page can only be a good thing; it can only give you the ability to do more things than you could if had no notice been there.
Esc is a single byte which is the prefix for multi-byte escape sequences.
Bytes arrive serially, one at a time, one after another.
There is no predictable garanteed time between bytes. Any two bytes in the stream may arrive with any amount of time between them, 1 ns, 1s, 1 hour, 1 week...
So anything that reads the bytes must have some sort of timeout whereby on seeing an esc, it waits up to some time for the rest of the escape sequence before giving up and treating the esc as a lone byte or a byte that was not lone but not not part of an escape sequence either. IE, no recognized termcap code ending with ";" etc. During that time it may be either waiting while no bytes are coming in, or it may be collecting bytes that haven't yet added up to some known terminal control code.
Normally even a very long valid escape sequence would all come in a fraction of a second, and so you'd think a tiny timeout like 0.1 second would be fine, but there are such things as far slower baud rates, and even if your immediate terminal has an infinite baud rate, some link in the unknown chain to your terminal could be any other speed, and there can be unpredictable pauses in otherwise fast baud rates. Even on the modern internet the timeout needs to account for some router hiccough anywhere in the 1000 miles between the source & your terminal.
Most apps that want to use esc as a direct "normal" key need to either use raw mode if that's even an option, or make the user type "esc-esc" instead of just "esc", and because of that, they just shouldn;t even be trying to do that in the first place, they should know better. It's not a good key to use for "abort" or anything else unless your environment is windows or dos.
LOL, now that you mentioned it, terminals have been always.. difficult (to avoid saying retarded again) with delete and backspace and i have no idea why :D
these days it's not so bad (probably because mainly working with linux these days), but when i was younger and working with different Unices, getting terminal to work properly involved lot of effort and internal screaming "Y U no work!"
I don't have a link. Basically only a problem when sshing (or telent, or serial) between linux and any of the older unixes and somewhat to current freebsd.
The break key is not really a terminal function, it's a tty control code, displayed and set by th stty command. It must be a single byte. It can be set to basically any value, but can only be a single byte.
On linux, both the console which is TERM=linux and most gui xterm-alikes which are mostly TERM=xterm-something, both of which are somewhat similar to vt220:
break aka stty intr is 0x03 (^C),
backspace aka stty erase is 0x7f (^?),
and the Del key emits a multi-byte sequence 0x1b5b337e (^[[3~ aka esc[3~)
On sco:
break / stty intr is ^?
backspace is ^H
the Del key emits ^?
hardly anyone will have to worry about a sco box these days but the freebsd console is almost identical to scoansi, though I don't remeber what the default stty settings are, and a freebsd box will at least have the same definition of xterm as everyone else. but "xterm" on a sco box has entirely different codes for the F-keys and I think some other stuff like colors and line-drawing, and the stty defaults are the same as for the console.
When sshing in either direction between the two systems, unless you install good terminal definitions for each terminal in the other systems termcap & terminfo, AND, add code to .profile to change stty settings based on the detected $TERM on login, you end up with super annoying things where in one direction pressing backspace blows away whatever you were doing because it's like pressing Ctrl-C, or in the other direction backspace does nothing or prints a visible "^H" or something, but pressing Del acts like backspace.
As a service provider moving users from sco hosts to linux, the users have been pressing Del for 10 to 15 years (20 years ago now), but a linux terminal emulator does not emit a single byte from it's Del key. The Del key CAN NOT be assigned to be the break key because it emits a multi-byte sequence not a single byte.
All fine for most users because they can use a terminal emulator that emulates scoansi instead of linux or xterm etc, and so for the bulk of normal users it's possible to make everything exactly the same, no change with the move to linux.
But the console can not be made to emulate the sco console without such dirty hacks that I just refuse to do it. I lie and say it's not possible.
And usually the business owner would use the console so it needs to behave the same as all the other terminals. None of these people are IT people. They don't ever actually see the bash prompt, just login directly to an application. They are like cashiers before barcodes who get real fast with muscle memory blazing through menus and screens without even looking, and so there can be no mix of different terminals with different rules and different keystrokes etc, and you can't be changing that single button Del for break that they press a zillion times an hour to some two button hot key like Ctrl-C.
No one hits any of this today because there is mostly no such thing as a regular user that logs in to a terminal at all, and those few that do access shells get the same xterm pretty much everywhere and there almost isn't any such thing as a console any more.
Then I found Textual (Python library, https://textual.textualize.io/) which feels like its modern and prettier child. Not gonna lie, it's still not a turnkey solution that transformed my clumsy scripts into a beautiful TUI without work but it's close!