-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmake_docs.jl
More file actions
319 lines (284 loc) · 11.7 KB
/
Copy pathmake_docs.jl
File metadata and controls
319 lines (284 loc) · 11.7 KB
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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
# make_docs.jl
# A simple static site generator for the Julia Crash Course.
# It walks the module directories, concatenates all markdown files,
# and embeds them into a single, self-contained HTML file.
import Dates
# --- Configuration ---
const ROOT_DIR = "."
const OUTPUT_HTML = "index.html"
const MODULE_PREFIX = "module"
const DOC_EXTENSION = ".md"
# Dictionary mapping module directory names to human-readable titles
const MODULE_TITLES = Dict(
"module01" => "Getting Started: Basics",
"module02" => "Control Flow",
"module03" => "Collections",
"module04" => "Functions and Dispatch",
"module05" => "Your Own Types and Code Organization",
"module06" => "High-Performance Techniques",
"module07" => "I/O and Concurrency",
"module08" => "Project Tooling",
"module09" => "Memory, Data Layout and Unsafe Operations",
"module10" => "Advanced Parallelism and Thread Safety",
"module11" => "Metaprogramming for Zero-Cost Abstractions",
"module12" => "System Integration and Interoperability"
# Add future modules here as needed
)
# --- Helper Functions ---
# Formats directory names like "01_REPL" into "REPL"
function format_name(dir_name)
name_part = replace(dir_name, r"^\d+_" => "")
return titlecase(replace(name_part, "_" => " "))
end
# Safely reads a file, returning an empty string on error.
function safe_read(filepath)
try
return read(filepath, String)
catch e
println("Warning: Could not read file '$filepath'. Error: $e")
return ""
end
end
# Escapes characters for safe embedding within a JavaScript template literal (`...`).
function escape_for_js_template(md_content)
content = replace(md_content, "\\" => "\\\\")
content = replace(content, "`" => "\\`")
content = replace(content, "\${" => "\\\${")
return content
end
# --- Main Logic ---
function build_docs()
println("Starting documentation build...")
markdown_buffer = IOBuffer()
# Find and sort all 'moduleXX' directories
module_dirs = filter(d -> startswith(d, MODULE_PREFIX) && isdir(joinpath(ROOT_DIR, d)), readdir(ROOT_DIR))
sort!(module_dirs, by = d -> parse(Int, match(r"module(\d+)", d).captures[1]))
println("Found modules: ", module_dirs)
for mod_dir in module_dirs
mod_path = joinpath(ROOT_DIR, mod_dir)
mod_num = parse(Int, match(r"module(\d+)", mod_dir).captures[1])
# Look up the human-readable title from the dictionary
mod_title = get(MODULE_TITLES, mod_dir, "Module $mod_num") # Fallback to number if not found
println("Processing Module $mod_num: $mod_title...")
# Add Module Heading using the title
write(markdown_buffer, "# Module $mod_num: $mod_title\n\n")
# Find and sort subsections within the module
subsection_dirs = filter(d -> isdir(joinpath(mod_path, d)), readdir(mod_path))
sort!(subsection_dirs) # Simple alphabetical sort is fine due to numbered prefixes
for sub_dir in subsection_dirs
sub_path = joinpath(mod_path, sub_dir)
sub_name = format_name(sub_dir)
println(" Processing Subsection: $sub_name...")
# Add Subsection Heading
write(markdown_buffer, "## $sub_name\n\n")
# Find and sort markdown files within the subsection
md_files = filter(f -> endswith(f, DOC_EXTENSION) && isfile(joinpath(sub_path, f)), readdir(sub_path))
sort!(md_files)
for md_file in md_files
file_path = joinpath(sub_path, md_file)
println(" Adding file: $md_file")
content = safe_read(file_path)
write(markdown_buffer, content)
write(markdown_buffer, "\n\n---\n\n") # Add a horizontal rule between files
end
end
write(markdown_buffer, "\n")
end
full_markdown = String(take!(markdown_buffer))
escaped_markdown = escape_for_js_template(full_markdown)
timestamp = Dates.format(Dates.now(), "yyyy-mm-dd HH:MM:SS")
println("Generating HTML...")
# --- HTML Template ---
html_content = """
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Julia Performance Crash Course</title>
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/atom-one-dark.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/julia.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/bash.min.js"></script>
<style>
:root {
--sidebar-bg: #f7f7f7;
--text-color: #333;
--link-color: #007bff;
--hover-bg: #e9e9e9;
--border-color: #ddd;
--code-bg: #282c34; /* Match atom-one-dark */
}
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
line-height: 1.6;
margin: 0;
padding: 0;
color: var(--text-color);
background-color: #fff;
}
.container {
display: flex;
}
#sidebar {
width: 280px;
background-color: var(--sidebar-bg);
border-right: 1px solid var(--border-color);
padding: 1.5em;
height: 100vh;
overflow-y: auto;
position: sticky;
top: 0;
}
#sidebar h1 {
margin-top: 0;
font-size: 1.5em;
color: #000;
}
#sidebar ul {
list-style: none;
padding: 0;
margin: 0;
}
#sidebar li a {
text-decoration: none;
color: var(--text-color);
display: block;
padding: 0.4em 0.5em;
border-radius: 4px;
transition: background-color 0.2s;
}
#sidebar li a:hover {
background-color: var(--hover-bg);
}
main {
flex-grow: 1;
padding: 2em 4em;
max-width: 900px;
margin: 0 auto;
}
h1, h2 {
border-bottom: 1px solid var(--border-color);
padding-bottom: 0.3em;
margin-top: 1.5em; /* Add space above headings */
}
pre code.hljs {
padding: 1em;
border-radius: 5px;
background-color: var(--code-bg);
overflow-x: auto; /* Allow horizontal scroll for long code lines */
}
code {
font-family: "SF Mono", "Menlo", "Consolas", monospace;
font-size: 0.9em; /* Slightly smaller code font */
}
/* Inline code background slightly different */
p > code, li > code, td > code {
background-color: #f0f0f0;
padding: 0.2em 0.4em;
border-radius: 3px;
}
blockquote {
border-left: 4px solid var(--border-color);
padding-left: 1em;
color: #666;
margin-left: 0;
background-color: #f9f9f9; /* Slight background for blockquotes */
}
table {
border-collapse: collapse;
width: 100%;
margin: 1em 0;
}
th, td {
border: 1px solid var(--border-color);
padding: 0.5em;
text-align: left;
}
th {
background-color: var(--sidebar-bg);
}
hr {
border: none;
border-top: 2px solid var(--hover-bg);
margin: 2.5em 0; /* More space around separators */
}
/* Adjustments for smaller screens */
@media (max-width: 768px) {
.container { flex-direction: column; }
#sidebar { position: static; width: 100%; height: auto; max-height: 40vh; /* Limit sidebar height on mobile */ border-right: none; border-bottom: 1px solid var(--border-color); }
main { padding: 1.5em; }
}
</style>
</head>
<body>
<div class="container">
<nav id="sidebar">
<h1>Crash Course</h1>
<ul id="toc-list"></ul>
<hr>
<p style="font-size: 0.8em; color: #666;">Generated: $timestamp</p>
</nav>
<main id="content">
<p>Loading content...</p>
</main>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
// The entire concatenated markdown content is embedded here.
const markdownContent = `$(escaped_markdown)`;
// Configure marked.js (no highlight option needed here)
marked.setOptions({
langPrefix: 'hljs language-' // Match highlight.js CSS prefix
});
// Render the Markdown to HTML and inject it into the main content area
const contentDiv = document.getElementById('content');
contentDiv.innerHTML = marked.parse(markdownContent);
// --- Apply Syntax Highlighting ---
// Tell highlight.js to find and highlight all code blocks within the contentDiv
contentDiv.querySelectorAll('pre code').forEach((block) => {
// Remove leading/trailing empty lines often added by markdown parsers
block.textContent = block.textContent.trim();
hljs.highlightElement(block);
});
// --- Generate Table of Contents (TOC) ---
const tocList = document.getElementById('toc-list');
const headings = contentDiv.querySelectorAll('h1, h2');
headings.forEach((heading, index) => {
const level = heading.tagName === 'H1' ? 1 : 2;
// Create a unique ID for each heading to link to
const idText = (heading.textContent || '').trim();
const id = idText.toLowerCase().replace(/[^a-z0-9]+/g, '-') + '-' + index;
heading.id = id;
const listItem = document.createElement('li');
const link = document.createElement('a');
link.href = '#' + id;
link.textContent = idText; // Use trimmed text
if (level === 1) {
link.style.fontWeight = 'bold';
link.style.marginTop = '0.75em';
link.style.fontSize = '1.1em';
} else {
link.style.paddingLeft = '1.5em';
}
listItem.appendChild(link);
tocList.appendChild(listItem);
});
});
</script>
</body>
</html>
"""
# Write the final HTML to the output file
try
open(OUTPUT_HTML, "w") do f
write(f, html_content)
end
println("Successfully generated '$OUTPUT_HTML'")
catch e
println("Error writing HTML file: $e")
end
end
# --- Run the Build ---
build_docs()