130 lines
3.7 KiB
Scheme
130 lines
3.7 KiB
Scheme
;;; (gulie config) — configuration loading and merging
|
|
;;;
|
|
;;; Reads .gulie.sexp from project root (or CLI-specified path),
|
|
;;; merges with built-in defaults, and provides config accessors.
|
|
|
|
(define-module (gulie config)
|
|
#:use-module (ice-9 rdelim)
|
|
#:use-module (srfi srfi-1)
|
|
#:export (default-config
|
|
load-config
|
|
merge-configs
|
|
config-ref
|
|
config-line-length
|
|
config-indent-width
|
|
config-max-blank-lines
|
|
config-enabled-rules
|
|
config-disabled-rules
|
|
config-ignore-patterns
|
|
config-indent-rules
|
|
generate-template))
|
|
|
|
(define default-config
|
|
'((line-length . 80)
|
|
(indent . 2)
|
|
(max-blank-lines . 2)
|
|
(enable . ())
|
|
(disable . ())
|
|
(ignore . ())
|
|
(indent-rules
|
|
(define . 1)
|
|
(define* . 1)
|
|
(define-public . 1)
|
|
(define-syntax . 1)
|
|
(define-syntax-rule . 1)
|
|
(define-module . 0)
|
|
(define-record-type . 1)
|
|
(lambda . 1)
|
|
(lambda* . 1)
|
|
(let . 1)
|
|
(let* . 1)
|
|
(letrec . 1)
|
|
(letrec* . 1)
|
|
(let-values . 1)
|
|
(if . special)
|
|
(cond . 0)
|
|
(case . 1)
|
|
(when . 1)
|
|
(unless . 1)
|
|
(match . 1)
|
|
(match-lambda . 0)
|
|
(match-lambda* . 0)
|
|
(syntax-case . 2)
|
|
(syntax-rules . 1)
|
|
(with-syntax . 1)
|
|
(begin . 0)
|
|
(do . 2)
|
|
(parameterize . 1)
|
|
(guard . 1)
|
|
(with-exception-handler . 1)
|
|
(call-with-values . 1)
|
|
(receive . 2)
|
|
(use-modules . 0)
|
|
(with-fluids . 1)
|
|
(dynamic-wind . 0))))
|
|
|
|
(define (config-ref config key . default)
|
|
"Look up KEY in CONFIG alist, returning DEFAULT if not found."
|
|
(let ((pair (assq key config)))
|
|
(if pair
|
|
(cdr pair)
|
|
(if (null? default) #f (car default)))))
|
|
|
|
(define (config-line-length config)
|
|
(or (config-ref config 'line-length) 80))
|
|
|
|
(define (config-indent-width config)
|
|
(or (config-ref config 'indent) 2))
|
|
|
|
(define (config-max-blank-lines config)
|
|
(or (config-ref config 'max-blank-lines) 2))
|
|
|
|
(define (config-enabled-rules config)
|
|
(or (config-ref config 'enable) '()))
|
|
|
|
(define (config-disabled-rules config)
|
|
(or (config-ref config 'disable) '()))
|
|
|
|
(define (config-ignore-patterns config)
|
|
(or (config-ref config 'ignore) '()))
|
|
|
|
(define (config-indent-rules config)
|
|
(or (config-ref config 'indent-rules) '()))
|
|
|
|
(define (load-config path)
|
|
"Load a .gulie.sexp config file at PATH. Returns an alist."
|
|
(if (and path (file-exists? path))
|
|
(call-with-input-file path
|
|
(lambda (port)
|
|
(let ((data (read port)))
|
|
(if (list? data) data '()))))
|
|
'()))
|
|
|
|
(define (merge-configs base override)
|
|
"Merge OVERRIDE config on top of BASE. Override wins for scalar values;
|
|
lists are replaced, not appended."
|
|
(let lp ((result base)
|
|
(pairs override))
|
|
(if (null? pairs)
|
|
result
|
|
(let ((pair (car pairs)))
|
|
(lp (assq-set! (list-copy result) (car pair) (cdr pair))
|
|
(cdr pairs))))))
|
|
|
|
(define (find-config-file start-dir)
|
|
"Search upward from START-DIR for .gulie.sexp. Returns path or #f."
|
|
(let lp ((dir start-dir))
|
|
(let ((candidate (string-append dir "/.gulie.sexp")))
|
|
(cond
|
|
((file-exists? candidate) candidate)
|
|
((string=? dir "/") #f)
|
|
(else (lp (dirname dir)))))))
|
|
|
|
(define (generate-template port)
|
|
"Write a template .gulie.sexp to PORT."
|
|
(display ";;; gulie configuration\n" port)
|
|
(display ";;; Place this file as .gulie.sexp in your project root.\n" port)
|
|
(display ";;; All fields are optional — defaults are shown below.\n\n" port)
|
|
(write default-config port)
|
|
(newline port))
|