新增章节内目录、评论系统,支持屏幕大小自适应

pull/591/head
sunface 3 years ago
parent 970d9ffba3
commit 295c5f1efe

@ -50,7 +50,7 @@
## 学习社区
为了帮助大家更好的学习和交流 Rust我们建立了一个社区**Rust语言学习社区**。
为了帮助大家更好的学习和交流 Rust我们建立了一个社区**Rust语言学习社区**( Rust学社 )
QQ群 1009730433 欢迎大家加入,一起 happy一起进步。

File diff suppressed because one or more lines are too long

@ -0,0 +1,104 @@
(function() {
var path = window.location.pathname;
if (path.endsWith("/print.html")) {
return;
}
var images = document.querySelectorAll("main img")
Array.prototype.forEach.call(images, function(img) {
img.addEventListener("click", function() {
BigPicture({
el: img,
});
});
});
// Un-active everything when you click it
Array.prototype.forEach.call(document.getElementsByClassName("pagetoc")[0].children, function(el) {
el.addEventHandler("click", function() {
Array.prototype.forEach.call(document.getElementsByClassName("pagetoc")[0].children, function(el) {
el.classList.remove("active");
});
el.classList.add("active");
});
});
var updateFunction = function() {
var id;
var elements = document.getElementsByClassName("header");
Array.prototype.forEach.call(elements, function(el) {
if (window.pageYOffset >= el.offsetTop) {
id = el;
}
});
Array.prototype.forEach.call(document.getElementsByClassName("pagetoc")[0].children, function(el) {
el.classList.remove("active");
});
Array.prototype.forEach.call(document.getElementsByClassName("pagetoc")[0].children, function(el) {
if (id.href.localeCompare(el.href) == 0) {
el.classList.add("active");
}
});
};
// Populate sidebar on load
window.addEventListener('load', function() {
var pagetoc = document.getElementsByClassName("pagetoc")[0];
var elements = document.getElementsByClassName("header");
Array.prototype.forEach.call(elements, function(el) {
var link = document.createElement("a");
// Indent shows hierarchy
var indent = "";
switch (el.parentElement.tagName) {
case "H1":
return;
// case "H2":
// indent = "20px";
// break;
case "H3":
indent = "20px";
break;
case "H4":
indent = "40px";
break;
default:
break;
}
link.appendChild(document.createTextNode(el.text));
link.style.paddingLeft = indent;
link.href = el.href;
pagetoc.appendChild(link);
});
updateFunction.call();
});
// Handle active elements on scroll
window.addEventListener("scroll", updateFunction);
var p = path.replace("index.html", "");
p = p.replace(".html", "");
var strs = p.split("/");
if (strs[strs.length-1] == ""){
strs.pop()
}
var str = strs[strs.length-1];
var title = document.querySelector("main>h1,h2>a").textContent
var gitalk = new Gitalk({
clientID: '07ea0357feefeb9de502',
clientSecret: '2f362f6990633ad63f7455b06fc00f4e45c5847d',
repo: 'rust-course-comments',
owner: 'sunface',
admin: ["sunface"],
labels: ['comments'],
title: title,
createIssueManually: false,
id: str,
distractionFreeMode: true
});
gitalk.render('gitalk-container');
})();

@ -1,33 +0,0 @@
body.light .does_not_compile,
body.light .panics,
body.light .not_desired_behavior,
body.rust .does_not_compile,
body.rust .panics,
body.rust .not_desired_behavior {
background: #fff1f1;
}
body.coal .does_not_compile,
body.coal .panics,
body.coal .not_desired_behavior,
body.navy .does_not_compile,
body.navy .panics,
body.navy .not_desired_behavior,
body.ayu .does_not_compile,
body.ayu .panics,
body.ayu .not_desired_behavior {
background: #501f21;
}
.ferris {
position: absolute;
z-index: 99;
right: 5px;
top: 30px;
width: 10%;
height: auto;
}
.ferris-explain {
width: 100px;
}

