| ... | ... | @@ -28,7 +28,7 @@ decls: std.ArrayListUnmanaged(DocData.Decl) = .{}, |
| 28 | 28 | exprs: std.ArrayListUnmanaged(DocData.Expr) = .{}, |
| 29 | 29 | ast_nodes: std.ArrayListUnmanaged(DocData.AstNode) = .{}, |
| 30 | 30 | comptime_exprs: std.ArrayListUnmanaged(DocData.ComptimeExpr) = .{}, |
| 31 | | guides: std.StringHashMapUnmanaged([]const u8) = .{}, |
| 31 | guide_sections: std.ArrayListUnmanaged(Section) = .{}, |
| 32 | 32 | |
| 33 | 33 | // These fields hold temporary state of the analysis process |
| 34 | 34 | // and are mainly used by the decl path resolving algorithm. |
| ... | ... | @@ -63,6 +63,16 @@ const SrcLocInfo = struct { |
| 63 | 63 | src_node: u32 = 0, |
| 64 | 64 | }; |
| 65 | 65 | |
| 66 | const Section = struct { |
| 67 | name: []const u8 = "", // empty string is the default section |
| 68 | guides: std.ArrayListUnmanaged(Guide) = .{}, |
| 69 | |
| 70 | const Guide = struct { |
| 71 | name: []const u8, |
| 72 | body: []const u8, |
| 73 | }; |
| 74 | }; |
| 75 | |
| 66 | 76 | var arena_allocator: std.heap.ArenaAllocator = undefined; |
| 67 | 77 | pub fn init(m: *Module, doc_location: Compilation.EmitLoc) Autodoc { |
| 68 | 78 | arena_allocator = std.heap.ArenaAllocator.init(m.gpa); |
| ... | ... | @@ -253,7 +263,7 @@ pub fn generateZirData(self: *Autodoc) !void { |
| 253 | 263 | .exprs = self.exprs.items, |
| 254 | 264 | .astNodes = self.ast_nodes.items, |
| 255 | 265 | .comptimeExprs = self.comptime_exprs.items, |
| 256 | | .guides = self.guides, |
| 266 | .guide_sections = self.guide_sections, |
| 257 | 267 | }; |
| 258 | 268 | |
| 259 | 269 | const base_dir = self.doc_location.directory orelse |
| ... | ... | @@ -419,7 +429,7 @@ const DocData = struct { |
| 419 | 429 | exprs: []Expr, |
| 420 | 430 | comptimeExprs: []ComptimeExpr, |
| 421 | 431 | |
| 422 | | guides: std.StringHashMapUnmanaged([]const u8), |
| 432 | guide_sections: std.ArrayListUnmanaged(Section), |
| 423 | 433 | |
| 424 | 434 | const Call = struct { |
| 425 | 435 | func: Expr, |
| ... | ... | @@ -440,7 +450,7 @@ const DocData = struct { |
| 440 | 450 | try jsw.objectField(f_name); |
| 441 | 451 | switch (f) { |
| 442 | 452 | .files => try writeFileTableToJson(self.files, &jsw), |
| 443 | | .guides => try writeGuidesToJson(self.guides, &jsw), |
| 453 | .guide_sections => try writeGuidesToJson(self.guide_sections, &jsw), |
| 444 | 454 | else => { |
| 445 | 455 | try std.json.stringify(@field(self, f_name), opts, w); |
| 446 | 456 | jsw.state_index -= 1; |
| ... | ... | @@ -4613,14 +4623,39 @@ fn writeFileTableToJson(map: std.AutoArrayHashMapUnmanaged(*File, usize), jsw: a |
| 4613 | 4623 | try jsw.endArray(); |
| 4614 | 4624 | } |
| 4615 | 4625 | |
| 4616 | | fn writeGuidesToJson(map: std.StringHashMapUnmanaged([]const u8), jsw: anytype) !void { |
| 4617 | | try jsw.beginObject(); |
| 4618 | | var it = map.iterator(); |
| 4619 | | while (it.next()) |entry| { |
| 4620 | | try jsw.objectField(entry.key_ptr.*); |
| 4621 | | try jsw.emitString(entry.value_ptr.*); |
| 4626 | /// Writes the data like so: |
| 4627 | /// ``` |
| 4628 | /// { |
| 4629 | /// "<section name>": [{name: "<guide name>", text: "<guide contents>"},], |
| 4630 | /// } |
| 4631 | /// ``` |
| 4632 | fn writeGuidesToJson(sections: std.ArrayListUnmanaged(Section), jsw: anytype) !void { |
| 4633 | try jsw.beginArray(); |
| 4634 | |
| 4635 | for (sections.items) |s| { |
| 4636 | // section name |
| 4637 | try jsw.arrayElem(); |
| 4638 | try jsw.beginObject(); |
| 4639 | try jsw.objectField("name"); |
| 4640 | try jsw.emitString(s.name); |
| 4641 | try jsw.objectField("guides"); |
| 4642 | |
| 4643 | // section value |
| 4644 | try jsw.beginArray(); |
| 4645 | for (s.guides.items) |g| { |
| 4646 | try jsw.arrayElem(); |
| 4647 | try jsw.beginObject(); |
| 4648 | try jsw.objectField("name"); |
| 4649 | try jsw.emitString(g.name); |
| 4650 | try jsw.objectField("body"); |
| 4651 | try jsw.emitString(g.body); |
| 4652 | try jsw.endObject(); |
| 4653 | } |
| 4654 | try jsw.endArray(); |
| 4655 | try jsw.endObject(); |
| 4622 | 4656 | } |
| 4623 | | try jsw.endObject(); |
| 4657 | |
| 4658 | try jsw.endArray(); |
| 4624 | 4659 | } |
| 4625 | 4660 | |
| 4626 | 4661 | fn writePackageTableToJson( |
| ... | ... | @@ -4688,19 +4723,31 @@ fn getTLDocComment(self: *Autodoc, file: *File) ![]const u8 { |
| 4688 | 4723 | } |
| 4689 | 4724 | |
| 4690 | 4725 | fn findGuidePaths(self: *Autodoc, file: *File, str: []const u8) !void { |
| 4691 | | const prefix = "zig-autodoc-guide:"; |
| 4726 | const guide_prefix = "zig-autodoc-guide:"; |
| 4727 | const section_prefix = "zig-autodoc-section:"; |
| 4728 | |
| 4729 | try self.guide_sections.append(self.arena, .{}); // add a default section |
| 4730 | var current_section = &self.guide_sections.items[self.guide_sections.items.len - 1]; |
| 4731 | |
| 4692 | 4732 | var it = std.mem.tokenize(u8, str, "\n"); |
| 4693 | 4733 | while (it.next()) |line| { |
| 4694 | 4734 | const trimmed_line = std.mem.trim(u8, line, " "); |
| 4695 | | if (std.mem.startsWith(u8, trimmed_line, prefix)) { |
| 4696 | | const path = trimmed_line[prefix.len..]; |
| 4735 | if (std.mem.startsWith(u8, trimmed_line, guide_prefix)) { |
| 4736 | const path = trimmed_line[guide_prefix.len..]; |
| 4697 | 4737 | const trimmed_path = std.mem.trim(u8, path, " "); |
| 4698 | | try self.addGuide(file, trimmed_path); |
| 4738 | try self.addGuide(file, trimmed_path, current_section); |
| 4739 | } else if (std.mem.startsWith(u8, trimmed_line, section_prefix)) { |
| 4740 | const section_name = trimmed_line[section_prefix.len..]; |
| 4741 | const trimmed_section_name = std.mem.trim(u8, section_name, " "); |
| 4742 | try self.guide_sections.append(self.arena, .{ |
| 4743 | .name = trimmed_section_name, |
| 4744 | }); |
| 4745 | current_section = &self.guide_sections.items[self.guide_sections.items.len - 1]; |
| 4699 | 4746 | } |
| 4700 | 4747 | } |
| 4701 | 4748 | } |
| 4702 | 4749 | |
| 4703 | | fn addGuide(self: *Autodoc, file: *File, guide_path: []const u8) !void { |
| 4750 | fn addGuide(self: *Autodoc, file: *File, guide_path: []const u8, section: *Section) !void { |
| 4704 | 4751 | if (guide_path.len == 0) return error.MissingAutodocGuideName; |
| 4705 | 4752 | |
| 4706 | 4753 | const cur_pkg_dir_path = file.pkg.root_src_directory.path orelse "."; |
| ... | ... | @@ -4716,5 +4763,8 @@ fn addGuide(self: *Autodoc, file: *File, guide_path: []const u8) !void { |
| 4716 | 4763 | else => |e| return e, |
| 4717 | 4764 | }; |
| 4718 | 4765 | |
| 4719 | | try self.guides.put(self.arena, resolved_path, guide); |
| 4766 | try section.guides.append(self.arena, .{ |
| 4767 | .name = resolved_path, |
| 4768 | .body = guide, |
| 4769 | }); |
| 4720 | 4770 | } |