line wrapping
Three-part suggestion.
One, add --width to khal list.
Two, add a configurable continuation indent to the wrapping (textwrap does have subsequent_indent, but the indent should not be highlighted, so you’ll probably wish to do it manually in color_wrap).
Three, make things actually line up. Right now, I have:
Today, 12.08.2025
↔ Urlaub $name
⇥ testgt2 mit einem sehr langen Namen lorem ipsum dolor und so weiter und so fort et cetera etm…
↔ Urlaub $othername
testgttermin mit einem sehr langen Namen lorem ipsum dolor und so weiter und so fort et cetera etm…
Tomorrow, 13.08.2025
↔ Urlaub $othername
17:00:00-18:00:00 Testtermin mit einem sehr langen Namen lorem ipsum dolor und so weiter und so fort et cetera etm…
I’d suggest adding • before nōn-range whole-day events and • before nōn-whole-day events, so they line up, plus continuation indent:
Today, 12.08.2025
↔ Urlaub $name
⇥ testgt2 mit einem sehr langen Namen lorem ipsum dolor und so weiter
und so fort et cetera etm…
↔ Urlaub $othername
• testgttermin mit einem sehr langen Namen lorem ipsum dolor und so
weiter und so fort et cetera etm…
Tomorrow, 13.08.2025
↔ Urlaub $othername
• 17:00:00-18:00:00 Testtermin mit einem sehr langen Namen lorem ipsum
dolor und so weiter und so fort et cetera etm…
For the ASCII case, of course equivalent, just wider indent.
In this case, you might not even need the continuation indent configurable, but OTOH since people can change the formatting, you may wish to keep it so.
PoC (definitely not PR-worthy, inlines Unicode):
--- khalendar/event.py~ 2025-08-12 17:35:27.202768626 +0200
+++ khalendar/event.py 2025-08-12 17:38:21.466616269 +0200
@@ -706,6 +706,13 @@
else:
attributes['start-end-time-style'] = ''
+ attributes['start-end-time-style-indented'] = attributes['start-end-time-style']
+ if allday:
+ if not attributes['start-end-time-style-indented']:
+ attributes['start-end-time-style-indented'] = '‣'
+ else:
+ attributes['start-end-time-style-indented'] = '• ' + attributes['start-end-time-style-indented']
+
if allday:
attributes['end-necessary'] = ''
attributes['end-necessary-long'] = ''
Turns out that using ‣ ipv • for whole-day events (closer to the range symbols) to differentiate looks better.
(And, yes, next I’ll fix my date/time formats.)
PoC for the line wrapping (I didn’t add the option because I don’t have the time to learn about click right now, but if you like my PoCs I can probably make a PR with better versions):
--- cli.py~ 2025-08-12 17:48:28.758595369 +0200
+++ cli.py 2025-08-12 17:49:56.490521171 +0200
@@ -189,6 +189,7 @@
daterange=daterange,
once=once,
notstarted=notstarted,
+ width=79,
conf=ctx.obj['conf'],
env={"calendars": ctx.obj['conf']['calendars']},
json=json
--- utils.py~ 2025-08-12 17:49:58.562519425 +0200
+++ utils.py 2025-08-12 17:51:07.614461014 +0200
@@ -100,6 +100,8 @@
lines[num] += RESET
if (num + 1) < len(lines):
lines[num + 1] = sgr + lines[num + 1]
+ if (num + 1) < len(lines):
+ lines[num + 1] = ' ' + lines[num + 1]
return lines
I did quickly look into not counting the colour escapes (relatively easy, as they all go from ESC to m in khal), but then we also need wcwidth(3), and while there are Python3 libraries that implement-ish a wcwidth-like function, they don’t use the same width data as the system libc (and therefore screen and xterm) does, and as such are unsuitable, so I decided to leave the colour escapes in while wrapping to overestimate the per-line character count so the occasional fullwidth character won’t make it fail.
To solve this properly, we’ll need to call out to libc, which is going to be iffy. Reimplementing the width calculation means updating it all the time, and then it’ll be out of sync if locale data gets updated anyway, so I’d advice against doing so.
I guess one alternative would be to output to JSON and then format that myself.