@lyse The what? What happened? Do I want to know? 😭
@lyse I might check it out – once the vacation is over. 😅
@lyse 😂😭
But it’s Windows, it doesn’t have a place in my heart.
The older I get, the more I’m glorifying anything pre XP. 😅 But that’s only because everything today is so horrible.
Well, not anything pre XP. 3.0 or newer would be nice, because Windows 2.x was still pretty bare bones:
(OS/2 was great, though, except for the lack of a good file manager.)
@lyse Ah, you mean the categorization. Yeah, that would never work in Windows, at least not without having a centralized package manager (so there’s one authoritative source of which program belongs into which category).
Oh wow, those Cassiopeias look pretty cool. Did you have one of those or one for each kid?
In the light of current events, I will first consult my pillow and only then write an article about readable code.
I didn’t try it, but this looks like something for real sysadmins: https://github.com/dimonomid/nerdlog The UI looks very usable and the README is also promising.
@movq Yes, yes, yes and yes.
The start screen looks exactly like a website not a desktop application.
I mean, I find Motif also fairly ugly. Granted, it’s a hell lot more discoverable than anything today. The old Windows UIs probably had the best balances. But it’s Windows, it doesn’t have a place in my heart. So, I stick with good old KDE. ;-) That’s my nostalgia kicking in.
@movq Yes, this screenshot. However, not the Dutch but rather the German version, no wonder it looks so crazy!!1!11
It’s been a hot minute or two since I last used KDE, so I don’t remember exactly. I just vaguely recall that I found myself thinking multiple times that the KDE application categories were better matching or there were more or something like that. Most of my classmates were on Windows and had one giant long list of all sort of stuff in there. You even had to scroll in the menu. Sure, they installed all kind of garbage, which didn’t exactly help. Where in KDE, they were actually grouped by Office, Internet, Graphics, Multimedia, Games, etc. In Windows, applications usually hid themselves in a sub folder named after the software vendor. At least in the later (?) days.
I only used Win 95, 98 and XP at home. For maths class with computer algebra system (Maple), we had a Cassiopeia with Win CE: https://en.wikipedia.org/wiki/Casio_Cassiopeia At school, there was probably also Win 2000, but I don’t know anymore for sure.
These commit messages… https://github.com/vergonha/garden-tui
Speaking of UIs, this is how Thunderbird looks now:
So we continue to let every program make up its own UI style (and then we complain that “the Linux desktop” looks “messy” and “inconsistent”). I guess this uses GTK, but it doesn’t look like any other GTK program. Buttons, tabs, drop-downs, whatever, it’s all different. It even has its own subwindow system (i.e., popups that you can’t move).
I didn’t say this in the blog post, but I’m convinced that programmers these days absolutely positively hate everything that looks even remotely like Windows 95 or Motif – with a passion. I see that in my coworkers as well, they really can’t stand it. It’s an emotional thing.
@lyse In what way was KDE 3’s menu organized? KDE 1 is the only KDE version I ever used. 😅 We’re talking about this one, right?
Isn’t Notepad++ and Python cheating!? :-D
Well, Python was certainly already a thing back then, but Notepad++ is from 2003, right. I think I used https://www.wintotal.de/download/proton/ at the time? Maybe? I don’t know. 😅
@movq Regarding https://movq.de/blog/postings/2026-06-16/0/POSTING-en.html:
In my opinion, the KDE 3.5 menu was organized way better than the Windows Start menu. Granted, a typical KDE installation had much more applications to offer, too. So, there was more need to get it right. And it probably was also later in time.
Isn’t Notepad++ and Python cheating!? :-D
Crazy story on the clock’s seconds. I never heard of that before. Neat.
Yeah, UI these days is horrible. (That’s why my own TUIs suck, too!)
Let’s see which other browser-based clients I broke with that message…
@lyse That, uh … yeah, that would work as well. 😅🤦♀️
@movq @bender Thank you! It’s some kind of a thistle I reckon. My mate is a bee hunter, I’ll link the next one that comes up.
@movq Phew! ;-)
@movq Yiha! Alternatively, you could embed the
@movq Gotta make the economy go “around” and keep public services in play 😅 Good luck! 🤞
☠️ Doing the taxes today. ☠️
@movq fully agree! And 10, and 11, and 18. By far my favourites, @lyse.
It’s one of those topics that might cause outrage because I’m getting it all wrong.
So far, nobody noticed. It didn’t get posted on HackerNews or Lobsters this time, and it only got 46 hits so far (as opposed to ~50-100k hits when it does end up on those sites). 🤣
@lyse Oh, 02.jpg is great. Camera just a little lower next time to put more emphasize on the … whatever that is in the foreground. 😅
Oh god, finally: The thumbnail generator for my blog now renders a typical “play” icon for videos.
https://movq.de/v/017c2070f4/s.png
Saves me the need to write “this is a video” every time. 😬
The dairy farm has a new milk vending machine. The prices increased by 20%. One liter is now 1.20€ instead of 1.00€. But I don’t complain.
In a few meters of shrubs there were easily 50 butterflies. That was crazy, I’ve never seen this many in one spot. I should have taken a video.
The grain field in the beginning was looking so great. Crazy colorful and very yummy looking. I would have loved to take a bite. Or at least lie down right in the middle.
That was another great time in the outdoors. The 21°C were killing us, though. We were always glad when we reached a shady spot with a little breeze. I’m not gonna survive the 35°C later this week. :-(
After the last two days were dry and a tad warmer, I left the house a few minutes later to check again. It was similar to last time. One deer on the pasture that didn’t run off, it was roughly 15-20 meters away, a bit further than the day before yesterday. Probably even the same individual. Many moths, zero fireflies and another two deer on the mown meadow when I left the forest. Those were closer to 50 and 100 meters away and evenutally escaped into the woods. The same street lamps were off, too.
The lovely smell of cut grass was in the air. Venus and Jupiter reflected brightly in the West. What a stroll, I call that a great success. :-)
@movq I’m completely with you. I just do rivo’s approach with some of my own stuff that nobody ever sees. But the vast majority gets a real version. Probably not a changelog, but a version. And it’s very small stuff.
Die Meisterschaft der Speisewagenschieber in Stuttgart: https://www.youtube.com/watch?v=OfgwdBBWzCw Eine großartige Vorstellung einer Unfalluntersuchung. :-D
@lyse Interesting approach. 🤔
The master branch should never be in a broken state (apart from bugs I don’t know about). Any intermediate state during the development of a larger feature will happen in a different branch.
I mean, yeah, but … I don’t know, I like having “traditional releases” as a second safety net when I write programs. I like to let things mature for a while and then I cut a new release. So it’s, like, “we have a bunch of new features and fixes here, and to the best of my knowledge this works fine now”. But maybe I’m just paranoid. 🤔
There: https://github.com/rivo/tview/issues/442#issuecomment-641898039
@movq Yes. The author tries hard not to break existing code, but apparently he did this time. In his defense, it’s not an official release, I just updated to master. Which is exactly what I always did in the past as there are no real versions (I even think that in one ticket he wrote years ago that master is always stable). That has finally changed a year ago, though: https://github.com/rivo/tview/releases/tag/v0.42.0
@movq Brilliant! Oh, I’m super happy to get it all wrong together with you. :-)
[Release notes] are meant for human beings, it’s a human-to-human interaction.
This is one of the most important messages. Absolute key, but misunderstood so often.
tt. But then, in the message tree, I spot another missed typo. My process is then to go to my twtxt.txt and fix it by hand. However, I still have to clean up tt's cache. This is rather tidious:
@lyse Is it this one? https://github.com/rivo/tview It’s almost 10 years old but hasn’t seen a 1.0.0 release yet? 🤔
Updated draft: http://movq.de/blog/drafts/changelog/POSTING-en.html
I’ll probably publish this later today. Or maybe not at all. It’s one of those topics that might cause outrage because I’m getting it all wrong. 🤪
@movq Exactly!
Haha, GitHub. I “unlocked” the “achievement” called “Quickdraw”:
https://movq.de/v/efc96874f0/s.png
It’s for closing an issue very soon after it was opened.
Only problem: I was the one who opened it and it was a mistake, so I quickly closed it again. 🤦♀️ https://github.com/bundlewrap/bundlewrap/issues/892
@lyse Oh god, yeah. In other words: Devs need to think about who their target audience is. 😐
tt. But then, in the message tree, I spot another missed typo. My process is then to go to my twtxt.txt and fix it by hand. However, I still have to clean up tt's cache. This is rather tidious:
Fuck me! I tried to upgrade tview and the first thing I notice is a shitload of added dependency versions:
go.mod | 18 ++++-----
go.sum | 97 ++++++++++++++++++++++++++++++++++++++-----------
My code does not compile anymore as the view.FormItem interface was extended. Get/SetDisabled(…) are quickly implemented, no worries.
But the tview.Primitive (what makes a widget) interface has now a bunch of PRIVATE methods. For focus handling. Would you believe that!? Thanks, I cannot satisfy this interface in my very custom widgets anymore. Okay then, I just embed *tview.Box. tt now successfully compiles, but does not react anymore on key presses and the message tree is not focused either.
I’m not in the mood to debug this shit. :-( Lunch time.
@movq I just ran across another thing. At least I personally couldn’t care less about CI infrastructure changes. Whether they’re using github action a or b or c or version v or w, it is not of my interest. At all. (It might be useful to estimate the supply chain attack risk, though.) If the maintainers want to include them in the changelog – and there are probably people to whom this information is crucial – it’s probably best to document CI infrastructure changes in their own section.
@movq You may want to include another antipattern to avoid in your article:
- bump $same_dependency from 1.0.0 to 1.0.1
- bump $same_dependency from 1.0.1 to 1.0.2
- bump $same_dependency from 1.0.2 to 1.1.0
- bump $same_dependency from 1.1.0 to 1.2.0
tt. But then, in the message tree, I spot another missed typo. My process is then to go to my twtxt.txt and fix it by hand. However, I still have to clean up tt's cache. This is rather tidious:
@movq Thank you very much! So, the concept is very similar. The root widget gets the input and can pass it to whatever child has the focus and so on.
My two main issues are the API design, that the input handler sometimes get an additional callback to notify the application about which element is focused, but sometimes not. And that focus switching sometimes just does not work as expected. Anyway.
As for rendering the selected button, I was also thinking about indicating it with some kind of border around it, square brackets seem to be a wonderful choice. :-)
@itsericwoodward Why hear? I’ll just put it up at https://twtxt.app now shall I? It’s good enough IMO that it’s already working quite well. The challenging parts now is to figure out a good set of default publishing connectors to support? 🤔
@itsericwoodward Yes really 🤣
tt. But then, in the message tree, I spot another missed typo. My process is then to go to my twtxt.txt and fix it by hand. However, I still have to clean up tt's cache. This is rather tidious:
With multicolored TUIs, I find it usually hard to immediately tell which button is selected if there are just two.
Indeed, I wouldn’t be able to tell in that example, either. movwin works around that by (mostly) assuming that there is no support for colors at all, so there should always be a way to tell which widget has focus, even without colors. That’s why it puts brackets around a button’s label when focused:
The fewer colors you use, the better, I guess. 🤔
tt. But then, in the message tree, I spot another missed typo. My process is then to go to my twtxt.txt and fix it by hand. However, I still have to clean up tt's cache. This is rather tidious:
Now I’m curious how movwin deals with that. ;-)
Focus handling? I hardly remember, lol. 😅 Did that 6 months ago and haven’t touched it since. Let’s see.
The core main loop gets keyboard/mouse events from curses. At this level, the main loop only knows about exactly one widget, so it passes the event to that widget (whatever that is, doesn’t matter – they all inherit from the Widget base class, it could be a Window, a WindowManager, or an Edit box directly).
The outermost widget is usually a WindowManager. It implements a few hotkeys of its own, like switching to another window. If none of those hotkeys match, it passes the event to the currently focused window.
Same story here: Window implements some hotkeys (like opening the menu bar). If none of those match, then … the magic happens.
Each Window acts as a focus manager. It can descend into its child widget hierarchy and collect all child widgets in a depth-first search. They are collected into a flat list. Each Window then has an attribute _focus_position, which is an index into that list. Pressing Tab or Shift+Tab increases or decreases that index and that allows you to select the next/previous focusable widget in the current window.
Eventually, Window passes the input event to the currently focused widget.
Usually on initialization, the application can ask a Window object to focus a certain widget. The file selection dialog does that, for example, because the “natural” focus order would be to focus the Edit box at the top of the window first – but that’s not what the user wants, the Table showing the list of files should be focused.
If no widget ever feels responsible for handling a certain input event, then there’s a global unhandled_input callback that the application can provide (same as in urwid).
I think that’s it.
Hm, that’s more complicated than I remembered, but apparently it works fine, because I completely forgot about this. 😅 All I did in the last few months was make new classes that inherit from Widget, like the new Table class or Edit or HexEdit or whatever, and if they want to get input events, then they must implement the methods input_key() or input_mouse().
Does this answer your question? 😅 (I admit that I didn’t exactly understand your scenario, so I just went ahead and rambled about my implementation. 😅)
tt. But then, in the message tree, I spot another missed typo. My process is then to go to my twtxt.txt and fix it by hand. However, I still have to clean up tt's cache. This is rather tidious:
Another thing: With multicolored TUIs, I find it usually hard to immediately tell which button is selected if there are just two. I’m asking people for any relevant information. :-)
tt. But then, in the message tree, I spot another missed typo. My process is then to go to my twtxt.txt and fix it by hand. However, I still have to clean up tt's cache. This is rather tidious:
Getting the vim key bindings to work for focus switching in this modal dialog took me forever. Only cursors and (Shift+)Tab are supported out of the box. I absolutely understand that, it’s fine. I installed an input handler on the dialog, but the focus always stayed the same.
After two wasted hours, I was in despair to copy the tview.Modal into my own code base. Of course, I had to fix all the private tview field accesses first. But even installing the input handler directly on the buttons themselves did not work. Even though, the handler was definitely executed, the focus did not shift. Forcing redraws as a last resort also did not work.
Looking through all the messy chained input handling, I eventually stumbled across another place in the tview.Form, which is internally used by tview.Modal. This messed around with app focus receptions and input handlers. This gave me the idea to make the tview.Application refocus my modal dialog after I told the modal dialog which button to select. And would you look at that, this did the trick! I haven’t completely figured out what is going on exactly, but I could get rid of my Modal clone again.
I always go through hell with focus handling in tview. Each and every time. It just does not feel natural to me. Complete brainfuck to wrap my head around. The Urwid API felt sooo much more refined, it never was an issue. It just works. In fact, I cannot think of any other TUI library that has remotely the same pain level when it comes to focusing widgets as tview.
Now I’m curious how movwin deals with that. ;-)
Every now and then, I think that I have carefully proof-read my message enough times and hit the “Add message” button in tt. But then, in the message tree, I spot another missed typo. My process is then to go to my twtxt.txt and fix it by hand. However, I still have to clean up tt’s cache. This is rather tidious:
- Recall the
sqlitebrowser ~/.local/share/twtxt/tt2.sqlitefrom my shell history.
- Switch to the “Browse data” tab.
- Go to the
messagestable and wait a second or two until it’s loaded.
- Sort by the
created_atcolumn twice, so that I get descending order.
- Select the first message, which is typically the one in question.
- Find the “Remove currently selected row” button in the tool bar.
- Commit the changes.
- Close sqlitebrowser.
So, I finally implemented the removal of messages from the cache in tt. I can now hit d and confirm the removal. Bam! Should have done that ages ago!
https://lyse.isobeef.org/tmp/tt-confirm-message-removal.png
Next up is the search, I think.
Belhod! I present Swag – Build offline-first web apps in pure Go and HTML.
@movq Right, at work, nobody gives a fuck. At all. There are so many universes between my definition of quality and everybody else’s.
Let’s stop here and enjoy the weekend or vacation. :-)