Skip to content

Commit 00e3f62

Browse files
committed
Write CLI
1 parent 644678c commit 00e3f62

File tree

5 files changed

+117
-8
lines changed

5 files changed

+117
-8
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@
44
.DS_Store
55
compiled/
66
/doc/
7+
*.svg

cli.rkt

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
#lang racket/base
2+
3+
(provide DEFAULT-OUTPUT-DIRNAME)
4+
5+
(require racket/cmdline
6+
racket/file
7+
racket/path
8+
racket/string
9+
file/convertible
10+
"main.rkt")
11+
12+
; The manual also uses this constant.
13+
(define DEFAULT-OUTPUT-DIRNAME "mind-maps-out")
14+
15+
(module+ main
16+
(define force? #f)
17+
(define << printf)
18+
(define dest-dir (build-path (current-directory) DEFAULT-OUTPUT-DIRNAME))
19+
20+
(command-line
21+
#:program "mind-map"
22+
#:once-each
23+
[("--dest")
24+
user-dest-dir
25+
"Set the output directory"
26+
(set! dest-dir (read-user-path user-dest-dir))]
27+
[("-f" "--force")
28+
"Overwrite output files, if they exist."
29+
(set! force? #t)]
30+
[("-q" "--quiet")
31+
"Suppress messages on STDOUT"
32+
(set! << void)]
33+
#:args mind-map-paths
34+
35+
; Validate user arguments.
36+
(when (null? mind-map-paths)
37+
(eprintf "No mind-maps specified.~n")
38+
(exit 1))
39+
40+
(define unreadable
41+
(for/fold ([dne null])
42+
([mm (in-list mind-map-paths)])
43+
(if (and (file-exists? mm)
44+
(member 'read (file-or-directory-permissions mm)))
45+
dne
46+
(cons mm dne))))
47+
48+
(unless (null? unreadable)
49+
(eprintf "These files are not readable:~n~a~n"
50+
(string-join (reverse (map (λ (p) (format " ~a" p)) unreadable)) "\n"))
51+
(exit 1))
52+
53+
; Read input files
54+
(define parse-trees
55+
(for/list ([mm (in-list mind-map-paths)])
56+
(cond [(has-lang? mm)
57+
(<< "Loading Racket module ~a~n" mm)
58+
(dynamic-require mm 'thoughts)]
59+
[else
60+
(<< "Loading text file ~a~n" mm)
61+
(call-with-input-file mm
62+
(λ (in) (read-thoughts in)))])))
63+
64+
; Write output files
65+
(make-directory* dest-dir)
66+
(for ([thoughts (in-list parse-trees)]
67+
[mm (in-list mind-map-paths)])
68+
(define output-path (build-path dest-dir (path-replace-extension (file-name-from-path mm) #".svg")))
69+
(if (or force? (not (file-exists? output-path)))
70+
(call-with-output-file output-path #:exists 'truncate/replace
71+
(λ (o) (write-bytes (convert (thoughts->pict thoughts) 'svg-bytes) o)
72+
(<< "Wrote ~a~n" output-path)))
73+
(<< "Skipped ~a~n" output-path)))))
74+
75+
(define (has-lang? path)
76+
(call-with-input-file path
77+
(λ (in) (regexp-match? #px"^\\s*#lang\\s+mind-map\\s+" in))))
78+
79+
(define (read-user-path user-path)
80+
(define p (string->path user-path))
81+
(cond [(file-exists? p)
82+
(eprintf "Expected ~a to be a directory, but it's a file.~n" p)
83+
(exit 1)]
84+
[else p]))

info.rkt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,5 @@
66
(define pkg-desc "Write and render mind maps in Racket")
77
(define version "0.0")
88
(define pkg-authors '(sage))
9+
(define raco-commands
10+
'(("mind-map" (submod mind-map/cli main) "Build mind maps" #f)))

main.rkt

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,3 @@
7777
(require mind-map)
7878
(provide thoughts)
7979
(define thoughts 'parse-tree)))))
80-
81-
(module+ main
82-
(require racket/cmdline)
83-
(command-line
84-
#:program "mind-map"
85-
#:args mind-maps
86-
(displayln mind-maps)))

scribblings/mind-map.scrbl

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
racket/base
44
racket/contract
55
racket/sequence]
6-
racket/runtime-path]
6+
racket/runtime-path
7+
mind-map/cli]
78

89
@title{Creating Mind Maps in Racket}
910
@author{Sage Gerard}
@@ -164,6 +165,34 @@ The indentation error can be fixed by replacing the tab with a space,
164165
or by replacing one space with a tab in all indented lines.
165166
}
166167

168+
@section{@tt{raco mind-map}}
169+
170+
The @tt{mind-map} collection includes a @tt{raco} command of the same
171+
name. The command will parse text files given as command line
172+
arguments and save the rendered mind maps to SVG files. Currently,
173+
any failure results in exit code 1.
174+
175+
@verbatim|{$ raco mind-map path/to/mind-map.rkt path/to/notes.txt}|
176+
177+
As implied in the above command line, the input files do not have to be
178+
Racket modules. If the file starts with @litchar{#lang mind-map}, then
179+
it will be loaded as a Racket module. Otherwise it will be read as a
180+
plain text file using @racket[read-thoughts].
181+
182+
By default, the command will render the SVG documents in a
183+
@tt[@DEFAULT-OUTPUT-DIRNAME] directory, relative to the command's working
184+
directory. You can override this directory with @litchar{--dest}.
185+
186+
@verbatim|{$ raco mind-map --dest other-dir ...}|
187+
188+
The command will not overwrite any files unless forced. Set @litchar{-f}
189+
or @litchar{--force} to overwrite any conflicting files.
190+
191+
By default, the command will print its activity on STDOUT. Use
192+
@litchar{--quiet} or @litchar{-q} to suppress STDOUT messages.
193+
194+
Run @tt{raco mind-map -h} to review these options.
195+
167196

168197
@section{Project Information}
169198

0 commit comments

Comments
 (0)