return to table of content

Things I've learned building a modern TUI Framework (2022)

traverseda
19 replies
1d4h

My big complaint with textual is that it wants to be react. I can see why it would want to be react, that's a very popular framework that a lot of people are already familiar with, but I don't think it's actually a good way of doing user interfaces. But the basic reactive design is a well trod road, and basing your system design on something that's known to work is a great way to derisk the project. Sure, we'll draw some heavy inspiration from react.

Alright, so we're using some bastardization of CSS as well? That might be going a little bit too far. The react model already breaks the idea of CSS in a lot of ways, preferring standardized components. Sure, developers still use CSS to customize components, but I view that more as a side effect of how react evolved rather than as a justifiable architectural choice. But as long as you don't have to use CSS I suppose it's fine.

Last I tried it, you do have to use CSS. There are no good standard components, so you will be making your own, and instead of having components be one nice self encapsulated Python class the standard docs use things like list components and then style them with an external style sheet.

For those reasons textual just isn't for me yet. In python there should be one, and preferably only one, obvious way to do something. By mirroring react so closely they're also mirroring what I see as the JavaScript communities biggest vice.

itronitron
7 replies
1d3h

Can you elaborate on how textual wants to be like the react framework? I don't see React (or react) mentioned anywhere in the article.

willm
4 replies
1d2h

They have a virtual DoM https://textual.textualize.io/api/dom_node/

It's not a virtual DOM. It's not technically even a DOM, because there is no Document. The name has stuck, which is why we went with that. Technically, its a tree. One of the most common data structures used to represent a UI, and predates React by decades.

This includes a lot of what you'd expect from HTML, classes, CSS, etc.

It has CSS in common with HTML. classes are pretty much required for CSS. That's not "a lot". But why shouldn't a UI framework borrow concepts that work for, you know, User Interfaces?

They have reactive attributes https://textual.textualize.io/guide/reactivity/

Reactives attributes are very useful concept to manage UI complexity. And again, not exclusive to React.

kragen
3 replies
1d1h

this sounds like you're elaborating on why textual wants to be react rather than rebutting the assertion that textual wants to be react. but nobody was saying that wanting to be react was unreasonable

hmm, well, i guess traverseda was sort of saying that react was bad. i doubt that's a widely shared opinion tho

willm
2 replies
1d

