diff options
| -rw-r--r-- | lib/docs/main.js | 26 | ||||
| -rw-r--r-- | src/Autodoc.zig | 72 |
2 files changed, 93 insertions, 5 deletions
diff --git a/lib/docs/main.js b/lib/docs/main.js index 2d10918400..14bcf0f544 100644 --- a/lib/docs/main.js +++ b/lib/docs/main.js @@ -563,12 +563,14 @@ const NAV_MODES = { let currentType = getType(mod.main); curNav.declObjs = [currentType]; + let lastDecl = mod.main; for (let i = 0; i < curNav.declNames.length; i += 1) { let childDecl = findSubDecl(currentType, curNav.declNames[i]); window.last_decl = childDecl; if (childDecl == null) { return render404(); } + lastDecl = childDecl; let childDeclValue = resolveValue(childDecl.value).expr; if ("type" in childDeclValue) { @@ -593,9 +595,7 @@ const NAV_MODES = { let lastIsType = isType(last); let lastIsContainerType = isContainerType(last); - if (lastIsDecl) { - renderDocTest(last); - } + renderDocTest(lastDecl); if (lastIsContainerType) { return renderContainer(last); @@ -642,7 +642,25 @@ const NAV_MODES = { if (!decl.decltest) return; const astNode = getAstNode(decl.decltest); domSectDocTests.classList.remove("hidden"); - domDocTestsCode.innerHTML = astNode.code; + domDocTestsCode.innerHTML = renderZigSource(astNode.code); + } + + function renderZigSource(code) { + let lines = code.split("\n"); + let result = ""; + let indent_level = 0; + for(let i = 0; i < lines.length; i += 1) { + let line = lines[i].trim(); + if(line[0] == "}") indent_level -= 1; + for(let j = 0; j < indent_level; j += 1) { + result += " "; + } + if (line.startsWith("\\\\")) result += " " + result += line; + result += "\n"; + if(line[line.length - 1] == "{") indent_level += 1; + } + return result; } function renderUnknownDecl(decl) { diff --git a/src/Autodoc.zig b/src/Autodoc.zig index 467ff55994..f73e718a4d 100644 --- a/src/Autodoc.zig +++ b/src/Autodoc.zig @@ -3104,7 +3104,9 @@ fn analyzeAllDecls( while (it.next()) |d| { const decl_name_index = file.zir.extra[d.sub_index + 5]; switch (decl_name_index) { - 0, 1, 2 => continue, // skip over usingnamespace decls + 0, 1 => continue, // skip over usingnamespace decls + 2 => continue, // skip decltests + else => if (file.zir.string_bytes[decl_name_index] == 0) { continue; }, @@ -3120,6 +3122,24 @@ fn analyzeAllDecls( ); } + // Fourth loop to analyze decltests + it = original_it; + while (it.next()) |d| { + const decl_name_index = file.zir.extra[d.sub_index + 5]; + switch (decl_name_index) { + 0, 1 => continue, // skip over usingnamespace decls + 2 => {}, + else => continue, // skip tests and normal decls + } + + try self.analyzeDecltest( + file, + scope, + parent_src, + d, + ); + } + return it.extra_index; } @@ -3327,6 +3347,56 @@ fn analyzeUsingnamespaceDecl( } } +fn analyzeDecltest( + self: *Autodoc, + file: *File, + scope: *Scope, + parent_src: SrcLocInfo, + d: Zir.DeclIterator.Item, +) AutodocErrors!void { + const data = file.zir.instructions.items(.data); + + const value_index = file.zir.extra[d.sub_index + 6]; + const decl_name_index = file.zir.extra[d.sub_index + 7]; + + // This is known to work because decl values are always block_inlines + const value_pl_node = data[value_index].pl_node; + const decl_src = try self.srcLocInfo(file, value_pl_node.src_node, parent_src); + + const func_index = getBlockInlineBreak(file.zir, value_index).?; + const pl_node = data[Zir.refToIndex(func_index).?].pl_node; + const fn_src = try self.srcLocInfo(file, pl_node.src_node, decl_src); + const tree = try file.getTree(self.comp_module.gpa); + const test_source_code = tree.getNodeSource(fn_src.src_node); + + const decl_name: ?[]const u8 = if (decl_name_index != 0) + file.zir.nullTerminatedString(decl_name_index) + else + null; + + // astnode + const ast_node_index = idx: { + const idx = self.ast_nodes.items.len; + try self.ast_nodes.append(self.arena, .{ + .file = self.files.getIndex(file).?, + .line = decl_src.line, + .col = 0, + .name = decl_name, + .code = test_source_code, + }); + break :idx idx; + }; + + const decl_status = scope.resolveDeclName(decl_name_index, file, 0); + + switch (decl_status.*) { + .Analyzed => |idx| { + self.decls.items[idx].decltest = ast_node_index; + }, + else => unreachable, // we assume analyzeAllDecls analyzed other decls by this point + } +} + /// An unresolved path has a non-string WalkResult at its beginnig, while every /// other element is a string WalkResult. Resolving means iteratively map each /// string to a Decl / Type / Call / etc. |
