forked from racket/zuo
-
Notifications
You must be signed in to change notification settings - Fork 0
/
tree.zuo
78 lines (69 loc) · 2.62 KB
/
tree.zuo
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
#lang zuo
;; This module implements a simple version of the `tree` program,
;; which shows the content of a directory in tree form.
;; Another script could use this `tree` function...
(provide tree)
;; ... but if this script is the main one passed to Zuo,
;; then the `main` submodule is run, which parses command-line
;; arguments and call `tree`.
(module+ main
;; Imitates Racket's `command-line` form, but we have to explicitly
;; thread through `accum`, because there's no state
(command-line
:init (hash) ; initial accumulator (but `(hash)` is the default, anyway)
:once-each
;; Each flag clause starts with the accumulator id
[accum ("-a") "Include names that start with `.`"
(hash-set accum 'all? #t)]
[accum ("-h") "Show file sizes human-readable"
(hash-set accum 'h-size? #t)]
:args ([dir "."])
(lambda (accum) ; args handler as procedure to receive the accumulator
(if (directory-exists? dir)
(tree dir
(hash-ref accum 'all? #f)
(hash-ref accum 'h-size? #f))
(error (~a (hash-ref (runtime-env) 'script)
": no such directory: "
dir))))))
;; Recur using `ls` to get a directory's content
(define (tree dir show-all? show-size?)
(displayln dir)
(let tree ([dir dir] [depth 0])
(define elems (sort (ls dir) string<?))
(let in-dir ([elems (if show-all? elems (filter not-dot? elems))])
(unless (null? elems)
(define elem (car elems))
(define elem-path (build-path dir elem))
(define s (stat elem-path))
(let loop ([depth depth])
(unless (= depth 0)
(display "│ ")
(loop (- depth 1))))
(if (null? (cdr elems))
(display "└─ ")
(display "├─ "))
(when show-size?
(display (~a "[" (human-readable (hash-ref s 'size)) "] ")))
(displayln elem)
(when (eq? (hash-ref s 'type) 'dir)
(tree elem-path (+ depth 1)))
(in-dir (cdr elems))))))
(define not-dot?
(let ([dot? (glob->matcher ".*")])
(lambda (s) (not (dot? s)))))
;; Arithmetic is not Zuo's strong suit, since it supports only
;; 64-bit signed integers
(define (human-readable n)
(define (decimal n)
(define d (quotient 1024 10))
(define dec (quotient (+ (modulo n 1024) (quotient d 2)) d))
(~a (quotient n (* 1024)) "." dec))
(define s
(cond
[(< n 1024) (~a n)]
[(< n (quotient (* 1024 1024) 10)) (~a (decimal n) "K")]
[else (~a (decimal (quotient n 1024)) "M")]))
(if (< (string-length s) 4)
(~a (substring " " (string-length s)) s)
s))