commit - 41ac9085dc74afb7030d4f0a9c786d14137f8843
commit + 044348ebfee5cdeab03452924bb5db2024d9f9ed
blob - 879b53732d4c4885c1418820b484d8c1e3864f05
blob + 8dc66ae98fe34a3fdf6c8c299e198bf4e3637933
--- content/posts/primeiro-post.md
+++ content/posts/primeiro-post.md
title: Primeiro Post
date: 2026-04-03
draft: false
-----
+---
# Meu primeiro post
blob - /dev/null
blob + b5d009f9cb11e4d0e9c74c4edf7e6535e8546ddf (mode 644)
--- /dev/null
+++ content/posts/os-part1.md
+---
+title: Construindo um OS em Rust - Parte 1
+date: 2026-04-01
+series: os-em-rust
+part: 1
+---
+
+# O Boot
+
+O que acontece quando vocĂȘ liga o computador...
blob - /dev/null
blob + 1a9bbef4b535816f532fe21028d2db8fac059b7e (mode 644)
--- /dev/null
+++ content/posts/os-part2.md
+---
+title: Construindo um OS em Rust - Parte 2
+date: 2026-04-02
+series: os-em-rust
+part: 2
+---
+
+# Modo Protegido
+
+Escapando do modo real...
blob - /dev/null
blob + b8dfd1ffaef4e27e6c910f63979c5e7a6464229d (mode 644)
--- /dev/null
+++ content/posts/os-part3.md
+---
+title: Construindo um OS em Rust - Parte 3
+date: 2026-04-03
+series: os-em-rust
+part: 3
+---
+
+# Longo Mode
+
+Ativando 64-bit
+
blob - 3acb5bcf3d5c13ffd92c2ac67979cf7b27660d31
blob + 88121dca19f0a12c13878a5c58adbb184c833616
--- src/main.rs
+++ src/main.rs
// Build
//////////////////////////////////////////////////////////////////////////////
+struct Post {
+ meta: Metadata,
+ html_content: String,
+ out_path: PathBuf,
+}
+
fn build() {
log!("starting build");
+
let template = fs::read_to_string("templates/base.html")
.expect("read templates/base.html");
let mut files = Vec::new();
walk(content_dir, &mut files);
+ let mut posts: Vec<Post> = Vec::new();
+
for file in &files {
if file.extension().and_then(|e| e.to_str()) != Some("md") {
continue;
let meta = parse_frontmatter(&md);
if meta.draft {
+ log!("skip draft: {}", file.display());
continue;
}
let relative = file.strip_prefix(content_dir).expect("strip prefix");
let out_path = Path::new("public").join(relative).with_extension("html");
- if let Some(parent) = out_path.parent() {
- fs::create_dir_all(parent).expect("create dir");
+ posts.push(Post { meta, html_content, out_path });
+
+ }
+
+ for i in 0..posts.len() {
+ let nav = series_nav(&posts, i);
+
+ let mut content = posts[i].html_content.clone();
+ if !nav.is_empty() {
+ content.push_str(&nav);
}
let output = template
- .replace("{{title}}", &meta.title)
- .replace("{{content}}", &html_content);
+ .replace("{{title}}", &posts[i].meta.title)
+ .replace("{{content}}", &content);
- fs::write(&out_path, output).expect("write html");
- println!("build ok: {}", out_path.display());
+ if let Some(parent) = posts[i].out_path.parent() {
+ fs::create_dir_all(parent).expect("create dir");
+ }
+
+ fs::write(&posts[i].out_path, output).expect("write html");
+ log!("wrote {}", posts[i].out_path.display());
}
let static_dir = Path::new("static");
if static_dir.exists() {
copy_dir(static_dir, &Path::new("public/static"));
}
+
+ println!("build ok");
}
+
+fn series_nav(posts: &[Post], current: usize) -> String {
+ let series = match &posts[current].meta.series {
+ Some(s) => s,
+ None => return String::new(),
+ };
+
+ let cur_part = posts[current].meta.part.unwrap_or(0);
+
+ let mut prev: Option<&Post> = None;
+ let mut next: Option<&Post> = None;
+
+ for post in posts {
+ if post.meta.series.as_deref() != Some(series) {
+ continue;
+ }
+
+ let p = post.meta.part.unwrap_or(0);
+ if p + 1 == cur_part {
+ prev = Some(post);
+ }
+ if p == cur_part + 1 {
+ next = Some(post);
+ }
+ }
+
+ if prev.is_none() && next.is_none() {
+ return String::new();
+ }
+
+ let mut nav = String::from("<nav class=\"series-nav\">");
+
+ if let Some(p) = prev {
+ let href = format!("/{}", p.out_path.display());
+ nav.push_str(
+ &format!("<a href=\"{}\">\u{2190} {}</a>", href, p.meta.title)
+ );
+ }
+
+ if let Some(p) = next {
+ let href = format!("/{}", p.out_path.display());
+ nav.push_str(
+ &format!("<a href=\"{}\">{} \u{2192}</a>", href, p.meta.title)
+ );
+ }
+
+ nav.push_str("</nav>");
+ nav
+}