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

View File

@@ -6,6 +6,7 @@
<meta charset="UTF-8">
<meta name="apple-mobile-web-app-capable" content="yes">
<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="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" />
<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>
<title>{% block title %}{% endblock title %} (Third Edition - Alpha)</title>
@@ -34,30 +42,19 @@
<footer class="footer">
<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>
&copy; <time datetime="2020">2020</time>. All rights reserved.
<a href="{{ get_url(path="@/pages/contact.md") | safe }}">Contact</a>
&copy; <time datetime="2022">2022</time>. All rights reserved.
<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>
</footer>
</div>
<div class="light-switch" onclick="toggle_lights()"></div>
<!-- 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 -->
<script data-goatcounter="https://phil-opp.goatcounter.com/count" async src="//gc.zgo.at/count.js"></script>
</body>
</html>

View File

@@ -6,34 +6,20 @@
{% block title %}{{ config.title }}{% endblock title %}
{% block main %}
{% set posts_section = get_section(path = "edition-3/posts/_index.md") %}
{% set posts = posts_section.pages %}
<h1>Writing an OS in Rust</h1>
<p>{{ config.extra.subtitle | replace(from=" ", to="&nbsp;") | safe }} <em class="gray">— Third Edition (Alpha Release)</em></p>
<div class="front-page-introduction">
<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>
-->
{{ section.content
| replace(from="<!-- latest-post -->", to=macros::latest_post(posts=posts))
| replace(from="<!-- alpha-warning -->", to=macros::alpha_warning())
| safe
}}
{%- set chapter = "none" -%}
{%- for post in posts -%}
{%- if post.extra["chapter"] != chapter -%}
{%- if chapter != "none" -%}
{%- if not loop.first -%}
</ul></div>
{%- endif -%}
@@ -52,8 +38,11 @@
{%- endif -%}
<li>{{ macros::post_link(page=post) }}</li>
{% if loop.last %}
</ul></div>
{% endif %}
{%- endfor -%}
</ul></div>
<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>
<ul>
<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>
<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>
</ul>
<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 %}
<aside class="page-aside-right">
<div class="block" id="language-selector">
{% if section.translations -%}
{% if section.translations | length > 1 %}
<div class="block" id="language-selector">
<h2>Other Languages</h2>
<ul>{%- for translation in section.translations | sort(attribute="lang") %}
{% set translations = section.translations | group_by(attribute="lang") %}
<ul>{%- for lang_code in config.extra.languages -%}
{%- 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 }}">
{%- if translation.lang == "en" -%}
English (original)
{%- else -%}
{{ trans(key="lang_name", lang = translation.lang) }}
{%- endif -%}
</a></li>
{%- endif -%}
{% endfor %}</ul>
</div>
{%- endif %}
</div>
{% endif %}
<div class="block">
<h2>Recent Updates</h2>
{% include "auto/recent-updates.html" %}

View File

@@ -1,10 +1,14 @@
{% macro latest_post(posts) %}
{% set post = posts|last %}
<strong><a href="{{ post.path | safe }}">{{ post.title }}</a></strong>
{% set post = posts|last %}
{% if post %}
<strong><a href="{{ post.path | safe }}">{{ post.title }}</a></strong>
{% else %}
<em>none yet, stay tuned!</em>
{% endif %}
{% endmacro latest_post %}
{% macro post_link(page) %}
<div>
<div>
{% set translations = page.translations | filter(attribute="lang", value=lang) -%}
{%- if translations -%}
{%- set post = get_page(path = translations.0.path) -%}
@@ -28,7 +32,10 @@
{% set extra_page = get_page(path = path) %}
<a href = "{{ extra_page.path | safe }}">{{ extra_page.title }}</a>{% if not loop.last %},{% endif %}
<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 %}
@@ -39,11 +46,11 @@
</aside>
{%- endif -%}
</div>
</div>
</div>
{% endmacro post_link %}
{% macro toc(toc) %}
<details id = "toc-inline">
<details id="toc-inline">
<summary><b>Table of Contents</b></summary>
<ul>
{% for h2 in toc %}<li>
@@ -56,16 +63,27 @@
</li>{% endfor %}
<li class="toc-comments-link"><a href="#comments">Comments</a></li>
</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 %}
{% macro utterances() %}
<script src="https://utteranc.es/client.js"
data-repo="phil-opp/blog_os"
data-issue-term="url"
data-label="comments"
crossorigin="anonymous"
theme="preferred-color-scheme"
async>
</script>
{% endmacro utterances %}
{% macro alpha_warning() %}
<div class="warning">
<p>
This is an <strong>early preview</strong> of the upcoming <em>third edition</em> of this guide. The edition is
still in alpha state, so things might be still in progress, not work, or change without warning!
</p>
<p>
For a more stable experience, check out the current <a href="{{ get_url(path = " @/edition-2/_index.md") | safe
}}"><strong>Second Edition</strong></a>.
</p>
</div>
{% endmacro alpha_warning %}

