diff options
| author | Yong He <yonghe@outlook.com> | 2024-10-15 14:21:21 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-10-15 14:21:21 -0700 |
| commit | ba26c2d7020b41e0d348c7235f86a4232982ab9e (patch) | |
| tree | 051f407170d724ba0196b6e174241548b2bd2230 /source/slang/slang-doc-markdown-writer.cpp | |
| parent | 3e170c732bfcd2aedf78deb047db94e196a1b83a (diff) | |
Add stdlib documentation for attributes and interfaces. (#5297)
* Add stdlib documentation for attributes and interfaces.
* Fix name mangling to avoid collision of functions in different extensions.
* Fix doc.
Diffstat (limited to 'source/slang/slang-doc-markdown-writer.cpp')
| -rw-r--r-- | source/slang/slang-doc-markdown-writer.cpp | 165 |
1 files changed, 144 insertions, 21 deletions
diff --git a/source/slang/slang-doc-markdown-writer.cpp b/source/slang/slang-doc-markdown-writer.cpp index 2b4586db2..dcfe011f8 100644 --- a/source/slang/slang-doc-markdown-writer.cpp +++ b/source/slang/slang-doc-markdown-writer.cpp @@ -223,17 +223,39 @@ String DocMarkdownWriter::_getFullName(Decl* decl) String _translateNameToPath(const UnownedStringSlice& name) { + // We will generate an all-lowercase file name based on the name of the decl. + // We do so by converting all capital letters to lowercase, and append a disambiguator + // postfix at the end that tracks the location of the capital letters in the original name. + // For example, `MyType` will be converted to `mytype-02`, because there is one capital letter + // at location 0 and one at location 2. + // To prevent URL issues, all leading underscores are replaced with '0', and we + // will also append the location of the replaced character to the disambiguator postfix. + // For example, `_MyType` will be converted to `0mytype-013`. + // To keep disambiguators short, we use base 36 to represent each location. + StringBuilder buf; - for (const char c : name) + StringBuilder disambiguatorSB; + for (Index i = 0; i < name.getLength(); i++) { + auto c = name[i]; // Removing leading underscores to prevent url issues. if (c == '_' && buf.getLength() == 0) + { + disambiguatorSB.append(String(i, 36)); + buf.appendChar('0'); continue; + } if (c == ' ') { buf.appendChar('-'); } + else if (c >= 'A' && c <= 'Z') + { + // Convert to lower case. + buf.appendChar((char)(c - 'A' + 'a')); + disambiguatorSB.append(String(i, 36)); + } else if (CharUtil::isAlphaOrDigit(c) || c == '_') { buf.appendChar(c); @@ -244,6 +266,11 @@ String _translateNameToPath(const UnownedStringSlice& name) buf << String((int)c, 16); } } + if (disambiguatorSB.getLength()) + { + buf << "-"; + buf << disambiguatorSB.produceString().toLower(); + } return buf; } @@ -263,6 +290,10 @@ String DocMarkdownWriter::_getDocFilePath(Decl* decl) { sb << "types/"; } + else if (as<AttributeDecl>(decl)) + { + sb << "attributes/"; + } else { sb << "global-decls/"; @@ -319,12 +350,15 @@ DocMarkdownWriter::NameAndText DocMarkdownWriter::_getNameAndText(ASTMarkup::Ent StringBuilder sb; if (auto varDeclBase = as<VarDeclBase>(decl)) { - sb << " : " << varDeclBase->type->toString(); - - if (varDeclBase->initExpr) + if (varDeclBase->type) { - sb << " = "; - _appendExpr(sb, varDeclBase->initExpr); + sb << " : " << varDeclBase->type->toString(); + + if (varDeclBase->initExpr) + { + sb << " = "; + _appendExpr(sb, varDeclBase->initExpr); + } } } else if (auto typeParam = as<GenericTypeParamDeclBase>(decl)) @@ -629,6 +663,71 @@ void DocMarkdownWriter::writeTypeDef(const ASTMarkup::Entry& entry, TypeDefDecl* declDoc.writeSection(out, this, typeDefDecl, DocPageSection::SeeAlso); } +static String getAttributeName(AttributeDecl* decl) +{ + auto name = getText(decl->getName()); + if (name.startsWith("vk_")) + { + return String("vk::") + String(name.getUnownedSlice().tail(3)); + } + return name; +} + +void DocMarkdownWriter::writeAttribute(const ASTMarkup::Entry& entry, AttributeDecl* attributeDecl) +{ + auto& out = *m_builder; + + out << toSlice("# attribute ["); + out << escapeMarkdownText(getAttributeName(attributeDecl)); + out << toSlice("]\n\n"); + DeclDocumentation declDoc; + declDoc.parse(entry.m_markup.getUnownedSlice()); + declDoc.writeDescription(out, this, attributeDecl); + registerCategory(m_currentPage, declDoc); + + out << toSlice("## Signature\n\n"); + List<Decl*> paramDecls; + for (auto param : attributeDecl->getMembersOfType<ParamDecl>()) + { + paramDecls.add(param); + } + out << "<pre>\n"; + out << "[" << translateToHTMLWithLinks(attributeDecl, getAttributeName(attributeDecl)); + if (paramDecls.getCount() > 0) + { + out << "("; + for (Index i = 0; i < paramDecls.getCount(); i++) + { + if (i > 0) + out << ", "; + auto param = paramDecls[i]; + out << translateToHTMLWithLinks(attributeDecl, _getName(param)); + auto type = as<ParamDecl>(param)->type; + if (type) + { + out << " : "; + out << translateToHTMLWithLinks(attributeDecl, type->toString()); + } + } + out << ")"; + } + out << "]\n</pre>\n\n"; + + if (paramDecls.getCount() > 0) + { + out << "## Parameters\n\n"; + + // Document ordinary parameters + _appendAsBullets(_getUniqueParams(paramDecls, &declDoc), false, 0); + + out << toSlice("\n"); + } + + declDoc.writeSection(out, this, attributeDecl, DocPageSection::Remarks); + declDoc.writeSection(out, this, attributeDecl, DocPageSection::Example); + declDoc.writeSection(out, this, attributeDecl, DocPageSection::SeeAlso); +} + void DocMarkdownWriter::writeExtensionConditions(StringBuilder& out, ExtensionDecl* extensionDecl, const char* prefix, bool isHtml) { // Synthesize `where` clause for things defined in an extension. @@ -1125,15 +1224,18 @@ void ParsedDescription::parse(UnownedStringSlice text) ownedText = text; List<UnownedStringSlice> lines; StringUtil::calcLines(text, lines); + Index codeBlockIndent = 0; bool isInCodeBlock = false; for (auto line : lines) { + auto originalLine = line; line = line.trim(); if (line.startsWith("```")) { isInCodeBlock = !isInCodeBlock; spans.add({ line, DocumentationSpanKind::OrdinaryText}); spans.add({ toSlice("\n"), DocumentationSpanKind::OrdinaryText }); + codeBlockIndent = originalLine.indexOf('`'); continue; } @@ -1169,6 +1271,18 @@ void ParsedDescription::parse(UnownedStringSlice text) } else { + line = originalLine; + for (Index i = 0; i < codeBlockIndent; i++) + { + if (line.startsWith(" ")) + { + line = line.tail(1); + } + else + { + break; + } + } spans.add({ line, DocumentationSpanKind::OrdinaryText }); spans.add({ toSlice("\n"), DocumentationSpanKind::OrdinaryText }); } @@ -1183,7 +1297,8 @@ void DeclDocumentation::parse(const UnownedStringSlice& text) Dictionary<DocPageSection, StringBuilder> sectionBuilders; for (Index ptr = 0; ptr < lines.getCount(); ptr++) { - auto line = lines[ptr].trim(); + auto originalLine = lines[ptr]; + auto line = originalLine.trim(); if (line.startsWith("@param")) { currentSection = DocPageSection::Parameter; @@ -1280,6 +1395,10 @@ void DeclDocumentation::parse(const UnownedStringSlice& text) } continue; } + else + { + line = originalLine; + } sectionBuilders[currentSection] << line << "\n"; // If the current directive is a callout, set currentSection back @@ -2201,7 +2320,7 @@ void DeclDocumentation::writeSection(StringBuilder& out, DocMarkdownWriter* writ } } -void DocMarkdownWriter::createPage(DocMarkdownWriter::WriteDeclMode mode, ASTMarkup::Entry& entry, Decl* decl) +void DocMarkdownWriter::createPage(ASTMarkup::Entry& entry, Decl* decl) { // Skip these they will be output as part of their respective 'containers' if (as<ParamDecl>(decl) || @@ -2218,35 +2337,33 @@ void DocMarkdownWriter::createPage(DocMarkdownWriter::WriteDeclMode mode, ASTMar { if (_isFirstOverridden(callableDecl)) { - if (mode == WriteDeclMode::Header) - ensureDeclPageCreated(entry); + ensureDeclPageCreated(entry); } } else if (as<EnumDecl>(decl)) { - if (mode == WriteDeclMode::Header) - ensureDeclPageCreated(entry); + ensureDeclPageCreated(entry); } else if (as<AggTypeDeclBase>(decl)) { - if (mode == WriteDeclMode::Header) - ensureDeclPageCreated(entry); + ensureDeclPageCreated(entry); } else if (as<VarDecl>(decl)) { // If part of aggregate type will be output there. - if (mode == WriteDeclMode::Header) - ensureDeclPageCreated(entry); + ensureDeclPageCreated(entry); } else if (as<TypeDefDecl>(decl)) { - if (mode == WriteDeclMode::Header) - ensureDeclPageCreated(entry); + ensureDeclPageCreated(entry); } else if (as<PropertyDecl>(decl)) { - if (mode == WriteDeclMode::Header) - ensureDeclPageCreated(entry); + ensureDeclPageCreated(entry); + } + else if (as<AttributeDecl>(decl)) + { + ensureDeclPageCreated(entry); } else if (as<GenericDecl>(decl)) { @@ -2504,6 +2621,7 @@ DocumentPage* DocMarkdownWriter::writeAll(UnownedStringSlice configStr) m_interfacesPage = addBuiltinPage(m_rootPage.get(), toSlice("interfaces/index.md"), toSlice("Interfaces"), toSlice("Interfaces")); m_typesPage = addBuiltinPage(m_rootPage.get(), toSlice("types/index.md"), toSlice("Types"), toSlice("Types")); + m_attributesPage = addBuiltinPage(m_rootPage.get(), toSlice("attributes/index.md"), toSlice("Attributes"), toSlice("Attributes")); m_globalDeclsPage = addBuiltinPage(m_rootPage.get(), toSlice("global-decls/index.md"), toSlice("Global Declarations"), toSlice("Global Declarations")); // In the first pass, we create all the pages so we can reference them @@ -2514,7 +2632,7 @@ DocumentPage* DocMarkdownWriter::writeAll(UnownedStringSlice configStr) if (decl && isVisible(entry)) { - createPage(WriteDeclMode::Header, entry, decl); + createPage(entry, decl); } } // In the second pass, actually writes the content to each page. @@ -2522,6 +2640,7 @@ DocumentPage* DocMarkdownWriter::writeAll(UnownedStringSlice configStr) generateSectionIndexPage(m_interfacesPage); generateSectionIndexPage(m_typesPage); + generateSectionIndexPage(m_attributesPage); generateSectionIndexPage(m_globalDeclsPage); return m_rootPage.get(); @@ -2576,6 +2695,10 @@ void DocMarkdownWriter::writePage(DocumentPage* page) { writeTypeDef(*page->getFirstEntry(), typeDefDecl); } + else if (AttributeDecl* attributeDecl = as<AttributeDecl>(decl)) + { + writeAttribute(*page->getFirstEntry(), attributeDecl); + } } void DocMarkdownWriter::writePageRecursive(DocumentPage* page) |
