summary refs log tree commit diff
path: root/src/tui.md
diff options
context:
space:
mode:
authordzwdz2023-08-19 19:08:25 +0200
committerdzwdz2023-08-19 19:08:25 +0200
commit384e2e40dc5b5497d2d6863f2716aac8b4052a7e (patch)
tree6b7ee38a007f912eafd338554fca5a251a69125e /src/tui.md
parenta31e70cc51ad197d01ccb09d5da85b9b74798c0d (diff)
add the tui article
Diffstat (limited to 'src/tui.md')
-rw-r--r--src/tui.md110
1 files changed, 110 insertions, 0 deletions
diff --git a/src/tui.md b/src/tui.md
new file mode 100644
index 0000000..5b23336
--- /dev/null
+++ b/src/tui.md
@@ -0,0 +1,110 @@
+---
+title: On TUIs
+date: 2023-08-19
+---
+
+I'm using a relatively modern terminal emulator.
+It has snappy native scrolling, with e.g. great touchpad support.
+I can search the scrollback with a single hotkey.
+The way I navigate and use it is consistent across all cli utilities.
+That is, except TUIs.
+
+## scrollback
+Most TUI programs---IRC clients, (web/gopher/gemini) browsers, mail clients---use
+custom scroll widgets, as opposed to just printing all the data and
+letting the terminal handle scrolling.
+
+If you're using them over ssh, scrolling turns from something your terminal
+can do instantly, to something that requires a roundtrip for each unit scrolled.
+This makes them painful to use on high latency connections, which would otherwise
+have enough bandwidth to just transfer all scrolled text.
+It also breaks touch support, as you lose pixel-wise scrolling, and the lag
+makes it harder to predict the length of a scroll.
+
+Every program has its own bespoke set of hotkeys, so you lose out on consistency.
+Some programs have vi bindings, some don't.
+Some don't even support arrow keys.
+Search support will differ, too, with a slightly different implementation in
+each program that supports it.
+
+You already pretty much need scrollback and search for regular shell usage, though.
+Even if you're using a "dumb" terminal, you're probably using something like
+tmux to provide that.
+Why, then, should programs reimplement what's already provided for you by the terminal?
+
+One common reason is top/sidebars.
+The terminal protocol we use is too primitive to express multiple windows, so
+scrolling a program with a sidebar ends up looking wrong.
+It's a tradeoff, sure, but IMO
+the benefits of using the terminal's scrollback outweight the benefits of sidebars.
+In most cases, you don't really need them:
+
+* Some IRC clients have sidebars with the list of open channels, users, or a topbar with the topic.
+  They're not really used too often, and they can always be checked with a single command.
+* Mail clients have sidebars with the inboxes.
+  It's useful to see the amount of unread messages in each, but that could be printed on startup.
+  After that, there's no need to keep the inboxes on screen when you're not actively switching between them.
+
+I'm not saying top/sidebars are useless.
+They're great in *true* GUIs, where using a sidebar doesn't mean you're no longer allowed to use native widgets.
+Sadly, terminals are much dumber than that.
+If you want to use them well, blindly copying GUI conventions isn't the way to go.
+
+## improving the situation
+The tradeoff would mostly be gone if terminals were extended to allow GUI-like subwindows.
+I believe that was one of [notty]'s goals.
+[rio] *sort of* supports that, too.
+
+## line editing
+Speaking of [rio], it had some good ideas.
+One of them was the "output point".
+It separated the program output from your current input.
+Instead of directly sending your input to the program, it let rio function as a line editor.
+
+It had autocompletion, utf8 support, and gracefully handled program output during editing.
+If the program sent some text, your input was moved out of the way.
+If the program erased some text (`\b`), your input was moved back to the available space.
+
+Going back to the status quo---this is actually pretty hard to achieve, if you're
+not also reimplementing a scroll widget.
+If you want to input and output text at the same time (think netcat, or an IRC client),
+your two options are:
+
+* Use Readline as a base. It doesn't support asynchronous output so you'll have
+  to [implement that on your own][rlwrap].
+* Use [linenoise]. Hopefully you didn't need utf8 support, as [until recently][yhirose]
+none of the utf8 forks supported the asynchronous API.
+
+Similarly, just as with custom scroll widgets, line editing over a high latency
+connection *hurts*, because you need to do a full roundtrip for each character typed.
+
+Also, some utf8 characters have ambiguous width. Only the terminal knows how they
+will be rendered, so, if you want your line editor to be fully correct, you'd
+have to poll the position after each such character printed.
+
+Doesn't this suggest that line editing would be better handled on the terminal's end, as in rio?
+
+### appendix: autocompletion
+How would autocompletion work if line editing was implemented in the terminal?
+rio was limited to autocompleting paths, but here's my idea for a more general
+approach:
+
+When a program with support for autocomplete starts, it'd send an escape code
+to notify the terminal that it can use autocomplete. Similarly, it'd disable
+autocomplete support when launching another program, or quitting.
+
+On `<Tab>`, the terminal would send the current, incomplete, line wrapped in
+another set of escape codes. The program would recognize that, and respond
+with a list of possible completions, potentially also informing the terminal
+that it can request more.
+
+## tldr
+1. Scrolling through TUI sucks.
+2. I wish terminals handled line editing.
+
+
+[notty]: https://github.com/withoutboats/notty
+[rio]: https://man.cat-v.org/plan_9/1/rio
+[rlwrap]: https://github.com/hanslub42/rlwrap/blob/master/src/readline.c
+[linenoise]: https://github.com/antirez/linenoise
+[yhirose]: https://github.com/yhirose/linenoise/pull/1