View File

@@ -6,9 +6,9 @@
{% block title %}{{ page.title }} | {{ config.title }}{% endblock title %}
{% block header %}
{% 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 -%}
<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 %}
{% endblock header %}
@@ -17,8 +17,8 @@
{%- endblock description %}
{% block toc_aside %}
<aside id="toc-aside">
<h2>Table of Contents</h2>
<aside id="toc-aside" class="{% if page.extra.rtl %}right-to-left{% endif %}">
<h2>{{ trans(key="toc", lang=lang) }}</h2>
<ol>
{% for h2 in page.toc %}<li>
<a href="#{{h2.id | safe}}">{{ h2.title | safe }}</a>
@@ -28,7 +28,7 @@
</li>{% endfor %}
</ol>{% endif %}
</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>
</aside>
{% endblock toc_aside %}
@@ -47,6 +47,8 @@
</time>
</div>
{{ macros::alpha_warning() }}
{% if page.extra.warning %}
<div class="warning">
{% if page.extra.warning_short %} <b>{{ page.extra.warning_short }}</b> {% endif %}
@@ -55,18 +57,20 @@
{% endif %}
{%- 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 original = translations.0 %}
<p>
<b>Translated Content:</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!
<b>{{ trans(key="translated_content", lang=lang) }}</b>
{{ trans(key="translated_content_notice", lang=lang) |
replace(from="_original.permalink_", to=original.permalink) |
replace(from="_original.title_", to=original.title) | safe }}
</p>
{%- if page.extra.translators %}
<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 loop.last %}, and {% else %}, {% endif -%}
{%- if loop.last %} {{ trans(key="word_separator", lang=lang) }} {% else %}, {% endif -%}
{%- endif -%}
<a href="https://github.com/{{user}}">@{{user}}</a>
{%- endfor %}.
@@ -79,7 +83,7 @@
{{ page.content | replace(from="<!-- toc -->", to=macros::toc(toc=page.toc)) | safe }}
</div>
<div class="post-footer-support">
<div class="post-footer-support{% if page.extra.rtl %} right-to-left{% endif %}">
<h2>Support Me</h2>
{{ snippets::support() }}
</div>
@@ -98,41 +102,41 @@
<hr>
<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" %}
<p>
Please leave your comments in English if possible.
<p class="{% if page.extra.rtl %}right-to-left{% endif %}">
{{ trans(key="comments_notice", lang=lang) }}
</p>
{% endif %}
{{ macros::utterances() }}
</section>
<aside class="page-aside-right">
{% if page.translations -%}
{% if page.translations | length > 1-%}
<div class="block" id="language-selector">
<h2>Other Languages</h2>
<ul>{%- for translation in page.translations | sort(attribute="lang") %}
{% set translations = page.translations | group_by(attribute="lang") %}
<ul>{%- for lang_code in config.extra.languages -%}{%- if translations[lang_code] -%}
{%- set translation = translations[lang_code] | first -%}
{%- if translation and lang_code != lang -%}
<li data-lang-switch-to="{{ translation.lang }}" class=""><a href="{{ translation.permalink | safe }}">
{%- if translation.lang == "en" -%}
English (original)
{%- else -%}
{{ trans(key="lang_name", lang = translation.lang) }}
{%- endif -%}
</a></li>
{% endfor %}</ul>
{%- endif -%}
{%- endif -%}{% endfor %}</ul>
</div>
{%- 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>
{% endblock main %}