Various 3rd edition template improvements

- merge improvements from second edition (e.g. improved light switch, prefered theme in session storage, translation support)
- giscus instead of utterances
- add an alpha warning
- fix error caused by missing posts

etc
This commit is contained in:
Philipp Oppermann
2022-01-23 21:32:43 +01:00
parent 6f1b982f3a
commit 233dec4caf
6 changed files with 176 additions and 152 deletions

View File

@@ -1,3 +1,21 @@
+++ +++
template = "edition-3/index.html" template = "edition-3/index.html"
+++ +++
<h1>Writing an OS in Rust</h1>
<h1 style="visibility: hidden; height: 0px; margin: 0px; padding: 0px;">Writing an OS in Rust</h1>
<p>A blog by Philipp Oppermann <em class="gray">— Third Edition (Alpha Release)</em></p>
<div class="front-page-introduction">
This blog series creates a small operating system in the [Rust programming language](https://www.rust-lang.org/). Each post is a small tutorial and includes all needed code, so you can follow along if you like. The source code is also available in the corresponding [Github repository](https://github.com/phil-opp/blog_os).
<!-- alpha-warning -->
We explain how to create an operating system for the **`x86_64`** architecture step by step. Starting from scratch, we create a bootable OS kernel, implement basic input/output support, show how to test and debug our kernel, explain virtual memory management, and add support for multitasking and userspace programs.
Latest post: <!-- latest-post -->
</div>

View File

@@ -16,7 +16,7 @@
{% block after_main %} {% block after_main %}
<hr> <hr>
<section> <section>
<h2>Comments</h2> <h2 id="comments">Comments</h2>
{{ snippets::utterances() }} {{ snippets::giscus(search_term=page.title ~ " (Extra Post)") }}
</section> </section>
{% endblock after_main %} {% endblock after_main %}

View File

@@ -6,6 +6,7 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="apple-mobile-web-app-capable" content="yes"> <meta name="apple-mobile-web-app-capable" content="yes">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="color-scheme" content="light dark">
<meta name="description" content="{% block description %}{{ config.description }}{% endblock description %}"> <meta name="description" content="{% block description %}{{ config.description }}{% endblock description %}">
<meta name="author" content="{{ config.extra.author.name }}"> <meta name="author" content="{{ config.extra.author.name }}">
@@ -16,6 +17,13 @@
<link rel="alternate" type="application/rss+xml" title="RSS feed for os.phil-opp.com" href="{{ config.base_url | safe }}/rss.xml" /> <link rel="alternate" type="application/rss+xml" title="RSS feed for os.phil-opp.com" href="{{ config.base_url | safe }}/rss.xml" />
<script>
let theme = localStorage.getItem("theme");
if (theme != null) {
document.documentElement.setAttribute("data-theme", theme);
}
</script>
<script async src="/js/edition-3/main.js"></script> <script async src="/js/edition-3/main.js"></script>
<title>{% block title %}{% endblock title %} (Third Edition - Alpha)</title> <title>{% block title %}{% endblock title %} (Third Edition - Alpha)</title>
@@ -34,30 +42,19 @@
<footer class="footer"> <footer class="footer">
<hr> <hr>
<div class="theme-switch">
<div class="light-switch" onclick="toggle_lights()" title="Switch between light and dark theme"></div>
<div class="light-switch-reset" onclick="clear_theme_override()" title="Clear the theme override and go back to the system theme"></div>
</div>
<small> <small>
&copy; <time datetime="2020">2020</time>. All rights reserved. &copy; <time datetime="2022">2022</time>. All rights reserved.
<a href="{{ get_url(path="@/pages/contact.md") | safe }}">Contact</a> <a class="spaced" href="https://github.com/phil-opp/blog_os#license">License</a>
<a class="spaced" href="{{ get_url(path="@/pages/contact.md") | safe }}">Contact</a>
</small> </small>
</footer> </footer>
</div> </div>
<div class="light-switch" onclick="toggle_lights()"></div> <script data-goatcounter="https://phil-opp.goatcounter.com/count" async src="//gc.zgo.at/count.js"></script>
<!-- Fathom - simple website analytics - https://github.com/usefathom/fathom -->
<script>
(function(f, a, t, h, o, m){
a[h]=a[h]||function(){
(a[h].q=a[h].q||[]).push(arguments)
};
o=f.createElement('script'),
m=f.getElementsByTagName('script')[0];
o.async=1; o.src=t; o.id='fathom-script';
m.parentNode.insertBefore(o,m)
})(document, window, '//fathom.phil-opp.com/tracker.js', 'fathom');
fathom('set', 'siteId', 'MUXWM');
fathom('trackPageview');
</script>
<!-- / Fathom -->
</body> </body>
</html> </html>

View File

@@ -6,34 +6,20 @@
{% block title %}{{ config.title }}{% endblock title %} {% block title %}{{ config.title }}{% endblock title %}
{% block main %} {% block main %}
{% set posts_section = get_section(path = "edition-3/posts/_index.md") %} {% set posts_section = get_section(path = "edition-3/posts/_index.md") %}
{% set posts = posts_section.pages %} {% set posts = posts_section.pages %}
<h1>Writing an OS in Rust</h1> {{ section.content
<p>{{ config.extra.subtitle | replace(from=" ", to="&nbsp;") | safe }} <em class="gray">— Third Edition (Alpha Release)</em></p> | replace(from="<!-- latest-post -->", to=macros::latest_post(posts=posts))
| replace(from="<!-- alpha-warning -->", to=macros::alpha_warning())
<div class="front-page-introduction"> | safe
<p> }}
This blog series creates a small operating system in the
<a href="https://www.rust-lang.org/">Rust programming language</a>. Each post is a small tutorial and includes all
needed code, so you can follow along if you like. The source code is also available in the corresponding
<a href="https://github.com/phil-opp/blog_os">Github repository</a>.
</p>
<p>Latest post:
{% set latest_post = posts|last %}
<strong><a href="{{ latest_post.path | safe }}">{{ latest_post.title }}</a></strong>
</p>
</div>
<!--
<p>In the following posts, we explain how to create an operating system for the <code>x86_64</code> architecture step for step. Starting from scratch, we create a bootable OS kernel, implement basic input/output support, show how to test and debug our kernel, explain virtual memory management, and add support for multitasking and userspace programs.</p>
-->
{%- set chapter = "none" -%} {%- set chapter = "none" -%}
{%- for post in posts -%} {%- for post in posts -%}
{%- if post.extra["chapter"] != chapter -%} {%- if post.extra["chapter"] != chapter -%}
{%- if chapter != "none" -%} {%- if not loop.first -%}
</ul></div> </ul></div>
{%- endif -%} {%- endif -%}
@@ -52,8 +38,11 @@
{%- endif -%} {%- endif -%}
<li>{{ macros::post_link(page=post) }}</li> <li>{{ macros::post_link(page=post) }}</li>
{% if loop.last %}
</ul></div>
{% endif %}
{%- endfor -%} {%- endfor -%}
</ul></div>
<hr> <hr>
@@ -83,10 +72,10 @@
<p>You are currently viewing the third edition of “Writing an OS in Rust”. In case you are interested in the older editions, you can still find them here:</p> <p>You are currently viewing the third edition of “Writing an OS in Rust”. In case you are interested in the older editions, you can still find them here:</p>
<ul> <ul>
<li> <li>
<strong><a href="{{ get_url(path="@/edition-2/_index.md")}}">Second Edition:</a></strong> The second edition is based on older version of the <code>bootloader</code> crate, which uses the hardware-provided VGA text buffer instead of a pixel-based framebuffer for screen output. Instead of the APIC, the legacy PIC is used for implementing hardware interrupts. The second edition only works on BIOS-based systems, not on the newer UEFI standard. <a class="read-more" href="{{ get_url(path = "edition-2") | safe }}"><em>read&nbsp;the&nbsp;second edition&nbsp;»</em></a></p> <p><strong><a href="{{ get_url(path="@/edition-2/_index.md")}}">Second Edition:</a></strong> The second edition is based on older version of the <code>bootloader</code> crate, which uses the hardware-provided VGA text buffer instead of a pixel-based framebuffer for screen output. Instead of the APIC, the legacy PIC is used for implementing hardware interrupts. The second edition only works on BIOS-based systems, not on the newer UEFI standard. <a class="read-more" href="{{ get_url(path = "edition-2") | safe }}"><em>read&nbsp;the&nbsp;second edition&nbsp;»</em></a></p>
</li> </li>
<li> <li>
<strong><a href="{{ get_url(path="@/edition-1/_index.md")}}">First Edition:</a></strong> The first edition was already started in 2015. It is very different in many aspects, for example it builds upon the GRUB bootloader instead of using the `bootloader` crate. This means that it requires you to manually write some assembly code and do an elaborate remap of the kernel's virtual pages in order to improve safety.<a class="read-more" href="{{ get_url(path = "edition-1") | safe }}"><em>read&nbsp;the&nbsp;first edition&nbsp;»</em></a></p> <p><strong><a href="{{ get_url(path="@/edition-1/_index.md")}}">First Edition:</a></strong> The first edition was already started in 2015. It is very different in many aspects, for example it builds upon the GRUB bootloader instead of using the `bootloader` crate. This means that it requires you to manually write some assembly code and do an elaborate remap of the kernel's virtual pages in order to improve safety.<a class="read-more" href="{{ get_url(path = "edition-1") | safe }}"><em>read&nbsp;the&nbsp;first edition&nbsp;»</em></a></p>
</li> </li>
</ul> </ul>
<p><em>Note that the older editions are no longer updated and might no longer work or contain outdated information.</em></p> <p><em>Note that the older editions are no longer updated and might no longer work or contain outdated information.</em></p>
@@ -100,22 +89,20 @@
{% block after_main %} {% block after_main %}
<aside class="page-aside-right"> <aside class="page-aside-right">
{% if section.translations | length > 1 %}
<div class="block" id="language-selector"> <div class="block" id="language-selector">
{% if section.translations -%} <h2>Other Languages</h2>
<div class="block" id="language-selector"> {% set translations = section.translations | group_by(attribute="lang") %}
<h2>Other Languages</h2> <ul>{%- for lang_code in config.extra.languages -%}
<ul>{%- for translation in section.translations | sort(attribute="lang") %} {%- if translations[lang_code] and lang_code != lang -%}
{%- set translation = translations[lang_code].0 -%}
<li data-lang-switch-to="{{ translation.lang }}" class=""><a href="{{ translation.permalink | safe }}"> <li data-lang-switch-to="{{ translation.lang }}" class=""><a href="{{ translation.permalink | safe }}">
{%- if translation.lang == "en" -%} {{ trans(key="lang_name", lang = translation.lang) }}
English (original)
{%- else -%}
{{ trans(key="lang_name", lang = translation.lang) }}
{%- endif -%}
</a></li> </a></li>
{% endfor %}</ul> {%- endif -%}
</div> {% endfor %}</ul>
{%- endif %}
</div> </div>
{% endif %}
<div class="block"> <div class="block">
<h2>Recent Updates</h2> <h2>Recent Updates</h2>
{% include "auto/recent-updates.html" %} {% include "auto/recent-updates.html" %}

View File

@@ -1,71 +1,89 @@
{% macro latest_post(posts) %} {% macro latest_post(posts) %}
{% set post = posts|last %} {% set post = posts|last %}
<strong><a href="{{ post.path | safe }}">{{ post.title }}</a></strong> {% if post %}
<strong><a href="{{ post.path | safe }}">{{ post.title }}</a></strong>
{% else %}
<em>none yet, stay tuned!</em>
{% endif %}
{% endmacro latest_post %} {% endmacro latest_post %}
{% macro post_link(page) %} {% macro post_link(page) %}
<div> <div>
{% set translations = page.translations | filter(attribute="lang", value=lang) -%} {% set translations = page.translations | filter(attribute="lang", value=lang) -%}
{%- if translations -%} {%- if translations -%}
{%- set post = get_page(path = translations.0.path) -%} {%- set post = get_page(path = translations.0.path) -%}
{%- else -%} {%- else -%}
{%- set post = page -%} {%- set post = page -%}
{%- set not_translated = true -%} {%- set not_translated = true -%}
{%- endif -%}
<h3 class="post-list-title"><a href="{{ post.path | safe }}">{{ post.title }}</a></h3>
<span class="post-list-icon">
{%- if post.extra.icon -%}{{post.extra.icon | safe}}{%- endif -%}
</span>
<div class="post-summary">
{{ post.summary | safe }}
<a class="read-more" href="{{ post.path | safe }}"><em>read&nbsp;more&nbsp;»</em></a>
{% if page.extra.extra_content %}
<aside class="post-extra-content">
<h4>Extra Content:</h4>
{% for name in page.extra.extra_content %}
{% set path = page.relative_path | split(pat="/") | slice(end=-1) | concat(with=name) | join(sep="/") %}
{% set extra_page = get_page(path = path) %}
<span class="post-list-extra-post-icon">
{%- if extra_page.extra.icon -%}{{extra_page.extra.icon | safe}}{%- endif -%}
</span>
<a href="{{ extra_page.path | safe }}">{{ extra_page.title }}</a>{% if not loop.last %},{% endif %}
{% endfor %}
</aside>
{% endif %}
{%- if lang and not_translated and lang != config.default_language -%}
<aside class="no-translation">
(This post is not translated yet.)
</aside>
{%- endif -%} {%- endif -%}
<h3 class="post-list-title"><a href="{{ post.path | safe }}">{{ post.title }}</a></h3>
<span class="post-list-icon">
{%- if post.extra.icon -%}{{post.extra.icon | safe}}{%- endif -%}
</span>
<div class="post-summary">
{{ post.summary | safe }}
<a class="read-more" href="{{ post.path | safe }}"><em>read&nbsp;more&nbsp;»</em></a>
{% if page.extra.extra_content %}
<aside class="post-extra-content">
<h4>Extra Content:</h4>
{% for name in page.extra.extra_content %}
{% set path = page.relative_path | split(pat="/") | slice(end=-1) | concat(with=name) | join(sep="/") %}
{% set extra_page = get_page(path = path) %}
<a href = "{{ extra_page.path | safe }}">{{ extra_page.title }}</a>{% if not loop.last %},{% endif %}
{% endfor %}
</aside>
{% endif %}
{%- if lang and not_translated and lang != config.default_language -%}
<aside class="no-translation">
(This post is not translated yet.)
</aside>
{%- endif -%}
</div>
</div> </div>
</div>
{% endmacro post_link %} {% endmacro post_link %}
{% macro toc(toc) %} {% macro toc(toc) %}
<details id = "toc-inline"> <details id="toc-inline">
<summary><b>Table of Contents</b></summary> <summary><b>Table of Contents</b></summary>
<ul> <ul>
{% for h2 in toc %}<li> {% for h2 in toc %}<li>
<a href="#{{h2.id | safe}}">{{ h2.title | safe }}</a> <a href="#{{h2.id | safe}}">{{ h2.title | safe }}</a>
{% if h2.children %}<ul> {% if h2.children %}<ul>
{% for h3 in h2.children %}<li> {% for h3 in h2.children %}<li>
<a href="#{{h3.id | safe}}">{{ h3.title | safe }}</a> <a href="#{{h3.id | safe}}">{{ h3.title | safe }}</a>
</li>{% endfor %} </li>{% endfor %}
</ul>{% endif %} </ul>{% endif %}
</li>{% endfor %} </li>{% endfor %}
<li class="toc-comments-link"><a href="#comments">Comments</a></li> <li class="toc-comments-link"><a href="#comments">Comments</a></li>
</ul> </ul>
</details> </details>
<div class="theme-switch-inline">
Switch between light and dark mode:
<span class="switches">
<span class="light-switch" onclick="toggle_lights()" title="Switch between light and dark theme"></span>
<span class="light-switch-reset" onclick="clear_theme_override()"
title="Clear the theme override and go back to the system theme"></span>
</span>
</div>
{% endmacro toc %} {% endmacro toc %}
{% macro utterances() %} {% macro alpha_warning() %}
<script src="https://utteranc.es/client.js" <div class="warning">
data-repo="phil-opp/blog_os" <p>
data-issue-term="url" This is an <strong>early preview</strong> of the upcoming <em>third edition</em> of this guide. The edition is
data-label="comments" still in alpha state, so things might be still in progress, not work, or change without warning!
crossorigin="anonymous" </p>
theme="preferred-color-scheme" <p>
async> For a more stable experience, check out the current <a href="{{ get_url(path = " @/edition-2/_index.md") | safe
</script> }}"><strong>Second Edition</strong></a>.
{% endmacro utterances %} </p>
</div>
{% endmacro alpha_warning %}