@ -1,51 +0,0 @@
var ferrisTypes = [
{
attr: 'does_not_compile',
title: 'This code does not compile!'
},
{
attr: 'panics',
title: 'This code panics!'
},
{
attr: 'unsafe',
title: 'This code block contains unsafe code.'
},
{
attr: 'not_desired_behavior',
title: 'This code does not produce the desired behavior.'
}
]
document.addEventListener('DOMContentLoaded', () => {
for (var ferrisType of ferrisTypes) {
attachFerrises(ferrisType)
}
})
function attachFerrises (type) {
var elements = document.getElementsByClassName(type.attr)
for (var codeBlock of elements) {
var lines = codeBlock.textContent.split(/\r|\r\n|\n/).length - 1;
if (lines >= 4) {
attachFerris(codeBlock, type)
}
}
}
function attachFerris (element, type) {
var a = document.createElement('a')
a.setAttribute('href', 'ch00-00-introduction.html#ferris')
a.setAttribute('target', '_blank')
var img = document.createElement('img')
img.setAttribute('src', '/img/ferris/' + type.attr + '.svg')
img.setAttribute('title', type.title)
img.className = 'ferris'
a.appendChild(img)
element.parentElement.insertBefore(a, element)
}

@ -1,9 +0,0 @@
span.caption {
font-size: .8em;
font-weight: 600;
}
span.caption code {
font-size: 0.875em;
font-weight: 400;
}

@ -5,8 +5,8 @@ title = "Rust语言圣经(Rust教程 Rust Course)"
src = "src"
[output.html]
additional-css = ["assets/ferris.css", "assets/theme/2018-edition.css"]
additional-js = ["assets/ferris.js"]
additional-css = ["theme/style2.css"]
additional-js = ["assets/custom0.js", "assets/bigPicture.js"]
git-repository-url = "https://github.com/sunface/rust-course"
edit-url-template = "https://github.com/sunface/rust-course/edit/main/{path}"

@ -217,6 +217,7 @@
- [数据布局](too-many-lists/unsafe-queue/layout.md)
- [基本操作](too-many-lists/unsafe-queue/basics.md)
- [Miri](too-many-lists/unsafe-queue/miri.md)
- [栈借用](too-many-lists/unsafe-queue/stacked-borrow.md)
- [Rust 性能优化 todo](profiling/intro.md)
- [深入内存 todo](profiling/memory/intro.md)
- [指针和引用 todo](profiling/memory/pointer-ref.md)

