From 88660684b7c47d8018196b597a653f67186e2cc6 Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Thu, 20 Dec 2018 14:52:06 +0100 Subject: [PATCH] add mdbook --- .gitignore | 1 + Cargo.toml | 6 +- book.toml | 13 + booksrc/SUMMARY.md | 13 + booksrc/tutorial1.md | 3 + booksrc/tutorial10.md | 8 + booksrc/tutorial11.md | 8 + booksrc/tutorial2.md | 8 + booksrc/tutorial3.md | 8 + booksrc/tutorial4.md | 8 + booksrc/tutorial5.md | 8 + booksrc/tutorial6.md | 8 + booksrc/tutorial7.md | 8 + booksrc/tutorial8.md | 8 + booksrc/tutorial9.md | 8 + examples/tutorial1.rs | 8 - examples/tutorial10.rs | 19 +- examples/tutorial11.rs | 19 +- examples/tutorial2.rs | 15 +- examples/tutorial3.rs | 15 +- examples/tutorial4.rs | 15 +- examples/tutorial5.rs | 12 +- examples/tutorial6.rs | 14 +- examples/tutorial7.rs | 16 +- examples/tutorial8.rs | 16 +- examples/tutorial9.rs | 16 +- src/lib.rs | 21 +- theme/book.js | 611 +++++++++++++++++++++++++++++++++++++++++ 28 files changed, 739 insertions(+), 174 deletions(-) create mode 100644 book.toml create mode 100644 booksrc/SUMMARY.md create mode 100644 booksrc/tutorial1.md create mode 100644 booksrc/tutorial10.md create mode 100644 booksrc/tutorial11.md create mode 100644 booksrc/tutorial2.md create mode 100644 booksrc/tutorial3.md create mode 100644 booksrc/tutorial4.md create mode 100644 booksrc/tutorial5.md create mode 100644 booksrc/tutorial6.md create mode 100644 booksrc/tutorial7.md create mode 100644 booksrc/tutorial8.md create mode 100644 booksrc/tutorial9.md create mode 100644 theme/book.js diff --git a/.gitignore b/.gitignore index f742782..ff24eec 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ **/*.rs.bk .idea/* Cargo.lock +book diff --git a/Cargo.toml b/Cargo.toml index 1951723..41f0011 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Harald Hoyer "] edition = "2018" [features] -default = [ "debug-cause", "fileline"] -fileline = [] +default = [ ] +no-fileline = [] display-cause = [] -debug-cause = [] \ No newline at end of file +no-debug-cause = [] \ No newline at end of file diff --git a/book.toml b/book.toml new file mode 100644 index 0000000..9e74718 --- /dev/null +++ b/book.toml @@ -0,0 +1,13 @@ +[book] +authors = ["Harald Hoyer"] +multilingual = false +src = "booksrc" +title = "chainerror" + +[output.html.playpen] +editable = true + +[build] +build-dir = "docs" +create-missing = true + diff --git a/booksrc/SUMMARY.md b/booksrc/SUMMARY.md new file mode 100644 index 0000000..8c48ac4 --- /dev/null +++ b/booksrc/SUMMARY.md @@ -0,0 +1,13 @@ +# Summary + +- [Chapter 1](./tutorial1.md) +- [Chapter 2](./tutorial2.md) +- [Chapter 3](./tutorial3.md) +- [Chapter 4](./tutorial4.md) +- [Chapter 5](./tutorial5.md) +- [Chapter 6](./tutorial6.md) +- [Chapter 7](./tutorial7.md) +- [Chapter 8](./tutorial8.md) +- [Chapter 9](./tutorial9.md) +- [Chapter 10](./tutorial10.md) +- [Chapter 11](./tutorial11.md) diff --git a/booksrc/tutorial1.md b/booksrc/tutorial1.md new file mode 100644 index 0000000..12bd9cd --- /dev/null +++ b/booksrc/tutorial1.md @@ -0,0 +1,3 @@ +~~~rust +{{#include ../examples/tutorial1.rs:2:}} +~~~ \ No newline at end of file diff --git a/booksrc/tutorial10.md b/booksrc/tutorial10.md new file mode 100644 index 0000000..7be3cb3 --- /dev/null +++ b/booksrc/tutorial10.md @@ -0,0 +1,8 @@ +~~~rust +use crate::chainerror::*; +{{#include ../examples/tutorial10.rs:2:}} +# #[allow(dead_code)] +# mod chainerror { +{{#includecomment ../src/lib.rs}} +# } +~~~ \ No newline at end of file diff --git a/booksrc/tutorial11.md b/booksrc/tutorial11.md new file mode 100644 index 0000000..0af9cea --- /dev/null +++ b/booksrc/tutorial11.md @@ -0,0 +1,8 @@ +~~~rust +use crate::chainerror::*; +{{#include ../examples/tutorial11.rs:2:}} +# #[allow(dead_code)] +# mod chainerror { +{{#includecomment ../src/lib.rs}} +# } +~~~ \ No newline at end of file diff --git a/booksrc/tutorial2.md b/booksrc/tutorial2.md new file mode 100644 index 0000000..dc34731 --- /dev/null +++ b/booksrc/tutorial2.md @@ -0,0 +1,8 @@ +~~~rust +use crate::chainerror::*; +{{#include ../examples/tutorial2.rs:2:}} +# #[allow(dead_code)] +# mod chainerror { +{{#includecomment ../src/lib.rs}} +# } +~~~ \ No newline at end of file diff --git a/booksrc/tutorial3.md b/booksrc/tutorial3.md new file mode 100644 index 0000000..ab61a8d --- /dev/null +++ b/booksrc/tutorial3.md @@ -0,0 +1,8 @@ +~~~rust +use crate::chainerror::*; +{{#include ../examples/tutorial3.rs:2:}} +# #[allow(dead_code)] +# mod chainerror { +{{#includecomment ../src/lib.rs}} +# } +~~~ \ No newline at end of file diff --git a/booksrc/tutorial4.md b/booksrc/tutorial4.md new file mode 100644 index 0000000..7744218 --- /dev/null +++ b/booksrc/tutorial4.md @@ -0,0 +1,8 @@ +~~~rust +use crate::chainerror::*; +{{#include ../examples/tutorial4.rs:2:}} +# #[allow(dead_code)] +# mod chainerror { +{{#includecomment ../src/lib.rs}} +# } +~~~ \ No newline at end of file diff --git a/booksrc/tutorial5.md b/booksrc/tutorial5.md new file mode 100644 index 0000000..ed8ae7a --- /dev/null +++ b/booksrc/tutorial5.md @@ -0,0 +1,8 @@ +~~~rust +use crate::chainerror::*; +{{#include ../examples/tutorial5.rs:2:}} +# #[allow(dead_code)] +# mod chainerror { +{{#includecomment ../src/lib.rs}} +# } +~~~ \ No newline at end of file diff --git a/booksrc/tutorial6.md b/booksrc/tutorial6.md new file mode 100644 index 0000000..8483c94 --- /dev/null +++ b/booksrc/tutorial6.md @@ -0,0 +1,8 @@ +~~~rust +use crate::chainerror::*; +{{#include ../examples/tutorial6.rs:2:}} +# #[allow(dead_code)] +# mod chainerror { +{{#includecomment ../src/lib.rs}} +# } +~~~ \ No newline at end of file diff --git a/booksrc/tutorial7.md b/booksrc/tutorial7.md new file mode 100644 index 0000000..6e5e544 --- /dev/null +++ b/booksrc/tutorial7.md @@ -0,0 +1,8 @@ +~~~rust +use crate::chainerror::*; +{{#include ../examples/tutorial7.rs:2:}} +# #[allow(dead_code)] +# mod chainerror { +{{#includecomment ../src/lib.rs}} +# } +~~~ \ No newline at end of file diff --git a/booksrc/tutorial8.md b/booksrc/tutorial8.md new file mode 100644 index 0000000..3ecb4e7 --- /dev/null +++ b/booksrc/tutorial8.md @@ -0,0 +1,8 @@ +~~~rust +use crate::chainerror::*; +{{#include ../examples/tutorial8.rs:2:}} +# #[allow(dead_code)] +# mod chainerror { +{{#includecomment ../src/lib.rs}} +# } +~~~ \ No newline at end of file diff --git a/booksrc/tutorial9.md b/booksrc/tutorial9.md new file mode 100644 index 0000000..09e20c3 --- /dev/null +++ b/booksrc/tutorial9.md @@ -0,0 +1,8 @@ +~~~rust +use crate::chainerror::*; +{{#include ../examples/tutorial9.rs:2:}} +# #[allow(dead_code)] +# mod chainerror { +{{#includecomment ../src/lib.rs}} +# } +~~~ \ No newline at end of file diff --git a/examples/tutorial1.rs b/examples/tutorial1.rs index 17d5534..4149773 100644 --- a/examples/tutorial1.rs +++ b/examples/tutorial1.rs @@ -1,11 +1,3 @@ -/*! - -~~~bash -$ cargo run -q --example tutorial1 -Error: StringError("func1 error") -~~~ - -!*/ use std::error::Error; use std::result::Result; diff --git a/examples/tutorial10.rs b/examples/tutorial10.rs index 282fbb6..72e703f 100644 --- a/examples/tutorial10.rs +++ b/examples/tutorial10.rs @@ -1,21 +1,4 @@ -/*! - -~~~bash -$ cargo run -q --example tutorial10 -Main Error Report: func1 error calling func2 -Error reported by Func2Error: Error reading 'foo.txt' - -Debug Error: -examples/tutorial10.rs:49: Func2 -Caused by: -examples/tutorial10.rs:29: Func2Error(Error reading 'foo.txt') -Caused by: -Kind(NotFound) -~~~ - -!*/ - -use chainerror::prelude::*; +use chainerror::*; use std::error::Error; use std::io; use std::result::Result; diff --git a/examples/tutorial11.rs b/examples/tutorial11.rs index dd80482..62cabaa 100644 --- a/examples/tutorial11.rs +++ b/examples/tutorial11.rs @@ -1,21 +1,4 @@ -/*! - -~~~bash -$ cargo run -q --example tutorial11 -Main Error Report: func1 error calling func2 -Error reported by Func2Error: Error reading 'foo.txt' - -Debug Error: -examples/tutorial11.rs:57: func1 error calling func2 -Caused by: -examples/tutorial11.rs:32: Func2Error(Error reading 'foo.txt') -Caused by: -Kind(NotFound) -~~~ - -!*/ - -use chainerror::prelude::*; +use chainerror::*; use std::error::Error; use std::io; use std::result::Result; diff --git a/examples/tutorial2.rs b/examples/tutorial2.rs index 2e076c4..2cf855d 100644 --- a/examples/tutorial2.rs +++ b/examples/tutorial2.rs @@ -1,17 +1,4 @@ -/*! - -~~~bash -$ cargo run -q --example tutorial2 -Error: examples/tutorial2.rs:28: "func1 error" -Caused by: -examples/tutorial2.rs:21: "func2 error" -Caused by: -StringError("do_some_io error") -~~~ - -!*/ - -use chainerror::prelude::*; +use chainerror::*; use std::error::Error; use std::result::Result; diff --git a/examples/tutorial3.rs b/examples/tutorial3.rs index 1742cc5..876f5a9 100644 --- a/examples/tutorial3.rs +++ b/examples/tutorial3.rs @@ -1,17 +1,4 @@ -/*! - -~~~bash -$ cargo run -q --example tutorial3 -examples/tutorial3.rs:30: "func1 error" -Caused by: -examples/tutorial3.rs:25: "func2 error" -Caused by: -StringError("do_some_io error") -~~~ - -!*/ - -use chainerror::prelude::*; +use chainerror::*; use std::error::Error; use std::result::Result; diff --git a/examples/tutorial4.rs b/examples/tutorial4.rs index 67ddc55..e55aaed 100644 --- a/examples/tutorial4.rs +++ b/examples/tutorial4.rs @@ -1,17 +1,4 @@ -/*! - -~~~bash -$ cargo run -q --example tutorial4 -examples/tutorial4.rs:29: "func1 error" -Caused by: -examples/tutorial4.rs:24: "func2 error" -Caused by: -StringError("do_some_io error") -~~~ - -!*/ - -use chainerror::prelude::*; +use chainerror::*; use std::error::Error; use std::result::Result; diff --git a/examples/tutorial5.rs b/examples/tutorial5.rs index 5b7cb90..e6f36f3 100644 --- a/examples/tutorial5.rs +++ b/examples/tutorial5.rs @@ -1,14 +1,4 @@ -/*! - -~~~bash -$ cargo run -q --example tutorial5 -Func2 failed because of 'entity not found' -func1 error -~~~ - -!*/ - -use chainerror::prelude::*; +use chainerror::*; use std::error::Error; use std::io; use std::result::Result; diff --git a/examples/tutorial6.rs b/examples/tutorial6.rs index b2b3b2a..aca48b4 100644 --- a/examples/tutorial6.rs +++ b/examples/tutorial6.rs @@ -1,16 +1,4 @@ -/*! - -~~~bash -$ cargo run -q --example tutorial6 -Error: func1 error -caused by: Error reading 'foo.txt' -caused by: std::io::Error: entity not found -of kind: std::io::ErrorKind::NotFound -~~~ - -!*/ - -use chainerror::prelude::*; +use chainerror::*; use std::error::Error; use std::io; use std::result::Result; diff --git a/examples/tutorial7.rs b/examples/tutorial7.rs index 89e002b..3cb3d2c 100644 --- a/examples/tutorial7.rs +++ b/examples/tutorial7.rs @@ -1,18 +1,4 @@ -/*! - -~~~bash -$ cargo run -q --example tutorial7 -Error: func1 error -caused by: std::io::Error: entity not found -of kind: std::io::ErrorKind::NotFound -The root cause was: std::io::Error: Kind( - NotFound -) -~~~ - -!*/ - -use chainerror::prelude::*; +use chainerror::*; use std::error::Error; use std::io; use std::result::Result; diff --git a/examples/tutorial8.rs b/examples/tutorial8.rs index 65e04d1..831e6ed 100644 --- a/examples/tutorial8.rs +++ b/examples/tutorial8.rs @@ -1,18 +1,4 @@ -/*! - -~~~bash -$ cargo run -q --example tutorial8 -Func1Error: func1 error -Func2Error: Error reading 'foo.txt' -Debug Func2Error: -examples/tutorial8.rs:27: Func2Error(Error reading 'foo.txt') -Caused by: -Kind(NotFound) -~~~ - -!*/ - -use chainerror::prelude::*; +use chainerror::*; use std::error::Error; use std::io; use std::result::Result; diff --git a/examples/tutorial9.rs b/examples/tutorial9.rs index b818e35..df4a1e9 100644 --- a/examples/tutorial9.rs +++ b/examples/tutorial9.rs @@ -1,18 +1,4 @@ -/*! - -~~~bash -$ cargo run -q --example tutorial9 -Func1ErrorFunc2: -examples/tutorial9.rs:37: Func1ErrorFunc2(func1 error calling func2) -Caused by: -examples/tutorial9.rs:29: Func2Error(Error reading 'foo.txt') -Caused by: -Kind(NotFound) -~~~ - -!*/ - -use chainerror::prelude::*; +use chainerror::*; use std::error::Error; use std::io; use std::result::Result; diff --git a/src/lib.rs b/src/lib.rs index f3ec61d..0987e34 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,7 +3,7 @@ use std::fmt::{Debug, Display, Formatter, Result}; use std::result::Result as StdResult; pub struct ChainError { - #[cfg(feature = "fileline")] + #[cfg(not(feature = "no-fileline"))] occurrence: Option<(u32, &'static str)>, kind: T, error_cause: Option>, @@ -12,7 +12,7 @@ pub struct ChainError { pub type ChainResult = StdResult>; impl ChainError { - #[cfg(feature = "fileline")] + #[cfg(not(feature = "no-fileline"))] pub fn new( kind: T, error_cause: Option>, @@ -25,7 +25,7 @@ impl ChainError { } } - #[cfg(not(feature = "fileline"))] + #[cfg(feature = "no-fileline")] pub fn new( kind: T, error_cause: Option>, @@ -194,7 +194,7 @@ impl Display for ChainError { impl Debug for ChainError { fn fmt(&self, f: &mut Formatter) -> Result { - #[cfg(feature = "fileline")] + #[cfg(not(feature = "no-fileline"))] { if let Some(o) = self.occurrence { write!(f, "{}:{}: ", o.1, o.0)?; @@ -203,7 +203,7 @@ impl Debug for ChainError { Debug::fmt(&self.kind, f)?; - #[cfg(feature = "debug-cause")] + #[cfg(not(feature = "no-debug-cause"))] { if let Some(e) = self.source() { writeln!(f, "\nCaused by:")?; @@ -274,14 +274,3 @@ macro_rules! try_cherr_mut { $e.downcast_mut::>() }; } - -pub mod prelude { - pub use super::{ - cherr, derive_str_cherr, mstrerr, try_cherr_mut, try_cherr_ref, ChainError, ChainErrorDown, - ChainResult, - }; -} - -#[cfg(test)] -mod tests { -} diff --git a/theme/book.js b/theme/book.js new file mode 100644 index 0000000..8c6946d --- /dev/null +++ b/theme/book.js @@ -0,0 +1,611 @@ +"use strict"; + +// Fix back button cache problem +window.onunload = function () { }; + +// Global variable, shared between modules +function playpen_text(playpen) { + let code_block = playpen.querySelector("code"); + + if (window.ace && code_block.classList.contains("editable")) { + let editor = window.ace.edit(code_block); + return editor.getValue(); + } else { + return code_block.textContent; + } +} + +(function codeSnippets() { + // Hide Rust code lines prepended with a specific character + var hiding_character = "#"; + + function fetch_with_timeout(url, options, timeout = 6000) { + return Promise.race([ + fetch(url, options), + new Promise((_, reject) => setTimeout(() => reject(new Error('timeout')), timeout)) + ]); + } + + var playpens = Array.from(document.querySelectorAll(".playpen")); + if (playpens.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"]); + playpens.forEach(block => handle_crate_list_update(block, playground_crates)); + }); + } + + function handle_crate_list_update(playpen_block, playground_crates) { + // update the play buttons after receiving the response + update_play_button(playpen_block, playground_crates); + + // and install on change listener to dynamically update ACE editors + if (window.ace) { + let code_block = playpen_block.querySelector("code"); + if (code_block.classList.contains("editable")) { + let editor = window.ace.edit(code_block); + editor.addEventListener("change", function (e) { + update_play_button(playpen_block, playground_crates); + }); + } + } + } + + // 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 = playpen_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 = playpen_text(code_block); + + var params = { + channel: "stable", + mode: "debug", + edition: "2018", + crateType: "bin", + tests: false, + code: text + }; + + if (text.indexOf("#![feature") !== -1) { + params.channel = "nightly"; + } + + if (text.indexOf("#[test]") !== -1) { + params.tests = "true"; + } + + if (text.indexOf("#![crate_type=\"lib\"]") !== -1) { + params.crateType = "lib"; + } + + result_block.innerText = "Running..."; + + fetch_with_timeout("https://play.rust-lang.org/execute", { + headers: { + 'Content-Type': "application/json", + }, + method: 'POST', + mode: 'cors', + body: JSON.stringify(params) + }) + .then(response => response.json()) + .then(response => result_block.innerText = response.stderr + "\n\n" + response.stdout) + .catch(error => result_block.innerText = "Playground Communication: " + error.message); + } + + // Syntax highlighting Configuration + hljs.configure({ + tabReplace: ' ', // 4 spaces + languages: [], // Languages used for auto-detection + }); + + if (window.ace) { + // language-rust class needs to be removed for editable + // blocks or highlightjs will capture events + Array + .from(document.querySelectorAll('code.editable')) + .forEach(function (block) { block.classList.remove('language-rust'); }); + + Array + .from(document.querySelectorAll('code:not(.editable)')) + .forEach(function (block) { hljs.highlightBlock(block); }); + } else { + Array + .from(document.querySelectorAll('code')) + .forEach(function (block) { hljs.highlightBlock(block); }); + } + + // Adding the hljs class gives code blocks the color css + // even if highlighting doesn't apply + Array + .from(document.querySelectorAll('code')) + .forEach(function (block) { block.classList.add('hljs'); }); + + Array.from(document.querySelectorAll("code.language-rust")).forEach(function (block) { + + var code_block = block; + var pre_block = block.parentNode; + // hide lines + var lines = code_block.innerHTML.split("\n"); + var first_non_hidden_line = false; + var lines_hidden = false; + var trimmed_line = ""; + + for (var n = 0; n < lines.length; n++) { + trimmed_line = lines[n].trim(); + if (trimmed_line[0] == hiding_character && trimmed_line[1] != hiding_character) { + if (first_non_hidden_line) { + lines[n] = "" + "\n" + lines[n].replace(/(\s*)# ?/, "$1") + ""; + } + else { + lines[n] = "" + lines[n].replace(/(\s*)# ?/, "$1") + "\n" + ""; + } + lines_hidden = true; + } + else if (first_non_hidden_line) { + lines[n] = "\n" + lines[n]; + } + else { + first_non_hidden_line = true; + } + if (trimmed_line[0] == hiding_character && trimmed_line[1] == hiding_character) { + lines[n] = lines[n].replace("##", "#") + } + } + code_block.innerHTML = lines.join(""); + + // If no lines were hidden, return + if (!lines_hidden) { return; } + + var buttons = document.createElement('div'); + buttons.className = 'buttons'; + buttons.innerHTML = ""; + + // add expand button + pre_block.insertBefore(buttons, pre_block.firstChild); + + pre_block.querySelector('.buttons').addEventListener('click', function (e) { + if (e.target.classList.contains('fa-expand')) { + var lines = pre_block.querySelectorAll('span.hidden'); + + e.target.classList.remove('fa-expand'); + e.target.classList.add('fa-compress'); + e.target.title = 'Hide lines'; + e.target.setAttribute('aria-label', e.target.title); + + Array.from(lines).forEach(function (line) { + line.classList.remove('hidden'); + line.classList.add('unhidden'); + }); + } else if (e.target.classList.contains('fa-compress')) { + var lines = pre_block.querySelectorAll('span.unhidden'); + + e.target.classList.remove('fa-compress'); + e.target.classList.add('fa-expand'); + e.target.title = 'Show hidden lines'; + e.target.setAttribute('aria-label', e.target.title); + + Array.from(lines).forEach(function (line) { + line.classList.remove('unhidden'); + line.classList.add('hidden'); + }); + } + }); + }); + + Array.from(document.querySelectorAll('pre code')).forEach(function (block) { + var pre_block = block.parentNode; + if (!pre_block.classList.contains('playpen')) { + 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 playpen code blocks + Array.from(document.querySelectorAll(".playpen")).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); + + 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(runCodeButton, buttons.firstChild); + buttons.insertBefore(copyCodeClipboardButton, buttons.firstChild); + + runCodeButton.addEventListener('click', function (e) { + run_rust_code(pre_block); + }); + + 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#" + document.body.className).focus(); + } + + function hideThemes() { + themePopup.style.display = 'none'; + themeToggleButton.setAttribute('aria-expanded', false); + themeToggleButton.focus(); + } + + function set_theme(theme) { + let ace_theme; + + if (theme == 'coal' || theme == 'navy') { + 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; + try { previousTheme = localStorage.getItem('mdbook-theme'); } catch (e) { } + if (previousTheme === null || previousTheme === undefined) { previousTheme = default_theme; } + + try { localStorage.setItem('mdbook-theme', theme); } catch (e) { } + + document.body.className = theme; + html.classList.remove(previousTheme); + html.classList.add(theme); + } + + // Set theme + var theme; + try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { } + if (theme === null || theme === undefined) { theme = default_theme; } + + set_theme(theme); + + themeToggleButton.addEventListener('click', function () { + if (themePopup.style.display === 'block') { + hideThemes(); + } else { + showThemes(); + } + }); + + themePopup.addEventListener('click', function (e) { + var theme = e.target.id || e.target.parentElement.id; + 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-nursery/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 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) { } + } + + 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")) { + showSidebar(); + } else if (html.classList.contains("sidebar-visible")) { + hideSidebar(); + } else { + if (getComputedStyle(sidebar)['transform'] === 'none') { + hideSidebar(); + } else { + showSidebar(); + } + } + }); + + 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 = sidebar.querySelector(".active"); + if (activeSection) { + sidebar.scrollTop = activeSection.offsetTop; + } +})(); + +(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 Clipboard('.clip-button', { + text: function (trigger) { + hideTooltip(trigger); + let playpen = trigger.closest("pre"); + return playpen_text(playpen); + } + }); + + 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 autoHideMenu() { + var menu = document.getElementById('menu-bar'); + + var previousScrollTop = document.scrollingElement.scrollTop; + + document.addEventListener('scroll', function () { + if (menu.classList.contains('folded') && document.scrollingElement.scrollTop < previousScrollTop) { + menu.classList.remove('folded'); + } else if (!menu.classList.contains('folded') && document.scrollingElement.scrollTop > previousScrollTop) { + menu.classList.add('folded'); + } + + if (!menu.classList.contains('bordered') && document.scrollingElement.scrollTop > 0) { + menu.classList.add('bordered'); + } + + if (menu.classList.contains('bordered') && document.scrollingElement.scrollTop === 0) { + menu.classList.remove('bordered'); + } + + previousScrollTop = document.scrollingElement.scrollTop; + }, { passive: true }); +})();