From e822f7b81245c919eda8bd8ad4b482df075e0508 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=B6rnquist?= Date: Fri, 24 Jan 2020 20:21:41 +0100 Subject: Start of new date structures. --- module/entry-points/ical.scm | 8 +- module/entry-points/terminal.scm | 9 +- module/output/ical.scm | 4 +- module/output/terminal.scm | 31 +-- module/srfi/srfi-19/alt.scm | 348 +++++++++++++++++++++++++++++++++ module/srfi/srfi-19/alt/util.scm | 107 ++++++++++ module/srfi/srfi-19/util.scm | 28 --- module/vcomponent/datetime.scm | 25 ++- module/vcomponent/group.scm | 4 +- module/vcomponent/load.scm | 6 +- module/vcomponent/parse.scm | 36 ++-- module/vcomponent/recurrence/parse.scm | 7 +- module/vulgar/components.scm | 6 +- 13 files changed, 528 insertions(+), 91 deletions(-) create mode 100644 module/srfi/srfi-19/alt.scm create mode 100644 module/srfi/srfi-19/alt/util.scm (limited to 'module') diff --git a/module/entry-points/ical.scm b/module/entry-points/ical.scm index 87b4a6fe..375613a3 100644 --- a/module/entry-points/ical.scm +++ b/module/entry-points/ical.scm @@ -5,8 +5,8 @@ :use-module ((vcomponent) :select (load-calendars*)) :use-module ((parameters) :select (calendar-files)) :use-module (ice-9 getopt-long) - :use-module (srfi srfi-19) - :use-module (srfi srfi-19 util) + :use-module (srfi srfi-19 alt) + :use-module (srfi srfi-19 alt util) ) (define opt-spec @@ -20,7 +20,9 @@ (define start (cond [(option-ref opts 'from #f) => parse-freeform-date] [else (start-of-month (current-date))])) (define end (cond [(option-ref opts 'to #f) => parse-freeform-date] - [else (normalize-date* (set (date-month start) = (+ 1)))])) + ;; [else (normalize-date* (set (month start) = (+ 1)))] + [(date+ start (date month: 1))] + )) ;; TODO this contains repeated events multiple times (define-values (calendars regular repeating) diff --git a/module/entry-points/terminal.scm b/module/entry-points/terminal.scm index 45f9b8eb..df15116c 100644 --- a/module/entry-points/terminal.scm +++ b/module/entry-points/terminal.scm @@ -3,8 +3,8 @@ :use-module (output terminal) :use-module (vcomponent) :use-module (ice-9 getopt-long) - :use-module (srfi srfi-19) - :use-module (srfi srfi-19 util) + :use-module (srfi srfi-19 alt) + :use-module (srfi srfi-19 alt util) :use-module (parameters) :use-module (vulgar) ) @@ -20,9 +20,8 @@ calendar-files: (cond [(option-ref opts 'file #f) => list] [else (calendar-files)]) )) - (let ((time (date->time-utc - (drop-time (or (and=> (option-ref opts 'date #f) parse-freeform-date) - (current-date)))))) + (let ((time (drop-time (or (and=> (option-ref opts 'date #f) parse-freeform-date) + (current-date))))) ;; (format (current-error-port) "len(events) = ~a~%" (stream-length events)) (with-vulgar (lambda () (main-loop time events)))) diff --git a/module/output/ical.scm b/module/output/ical.scm index 6fedc391..c7a6503c 100644 --- a/module/output/ical.scm +++ b/module/output/ical.scm @@ -4,8 +4,8 @@ :use-module (util) :use-module (vcomponent) :use-module (srfi srfi-1) - :use-module (srfi srfi-19) - :use-module (srfi srfi-19 util) + :use-module (srfi srfi-19 alt) + :use-module (srfi srfi-19 alt util) :use-module (srfi srfi-41) :use-module (srfi srfi-41 util) ) diff --git a/module/output/terminal.scm b/module/output/terminal.scm index 8b113c82..ece11a4b 100644 --- a/module/output/terminal.scm +++ b/module/output/terminal.scm @@ -2,8 +2,8 @@ #:use-module (output general) #:use-module (output text) #:use-module (srfi srfi-1) - #:use-module (srfi srfi-19) - #:use-module (srfi srfi-19 util) + #:use-module (srfi srfi-19 alt) + #:use-module (srfi srfi-19 alt util) #:use-module (srfi srfi-26) #:use-module (srfi srfi-41) #:use-module (srfi srfi-41 util) @@ -63,7 +63,7 @@ (define (displayln a) (display a) (newline)) -(define (main-loop time event-stream) +(define (main-loop date event-stream) (define cur-event 0) (define-values (height width) (get-terminal-size)) @@ -74,14 +74,14 @@ ;; TODO reusing the same grouping causes it to lose events. ;; I currently have no idea why, but it's BAD. (let ((groups (get-groups-between grouped-stream - (time-utc->date time) (time-utc->date time)))) + date date))) (format (current-error-port) "len(groups) = ~a~%" (stream-length groups)) (let ((events (if (stream-null? groups) '() (group->event-list (stream-car groups))))) (cls) - (display-calendar-header! (time-utc->date time)) + (display-calendar-header! date) (let* ((date-width 20) (location-width 15) @@ -103,8 +103,16 @@ (attr ev 'SUMMARY) (or (and=> (attr ev 'LOCATION) (cut string-append "\x1b[1mPlats:\x1b[m " <> "\n")) "") - (time->string (attr ev 'DTSTART) "~1 ~3") - (time->string (attr ev 'DTEND) "~1 ~3") + (let ((start (attr ev 'DTSTART))) + (if (datetime? start) + (string-append (date->string (date start)) + (time->string (time start))) + (date->string (date start)))) + (let ((end (attr ev 'DTEND))) + (if (datetime? start) + (string-append (date->string (date end)) + (time->string (time end))) + (date->string (date end)))) (unlines (take-to (flow-text (or (attr ev 'DESCRIPTION) "") #:width (min 70 width)) (- height 8 5 (length events) 5)))))) @@ -114,13 +122,13 @@ ;; "c = ~c (~d)~%" char (char->integer char)) (case char ((#\L #\l) - (set! time (add-day time) + (set! time (add-day date) cur-event 0)) ((#\h #\H) - (set! time (remove-day time) + (set! time (remove-day date) cur-event 0)) ((#\t) - (set! time (date->time-utc (drop-time (current-date))) + (set! time (current-date) cur-event 0)) ((#\j #\J) (unless (= cur-event (1- (length events))) (mod! cur-event 1+))) @@ -128,7 +136,8 @@ (mod! cur-event 1-))) ((#\p) (print-vcomponent (list-ref events cur-event) (current-error-port))) - ((#\E) (serialize-vcomponent (list-ref events cur-event) (open-output-file "/tmp/event.ics"))) + ((#\E) (serialize-vcomponent (list-ref events cur-event) + (open-output-file "/tmp/event.ics"))) ((#\e) (let ((fname (tmpnam))) (with-output-to-file fname diff --git a/module/srfi/srfi-19/alt.scm b/module/srfi/srfi-19/alt.scm new file mode 100644 index 00000000..b3e8a478 --- /dev/null +++ b/module/srfi/srfi-19/alt.scm @@ -0,0 +1,348 @@ +(define-module (srfi srfi-19 alt) + :export (date? year month day + hour minute second + time? datetime? + ) + + :use-module (srfi srfi-1) + :use-module (srfi srfi-9) + :use-module (srfi srfi-9 gnu) + :use-module (ice-9 match) + + :use-module (util) + ) + +(define-many define-public + (jan january ) 1 + (feb february ) 2 + (mar mars ) 3 + (apr april ) 4 + (may ) 5 + (jun june ) 6 + (jul july ) 7 + (aug august ) 8 + (sep september ) 9 + (oct october ) 10 + (nov november ) 11 + (dec december ) 12 + ) + +(define-immutable-record-type + (make-date year month day) + date? + (year year) (month month) (day day)) + +(set-record-type-printer! + + (lambda (r p) + (format p "~4'0d­~2'0d­~2'0d" + (year r) (month r) (day r)))) + +(define*-public (date key: (year 0) (month 0) (day 0)) + (make-date year month day)) + + +;; int -> bool +(define-public (leap-year? year) + (and (zero? (remainder year 4)) + (or (zero? (remainder year 400)) + (not (zero? (remainder year 100)))))) + +;; Returns number of days month for a given date. Just looks at the year and month components. +(define-public (days-in-month date) + (case* (month date) + ((jan mar may jul aug oct dec) 31) + ((apr jun sep nov) 30) + ((feb) + (if (leap-year? (year date)) + 29 28)))) + +(define-public (days-in-year date) + (if (leap-year? (year date)) + 366 365)) + +;; 2020-01-10 + 0-0-30 = 2020-02-09 +;; 10 + 30 = 40 ; day + day +;; 40 > 31 ; target days > days in month +;; 2020-02-00 + 0-0- (40 - 31) ; +;; 2020-02-09 + +(define-public (date= a b) + (and (= (year a) (year b)) + (= (month a) (month b)) + (= (day a) (day b)))) + +(define-public date=? date=) + +(define (date+% base change) + + ;; while (day base) > (days-in-month base) + ;; month++; days -= (days-in-month base) + (define days-fixed + (let loop ((target (set (day base) = (+ (day change))))) + (if (> (day target) (days-in-month target)) + (loop (set-> target + (month = (+ 1)) + (day = (- (days-in-month target))))) + target))) + + ;; while (month base) > 12 + ;; year++; month -= 12 + (define months-fixed + (let loop ((target (set (month days-fixed) = (+ (month change))))) + (if (> (month target) 12) + (loop (set-> target + (year = (+ 1)) + (month = (- 12)))) + target))) + + (set (year months-fixed) = (+ (year change)))) + +(define-public (date+ base . rest) + (fold date+% base rest)) + +(define-public (date- base change) + + (define-values (days-fixed change*) + (let loop ((target base) (change change)) + (if (>= (day change) (day target)) + (loop (set-> target + (month = (- 1)) + (day (days-in-month (set (month target) = (- 1))))) + (set (day change) = (- (day target)))) + (values (set (day target) = (- (day change))) + (set (day change) 0))))) + + (define-values (month-fixed change**) + (let loop ((target days-fixed) (change change*)) + (if (>= (month change) (month target)) + (loop (set-> target + (year = (- 1)) + (month 12)) + (set (month change) = (- (month target)))) + (values (set (month target) = (- (month change))) + (set (month change) 0))))) + + ;; change** should here should have both month and date = 0 + + (set (year month-fixed) = (- (year change)))) + +(define-public (time- base change) + + (define-values (second-fixed change*) + (let loop ((target base) (change change)) + (if (> (second change) (second target)) + (loop (set-> target + (minute = (- 1)) + (second 60)) + (set (second change) = (- (second target)))) + (values (set (second target) = (- (second change))) + (set (second change) 0))))) + + (define-values (minute-fixed change**) + (let loop ((target second-fixed) (change change*)) + (if (> (minute change) (minute target)) + (loop (set-> target + (hour = (- 1)) + (minute 60)) + (set (minute change) = (- (minute target)))) + (values (set (minute target) = (- (minute change))) + (set (minute change) 0))))) + + ;; change** should here should have both month and date = 0 + + (set (hour month-fixed) = (- (hour change))) + ) + + + +(define-immutable-record-type