I only meant to rebut the factual claims made in the previous comment. Textual is inspired by web development (and I've always described it as such), but "want to be react" is way overblown. It has things in common with React, but equally many other web and UI frameworks. Heck you could say that Textual wants to be JQuery, and that would be just as apt...

yunohn
0 replies
1d

How is it more like jQuery than React?

kragen
0 replies
1d

maybe it depends on what the implicit reference class is. if you're comparing it to react, angular, ncurses, s-lang, jquery, vue.js, and php, then sure, things like html and css are hardly react-specific. if you're comparing it to ncurses, s-lang, win32, mfc, the vic in the commodore 64, winforms, whiptail, dear imgui, the tms9918 used in the msx, emacs lisp markers and text properties, gtk, the nintendo ppu, opengl and glut, xlib, xt, tcl/tk, ansi.sys, naplps, ripscrip, turbovision, direct access menu.exe, and react, it's basically exactly the same thing as react

jesus, i sure have built shitty user interfaces on a lot of platforms

itronitron
0 replies
1d

Thanks, it seems like people tend to say react, or reactive attributes, when they are describing model-view-controller (MVC) patterns.

nine_k
3 replies
22h44m

If you think that react (and FRP in general) is not a good way to build UIs, what is, in your opinion?

sesm
2 replies
21h46m

I don't agree that React is FRP. FRP is a generic solution that builds data-UI synchronization around data, and assumes that incremental UI updates will be written in UI code. React puts data-UI synchronization code inside UI components and provides an Immediate Mode-like API to avoid writing incremental updates in UI code.

srcreigh
1 replies
18h34m

In your world, the incremental UI code lives in the react library, and react applications aren’t UI code, they’re just FRP data transformations.

sesm
0 replies
9h10m

React components are clearly not FRP data transformations, they don't have any notion of data flows, observable/computed values, etc.

actionfromafar
3 replies
1d

I want a way to embed a terminal (it doesn't have to support a myriad terminal emulations, only one) inside a graphical program. MacOS first, but other platforms would be nice.

So, imagine a normal GUI window, but one of the components in it is a terminal window. Is there something like that?

Or should I just use mono font text view?

joerick
0 replies
2h20m

I've used xterm.js for this, but I was already in a webview. It's pretty good, might even be worth the webview for https://github.com/xtermjs/xterm.js Used by vscode among others

ho_schi
0 replies
11h46m

GNOMEs Gtk has a companion library named libvte which provides the terminal as widget. It is used by Gnome-Terminal (and many other terminals) itself and now supports Gtk4:

https://gitlab.gnome.org/GNOME/vte

Basically its usage starts with vte_terminal_new().

Unicode? Emojis? https://gitlab.gnome.org/GNOME/vte/-/blob/master/doc/ambiguo...

What hurts me? The only thing which hurts me is that the maintainer doesn’t like background transparency in the official terminal application. The library supports it and many terminals use it. But this is another topic. With an embedded terminal you will likely not use that feature ;)

PS: KDE likely has a smiliar solution within Qt. As you named portability either Gtk or Qt are you tools. The biggest hurdle is shipping the libraries on macOS. On Linux it is done automatically. Windows is rather easy. Regarding Gtk, ship the gdk-pixbuf loaders alongside, they are loaded at runtime via dlopen(). The small differences hurt during porting.

aatd86
0 replies
5h1m

People probably simply emulate a terminal window and execute the commands via the OS APIs (syscalls). This is unlikely to be truly "embedding".

willm
1 replies
1d2h

Last I tried it, you do have to use CSS.

You don't have to use CSS (actually you never did). Every style can be set in code, and the docs have CSS + Python equivalent for every style.

There are no good standard components

I guess its been a while since you checked https://textual.textualize.io/widget_gallery/

traverseda
0 replies
21h47m

Yeah, it does seem like things have changed a lot since I last used it, which I think was probably a few years ago. Time flies.

yoavm
0 replies
23h30m

I don't see how it is trying to be React; It definitely tries to use concepts from HTML and CSS (and perhaps even some JS?), but I actually found that it allowed me to move very quickly as I didn't need to learn a whole new UI system from scratch. I didn't need to create any component of my own, and CSS is something I already know. If anything, like I wrote in another comment, the slight layout differences and deviation from CSS is what sometimes got me a little confused.

mikkelam
16 replies
1d1h

Why do software engineers care so much about TUI? I really don't get it. I love a good command line program. But TUI just doesn't appeal to me.

squigz
3 replies
14h23m

Because I don't need a resource-heavy GUI for something as simple as a music player.

zokier
2 replies
11h47m

GUI is not intrinsically any more resource-heavy than TUI; ultimately you need to render stuff on screen somehow and get user input, and going through tty layer just is extra bloat.

squigz
0 replies
6h2m

GUI is not intrinsically any more resource-heavy than TUI

Okay well, maybe you should tell that to the GUI developers :P

creesch
0 replies
9h32m

It isn't extra bloat when you are already using that layer for other things and also doesn't require any extra packages or connections on your side of things.

Specifically when dealing with remote environments where you connect to through ssh anyway it is really awesome when some things can be done through a nice TUI. In that context a GUI would actually be more resource heavy considering that it likely will be web based with much more client side processing happening for the GUI.

pjmlp
3 replies
1d1h

I guess, mainly because of nostalgia, back from the days TUIs were the only way to interact with computers.

Turbo Vision, curses and dialog were cool back in the 1990's.

Having started with computers in 1986, I really don't get the TUI fetisch, not even remote access is an issue, given X Windows, VNC, RDP, Citrix,... exist for decades.

nine_k
1 replies
22h38m

Having run X programs over network connections quite a bit, I'd say that they make sense for graphics stuff, and textual interfaces over SSH are significantly more responsive.

But once a fixed-width text grid stops being the right tool for the job, it's likely better to have a web UI.

pjmlp
0 replies
22h17m

I used xterm for such purposes.

Yes, I do agree the browser is the new X Windows / RDP client, on the modern timesharing systems.

consteval
0 replies
4h34m

X Windows, VNC, RDP, Citrix,... exist for decades.

Yeah but those are all awful. I mean, okay, they work almost okay with a wired network connection and on the same network.

But as soon as you hit the WAN and you throw wifi in there it's painful. Having noticeable latency and graphical artifacts does, in my opinion, hurt productivity. For those pieces of software where completing tasks as fast and accurately as possible is the most important goal, TUIs are great. Especially when you have comprehensive keyboard shortcuts. If you've ever seen an office worker rip through a TUI underwriting a loan, you'll know what I mean.

electroly
1 replies
21h4m

There isn't much obvious benefit in using TUIs, but writing TUIs has a big upside: it's easier in most ways. It's trivially cross-platform, you don't have to make pixel-perfect GUIs (because it's impossible), you don't need icons or graphics (because you can't show graphics), etc.

ofseed
0 replies
10h33m

That's the main reason. TUI programs can be created quickly, and they're mostly developer-oriented, so they just need to be useful enough and don't need to be optimized as much as a GUI program.

wpm
0 replies
10h44m

I like TUIs because they are usually the exact opposite of the large range of UX fashions that absolutely suck, and have infected every other GUI app and website I use. The terminal is a breath of fresh “I’m not going to treat you like a moron” “more is more” “you’ll know if it’s a button” high contrast air.

willm
0 replies
1d1h

Each to their own. But running apps over SSH is a big plus. And some folk, like myself, enjoy the snappy keyboards focused experience that perhaps GUI apps could offer, but typically don't.

sam1r
0 replies
17h43m

Because you may have no issue using browsers with extended batteries + features.

How about displaying data on cli w/ textualize vs on an admin web interface.

I find it much easier + direct to use some py-orm w/ textualize.

On an admin interface you’d have to worry about auth + some js ui framework that prints your custom html directives to tables… that eventually display text.

habitue
0 replies
23h27m

It's the other ubiquitously installed cross-platform GUI toolkit other than the web.

Additionally, it has a hacker aesthetic. The styling is aggressively not separated from the content, and the styling knobs are pretty limited, so tui apps kind of converge on a single style. That style reminds us of hacker movies and cool sci-fi shit :)

It's not loved by corporate designers. Companies don't make sales based on their TUIs (to either businesses or consumers). So without those commercial pressures, tuis are designed by developers for developers.

Because of this, the meme of tuis self-reinforces. Developers see and use TUIs, notice that they are usually tools built with developers in mind, and then want to go on to make their own TUIs.

fastasucan
0 replies
1d

Its great for running things in a terminal where you want more of a user interface than a CLI. Sometimes a TUI is faster and gives better oversight than a CLI.

citrin_ru
0 replies
7h41m

I use CLI heavily but some tasks GUI suits better and TUI is a middle ground between GUI and CLI - you can continue using your terminal emulator with you favorite font but have a GUI like interface. Also all TUI applications I've used have low response time. Most GUI apps are also has fast interface (most of the time) but all frustratingly slow apps I've used were GUI apps.

rivo
13 replies
1d3h

It's funny how every TUI developer eventually stumbles over Unicode and then handling international characters and emojis correctly turns into its own project close to the same scope of (or even bigger than) the original TUI project. It happened to me on rivo/tview and through the resulting rivo/uniseg package, I learned that all other TUI library maintainers deal with the same issues. Finally, everyone invents their own unique solutions to the problem because character width is not standardized and terminals are messy, as noted in the article. OP simply supports Unicode 9 only (Unicode is at version 15.1 at the moment). Sooner or later, users will complain, however, that certain emojis or international characters are not rendered correctly. So I'm not sure that this is a great solution.

rockorager
7 replies
1d

The state of the art here is to detect mode 2027, and enable it when supported. This lets you know the terminal will handle graphemes properly.

I maintain two TUI libraries which use this technique and emoji support has been (nearly) great. (One of which uses your uniseg library!)

https://mitchellh.com/writing/grapheme-clusters-in-terminals

sweeter
2 replies
23h46m

really great read, thanks. Im a little disappointed that no terminal emulator both implements the Kitty image protocol, and mode 2027. I wish there would be a terminal project that would just pick the best standards we have at the moment. Im not a fan of sixel for a lot of reasons. Im looking forward to trying Ghostty, though.

rockorager
0 replies
23h29m

Ghostty has both mode 2027 and kitty image protocol

eNV25
0 replies
21h7m

wezterm has both according to the above article

Joker_vD
2 replies
18h11m

I personally don't think this mode is all that very useful, to be fair. First of all, the grapheme clustering is not set in stone, it's been changed from one Unicode standard version to other.

Second, and this is mostly because my personal use cases are very humble, a much, much simple to implement workaround, for everyone involved, would be a couple of OSC sequences which would mark a part of output text as the prompt (when terminal is in canonical/cooked mode), so that a huge chunk of readline could be simply thrown away.

So your program could just print a prompt, and then simply read the cooked line. In the meanwhile, the terminal emulator would handle line editing, line-wrapping and asynchronous output: if you keep outputing text to the terminal while a prompt is active, the terminal would clear the prompt and the unfinished line, print the text, then re-display the prompt and the line; basically what all "async readline" libraries do already with rl_clear/rl_redisplay — but doing it in the terminal would take care of this properly, because the terminal definitely knows how wide all the symbols it itself thinks are. And the tab completion could be supported by returning a <TAB>-terminated line to the program, instead of an <LF>-terminated line.

Unfortunately, I don't think something like this can actually become even moderately widely adopted.

Edit: Or, you know, maybe we could extend terminfo? Like, introduce twcswidth() function that would take your string, and the somehow encoded Unicode grapheme clustering data that the current terminal is actually using which you can query from terminfo, and return the number of screen cells it would take on this terminal.

ori_b
1 replies
16h17m

At this point, why not just write a graphical program?

Joker_vD
0 replies
14h29m

Unfortunately, servers are usually configured without X forwarding enabled. And the functionality I am describing already exists for terminal-based programs, it's been reimplemented multiple times — see e.g. [0][1], it's just implemented with horrible hackery (by manually driving terminal, processing raw input and counting how much lines of text the terminal screen is probably displaying right now).

I just want to, e.g. write a simple Python program that has

    for line in streaming_response.lines():
        print(line)
in one thread, and

    while True:
        cmd = input('> ').strip()
        if cmd == 'q':
             break
        if cmd == 'stop':
             requests.post(...)
        ...
in another, and be able to input my commands without the echo of my input being teared up by the output. Erlang's shell can do that. Readline can be used to do that, but Python's bindings don't export the needed functions. Swapping out the sys.stdout/sys.stdin with my custom interceptors to do this manually... barely works, slow, ugly as hell and complicated.

[0] https://github.com/thejoshwolfe/consoline

[1] https://github.com/erlang/otp/blob/90a48ae2bff26d5df67ceaa7e...

kevin_thibedeau
0 replies
17h25m

That isn't sufficient. Codepoints with ambiguous width can't be detected in a standard way. A large number of pre-emoji symbols have been upgraded to have emoji presentation. Some systems default them to emojis with wide rendering, others maintain the text presentation with narrow rendering. Many systems ignore the presentation selectors if you want to force it.

roland35
4 replies
1d2h

Are there any libraries in place which can normalize all emojis down to a single symbol?

kevindamm
1 replies
1d1h

It's a design decision. On one end, if I'm reading your question correctly, you could use 0xFFFD (the replacement character) for anything not recognized as language-specific characters in the BMP and SMPs (this can be done within practically all existing Unicode libraries by filtering on character class) which will inadvertantly filter some non-emoji symbols and doesn't really convey any information (it can even look unprofessional, it reminds me a lot of the early web during the pre-unicode growing pains of poorly implemented i18n/l11n).

There are libraries like Unidecode[0py] [0go] [0js] which convert from unicode to ASCII text that might be easiest to include in a TUI. All the ones I looked at will convert emoji to `[?]` but many other characters are converted to that, too, including unknowns.

On the other end you can keep a running list of what you mean by emoji[1] and pattern match on those characters, then substitute for a representative emoji. But it will still pose some difficulty around what to choose for the representative symbol and how to make it fit nicely within a TUI. An example of a library for pattern-matching on emoji is emoji-test-regex-pattern[2] but you can see it is based on a txt file that needs to be updated to correspond with additions to Unicode.

[0py]: https://github.com/avian2/unidecode

[0go]: (actually there are a few of these) https://pkg.go.dev/github.com/gosimple/unidecode

[0js]: https://github.com/xen0n/jsunidecode

[1]: these aren't really contiguous ranges, and opinions vary, see https://en.m.wikipedia.org/wiki/Emoji#Unicode_blocks

[2]: https://github.com/mathiasbynens/emoji-test-regex-pattern

estebank
0 replies
1d

There's a "trick" that works somewhat well for some compound emoji like "family": replace ZWJs with whitespace. Emoji width is not standardized because it depends on platform, fonts available, shell and terminal emulator, but almost no terminal supports compound emoji correctly. Because of how they were designed, most terminals will print the emoji as its component parts. If you need to do something like underline a piece of text (like rustc has to) we decompose them ourselves, and then it is a more tractable problem to know what the width of a char is (0, 1 or 2, and var width for tabs, which we just transform to a hardcoded 4—incorrect but usable). This can still be incorrect, on specific terminals, but works well enough on most.

Joker_vD
1 replies
18h39m

It doesn't matter; what matters is that both your (terminal-manipulating) program and terminal emulator agree on the symbols widths. Considering that they usually won't (lots of terminal emulators have their own hand-crafted, statically linked wcwidth/wcswidth functions; the readline library also has them hard-coded, by the way), it's quite frustrating.

ku1ik
0 replies
9h29m

This.

bogdan-lab
9 replies
1d1h

This TUI looks pretty, but I cannot imagine situation, when I would actually use it and be ready to pay for it. Probably I am not living in a right environment for it. But in my experience, either people are happy with something truly minimalistic or they try to please a user with GUI right away.

For example, YouTube link in the article showed a possibility to display table with highlighting cells. Why would I need that as TUI? Probably if I want to navigate through table with highlighting active cell I would also need a bunch of other stuff and eventually I would need a proper GUI.

mrweasel
2 replies
1d1h

It does seems niche at this point. One scenario I can see is where you want something more user friendly than pure CLI and where providing a web UI might be too risky for some reason. A TUI could allow users to SSH in to server somewhere and just have TUI app as their shell. It's a bit contrived I grant you that.

Personally I found Textual a little weird to use, but better than ncurses. Though it didn't really yield what I wanted. I like the old mainframe style TUI application, those already struck me as being wildly efficient.

justinclift
1 replies
17h9m

Personally I found Textual a little weird to use, but better than ncurses.

Out of curiosity, have you looked at it's sibling project "rich"?

https://github.com/Textualize/rich

Seems like it provides a TUI toolkit as well, and it looks a bit less weird than the approach Textual uses.

Was thinking of trying it out with a side project recently, but got pulled onto some other stuff instead so haven't yet started. Nor made the choice between them. ;)

seeknotfind
1 replies
1d1h

One reason to prefer textual UIs is that you can use them from any computer anywhere fast (no slow video VNC). Also, if you are already using a terminal, then improving that experience is nice. There is a big enough market there for this company.

However, I'm not sure what a "proper" GUI is. Terminals have a widely used open standard. These protocols are more standard and interoperable than any GUI framework, and they are supported on every system. Once you add video in there, close a few more gaps, I think competing with the browser, or bringing the full computer experience to the terminal is reasonable.

Obviously if terminals add something like video, it's "copying" rendering pipelines from "proper" GUIs, but making the terminal experience better, which could also be viewed as bringing UNIX zen to GUIs, if it makes it big, you'll love it too! <3

sam1r
0 replies
17h54m

Or what if you just prefer to not use a browser to get your information on the internet. Textualize is like the only choice I can jump to.

It’s much better to hyperlink and open image and video in the browser from the terminal. In my opinion. Playing it would just block your terminal session, so it’s pretty annoying to have to open another tab with an inline video playing. I am happy with the features with textualize and haven’t even thought about needing things that play over a duration beyond a few seconds.

Textualize then becomes the browser api that I build my terminal browser and render only the components I care about.

None of that background or js libraries, ads. It’s well worth it.

justinclift
1 replies
17h14m

Proper GUI's are nice and all, until you need to do the same thing over an ssh connection.

Sometimes that works ok (ie forwarding X on a high bandwidth connection), but other times the proper GUI acts like a complete pig. :(

A text based GUI sounds like it might be the best of both worlds.

arminiusreturns
0 replies
1h20m

greybeard nix admin here: I agree People have forgotten way too many of the lessons we learned in Ops Companies like to slap "agile" and "devops" labels on things, but I see the same old fights... (biased because I hate gui-ninjas)

halfcat
1 replies
23h29m

The use case is something like medical billing entry where people are trained to know all of the billing codes and they still use an AS400 green screen console.

The employees work by keyboard shortcuts and are extremely efficient, and every time someone tries to replace the AS400 with a modern web app, their productivity drops 100x.

It’s the same scenario as a vim/emacs wizard vs a slick looking GUI that doesn’t have keyboard shortcuts.

tyre
0 replies
19h59m

The solution to manual medical billing is to have computers do the billing. The system can be configured via GUI with rules about billing codes, payers, DX codes, etc. and then the rest of the system Just Does It.

(I work at a company automating medical billing.)

lynx23
7 replies
1d3h

Anyone old and naiv enough to share this observation: Almost everything I looked at after TurboVision was inspired, but actually not really finished. Once you take the toolkit for a ride, you realize its kind of cute but unfinished. Maybe another way of looking at this is to call many of the TUI frameworks I say "opinionated", whatever that exactly means.

I am likely just dense and uncreative, but the truth is, when I switched from DOS to Linux in the 90s, I was never again as productive as I happened to be with B800. Granted, it likely took me a long time to understand the need for double buffering and the difference between a local/direct text mode vs a terminal, let alone escape sequences. But still. Whenever I tried to do something directly in ncurses, I pretty much gave up due to a distinct feeling of being unhappy. Completely different to what I was able to do with the simple ideal of B800.

dualogy
5 replies
1d1h

I get what Turbo Vision is (was), but what's that B800 thing? Surely you aren't talking about a Celeron processor? Seems tricky to google, also no Wiki page on that. You got me curious, plz spill it! =)

vetinari
1 replies
23h0m

In real mode addressing and graphic card in text mode, your video memory started at absolute address 0xb800:0x0000. It was an two-dimensional array, where you could poke and whatever you changed here, was reflected immediately on the display. Each element of the array was two bytes: character itself and color attributes.

IWeldMelons
0 replies
1h53m

I think it is also 0xb800 as it is a physical address; not ionly in real mode.

anothername12
1 replies
1d1h

Ok I think he’s referring to 0xB800, the VGA text buffer segment in real mode.

IWeldMelons
0 replies
1h54m

No not VGA, CGA actually

lelanthran
0 replies
22h28m

0xb800 is the address of the framebuffer for text. Simply write characters to that address, using offset `((row * width) + col)` and they'll appear on screen.

In graphics mode it was, IIRC, 0xa000. I once wrote a pacman-type easter egg inside the point-of-sale system[1], because doing direct graphics straight to an address is so easy and simple.

[1] Was removed after pilot and before actual release.

thechao
0 replies
1d2h

I learned GUI programming using win16, then win32 — this would've been during the transition to WinXP. I must have a city-wide blind spot, but every post message pump GUI framework has left me completely befuddled. One thing I never understood was how these OO frameworks helped to really solve the multithreaded UI issues. In Win32, I just threw the main renderer into a thread, then had support renderers build models "on the side", and then updated the difference. The code never really got out of hand.

miki123211
6 replies
1d2h

As a screen reader user, reading this post makes me want to scream.

If you care about accessibility even one bit, for the love of god, please, don't use any of the features this post mentions.

Things like animation or unicode diagrams break screen readers in horrible ways.

willm
5 replies
1d1h

I would love to improve support accessibility for TUIs. Textual internally keeps a browser like DOM structure, which means it could in theory offer browser-like support for screen readers while keeping all the features offered to sighted user. But it would require a protocol to allow the app to send structured information so that the screen reader has more to work with than a matrix of characters. AFAIK this doesn't exist.

The most promising way forward for accessibility is the web support for Textual. It would be possible for the app to work with the browser to make highly accessible TUIs.

blooalien
3 replies
1d1h

Textual internally keeps a browser like DOM structure, which means it could in theory offer browser-like support for screen readers while keeping all the features offered to sighted user. But it would require a protocol to allow the app to send structured information so that the screen reader has more to work with than a matrix of characters.

Isn't it possible to expose this content via a publicly accessible API that screen readers could simply hook into? BTW, thank you so very much for Rich and Textual. Wonderful tools. Love 'em.

willm
2 replies
1d

De nada!

Isn't it possible to expose this content via a publicly accessible API that screen readers could simply hook into?

Definitely possible from a technical standpoint, but I don't know of anyone who has done that. Maybe one day, Textual could provide that solution.

miki123211
0 replies
20h28m

Definitely possible from a technical standpoint

Yes and no, it would be possible, but only if the terminal emulator, the operating system's accessibility API, the screen reader and the library supported it. The library needs to output the right information via escape codes, the terminal emulator needs to expose it via the OS API, the OS API needs to have support for it, and the screen reader needs to know what to do with the information. I believe you could wrangle the existing a11y APIs and make it work, but you'd still need to implement support for it in emulators, libraries and screen readers. Not to mention that you'd actually have to design the standard and write a spec for it.

This would be slightly easier to do for terminal screen readers, which run directly inside a terminal emulator (kind of like Tmux) and pass most commands and keys unmodified, generating speech in the meantime.

ericwood
0 replies
21h10m

It’s more in the Rust ecosystem but AccessKit looks really promising from this standpoint. I’m not sure if it could work in the context of a TUI but it might be a great starting point! https://github.com/AccessKit/accesskit

miki123211
0 replies
23h39m

AFAIK this doesn't exist

I have complained about this not existing many times and at length, and have actually been thinking about how such a think could work.

It's a great idea, but we'd need support both from screen readers, TUI libraries and some terminal emulators, and I don't know if we could get that to happen.

spencerchubb
5 replies
1d4h

Interesting that they're hiring. I'm curious how they plan to make money from a TUI framework

itronitron
1 replies
1d3h

the jobs link gives a 404 error

__float
0 replies
1d3h

This post 2 years old, it seems they have filled their open roles :)

ynniv
0 replies
1d3h

He mentioned eventually running on the web, so my guess is to facilitate migrating old TUIs. There's plenty of consulting money in maintaining old enterprise software.

tyre
0 replies
19h58m

Yeah same question. It looks like they’re building some pretty cool software, but engineers are expensive and other frameworks exist.

zokier
4 replies
11h6m

Many people here mention SSH as one motivating uses for TUIs. It's a shame that we don't have standardized HTTP forwarding over SSH that would work as seamlessly as X forwarding can work.

f1refly
3 replies
9h55m

We have -L though, isn't that kind of what you're looking for?

zokier
2 replies
8h20m

Common ssh (port) forwarding has lots of shortcomings that make it far less practical than X forwarding for this sort of use.

Sketching out this idea, what I'd want is that ssh would set some standardized env var pointing to unix socket (analogous to $DISPLAY), and applications when starting up should pick that up. That should trigger applications to start listening on another unix socket (instead of tcp port), and notify ssh through the socket pointed by the env var. Upon that notification, ssh should set up new tunnel and open new browser window pointing to the tunnel.

Nothing about that is technically particularly difficult (I'd say its almost trivial), but it'd need standardization to be truly useful.

SoftTalker
1 replies
2h32m

Common ssh (port) forwarding has lots of shortcomings

What are the shortcomings? It always works very well when I use it.

zokier
0 replies
2h14m

Biggest problem is that manually adding/removing forwards in a session is a hassle. There is no standard way to communicate (to user or to ssh client) that application wants something forwarded. Finally tcp sockets do not have any sort of access control, which is problem especially on server-side.

Smaller problem is that because the applications all appear as localhost you lose some of the compartmentalization that browsers have, so different applications might end up seeing each others cookies/localstorage/cache/etc.

emrah
4 replies
1d4h

The first trick is "overwrite, don't clear"

This is how games were written back in the day before DirectX was a thing. You'd write directly to the frame buffer and instead of clearing and redrawing, you'd redraw what changed and what was around and under it (because there was no time to refresh the entire view in time in addition to everything else you need to do)

moring
2 replies
22h27m

There were at least two other techniques back then.

The first is to write to another buffer (possibly in normal RAM, not video RAM), then when the frame is done copy the whole buffer at once, so every pixel gets changed only once.

The second is to write to another buffer that must be in video RAM too, then change the registers of the graphics hardware to use that buffer to generate pixels for the monitor to show.

They had different tradeoffs. Copying the whole buffer when done was expensive, changing an address register was cheap. But the details of the register were possibly hardware-dependent, and there was no real graphics driver framework in place. Also, to just "flip buffers" (as changing the address register was called), rendering to the off-screen buffer meant sending pixels to video RAM, which was (IIRC) slower to access than normal RAM (basically a NUMA architecture), so depending on how often a pixel gets overdrawn, rendering in normal RAM could be faster overall even with the final copy taken into account.

CBarkleyU
1 replies
21h42m

But the details of the register were possibly hardware-dependent, and there was no real graphics driver framework in place

Did this change with 3dfx's Glide (or subsequently Direct3D once Windows got a foothold into the gaming industry)?

eropple
0 replies
16h59m

It's been a while, but as I recall, DirectX introduced a hardware abstraction layer from the get-go, but support was pretty spotty for the first few years. DirectX 7 was a pretty big step forward, and coincided with a lot of pretty important 3D features like hardware T&L and vertex buffer allocation. They got there before OpenGL, so the vendors mostly oriented around D3D7 and D3D8, but vendors' implementation was still pretty wonky and bespoke. Shaders hit for D3D9, and you had to pick between HLSL and GLSL, so the gap was widening then but I think the first time you can really describe a rigorous framework for graphics drivers, as opposed to a stack of shims of varying height, would be Windows 2000/XP bringing along XDDM (which then begat WDDM in Vista; WDDM has changed over the years, but is still recognizable in Windows 11).

Neywiny
0 replies
1d1h

I learned this from ComputerCraft programming. It's become applicable many times since then, occasionally professionally. But, the ability to tell the terminal when it's starting/done a frame is a lot more powerful IMO.

nine_k
1 replies
22h27m

I prefer WezTerm over Kitty, because of the Kitty's author attitude towards feature requests and even pull requests. And yes, you can do graphics on both, using the same protocols. If you really need graphics, a terminal is hardly a right solution. It's occasionally useful for tiny stuff like icons though.

ranger_danger
0 replies
5h59m

Do you also prefer Windows because of Linus' attitude?

zelphirkalt
1 replies
7h46m

Is there any terminal, that throws out all the stone age terminal stuff, like weird codes for starting colored output and stopping colored output? A terminal, that instead makes use of some XML tags or so, to mark text in a readable fashion as prompt, input, output, maybe variables and such, colored and non-colored, etc., and then simply has some logic to render that XML correctly?

Of course that would lead to not recognizing weird color codes and so on, but perhaps there could be a plugin system, where one could add a plugin that transforms color codes and such in the output into XML tree representation.

And then one could perhaps log the whole thing in various formats: Only visible text with colors, without colors, whole XML tree, or as JSON, or whatever other format it translates well to. Also could be extended via plugin.

But bare bones it merely treats everything as text.

SoftTalker
0 replies
2h38m

A terminal, that instead makes use of some XML tags or so, to mark text in a readable fashion as prompt, input, output, maybe variables and such, colored and non-colored, etc., and then simply has some logic to render that XML correctly?

That would be a browser. Forgive me if you were being sarcastic and I didn't pick up on it.

qwerty456127
1 replies
4h2m

How comes we had perfect TUIs and no problems on DOS yet apparently always have some problems with TUIs on Linux?

saulpw
0 replies
3h45m

Unicode, primarily.

frontporch
1 replies
18h42m

terminals are fast

their slow as hell and incredibly inefficient to build graphics on top of

but many are powered by the same graphics technologies used in video games

what does that mean? obviously they have to render text to graphics at some point

The first trick is "overwrite, don't clear". If you clear the "screen" and then add new content, you risk seeing a blank or partially blank frame for a brief moment.

The second trick would be to write new content in a single write to standard output.

its just luck when any of these work

The third trick would be to use the Synchronized Output protocol;

this could work...

With these three tricks in place you can create very smooth animation as long as you can deliver updates at regular intervals. Textual uses 60fps as a baseline. Any more than that probably isnt going to be noticeable.

no, anything above 60hz will be noticeable more smooth and less laggy. also this isnt a question about bigger=better. youll notice jank even if you run 75fps on 60hz or 60fps on 75hz, and of course with unsynchronized rendering there will be jank and other artifacts even with Xfps on Xhz.

Now that you can have smooth animation in the terminal, the question becomes should you?

nothing you demonstrated was smooth, just better than current broken (terminal) shit. and no, because the thing terminals miss out on is being able to scroll at just a constant pixel/time rate and actually follow the mouse precisely and without lag. as you can see in the video you cant do this because the terminal cant do this period because they can only move one font width/height per step. then if we actually explore this issue well soon find out a 125hz mouse polling rate adds tons of jank, and well discover 60hz is too slow to be smooth even with perfect sync, then that you need a CRT to have legible text at such a slow framerate. your video looks like a slightly faster windows 3.0. which is good for a terminal, but bad compared to what graphics could do even 20 years ago (at 60hz), no your not scrolling at 60hz, because thats impossible in the terminal.

none of this means i want what Windows / GTK / KDE / android / ... came up with where you press a button and the program then starts slowly animating something like its (ironically) a type writer instead of just doing what i said. you lose your position in scrolling because its done wrong, the "smooth scrolling" shit in firefox or whatever is just a poor (oblivious) attempt at the solution

efilife
0 replies
17h28m

They are slow!

sam1r
0 replies
18h1m

Whoa! That is so cool. Thanks for the use case example.

yoavm
0 replies
23h41m

I've used Textual to build a quick Swedish-English dictionary that runs in terminal but also works using touch, when using the laptop as a tablet and on my Android phone. It was a pretty smooth experience and was very fast to get something working. The TCSS layout system thing is a little strange, but only because I automatically expected it to be CSS and obviously that doesn't really work in the terminal.

https://yoavmoshe.com/blog/learning-swedish-with-sway-and-an...

tuieachtheirown
0 replies
16h44m

FWIW, I evaluated a dozen compiled TUI libraries and found FTXUI to be the easiest to use and most reliable:

https://github.com/ArthurSonzogni/FTXUI

It's a nice tool to build interactive dashboards with both keyboard and mouse support.

theanonymousone
0 replies
12h15m

Isn't it written in 2022, hence requiring the year in the title?

superlopuh
0 replies
8h33m

We use Textual as an interactive way to explore compilation pipelines in xDSL [0]. As our compiler is written in Python, it was the perfect tool to build a UI in the same language as the existing codebase. After starting the `xdsl-gui` project, we found Marimo [1], a reactive notebook for Python, which also lets users build apps in Python. It's been interesting to compare these two, especially in the way they handle state and propagate updates. For now we're using both tools, but it might make sense to centralise at some point. Both of these frameworks like immutable data structures, which I find is a positive incentive to use immutability throughout the code, and has been good for the rest of the project.

[0]: https://xdsl.dev/ [1]: https://marimo.io/

snthpy
0 replies
11h31m

I think this should include (2022) in the title.

sam1r
0 replies
18h3m

Thank you so much for making this. I use this quite regularly + rigorously for my own personal tracking, scheduling and much more.

Thanks to textualize, I can interact with the external world with full control in a black box.

rtpg
0 replies
18h58m

RE Fractions, for _many people_, decimal.Decimal will work very well.

For layout concerns, fractions are probably a more natural fit (things like 1/3), but Decimal is a great floating point default for a lot of problems. They aren't exact, but a lot of the "normal" floating point weirdness goes away and your results look a lot more human. Highly recommend if you don't have a perf reason not to.

lofenfew
0 replies
19h21m

There is a heuristic where you write various sequences and ask the terminal for the cursor position, which should make an educated guess as the Unicode version. Unfortunately from testing we've discovered that terminals still render emoji unpredictably even if you think you know the Unicode database used.

Rather than using this as a heuristic, couldn't you simply use this whenever you need to determine the width of a string? Write it to the terminal, if it ends up going farther than you expected, then you need to wrap it somewhere. I used a trick like this at one point after I got annoyed with wcwidth.

kbouck
0 replies
1d2h

This TUI discussion triggered a bit of 80s/90s programming nostalgia -- anyone remember TTT (TechnoJock's Turbo Toolkit)? Pre-gui era UI framework.

hggh
0 replies
1d1h

(2022)

gudzpoz
0 replies
2h23m

Emojis are terrible

Not just emojis. Recently I've had some fun trying weird Unicode characters in different terminals (e.g. 𒐫):

- QTerminal/Konsole: Tofu

- Xfce terminal: Results in overlaps with characters that comes after it.

- Alacritty: Similar to Xfce terminal, but glitches when the cursor/glyph moves.

- COSMIC term: No overlapping glyphs, except that the line then wraps only after it grows out of screen.

- Kitty/WezTerm: Scales the glyph to fit it into a single column. (Barely legible.)

I don't even known what to expect. It is indeed a mess over there.

cocodill
0 replies
1d2h

Humanity needs more TUI tools

RunSet
0 replies
1d1h

I use monodraw for these diagrams. Monodraw is MacOS only unfortunately, but there are no doubt good alternatives for other platforms.

https://github.com/Nokse22/ascii-draw