anatomy 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|