Skip to content

Commit

Permalink
Support Sphinx (#961)
Browse files Browse the repository at this point in the history
  • Loading branch information
josefpihrt authored Oct 22, 2022
1 parent 1a8d544 commit 41816ef
Show file tree
Hide file tree
Showing 23 changed files with 365 additions and 207 deletions.
2 changes: 2 additions & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Add code fix for CS0037 ([#929](https://github.com/josefpihrt/roslynator/pull/929)).
- [CLI] Generate reference documentation that can be published with Docusaurus ([#918](https://github.com/josefpihrt/roslynator/pull/918)).
- `roslynator generate-doc --host docusaurus`
- [CLI] Generate reference documentation that can be published with Sphinx ([#961](https://github.com/josefpihrt/roslynator/pull/961)).
- `roslynator generate-doc --host sphinx`

### Changed

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup Condition="'$(RoslynatorDotNetCli)' != true AND '$(RoslynatorCommandLine)' != true">
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
</PropertyGroup>

<PropertyGroup Condition="'$(RoslynatorDotNetCli)' == true AND '$(Configuration)' == 'Release'">
<PropertyGroup Condition="'$(RoslynatorDotNetCli)' == true">
<TargetFrameworks>net5.0;net6.0</TargetFrameworks>
</PropertyGroup>

Expand Down
3 changes: 2 additions & 1 deletion src/CommandLine/AssemblyResolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEven
Debug.Assert(
(!assemblyName.Name.StartsWith("Microsoft.")
|| assemblyName.Name.StartsWith("Microsoft.VisualStudio.")
|| string.Equals(assemblyName.Name, "Microsoft.DiaSymReader", StringComparison.Ordinal))
|| string.Equals(assemblyName.Name, "Microsoft.DiaSymReader", StringComparison.Ordinal)
|| assemblyName.Name.EndsWith(".Analyzers"))
&& !assemblyName.Name.StartsWith("System."),
assemblyName.ToString());

Expand Down
2 changes: 1 addition & 1 deletion src/CommandLine/CommandLine.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup Condition="'$(RoslynatorDotNetCli)' != true AND '$(RoslynatorCommandLine)' != true">
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
</PropertyGroup>

<PropertyGroup Condition="'$(RoslynatorDotNetCli)' == true">
Expand Down
86 changes: 82 additions & 4 deletions src/CommandLine/Commands/GenerateDocCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
Expand Down Expand Up @@ -112,7 +113,7 @@ public override async Task<CommandResult> ExecuteAsync(ProjectOrSolution project
ignoredCommonParts: IgnoredCommonParts,
includeContainingNamespaceFilter: IncludeContainingNamespaceFilter,
filesLayout: FilesLayout,
scrollToContent: Options.ScrollToContent);
scrollToContent: (DocumentationHost == DocumentationHost.GitHub) && Options.ScrollToContent);

ImmutableArray<Compilation> compilations = await GetCompilationsAsync(projectOrSolution, cancellationToken);

Expand All @@ -123,7 +124,9 @@ public override async Task<CommandResult> ExecuteAsync(ProjectOrSolution project
if (GroupByCommonNamespace)
{
commonNamespaces = DocumentationUtility.FindCommonNamespaces(
documentationModel.Types.Concat(documentationModel.GetExtendedExternalTypes()));
documentationModel.Types
.Concat(documentationModel.GetExtendedExternalTypes())
.Where(f => !documentationOptions.ShouldBeIgnored(f)));
}

UrlSegmentProvider urlSegmentProvider = new DefaultUrlSegmentProvider(FilesLayout, commonNamespaces);
Expand All @@ -138,6 +141,8 @@ DocumentationUrlProvider GetUrlProvider()
return new GitHubDocumentationUrlProvider(urlSegmentProvider, externalProviders);
case DocumentationHost.Docusaurus:
return new DocusaurusDocumentationUrlProvider(urlSegmentProvider, externalProviders);
case DocumentationHost.Sphinx:
return new SphinxDocumentationUrlProvider(urlSegmentProvider, externalProviders);
default:
throw new InvalidOperationException($"Unknown value '{DocumentationHost}'.");
}
Expand All @@ -148,6 +153,7 @@ MarkdownWriterSettings GetMarkdownWriterSettings()
switch (DocumentationHost)
{
case DocumentationHost.GitHub:
case DocumentationHost.Sphinx:
return MarkdownWriterSettings.Default;
case DocumentationHost.Docusaurus:
return new MarkdownWriterSettings(new MarkdownFormat(angleBracketEscapeStyle: AngleBracketEscapeStyle.EntityRef));
Expand All @@ -165,9 +171,11 @@ DocumentationWriter CreateDocumentationWriter(DocumentationContext context)
switch (DocumentationHost)
{
case DocumentationHost.GitHub:
return new MarkdownDocumentationWriter(context, writer);
return new GitHubDocumentationWriter(context, writer);
case DocumentationHost.Docusaurus:
return new DocusaurusDocumentationWriter(context, writer);
case DocumentationHost.Sphinx:
return new SphinxDocumentationWriter(context, writer);
default:
throw new InvalidOperationException($"Unknown value '{DocumentationHost}'.");
}
Expand Down Expand Up @@ -206,7 +214,16 @@ DocumentationWriter CreateDocumentationWriter(DocumentationContext context)

WriteLine($"Generate documentation to '{Options.Output}'", Verbosity.Minimal);

foreach (DocumentationGeneratorResult documentationFile in generator.Generate(heading: Options.Heading, cancellationToken))
IEnumerable<DocumentationGeneratorResult> results = generator.Generate(heading: Options.Heading, cancellationToken);

if (DocumentationHost == DocumentationHost.Sphinx)
{
List<DocumentationGeneratorResult> resultList = results.ToList();
AddTableOfContents(resultList);
results = resultList;
}

foreach (DocumentationGeneratorResult documentationFile in results)
{
string path = Path.Combine(directoryPath, documentationFile.FilePath);

Expand All @@ -221,5 +238,66 @@ DocumentationWriter CreateDocumentationWriter(DocumentationContext context)

return CommandResults.Success;
}

private void AddTableOfContents(IEnumerable<DocumentationGeneratorResult> results)
{
foreach (DocumentationGeneratorResult result in results)
{
string content = result.Content;
string filePath = result.FilePath;
string directoryPath = Path.GetDirectoryName(filePath);

IEnumerable<DocumentationGeneratorResult> children = results.Where(r =>
{
if (r != result)
{
string path = r.FilePath;
if (path.StartsWith(directoryPath))
{
string relativePath = path.Substring(directoryPath.Length).TrimStart(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
if (relativePath.Count(f => f == Path.DirectorySeparatorChar || f == Path.AltDirectorySeparatorChar) == 1)
{
return true;
}
}
}
return false;
});

if (children.Any())
{
var sb = new StringBuilder();

sb.AppendLine();
sb.AppendLine("```{toctree}");
sb.AppendLine(":hidden:");
sb.AppendLine(":maxdepth: 1");
sb.AppendLine();

foreach (DocumentationGeneratorResult child in children
.OrderBy(child => child.Label))
{
Debug.Assert(child.Label is not null);

sb.Append(child.Label);
sb.Append(" <");

sb.Append(child.FilePath
.Substring(directoryPath.Length)
.TrimStart(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)
.Replace('\\', '/'));

sb.AppendLine(">");
}

sb.AppendLine("```");

result.Content += sb.ToString();
}
}
}
}
}
9 changes: 7 additions & 2 deletions src/CommandLine/Commands/GenerateDocRootCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public override async Task<CommandResult> ExecuteAsync(ProjectOrSolution project
depth: Depth,
ignoredRootParts: IgnoredParts,
includeContainingNamespaceFilter: IncludeContainingNamespaceFilter,
scrollToContent: Options.ScrollToContent);
scrollToContent: (DocumentationHost == DocumentationHost.GitHub) && Options.ScrollToContent);

ImmutableArray<Compilation> compilations = await GetCompilationsAsync(projectOrSolution, cancellationToken);

Expand All @@ -80,6 +80,8 @@ DocumentationUrlProvider GetUrlProvider()
return new GitHubDocumentationUrlProvider(urlSegmentProvider, externalProviders);
case DocumentationHost.Docusaurus:
return new DocusaurusDocumentationUrlProvider(urlSegmentProvider, externalProviders);
case DocumentationHost.Sphinx:
return new SphinxDocumentationUrlProvider(urlSegmentProvider, externalProviders);
default:
throw new InvalidOperationException($"Unknown value '{DocumentationHost}'.");
}
Expand All @@ -90,6 +92,7 @@ MarkdownWriterSettings GetMarkdownWriterSettings()
switch (DocumentationHost)
{
case DocumentationHost.GitHub:
case DocumentationHost.Sphinx:
return MarkdownWriterSettings.Default;
case DocumentationHost.Docusaurus:
return new MarkdownWriterSettings(new MarkdownFormat(angleBracketEscapeStyle: AngleBracketEscapeStyle.EntityRef));
Expand All @@ -107,9 +110,11 @@ DocumentationWriter CreateDocumentationWriter(DocumentationContext context)
switch (DocumentationHost)
{
case DocumentationHost.GitHub:
return new MarkdownDocumentationWriter(context, writer);
return new GitHubDocumentationWriter(context, writer);
case DocumentationHost.Docusaurus:
return new DocusaurusDocumentationWriter(context, writer);
case DocumentationHost.Sphinx:
return new SphinxDocumentationWriter(context, writer);
default:
throw new InvalidOperationException($"Unknown value '{DocumentationHost}'.");
}
Expand Down
3 changes: 2 additions & 1 deletion src/CommandLine/DocumentationHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ namespace Roslynator.CommandLine
{
internal enum DocumentationHost
{
GitHub,
Docusaurus,
GitHub,
Sphinx,
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public abstract class AbstractGenerateDocCommandLineOptions : MSBuildCommandLine
[Option(
longName: OptionNames.Host,
Required = true,
HelpText = "Defines a host where the content will be published. Allowed values are github or docusaurus.",
HelpText = "Defines a host where the content will be published. Allowed values are docusaurus, github or sphinx.",
MetaValue = "<HOST>")]
public string Host { get; set; }

Expand All @@ -59,7 +59,7 @@ public abstract class AbstractGenerateDocCommandLineOptions : MSBuildCommandLine

[Option(
longName: "scroll-to-content",
HelpText = "Indicates whether a link should lead to the top of the documentation content.")]
HelpText = "Indicates whether a link should lead to the top of the documentation content. This option is applicable when host is set to 'github'.")]
public bool ScrollToContent { get; set; }

[Option(
Expand Down
12 changes: 12 additions & 0 deletions src/Documentation/DocumentationContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using Microsoft.CodeAnalysis;

namespace Roslynator.Documentation
{
public class DocumentationContext
{
private readonly Func<DocumentationContext, DocumentationWriter> _createWriter;
private ImmutableHashSet<(INamespaceSymbol, string)> _commonNamespacesAsText;

public DocumentationContext(
DocumentationModel documentationModel,
Expand Down Expand Up @@ -44,6 +46,16 @@ public DocumentationContext(

public ImmutableHashSet<INamespaceSymbol> CommonNamespaces { get; }

internal ImmutableHashSet<(INamespaceSymbol symbol, string displayString)> CommonNamespacesAsText
{
get
{
return _commonNamespacesAsText ??= CommonNamespaces
.Select(f => (f, f.ToDisplayString(TypeSymbolDisplayFormats.Name_ContainingTypes_Namespaces_GlobalNamespace_OmittedAsContaining)))
.ToImmutableHashSet();
}
}

public DocumentationWriter CreateWriter()
{
return _createWriter(this);
Expand Down
Loading

0 comments on commit 41816ef

Please sign in to comment.