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.
- checksums.yaml +7 -0
- data/LICENSE.md +201 -0
- data/bin/anatomy +5 -0
- data/lib/anatomy/atomy.ay +202 -0
- data/lib/anatomy/base.ay +151 -0
- data/lib/anatomy/cmd.ay +60 -0
- data/lib/anatomy/data.ay +147 -0
- data/lib/anatomy/html.ay +73 -0
- data/lib/anatomy/language/parser.ay +130 -0
- data/lib/anatomy/processor.ay +35 -0
- data/lib/anatomy/renderers/html.ay +306 -0
- data/lib/anatomy/ruby.ay +178 -0
- data/lib/anatomy/server.ay +80 -0
- data/lib/anatomy/slides.ay +48 -0
- data/lib/anatomy/stages/collect.ay +35 -0
- data/lib/anatomy/stages/meta.ay +100 -0
- data/lib/anatomy/stages/resolve.ay +55 -0
- data/lib/anatomy/stages/traverse.ay +34 -0
- data/lib/anatomy.ay +4 -0
- data/public/anatomy.css +427 -0
- data/public/highlight.css +60 -0
- data/public/jquery.hotkeys.js +99 -0
- data/public/jquery.js +16 -0
- data/public/main.js +237 -0
- metadata +110 -0
data/lib/anatomy/data.ay
ADDED
@@ -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)): ""
|
data/lib/anatomy/html.ay
ADDED
@@ -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…"
|
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
|