From 3fc94fdf6b056a8f2ef812d4479619752fdd99c2 Mon Sep 17 00:00:00 2001 From: Nikolay Puzanov Date: Tue, 20 May 2014 16:14:35 +0400 Subject: [PATCH] Rewrite deadlines code. Add zsh autocompletion. Add symlink to worktimer.scm --- timer | 1 + worktimer.scm | 827 ++++++++++++++++++++++-------------------- zsh-completion/_timer | 69 ++++ 3 files changed, 508 insertions(+), 389 deletions(-) create mode 120000 timer create mode 100644 zsh-completion/_timer diff --git a/timer b/timer new file mode 120000 index 0000000..f558191 --- /dev/null +++ b/timer @@ -0,0 +1 @@ +worktimer.scm \ No newline at end of file diff --git a/worktimer.scm b/worktimer.scm index 33f1785..930cdd0 100755 --- a/worktimer.scm +++ b/worktimer.scm @@ -37,11 +37,12 @@ ;;; PROJECT/TASK/SUBTASK/ETC: [START_TIME] - [STOP_TIME] - DURATION ;;; Hardcoded timesheet filename -(define ts-file (string-append (getenv "HOME") "/.timesheet")) -(define dl-file (string-append (getenv "HOME") "/.deadlines")) +(define ts-file (string-append (getenv "HOME") "/.timesheet-new")) (define date-time-format "~Y-~m-~d ~H:~M:~S") (define date-format "~Y-~m-~d") +;;; ========================= COMMON HELPER FUNCTIONS ========================== + ;;; Find substring separated by ch-start and ch-end. ;;; (substring/find str ch-start ch-end [begin end]) ;;; If ch-start is #f, select substring from beginning of string. @@ -57,7 +58,16 @@ (if (not cs) (reverse strings) (loop (cons (substring str (1+ cs) ce) strings) (1+ ce))))))))) -;;; Convert time-difference to string "hh:mm:ss" +;;; Remove duplicates in list +(define (remove-dup list) + (reverse + (fold (lambda (x l) + (if (or (null? l) + (not (equal? (car l) x))) + (cons x l) l)) + '() list))) + +;;; Convert time to string "hh:mm:ss" (define (time->string td) (let ((sec (time-second td))) (let* ((h (quotient sec 3600)) @@ -68,6 +78,32 @@ (format #f "~2,'0d" m) ":" (format #f "~2,'0d" s))))) +;;; Convert string "hh:mm:ss" to time +(define (string->time str) + (let ((splitted (string-split str #\:))) + (if (not (= (length splitted) 3)) + (throw 'bad-time-string "Bad time format (expected hh:mm:ss)" str) + (let ((h (string->number (car splitted))) + (m (string->number (cadr splitted))) + (s (string->number (caddr splitted)))) + (if (and (and h m s) (< m 60) (< s 60)) + (make-time 'time-duration 0 + (+ (* h 3600) (* m 60) s)) + (throw 'bad-time-string "Bad time string" str)))))) + +;;; Convert string to date or time +;;; Time is "hh:mm:ss", date is date-format +(define (string->date/time str) + (if (string-any #\: str) + (string->time str) + (string->date str date-format))) + +;;; Convert date or time to string +(define (date/time->string time) + (if (date? time) + (date->string time date-format) + (time->string time))) + ;;; Convert path to string (define (path->string path) (let loop ((path path) @@ -91,49 +127,6 @@ (loop (cons (substring str path-start item-end) path) (1+ item-end))))))) -;;; Parse task string and return list: -;;; '((list of path elements) start-date stop-date duration) -(define (parse-task-string str) - (let ((str (string-trim-both str))) - (if (or (zero? (string-length str)) - (equal? (string-ref str 0) #\#)) - #f - (let ((path - (let ((path-end (string-index str #\:))) - (if (not path-end) #f - (path-split str 0 path-end)))) - (dates (substring/find str #\[ #\]))) - (if (or (not path) (not dates) (null? dates)) - #f - (let ((date-start (string->date (car dates) date-time-format))) - (let-values (((date-end duration) - (if (null? (cdr dates)) - (values #f #f) - (let* ((date-end (string->date (cadr dates) date-time-format)) - (duration (time-difference - (date->time-utc date-end) - (date->time-utc date-start)))) - (values date-end duration))))) - (list path date-start date-end duration)))))))) - -;;; Read file and parse it line by line. -;;; Returns list of parsed lines. -(define (read-and-parse-file filename lineparser) - (if (file-exists? filename) - (call-with-input-file filename - (lambda (port) - (let loop ((recs '())) - (let ((line (get-line port))) - (if (eof-object? line) - (reverse recs) - (loop (let ((item (lineparser line))) - (if item (cons item recs) recs)))))))) - '())) - -;;; Parse timesheet file and return list of tasks -(define (read-timesheet filename) - (read-and-parse-file filename parse-task-string)) - ;;; Compare paths (define (pathtime-utc a)) + (tb (date->time-utc b))) + (timetime-utc d1) (date->time-utc d2))) -;;; Print timesheet item -(define (print-task task . now) - (let ((path (car task)) - (sdate (cadr task)) - (edate (caddr task)) - (duration (cadddr task)) - (now (if (null? now) #f (car now)))) - (let-values (((edate duration) - (if edate - (values edate duration) - (if now - (values now (date-difference now sdate)) - (values #f #f))))) - (format #t "~a: [~a]" - (path->string path) - (date->string sdate date-time-format)) - (if edate - (format #t " - [~a] - ~a\n" - (date->string edate date-time-format) - (time->string duration)) - (newline))))) - -;;; Print timesheet -(define (print-timesheet timesheet) - (for-each print-task timesheet)) - -;;; Report is a tree of projects items. -;;; Root of the tree is super-project with name "ROOT": -;;; ("ROOT" d -;;; ("PROJ1" d -;;; ("P1-TASK1" d -;;; ("P1-T1-SUBTASK1" d) -;;; ("P1-T1-SUBTASK2" d)) -;;; ("P1-TASK2" d))) -(define (make-report timesheet) - ;; Add task duration to project branch - (define (tree-add-duration project-tree path duration) - (let tree-walk ((tree project-tree) - (path path)) - ;; Add task duration - (set-car! (cdr tree) (add-duration (cadr tree) duration)) - - ;; Search next leaf corresponding to path item - (if (null? path) - project-tree - (let ((item (find - (lambda (i) (string= (car i) (car path))) - (cddr tree)))) - (if item - (tree-walk item (cdr path)) - - ;; Add new branch (or leaf) to tree - (let ((add-items - (let add-item-loop ((add-items '()) - (path (reverse path))) - (if (null? path) - add-items - (add-item-loop - (if (null? add-items) - (list (car path) duration) - (list (car path) duration add-items)) - (cdr path)))))) - (set-cdr! (cdr tree) (cons add-items (cddr tree))) - project-tree)))))) - ;; END tree-add-duration - - (let loop ((projects (list "Overall" (make-time 'time-duration 0 0))) - (timesheet timesheet)) - (if (null? timesheet) - projects ; TODO Sort projects by path - (let* ((task (car timesheet)) - (path (car task)) - (start (cadr task)) - (duration (cadddr task))) - (loop (tree-add-duration projects path - (if duration duration - (date-difference (current-date) start))) - (cdr timesheet)))))) - - ;;; Dates is in same day? (define (same-month? d1 d2) (and @@ -325,37 +197,27 @@ (let ((jd (date->julian-day date))) (+ jd (- 7 (remainder-and-rest jd 7))))))) -;;; Print report -(define (print-report report) - (let ((deadlines (read-deadlines dl-file))) - (let walk ((tree report) - (level 0) - (path '())) - (when (not (null? tree)) - (format #t "~v_~a: ~a" level (car tree) - (time->string (cadr tree))) +;;; ========================= PROJECT SPECIFIC HELPERS ========================= - (let ((dl (find-by-path deadlines path))) - (when dl - (let ((time (cadr dl))) - (if (date? time) - (begin - (format #t " -- DEADLINE AT ~a" (date/time->string time)) - (when (timetime-utc time) - (date->time-utc (current-date))) - (format #t " (expired)"))) - (begin - (format #t " -- DEADLINE TIME ~a" (date/time->string time)) - (if (timestring (time-difference time (cadr tree)))))))))) - (newline) - - (for-each - (lambda (l) - (walk l (+ level 2) (append path (list (car l))))) - (cddr tree)))))) +;;; Find task or deadline by path +(define (find-by-path sheet path) + (find (lambda (x) (equal? (car x) path)) sheet)) + +;;; Compare deadlines by path +(define (deadlinetime str) - (let ((splitted (string-split str #\:))) - (if (not (= (length splitted) 3)) - (throw 'bad-time-string "Bad time format (expected hh:mm:ss)" str) - (let ((h (string->number (car splitted))) - (m (string->number (cadr splitted))) - (s (string->number (caddr splitted)))) - (if (and (and h m s) (< m 60) (< s 60)) - (make-time 'time-duration 0 - (+ (* h 3600) (* m 60) s)) - (throw 'bad-time-string "Bad time string" str)))))) +;;; Returns unique path names of record lists +(define (record-path-list records . more) + (remove-dup + (sort + (let loop ((recs (apply append (cons records more))) + (tasklist '())) + (if (null? recs) tasklist + (loop (cdr recs) + (let fold-path ((path (caar recs)) + (spath "") + (tasklist tasklist)) + (if (null? path) tasklist + (let ((spath (string-append + spath + (if (zero? (string-length spath)) "" "/") + (car path)))) + (fold-path (cdr path) spath + (cons spath tasklist)))))))) + stringdate/time str) - (if (string-any #\: str) - (string->time str) - (string->date str date-format))) +;;; Returns unique task names +(define (record-name-list records . more) + (remove-dup + (sort + (map (lambda (x) (path->string (car x))) + (apply append (cons records more))) + stringstring time) - (if (date? time) - (date->string time date-format) - (time->string time))) +;;; ========================= PROJECT MAIN FUNCTIONS ========================== + +;;; Parse task string and return list: +;;; '((list of path elements) start-date stop-date|#f duration|#f) +(define (parse-task-string str) + (let ((str (string-trim-both str))) + (if (or (zero? (string-length str)) + (equal? (string-ref str 0) #\#)) + #f + (let ((path + (let ((path-end (string-index str #\:))) + (if (not path-end) #f + (path-split str 0 path-end)))) + (dates (substring/find str #\[ #\]))) + (if (or (not path) (not dates) (null? dates)) + #f + (let ((date-start (string->date (car dates) date-time-format))) + (let-values (((date-end duration) + (if (null? (cdr dates)) + (values #f #f) + (let* ((date-end (string->date (cadr dates) date-time-format)) + (duration (time-difference + (date->time-utc date-end) + (date->time-utc date-start)))) + (values date-end duration))))) + (list path date-start date-end duration)))))))) ;;; Deadline file format ;;; PROJECT/TASK/ETC: DATE|TIME +;;; Returns list '((list of path elements) date|time) (define (parse-deadline-string str) (let ((colon (string-index str #\:))) (if (not colon) #f @@ -419,38 +311,207 @@ (let ((time (string->date/time time))) (list path time))))))) + +;;; Read timesheet and deadlines +(define (read-timesheet filename) + (if (file-exists? filename) + (call-with-input-file filename + (lambda (port) + (let loop ((record-type 'unknown) + (timerecords '()) + (deadlines '())) + (let ((line (get-line port))) + (if (eof-object? line) + (values (remove-dup + (sort timerecords timerecordstring (car dline)) (date/time->string (cadr dline)))) -;;; Read deadline records from file -(define (read-deadlines filename) - (sort - (read-and-parse-file filename parse-deadline-string) - (lambda (a b) - (let loop ((pa (car a)) - (pb (car b))) - (if (and (null? pa) (null? pb)) #f - (if (null? pa) #t - (if (null? pb) #f - (if (string=? (car pa) (car pb)) - (loop (cdr pa) (cdr pb)) - (string< (car pa) (car pb)))))))))) +;;; Print timesheet record +(define (print-timerecord task . now) + (let ((path (car task)) + (sdate (cadr task)) + (edate (caddr task)) + (duration (cadddr task)) + (now (if (null? now) #f (car now)))) + (let-values (((edate duration) + (if edate + (values edate duration) + (if now + (values now (date-difference now sdate)) + (values #f #f))))) + (format #t "~a: [~a]" + (path->string path) + (date->string sdate date-time-format)) + (if edate + (format #t " - [~a] - ~a\n" + (date->string edate date-time-format) + (time->string duration)) + (newline))))) -;;; Print deadline records -(define (print-deadlines dlines) - (for-each (lambda (x) (print-deadline x)) dlines)) +;;; Print timerecords +(define (print-timerecords timesheet) + (for-each print-timerecord (sort timesheet timerecordstring (cadr tree)) + (let ((deadline (caddr tree))) + (cond + ;; deadline is date + ((date? deadline) + (string-append + " -- deadline at " + (date/time->string deadline) + (if (datestring deadline) + (if (timestring + (time-difference deadline (cadr tree))) ")")))) + + ;; no deadline + (else "")))) + + (for-each + (lambda (l) + (walk l (+ level 2))) + (cdddr tree))))) ;;; ================================ COMMANDS ================================== ;;; Start new task. Returns new sheet with started task or #f if nothing started. -(define (cmd-start-task sheet . params) +(define (cmd-start-task sheet deadlines . params) (let* ((last (last-task sheet)) (path (if (null? params) (if last (car last) #f) @@ -460,28 +521,28 @@ (begin (format (current-error-port) "Not specified task path. No tasks in the sheet.\n") - #f) + (values #f #f)) (begin (stop-task last) (let-values (((sheet task) (new-task sheet path))) (format #t "--- NEW TASK RUN\n") - (print-task task) - sheet))))) + (print-timerecord task) + (values sheet deadlines)))))) ;;; Stop a running task. Returns new sheet or #f if nothing to stop. -(define (cmd-stop-task sheet . params) +(define (cmd-stop-task sheet deadlines . params) (let ((last (last-task sheet))) (if (stop-task last) (begin (format #t "--- STOP TASK\n") - (print-task last) - sheet) + (print-timerecord last) + (values sheet deadlines)) (begin (format (current-error-port) "Nothing to stop\n") - #f)))) + (values #f #f))))) ;;; Print report -(define (cmd-report sheet . params) +(define (cmd-report sheet deadlines . params) (format #t "--- REPORT") (let ((sheet (if (null? params) sheet @@ -525,118 +586,104 @@ sheet))))) (newline) (print-report - (make-report sheet))) + (add-deadlines-to-report! + (make-report sheet) deadlines))) (let ((last (last-task sheet))) (when last (format #t "\n--- ~a TASK\n" (if (caddr last) "LAST STOPPED" "RUNNING")) - (print-task last (current-date)))) - #f) + (print-timerecord last (current-date)))) + (values #f #f)) ;;; Print all tasks -(define (cmd-tasklist sheet . unused) - (format - #t "~{~a ~}\n" - (let loop ((sheet sheet) - (tasklist '())) - (if (null? sheet) tasklist - (loop (cdr sheet) - (let fold-path ((path (caar sheet)) - (spath "") - (tasklist tasklist)) - (if (null? path) tasklist - (let ((spath (string-append - spath - (if (zero? (string-length spath)) "" "/") - (car path)))) - (fold-path (cdr path) spath - (if (find (lambda (x) (string=? x spath)) tasklist) - tasklist - (cons spath tasklist)))))))))) - - #f) +(define (cmd-tasklist sheet deadlines . unused) + (format #t "~{~a ~}\n" (record-path-list sheet deadlines)) + (values #f #f)) + +;;; Print deadlines +(define (cmd-deadlist sheet deadlines . unused) + (format #t "~{~a ~}\n" (record-name-list deadlines)) + (values #f #f)) ;;; Deadlines -(define (cmd-deadline sheet . args) - (let ((dlines (read-deadlines dl-file))) - (let ((new-dlines - (let* ((arg0 (if (null? args) #f (car args))) - (arg1 (if (and arg0 (not (null? (cdr args)))) (cadr args) #f)) - (arg2 (if (and arg1 (not (null? (cddr args)))) (caddr args) #f)) - (last (last-task sheet))) - (cond - ;; Add deadline - ((equal? arg0 "set") - (if (not arg1) - (begin (format #t "Not specified date/time of deadline\n") #f) - (let-values (((task time) - (if arg2 - (values (path-split arg1) - (string->date/time arg2)) - (values (if last (car last) #f) - (string->date/time arg1))))) - (if (not task) +(define (cmd-deadline sheet deadlines . args) + (let ((deadlines + (let* ((arg0 (if (null? args) #f (car args))) + (arg1 (if (and arg0 (not (null? (cdr args)))) (cadr args) #f)) + (arg2 (if (and arg1 (not (null? (cddr args)))) (caddr args) #f)) + (last (last-task sheet))) + (cond + ;; Add deadline + ((equal? arg0 "set") + (if (not arg1) + (begin (format #t "Not specified date/time of deadline\n") #f) + (let-values (((task time) + (if arg2 + (values (path-split arg1) + (string->date/time arg2)) + (values (if last (car last) #f) + (string->date/time arg1))))) + (if (not task) + (begin + (format #t "Not specified task path.\n") + #f) + (let ((dl (find-by-path deadlines task))) + (if dl + (begin (set-car! (cdr dl) time) deadlines) + (append deadlines (list (list task time))))))))) + + ;; Delete deadline + ((equal? arg0 "clear") + (call/cc + (lambda (break-del) + (let ((task (if arg1 + (path-split arg1) + (if (null? last) + (begin (format #t "Not specified task path.\n") (break-del #f)) + (car last))))) + (fold-right + (lambda (x l) + (if (equal? (car x) task) (begin - (format #t "Not specified task path.\n") - #f) - (let ((dl (find-by-path dlines task))) - (if dl - (begin (set-car! (cdr dl) time) dlines) - (append dlines (list (list task time))))))))) + (format #t "Deleted ~a: ~a\n" + (path->string (car x)) + (date/time->string (cadr x))) + l) + (cons x l))) + '() deadlines))))) - ;; Delete deadline - ((equal? arg0 "clear") - (call/cc - (lambda (break-del) - (let ((task (if arg1 - (path-split arg1) - (if (null? last) - (begin (format #t "Not specified task path.\n") (break-del #f)) - (car last))))) - (fold-right - (lambda (x l) - (if (equal? (car x) task) - (begin - (format #t "Deleted ~a: ~a\n" - (path->string (car x)) - (date/time->string (cadr x))) - l) - (cons x l))) - '() dlines))))) - - ;; Show all deadlines - ((equal? arg0 "all") - (print-deadlines dlines) - #f) - - ;; Show deadline for task - (else - (let ((task (if arg0 - (path-split arg0) - (if (null? last) - (begin (format #t "--- SHOW ALL DEADLINES\n") `()) - (car last))))) - (for-each - (lambda (dl) - (when (let loop ((p1 task) - (p2 (car dl))) - (if (null? p1) #t - (if (null? p2) #f - (if (not (string=? (car p1) (car p2))) #f - (loop (cdr p1) (cdr p2)))))) - (print-deadline dl))) - dlines)) - #f))))) - - (when new-dlines - (with-output-to-file dl-file - (lambda () (print-deadlines new-dlines)))))) - #f) + ;; Show all deadlines + ((equal? arg0 "all") + (print-deadlines deadlines) + #f) + + ;; Show deadline for task + (else + (let ((task (if arg0 + (path-split arg0) + (if (null? last) + (begin (format #t "--- ALL DEADLINES\n") `()) + (car last))))) + (for-each + (lambda (dl) + (when (let loop ((p1 task) + (p2 (car dl))) + (if (null? p1) #t + (if (null? p2) #f + (if (not (string=? (car p1) (car p2))) #f + (loop (cdr p1) (cdr p2)))))) + (print-deadline dl))) + deadlines)) + #f))))) + (if deadlines + (values sheet deadlines) + (values #f #f)))) ;;; ================================ MAIN FUNCTION ================================== + (define (main cmdl) (let ((command (cdr cmdl))) - (let-values (((sheet deadlines) (read-timesheet1 ts-file))) + (let-values (((sheet deadlines) (read-timesheet ts-file))) (if (null? command) ;; Show running task @@ -651,48 +698,50 @@ ;; Else run command (let ((param (cdr command)) (command (car command))) - (let ((new-sheet - (apply (cond - ((string= command "start") cmd-start-task) - ((string= command "stop") cmd-stop-task) - ((string= command "report") cmd-report) - ((string= command "refresh") (lambda (s . p) s)) - ((string= command "tasklist") cmd-tasklist) - ((string= command "deadline") cmd-deadline) - - ;; ----------------------- Show usage ------------------------- ;; - (else - (with-output-to-port (current-error-port) - (lambda () - (format #t "Usage: ~a [command]\n" (car cmdl)) - (format #t "Commands:\n") - (format #t " start [TASK] Start new task. If no task, use last runned task\n") - (format #t " stop Stop task\n") - (format #t " report Show report\n") - (format #t " report day [DATE] Show report for today or DATE\n") - (format #t " report week [DATE] Show report for current week or week of DATE\n") - (format #t " report month [DATE] Show report for current month or month of DATE\n") - (format #t " report TASK Show report for project\n") - (format #t " deadline set [TASK] DATE|+TIME Add deadline for project (or for last task)\n") - (format #t " deadline clear [TASK] Remove deadline for project (or for last task)\n") - (format #t " deadline [TASK] Show deadline for project\n") - (format #t " deadline all Show all deadlines\n") - (format #t " refresh Refresh worksheet file after manual edit\n") - (format #t " (no command) Show running task and timer\n\n") - (format #t "DATE format: YYYY-mm-dd\n") - (format #t "TIME format: HH-MM-SS\n") - (newline))) - (lambda (s . p) #f))) - (cons sheet param)))) + (let-values + (((sheet' deadlines') + (apply + (cond + ((string= command "start") cmd-start-task) + ((string= command "stop") cmd-stop-task) + ((string= command "report") cmd-report) + ((string= command "refresh") (lambda (s d . p) (values s d))) + ((string= command "deadline") cmd-deadline) + ((string= command "tasklist") cmd-tasklist) + ((string= command "deadlist") cmd-deadlist) + + ;; ----------------------- Show usage ------------------------- ;; + (else + (with-output-to-port (current-error-port) + (lambda () + (format #t "Usage: ~a [command]\n" (car cmdl)) + (format #t "Commands:\n") + (format #t " start [TASK] Start new task. If no task, use last runned task\n") + (format #t " stop Stop task\n") + (format #t " report Show report\n") + (format #t " report day [DATE] Show report for today or DATE\n") + (format #t " report week [DATE] Show report for current week or week of DATE\n") + (format #t " report month [DATE] Show report for current month or month of DATE\n") + (format #t " report TASK Show report for project\n") + (format #t " deadline set [TASK] DATE|TIME Add deadline for project (or for last task)\n") + (format #t " deadline clear [TASK] Remove deadline for project (or for last task)\n") + (format #t " deadline [TASK] Show deadline for project\n") + (format #t " deadline all Show all deadlines\n") + (format #t " refresh Refresh worksheet file after manual edit\n") + (format #t " (no command) Show running task and timer\n\n") + (format #t "DATE format: YYYY-mm-dd\n") + (format #t "TIME format: HH:MM:SS\n") + (newline))) + (lambda (s d . p) (values #f #f)))) + (cons* sheet deadlines param)))) ;; ----------------------- Save new sheet ------------------------- ;; (when (and - (list? new-sheet) - (not (null? new-sheet))) + (list? sheet') + (not (null? sheet'))) (with-output-to-file ts-file (lambda () - (print-timesheet new-sheet)))))))))) + (print-timesheet sheet' deadlines')))))))))) ;;; JUST DO IT! -;(main (command-line)) - +(main (command-line)) diff --git a/zsh-completion/_timer b/zsh-completion/_timer new file mode 100644 index 0000000..e7bd8a6 --- /dev/null +++ b/zsh-completion/_timer @@ -0,0 +1,69 @@ +#compdef timer + +_timer() { + + typeset -A opt_args + + _arguments \ + '1: :->command' \ + '2: :->arg1' \ + '3: :->arg2' \ + '4: :->arg3' + + case "$state" in + (command) + _arguments '1:commands:(start stop report deadline refresh help)' + ;; + + (arg1) + case $words[2] in + (start) + compadd $(timer tasklist) + ;; + (report) + compadd day week month $(timer tasklist) + ;; + (deadline) + compadd set clear all $(timer deadlist) + ;; + esac + ;; + + (arg2) + case $words[2] in + (report) + case $words[3] in + (day) + compadd $(date +"%Y-%m-%d") + ;; + (week) + compadd $(date +"%Y-%m-%d") + ;; + (month) + compadd $(date +"%Y-%m-%d") + ;; + esac + ;; + (deadline) + case $words[3] in + (set) + compadd $(timer tasklist) $(date +"%Y-%m-%d") + ;; + (clear) + compadd $(timer deadlist) + ;; + esac + ;; + esac + ;; + + (arg3) + if [ "$words[2]" = "deadline" ] + then + compadd $(date +"%Y-%m-%d") + fi + ;; + esac +} + +_timer "$@"