4 ms·
> The amount of work and frustration we could save with a modern equivalent to terminal emulators (without historical baggage) would be really significant. Thi
by rollcat 4y ago
> The amount of work and frustration we could save with a modern equivalent to terminal emulators (without historical baggage) would be really significant.
This has been occupying my mind for over a decade, but I can't come up with a design that I like.
For "TUI" apps: something like a GUI toolkit, but should remain reasonably performant over a poor connection (think how mosh tries to hide input latency), and the wire protocol should be something you can bang out in bash.
For shells: the shell should not be concerned with things like keyboard shortcuts, line wrapping, or positioning the cursor - this should be done on the client (terminal). You should be able to set a proportional font, if that's what you like. The shell should be able to trivially request displaying a picture, report on the status of a background task, or present an interactive progress bar.
Maybe this is two different projects / efforts, maybe one can build on top of another.
- thomastjeffery 4y agoTL;DR: I'm about to go on a lengthy rant, because I too have spent over a decade obsessing over this subject. I feel like I've been starting to actually get somewhere, but there's still a lot up in the air. Also my meds are wearing off, so all eighdy HD's are present. Read at your own risk... ----- It's a game of compromises. The first problem is to decide what goals you value most. The current compromises are decided by the goal of backwards compatibility. In that sense, we are "steeped in tradition". It's a mess, but at least decisions have been made; and we are recognizing - right here, right now - just how significant that fact is on its own. > For "TUI" apps: something like a GUI toolkit, but should remain reasonably performant over a poor connection That sounds a lot like what web browsers are; which reminds me of the sheer magnitude of options we have available. It's easy to get stuck with decision fatigue. We aren't making a universe simulator here, so we need to break this project down to a smaller domain. The constraints of the problem domain are what define a project, so pinning them down is 90% of the work. I'm thinking back at what my motivation was in the first place: frustration with the status quo. Having a simple text UI interface is evidently useful. The shell is the first and last thing I use: it's my home, and that's why I care so much in the first place. Something with generally the same constraints of a terminal emulator & shell is what I want. My frustration lies with the complexity in both the terminal emulator itself, and the way a shell (and every other terminal-based program) interfaces with that. So what's the bare minimum that these two things need to function? First, the terminal needs input and output. But these needs are really just an extension of the text-based program's needs, right? So what does a shell or a text editor need to function? Well, it needs input and output. Hold on now, do we really need the terminal emulator? Why not have the shell do that? Well, there are some reasons: Shells can be run without any IO. Inside shells, we can pipe programs into each other. Those pipes are made of text. Is that the domain we want? Well, using text as the interface is one of my main frustrations with terminal emulators: even the ASCII table itself shoves key-presses into the domain of text, and that's an ugly hack I don't want to keep. There are functional needs for dropping that, too: "ctrl-m" is the same ASCII code as "enter", and keyboard layouts aren't always very compatible with ASCII in the first place. There are too many assumptions baked in here. And while we are on the topic of ASCII, escape characters are the ugliest hack in here. On the terminal, we use them for input - to extend the ASCII table to accommodate a few more keys - and for output - for decoration like text color, boldness, and even flashing background. It's like a markup language, but made out of non-drawable characters that were supposed to be typed with the escape key. There are so many ugly edge cases here, you could write a novel about them! But shells aren't always about plain text. You can pipe gzip to dd or a file, and it will totally work. But if you pipe it to your terminal output, weird things can happen. That's because some raw binary looks like escape characters, and we are already solving that problem by making user input a separate thing. Progress! So what do we do with keystrokes? Let the user decide! But what data will end up getting sent to the program? The status quo is to be a REPL by default. That's the foundation for a lot of the ugly assumptions we just dropped. It's the reason that the OP has two whole chapters just on disabling that behavior. But most programs we invoke from a shell are either printing, or running a REPL of their own. And a lot of them are bad at it, which is why GNU readline is a thing. There's even rlwrap, which wraps a program in readline! That's very helpful, but I would love to never need it again. Plus, readline makes some UI decisions of its own, like its emacs-like key bindings, and I would rather it not. So the big question here is about how UI should flow. That question gets me all kinds of excited, and all kinds of overwhelmed. This is where I start shifting my focus away from shells and back to text editors. --- Emacs has its own shell. But Emacs isn't a dumb terminal emulator. It's built out of lisp, which represents data as text in a much cleaner way than ASCII escape sequences could ever dream of. And the way its interface flows is definitely more interesting than a REPL. In fact, some of the crazy shit you can do in eshell is one of the main things that get me thinking about shells and terminals and the ways they hold me back. And if you really want a good example of how text-based UI can flow, look no farther than Vim. The modular flow is elegant and efficient in ways that the primitive REPL could only dream of. Yet both of these wonderful programs bring me back to the very same frustrations I have with terminal emulators and shells: they are steeped in tradition! Vim was my first. I was happy to sin against the Church of Emacs, the stubborn atheist I am, and vi is a seductive mistress. But while vi could do most anything I wanted, and it could bend and extend in many exciting ways, I still managed to find its limits. When I started typing with a non-standard keyboard layout (workman), I tried remapping Vim's keys to compensate. First you remap a key, then you remap the one it replaced, then the next, etc... and eventually you hit a circular dependency. It can't be done. So I decided to take the opportunity to learn me an Emacs. Emacs is incredibly customizable. If you can navigate your way into its elisp structures, you can mold it into anything you want. But what Emacs already is by default may be easy to decorate and add to, it's not so easily unmade. I had big ideas about making my own vi-style modular editing keybindings once, but I never could quite find my way. Every move I made, I found myself tripping over what was already there; what I had come to replace. The whole time, in the back of my mind, my conscience screamed, "We just need a clean slate! Emacs without the defaults. VoidMACS."
- thomastjeffery 4y agoRant continued... --- It's the same problem everywhere I look: UX assumptions. Predetermined flow. Defaults. My ultimate arch-villain. Every time I think about this, I fantasize about the perfect user experience: one with zero assumptions. A modular UI, totally factored away from data and functions. That's what shells got right in the first place! What if we did that with GUI? Take a moment and think about your favorite shell utilities. What do they look like? What do they do? What input do they need? How do they flow? Here we are, at home, in the REPL. But what if we stepped out, right through the fourth wall, and looked at it? What if we took that output and forked it into a file, or another utility? That's where the shell was born. Can it be bourne again again? Emacs tried. It took the flow, and put it into a text buffer. That let us do some non-linear flow. Emacs also recreated some utilities in lisp, so that they could interface with more complicated structures, and react to different events like hooks. Over time, some structure emerged, but it was too organic. Using Emacs today means wading through traditions every bit as deep as the shell itself. Like a fine aged whiskey, it soothes us into a drunken haze. The hangover leaves me desperate for clarity. Turn off the stimulus. Give me a blank slate. An empty canvas. You've got a default startup sequence? Drop it. Got a welcome screen? Drop it. Default scratch buffer? Drop it. Default keybinds? Drop. It. I want nothing. I don't care how broken that makes it! In Episode 2 of Firefly, Mal speculates about where the mysterious Reavers came from: "They got out to the edge of the galaxy, to that place of nothin' and that's what they became." I'm not afraid: Give me the void, and let me get to work. I am the user. I am God! When I start my text editor, I want nothing there but what I configured. It's not that scary of a concept when you think about it: "defined" doesn't have to be from scratch. What I really envision is a choice of options. Like libraries or plugins that you drop into the top of your config file. Someone made a Vi-clone mode you like? Put it in your config. Someone made a Sublime text clone mode you like? Put it in your config. Someone made a Windows Vista clone with a half-broken MS notepad that you like? I don't give a fuck about your personal preferences, put it in your config! No one needs to know what your interface looks like, or what your keys are mapped to. They just need to give you two simple things: input and output. Want to edit text? Import the text editing mod, then map a part of your windowing system to the text renderer (output), and map some keybindings (input) to the text-editing functions. Want to rebase a git tree? Import the interactive git editor mod, then map a part of your windowing system to the interactive git UI renderer (output), and map some keybindings (input) to the interactive git functions. Want to play Tetris? Import the Tetris-clone mod, then map a part of your windowing system to the tetris clone renderer (output), and map some keybindings (input) to the game movement functions. Want a web browser? Import the Firefox-fork for voidmacs mod, then map a part of your windowing system to the voidfox renderer (output), and map some keybindings/mouse events (input) to it. Want a tiling window manager? Import the i3-for-voidmacs mod, then map your windowing system to a tile of windowing system instances (output), and map some keybindings (input) to the window split, move, and close functions. Want a Vim-like modal interface? Put your regular basic text-editing keybindings in a new namespace called "insert mode" (plus a key to go back to normal-mode), and make some new "normal mode" keybinds. Put all of that in a mod, and import that into your config. Done. Works everywhere. Want an Alexa/Siri/GoogleHome/Bixby/Jarvis assistant to bitch at? Import the mod, then set the default speaker and whatever other mod input functions you want integrated (output), configure the wake word hook to "HAL 9000" (input), and tell it to sudo make me a sandwich. --- Confused yet? I've been ranting for a while now. Basically, I want an Emacs, but one where modules/packages never define their user interface. Or maybe a module/package defines a user interface, but that's all it does. Never both. That way, modules/packages are guaranteed to be composable. Like neatly factored out functions, you can stack them together. You can weave them into whatever convoluted tapestry your heart desires. And you never have to undo any configuration. Because undoing configuration is pain. As soon as a module/package defines functionality and user interface, it ties a knot. That is not allowed. Only the user can do that. Otherwise, at some point, the user is going to have to go around untying knots all over the place. I could keep ranting forever, but I'm starting to worry about the character limit on HN... So I bid thee good afternoon, good evening, and goodnight.