-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdialog.rkt
156 lines (139 loc) · 7.73 KB
/
dialog.rkt
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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#lang racket
(require racket/generator)
(require racket/string)
(require "system.rkt")
(provide toggle-todos add-todo edit-todos menu)
; displays a menu
(define menu
(lambda ()
(let* ([window-options (list "--no-items" "--title" "YATΛ!" "--menu" "Main Menu" WINDOW-HEIGHT WINDOW-WIDTH "5")]
[item-options (list "Toggle Todos" "New Todo" "Remove Completed" "Edit Todo" "Quit")]
[arguments (append window-options item-options)])
(dialog->string arguments))))
; takes a list of (tag item status)s
; returns the new state of the todo list after toggling
(define toggle-todos
(lambda (todo-list)
(let* ([menu-heigth (number->string (length todo-list))]
[window-options (list "--title" "YATΛ!" "--checklist" "Toggle Todos" WINDOW-HEIGHT WINDOW-WIDTH menu-heigth)]
[todo-list-options (todo-list->shell-options todo-list)]
[arguments (append window-options todo-list-options)]
[checked-indicies (dialog->string arguments)])
(cond [(non-empty-string? checked-indicies)
(map cdr ; removes the index again
; returns todo-list with completed field true or false based on the complted indices list
(apply-status
(zip-with-index
(sort todo-list #:key caddr <) 1)
; '("1" "3" "4") -> '(1 3 4)
(map string->number
; "1 3 4" -> '("1" "3" "4")
(string-split checked-indicies))))]
; if the toggle-dialog returns a empty string usually means the dialog got cancelled
; could also mean that no todo is checked -> check issues
[else #f]))))
(define add-todo (lambda ()
(let ([add-todo-text-options (list "--clear" "--title" "YATΛ!" "--inputbox" "New Todo: Content" WINDOW-HEIGHT WINDOW-WIDTH)]
[add-todo-priority-options (list "--clear" "--title" "YATΛ!" "--menu" "New Todo: Priority" WINDOW-HEIGHT WINDOW-WIDTH "3" "1" "High" "2" "Medium" "3" "Low")])
; capture the result of the todo-text dialog as text
(let* ([text (dialog->string add-todo-text-options)]
; pass text to this immediatly invoked lambda
[priority ((lambda (previous-dialog-passed?)
; which assigns the result of the priority-dialog to priority if the text-dialog didn't get cancelled
(cond [previous-dialog-passed? (dialog->string add-todo-priority-options)]
; if the text-dialog got cancelled don't even display the priority-dialog
[else #f]))
(non-empty-string? text))])
; if the priority-dialog didn't get cancelled
(cond [(non-empty-string? priority)
; return a new todo item
(list text #f (string->number priority))]
; otherwise return false
[else #f])))))
; todo-list (unindexed) -> todo-list (unindexed)
(define edit-todos
(lambda (todo-list)
; if the todo-list is smaller than 6 let the menu-heigth be 3*size, else 18
(let* ([menu-heigth (number->string((lambda (x) (if (> x 6) 18 (* x 3)))(length todo-list)))]
; using 19 as heigth makes 4 items fit on the screen in --inputmenu mode
[window-options (list "--title" "YATΛ!" "--inputmenu" "Edit Todos" "19" WINDOW-WIDTH menu-heigth)]
[todo-list-options (todo-list->index-content-pair todo-list)]
[arguments (append window-options todo-list-options)]
; returns something like RENAMED 1 new todo content
[changes (dialog->string arguments)])
(cond [(string=? (car (string-split changes)) "RENAMED")
(let ([changed-index (string->number(cadr (string-split changes)))]
; TODO: refactor to (substring changes (+ (index-of changed-index) (length changed-index)))
[new-content (substring changes 10)])
(rename-at-with todo-list changed-index new-content))]
[else #f]))))
(define rename-at-with
(lambda (todo-list index content)
(let ([sorted (zip-with-index-from-1 (sort-by-prio todo-list))])
(map
(lambda (todo-item)
(cond [(= (string->number(car todo-item)) index) (list* content (cddr todo-item))]
[else (cdr todo-item)]))
sorted))))
; curry for convenience
(define zip-with-index-from-1
(lambda (lst)
(zip-with-index lst 1)))
(define sort-by-prio
(λ (todo-list)
(sort todo-list #:key caddr <)))
; returns todo-list with completed field true or false based on the complted indices list
(define apply-status
(lambda (todo-list completed-indices)
; map over todo itmes
(map (lambda (todo-item)
; if the todo item's index is member of the completed indicies
(cond [(member (string->number(car todo-item)) completed-indices)
; set it's completed status to true
(list-set todo-item 2 #t)]
[else
(list-set todo-item 2 #f)]))
todo-list)))
; to todo-list->shell-options -> sanitize to use as argument. ex: #f to OFF
(define argify-status (lambda (todo) (if (cadr todo)
(cons (car todo) "ON")
(cons (car todo) "OFF"))))
; TODO: refactor todo-list->shell-options to operate on single todo-item and call map in todo-list
; returns a whiptail/dialog compatible arguemnt string from a todo-list
; ("1st todo" #f 4) -> "1" "1st todo" "OFF"
(define todo-list->shell-options (lambda (todo-list)
(flatten
(zip-with-index
; replace #t and #f with ON and OFF
(map argify-status
(map (lambda (todo-item)
; only take title and completed field
(take todo-item 2))
; sort by priority
(sort todo-list #:key caddr <)))
1))))
; TODO Refactor/combine with shell-options
(define todo-list->index-content-pair (lambda (todo-list)
(flatten
(zip-with-index
; replace #t and #f with ON and OFF
(map (lambda (todo-item)
; only take title
(car todo-item))
; sort by priority
(sort todo-list #:key caddr <))
1))))
; (zip-with-index '("@" "!" "%") 3) -> '(3 . "@") (4 . "!") (5 . "%"))
(define zip-with-index (lambda (lst start-index)
; define a generators of natural integers starting from start-index
(letrec ([naturals (sequence->generator (in-naturals start-index))]
[zip-with-naturals (lambda (lst)
(cond ((empty? lst) empty)
(else (cons
; cons (1 "a")
(cons
(number->string(naturals))
(car lst))
; with the recursive call on the lst's tail
(zip-with-naturals(cdr lst))))))])
(zip-with-naturals lst))))