diff --git a/src/main.zig b/src/main.zig index 3d8514f..96dc05d 100644 --- a/src/main.zig +++ b/src/main.zig @@ -142,7 +142,7 @@ pub fn main() anyerror!void { var root_dir = try std.fs.cwd().makeOpenPath("render", .{}); defer root_dir.close(); - try website.renderIndexFile("website/index.md", root_dir, "index.htm"); + try website.renderMarkdownFile("website/index.md", root_dir, "index.htm"); try website.renderArticleIndex(root_dir, "articles.htm"); @@ -271,7 +271,10 @@ const Website = struct { var list = std.ArrayList(u8).init(&self.arena.allocator); defer list.deinit(); - try koino.html.print(list.writer(), &self.arena.allocator, markdown_options, heading); + var options = markdown_options; + options.render.header_anchors = false; + + try koino.html.print(list.writer(), &self.arena.allocator, options, heading); const string = list.toOwnedSlice(); @@ -373,58 +376,15 @@ const Website = struct { } } - /// Renders the root file and replaces `` with the first 10 articles, - /// in descending order - fn renderIndexFile(self: *Self, src_path: []const u8, dst_dir: std.fs.Dir, file_name: []const u8) !void { - std.debug.assert(self.is_prepared); - - var src_code = try std.fs.cwd().readFileAlloc(self.allocator, src_path, 10_000_000); - defer self.allocator.free(src_code); - - var array_buffer = std.ArrayList(u8).init(self.allocator); - defer array_buffer.deinit(); - - const offset = std.mem.indexOf(u8, src_code, "") orelse return error.MissingArticlesMarker; - - var writer = array_buffer.writer(); - - try writer.writeAll(src_code[0..offset]); - - for (self.articles.items[0..std.math.min(self.articles.items.len, 10)]) |art| { - try writer.print("- [{} - {s}](articles/{s}.htm)\n", .{ - art.date, - art.title, - try self.urlEscape(removeExtension(std.fs.path.basename(art.src_file))), - }); - } - - try writer.writeAll(src_code[offset + 17 ..]); - - try self.renderMarkdown(array_buffer.items, dst_dir, file_name); - } - - /// Renders the root file and replaces `` with the first 10 articles, - /// in descending order + /// Renders a list of all possible articles fn renderArticleIndex(self: *Self, dst_dir: std.fs.Dir, file_name: []const u8) !void { std.debug.assert(self.is_prepared); - var array_buffer = std.ArrayList(u8).init(self.allocator); - defer array_buffer.deinit(); - - var writer = array_buffer.writer(); - - try writer.writeAll("# Articles\n"); - try writer.writeAll("\n"); - - for (self.articles.items[0..std.math.min(self.articles.items.len, 10)]) |art| { - try writer.print("- [{} - {s}](articles/{s}.htm)\n", .{ - art.date, - art.title, - try self.urlEscape(removeExtension(std.fs.path.basename(art.src_file))), - }); - } - - try self.renderMarkdown(array_buffer.items, dst_dir, file_name); + try self.renderMarkdown( + \\# Articles + \\ + \\ + , dst_dir, file_name); } /// Render a given markdown file into `dst_path`. @@ -438,24 +398,136 @@ const Website = struct { } /// Render the given markdown source into `dst_path`. + /// supported features here are: + /// - `` (renders a table of contents with all items that come *after* said TOC + /// - `` Renders the 10 latest articles + /// - `` Renders all articles fn renderMarkdown(self: *Self, source: []const u8, dst_dir: std.fs.Dir, dst_path: []const u8) !void { std.debug.assert(self.is_prepared); - var p = try koino.parser.Parser.init(&self.arena.allocator, markdown_options); - try p.feed(source); - - var doc = try p.finish(); - p.deinit(); - + var doc: *koino.nodes.AstNode = blk: { + var p = try koino.parser.Parser.init(&self.arena.allocator, markdown_options); + try p.feed(source); + defer p.deinit(); + break :blk try p.finish(); + }; defer doc.deinit(); + std.debug.assert(doc.data.value == .Document); + var output_file = try dst_dir.createFile(dst_path, .{}); defer output_file.close(); var writer = output_file.writer(); try self.renderHeader(writer); - try koino.html.print(writer, &self.arena.allocator, p.options, doc); + { + var iter = doc.first_child; + while (iter) |item| : (iter = item.next) { + if (item.data.value == .HtmlBlock) { + const raw_string = item.data.value.HtmlBlock.literal.items; + + const string = std.mem.trim(u8, raw_string, " \t\r\n"); + + if (std.mem.eql(u8, string, "")) { + var min_heading_level: ?u8 = null; + var current_heading_level: u8 = undefined; + + var heading_options = markdown_options; + heading_options.render.header_anchors = false; + + try writer.writeAll(""); + current_heading_level -= 1; + } + while (current_heading_level < heading.level) { + try writer.writeAll(""); + current_heading_level -= 1; + } + + try writer.writeAll(""); + } + } + + if (min_heading_level) |mhl| { + while (current_heading_level > mhl) { + try writer.writeAll(""); + current_heading_level -= 1; + } + } + + try writer.writeAll(""); + } else if (std.mem.eql(u8, string, "")) { + for (self.articles.items[0..std.math.min(self.articles.items.len, 10)]) |art| { + try writer.print( + \\
  • {} - {s}
  • + \\ + , .{ + try self.urlEscape(removeExtension(std.fs.path.basename(art.src_file))), + art.date, + art.title, + }); + } + } else if (std.mem.eql(u8, string, "")) { + try writer.writeAll("\n"); + } else { + std.log.err("Unhandled HTML inline: {s}", .{string}); + } + } else { + try koino.html.print( + writer, + &self.arena.allocator, + markdown_options, + item, + ); + } + } + } try self.renderFooter(writer); } diff --git a/website/tutorials/01-embedded-basics.md b/website/tutorials/01-embedded-basics.md index fe4229f..0bfda5c 100644 --- a/website/tutorials/01-embedded-basics.md +++ b/website/tutorials/01-embedded-basics.md @@ -10,20 +10,7 @@ None! This is your entry point into the embedded world! ## Contents -- [What are embedded systems?](#what-are-embedded-systems) -- Electronics 101 - - Current, voltage, power and all - - Diodes, Resistors, Capacitors - - Ohm's law - - LEDs and pre-resistors - - MosFETs -- Breadboard vs. Soldering -- Digital I/O -- Analog I/O -- Bus Systems - - UART - - SPI - - I²C / TWI + ## What are embedded systems? @@ -45,4 +32,28 @@ An important characteristic that's often required for an embedded system is "rea This is simply the ability for the system to respond to an input within a hard deadline, Eg. automatic breaks for a car. A general operating system like Linux is not suitable for these applications because it uses time sharing when scheduling tasks/programs, and unreliably responds to important signals. +## Electronics 101 +### Current, voltage, power and all + +### Diodes, Resistors, Capacitors + +### Ohm's law + +### LEDs and pre-resistors + +### MosFETs + +## Breadboard vs. Soldering + +## Digital I/O + +## Analog I/O + +## Bus Systems + +### UART + +### SPI + +### I²C / TWI \ No newline at end of file diff --git a/website/tutorials/02-embedded-programming.md b/website/tutorials/02-embedded-programming.md index 5362598..0c9fbde 100644 --- a/website/tutorials/02-embedded-programming.md +++ b/website/tutorials/02-embedded-programming.md @@ -4,20 +4,11 @@ In this tutorial, you'll learn the ways of the embedded programmer and how to ma ## Prerequisites - - - [Embedded Basics](01-embedded-basics.htm) ## Contents -- Differences to desktop programming -- Inventory of an embedded programmer -- The startup procedure -- Interacting with peripherials -- Interrupts and how to get them -- `.text`, `.data` and other curious sections -- Binary formats you might use -- Deploying your application + ## Differences to desktop programming