anatomy 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,147 @@
1
+ use(require("atomy"))
2
+
3
+ require("set")
4
+
5
+ data(Block(@content, @style = nil)):
6
+ Table(@rows)
7
+ Itemization(@elements)
8
+ NestedFlow(@blocks)
9
+ Paragraph(@content, @closed? = false)
10
+ MetaBlock(@action)
11
+ TraverseBlock(@action)
12
+ ResolveBlock(@action)
13
+ List(@elements):
14
+ OrderedList(@elements)
15
+
16
+ data(Element(@content, @style = nil)):
17
+ Target(@name)
18
+ TOC(@content)
19
+ Reference(@tag, @content = nil)
20
+ Index(@keys, @description)
21
+ TraverseElement(@action)
22
+ ResolveElement(@action)
23
+ CollectElement(@action)
24
+ RenderElement(@action)
25
+
26
+ data(Style(@type = nil, @properties = []))
27
+
28
+ data(Tag(@part, @name, @target = .self, @display = nil))
29
+
30
+ data(
31
+ Part(
32
+ -- nil or title content
33
+ @title = nil
34
+
35
+ -- the part style
36
+ @style = Style new
37
+
38
+ -- initial content before sub-parts
39
+ @body = []
40
+
41
+ -- sub-parts
42
+ @parts = []
43
+
44
+ -- parent part
45
+ @parent = nil
46
+
47
+ -- tags
48
+ -- tag -> reference
49
+ @tags = #{}
50
+ @tag-prefix = nil
51
+
52
+ -- tags that cannot be found by parents
53
+ @local-tags = #{}
54
+
55
+ -- the primary tag used for this Part
56
+ -- used for URIs
57
+ @tag = nil
58
+
59
+ -- content that is inspected during the collect pass,
60
+ -- but doesn't produce output
61
+ @to-collect = []
62
+
63
+ -- dependent assets
64
+ @assets = []
65
+
66
+ -- css files to add
67
+ @css-additions = Set new
68
+
69
+ -- omit children from table of contents
70
+ @omit-children-from-table-of-contents? = false))
71
+
72
+ def(Part set-tag(name, target = .self, display = nil)):
73
+ @tags[name] = Tag new(self, name, target, display)
74
+
75
+ def(Part set-local-tag(name, target = nil, display = nil)):
76
+ @local-tags[name] = Tag new(self, name, target, display)
77
+
78
+ def(Part toc?): style properties include?(.toc)
79
+
80
+ def(Part inspect): i"#<Part: '#{@tag name}'>"
81
+
82
+ -- search in order:
83
+ -- 1. local hidden tags
84
+ -- 2. local tags
85
+ -- 3. children
86
+ -- 1. local tags
87
+ -- 2. children
88
+ -- 4. parent
89
+ -- 1. local hidden tags
90
+ -- 2. tags
91
+ -- 3. siblings, searching in order
92
+ -- 4. parent ...
93
+ def(Part find-tag(tag, excluding = nil)):
94
+ catch(.found):
95
+ search-tag-excluding(tag, nil)
96
+ nil
97
+
98
+ def(Part search-tag-excluding(name, excluding)): do:
99
+ when(found = (@local-tags[name] || @tags[name])):
100
+ throw(.found, found)
101
+
102
+ when(name == @title):
103
+ throw(.found, @tag)
104
+
105
+ @parts each [p]:
106
+ unless(p == excluding):
107
+ p search-tag(name)
108
+
109
+ when(@parent):
110
+ @parent search-tag-excluding(name, self)
111
+
112
+ nil
113
+
114
+ -- called from find-tag; only search exposed tags and children
115
+ def(Part search-tag(name)): do:
116
+ when(name == @title):
117
+ throw(.found, @tag)
118
+
119
+ when(found = @tags[name]):
120
+ throw(.found, found)
121
+
122
+ @parts each [p]:
123
+ p search-tag(name)
124
+
125
+
126
+ def(Part top):
127
+ if(@parent)
128
+ then: @parent top
129
+ else: self
130
+
131
+ def(content?(String)): true
132
+ def(content?(Element)): true
133
+ def(content?(nil)): true
134
+ def(content?(x & Array)): x all? &.content?
135
+ def(content?(_)): false
136
+
137
+ def(sanitize(x)):
138
+ contents-of(x) gsub(r" & ", " and ")
139
+ gsub(r"\s+", "-")
140
+ gsub(r"[^[:alnum:]_\-:.]", "")
141
+ downcase
142
+
143
+ def(contents-of(s & String)): s
144
+ def(contents-of(e & Element)): contents-of(e content)
145
+ def(contents-of(b & Block)): contents-of(b content)
146
+ def(contents-of(a & Array)): a collect [x] { contents-of(x) } join
147
+ def(contents-of(nil)): ""
@@ -0,0 +1,73 @@
1
+ use(require("atomy"))
2
+
3
+ require("cgi")
4
+
5
+
6
+ data(HTMLElement(@name, @attributes = #{}, @body = nil))
7
+
8
+ fn(attr-to-pair(`.~name)): `(.class -> ~(Atomy Code StringLiteral new(name text to-s)))
9
+ fn(attr-to-pair(`#~name)): `(.id -> ~(Atomy Code StringLiteral new(name text to-s)))
10
+ fn(attr-to-pair(`(~x = ~y))): `(.~x -> ~y)
11
+
12
+ macro(<(~name)(~*attrs): ~*body):
13
+ `(HTMLElement new(
14
+ .~name
15
+ #{ ~*(attrs collect [a]: attr-to-pair(a)) }
16
+ [~*body]))
17
+
18
+ macro(<(~name): ~*body):
19
+ `(HTMLElement new(.~name, #{}, [~*body]))
20
+
21
+ macro(<(~name)(~*attrs)):
22
+ `(HTMLElement new(
23
+ .~name
24
+ #{ ~*(attrs collect [a]: attr-to-pair(a)) }
25
+ nil))
26
+
27
+ macro(<~name):
28
+ `(HTMLElement new(.~name))
29
+
30
+ data(UnescapedString(@raw))
31
+
32
+ def(UnescapedString to-s): @raw
33
+
34
+ fn(render(out, x & Array)):
35
+ x collect [y]: render(out, y)
36
+ fn(render(out, x & String)):
37
+ out << CGI escapeHTML(x)
38
+ fn(render(out, x)):
39
+ out << x to-s
40
+
41
+ stripped? = dynamic(false)
42
+
43
+ def(HTMLElement to-s):
44
+ out = ""
45
+
46
+ when(^stripped?):
47
+ render(out, @body)
48
+ return(out)
49
+
50
+ out << i"<#{@name}"
51
+
52
+ @attributes each [k, v]:
53
+ out << i" #{k}=\"#{v}\""
54
+
55
+ unless(@body):
56
+ out << " />"
57
+ return(out)
58
+
59
+ out << ">"
60
+
61
+ render(out, @body)
62
+
63
+ out << i"</#{@name}>"
64
+
65
+ out
66
+
67
+ data(StrippedTags(@body))
68
+
69
+ def(StrippedTags to-s):
70
+ with(stripped? = true):
71
+ out = ""
72
+ render(out, @body)
73
+ out
@@ -0,0 +1,130 @@
1
+ use(require("atomy"))
2
+ use(require("grammar"))
3
+
4
+ parser(Parser):
5
+ %%:
6
+ def(trim-leading(str, n)):
7
+ unless(n > 0):
8
+ return(str)
9
+
10
+ str gsub!(r"\n {0,#{n}}", "\n")
11
+
12
+ def(word(l, x)):
13
+ w = Atomy Grammar AST Word new(x)
14
+ w line = l
15
+ w
16
+
17
+ %atomy = Atomy Grammar
18
+
19
+ rule(line): { current-line }
20
+ rule(column): { current-column }
21
+
22
+ rule(comment): "{-" in-multi
23
+
24
+ rule(in-multi): [
25
+ /"[^\-\{\}]*"/ "-}"
26
+ /"[^\-\{\}]*"/ "{-" in-multi /"[^\-\{\}]*"/ "-}"
27
+ /"[^\-\{\}]*"/ /"[-{}]"/ in-multi
28
+ ]
29
+
30
+ rule(content(s)): comment? c=(chunk(s) | escaped) comment? { c }
31
+
32
+ rule(insignificant): (<(/"[^\\\{\}]+"/)> | "\\" <(/"[\\\{\}]"/)>) {
33
+ text
34
+ }
35
+
36
+ rule(chunk(s)): [
37
+ l=(line) chunk=(insignificant+) c=((&"}" | comment)?) {
38
+ text = chunk join
39
+
40
+ when(c):
41
+ text rstrip!
42
+
43
+ trim-leading(text, s)
44
+
45
+ Atomy Grammar AST StringLiteral new(text)
46
+ }
47
+
48
+ nested
49
+ ]
50
+
51
+ rule(escaped): [
52
+ l=(line) "\\" n=(%atomy(identifier)) as=(argument+) {
53
+ `((~word(l, n))(~*as))
54
+ }
55
+
56
+ l=(line) "\\" n=(%atomy(identifier)) { word(l, n) }
57
+
58
+ l=(line) "\\" "(" e=(%atomy(expression)) ")" { e }
59
+ ]
60
+
61
+ rule(leading): [
62
+ &(/"\n+"/ b=(column) /"\s+"/ a=(column)) { a - b }
63
+ { 0 }
64
+ ]
65
+
66
+ rule(nested):
67
+ l=(line) "{" s=(leading) cs=(content(s)*) "}" {
68
+ when(cs[0] is-a?(Atomy Grammar AST StringLiteral)):
69
+ cs[0] value sub!(r"^\n", "")
70
+
71
+ cs match:
72
+ []: Atomy Grammar AST StringLiteral new("")
73
+ [x]: x
74
+ _: `[~*cs]
75
+ }
76
+
77
+ rule(atomy): "[" e=(%atomy(expression)) "]" { e }
78
+
79
+ rule(argument): nested | atomy
80
+
81
+ rule(root):
82
+ l=(line) cs=(content(0)*) !_ {
83
+ setup = Array[]
84
+ definitions = Array[]
85
+
86
+ filter = [c]:
87
+ c match:
88
+ (`use(~_) | `require(~_)):
89
+ setup << c
90
+ 'nil
91
+
92
+ `(def(~x): ~*y):
93
+ definitions << c
94
+ 'nil
95
+
96
+ `let(~x, ~y):
97
+ definitions << `(~x = ~y)
98
+ 'nil
99
+
100
+ `[~*cs]:
101
+ `[~*(cs map &filter)]
102
+
103
+ _:
104
+ c
105
+
106
+ body = cs map &filter
107
+
108
+ Atomy Grammar AST Sequence new([
109
+ 'use(require("atomy"))
110
+ 'use(require("anatomy/base"))
111
+
112
+ `(do:
113
+ ~*setup
114
+ ~*definitions
115
+ def(doc): decode(~*body))
116
+ ])
117
+ }
118
+
119
+
120
+ Parser singleton:
121
+ def(parse-string(str)):
122
+ p = new(str)
123
+ unless(p parse):
124
+ p raise-error
125
+
126
+ p result
127
+
128
+ def(parse-file(path)):
129
+ File open(path, "r") [f]:
130
+ parse-string(f read)
@@ -0,0 +1,35 @@
1
+ use(require("atomy"))
2
+
3
+ require("atomy/codeloader")
4
+
5
+ pretty = require("pretty")
6
+
7
+ require("fileutils")
8
+
9
+ traverse = require("anatomy/stages/traverse")
10
+ collect = require("anatomy/stages/collect")
11
+ resolve = require("anatomy/stages/resolve")
12
+ html = require("anatomy/renderers/html")
13
+
14
+ def(process(input, renderer, output = ".")):
15
+ input = File expand-path(input)
16
+ output = File expand-path(output)
17
+
18
+ mod = Atomy CodeLoader require(input)
19
+
20
+ part = mod doc
21
+ traversed = traverse over(part)
22
+ collected = collect over(traversed)
23
+ resolved = resolve over(collected)
24
+
25
+ unless(Dir exists?(output)):
26
+ Dir mkdir(output)
27
+
28
+ unless(Dir exists?(output + "/public")):
29
+ Dir mkdir(output + "/public")
30
+
31
+ FileUtils cp-r(
32
+ File expand-path("../../../public", __FILE__) + "/."
33
+ output + "/public")
34
+
35
+ renderer render(resolved, output)
@@ -0,0 +1,306 @@
1
+ use(require("atomy"))
2
+ use(require("io"))
3
+ use(require("dynamic"))
4
+
5
+ require("json")
6
+ require("fileutils")
7
+
8
+ use(require("anatomy/html"))
9
+ data = require("anatomy/data")
10
+
11
+
12
+ fn(tag-url(t)):
13
+ t target match:
14
+ .anchor(x):
15
+ url(t part, x)
16
+
17
+ .self:
18
+ url(t part)
19
+
20
+ .url(x):
21
+ x
22
+
23
+ def(over(i & data Itemization)):
24
+ i elements collect [name, body]:
25
+ <dl:
26
+ [ <dt: over(name)
27
+ <dd: over(body)
28
+ ]
29
+ def(over(l & data List)):
30
+ <ul:
31
+ l elements collect [body]:
32
+ <li: over(body)
33
+ def(over(l & data OrderedList)):
34
+ <ol:
35
+ l elements collect [body]:
36
+ <li: over(body)
37
+ def(over(p & data Paragraph)):
38
+ <p: over(p content)
39
+ def(over(b & data Block)):
40
+ b style match:
41
+ .tt:
42
+ <pre: over(b content)
43
+
44
+ .verbatim:
45
+ <pre(.verbatim): over(b content)
46
+
47
+ .class(*classes):
48
+ <div(class = classes join(" ")): over(b content)
49
+
50
+ .header(depth):
51
+ <"h#{depth}": over(b content)
52
+
53
+ .inset:
54
+ <div(style = "margin: 0 2em 1em"): over(b content)
55
+
56
+ .centered:
57
+ <div(style = "text-align: center"): over(b content)
58
+
59
+ .margin-note:
60
+ <blockquote: over(b content)
61
+
62
+ nil:
63
+ <div: over(b content)
64
+
65
+ in-reference? = dynamic(false)
66
+
67
+ def(over(t & data Target)):
68
+ <a(name = t name): nil
69
+ def(over(p & data Reference)):
70
+ if(p tag)
71
+ then:
72
+ <a(href = tag-url(p tag)):
73
+ with(in-reference? = true):
74
+ over(p content)
75
+ else:
76
+ <a(.undefined): over(p content)
77
+ def(over(r & data ResolveElement)):
78
+ error(.did-not-resolve(r))
79
+ def(over(e & data Element)):
80
+ e style match:
81
+ .italic:
82
+ <em: over(e content)
83
+
84
+ .bold:
85
+ <strong: over(e content)
86
+
87
+ .tt:
88
+ <code: over(e content)
89
+
90
+ .superscript:
91
+ <sup: over(e content)
92
+
93
+ .subscript:
94
+ <sub: over(e content)
95
+
96
+ .smaller:
97
+ <span(style = "font-size: 80%"): over(e content)
98
+
99
+ .larger:
100
+ <span(style = "font-size: 120%"): over(e content)
101
+
102
+ .strike:
103
+ <span(style = "text-decoration: line-through"): over(e content)
104
+
105
+ .class(*classes):
106
+ <span(class = classes join(" ")): over(e content)
107
+
108
+ .hyperlink(url):
109
+ <a(href = url): over(e content)
110
+
111
+ .image(file):
112
+ <img(src = file, alt = over(e content))
113
+
114
+ .svg(file):
115
+ <object(data = file, type = "image/svg+xml", width = "100%", height = "100%"):
116
+ <param(name = "src", value = file)
117
+
118
+ .aux:
119
+ unless(^(in-reference?)):
120
+ over(e content)
121
+
122
+ def(over(nil)): nil
123
+ def(over(s & String)): s
124
+ def(over(a & Array)):
125
+ a collect [x]: over(x)
126
+
127
+
128
+ def(filename(p)): p tag name + ".html"
129
+
130
+
131
+ def(top(p)):
132
+ condition:
133
+ (p parent && p parent toc?):
134
+ p
135
+
136
+ p parent:
137
+ top(p parent)
138
+
139
+ otherwise:
140
+ p
141
+
142
+ def(url(p, anchor = nil)):
143
+ condition:
144
+ (top(p) != p):
145
+ (url(top(p)) + "#") + (anchor || p tag name)
146
+
147
+ anchor:
148
+ (filename(p) + "#") + anchor
149
+
150
+ otherwise:
151
+ filename(p)
152
+
153
+
154
+ def(toc-leaf(part)):
155
+ <li:
156
+ <a(href = url(part)):
157
+ over(part title)
158
+
159
+ unless(part omit-children-from-table-of-contents? || part parts empty?):
160
+ <ol:
161
+ part parts collect [p]: toc-leaf(p) --&.(Self toc-leaf(_))
162
+
163
+
164
+ def(render(part, out = ".")):
165
+ unless(part parent):
166
+ tags = search-tags(part) collect [t, d, u]:
167
+ [t, d to-s, u]
168
+
169
+ File open(i"#{out}/public/tags.js", "w") [f]:
170
+ f write(i"var SEARCH_TAGS = #{tags to-json};")
171
+
172
+ class =
173
+ if(part style properties empty?)
174
+ then: "normal"
175
+ else: part style properties collect &.to-s join(" ")
176
+
177
+ File open(i"#{out}/#{filename(part)}", "w") [f]:
178
+ f write("<!DOCTYPE html>")
179
+ f write(
180
+ <html {
181
+ <head:
182
+ <meta("http-equiv" = "Content-Type", content = "text/html; charset=UTF-8")
183
+ <title: StrippedTags new(over(part title))
184
+ <link(type = "text/css", rel = "stylesheet", href = "public/anatomy.css")
185
+ <link(type = "text/css", rel = "stylesheet", href = "public/highlight.css")
186
+ <script(type = "text/javascript", src = "public/jquery.js") {}
187
+ <script(type = "text/javascript", src = "public/jquery.hotkeys.js") {}
188
+ <script(type = "text/javascript", src = "public/tags.js") {}
189
+ <script(type = "text/javascript", src = "public/main.js") {}
190
+
191
+ all-css-additions(part) collect [addition]:
192
+ <link(type = "text/css", rel = "stylesheet", href = File basename(addition))
193
+
194
+ <body(class = class):
195
+ <div(#main):
196
+ <div(#content):
197
+ render-part(part, out)
198
+
199
+ <div(.search):
200
+ <form(action = "javascript:void(0)"):
201
+ <input(
202
+ type = "text"
203
+ placeholder = "Search&hellip;"
204
+ autocomplete = "off"
205
+ #search)
206
+
207
+ <ul(.search-results) {}
208
+
209
+ <div(#sidebar):
210
+ unless(part parts empty?):
211
+ [ <h4: "On this page:"
212
+
213
+ <ol(.toc):
214
+ part parts collect [s]: toc-leaf(s)
215
+ ]
216
+
217
+ when(part parent):
218
+ [ <h4: "Up one level:"
219
+ <ol(.toc):
220
+ toc-leaf(part parent)
221
+ ]
222
+
223
+ when(analytics-id = ENV["ANALYTICS_ID"]):
224
+ <script: UnescapedString new(i"
225
+ (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
226
+ (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
227
+ m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
228
+ })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
229
+
230
+ ga('create', '#{analytics-id}', 'auto');
231
+ ga('send', 'pageview');
232
+ ")
233
+ })
234
+
235
+ def(render-part(part, out = ".", depth = 1)):
236
+ part assets each [a]:
237
+ FileUtils cp(a, out)
238
+
239
+ part css-additions each [a]:
240
+ FileUtils cp(a, out)
241
+
242
+ <div(.section, id = i"section_#{part tag name}"):
243
+ <"h#{depth}"(.section_header):
244
+ <a(name = part tag name) {}
245
+ over(part title)
246
+
247
+ over(part body)
248
+
249
+ if(part toc?)
250
+ then:
251
+ <ol(.toc, #table-of-contents):
252
+ part parts collect [sub]:
253
+ render(sub, out)
254
+ toc-leaf(sub)
255
+ else:
256
+ part parts collect [sub]:
257
+ render-part(sub, out, depth + 1)
258
+
259
+
260
+ def(search-tags(p)):
261
+ tags = [
262
+ [ data contents-of(p title)
263
+ <span(.title):
264
+ <a(href = url(p)):
265
+ over(p title)
266
+ url(p)
267
+ ]
268
+ ]
269
+
270
+ p tags each-key [tag-name]:
271
+ tag = p find-tag(tag-name)
272
+ url = tag-url(tag)
273
+ tags <<
274
+ [ tag name
275
+ (tag display && over(tag display)) ||
276
+ <span(.tag):
277
+ <code:
278
+ <a(href = url):
279
+ tag name
280
+ url
281
+ ]
282
+
283
+ p parts each [sub]:
284
+ tags += search-tags(sub) collect [t, d, u]:
285
+ [ t
286
+ if(d is-a?(HTMLElement) && (d attributes[.class] == "with_parent"))
287
+ then: d
288
+ else:
289
+ <span(.with-parent):
290
+ d
291
+ <span(.parent):
292
+ " in "
293
+ <a(href = url(p)):
294
+ over(p title)
295
+ u
296
+ ]
297
+
298
+ tags
299
+
300
+ def(all-css-additions(p)):
301
+ assets = p css-additions to-a
302
+
303
+ p parts each [sub]:
304
+ assets += all-css-additions(sub)
305
+
306
+ assets