diff --git a/Cargo.lock b/Cargo.lock
index 01417afb..2423939a 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -953,6 +953,18 @@ dependencies = [
"simd-adler32",
]
+[[package]]
+name = "filetime"
+version = "0.2.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5cbc844cecaee9d4443931972e1289c8ff485cb4cc2767cb03ca139ed6885153"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "redox_syscall 0.2.16",
+ "windows-sys 0.48.0",
+]
+
[[package]]
name = "fixedbitset"
version = "0.4.2"
@@ -2095,6 +2107,7 @@ dependencies = [
"thiserror",
"tokio",
"toml",
+ "toml_edit",
"tower-http",
"tracing",
"tracing-appender",
diff --git a/Cargo.toml b/Cargo.toml
index 8a2a507d..23bcb244 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -43,6 +43,7 @@ miette = "5.7.0"
futures-util = "0.3.28"
mdbook = { version = "0.4.17", default-features = false }
notify = "6.0.0"
+toml_edit = "0.19.9"
[dev-dependencies]
assert_cmd="2"
diff --git a/docs/book.toml b/docs/book.toml
index 3b94f8b9..c4ecc76a 100644
--- a/docs/book.toml
+++ b/docs/book.toml
@@ -5,4 +5,6 @@ multilingual = false
src = "src"
[output.markdown]
-[output.html]
\ No newline at end of file
+[output.html]
+default-theme = "axo"
+preferred-dark-theme = "axo"
diff --git a/docs/theme/book.js b/docs/theme/book.js
new file mode 100644
index 00000000..4a54c347
--- /dev/null
+++ b/docs/theme/book.js
@@ -0,0 +1,688 @@
+"use strict";
+
+// Fix back button cache problem
+window.onunload = function () { };
+
+// Global variable, shared between modules
+function playground_text(playground, hidden = true) {
+ let code_block = playground.querySelector("code");
+
+ if (window.ace && code_block.classList.contains("editable")) {
+ let editor = window.ace.edit(code_block);
+ return editor.getValue();
+ } else if (hidden) {
+ return code_block.textContent;
+ } else {
+ return code_block.innerText;
+ }
+}
+
+(function codeSnippets() {
+ function fetch_with_timeout(url, options, timeout = 6000) {
+ return Promise.race([
+ fetch(url, options),
+ new Promise((_, reject) => setTimeout(() => reject(new Error('timeout')), timeout))
+ ]);
+ }
+
+ var playgrounds = Array.from(document.querySelectorAll(".playground"));
+ if (playgrounds.length > 0) {
+ fetch_with_timeout("https://play.rust-lang.org/meta/crates", {
+ headers: {
+ 'Content-Type': "application/json",
+ },
+ method: 'POST',
+ mode: 'cors',
+ })
+ .then(response => response.json())
+ .then(response => {
+ // get list of crates available in the rust playground
+ let playground_crates = response.crates.map(item => item["id"]);
+ playgrounds.forEach(block => handle_crate_list_update(block, playground_crates));
+ });
+ }
+
+ function handle_crate_list_update(playground_block, playground_crates) {
+ // update the play buttons after receiving the response
+ update_play_button(playground_block, playground_crates);
+
+ // and install on change listener to dynamically update ACE editors
+ if (window.ace) {
+ let code_block = playground_block.querySelector("code");
+ if (code_block.classList.contains("editable")) {
+ let editor = window.ace.edit(code_block);
+ editor.addEventListener("change", function (e) {
+ update_play_button(playground_block, playground_crates);
+ });
+ // add Ctrl-Enter command to execute rust code
+ editor.commands.addCommand({
+ name: "run",
+ bindKey: {
+ win: "Ctrl-Enter",
+ mac: "Ctrl-Enter"
+ },
+ exec: _editor => run_rust_code(playground_block)
+ });
+ }
+ }
+ }
+
+ // updates the visibility of play button based on `no_run` class and
+ // used crates vs ones available on http://play.rust-lang.org
+ function update_play_button(pre_block, playground_crates) {
+ var play_button = pre_block.querySelector(".play-button");
+
+ // skip if code is `no_run`
+ if (pre_block.querySelector('code').classList.contains("no_run")) {
+ play_button.classList.add("hidden");
+ return;
+ }
+
+ // get list of `extern crate`'s from snippet
+ var txt = playground_text(pre_block);
+ var re = /extern\s+crate\s+([a-zA-Z_0-9]+)\s*;/g;
+ var snippet_crates = [];
+ var item;
+ while (item = re.exec(txt)) {
+ snippet_crates.push(item[1]);
+ }
+
+ // check if all used crates are available on play.rust-lang.org
+ var all_available = snippet_crates.every(function (elem) {
+ return playground_crates.indexOf(elem) > -1;
+ });
+
+ if (all_available) {
+ play_button.classList.remove("hidden");
+ } else {
+ play_button.classList.add("hidden");
+ }
+ }
+
+ function run_rust_code(code_block) {
+ var result_block = code_block.querySelector(".result");
+ if (!result_block) {
+ result_block = document.createElement('code');
+ result_block.className = 'result hljs language-bash';
+
+ code_block.append(result_block);
+ }
+
+ let text = playground_text(code_block);
+ let classes = code_block.querySelector('code').classList;
+ let edition = "2015";
+ if(classes.contains("edition2018")) {
+ edition = "2018";
+ } else if(classes.contains("edition2021")) {
+ edition = "2021";
+ }
+ var params = {
+ version: "stable",
+ optimize: "0",
+ code: text,
+ edition: edition
+ };
+
+ if (text.indexOf("#![feature") !== -1) {
+ params.version = "nightly";
+ }
+
+ result_block.innerText = "Running...";
+
+ fetch_with_timeout("https://play.rust-lang.org/evaluate.json", {
+ headers: {
+ 'Content-Type': "application/json",
+ },
+ method: 'POST',
+ mode: 'cors',
+ body: JSON.stringify(params)
+ })
+ .then(response => response.json())
+ .then(response => {
+ if (response.result.trim() === '') {
+ result_block.innerText = "No output";
+ result_block.classList.add("result-no-output");
+ } else {
+ result_block.innerText = response.result;
+ result_block.classList.remove("result-no-output");
+ }
+ })
+ .catch(error => result_block.innerText = "Playground Communication: " + error.message);
+ }
+
+ // Syntax highlighting Configuration
+ hljs.configure({
+ tabReplace: ' ', // 4 spaces
+ languages: [], // Languages used for auto-detection
+ });
+
+ let code_nodes = Array
+ .from(document.querySelectorAll('code'))
+ // Don't highlight `inline code` blocks in headers.
+ .filter(function (node) {return !node.parentElement.classList.contains("header"); });
+
+ if (window.ace) {
+ // language-rust class needs to be removed for editable
+ // blocks or highlightjs will capture events
+ code_nodes
+ .filter(function (node) {return node.classList.contains("editable"); })
+ .forEach(function (block) { block.classList.remove('language-rust'); });
+
+ code_nodes
+ .filter(function (node) {return !node.classList.contains("editable"); })
+ .forEach(function (block) { hljs.highlightBlock(block); });
+ } else {
+ code_nodes.forEach(function (block) { hljs.highlightBlock(block); });
+ }
+
+ // Adding the hljs class gives code blocks the color css
+ // even if highlighting doesn't apply
+ code_nodes.forEach(function (block) { block.classList.add('hljs'); });
+
+ Array.from(document.querySelectorAll("code.language-rust")).forEach(function (block) {
+
+ var lines = Array.from(block.querySelectorAll('.boring'));
+ // If no lines were hidden, return
+ if (!lines.length) { return; }
+ block.classList.add("hide-boring");
+
+ var buttons = document.createElement('div');
+ buttons.className = 'buttons';
+ buttons.innerHTML = "";
+
+ // add expand button
+ var pre_block = block.parentNode;
+ pre_block.insertBefore(buttons, pre_block.firstChild);
+
+ pre_block.querySelector('.buttons').addEventListener('click', function (e) {
+ if (e.target.classList.contains('fa-eye')) {
+ e.target.classList.remove('fa-eye');
+ e.target.classList.add('fa-eye-slash');
+ e.target.title = 'Hide lines';
+ e.target.setAttribute('aria-label', e.target.title);
+
+ block.classList.remove('hide-boring');
+ } else if (e.target.classList.contains('fa-eye-slash')) {
+ e.target.classList.remove('fa-eye-slash');
+ e.target.classList.add('fa-eye');
+ e.target.title = 'Show hidden lines';
+ e.target.setAttribute('aria-label', e.target.title);
+
+ block.classList.add('hide-boring');
+ }
+ });
+ });
+
+ if (window.playground_copyable) {
+ Array.from(document.querySelectorAll('pre code')).forEach(function (block) {
+ var pre_block = block.parentNode;
+ if (!pre_block.classList.contains('playground')) {
+ var buttons = pre_block.querySelector(".buttons");
+ if (!buttons) {
+ buttons = document.createElement('div');
+ buttons.className = 'buttons';
+ pre_block.insertBefore(buttons, pre_block.firstChild);
+ }
+
+ var clipButton = document.createElement('button');
+ clipButton.className = 'fa fa-copy clip-button';
+ clipButton.title = 'Copy to clipboard';
+ clipButton.setAttribute('aria-label', clipButton.title);
+ clipButton.innerHTML = '';
+
+ buttons.insertBefore(clipButton, buttons.firstChild);
+ }
+ });
+ }
+
+ // Process playground code blocks
+ Array.from(document.querySelectorAll(".playground")).forEach(function (pre_block) {
+ // Add play button
+ var buttons = pre_block.querySelector(".buttons");
+ if (!buttons) {
+ buttons = document.createElement('div');
+ buttons.className = 'buttons';
+ pre_block.insertBefore(buttons, pre_block.firstChild);
+ }
+
+ var runCodeButton = document.createElement('button');
+ runCodeButton.className = 'fa fa-play play-button';
+ runCodeButton.hidden = true;
+ runCodeButton.title = 'Run this code';
+ runCodeButton.setAttribute('aria-label', runCodeButton.title);
+
+ buttons.insertBefore(runCodeButton, buttons.firstChild);
+ runCodeButton.addEventListener('click', function (e) {
+ run_rust_code(pre_block);
+ });
+
+ if (window.playground_copyable) {
+ var copyCodeClipboardButton = document.createElement('button');
+ copyCodeClipboardButton.className = 'fa fa-copy clip-button';
+ copyCodeClipboardButton.innerHTML = '';
+ copyCodeClipboardButton.title = 'Copy to clipboard';
+ copyCodeClipboardButton.setAttribute('aria-label', copyCodeClipboardButton.title);
+
+ buttons.insertBefore(copyCodeClipboardButton, buttons.firstChild);
+ }
+
+ let code_block = pre_block.querySelector("code");
+ if (window.ace && code_block.classList.contains("editable")) {
+ var undoChangesButton = document.createElement('button');
+ undoChangesButton.className = 'fa fa-history reset-button';
+ undoChangesButton.title = 'Undo changes';
+ undoChangesButton.setAttribute('aria-label', undoChangesButton.title);
+
+ buttons.insertBefore(undoChangesButton, buttons.firstChild);
+
+ undoChangesButton.addEventListener('click', function () {
+ let editor = window.ace.edit(code_block);
+ editor.setValue(editor.originalCode);
+ editor.clearSelection();
+ });
+ }
+ });
+})();
+
+(function themes() {
+ var html = document.querySelector('html');
+ var themeToggleButton = document.getElementById('theme-toggle');
+ var themePopup = document.getElementById('theme-list');
+ var themeColorMetaTag = document.querySelector('meta[name="theme-color"]');
+ var stylesheets = {
+ ayuHighlight: document.querySelector("[href$='ayu-highlight.css']"),
+ tomorrowNight: document.querySelector("[href$='tomorrow-night.css']"),
+ highlight: document.querySelector("[href$='highlight.css']"),
+ };
+
+ function showThemes() {
+ themePopup.style.display = 'block';
+ themeToggleButton.setAttribute('aria-expanded', true);
+ themePopup.querySelector("button#" + get_theme()).focus();
+ }
+
+ function updateThemeSelected() {
+ themePopup.querySelectorAll('.theme-selected').forEach(function (el) {
+ el.classList.remove('theme-selected');
+ });
+ themePopup.querySelector("button#" + get_theme()).classList.add('theme-selected');
+ }
+
+ function hideThemes() {
+ themePopup.style.display = 'none';
+ themeToggleButton.setAttribute('aria-expanded', false);
+ themeToggleButton.focus();
+ }
+
+ function get_theme() {
+ var theme;
+ try { theme = localStorage.getItem('axomdbook-theme'); } catch (e) { }
+ if (theme === null || theme === undefined) {
+ return default_theme;
+ } else {
+ return theme;
+ }
+ }
+
+ function set_theme(theme, store = true) {
+ let ace_theme;
+
+ if (theme == 'coal' || theme == 'navy' || theme == "axo") {
+ stylesheets.ayuHighlight.disabled = true;
+ stylesheets.tomorrowNight.disabled = false;
+ stylesheets.highlight.disabled = true;
+
+ ace_theme = "ace/theme/tomorrow_night";
+ } else if (theme == 'ayu') {
+ stylesheets.ayuHighlight.disabled = false;
+ stylesheets.tomorrowNight.disabled = true;
+ stylesheets.highlight.disabled = true;
+ ace_theme = "ace/theme/tomorrow_night";
+ } else {
+ stylesheets.ayuHighlight.disabled = true;
+ stylesheets.tomorrowNight.disabled = true;
+ stylesheets.highlight.disabled = false;
+ ace_theme = "ace/theme/dawn";
+ }
+
+ setTimeout(function () {
+ themeColorMetaTag.content = getComputedStyle(document.body).backgroundColor;
+ }, 1);
+
+ if (window.ace && window.editors) {
+ window.editors.forEach(function (editor) {
+ editor.setTheme(ace_theme);
+ });
+ }
+
+ var previousTheme = get_theme();
+
+ if (store) {
+ try { localStorage.setItem('axomdbook-theme', theme); } catch (e) { }
+ }
+
+ html.classList.remove(previousTheme);
+ html.classList.add(theme);
+ updateThemeSelected();
+ }
+
+ // Set theme
+ var theme = get_theme();
+
+ set_theme(theme, false);
+
+ themeToggleButton.addEventListener('click', function () {
+ if (themePopup.style.display === 'block') {
+ hideThemes();
+ } else {
+ showThemes();
+ }
+ });
+
+ themePopup.addEventListener('click', function (e) {
+ var theme;
+ if (e.target.className === "theme") {
+ theme = e.target.id;
+ } else if (e.target.parentElement.className === "theme") {
+ theme = e.target.parentElement.id;
+ } else {
+ return;
+ }
+ set_theme(theme);
+ });
+
+ themePopup.addEventListener('focusout', function(e) {
+ // e.relatedTarget is null in Safari and Firefox on macOS (see workaround below)
+ if (!!e.relatedTarget && !themeToggleButton.contains(e.relatedTarget) && !themePopup.contains(e.relatedTarget)) {
+ hideThemes();
+ }
+ });
+
+ // Should not be needed, but it works around an issue on macOS & iOS: https://github.com/rust-lang/mdBook/issues/628
+ document.addEventListener('click', function(e) {
+ if (themePopup.style.display === 'block' && !themeToggleButton.contains(e.target) && !themePopup.contains(e.target)) {
+ hideThemes();
+ }
+ });
+
+ document.addEventListener('keydown', function (e) {
+ if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) { return; }
+ if (!themePopup.contains(e.target)) { return; }
+
+ switch (e.key) {
+ case 'Escape':
+ e.preventDefault();
+ hideThemes();
+ break;
+ case 'ArrowUp':
+ e.preventDefault();
+ var li = document.activeElement.parentElement;
+ if (li && li.previousElementSibling) {
+ li.previousElementSibling.querySelector('button').focus();
+ }
+ break;
+ case 'ArrowDown':
+ e.preventDefault();
+ var li = document.activeElement.parentElement;
+ if (li && li.nextElementSibling) {
+ li.nextElementSibling.querySelector('button').focus();
+ }
+ break;
+ case 'Home':
+ e.preventDefault();
+ themePopup.querySelector('li:first-child button').focus();
+ break;
+ case 'End':
+ e.preventDefault();
+ themePopup.querySelector('li:last-child button').focus();
+ break;
+ }
+ });
+})();
+
+(function sidebar() {
+ var html = document.querySelector("html");
+ var sidebar = document.getElementById("sidebar");
+ var sidebarLinks = document.querySelectorAll('#sidebar a');
+ var sidebarToggleButton = document.getElementById("sidebar-toggle");
+ var sidebarResizeHandle = document.getElementById("sidebar-resize-handle");
+ var firstContact = null;
+
+ function showSidebar() {
+ html.classList.remove('sidebar-hidden')
+ html.classList.add('sidebar-visible');
+ Array.from(sidebarLinks).forEach(function (link) {
+ link.setAttribute('tabIndex', 0);
+ });
+ sidebarToggleButton.setAttribute('aria-expanded', true);
+ sidebar.setAttribute('aria-hidden', false);
+ try { localStorage.setItem('mdbook-sidebar', 'visible'); } catch (e) { }
+ }
+
+
+ var sidebarAnchorToggles = document.querySelectorAll('#sidebar a.toggle');
+
+ function toggleSection(ev) {
+ ev.currentTarget.parentElement.classList.toggle('expanded');
+ }
+
+ Array.from(sidebarAnchorToggles).forEach(function (el) {
+ el.addEventListener('click', toggleSection);
+ });
+
+ function hideSidebar() {
+ html.classList.remove('sidebar-visible')
+ html.classList.add('sidebar-hidden');
+ Array.from(sidebarLinks).forEach(function (link) {
+ link.setAttribute('tabIndex', -1);
+ });
+ sidebarToggleButton.setAttribute('aria-expanded', false);
+ sidebar.setAttribute('aria-hidden', true);
+ try { localStorage.setItem('mdbook-sidebar', 'hidden'); } catch (e) { }
+ }
+
+ // Toggle sidebar
+ sidebarToggleButton.addEventListener('click', function sidebarToggle() {
+ if (html.classList.contains("sidebar-hidden")) {
+ var current_width = parseInt(
+ document.documentElement.style.getPropertyValue('--sidebar-width'), 10);
+ if (current_width < 150) {
+ document.documentElement.style.setProperty('--sidebar-width', '150px');
+ }
+ showSidebar();
+ } else if (html.classList.contains("sidebar-visible")) {
+ hideSidebar();
+ } else {
+ if (getComputedStyle(sidebar)['transform'] === 'none') {
+ hideSidebar();
+ } else {
+ showSidebar();
+ }
+ }
+ });
+
+ sidebarResizeHandle.addEventListener('mousedown', initResize, false);
+
+ function initResize(e) {
+ window.addEventListener('mousemove', resize, false);
+ window.addEventListener('mouseup', stopResize, false);
+ html.classList.add('sidebar-resizing');
+ }
+ function resize(e) {
+ var pos = (e.clientX - sidebar.offsetLeft);
+ if (pos < 20) {
+ hideSidebar();
+ } else {
+ if (html.classList.contains("sidebar-hidden")) {
+ showSidebar();
+ }
+ pos = Math.min(pos, window.innerWidth - 100);
+ document.documentElement.style.setProperty('--sidebar-width', pos + 'px');
+ }
+ }
+ //on mouseup remove windows functions mousemove & mouseup
+ function stopResize(e) {
+ html.classList.remove('sidebar-resizing');
+ window.removeEventListener('mousemove', resize, false);
+ window.removeEventListener('mouseup', stopResize, false);
+ }
+
+ document.addEventListener('touchstart', function (e) {
+ firstContact = {
+ x: e.touches[0].clientX,
+ time: Date.now()
+ };
+ }, { passive: true });
+
+ document.addEventListener('touchmove', function (e) {
+ if (!firstContact)
+ return;
+
+ var curX = e.touches[0].clientX;
+ var xDiff = curX - firstContact.x,
+ tDiff = Date.now() - firstContact.time;
+
+ if (tDiff < 250 && Math.abs(xDiff) >= 150) {
+ if (xDiff >= 0 && firstContact.x < Math.min(document.body.clientWidth * 0.25, 300))
+ showSidebar();
+ else if (xDiff < 0 && curX < 300)
+ hideSidebar();
+
+ firstContact = null;
+ }
+ }, { passive: true });
+
+ // Scroll sidebar to current active section
+ var activeSection = document.getElementById("sidebar").querySelector(".active");
+ if (activeSection) {
+ // https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView
+ activeSection.scrollIntoView({ block: 'center' });
+ }
+})();
+
+(function chapterNavigation() {
+ document.addEventListener('keydown', function (e) {
+ if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) { return; }
+ if (window.search && window.search.hasFocus()) { return; }
+
+ switch (e.key) {
+ case 'ArrowRight':
+ e.preventDefault();
+ var nextButton = document.querySelector('.nav-chapters.next');
+ if (nextButton) {
+ window.location.href = nextButton.href;
+ }
+ break;
+ case 'ArrowLeft':
+ e.preventDefault();
+ var previousButton = document.querySelector('.nav-chapters.previous');
+ if (previousButton) {
+ window.location.href = previousButton.href;
+ }
+ break;
+ }
+ });
+})();
+
+(function clipboard() {
+ var clipButtons = document.querySelectorAll('.clip-button');
+
+ function hideTooltip(elem) {
+ elem.firstChild.innerText = "";
+ elem.className = 'fa fa-copy clip-button';
+ }
+
+ function showTooltip(elem, msg) {
+ elem.firstChild.innerText = msg;
+ elem.className = 'fa fa-copy tooltipped';
+ }
+
+ var clipboardSnippets = new ClipboardJS('.clip-button', {
+ text: function (trigger) {
+ hideTooltip(trigger);
+ let playground = trigger.closest("pre");
+ return playground_text(playground, false);
+ }
+ });
+
+ Array.from(clipButtons).forEach(function (clipButton) {
+ clipButton.addEventListener('mouseout', function (e) {
+ hideTooltip(e.currentTarget);
+ });
+ });
+
+ clipboardSnippets.on('success', function (e) {
+ e.clearSelection();
+ showTooltip(e.trigger, "Copied!");
+ });
+
+ clipboardSnippets.on('error', function (e) {
+ showTooltip(e.trigger, "Clipboard error!");
+ });
+})();
+
+(function scrollToTop () {
+ var menuTitle = document.querySelector('.menu-title');
+
+ menuTitle.addEventListener('click', function () {
+ document.scrollingElement.scrollTo({ top: 0, behavior: 'smooth' });
+ });
+})();
+
+(function controllMenu() {
+ var menu = document.getElementById('menu-bar');
+
+ (function controllPosition() {
+ var scrollTop = document.scrollingElement.scrollTop;
+ var prevScrollTop = scrollTop;
+ var minMenuY = -menu.clientHeight - 50;
+ // When the script loads, the page can be at any scroll (e.g. if you reforesh it).
+ menu.style.top = scrollTop + 'px';
+ // Same as parseInt(menu.style.top.slice(0, -2), but faster
+ var topCache = menu.style.top.slice(0, -2);
+ menu.classList.remove('sticky');
+ var stickyCache = false; // Same as menu.classList.contains('sticky'), but faster
+ document.addEventListener('scroll', function () {
+ scrollTop = Math.max(document.scrollingElement.scrollTop, 0);
+ // `null` means that it doesn't need to be updated
+ var nextSticky = null;
+ var nextTop = null;
+ var scrollDown = scrollTop > prevScrollTop;
+ var menuPosAbsoluteY = topCache - scrollTop;
+ if (scrollDown) {
+ nextSticky = false;
+ if (menuPosAbsoluteY > 0) {
+ nextTop = prevScrollTop;
+ }
+ } else {
+ if (menuPosAbsoluteY > 0) {
+ nextSticky = true;
+ } else if (menuPosAbsoluteY < minMenuY) {
+ nextTop = prevScrollTop + minMenuY;
+ }
+ }
+ if (nextSticky === true && stickyCache === false) {
+ menu.classList.add('sticky');
+ stickyCache = true;
+ } else if (nextSticky === false && stickyCache === true) {
+ menu.classList.remove('sticky');
+ stickyCache = false;
+ }
+ if (nextTop !== null) {
+ menu.style.top = nextTop + 'px';
+ topCache = nextTop;
+ }
+ prevScrollTop = scrollTop;
+ }, { passive: true });
+ })();
+ (function controllBorder() {
+ menu.classList.remove('bordered');
+ document.addEventListener('scroll', function () {
+ if (menu.offsetTop === 0) {
+ menu.classList.remove('bordered');
+ } else {
+ menu.classList.add('bordered');
+ }
+ }, { passive: true });
+ })();
+})();
diff --git a/docs/theme/css/general.css b/docs/theme/css/general.css
new file mode 100644
index 00000000..93bbde00
--- /dev/null
+++ b/docs/theme/css/general.css
@@ -0,0 +1,207 @@
+/* Base styles and content styles */
+
+@import 'variables.css';
+
+:root {
+ /* Browser default font-size is 16px, this way 1 rem = 10px */
+ font-size: 62.5%;
+}
+
+html {
+ font-family: var(--main-font, "Open Sans"), sans-serif;
+ color: var(--fg);
+ background-color: var(--bg);
+ text-size-adjust: none;
+ -webkit-text-size-adjust: none;
+}
+
+body {
+ margin: 0;
+ font-size: 1.6rem;
+ overflow-x: hidden;
+}
+
+code {
+ font-family: var(--mono-font) !important;
+ font-size: var(--code-font-size);
+}
+
+/* make long words/inline code not x overflow */
+main {
+ overflow-wrap: break-word;
+}
+
+/* make wide tables scroll if they overflow */
+.table-wrapper {
+ overflow-x: auto;
+}
+
+/* Don't change font size in headers. */
+h1 code, h2 code, h3 code, h4 code, h5 code, h6 code {
+ font-size: unset;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ color: var(--title-fg);
+}
+
+.left { float: left; }
+.right { float: right; }
+.boring { opacity: 0.6; }
+.hide-boring .boring { display: none; }
+.hidden { display: none !important; }
+
+h2, h3 { margin-top: 2.5em; }
+h4, h5 { margin-top: 2em; }
+
+.header + .header h3,
+.header + .header h4,
+.header + .header h5 {
+ margin-top: 1em;
+}
+
+h1:target::before,
+h2:target::before,
+h3:target::before,
+h4:target::before,
+h5:target::before,
+h6:target::before {
+ display: inline-block;
+ content: "»";
+ margin-left: -30px;
+ width: 30px;
+}
+
+/* This is broken on Safari as of version 14, but is fixed
+ in Safari Technology Preview 117 which I think will be Safari 14.2.
+ https://bugs.webkit.org/show_bug.cgi?id=218076
+*/
+:target {
+ scroll-margin-top: calc(var(--menu-bar-height) + 0.5em);
+}
+
+.page {
+ outline: 0;
+ padding: 0 var(--page-padding);
+ margin-top: calc(0px - var(--menu-bar-height)); /* Compensate for the #menu-bar-hover-placeholder */
+}
+.page-wrapper {
+ box-sizing: border-box;
+}
+.js:not(.sidebar-resizing) .page-wrapper {
+ transition: margin-left 0.3s ease, transform 0.3s ease; /* Animation: slide away */
+}
+
+.content {
+ overflow-y: auto;
+ padding: 0 5px 50px 5px;
+}
+.content main {
+ margin-left: auto;
+ margin-right: auto;
+ max-width: var(--content-max-width);
+}
+.content p { line-height: 1.45em; }
+.content ol { line-height: 1.45em; }
+.content ul { line-height: 1.45em; }
+.content a { text-decoration: none; }
+.content a:hover { text-decoration: underline; }
+.content img, .content video { max-width: 100%; }
+.content .header:link,
+.content .header:visited {
+ color: var(--title-fg, var(--fg));
+}
+.content .header:link,
+.content .header:visited:hover {
+ text-decoration: none;
+}
+
+table {
+ margin: 0 auto;
+ border-collapse: collapse;
+}
+table td {
+ padding: 3px 20px;
+ border: 1px var(--table-border-color) solid;
+}
+table thead {
+ background: var(--table-header-bg);
+}
+table thead td {
+ font-weight: 700;
+ border: none;
+}
+table thead th {
+ padding: 3px 20px;
+}
+table thead tr {
+ border: 1px var(--table-header-bg) solid;
+}
+/* Alternate background colors for rows */
+table tbody tr:nth-child(2n) {
+ background: var(--table-alternate-bg);
+}
+
+
+blockquote {
+ margin: 20px 0;
+ padding: 0 20px;
+ color: var(--fg);
+ background-color: var(--quote-bg);
+ border-top: .1em solid var(--quote-border);
+ border-bottom: .1em solid var(--quote-border);
+}
+
+kbd {
+ background-color: var(--table-border-color);
+ border-radius: 4px;
+ border: solid 1px var(--theme-popup-border);
+ box-shadow: inset 0 -1px 0 var(--theme-hover);
+ display: inline-block;
+ font-size: var(--code-font-size);
+ font-family: var(--mono-font);
+ line-height: 10px;
+ padding: 4px 5px;
+ vertical-align: middle;
+}
+
+:not(.footnote-definition) + .footnote-definition,
+.footnote-definition + :not(.footnote-definition) {
+ margin-top: 2em;
+}
+.footnote-definition {
+ font-size: 0.9em;
+ margin: 0.5em 0;
+}
+.footnote-definition p {
+ display: inline;
+}
+
+.tooltiptext {
+ position: absolute;
+ visibility: hidden;
+ color: #fff;
+ background-color: #333;
+ transform: translateX(-50%); /* Center by moving tooltip 50% of its width left */
+ left: -8px; /* Half of the width of the icon */
+ top: -35px;
+ font-size: 0.8em;
+ text-align: center;
+ border-radius: 6px;
+ padding: 5px 8px;
+ margin: 5px;
+ z-index: 1000;
+}
+.tooltipped .tooltiptext {
+ visibility: visible;
+}
+
+.chapter li.part-title {
+ color: var(--sidebar-fg);
+ margin: 5px 0px;
+ font-weight: bold;
+}
+
+.result-no-output {
+ font-style: italic;
+}
diff --git a/docs/theme/css/variables.css b/docs/theme/css/variables.css
new file mode 100644
index 00000000..25e3c29d
--- /dev/null
+++ b/docs/theme/css/variables.css
@@ -0,0 +1,359 @@
+
+/* Globals */
+
+:root {
+ --sidebar-width: 300px;
+ --page-padding: 15px;
+ --content-max-width: 750px;
+ --menu-bar-height: 50px;
+ --mono-font: "Source Code Pro", Consolas, "Ubuntu Mono", Menlo, "DejaVu Sans Mono", monospace, monospace;
+ --code-font-size: 0.875em /* please adjust the ace font size accordingly in editor.js */
+}
+
+/* Themes */
+
+.ayu {
+ --bg: hsl(210, 25%, 8%);
+ --fg: #c5c5c5;
+
+ --sidebar-bg: #14191f;
+ --sidebar-fg: #c8c9db;
+ --sidebar-non-existant: #5c6773;
+ --sidebar-active: #ffb454;
+ --sidebar-spacer: #2d334f;
+
+ --scrollbar: var(--sidebar-fg);
+
+ --icons: #737480;
+ --icons-hover: #b7b9cc;
+
+ --links: #0096cf;
+
+ --inline-code-color: #ffb454;
+
+ --theme-popup-bg: #14191f;
+ --theme-popup-border: #5c6773;
+ --theme-hover: #191f26;
+
+ --quote-bg: hsl(226, 15%, 17%);
+ --quote-border: hsl(226, 15%, 22%);
+
+ --table-border-color: hsl(210, 25%, 13%);
+ --table-header-bg: hsl(210, 25%, 28%);
+ --table-alternate-bg: hsl(210, 25%, 11%);
+
+ --searchbar-border-color: #848484;
+ --searchbar-bg: #424242;
+ --searchbar-fg: #fff;
+ --searchbar-shadow-color: #d4c89f;
+ --searchresults-header-fg: #666;
+ --searchresults-border-color: #888;
+ --searchresults-li-bg: #252932;
+ --search-mark-bg: #e3b171;
+}
+
+.coal {
+ --bg: hsl(200, 7%, 8%);
+ --fg: #98a3ad;
+
+ --sidebar-bg: #292c2f;
+ --sidebar-fg: #a1adb8;
+ --sidebar-non-existant: #505254;
+ --sidebar-active: #3473ad;
+ --sidebar-spacer: #393939;
+
+ --scrollbar: var(--sidebar-fg);
+
+ --icons: #43484d;
+ --icons-hover: #b3c0cc;
+
+ --links: #2b79a2;
+
+ --inline-code-color: #c5c8c6;
+
+ --theme-popup-bg: #141617;
+ --theme-popup-border: #43484d;
+ --theme-hover: #1f2124;
+
+ --quote-bg: hsl(234, 21%, 18%);
+ --quote-border: hsl(234, 21%, 23%);
+
+ --table-border-color: hsl(200, 7%, 13%);
+ --table-header-bg: hsl(200, 7%, 28%);
+ --table-alternate-bg: hsl(200, 7%, 11%);
+
+ --searchbar-border-color: #aaa;
+ --searchbar-bg: #b7b7b7;
+ --searchbar-fg: #000;
+ --searchbar-shadow-color: #aaa;
+ --searchresults-header-fg: #666;
+ --searchresults-border-color: #98a3ad;
+ --searchresults-li-bg: #2b2b2f;
+ --search-mark-bg: #355c7d;
+}
+
+.light {
+ --bg: hsl(0, 0%, 100%);
+ --fg: hsl(0, 0%, 0%);
+
+ --sidebar-bg: #fafafa;
+ --sidebar-fg: hsl(0, 0%, 0%);
+ --sidebar-non-existant: #aaaaaa;
+ --sidebar-active: #1f1fff;
+ --sidebar-spacer: #f4f4f4;
+
+ --scrollbar: #8F8F8F;
+
+ --icons: #747474;
+ --icons-hover: #000000;
+
+ --links: #20609f;
+
+ --inline-code-color: #301900;
+
+ --theme-popup-bg: #fafafa;
+ --theme-popup-border: #cccccc;
+ --theme-hover: #e6e6e6;
+
+ --quote-bg: hsl(197, 37%, 96%);
+ --quote-border: hsl(197, 37%, 91%);
+
+ --table-border-color: hsl(0, 0%, 95%);
+ --table-header-bg: hsl(0, 0%, 80%);
+ --table-alternate-bg: hsl(0, 0%, 97%);
+
+ --searchbar-border-color: #aaa;
+ --searchbar-bg: #fafafa;
+ --searchbar-fg: #000;
+ --searchbar-shadow-color: #aaa;
+ --searchresults-header-fg: #666;
+ --searchresults-border-color: #888;
+ --searchresults-li-bg: #e4f2fe;
+ --search-mark-bg: #a2cff5;
+}
+
+.navy {
+ --bg: hsl(226, 23%, 11%);
+ --fg: #bcbdd0;
+
+ --sidebar-bg: #282d3f;
+ --sidebar-fg: #c8c9db;
+ --sidebar-non-existant: #505274;
+ --sidebar-active: #2b79a2;
+ --sidebar-spacer: #2d334f;
+
+ --scrollbar: var(--sidebar-fg);
+
+ --icons: #737480;
+ --icons-hover: #b7b9cc;
+
+ --links: #2b79a2;
+
+ --inline-code-color: #c5c8c6;
+
+ --theme-popup-bg: #161923;
+ --theme-popup-border: #737480;
+ --theme-hover: #282e40;
+
+ --quote-bg: hsl(226, 15%, 17%);
+ --quote-border: hsl(226, 15%, 22%);
+
+ --table-border-color: hsl(226, 23%, 16%);
+ --table-header-bg: hsl(226, 23%, 31%);
+ --table-alternate-bg: hsl(226, 23%, 14%);
+
+ --searchbar-border-color: #aaa;
+ --searchbar-bg: #aeaec6;
+ --searchbar-fg: #000;
+ --searchbar-shadow-color: #aaa;
+ --searchresults-header-fg: #5f5f71;
+ --searchresults-border-color: #5c5c68;
+ --searchresults-li-bg: #242430;
+ --search-mark-bg: #a2cff5;
+}
+
+.rust {
+ --bg: hsl(60, 9%, 87%);
+ --fg: #262625;
+
+ --sidebar-bg: #3b2e2a;
+ --sidebar-fg: #c8c9db;
+ --sidebar-non-existant: #505254;
+ --sidebar-active: #e69f67;
+ --sidebar-spacer: #45373a;
+
+ --scrollbar: var(--sidebar-fg);
+
+ --icons: #737480;
+ --icons-hover: #262625;
+
+ --links: #2b79a2;
+
+ --inline-code-color: #6e6b5e;
+
+ --theme-popup-bg: #e1e1db;
+ --theme-popup-border: #b38f6b;
+ --theme-hover: #99908a;
+
+ --quote-bg: hsl(60, 5%, 75%);
+ --quote-border: hsl(60, 5%, 70%);
+
+ --table-border-color: hsl(60, 9%, 82%);
+ --table-header-bg: #b3a497;
+ --table-alternate-bg: hsl(60, 9%, 84%);
+
+ --searchbar-border-color: #aaa;
+ --searchbar-bg: #fafafa;
+ --searchbar-fg: #000;
+ --searchbar-shadow-color: #aaa;
+ --searchresults-header-fg: #666;
+ --searchresults-border-color: #888;
+ --searchresults-li-bg: #dec2a2;
+ --search-mark-bg: #e69f67;
+}
+
+
+.axo {
+ --color-axo-pink: hsla(326, 100%, 73%, 1);
+ --color-axo-pink-dark: hsla(326, 52%, 58%, 1);
+ --color-axo-orange: hsla(0, 87%, 70%, 1);
+ --color-axo-orange-dark: hsla(356, 75%, 64%, 1);
+ --color-axo-highlighter: hsla(51, 100%, 50%, 1);
+ --color-axo-black: hsla(0, 0%, 5%, 1);
+
+ --title-fg: var(--color-axo-pink);
+ --main-font: Comfortaa;
+
+ /* modified version of the navy theme above */
+ --bg: var(--color-axo-black);
+ --fg: #bcbdd0;
+
+ --sidebar-bg: var(--color-axo-black);
+ --sidebar-fg: var(--color-axo-orange);
+ --sidebar-non-existant: #505274;
+ --sidebar-active: var(--color-axo-pink);
+ --sidebar-spacer: var(--color-axo-orange);
+
+ --scrollbar: var(--sidebar-fg);
+
+ --icons: var(--color-axo-orange);
+ --icons-hover: var(--color-axo-pink);
+
+ --links: var(--color-axo-orange);
+
+ --inline-code-color: #c5c8c6;
+
+ --theme-popup-bg: #161923;
+ --theme-popup-border: #737480;
+ --theme-hover: #282e40;
+
+ --quote-bg: hsl(226, 15%, 17%);
+ --quote-border: hsl(226, 15%, 22%);
+
+ --table-border-color: var(--color-axo-orange);
+ --table-header-bg: hsl(226, 23%, 31%);
+ --table-alternate-bg: hsl(226, 23%, 14%);
+
+ --searchbar-border-color: #aaa;
+ --searchbar-bg: #aeaec6;
+ --searchbar-fg: #000;
+ --searchbar-shadow-color: #aaa;
+ --searchresults-header-fg: #5f5f71;
+ --searchresults-border-color: #5c5c68;
+ --searchresults-li-bg: #242430;
+ --search-mark-bg: #a2cff5;
+}
+
+
+.axo-light {
+ --color-axo-pink: hsla(326, 100%, 73%, 1);
+ --color-axo-pink-dark: hsla(326, 52%, 58%, 1);
+ --color-axo-orange: hsla(0, 87%, 70%, 1);
+ --color-axo-orange-dark: hsla(356, 75%, 64%, 1);
+ --color-axo-highlighter: hsla(51, 100%, 50%, 1);
+ --color-axo-black: hsla(0, 0%, 5%, 1);
+
+ --title-fg: var(--color-axo-pink);
+ --main-font: Comfortaa;
+
+ /* modified version of the light theme above */
+ --bg: hsl(0, 0%, 100%);
+ --fg: hsl(0, 0%, 0%);
+
+ --sidebar-bg: #fafafa;
+ --sidebar-fg: var(--color-axo-orange);
+ --sidebar-non-existant: #aaaaaa;
+ --sidebar-active: var(--color-axo-pink);
+ --sidebar-spacer: var(--color-axo-orange);
+
+ --scrollbar: var(--sidebar-fg);
+
+ --icons: var(--color-axo-orange);
+ --icons-hover: var(--color-axo-pink);
+
+ --links: var(--color-axo-orange);
+
+ --inline-code-color: #301900;
+
+ --theme-popup-bg: #fafafa;
+ --theme-popup-border: #cccccc;
+ --theme-hover: #e6e6e6;
+
+ --quote-bg: hsl(197, 37%, 96%);
+ --quote-border: hsl(197, 37%, 91%);
+
+ --table-border-color: var(--color-axo-orange);
+ --table-header-bg: hsl(0, 0%, 80%);
+ --table-alternate-bg: hsl(0, 0%, 97%);
+
+ --searchbar-border-color: #aaa;
+ --searchbar-bg: #fafafa;
+ --searchbar-fg: #000;
+ --searchbar-shadow-color: #aaa;
+ --searchresults-header-fg: #666;
+ --searchresults-border-color: #888;
+ --searchresults-li-bg: #e4f2fe;
+ --search-mark-bg: #a2cff5;
+}
+
+@media (prefers-color-scheme: dark) {
+ .light.no-js {
+ --bg: hsl(200, 7%, 8%);
+ --fg: #98a3ad;
+
+ --sidebar-bg: #292c2f;
+ --sidebar-fg: #a1adb8;
+ --sidebar-non-existant: #505254;
+ --sidebar-active: #3473ad;
+ --sidebar-spacer: #393939;
+
+ --scrollbar: var(--sidebar-fg);
+
+ --icons: #43484d;
+ --icons-hover: #b3c0cc;
+
+ --links: #2b79a2;
+
+ --inline-code-color: #c5c8c6;
+
+ --theme-popup-bg: #141617;
+ --theme-popup-border: #43484d;
+ --theme-hover: #1f2124;
+
+ --quote-bg: hsl(234, 21%, 18%);
+ --quote-border: hsl(234, 21%, 23%);
+
+ --table-border-color: hsl(200, 7%, 13%);
+ --table-header-bg: hsl(200, 7%, 28%);
+ --table-alternate-bg: hsl(200, 7%, 11%);
+
+ --searchbar-border-color: #aaa;
+ --searchbar-bg: #b7b7b7;
+ --searchbar-fg: #000;
+ --searchbar-shadow-color: #aaa;
+ --searchresults-header-fg: #666;
+ --searchresults-border-color: #98a3ad;
+ --searchresults-li-bg: #2b2b2f;
+ --search-mark-bg: #355c7d;
+ }
+}
diff --git a/docs/theme/fonts/fonts.css b/docs/theme/fonts/fonts.css
new file mode 100644
index 00000000..92075a2f
--- /dev/null
+++ b/docs/theme/fonts/fonts.css
@@ -0,0 +1,104 @@
+/* Open Sans is licensed under the Apache License, Version 2.0. See http://www.apache.org/licenses/LICENSE-2.0 */
+/* Source Code Pro is under the Open Font License. See https://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL */
+
+@import url("https://fonts.googleapis.com/css2?family=Comfortaa:wght@400;700&display=swap");
+@import url("https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;600;700&display=swap");
+@import url("https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap");
+
+/* open-sans-300 - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */
+@font-face {
+ font-family: 'Open Sans';
+ font-style: normal;
+ font-weight: 300;
+ src: local('Open Sans Light'), local('OpenSans-Light'),
+ url('open-sans-v17-all-charsets-300.woff2') format('woff2');
+}
+
+/* open-sans-300italic - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */
+@font-face {
+ font-family: 'Open Sans';
+ font-style: italic;
+ font-weight: 300;
+ src: local('Open Sans Light Italic'), local('OpenSans-LightItalic'),
+ url('open-sans-v17-all-charsets-300italic.woff2') format('woff2');
+}
+
+/* open-sans-regular - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */
+@font-face {
+ font-family: 'Open Sans';
+ font-style: normal;
+ font-weight: 400;
+ src: local('Open Sans Regular'), local('OpenSans-Regular'),
+ url('open-sans-v17-all-charsets-regular.woff2') format('woff2');
+}
+
+/* open-sans-italic - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */
+@font-face {
+ font-family: 'Open Sans';
+ font-style: italic;
+ font-weight: 400;
+ src: local('Open Sans Italic'), local('OpenSans-Italic'),
+ url('open-sans-v17-all-charsets-italic.woff2') format('woff2');
+}
+
+/* open-sans-600 - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */
+@font-face {
+ font-family: 'Open Sans';
+ font-style: normal;
+ font-weight: 600;
+ src: local('Open Sans SemiBold'), local('OpenSans-SemiBold'),
+ url('open-sans-v17-all-charsets-600.woff2') format('woff2');
+}
+
+/* open-sans-600italic - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */
+@font-face {
+ font-family: 'Open Sans';
+ font-style: italic;
+ font-weight: 600;
+ src: local('Open Sans SemiBold Italic'), local('OpenSans-SemiBoldItalic'),
+ url('open-sans-v17-all-charsets-600italic.woff2') format('woff2');
+}
+
+/* open-sans-700 - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */
+@font-face {
+ font-family: 'Open Sans';
+ font-style: normal;
+ font-weight: 700;
+ src: local('Open Sans Bold'), local('OpenSans-Bold'),
+ url('open-sans-v17-all-charsets-700.woff2') format('woff2');
+}
+
+/* open-sans-700italic - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */
+@font-face {
+ font-family: 'Open Sans';
+ font-style: italic;
+ font-weight: 700;
+ src: local('Open Sans Bold Italic'), local('OpenSans-BoldItalic'),
+ url('open-sans-v17-all-charsets-700italic.woff2') format('woff2');
+}
+
+/* open-sans-800 - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */
+@font-face {
+ font-family: 'Open Sans';
+ font-style: normal;
+ font-weight: 800;
+ src: local('Open Sans ExtraBold'), local('OpenSans-ExtraBold'),
+ url('open-sans-v17-all-charsets-800.woff2') format('woff2');
+}
+
+/* open-sans-800italic - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */
+@font-face {
+ font-family: 'Open Sans';
+ font-style: italic;
+ font-weight: 800;
+ src: local('Open Sans ExtraBold Italic'), local('OpenSans-ExtraBoldItalic'),
+ url('open-sans-v17-all-charsets-800italic.woff2') format('woff2');
+}
+
+/* source-code-pro-500 - latin_vietnamese_latin-ext_greek_cyrillic-ext_cyrillic */
+@font-face {
+ font-family: 'Source Code Pro';
+ font-style: normal;
+ font-weight: 500;
+ src: url('source-code-pro-v11-all-charsets-500.woff2') format('woff2');
+}
diff --git a/docs/theme/index.hbs b/docs/theme/index.hbs
new file mode 100644
index 00000000..5111bc16
--- /dev/null
+++ b/docs/theme/index.hbs
@@ -0,0 +1,317 @@
+
+
+
+
+
+ {{ title }}
+ {{#if is_print }}
+
+ {{/if}}
+ {{#if base_url}}
+
+ {{/if}}
+
+
+
+ {{> head}}
+
+
+
+
+
+ {{#if favicon_svg}}
+
+ {{/if}}
+ {{#if favicon_png}}
+
+ {{/if}}
+
+
+
+ {{#if print_enable}}
+
+ {{/if}}
+
+
+
+ {{#if copy_fonts}}
+
+ {{/if}}
+
+
+
+
+
+
+
+ {{#each additional_css}}
+
+ {{/each}}
+
+ {{#if mathjax_support}}
+
+
+ {{/if}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{> header}}
+
+
+
+ {{#if search_enabled}}
+
+ {{/if}}
+
+
+
+
+
+
+ {{{ content }}}
+
+
+
+
+
+
+
+
+
+
+ {{#if live_reload_endpoint}}
+
+
+ {{/if}}
+
+ {{#if google_analytics}}
+
+
+ {{/if}}
+
+ {{#if playground_line_numbers}}
+
+ {{/if}}
+
+ {{#if playground_copyable}}
+
+ {{/if}}
+
+ {{#if playground_js}}
+
+
+
+
+
+ {{/if}}
+
+ {{#if search_js}}
+
+
+
+ {{/if}}
+
+
+
+
+
+
+ {{#each additional_js}}
+
+ {{/each}}
+
+ {{#if is_print}}
+ {{#if mathjax_support}}
+
+ {{else}}
+
+ {{/if}}
+ {{/if}}
+
+
+
+
diff --git a/oranda-css/mdbook-theme/book.js b/oranda-css/mdbook-theme/book.js
new file mode 100644
index 00000000..4a54c347
--- /dev/null
+++ b/oranda-css/mdbook-theme/book.js
@@ -0,0 +1,688 @@
+"use strict";
+
+// Fix back button cache problem
+window.onunload = function () { };
+
+// Global variable, shared between modules
+function playground_text(playground, hidden = true) {
+ let code_block = playground.querySelector("code");
+
+ if (window.ace && code_block.classList.contains("editable")) {
+ let editor = window.ace.edit(code_block);
+ return editor.getValue();
+ } else if (hidden) {
+ return code_block.textContent;
+ } else {
+ return code_block.innerText;
+ }
+}
+
+(function codeSnippets() {
+ function fetch_with_timeout(url, options, timeout = 6000) {
+ return Promise.race([
+ fetch(url, options),
+ new Promise((_, reject) => setTimeout(() => reject(new Error('timeout')), timeout))
+ ]);
+ }
+
+ var playgrounds = Array.from(document.querySelectorAll(".playground"));
+ if (playgrounds.length > 0) {
+ fetch_with_timeout("https://play.rust-lang.org/meta/crates", {
+ headers: {
+ 'Content-Type': "application/json",
+ },
+ method: 'POST',
+ mode: 'cors',
+ })
+ .then(response => response.json())
+ .then(response => {
+ // get list of crates available in the rust playground
+ let playground_crates = response.crates.map(item => item["id"]);
+ playgrounds.forEach(block => handle_crate_list_update(block, playground_crates));
+ });
+ }
+
+ function handle_crate_list_update(playground_block, playground_crates) {
+ // update the play buttons after receiving the response
+ update_play_button(playground_block, playground_crates);
+
+ // and install on change listener to dynamically update ACE editors
+ if (window.ace) {
+ let code_block = playground_block.querySelector("code");
+ if (code_block.classList.contains("editable")) {
+ let editor = window.ace.edit(code_block);
+ editor.addEventListener("change", function (e) {
+ update_play_button(playground_block, playground_crates);
+ });
+ // add Ctrl-Enter command to execute rust code
+ editor.commands.addCommand({
+ name: "run",
+ bindKey: {
+ win: "Ctrl-Enter",
+ mac: "Ctrl-Enter"
+ },
+ exec: _editor => run_rust_code(playground_block)
+ });
+ }
+ }
+ }
+
+ // updates the visibility of play button based on `no_run` class and
+ // used crates vs ones available on http://play.rust-lang.org
+ function update_play_button(pre_block, playground_crates) {
+ var play_button = pre_block.querySelector(".play-button");
+
+ // skip if code is `no_run`
+ if (pre_block.querySelector('code').classList.contains("no_run")) {
+ play_button.classList.add("hidden");
+ return;
+ }
+
+ // get list of `extern crate`'s from snippet
+ var txt = playground_text(pre_block);
+ var re = /extern\s+crate\s+([a-zA-Z_0-9]+)\s*;/g;
+ var snippet_crates = [];
+ var item;
+ while (item = re.exec(txt)) {
+ snippet_crates.push(item[1]);
+ }
+
+ // check if all used crates are available on play.rust-lang.org
+ var all_available = snippet_crates.every(function (elem) {
+ return playground_crates.indexOf(elem) > -1;
+ });
+
+ if (all_available) {
+ play_button.classList.remove("hidden");
+ } else {
+ play_button.classList.add("hidden");
+ }
+ }
+
+ function run_rust_code(code_block) {
+ var result_block = code_block.querySelector(".result");
+ if (!result_block) {
+ result_block = document.createElement('code');
+ result_block.className = 'result hljs language-bash';
+
+ code_block.append(result_block);
+ }
+
+ let text = playground_text(code_block);
+ let classes = code_block.querySelector('code').classList;
+ let edition = "2015";
+ if(classes.contains("edition2018")) {
+ edition = "2018";
+ } else if(classes.contains("edition2021")) {
+ edition = "2021";
+ }
+ var params = {
+ version: "stable",
+ optimize: "0",
+ code: text,
+ edition: edition
+ };
+
+ if (text.indexOf("#![feature") !== -1) {
+ params.version = "nightly";
+ }
+
+ result_block.innerText = "Running...";
+
+ fetch_with_timeout("https://play.rust-lang.org/evaluate.json", {
+ headers: {
+ 'Content-Type': "application/json",
+ },
+ method: 'POST',
+ mode: 'cors',
+ body: JSON.stringify(params)
+ })
+ .then(response => response.json())
+ .then(response => {
+ if (response.result.trim() === '') {
+ result_block.innerText = "No output";
+ result_block.classList.add("result-no-output");
+ } else {
+ result_block.innerText = response.result;
+ result_block.classList.remove("result-no-output");
+ }
+ })
+ .catch(error => result_block.innerText = "Playground Communication: " + error.message);
+ }
+
+ // Syntax highlighting Configuration
+ hljs.configure({
+ tabReplace: ' ', // 4 spaces
+ languages: [], // Languages used for auto-detection
+ });
+
+ let code_nodes = Array
+ .from(document.querySelectorAll('code'))
+ // Don't highlight `inline code` blocks in headers.
+ .filter(function (node) {return !node.parentElement.classList.contains("header"); });
+
+ if (window.ace) {
+ // language-rust class needs to be removed for editable
+ // blocks or highlightjs will capture events
+ code_nodes
+ .filter(function (node) {return node.classList.contains("editable"); })
+ .forEach(function (block) { block.classList.remove('language-rust'); });
+
+ code_nodes
+ .filter(function (node) {return !node.classList.contains("editable"); })
+ .forEach(function (block) { hljs.highlightBlock(block); });
+ } else {
+ code_nodes.forEach(function (block) { hljs.highlightBlock(block); });
+ }
+
+ // Adding the hljs class gives code blocks the color css
+ // even if highlighting doesn't apply
+ code_nodes.forEach(function (block) { block.classList.add('hljs'); });
+
+ Array.from(document.querySelectorAll("code.language-rust")).forEach(function (block) {
+
+ var lines = Array.from(block.querySelectorAll('.boring'));
+ // If no lines were hidden, return
+ if (!lines.length) { return; }
+ block.classList.add("hide-boring");
+
+ var buttons = document.createElement('div');
+ buttons.className = 'buttons';
+ buttons.innerHTML = "";
+
+ // add expand button
+ var pre_block = block.parentNode;
+ pre_block.insertBefore(buttons, pre_block.firstChild);
+
+ pre_block.querySelector('.buttons').addEventListener('click', function (e) {
+ if (e.target.classList.contains('fa-eye')) {
+ e.target.classList.remove('fa-eye');
+ e.target.classList.add('fa-eye-slash');
+ e.target.title = 'Hide lines';
+ e.target.setAttribute('aria-label', e.target.title);
+
+ block.classList.remove('hide-boring');
+ } else if (e.target.classList.contains('fa-eye-slash')) {
+ e.target.classList.remove('fa-eye-slash');
+ e.target.classList.add('fa-eye');
+ e.target.title = 'Show hidden lines';
+ e.target.setAttribute('aria-label', e.target.title);
+
+ block.classList.add('hide-boring');
+ }
+ });
+ });
+
+ if (window.playground_copyable) {
+ Array.from(document.querySelectorAll('pre code')).forEach(function (block) {
+ var pre_block = block.parentNode;
+ if (!pre_block.classList.contains('playground')) {
+ var buttons = pre_block.querySelector(".buttons");
+ if (!buttons) {
+ buttons = document.createElement('div');
+ buttons.className = 'buttons';
+ pre_block.insertBefore(buttons, pre_block.firstChild);
+ }
+
+ var clipButton = document.createElement('button');
+ clipButton.className = 'fa fa-copy clip-button';
+ clipButton.title = 'Copy to clipboard';
+ clipButton.setAttribute('aria-label', clipButton.title);
+ clipButton.innerHTML = '';
+
+ buttons.insertBefore(clipButton, buttons.firstChild);
+ }
+ });
+ }
+
+ // Process playground code blocks
+ Array.from(document.querySelectorAll(".playground")).forEach(function (pre_block) {
+ // Add play button
+ var buttons = pre_block.querySelector(".buttons");
+ if (!buttons) {
+ buttons = document.createElement('div');
+ buttons.className = 'buttons';
+ pre_block.insertBefore(buttons, pre_block.firstChild);
+ }
+
+ var runCodeButton = document.createElement('button');
+ runCodeButton.className = 'fa fa-play play-button';
+ runCodeButton.hidden = true;
+ runCodeButton.title = 'Run this code';
+ runCodeButton.setAttribute('aria-label', runCodeButton.title);
+
+ buttons.insertBefore(runCodeButton, buttons.firstChild);
+ runCodeButton.addEventListener('click', function (e) {
+ run_rust_code(pre_block);
+ });
+
+ if (window.playground_copyable) {
+ var copyCodeClipboardButton = document.createElement('button');
+ copyCodeClipboardButton.className = 'fa fa-copy clip-button';
+ copyCodeClipboardButton.innerHTML = '';
+ copyCodeClipboardButton.title = 'Copy to clipboard';
+ copyCodeClipboardButton.setAttribute('aria-label', copyCodeClipboardButton.title);
+
+ buttons.insertBefore(copyCodeClipboardButton, buttons.firstChild);
+ }
+
+ let code_block = pre_block.querySelector("code");
+ if (window.ace && code_block.classList.contains("editable")) {
+ var undoChangesButton = document.createElement('button');
+ undoChangesButton.className = 'fa fa-history reset-button';
+ undoChangesButton.title = 'Undo changes';
+ undoChangesButton.setAttribute('aria-label', undoChangesButton.title);
+
+ buttons.insertBefore(undoChangesButton, buttons.firstChild);
+
+ undoChangesButton.addEventListener('click', function () {
+ let editor = window.ace.edit(code_block);
+ editor.setValue(editor.originalCode);
+ editor.clearSelection();
+ });
+ }
+ });
+})();
+
+(function themes() {
+ var html = document.querySelector('html');
+ var themeToggleButton = document.getElementById('theme-toggle');
+ var themePopup = document.getElementById('theme-list');
+ var themeColorMetaTag = document.querySelector('meta[name="theme-color"]');
+ var stylesheets = {
+ ayuHighlight: document.querySelector("[href$='ayu-highlight.css']"),
+ tomorrowNight: document.querySelector("[href$='tomorrow-night.css']"),
+ highlight: document.querySelector("[href$='highlight.css']"),
+ };
+
+ function showThemes() {
+ themePopup.style.display = 'block';
+ themeToggleButton.setAttribute('aria-expanded', true);
+ themePopup.querySelector("button#" + get_theme()).focus();
+ }
+
+ function updateThemeSelected() {
+ themePopup.querySelectorAll('.theme-selected').forEach(function (el) {
+ el.classList.remove('theme-selected');
+ });
+ themePopup.querySelector("button#" + get_theme()).classList.add('theme-selected');
+ }
+
+ function hideThemes() {
+ themePopup.style.display = 'none';
+ themeToggleButton.setAttribute('aria-expanded', false);
+ themeToggleButton.focus();
+ }
+
+ function get_theme() {
+ var theme;
+ try { theme = localStorage.getItem('axomdbook-theme'); } catch (e) { }
+ if (theme === null || theme === undefined) {
+ return default_theme;
+ } else {
+ return theme;
+ }
+ }
+
+ function set_theme(theme, store = true) {
+ let ace_theme;
+
+ if (theme == 'coal' || theme == 'navy' || theme == "axo") {
+ stylesheets.ayuHighlight.disabled = true;
+ stylesheets.tomorrowNight.disabled = false;
+ stylesheets.highlight.disabled = true;
+
+ ace_theme = "ace/theme/tomorrow_night";
+ } else if (theme == 'ayu') {
+ stylesheets.ayuHighlight.disabled = false;
+ stylesheets.tomorrowNight.disabled = true;
+ stylesheets.highlight.disabled = true;
+ ace_theme = "ace/theme/tomorrow_night";
+ } else {
+ stylesheets.ayuHighlight.disabled = true;
+ stylesheets.tomorrowNight.disabled = true;
+ stylesheets.highlight.disabled = false;
+ ace_theme = "ace/theme/dawn";
+ }
+
+ setTimeout(function () {
+ themeColorMetaTag.content = getComputedStyle(document.body).backgroundColor;
+ }, 1);
+
+ if (window.ace && window.editors) {
+ window.editors.forEach(function (editor) {
+ editor.setTheme(ace_theme);
+ });
+ }
+
+ var previousTheme = get_theme();
+
+ if (store) {
+ try { localStorage.setItem('axomdbook-theme', theme); } catch (e) { }
+ }
+
+ html.classList.remove(previousTheme);
+ html.classList.add(theme);
+ updateThemeSelected();
+ }
+
+ // Set theme
+ var theme = get_theme();
+
+ set_theme(theme, false);
+
+ themeToggleButton.addEventListener('click', function () {
+ if (themePopup.style.display === 'block') {
+ hideThemes();
+ } else {
+ showThemes();
+ }
+ });
+
+ themePopup.addEventListener('click', function (e) {
+ var theme;
+ if (e.target.className === "theme") {
+ theme = e.target.id;
+ } else if (e.target.parentElement.className === "theme") {
+ theme = e.target.parentElement.id;
+ } else {
+ return;
+ }
+ set_theme(theme);
+ });
+
+ themePopup.addEventListener('focusout', function(e) {
+ // e.relatedTarget is null in Safari and Firefox on macOS (see workaround below)
+ if (!!e.relatedTarget && !themeToggleButton.contains(e.relatedTarget) && !themePopup.contains(e.relatedTarget)) {
+ hideThemes();
+ }
+ });
+
+ // Should not be needed, but it works around an issue on macOS & iOS: https://github.com/rust-lang/mdBook/issues/628
+ document.addEventListener('click', function(e) {
+ if (themePopup.style.display === 'block' && !themeToggleButton.contains(e.target) && !themePopup.contains(e.target)) {
+ hideThemes();
+ }
+ });
+
+ document.addEventListener('keydown', function (e) {
+ if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) { return; }
+ if (!themePopup.contains(e.target)) { return; }
+
+ switch (e.key) {
+ case 'Escape':
+ e.preventDefault();
+ hideThemes();
+ break;
+ case 'ArrowUp':
+ e.preventDefault();
+ var li = document.activeElement.parentElement;
+ if (li && li.previousElementSibling) {
+ li.previousElementSibling.querySelector('button').focus();
+ }
+ break;
+ case 'ArrowDown':
+ e.preventDefault();
+ var li = document.activeElement.parentElement;
+ if (li && li.nextElementSibling) {
+ li.nextElementSibling.querySelector('button').focus();
+ }
+ break;
+ case 'Home':
+ e.preventDefault();
+ themePopup.querySelector('li:first-child button').focus();
+ break;
+ case 'End':
+ e.preventDefault();
+ themePopup.querySelector('li:last-child button').focus();
+ break;
+ }
+ });
+})();
+
+(function sidebar() {
+ var html = document.querySelector("html");
+ var sidebar = document.getElementById("sidebar");
+ var sidebarLinks = document.querySelectorAll('#sidebar a');
+ var sidebarToggleButton = document.getElementById("sidebar-toggle");
+ var sidebarResizeHandle = document.getElementById("sidebar-resize-handle");
+ var firstContact = null;
+
+ function showSidebar() {
+ html.classList.remove('sidebar-hidden')
+ html.classList.add('sidebar-visible');
+ Array.from(sidebarLinks).forEach(function (link) {
+ link.setAttribute('tabIndex', 0);
+ });
+ sidebarToggleButton.setAttribute('aria-expanded', true);
+ sidebar.setAttribute('aria-hidden', false);
+ try { localStorage.setItem('mdbook-sidebar', 'visible'); } catch (e) { }
+ }
+
+
+ var sidebarAnchorToggles = document.querySelectorAll('#sidebar a.toggle');
+
+ function toggleSection(ev) {
+ ev.currentTarget.parentElement.classList.toggle('expanded');
+ }
+
+ Array.from(sidebarAnchorToggles).forEach(function (el) {
+ el.addEventListener('click', toggleSection);
+ });
+
+ function hideSidebar() {
+ html.classList.remove('sidebar-visible')
+ html.classList.add('sidebar-hidden');
+ Array.from(sidebarLinks).forEach(function (link) {
+ link.setAttribute('tabIndex', -1);
+ });
+ sidebarToggleButton.setAttribute('aria-expanded', false);
+ sidebar.setAttribute('aria-hidden', true);
+ try { localStorage.setItem('mdbook-sidebar', 'hidden'); } catch (e) { }
+ }
+
+ // Toggle sidebar
+ sidebarToggleButton.addEventListener('click', function sidebarToggle() {
+ if (html.classList.contains("sidebar-hidden")) {
+ var current_width = parseInt(
+ document.documentElement.style.getPropertyValue('--sidebar-width'), 10);
+ if (current_width < 150) {
+ document.documentElement.style.setProperty('--sidebar-width', '150px');
+ }
+ showSidebar();
+ } else if (html.classList.contains("sidebar-visible")) {
+ hideSidebar();
+ } else {
+ if (getComputedStyle(sidebar)['transform'] === 'none') {
+ hideSidebar();
+ } else {
+ showSidebar();
+ }
+ }
+ });
+
+ sidebarResizeHandle.addEventListener('mousedown', initResize, false);
+
+ function initResize(e) {
+ window.addEventListener('mousemove', resize, false);
+ window.addEventListener('mouseup', stopResize, false);
+ html.classList.add('sidebar-resizing');
+ }
+ function resize(e) {
+ var pos = (e.clientX - sidebar.offsetLeft);
+ if (pos < 20) {
+ hideSidebar();
+ } else {
+ if (html.classList.contains("sidebar-hidden")) {
+ showSidebar();
+ }
+ pos = Math.min(pos, window.innerWidth - 100);
+ document.documentElement.style.setProperty('--sidebar-width', pos + 'px');
+ }
+ }
+ //on mouseup remove windows functions mousemove & mouseup
+ function stopResize(e) {
+ html.classList.remove('sidebar-resizing');
+ window.removeEventListener('mousemove', resize, false);
+ window.removeEventListener('mouseup', stopResize, false);
+ }
+
+ document.addEventListener('touchstart', function (e) {
+ firstContact = {
+ x: e.touches[0].clientX,
+ time: Date.now()
+ };
+ }, { passive: true });
+
+ document.addEventListener('touchmove', function (e) {
+ if (!firstContact)
+ return;
+
+ var curX = e.touches[0].clientX;
+ var xDiff = curX - firstContact.x,
+ tDiff = Date.now() - firstContact.time;
+
+ if (tDiff < 250 && Math.abs(xDiff) >= 150) {
+ if (xDiff >= 0 && firstContact.x < Math.min(document.body.clientWidth * 0.25, 300))
+ showSidebar();
+ else if (xDiff < 0 && curX < 300)
+ hideSidebar();
+
+ firstContact = null;
+ }
+ }, { passive: true });
+
+ // Scroll sidebar to current active section
+ var activeSection = document.getElementById("sidebar").querySelector(".active");
+ if (activeSection) {
+ // https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView
+ activeSection.scrollIntoView({ block: 'center' });
+ }
+})();
+
+(function chapterNavigation() {
+ document.addEventListener('keydown', function (e) {
+ if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) { return; }
+ if (window.search && window.search.hasFocus()) { return; }
+
+ switch (e.key) {
+ case 'ArrowRight':
+ e.preventDefault();
+ var nextButton = document.querySelector('.nav-chapters.next');
+ if (nextButton) {
+ window.location.href = nextButton.href;
+ }
+ break;
+ case 'ArrowLeft':
+ e.preventDefault();
+ var previousButton = document.querySelector('.nav-chapters.previous');
+ if (previousButton) {
+ window.location.href = previousButton.href;
+ }
+ break;
+ }
+ });
+})();
+
+(function clipboard() {
+ var clipButtons = document.querySelectorAll('.clip-button');
+
+ function hideTooltip(elem) {
+ elem.firstChild.innerText = "";
+ elem.className = 'fa fa-copy clip-button';
+ }
+
+ function showTooltip(elem, msg) {
+ elem.firstChild.innerText = msg;
+ elem.className = 'fa fa-copy tooltipped';
+ }
+
+ var clipboardSnippets = new ClipboardJS('.clip-button', {
+ text: function (trigger) {
+ hideTooltip(trigger);
+ let playground = trigger.closest("pre");
+ return playground_text(playground, false);
+ }
+ });
+
+ Array.from(clipButtons).forEach(function (clipButton) {
+ clipButton.addEventListener('mouseout', function (e) {
+ hideTooltip(e.currentTarget);
+ });
+ });
+
+ clipboardSnippets.on('success', function (e) {
+ e.clearSelection();
+ showTooltip(e.trigger, "Copied!");
+ });
+
+ clipboardSnippets.on('error', function (e) {
+ showTooltip(e.trigger, "Clipboard error!");
+ });
+})();
+
+(function scrollToTop () {
+ var menuTitle = document.querySelector('.menu-title');
+
+ menuTitle.addEventListener('click', function () {
+ document.scrollingElement.scrollTo({ top: 0, behavior: 'smooth' });
+ });
+})();
+
+(function controllMenu() {
+ var menu = document.getElementById('menu-bar');
+
+ (function controllPosition() {
+ var scrollTop = document.scrollingElement.scrollTop;
+ var prevScrollTop = scrollTop;
+ var minMenuY = -menu.clientHeight - 50;
+ // When the script loads, the page can be at any scroll (e.g. if you reforesh it).
+ menu.style.top = scrollTop + 'px';
+ // Same as parseInt(menu.style.top.slice(0, -2), but faster
+ var topCache = menu.style.top.slice(0, -2);
+ menu.classList.remove('sticky');
+ var stickyCache = false; // Same as menu.classList.contains('sticky'), but faster
+ document.addEventListener('scroll', function () {
+ scrollTop = Math.max(document.scrollingElement.scrollTop, 0);
+ // `null` means that it doesn't need to be updated
+ var nextSticky = null;
+ var nextTop = null;
+ var scrollDown = scrollTop > prevScrollTop;
+ var menuPosAbsoluteY = topCache - scrollTop;
+ if (scrollDown) {
+ nextSticky = false;
+ if (menuPosAbsoluteY > 0) {
+ nextTop = prevScrollTop;
+ }
+ } else {
+ if (menuPosAbsoluteY > 0) {
+ nextSticky = true;
+ } else if (menuPosAbsoluteY < minMenuY) {
+ nextTop = prevScrollTop + minMenuY;
+ }
+ }
+ if (nextSticky === true && stickyCache === false) {
+ menu.classList.add('sticky');
+ stickyCache = true;
+ } else if (nextSticky === false && stickyCache === true) {
+ menu.classList.remove('sticky');
+ stickyCache = false;
+ }
+ if (nextTop !== null) {
+ menu.style.top = nextTop + 'px';
+ topCache = nextTop;
+ }
+ prevScrollTop = scrollTop;
+ }, { passive: true });
+ })();
+ (function controllBorder() {
+ menu.classList.remove('bordered');
+ document.addEventListener('scroll', function () {
+ if (menu.offsetTop === 0) {
+ menu.classList.remove('bordered');
+ } else {
+ menu.classList.add('bordered');
+ }
+ }, { passive: true });
+ })();
+})();
diff --git a/oranda-css/mdbook-theme/css/general.css b/oranda-css/mdbook-theme/css/general.css
new file mode 100644
index 00000000..93bbde00
--- /dev/null
+++ b/oranda-css/mdbook-theme/css/general.css
@@ -0,0 +1,207 @@
+/* Base styles and content styles */
+
+@import 'variables.css';
+
+:root {
+ /* Browser default font-size is 16px, this way 1 rem = 10px */
+ font-size: 62.5%;
+}
+
+html {
+ font-family: var(--main-font, "Open Sans"), sans-serif;
+ color: var(--fg);
+ background-color: var(--bg);
+ text-size-adjust: none;
+ -webkit-text-size-adjust: none;
+}
+
+body {
+ margin: 0;
+ font-size: 1.6rem;
+ overflow-x: hidden;
+}
+
+code {
+ font-family: var(--mono-font) !important;
+ font-size: var(--code-font-size);
+}
+
+/* make long words/inline code not x overflow */
+main {
+ overflow-wrap: break-word;
+}
+
+/* make wide tables scroll if they overflow */
+.table-wrapper {
+ overflow-x: auto;
+}
+
+/* Don't change font size in headers. */
+h1 code, h2 code, h3 code, h4 code, h5 code, h6 code {
+ font-size: unset;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ color: var(--title-fg);
+}
+
+.left { float: left; }
+.right { float: right; }
+.boring { opacity: 0.6; }
+.hide-boring .boring { display: none; }
+.hidden { display: none !important; }
+
+h2, h3 { margin-top: 2.5em; }
+h4, h5 { margin-top: 2em; }
+
+.header + .header h3,
+.header + .header h4,
+.header + .header h5 {
+ margin-top: 1em;
+}
+
+h1:target::before,
+h2:target::before,
+h3:target::before,
+h4:target::before,
+h5:target::before,
+h6:target::before {
+ display: inline-block;
+ content: "»";
+ margin-left: -30px;
+ width: 30px;
+}
+
+/* This is broken on Safari as of version 14, but is fixed
+ in Safari Technology Preview 117 which I think will be Safari 14.2.
+ https://bugs.webkit.org/show_bug.cgi?id=218076
+*/
+:target {
+ scroll-margin-top: calc(var(--menu-bar-height) + 0.5em);
+}
+
+.page {
+ outline: 0;
+ padding: 0 var(--page-padding);
+ margin-top: calc(0px - var(--menu-bar-height)); /* Compensate for the #menu-bar-hover-placeholder */
+}
+.page-wrapper {
+ box-sizing: border-box;
+}
+.js:not(.sidebar-resizing) .page-wrapper {
+ transition: margin-left 0.3s ease, transform 0.3s ease; /* Animation: slide away */
+}
+
+.content {
+ overflow-y: auto;
+ padding: 0 5px 50px 5px;
+}
+.content main {
+ margin-left: auto;
+ margin-right: auto;
+ max-width: var(--content-max-width);
+}
+.content p { line-height: 1.45em; }
+.content ol { line-height: 1.45em; }
+.content ul { line-height: 1.45em; }
+.content a { text-decoration: none; }
+.content a:hover { text-decoration: underline; }
+.content img, .content video { max-width: 100%; }
+.content .header:link,
+.content .header:visited {
+ color: var(--title-fg, var(--fg));
+}
+.content .header:link,
+.content .header:visited:hover {
+ text-decoration: none;
+}
+
+table {
+ margin: 0 auto;
+ border-collapse: collapse;
+}
+table td {
+ padding: 3px 20px;
+ border: 1px var(--table-border-color) solid;
+}
+table thead {
+ background: var(--table-header-bg);
+}
+table thead td {
+ font-weight: 700;
+ border: none;
+}
+table thead th {
+ padding: 3px 20px;
+}
+table thead tr {
+ border: 1px var(--table-header-bg) solid;
+}
+/* Alternate background colors for rows */
+table tbody tr:nth-child(2n) {
+ background: var(--table-alternate-bg);
+}
+
+
+blockquote {
+ margin: 20px 0;
+ padding: 0 20px;
+ color: var(--fg);
+ background-color: var(--quote-bg);
+ border-top: .1em solid var(--quote-border);
+ border-bottom: .1em solid var(--quote-border);
+}
+
+kbd {
+ background-color: var(--table-border-color);
+ border-radius: 4px;
+ border: solid 1px var(--theme-popup-border);
+ box-shadow: inset 0 -1px 0 var(--theme-hover);
+ display: inline-block;
+ font-size: var(--code-font-size);
+ font-family: var(--mono-font);
+ line-height: 10px;
+ padding: 4px 5px;
+ vertical-align: middle;
+}
+
+:not(.footnote-definition) + .footnote-definition,
+.footnote-definition + :not(.footnote-definition) {
+ margin-top: 2em;
+}
+.footnote-definition {
+ font-size: 0.9em;
+ margin: 0.5em 0;
+}
+.footnote-definition p {
+ display: inline;
+}
+
+.tooltiptext {
+ position: absolute;
+ visibility: hidden;
+ color: #fff;
+ background-color: #333;
+ transform: translateX(-50%); /* Center by moving tooltip 50% of its width left */
+ left: -8px; /* Half of the width of the icon */
+ top: -35px;
+ font-size: 0.8em;
+ text-align: center;
+ border-radius: 6px;
+ padding: 5px 8px;
+ margin: 5px;
+ z-index: 1000;
+}
+.tooltipped .tooltiptext {
+ visibility: visible;
+}
+
+.chapter li.part-title {
+ color: var(--sidebar-fg);
+ margin: 5px 0px;
+ font-weight: bold;
+}
+
+.result-no-output {
+ font-style: italic;
+}
diff --git a/oranda-css/mdbook-theme/css/variables.css b/oranda-css/mdbook-theme/css/variables.css
new file mode 100644
index 00000000..25e3c29d
--- /dev/null
+++ b/oranda-css/mdbook-theme/css/variables.css
@@ -0,0 +1,359 @@
+
+/* Globals */
+
+:root {
+ --sidebar-width: 300px;
+ --page-padding: 15px;
+ --content-max-width: 750px;
+ --menu-bar-height: 50px;
+ --mono-font: "Source Code Pro", Consolas, "Ubuntu Mono", Menlo, "DejaVu Sans Mono", monospace, monospace;
+ --code-font-size: 0.875em /* please adjust the ace font size accordingly in editor.js */
+}
+
+/* Themes */
+
+.ayu {
+ --bg: hsl(210, 25%, 8%);
+ --fg: #c5c5c5;
+
+ --sidebar-bg: #14191f;
+ --sidebar-fg: #c8c9db;
+ --sidebar-non-existant: #5c6773;
+ --sidebar-active: #ffb454;
+ --sidebar-spacer: #2d334f;
+
+ --scrollbar: var(--sidebar-fg);
+
+ --icons: #737480;
+ --icons-hover: #b7b9cc;
+
+ --links: #0096cf;
+
+ --inline-code-color: #ffb454;
+
+ --theme-popup-bg: #14191f;
+ --theme-popup-border: #5c6773;
+ --theme-hover: #191f26;
+
+ --quote-bg: hsl(226, 15%, 17%);
+ --quote-border: hsl(226, 15%, 22%);
+
+ --table-border-color: hsl(210, 25%, 13%);
+ --table-header-bg: hsl(210, 25%, 28%);
+ --table-alternate-bg: hsl(210, 25%, 11%);
+
+ --searchbar-border-color: #848484;
+ --searchbar-bg: #424242;
+ --searchbar-fg: #fff;
+ --searchbar-shadow-color: #d4c89f;
+ --searchresults-header-fg: #666;
+ --searchresults-border-color: #888;
+ --searchresults-li-bg: #252932;
+ --search-mark-bg: #e3b171;
+}
+
+.coal {
+ --bg: hsl(200, 7%, 8%);
+ --fg: #98a3ad;
+
+ --sidebar-bg: #292c2f;
+ --sidebar-fg: #a1adb8;
+ --sidebar-non-existant: #505254;
+ --sidebar-active: #3473ad;
+ --sidebar-spacer: #393939;
+
+ --scrollbar: var(--sidebar-fg);
+
+ --icons: #43484d;
+ --icons-hover: #b3c0cc;
+
+ --links: #2b79a2;
+
+ --inline-code-color: #c5c8c6;
+
+ --theme-popup-bg: #141617;
+ --theme-popup-border: #43484d;
+ --theme-hover: #1f2124;
+
+ --quote-bg: hsl(234, 21%, 18%);
+ --quote-border: hsl(234, 21%, 23%);
+
+ --table-border-color: hsl(200, 7%, 13%);
+ --table-header-bg: hsl(200, 7%, 28%);
+ --table-alternate-bg: hsl(200, 7%, 11%);
+
+ --searchbar-border-color: #aaa;
+ --searchbar-bg: #b7b7b7;
+ --searchbar-fg: #000;
+ --searchbar-shadow-color: #aaa;
+ --searchresults-header-fg: #666;
+ --searchresults-border-color: #98a3ad;
+ --searchresults-li-bg: #2b2b2f;
+ --search-mark-bg: #355c7d;
+}
+
+.light {
+ --bg: hsl(0, 0%, 100%);
+ --fg: hsl(0, 0%, 0%);
+
+ --sidebar-bg: #fafafa;
+ --sidebar-fg: hsl(0, 0%, 0%);
+ --sidebar-non-existant: #aaaaaa;
+ --sidebar-active: #1f1fff;
+ --sidebar-spacer: #f4f4f4;
+
+ --scrollbar: #8F8F8F;
+
+ --icons: #747474;
+ --icons-hover: #000000;
+
+ --links: #20609f;
+
+ --inline-code-color: #301900;
+
+ --theme-popup-bg: #fafafa;
+ --theme-popup-border: #cccccc;
+ --theme-hover: #e6e6e6;
+
+ --quote-bg: hsl(197, 37%, 96%);
+ --quote-border: hsl(197, 37%, 91%);
+
+ --table-border-color: hsl(0, 0%, 95%);
+ --table-header-bg: hsl(0, 0%, 80%);
+ --table-alternate-bg: hsl(0, 0%, 97%);
+
+ --searchbar-border-color: #aaa;
+ --searchbar-bg: #fafafa;
+ --searchbar-fg: #000;
+ --searchbar-shadow-color: #aaa;
+ --searchresults-header-fg: #666;
+ --searchresults-border-color: #888;
+ --searchresults-li-bg: #e4f2fe;
+ --search-mark-bg: #a2cff5;
+}
+
+.navy {
+ --bg: hsl(226, 23%, 11%);
+ --fg: #bcbdd0;
+
+ --sidebar-bg: #282d3f;
+ --sidebar-fg: #c8c9db;
+ --sidebar-non-existant: #505274;
+ --sidebar-active: #2b79a2;
+ --sidebar-spacer: #2d334f;
+
+ --scrollbar: var(--sidebar-fg);
+
+ --icons: #737480;
+ --icons-hover: #b7b9cc;
+
+ --links: #2b79a2;
+
+ --inline-code-color: #c5c8c6;
+
+ --theme-popup-bg: #161923;
+ --theme-popup-border: #737480;
+ --theme-hover: #282e40;
+
+ --quote-bg: hsl(226, 15%, 17%);
+ --quote-border: hsl(226, 15%, 22%);
+
+ --table-border-color: hsl(226, 23%, 16%);
+ --table-header-bg: hsl(226, 23%, 31%);
+ --table-alternate-bg: hsl(226, 23%, 14%);
+
+ --searchbar-border-color: #aaa;
+ --searchbar-bg: #aeaec6;
+ --searchbar-fg: #000;
+ --searchbar-shadow-color: #aaa;
+ --searchresults-header-fg: #5f5f71;
+ --searchresults-border-color: #5c5c68;
+ --searchresults-li-bg: #242430;
+ --search-mark-bg: #a2cff5;
+}
+
+.rust {
+ --bg: hsl(60, 9%, 87%);
+ --fg: #262625;
+
+ --sidebar-bg: #3b2e2a;
+ --sidebar-fg: #c8c9db;
+ --sidebar-non-existant: #505254;
+ --sidebar-active: #e69f67;
+ --sidebar-spacer: #45373a;
+
+ --scrollbar: var(--sidebar-fg);
+
+ --icons: #737480;
+ --icons-hover: #262625;
+
+ --links: #2b79a2;
+
+ --inline-code-color: #6e6b5e;
+
+ --theme-popup-bg: #e1e1db;
+ --theme-popup-border: #b38f6b;
+ --theme-hover: #99908a;
+
+ --quote-bg: hsl(60, 5%, 75%);
+ --quote-border: hsl(60, 5%, 70%);
+
+ --table-border-color: hsl(60, 9%, 82%);
+ --table-header-bg: #b3a497;
+ --table-alternate-bg: hsl(60, 9%, 84%);
+
+ --searchbar-border-color: #aaa;
+ --searchbar-bg: #fafafa;
+ --searchbar-fg: #000;
+ --searchbar-shadow-color: #aaa;
+ --searchresults-header-fg: #666;
+ --searchresults-border-color: #888;
+ --searchresults-li-bg: #dec2a2;
+ --search-mark-bg: #e69f67;
+}
+
+
+.axo {
+ --color-axo-pink: hsla(326, 100%, 73%, 1);
+ --color-axo-pink-dark: hsla(326, 52%, 58%, 1);
+ --color-axo-orange: hsla(0, 87%, 70%, 1);
+ --color-axo-orange-dark: hsla(356, 75%, 64%, 1);
+ --color-axo-highlighter: hsla(51, 100%, 50%, 1);
+ --color-axo-black: hsla(0, 0%, 5%, 1);
+
+ --title-fg: var(--color-axo-pink);
+ --main-font: Comfortaa;
+
+ /* modified version of the navy theme above */
+ --bg: var(--color-axo-black);
+ --fg: #bcbdd0;
+
+ --sidebar-bg: var(--color-axo-black);
+ --sidebar-fg: var(--color-axo-orange);
+ --sidebar-non-existant: #505274;
+ --sidebar-active: var(--color-axo-pink);
+ --sidebar-spacer: var(--color-axo-orange);
+
+ --scrollbar: var(--sidebar-fg);
+
+ --icons: var(--color-axo-orange);
+ --icons-hover: var(--color-axo-pink);
+
+ --links: var(--color-axo-orange);
+
+ --inline-code-color: #c5c8c6;
+
+ --theme-popup-bg: #161923;
+ --theme-popup-border: #737480;
+ --theme-hover: #282e40;
+
+ --quote-bg: hsl(226, 15%, 17%);
+ --quote-border: hsl(226, 15%, 22%);
+
+ --table-border-color: var(--color-axo-orange);
+ --table-header-bg: hsl(226, 23%, 31%);
+ --table-alternate-bg: hsl(226, 23%, 14%);
+
+ --searchbar-border-color: #aaa;
+ --searchbar-bg: #aeaec6;
+ --searchbar-fg: #000;
+ --searchbar-shadow-color: #aaa;
+ --searchresults-header-fg: #5f5f71;
+ --searchresults-border-color: #5c5c68;
+ --searchresults-li-bg: #242430;
+ --search-mark-bg: #a2cff5;
+}
+
+
+.axo-light {
+ --color-axo-pink: hsla(326, 100%, 73%, 1);
+ --color-axo-pink-dark: hsla(326, 52%, 58%, 1);
+ --color-axo-orange: hsla(0, 87%, 70%, 1);
+ --color-axo-orange-dark: hsla(356, 75%, 64%, 1);
+ --color-axo-highlighter: hsla(51, 100%, 50%, 1);
+ --color-axo-black: hsla(0, 0%, 5%, 1);
+
+ --title-fg: var(--color-axo-pink);
+ --main-font: Comfortaa;
+
+ /* modified version of the light theme above */
+ --bg: hsl(0, 0%, 100%);
+ --fg: hsl(0, 0%, 0%);
+
+ --sidebar-bg: #fafafa;
+ --sidebar-fg: var(--color-axo-orange);
+ --sidebar-non-existant: #aaaaaa;
+ --sidebar-active: var(--color-axo-pink);
+ --sidebar-spacer: var(--color-axo-orange);
+
+ --scrollbar: var(--sidebar-fg);
+
+ --icons: var(--color-axo-orange);
+ --icons-hover: var(--color-axo-pink);
+
+ --links: var(--color-axo-orange);
+
+ --inline-code-color: #301900;
+
+ --theme-popup-bg: #fafafa;
+ --theme-popup-border: #cccccc;
+ --theme-hover: #e6e6e6;
+
+ --quote-bg: hsl(197, 37%, 96%);
+ --quote-border: hsl(197, 37%, 91%);
+
+ --table-border-color: var(--color-axo-orange);
+ --table-header-bg: hsl(0, 0%, 80%);
+ --table-alternate-bg: hsl(0, 0%, 97%);
+
+ --searchbar-border-color: #aaa;
+ --searchbar-bg: #fafafa;
+ --searchbar-fg: #000;
+ --searchbar-shadow-color: #aaa;
+ --searchresults-header-fg: #666;
+ --searchresults-border-color: #888;
+ --searchresults-li-bg: #e4f2fe;
+ --search-mark-bg: #a2cff5;
+}
+
+@media (prefers-color-scheme: dark) {
+ .light.no-js {
+ --bg: hsl(200, 7%, 8%);
+ --fg: #98a3ad;
+
+ --sidebar-bg: #292c2f;
+ --sidebar-fg: #a1adb8;
+ --sidebar-non-existant: #505254;
+ --sidebar-active: #3473ad;
+ --sidebar-spacer: #393939;
+
+ --scrollbar: var(--sidebar-fg);
+
+ --icons: #43484d;
+ --icons-hover: #b3c0cc;
+
+ --links: #2b79a2;
+
+ --inline-code-color: #c5c8c6;
+
+ --theme-popup-bg: #141617;
+ --theme-popup-border: #43484d;
+ --theme-hover: #1f2124;
+
+ --quote-bg: hsl(234, 21%, 18%);
+ --quote-border: hsl(234, 21%, 23%);
+
+ --table-border-color: hsl(200, 7%, 13%);
+ --table-header-bg: hsl(200, 7%, 28%);
+ --table-alternate-bg: hsl(200, 7%, 11%);
+
+ --searchbar-border-color: #aaa;
+ --searchbar-bg: #b7b7b7;
+ --searchbar-fg: #000;
+ --searchbar-shadow-color: #aaa;
+ --searchresults-header-fg: #666;
+ --searchresults-border-color: #98a3ad;
+ --searchresults-li-bg: #2b2b2f;
+ --search-mark-bg: #355c7d;
+ }
+}
diff --git a/oranda-css/mdbook-theme/fonts/fonts.css b/oranda-css/mdbook-theme/fonts/fonts.css
new file mode 100644
index 00000000..92075a2f
--- /dev/null
+++ b/oranda-css/mdbook-theme/fonts/fonts.css
@@ -0,0 +1,104 @@
+/* Open Sans is licensed under the Apache License, Version 2.0. See http://www.apache.org/licenses/LICENSE-2.0 */
+/* Source Code Pro is under the Open Font License. See https://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL */
+
+@import url("https://fonts.googleapis.com/css2?family=Comfortaa:wght@400;700&display=swap");
+@import url("https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;600;700&display=swap");
+@import url("https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap");
+
+/* open-sans-300 - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */
+@font-face {
+ font-family: 'Open Sans';
+ font-style: normal;
+ font-weight: 300;
+ src: local('Open Sans Light'), local('OpenSans-Light'),
+ url('open-sans-v17-all-charsets-300.woff2') format('woff2');
+}
+
+/* open-sans-300italic - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */
+@font-face {
+ font-family: 'Open Sans';
+ font-style: italic;
+ font-weight: 300;
+ src: local('Open Sans Light Italic'), local('OpenSans-LightItalic'),
+ url('open-sans-v17-all-charsets-300italic.woff2') format('woff2');
+}
+
+/* open-sans-regular - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */
+@font-face {
+ font-family: 'Open Sans';
+ font-style: normal;
+ font-weight: 400;
+ src: local('Open Sans Regular'), local('OpenSans-Regular'),
+ url('open-sans-v17-all-charsets-regular.woff2') format('woff2');
+}
+
+/* open-sans-italic - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */
+@font-face {
+ font-family: 'Open Sans';
+ font-style: italic;
+ font-weight: 400;
+ src: local('Open Sans Italic'), local('OpenSans-Italic'),
+ url('open-sans-v17-all-charsets-italic.woff2') format('woff2');
+}
+
+/* open-sans-600 - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */
+@font-face {
+ font-family: 'Open Sans';
+ font-style: normal;
+ font-weight: 600;
+ src: local('Open Sans SemiBold'), local('OpenSans-SemiBold'),
+ url('open-sans-v17-all-charsets-600.woff2') format('woff2');
+}
+
+/* open-sans-600italic - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */
+@font-face {
+ font-family: 'Open Sans';
+ font-style: italic;
+ font-weight: 600;
+ src: local('Open Sans SemiBold Italic'), local('OpenSans-SemiBoldItalic'),
+ url('open-sans-v17-all-charsets-600italic.woff2') format('woff2');
+}
+
+/* open-sans-700 - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */
+@font-face {
+ font-family: 'Open Sans';
+ font-style: normal;
+ font-weight: 700;
+ src: local('Open Sans Bold'), local('OpenSans-Bold'),
+ url('open-sans-v17-all-charsets-700.woff2') format('woff2');
+}
+
+/* open-sans-700italic - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */
+@font-face {
+ font-family: 'Open Sans';
+ font-style: italic;
+ font-weight: 700;
+ src: local('Open Sans Bold Italic'), local('OpenSans-BoldItalic'),
+ url('open-sans-v17-all-charsets-700italic.woff2') format('woff2');
+}
+
+/* open-sans-800 - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */
+@font-face {
+ font-family: 'Open Sans';
+ font-style: normal;
+ font-weight: 800;
+ src: local('Open Sans ExtraBold'), local('OpenSans-ExtraBold'),
+ url('open-sans-v17-all-charsets-800.woff2') format('woff2');
+}
+
+/* open-sans-800italic - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */
+@font-face {
+ font-family: 'Open Sans';
+ font-style: italic;
+ font-weight: 800;
+ src: local('Open Sans ExtraBold Italic'), local('OpenSans-ExtraBoldItalic'),
+ url('open-sans-v17-all-charsets-800italic.woff2') format('woff2');
+}
+
+/* source-code-pro-500 - latin_vietnamese_latin-ext_greek_cyrillic-ext_cyrillic */
+@font-face {
+ font-family: 'Source Code Pro';
+ font-style: normal;
+ font-weight: 500;
+ src: url('source-code-pro-v11-all-charsets-500.woff2') format('woff2');
+}
diff --git a/oranda-css/mdbook-theme/index.hbs b/oranda-css/mdbook-theme/index.hbs
new file mode 100644
index 00000000..5111bc16
--- /dev/null
+++ b/oranda-css/mdbook-theme/index.hbs
@@ -0,0 +1,317 @@
+
+
+
+
+
+ {{ title }}
+ {{#if is_print }}
+
+ {{/if}}
+ {{#if base_url}}
+
+ {{/if}}
+
+
+
+ {{> head}}
+
+
+
+
+
+ {{#if favicon_svg}}
+
+ {{/if}}
+ {{#if favicon_png}}
+
+ {{/if}}
+
+
+
+ {{#if print_enable}}
+
+ {{/if}}
+
+
+
+ {{#if copy_fonts}}
+
+ {{/if}}
+
+
+
+
+
+
+
+ {{#each additional_css}}
+
+ {{/each}}
+
+ {{#if mathjax_support}}
+
+
+ {{/if}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{> header}}
+
+
+
+ {{#if search_enabled}}
+
+ {{/if}}
+
+
+
+
+
+
+ {{{ content }}}
+
+
+
+
+
+
+
+
+
+
+ {{#if live_reload_endpoint}}
+
+
+ {{/if}}
+
+ {{#if google_analytics}}
+
+
+ {{/if}}
+
+ {{#if playground_line_numbers}}
+
+ {{/if}}
+
+ {{#if playground_copyable}}
+
+ {{/if}}
+
+ {{#if playground_js}}
+
+
+
+
+
+ {{/if}}
+
+ {{#if search_js}}
+
+
+
+ {{/if}}
+
+
+
+
+
+
+ {{#each additional_js}}
+
+ {{/each}}
+
+ {{#if is_print}}
+ {{#if mathjax_support}}
+
+ {{else}}
+
+ {{/if}}
+ {{/if}}
+
+
+
+
diff --git a/src/errors.rs b/src/errors.rs
index 7cdd5403..edabc234 100644
--- a/src/errors.rs
+++ b/src/errors.rs
@@ -108,6 +108,20 @@ pub enum OrandaError {
#[diagnostic_source]
cause: axoproject::errors::AxoprojectError,
},
+ /// This error indicates we tried to deserialize some TOML with toml_edit
+ /// but failed.
+ #[error("Failed to edit toml document")]
+ TomlEdit {
+ /// The SourceFile we were trying to parse
+ #[source_code]
+ source: axoasset::SourceFile,
+ /// The range the error was found on
+ #[label]
+ span: Option,
+ /// Details of the error
+ #[source]
+ details: toml_edit::TomlError,
+ },
#[error("We were unable to watch your filesystem for changes")]
#[diagnostic(help = "Make sure that oranda has privileges to set up file watchers!")]
diff --git a/src/lib.rs b/src/lib.rs
index d7a67fe8..35f2dcfa 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,4 +1,5 @@
#![allow(clippy::uninlined_format_args)]
+#![allow(clippy::result_large_err)]
pub mod config;
pub mod data;
diff --git a/src/site/mdbook.rs b/src/site/mdbook.rs
new file mode 100644
index 00000000..de4fc1ed
--- /dev/null
+++ b/src/site/mdbook.rs
@@ -0,0 +1,129 @@
+use axoasset::{LocalAsset, SourceFile};
+use camino::{Utf8Path, Utf8PathBuf};
+use mdbook::MDBook;
+
+use crate::config::MdBookConfig;
+use crate::errors::*;
+use crate::message::{Message, MessageType};
+use crate::site::Site;
+
+use toml_edit::value;
+
+/// Name of the config for mdbook
+const MDBOOK_TOML: &str = "book.toml";
+
+// Files we're importing
+const THEME_GENERAL_CSS_PATH: &str = "css/general.css";
+const THEME_GENERAL_CSS: &str = include_str!("../../oranda-css/mdbook-theme/css/general.css");
+const THEME_VARIABLES_CSS_PATH: &str = "css/variables.css";
+const THEME_VARIABLES_CSS: &str = include_str!("../../oranda-css/mdbook-theme/css/variables.css");
+const THEME_FONTS_CSS_PATH: &str = "fonts/fonts.css";
+const THEME_FONTS_CSS: &str = include_str!("../../oranda-css/mdbook-theme/fonts/fonts.css");
+const THEME_BOOK_JS_PATH: &str = "book.js";
+const THEME_BOOK_JS: &str = include_str!("../../oranda-css/mdbook-theme/book.js");
+const THEME_INDEX_HBS_PATH: &str = "index.hbs";
+const THEME_INDEX_HBS: &str = include_str!("../../oranda-css/mdbook-theme/index.hbs");
+
+/// Build and write mdbook to the dist dir
+pub fn build_mdbook(dist: &Utf8Path, book_cfg: &MdBookConfig) -> Result<()> {
+ Message::new(MessageType::Info, "Building mdbook...").print();
+ tracing::info!("Building mdbook...");
+
+ // Read mdbook's config to find the right dirs
+ let book_dir = Utf8PathBuf::from(&book_cfg.path);
+
+ if book_cfg.theme.unwrap_or(true) {
+ let md = load_mdbook(&book_dir)?;
+ let theme_dir =
+ Utf8PathBuf::from_path_buf(md.theme_dir()).expect("mdbook theme path wasn't utf8");
+ init_theme(&book_dir, &theme_dir)?;
+ }
+
+ let md = load_mdbook(&book_dir)?;
+
+ let build_dir =
+ Utf8PathBuf::from_path_buf(md.build_dir_for("html")).expect("mdbook path wasn't utf8");
+
+ // Build the mdbook
+ md.build().map_err(|e| OrandaError::MdBookBuild {
+ path: book_dir.to_string(),
+ inner: e,
+ })?;
+
+ // Copy the contents to "public/book/"
+ // FIXME: make this something they can set in the MdBookConfig
+ let book_dist = dist.join("book");
+ Site::copy_static(&book_dist, build_dir.as_str())?;
+
+ Ok(())
+}
+
+fn load_mdbook(book_dir: &Utf8Path) -> Result {
+ let md = MDBook::load(book_dir).map_err(|e| OrandaError::MdBookLoad {
+ path: book_dir.to_string(),
+ inner: e,
+ })?;
+
+ Ok(md)
+}
+
+fn init_theme(book_dir: &Utf8Path, theme_dir: &Utf8Path) -> Result<()> {
+ Message::new(MessageType::Info, "Adding oranda mdbook theme...").print();
+ tracing::info!("Adding oranda mdbook theme...");
+
+ init_theme_files(theme_dir)?;
+ add_theme_to_book_toml(book_dir)?;
+
+ Ok(())
+}
+
+fn init_theme_files(theme_dir: &Utf8Path) -> Result<()> {
+ if theme_dir.exists() {
+ LocalAsset::remove_dir_all(theme_dir.as_str())?;
+ }
+
+ let files = vec![
+ (THEME_GENERAL_CSS_PATH, THEME_GENERAL_CSS),
+ (THEME_VARIABLES_CSS_PATH, THEME_VARIABLES_CSS),
+ (THEME_FONTS_CSS_PATH, THEME_FONTS_CSS),
+ (THEME_BOOK_JS_PATH, THEME_BOOK_JS),
+ (THEME_INDEX_HBS_PATH, THEME_INDEX_HBS),
+ ];
+
+ for (subpath, contents) in files {
+ let path = theme_dir.join(subpath);
+ LocalAsset::create_dir_all(theme_dir.as_str())?;
+ LocalAsset::write_new_all(contents, path)?;
+ }
+
+ Ok(())
+}
+
+fn add_theme_to_book_toml(book_dir: &Utf8Path) -> Result<()> {
+ let book_toml_path = book_dir.join(MDBOOK_TOML);
+ let book_toml_src = SourceFile::load_local(&*book_toml_path)?;
+ let mut book_toml = deserialize_toml_edit(&book_toml_src)?;
+
+ let html_table = &mut book_toml["output"]["html"];
+ html_table["default-theme"] = value("axo");
+ html_table["preferred-dark-theme"] = value("axo");
+
+ let new_toml_contents = book_toml.to_string();
+ LocalAsset::write_new(&new_toml_contents, book_toml_path)?;
+ Ok(())
+}
+
+fn deserialize_toml_edit(src: &SourceFile) -> Result {
+ let toml = src
+ .contents()
+ .parse::()
+ .map_err(|details| {
+ let span = details.span().map(|span| span.into());
+ OrandaError::TomlEdit {
+ source: src.clone(),
+ span,
+ details,
+ }
+ })?;
+ Ok(toml)
+}
diff --git a/src/site/mod.rs b/src/site/mod.rs
index 09fc932c..a10f9fe2 100644
--- a/src/site/mod.rs
+++ b/src/site/mod.rs
@@ -4,7 +4,7 @@ use std::path::Path;
use axoasset::LocalAsset;
use camino::{Utf8Path, Utf8PathBuf};
-use crate::config::{Config, MdBookConfig};
+use crate::config::Config;
use crate::data::Context;
use crate::errors::*;
use crate::message::{Message, MessageType};
@@ -18,6 +18,7 @@ pub mod markdown;
pub mod page;
use page::Page;
pub mod changelog;
+pub mod mdbook;
#[derive(Debug)]
pub struct Site {
@@ -139,7 +140,7 @@ impl Site {
LocalAsset::write_new_all(&page.contents, full_path)?;
}
if let Some(book_cfg) = &config.mdbook {
- Self::handle_mdbook(&dist, book_cfg)?;
+ mdbook::build_mdbook(&dist, book_cfg)?;
}
if Path::new(&config.static_dir).exists() {
Self::copy_static(&dist, &config.static_dir)?;
@@ -166,32 +167,4 @@ impl Site {
}),
}
}
-
- /// Build and write mdbook to the dist dir
- pub fn handle_mdbook(dist: &Utf8Path, book_cfg: &MdBookConfig) -> Result<()> {
- Message::new(MessageType::Info, "Building mdbook...").print();
- tracing::info!("Building mdbook...");
-
- // Read mdbook's config to find the right dirs
- let book_path = &book_cfg.path;
- let md = mdbook::MDBook::load(book_path).map_err(|e| OrandaError::MdBookLoad {
- path: book_path.clone(),
- inner: e,
- })?;
- let build_dir =
- Utf8PathBuf::from_path_buf(md.build_dir_for("html")).expect("mdbook path wasn't utf8");
-
- // Build the mdbook
- md.build().map_err(|e| OrandaError::MdBookBuild {
- path: book_path.clone(),
- inner: e,
- })?;
-
- // Copy the contents to "public/book/"
- // FIXME: make this something they can set in the MdBookConfig
- let book_dist = dist.join("book");
- Self::copy_static(&book_dist, build_dir.as_str())?;
-
- Ok(())
- }
}