View File

@@ -6,9 +6,9 @@
{% block title %}{{ page.title }} | {{ config.title }}{% endblock title %} {% block title %}{{ page.title }} | {{ config.title }}{% endblock title %}
{% block header %} {% block header %}
{% if lang != "en" -%} {% if lang != "en" -%}
<aside id="all-posts-link"><a href="{{ get_url(path="@/edition-3/_index.md") }}/{{ lang }}" title="All Posts">« All Posts</a></aside> <aside id="all-posts-link"><a href="{{ get_url(path="@/edition-3/_index.md") }}/{{ lang }}" title="All Posts">{{ trans(key="all_posts", lang=lang) }}</a></aside>
{%- else -%} {%- else -%}
<aside id="all-posts-link"><a href="{{ get_url(path="@/edition-3/_index.md") }}" title="All Posts">« All Posts</a></aside> <aside id="all-posts-link"><a href="{{ get_url(path="@/edition-3/_index.md") }}" title="All Posts">{{ trans(key="all_posts", lang=lang) }}</a></aside>
{%- endif %} {%- endif %}
{% endblock header %} {% endblock header %}
@@ -17,8 +17,8 @@
{%- endblock description %} {%- endblock description %}
{% block toc_aside %} {% block toc_aside %}
<aside id="toc-aside"> <aside id="toc-aside" class="{% if page.extra.rtl %}right-to-left{% endif %}">
<h2>Table of Contents</h2> <h2>{{ trans(key="toc", lang=lang) }}</h2>
<ol> <ol>
{% for h2 in page.toc %}<li> {% for h2 in page.toc %}<li>
<a href="#{{h2.id | safe}}">{{ h2.title | safe }}</a> <a href="#{{h2.id | safe}}">{{ h2.title | safe }}</a>
@@ -28,7 +28,7 @@
</li>{% endfor %} </li>{% endfor %}
</ol>{% endif %} </ol>{% endif %}
</li>{% endfor %} </li>{% endfor %}
<li class="toc-comments-link"><a href="#comments">Comments</a></li> <li class="toc-comments-link"><a href="#comments">{{ trans(key="comments", lang=lang) }}</a></li>
</ol> </ol>
</aside> </aside>
{% endblock toc_aside %} {% endblock toc_aside %}
@@ -47,6 +47,8 @@
</time> </time>
</div> </div>
{{ macros::alpha_warning() }}
{% if page.extra.warning %} {% if page.extra.warning %}
<div class="warning"> <div class="warning">
{% if page.extra.warning_short %} <b>{{ page.extra.warning_short }}</b> {% endif %} {% if page.extra.warning_short %} <b>{{ page.extra.warning_short }}</b> {% endif %}
@@ -55,18 +57,20 @@
{% endif %} {% endif %}
{%- if page.lang != "en" %} {%- if page.lang != "en" %}
<div class="warning"> <div class="warning{% if page.extra.rtl %} right-to-left{% endif %}">
{% set translations = page.translations | filter(attribute="lang", value="en") %} {% set translations = page.translations | filter(attribute="lang", value="en") %}
{% set original = translations.0 %} {% set original = translations.0 %}
<p> <p>
<b>Translated Content:</b> <b>{{ trans(key="translated_content", lang=lang) }}</b>
This is a community translation of the <strong><a href="{{ original.permalink }}">{{ original.title }}</a></strong> post. It might be incomplete, outdated or contain errors. Please report any issues! {{ trans(key="translated_content_notice", lang=lang) |
replace(from="_original.permalink_", to=original.permalink) |
replace(from="_original.title_", to=original.title) | safe }}
</p> </p>
{%- if page.extra.translators %} {%- if page.extra.translators %}
<p> <p>
Translation by {% for user in page.extra.translators -%} {{ trans(key="translated_by", lang=lang) }} {% for user in page.extra.translators -%}
{%- if not loop.first -%} {%- if not loop.first -%}
{%- if loop.last %}, and {% else %}, {% endif -%} {%- if loop.last %} {{ trans(key="word_separator", lang=lang) }} {% else %}, {% endif -%}
{%- endif -%} {%- endif -%}
<a href="https://github.com/{{user}}">@{{user}}</a> <a href="https://github.com/{{user}}">@{{user}}</a>
{%- endfor %}. {%- endfor %}.
@@ -75,11 +79,11 @@
</div> </div>
{% endif %} {% endif %}
<div class="{% if page.extra.rtl %}right-to-left{% endif %}"> <div class="{% if page.extra.rtl %}right-to-left{% endif %}">
{{ page.content | replace(from="<!-- toc -->", to=macros::toc(toc=page.toc)) | safe }} {{ page.content | replace(from="<!-- toc -->", to=macros::toc(toc=page.toc)) | safe }}
</div> </div>
<div class="post-footer-support"> <div class="post-footer-support{% if page.extra.rtl %} right-to-left{% endif %}">
<h2>Support Me</h2> <h2>Support Me</h2>
{{ snippets::support() }} {{ snippets::support() }}
</div> </div>
@@ -98,41 +102,41 @@
<hr> <hr>
<section> <section>
<h2 id="comments">Comments</h2> <h2 id="comments" class="{% if page.extra.rtl %}right-to-left{% endif %}">{{ trans(key="comments", lang=lang) }}</h2>
{% if page.extra.comments_search_term %}
{% set search_term=page.extra.comments_search_term %}
{% elif page.lang != "en" %}
{% set translations = page.translations | filter(attribute="lang", value="en") %}
{% set original = translations.0 %}
{% set search_term=original.title ~ " (" ~ page.lang ~ ")" %}
{% else %}
{% set search_term=page.title %}
{% endif %}
{{ snippets::giscus(search_term=search_term) }}
{%- if page.lang != "en" %} {%- if page.lang != "en" %}
<p> <p class="{% if page.extra.rtl %}right-to-left{% endif %}">
Please leave your comments in English if possible. {{ trans(key="comments_notice", lang=lang) }}
</p> </p>
{% endif %} {% endif %}
{{ macros::utterances() }}
</section> </section>
<aside class="page-aside-right"> <aside class="page-aside-right">
{% if page.translations -%} {% if page.translations | length > 1-%}
<div class="block" id="language-selector"> <div class="block" id="language-selector">
<h2>Other Languages</h2> <h2>Other Languages</h2>
<ul>{%- for translation in page.translations | sort(attribute="lang") %} {% set translations = page.translations | group_by(attribute="lang") %}
<li data-lang-switch-to="{{ translation.lang }}" class=""><a href="{{ translation.permalink | safe }}"> <ul>{%- for lang_code in config.extra.languages -%}{%- if translations[lang_code] -%}
{%- if translation.lang == "en" -%} {%- set translation = translations[lang_code] | first -%}
English (original) {%- if translation and lang_code != lang -%}
{%- else -%} <li data-lang-switch-to="{{ translation.lang }}" class=""><a href="{{ translation.permalink | safe }}">
{{ trans(key="lang_name", lang = translation.lang) }} {{ trans(key="lang_name", lang = translation.lang) }}
{%- endif -%} </a></li>
</a></li> {%- endif -%}
{% endfor %}</ul> {%- endif -%}{% endfor %}</ul>
</div> </div>
{%- endif %} {%- endif %}
<div class="block">
<h2>About Me</h2>
<p>
I'm a Rust freelancer with a master's degree in computer science. I love systems programming, open source software, and new challenges.
</p><p>
If you want to work with me, reach out on <a href = "https://www.linkedin.com/in/phil-opp/">LinkedIn</a> or write me at <a href="mailto:job@phil-opp.com">job@phil-opp.com</a>.
</p>
</div>
</aside> </aside>
{% endblock main %} {% endblock main %}