@ -0,0 +1,111 @@
# 栈借用( Stacked Borrorw)
上一章节中我们运行 miri 时遇到了一个栈借用错误,还给了文档链接,但这些文档主要是给编译器开发者和 Rust 研究者看的,因此就不进行讲解了。
而这里,我们将从一个更高层次的角度来看看何为栈借用。
> 目前栈借用在 Rust 语义模型中还是试验阶段,因此破坏这些规则不一定说明你的程序错了。但是除非你在做编译器开发,否则最好还是修复这些错误。事前的麻烦总比事后的不安全要好,特别是当涉及到 UB 未定义行为时
## 指针混叠( Pointer Aliasing )
在开始了解我们破坏的规则之前,首先应该了解为何会有这些规则的存在。这里有多个动机,但是我认为最重要的动机是: 指针混叠.
当两个指针指向的内存区域存在重叠时,就说这两个指针发生了混叠,这种情况会造成一些问题。例如,编译器使用指针混叠的信息来优化内存的访问,当这些信息出错时,那程序就会被不正确地编译,然后产生一些奇怪的结果。
> 实际上,混叠更多关心的是内存访问而不是指针本身,而且只有在其中一个访问是可变的时,才可能出问题。之所以说指针,是因为指针这个概念更方便跟一些规则进行关联。
再比如,编译器需要获取一个值时,是该去缓存中查询还是每次都去内存中加载呢?关于这个选择,编译器需要清晰地知道是否有一个指针在背后修改内存,如果内存值被修改了,那缓存显然就失效了。
## 安全地栈借用
有了之前的铺垫,大家肯定希望编译器能对指针混叠的信息了若指掌,但是可以吗?对于 Rust 正常代码而言,这种情况是可以避免的,因为严格的借用规则是我们的后盾:要么同时存在一个可变引用,要么同时存在多个不可变引用,这种规则简直完美避免了:两个指针指向同一块儿重叠内存区域,而其中一个是可变指针。
然而实际使用中,有一些情况会较为复杂,例如以下代码中发生了可变引用的再借用( reborrow )
```rust
let mut data = 10;
let ref1 = &mut data;
let ref2 = &mut *ref1;
*ref2 += 2;
*ref1 += 1;
println!("{}", data);
```
看上去像是违反了借用规则,但是这段代码确实可以正常编译运行,如果交换下引用使用的顺序呢?
```rust
let mut data = 10;
let ref1 = &mut data;
let ref2 = &mut *ref1;
// ORDER SWAPPED!
*ref1 += 1;
*ref2 += 2;
println!("{}", data);
```
```shell
error[E0503]: cannot use `*ref1` because it was mutably borrowed
--> src/main.rs:6:5
|
4 | let ref2 = &mut *ref1;
| ---------- borrow of `*ref1` occurs here
5 |
6 | *ref1 += 1;
| ^^^^^^^^^^ use of borrowed `*ref1`
7 | *ref2 += 2;
| ---------- borrow later used here
For more information about this error, try `rustc --explain E0503`.
error: could not compile `playground` due to previous error
```
果不其然,编译器抛出了错误,当我们再借用了一个可变引用时,那原始的引用就不能再被使用,直到借用者完成了任务:借用者的借用有效范围并不是看作用域,而是看最后一次使用的位置,正因为如此,第一段代码可以编译通过,而第二段不行,这是著名的生命周期 [NLL 规则](https://course.rs/advance/lifetime/advance.html#nll-non-lexical-lifetime)。
以上就是我们拥有再借用但是还拥有混叠信息的原因:所有的再借用都在清晰地进行嵌套,因此每个再借用都不会与其它的冲突。那大家知道什么方法可以很好的展现嵌套的事物吗?答案就是使用栈来存放这些嵌套的借用。
嘿,这不就是栈借用吗?
这个栈的顶部借用就是当前正在使用( live )的借用,而它清晰的知道在它使用的期间不会发生混叠。当对一个指针进行再借用时,新的借用会被插入到栈的顶部,并变成 live 状态。如果要将一个旧的指针变成 live就需要将借用栈上在它之前的借用全部弹出( pop )。
通过栈借用的方式,我们保证了尽管存在多个再借用,但是在同一个时间,只会有一个可变引用访问目标内存,再也不用担心指针混叠的问题了。只要不去访问一个已经被弹出借用栈的指针,就会非常安全!
从表述方式来说,与其说使用 `ref1` 会让 `ref2` 不合法,不如说 `ref2` 必须要在所有使用情况下合法,`ref1` 恰恰是其中一种情况,会破坏 `ref2` 的合法性。而编译器的报错也是选择了第二种表述方式:无法使用 `*ref1`,原因是它已经被可变借用了,可以看出,第二种表述方式比第一种要更加符合直觉。
**但是,当使用 `unsafe` 指针时,借用检查器就无法再帮助我们了!**
## 不安全地栈借用
所以,我们现在需要一个方式让 unsafe 指针也可以参与到栈借用系统中来,即使编译器无法正确地跟踪它们。同时我们也希望这个系统能宽松一些,不要很容易就产生 UB。
这是一个困难的问题,我也不知道该如何解决,但是目前在编写栈借用系统的开发者显然是有想法的,例如 miri 就是其中一个产物。
从一个高抽象层次来看,当我们将一个引用转换成裸指针时,就是一种再借用。那么随后,裸指针就可以对目标内存进行操作,当再借用结束时,发生的事情跟正常的再借用结束也没有区别。
但是问题是,你还可以将一个裸指针转变成引用,最重要的是,还可以对裸指针进行拷贝!如果发生了以下转换 `&mut -> *mut -> &mut -> *mut`,然后去访问第一个 `*mut`,这种见鬼的情况下,栈借用该如何发挥作用?
反正我不知道,只能求助于 miri 了。事实上正因为这种情况miri 还提供了试验性的模式: `-Zmiri-tag-raw-pointers`。可以通过环境的方式来开启该模式:
```shell
MIRIFLAGS="-Zmiri-tag-raw-pointers" cargo +nightly-2022-01-21 miri test
```
如果是 Windows你需要设置全局变量:
```shell
$env:MIRIFLAGS="-Zmiri-tag-raw-pointers"
cargo +nightly-2022-01-21 miri test
```
## 管理栈借用
因为之前的问题,使用裸指针,应该遵守一个原则:**一旦开始使用裸指针,就要尝试着只使用它**。
现在,我们依然希望在接口中使用安全的引用去构建一个安全的抽象,例如在函数参数中使用引用而不是裸指针,这样我们的用户就无需操心 unsafe 的问题。
为此,我们需要做以下事情:
1. 在开始时,将输入参数中的引用转换成裸指针
2. 在函数体中只使用裸指针
3. 返回之前,将裸指针转换成安全的指针
但是由于数据结构中的字段都是私有的,无需暴露给用户,因此无需这么麻烦,直接使用裸指针即可。
事实上,一个依然存在的问题就是还在继续使用 `Box`, 它会告诉编译器hey这个看上去很像是 `&mut` ,因为它唯一的持有那个指针。
但是我们在链表中一直使用的裸指针是指向 Box 的内部,所以无论何时我们通过正常的方式访问 Box我们都有可能让该裸指针的再借用变得不合法。

@ -0,0 +1,318 @@
<!DOCTYPE HTML>
<html lang="{{ language }}" class="sidebar-visible no-js {{ default_theme }}">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>{{ title }}</title>
{{#if is_print }}
<meta name="robots" content="noindex" />
{{/if}}
{{#if base_url}}
<base href="{{ base_url }}">
{{/if}}
<!-- Custom HTML head -->
{{> head}}
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
<meta name="description" content="{{ description }}">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#ffffff" />
{{#if favicon_svg}}
<link rel="icon" href="{{ path_to_root }}favicon.svg">
{{/if}}
{{#if favicon_png}}
<link rel="shortcut icon" href="{{ path_to_root }}favicon.png">
{{/if}}
<link rel="stylesheet" href="{{ path_to_root }}css/variables.css">
<link rel="stylesheet" href="{{ path_to_root }}css/general.css">
<link rel="stylesheet" href="{{ path_to_root }}css/chrome.css">
{{#if print_enable}}
<link rel="stylesheet" href="{{ path_to_root }}css/print.css" media="print">
{{/if}}
<!-- Fonts -->
<link rel="stylesheet" href="{{ path_to_root }}FontAwesome/css/font-awesome.css">
{{#if copy_fonts}}
<link rel="stylesheet" href="{{ path_to_root }}fonts/fonts.css">
{{/if}}
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" href="{{ path_to_root }}highlight.css">
<link rel="stylesheet" href="{{ path_to_root }}tomorrow-night.css">
<link rel="stylesheet" href="{{ path_to_root }}ayu-highlight.css">
<!-- Custom theme stylesheets -->
{{#each additional_css}}
<link rel="stylesheet" href="{{ ../path_to_root }}{{ this }}">
{{/each}}
{{#if mathjax_support}}
<!-- MathJax -->
<script async type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
{{/if}}
<link rel="stylesheet" href="https://unpkg.com/gitalk/dist/gitalk.css">
<script src="https://unpkg.com/gitalk/dist/gitalk.min.js"></script>
</head>
<body>
<!-- Provide site root to javascript -->
<script type="text/javascript">
var path_to_root = "{{ path_to_root }}";
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "{{ preferred_dark_theme }}" : "{{ default_theme }}";
</script>
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script type="text/javascript">
try {
var theme = localStorage.getItem('mdbook-theme');
var sidebar = localStorage.getItem('mdbook-sidebar');
if (theme.startsWith('"') && theme.endsWith('"')) {
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
}
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
}
} catch (e) { }
</script>
<!-- Set the theme before any content is loaded, prevents flash -->
<script type="text/javascript">
var theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
var html = document.querySelector('html');
html.classList.remove('no-js')
html.classList.remove('{{ default_theme }}')
html.classList.add(theme);
html.classList.add('js');
</script>
<!-- Hide / unhide sidebar before it is displayed -->
<script type="text/javascript">
var html = document.querySelector('html');
var sidebar = 'hidden';
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
}
html.classList.remove('sidebar-visible');
html.classList.add("sidebar-" + sidebar);
</script>
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
<div class="sidebar-scrollbox">
{{#toc}}{{/toc}}
</div>
<div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
</nav>
<div id="page-wrapper" class="page-wrapper">
<div class="page">
{{> header}}
<div id="menu-bar-hover-placeholder"></div>
<div id="menu-bar" class="menu-bar sticky bordered">
<div class="left-buttons">
<button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<i class="fa fa-bars"></i>
</button>
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
<i class="fa fa-paint-brush"></i>
</button>
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="light">{{ theme_option "Light" }}</button></li>
<li role="none"><button role="menuitem" class="theme" id="rust">{{ theme_option "Rust" }}</button></li>
<li role="none"><button role="menuitem" class="theme" id="coal">{{ theme_option "Coal" }}</button></li>
<li role="none"><button role="menuitem" class="theme" id="navy">{{ theme_option "Navy" }}</button></li>
<li role="none"><button role="menuitem" class="theme" id="ayu">{{ theme_option "Ayu" }}</button></li>
</ul>
{{#if search_enabled}}
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
<i class="fa fa-search"></i>
</button>
{{/if}}
</div>
<h1 class="menu-title">{{ book_title }}</h1>
<div class="right-buttons">
{{#if print_enable}}
<a href="{{ path_to_root }}print.html" title="Print this book" aria-label="Print this book">
<i id="print-button" class="fa fa-print"></i>
</a>
{{/if}}
{{#if git_repository_url}}
<a href="{{git_repository_url}}" title="Git repository" aria-label="Git repository">
<i id="git-repository-button" class="fa {{git_repository_icon}}"></i>
</a>
{{/if}}
{{#if git_repository_edit_url}}
<a href="{{git_repository_edit_url}}" title="Suggest an edit" aria-label="Suggest an edit">
<i id="git-edit-button" class="fa fa-edit"></i>
</a>
{{/if}}
</div>
</div>
{{#if search_enabled}}
<div id="search-wrapper" class="hidden">
<form id="searchbar-outer" class="searchbar-outer">
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
</form>
<div id="searchresults-outer" class="searchresults-outer hidden">
<div id="searchresults-header" class="searchresults-header"></div>
<ul id="searchresults">
</ul>
</div>
</div>
{{/if}}
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script type="text/javascript">
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="content" class="content">
<!-- Page table of contents -->
<div class="sidetoc"><nav class="pagetoc"></nav></div>
<main>
{{{ content }}}
<div id="gitalk-container"></div>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
{{#previous}}
<a rel="prev" href="{{ path_to_root }}{{link}}" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
{{/previous}}
{{#next}}
<a rel="next" href="{{ path_to_root }}{{link}}" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
{{/next}}
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
{{#previous}}
<a rel="prev" href="{{ path_to_root }}{{link}}" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
{{/previous}}
{{#next}}
<a rel="next" href="{{ path_to_root }}{{link}}" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
{{/next}}
</nav>
</div>
{{#if livereload}}
<!-- Livereload script (if served using the cli tool) -->
<script type="text/javascript">
var socket = new WebSocket("{{{livereload}}}");
socket.onmessage = function (event) {
if (event.data === "reload") {
socket.close();
location.reload();
}
};
window.onbeforeunload = function() {
socket.close();
}
</script>
{{/if}}
{{#if google_analytics}}
<!-- Google Analytics Tag -->
<script type="text/javascript">
var localAddrs = ["localhost", "127.0.0.1", ""];
// make sure we don't activate google analytics if the developer is
// inspecting the book locally...
if (localAddrs.indexOf(document.location.hostname) === -1) {
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
ga('create', '{{google_analytics}}', 'auto');
ga('send', 'pageview');
}
</script>
{{/if}}
{{#if playground_line_numbers}}
<script type="text/javascript">
window.playground_line_numbers = true;
</script>
{{/if}}
{{#if playground_copyable}}
<script type="text/javascript">
window.playground_copyable = true;
</script>
{{/if}}
{{#if playground_js}}
<script src="{{ path_to_root }}ace.js" type="text/javascript" charset="utf-8"></script>
<script src="{{ path_to_root }}editor.js" type="text/javascript" charset="utf-8"></script>
<script src="{{ path_to_root }}mode-rust.js" type="text/javascript" charset="utf-8"></script>
<script src="{{ path_to_root }}theme-dawn.js" type="text/javascript" charset="utf-8"></script>
<script src="{{ path_to_root }}theme-tomorrow_night.js" type="text/javascript" charset="utf-8"></script>
{{/if}}
{{#if search_js}}
<script src="{{ path_to_root }}elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
<script src="{{ path_to_root }}mark.min.js" type="text/javascript" charset="utf-8"></script>
<script src="{{ path_to_root }}searcher.js" type="text/javascript" charset="utf-8"></script>
{{/if}}
<script src="{{ path_to_root }}clipboard.min.js" type="text/javascript" charset="utf-8"></script>
<script src="{{ path_to_root }}highlight.js" type="text/javascript" charset="utf-8"></script>
<script src="{{ path_to_root }}book.js" type="text/javascript" charset="utf-8"></script>
<!-- Custom JS scripts -->
{{#each additional_js}}
<script type="text/javascript" src="{{ ../path_to_root }}{{this}}"></script>
{{/each}}
{{#if is_print}}
{{#if mathjax_support}}
<script type="text/javascript">
window.addEventListener('load', function() {
MathJax.Hub.Register.StartupHook('End', function() {
window.setTimeout(window.print, 100);
});
});
</script>
{{else}}
<script type="text/javascript">
window.addEventListener('load', function() {
window.setTimeout(window.print, 100);
});
</script>
{{/if}}
{{/if}}
</body>
</html>

@ -0,0 +1,53 @@
@media only screen and (max-width:1080px) {
.sidetoc {
display: none !important;
}
}
@media only screen and (min-width:1080px) {
main {
position: relative;
padding-right: 170px !important;
}
.sidetoc {
margin-left: auto;
margin-right: auto;
/*left: calc(100% + (var(--content-max-width))/4 - 180px);*/
left: calc(100% - 200px);
position: absolute;
}
.pagetoc {
position: fixed;
width: 200px;
height: calc(100vh - var(--menu-bar-height) - 0.67em * 4);
overflow: auto;
}
.pagetoc a {
border-left: 1px solid var(--sidebar-bg);
color: var(--fg) !important;
display: block;
padding-bottom: 5px;
padding-top: 5px;
padding-left: 10px;
text-align: left;
text-decoration: none;
font-size: 1.2rem;
}
.pagetoc a:hover,
.pagetoc a.active {
background: var(--sidebar-bg);
color: var(--sidebar-fg) !important;
}
.pagetoc .active {
background: var(--sidebar-bg);
color: var(--sidebar-fg);
}
}
.page-footer {
margin-top: 50px;
border-top: 1px solid #ccc;
overflow: hidden;
padding: 10px 0;
color: gray;
}
Loading…
Cancel
Save