summaryrefslogtreecommitdiff
path: root/source/slang/slang-doc-markdown-writer.cpp
diff options
context:
space:
mode:
authorYong He <yonghe@outlook.com>2024-10-15 14:21:21 -0700
committerGitHub <noreply@github.com>2024-10-15 14:21:21 -0700
commitba26c2d7020b41e0d348c7235f86a4232982ab9e (patch)
tree051f407170d724ba0196b6e174241548b2bd2230 /source/slang/slang-doc-markdown-writer.cpp
parent3e170c732bfcd2aedf78deb047db94e196a1b83a (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.cpp165
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)