aboutsummaryrefslogtreecommitdiff
path: root/module/util/config.scm
blob: 462ed1d0fd1fd291131a00e2fe1491646e7b6c5f (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
;;; Commentary:

;; This file should define all global configurable variables which
;; doesn't belong anywhere else. The config module should then import
;; this module, and set all configs as needed. The config module
;; should also be able to set configs gotten from other parts.

;;; Code:

(define-module (util config)
  :use-module (srfi srfi-1)
  :use-module (srfi srfi-9)
  :use-module (srfi srfi-26)
  :use-module (ice-9 match)
  :use-module (ice-9 format)
  :use-module (ice-9 curried-definitions) ; for ensure
  :use-module (util)
  :export (define-config)
)

(define-once config-values (make-hash-table))
(define-once config-properties (make-hash-table))
(hashq-set! config-properties #:description (make-object-property))
(hashq-set! config-properties #:source-module (make-object-property))
(hashq-set! config-properties #:pre (make-object-property))
(hashq-set! config-properties #:post (make-object-property))

(define-public (get-property config-name property-key)
  ((hashq-ref config-properties property-key) config-name))

(define (define-config% name default-value kwargs)
  (for (key value) in (group kwargs 2)
       (set! ((or (hashq-ref config-properties key)
                  (error "Missing config protperty slot " key))
              name)
         value))
  (set-config! name (get-config name default-value)))

(define-syntax define-config
  (syntax-rules ()
    ((_ name default kwargs ...)
     (define-config% (quote name) default
       (list source-module: (current-module)
             kwargs ...)))))

(define-public (set-config! name value)
  (hashq-set! config-values name
              (aif (get-property name #:pre)
                   (or (it value) (error "Pre crashed for" name))
                   value))

  (awhen (get-property name #:post)
         (it value)))
;; unique symbol here since #f is a valid configuration value.
(define %uniq (gensym))
(define*-public (get-config key optional: (default %uniq))
  (if (eq? default %uniq)
      (let ((v (hashq-ref config-values key %uniq)))
        (when (eq? v %uniq)
          (error "Missing config" key))
        v)
      (hashq-ref config-values key default)))

(define-public ((ensure predicate) value)
  (if (not (predicate value))
      #f value))



;; (format-procedure (lambda (x y) ...)) => λx, y
;; (define (f x) ...)
;; (format-procedure f) => f(x)
(define (format-procedure proc)
  ((aif (procedure-name proc)
        (lambda (s) (string-append (symbol->string it) "(" s ")"))
        (lambda (s) (string-append "λ" s)))
   (let ((args ((@ (ice-9 session) procedure-arguments)
                proc)))
     (string-join
      (remove null?
              (list
               (awhen ((ensure (negate null?))
                       (assoc-ref args 'required))
                      (format #f "~{~a~^, ~}" it))
               (awhen ((ensure (negate null?))
                       (assoc-ref args 'optional))
                      (format #f "[~{~a~^, ~}]" it))
               (awhen ((ensure (negate null?))
                       (assoc-ref args 'keyword))
                      (format #f "key: ~{~a~^, ~}"
                              (map keyword->symbol
                                   (map car it))))
               (awhen ((ensure (negate null?))
                       (assoc-ref args 'rest))
                      (format #f "~a ..." it))))
      ", "))))

(export format-procedure)

(define-public (get-configuration-documentation)
  (define groups
    (group-by (match-lambda [(__ v)
                             (if (config? v)
                                 (get-source-module v)
                                 #f)])
              (hash-map->list list config-values )) )


  `(*TOP*
    (header "Configuration variables")
    (dl
     ,@(concatenate
        (for (module values) in groups
             `((dt "") (dd (header ,(format #f "~a" (module-name module))))
               ,@(concatenate
                  (for (key value) in values
                       `((dt ,key)
                         (dd (p (@ (inline)) ,(get-documentation value)))
                         (dt "V:")
                         (dd ,(let ((v (get-value value)))
                                (if (procedure? v)
                                    (format-procedure v)
                                    `(scheme ,v)))
                             (br)))))))))))