blob: 0c83a4a88986cffb56e71b0a6cf6f45c3502c564 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
|
#!/usr/bin/guile \
-e main -s
!#
(add-to-load-path (dirname (current-filename)))
(use-modules (srfi srfi-1)
(srfi srfi-19)
(srfi srfi-19 util)
(srfi srfi-26)
(ice-9 format)
(texinfo string-utils) ; string->wrapped-lines
(util)
(vcalendar)
(vcalendar datetime)
(vcalendar output)
(terminal escape)
(terminal util))
(define (take-to lst i)
(if (> i (length lst))
lst (take lst i)))
;;; ------------------------------------------------------------
#; (define pizza-event (search cal "pizza"))
(define (trim-to-width str len)
(let ((trimmed (string-pad-right str len)))
(if (< (string-length trimmed)
(string-length str))
(string-append (string-drop-right trimmed 1)
"…")
trimmed)))
; TODO show truncated string
(define (main-loop regular-events repeating-events)
(define time (date->time-utc (current-date)))
(define cur-event 0)
(let loop ((char #\nul))
(let ((events
(filter (cut event-in? <> time)
regular-events)))
(case char
;; TODO The explicit loop call is a hack to rerender the display
;; It's REALLY ugly.
((#\L #\l) (set! time (add-day time)) (set! cur-event 0) (loop #\nul))
((#\h #\H) (set! time (remove-day time)) (set! cur-event 0) (loop #\nul))
((#\j #\J) (unless (= cur-event (1- (length events)))
(set! cur-event (1+ cur-event))))
((#\k #\K) (unless (= cur-event 0)
(set! cur-event (1- cur-event)))))
(cls)
(display-calendar-header! (time-utc->date time))
;; (line)
(format #t "~a┬~a┬~a~%"
(make-string 20 #\─)
(make-string 32 #\─)
(make-string 10 #\─))
(for-each
(lambda (ev i)
(format #t "~a │ ~a~a~a~a │ ~a~a~%"
(time->string (attr ev 'DTSTART) "~1 ~3") ; TODO show truncated string
(if (= i cur-event) "\x1b[7m" "")
(color-escape (attr (parent ev) 'COLOR))
(trim-to-width (attr ev 'SUMMARY) 30)
STR-RESET
(trim-to-width
(or (attr ev 'LOCATION) "\x1b[1;30mINGEN LOKAL") 20)
STR-RESET))
events
(iota (length events)))
(format #t "~a┴~a┴~a~%"
(make-string 20 #\─)
(make-string 32 #\─)
(make-string 10 #\─))
(unless (null? events)
(let ((ev (list-ref events cur-event)))
(format #t "~a~%~aStart: ~a Slut: ~a~%~%~a~%"
(attr ev 'SUMMARY)
(or (and=> (attr ev 'LOCATION) (cut string-append "Plats: " <> "\n")) "")
(time->string (attr ev 'DTSTART) "~1 ~3")
(time->string (attr ev 'DTEND) "~1 ~3")
(string-join ; TODO replace this with a better text flower
(take-to ; This one destroys newlines used for layout
(string->wrapped-lines (or (attr ev 'DESCRIPTION) "")
#:line-width 60
#:collapse-whitespace? #f)
10)
(string #\newline))
)))
;; (format #t "c = ~c (~d)~%" char (char->integer char))
(unless (or (eof-object? char)
;; TODO this requires that `q' is pressed as many
;; times as other inputs where pressed to actually
;; quit.
;; ^C only works because it force closes the
;; program.
(memv char (list #\q (ctrl #\C))))
(loop (read-char (current-input-port)))))))
(load "config.scm")
(define (main args)
(define calendars (map make-vcomponent calendar-files))
(define events (concatenate (map (cut children <> 'VEVENT) calendars)))
(let* ((repeating regular (partition repeating? events)))
(sort*! repeating time<? (extract 'DTSTART))
(sort*! regular time<? (extract 'DTSTART))
(with-vulgar
(lambda () (main-loop regular repeating)))))
|