Uuhh, nice, @eldersnake@we.loveprivacy.club is back!
@prologic@twtxt.net Perhaps somebody tried to register âyarn_secret_serviceâ. 8-)
@prologic@twtxt.net Whereâs the before picture!? :-D
@movq@www.uninformativ.de Yes, this is absolutely a no-go!
A long time ago when the first telemetry shitstorm happened, I added export GOTELEMETRY=off in my ~/.zshrc. But it doesnât seem to be picked up at all (I actually call this sabotage!):
$ go env GOTELEMETRY
local
$ go env -w GOTELEMETRY=off
go: GOTELEMETRY cannot be modified
$ go telemetry off
$ go env GOTELEMETRY
off
@prologic@twtxt.net @david@daiwei.me I just want to bring up the following: From a data protection point of view, edits and deletions are important. But thatâs about it, I will not join discussions on that topic. :-)
@prologic@twtxt.net You also have to tell us the username!
Hell yeah, @kat@yarn.girlonthemoon.xyz is back! \o/
Hurray, I can now press gg instead of g to go to the top in tt. Much better! :-) Other multi-key combinations are also easily possible now.
I should probably write a real article about this at some point, but here we go. The only downside with my new key binding system is that it breaks tviewâs established pattern. Youâve got an InputHandler(), that is implemented using WrapInputHandler(âŠ). It typically then directly implements the switching logic depending on the key press. Something like this:
func (w *Widget) InputHandler() func(event *tcell.EventKey, setFocus func(p tview.Primitive)) {
// WrapInputHandler allows for intercepting key events with SetInputCapture(âŠ)
// from the outside for customization. This handles the default key bindings.
return t.WrapInputHandler(func(event *tcell.EventKey, setFocus func(p tview.Primitive)) {
switch event.Key() {
case tcell.KeyRune:
if event.Modifiers() == tcell.ModNone {
switch event.Rune() {
case 'k':
w.scrollUp()
return // we already handled the event, stop processing
case 'j':
w.scrollDown()
return
}
}
}
// We didn't handle the key event. Maybe the parent
// widget knows what to do with it.
if handler := w.parent.InputHandler(); handler != nil {
handler(event, setFocus)
}
})
}
From the outside, you can intercept and either stop or continue the widgetâs original key handling with a potentially rewritten key event using SetInputCapture(âŠ):
w := NewWidget()
// customized or additional key bindings
w.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
switch event.Key() {
case tcell.KeyUp:
// Rewrite the event, so the "cursor up" key is an alias
// for the vim key binding "k", that is handled by the
// wrapped input handler above. (I know, I know, this is a
// completely unrealistic example, why would anyone use
// cursor keys when there are vim key bindings available?!)
return tcell.NewEventKey(tcell.KeyRune, 'k', tcell.ModNone)
case tcell.KeyRune:
if event.Modifiers() == tcell.ModNone {
switch event.Rune() {
case 'q':
app.Stop()
// we already handled the event, do not pass it
// to the wrapped input handler above
return nil
case 'r':
toggleMessageReadStatus()
return nil
}
}
}
// we didn't handle the event, pass it to the wrapped
// input handler above
return event
}
Since they all expect a single key, Iâve noticed that using multiple dedicated KeyBindings of mine on these different levels kinda breaks multi-key handling with common prefixes. The outer-most KeyBinding captures the prefix, but it canât transfer it to the inner one if not handled by the outer one. At least not without some more (potentially ugly) changes. So, I now have to work with just a single KeyBindings object for the entire widget chain (if it consists of multiple other widgets or the regular input handler and input capture are in the game). The outside needs to register all its key bind customizations or extensions at the same level that the original widget handles its default ones. Doable by exposing the widgetâs KeyBindings instance, but not pretty. You always have to keep this in mind.
With the KeyBindings, it will look like that:
type Widget struct {
parent tview.Primitive
// make it available to children or the outside either by
// direct field access or by providing a getter method
KeyBindings *bind.KeyBindings
}
func NewWidget() *Widget {
w := &Widget{KeyBindings: &bind.KeyBindings{}}
w.KeyBindings. // default key bindings
Bind0(bind.KeySequence('k', w.scrollUp).
Bind0(bind.KeySequence('j', w.scrollDown)
return w
}
func (w *Widget) InputHandler() InputHandler() func(event *tcell.EventKey, setFocus func(p tview.Primitive)) {
return t.WrapInputHandler(func(event *tcell.EventKey, setFocus func(p tview.Primitive)) {
// also note the missing support for focus transfer at the moment
event = w.KeyBindings.Capture(event)
if event == nil {
return
}
if handler := w.parent.InputHandler(); handler != nil {
handler(event, setFocus)
}
}
}
And then from the outside, or in a child widget:
w := NewWidget()
w.KeyBindings. // additional or customized key bindings
Bind1(bind.KeySequence(tcell.KeyUp), func(*tcell.EventKey) *tcell.EventKey {
return tcell.NewEventKey(tcell.KeyRune, 'k', tcell.ModNone)
}).
Bind0(bind.KeySequence('q'), app.Stop).
Bind0(bind.KeySequence('r'), toggleMessageReadStatus)
When directly working with tview primitives that are not part of custom widget implementations, the following works well so far:
textView := tview.NewTextView().
SetWordWrap(true).
SetText("âŠ")
SetScrollable(true)
textView.SetInputCapture((&bind.KeyBindings{}).
Bind0(bind.KeySequence('q'), app.Stop).
Bind1(bind.KeySequence('g', 'g'), func(*tcell.EventKey) *tcell.EventKey {
return tcell.NewEventKey(tcell.KeyHome, 0, tcell.ModNone)
}).
Capture)
I need to sleep on this some more.
Also, writing very long messages like this one is really not all that fun in ttâs editor. I should absolutely provide a way to shell out to vim.
(Took me about one and a half hours to compose, holy crap. But not only because of not using vim. Although, that might have saved me a quarter hour or so for sure. Proof-reading this message also uncovered quite a few bugs in my real documentation. So, thatâs a big win!) Good night!
@david@daiwei.me Not so keen on the mowing part. :-)
@prologic@twtxt.net Thatâs a good way to keep spammers out:
Your browser did not pass the anti-spam check! Please make sure JavaScript is enabled and try again.
It was turned on.
@david@daiwei.me Haha, great response!
@movq@www.uninformativ.de Hottest room is still at 24°C. But that will change in this week, no doubt. :-(
@david@daiwei.me I donât want to start the discussion again, but edits wouldnât be an issue if we had agreed on a better addressing scheme. Maybe edit more as a quiet riot. :-P
@david@daiwei.me Oh boy, that looks super yummy! :-) I want to have rain here, too!
@david@daiwei.me Exactly. Spaces are fixed, tabs always break the layout when the tab sizes are different.
@david@daiwei.me Hahaahaaahaaaahaaaaa, so good! :â-D
Nice product, I should probably buy it: 
+00:00 vs Z should be treated as equivalent UTC đ€Šââïž I'll take a look at the timestamp parsing in Yarnd đ§
@prologic@twtxt.net For what itâs worth, the twt hash extension is specifically modeled after yarndâs implementation with all the quirks coming from Goâs stdlib: https://twtxt.dev/exts/twt-hash.html#timestamp-format
âAll timezones representing UTC must be formatted using the designated Zulu indicator Z rather than the numeric offsets +00:00 or -00:00. If the timestamp does not explicitly include any timezone information, it must be assumed to be in UTC.â
<tab> (white space) between the timestamps and posts look a bit shorter than the ones from jenny? just noticed that and thought maybe it's someting you'd want to know.
@aelaraji@aelaraji.com @david@daiwei.me @prologic@twtxt.net It depends on the tab size, but often, a tab aligns the following character to next column that is a multiple of eight.
1 8 |16 |24 |32
2026-07-12T08:11:34+02:00 Here goes the text
2026-07-12T06:11:34Z Here goes the text
@david@daiwei.me Oh no, what a giant waste of time. :-(
@arne@uplegger.eu Diese Karten sind ja echt winzig. :-)
Aber da fĂ€llt mir ein, ich sollte mir auch mal wieder ein Taschenmesser zulegen. Hab ich es doch ĂŒber all die Jahre geschafft, alle schlussendlich zu verlieren.
@david@daiwei.me Ta, I continued my fun with studying the tcell and cbind code bases for key bindings. My plan is to eventually not only support custom key bindings in the tt configuration file, but also to enable multi-key sequences, such as gg to jump to the top of a list/tree. Or use other vim-like navigation movements like 7j or 25gg etc.
And it turns out there are only a hand full oft tcell/cbind version combinations that work together. Only if all stars align, thereâs chance of success. I will probably end up pulling cbind in to simplify my life. There are situations where tcell.EventKeyâs triple of key, modifiers and rune are not all that intuitive to me. Letâs see.
@prologic@twtxt.net Well, 15 shows the site. On the left, I had a roll mat on a tarp. I borrowed some âNVA tarpsâ from the scouts for this trip. The scouts got them from the National Peopleâs Army, the German Democratic Republicâs armed forces after Germany was reunited. Theyâre 1.75m x 1.75m in size and weigh 1.3kg, quite heavy, but super awesome. One tarp on the bottom, another one to cover up the clothes, shoes and sleeping bag in order to protect against the thaw. Finally, a mosquito net over all that, hung from a rope between two trees.
My mate just used a hammock with a mozzie net on the right hand side. The third tarp served as the luxurious bedside carpet. :-)
We sat on my second tarp to chill and enjoy the sunset and surroundings. It was nice to notice birds etc. die down. It took a really long time for the last light to fade away. Since we have a very high risk of forest fires, we of course couldnât have a camp fire. But after all the exhaustion, I didnât even miss it for one second.
Since we had dinner at home before leaving, all we brought were two lye rolls, two grain rolls, two brezels, some sausage and chocolate biscuits for breakfast. From the 2.5l of water, I ended up using 2l. Itâs always good to have a little extra, despite the unnecessary weight. We had brekkie a few kilometers further on a bench in the shade. The first bench was already in direct sun.
Our camp site was maybe 30m to the side and a few meters down of a summit path hidden behind some trees and bushes. We were quite lucky, the other side of the hill got quite a bit of a breeze at night. We could hear the leaved treetops making much more noise behind us.
@movq@www.uninformativ.de Yes, these kind of dogs should really be strictly forbidden!
Itâs not illegal if you own the forest or ask the owner. :-)
@david@daiwei.me Yeah, no clue. But my mate said the dog is disqualified from such adventures in the future. :-)
The temps were supposed to hit 14°C just before sunrise. Since we didnât bring a thermometer, I canât tell for sure. I was rather hot in my sleeping bag, so I had to pull out my arms every now and then. My mateâs sleeping bag was a little lighter and, unfortunately, the zipper jammed up. Since it didnât close all the way, it felt quite a bit cold I was told in the morning. When we got up at 6ish (we said, we donât care about time at all), it was probably already 16°C if not more. I brought a jumper, but a t-shirt was already nice enough to wear. The jumper just served as my pillow. The mercury raised by the minute then.
Yeah, I circled the spot with a biro to keep an eye on it. Until now, thereâs absolutely nothing to see. Looks like I got lucky.
We slept in the forest. It was really great except of my mateâs fucking terror dog who was barking and snarling the entire night to each and every sound. I had maybe half an hour of sleep in total. Despite that, it was pleasantly warm. Well, the night, that is. The heat was brutal during the days. Literally streams of sweat were running down on us on the way there in the evening and back in the morning.
Surprisingly, there werenât any mozzies around at night, I would have lost all safe bets. On the way there, my mate convinced me to take a shortcut through the taller and taller growing grass. Itâs been some time that somebody traveled on this track, so we had to search around a bit for the overgrown path where we could cross the mostly dried up creek. In the beginning I said that this will be a bad idea. Lo and behold, I discovered a tick on my inner upper leg the next morning. Luckily, I got it out with my tick hook on the first attempt.
@bender@twtxt.net Immediately reminded me of the German childrenâs song âLaurentia, liebe Laurentia meinâ: https://www.youtube.com/watch?v=3Q0aky9FvLc
Have a nice weekend!
@prologic@twtxt.net Iâm glad you like it. :-)
@bender@twtxt.net I bet thatâs true!
@bender@twtxt.net Nice job! Without the comparison of the after photo, the grass doesnât look all that tall before. :-D But there sure was one or the other centimeter chopped off.
@movq@www.uninformativ.de What a desaster.
@bender@twtxt.net Thanks! I wanted that to never end as well. :-)
@movq@www.uninformativ.de Even way lower than that.
@prologic@twtxt.net @bender@twtxt.net @movq@www.uninformativ.de @aelaraji@aelaraji.com Success!
@david@daiwei.me Some entries can be probably simplified with just *bot*. :-) (But I donât use Caddy, so no idea about case (in)sensitivity.
That reminds me, I should do something similar with my Nginx.
@aelaraji@aelaraji.com I do use XMPP. But only the text chat part. ;-)
@movq@www.uninformativ.de Hier hab ich zum GlĂŒck ĂŒberhaupt gar nichts davon mitbekommen.
Very hot above 30°C, but luckily also incredibly cloudy and a lot of wind. Thatâs what we got today. My mate and I went on a quick stroll this evening and got a surprise killer sunset: https://lyse.isobeef.org/abendhimmel-2026-07-07/
@bender@twtxt.net Iâm glad to announce that Lyseâs Free Nose Cleaning Service is now internationally available.
@movq@www.uninformativ.de Congrats! :-)
@movq@www.uninformativ.de There is nothing like that on Linux, because you donât need it. Everything just works!
@prologic@twtxt.net Very nice! Which boat is yours? :-)
@arne@uplegger.eu Whoah! âSchaffung eines Aufenthaltsraumes fĂŒr Nichtraucher!â Irre, dass es einen solchen vor dem 1. Mai 1975 nicht gab. Kann man sich heute ĂŒberhaupt nicht vorstellen.
Cool, schönes Heftchen hast Du da gesetzt. :-) Die Lochkartenanzahlen sind auch der absolute Wahnsinn.
@itsericwoodward@itsericwoodward.com @bender@twtxt.net Oh, I missed that. Whoopsy daisy!
@kiwu@twtxt.net Hanging on by a thread is plenty good enough for many spiders, so it should be sufficient for you, too!!1!
@bender@twtxt.net I, too, should take a nap now.
Set/GetDisabled(âŠ) and PasteHandler(), tt starts up fine and seems to work without issues.
@movq@www.uninformativ.de @bender@twtxt.net Indeed! No idea why this isnât the default in the first place.
@itsericwoodward@itsericwoodward.com Twtxthashgeddon, hahahaha, brilliant. :-D
Set/GetDisabled(âŠ) and PasteHandler(), tt starts up fine and seems to work without issues.
After updating to tview 0.42.0, I also sadly noticed, that the tview.Modal now clears the background and doesnât simply draw over the already present widget. So, I decided to write my own Dialog widget. This endeavor lead me down the path to actually bring back a custom Button implementation, too. When the button is focused, it surrounds the button text with [ and ]. When not in focus, the brackets are removed. Much better than before (https://twtxt.net/conv/qx3vz4a):

I also use the same buttons in the compose view, too.
Great news, thank you! I can confirm, it looks good so far. After your change, the crawler requests every hour and five minutes: :-)
2026-07-04T14:03:09+02:00 200
2026-07-04T15:08:07+02:00 304
2026-07-04T16:13:08+02:00 304
2026-07-04T17:18:07+02:00 304
2026-07-04T18:23:07+02:00 304
2026-07-04T19:28:07+02:00 304
@bender@twtxt.net Thanks, mate!
On the back of the bench, the badge says: âGestiftet Verein berg hohenstaufen Göppingen 2013â. I read that as the Mt. Hohenstaufen club donated the bench itself: 
On the front of the bench, the badge says: âGestiftet von Hildegard Schuster, Gesellschafterin der Schwarz-Gruppe, Firma Wacklerâ. The bronze lady was donated by a shareholder of the Schwarz group, specifically the local Wackler trucking and logistics company. Clip of 27 in original resolution: 
The book itself reads: âZur Erinnerung an Ralph Kobzaâ Itâs in memory of the sales manager of the art foundry next town that created also this statue. My mate took this photo: 