Docs redesign (#728)

* Adding a dark mode
* Adding reference for types to summary pages
* Adding API Reference
* Adding modifiers to methods/fields/etc
* Minimizing files input
* Caching a lot of the output pages
* Cache only for each execution
* Adding API references to existing docs
This commit is contained in:
Phil Scott 2022-02-14 12:44:25 -05:00 committed by GitHub
parent 74a2e10ff0
commit c2da268129
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
147 changed files with 4112 additions and 6897 deletions

View File

@ -6,12 +6,13 @@
<RunWorkingDirectory>$(MSBuildProjectDirectory)</RunWorkingDirectory> <RunWorkingDirectory>$(MSBuildProjectDirectory)</RunWorkingDirectory>
<DefaultItemExcludes>$(DefaultItemExcludes);output\**;.gitignore</DefaultItemExcludes> <DefaultItemExcludes>$(DefaultItemExcludes);output\**;.gitignore</DefaultItemExcludes>
<NoWarn>MVC1000</NoWarn> <NoWarn>MVC1000</NoWarn>
<MinVerSkip Condition="'$(Configuration)' == 'Debug'">true</MinVerSkip> <MinVerSkip>true</MinVerSkip>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Compile Remove="input\**" /> <Compile Remove="input\**" />
<Compile Remove="sass\**" /> <Compile Remove="sass\**" />
<Compile Include="input\api\Sections\_ConstantValue.cshtml.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@ -33,8 +34,10 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.Playwright" Version="1.13.0-next-1" /> <PackageReference Include="Microsoft.Playwright" Version="1.13.0-next-1" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="Statiq.Web" Version="1.0.0-beta.34" /> <PackageReference Include="Statiq.CodeAnalysis" Version="1.0.0-beta.56" />
<PackageReference Include="Statiq.Common" Version="1.0.0-beta.56" />
<PackageReference Include="Statiq.Web" Version="1.0.0-beta.42" />
<PackageReference Include="MinVer" PrivateAssets="All" Version="2.3.1" /> <PackageReference Include="MinVer" PrivateAssets="All" Version="2.3.1" />
</ItemGroup> </ItemGroup>

View File

@ -1,5 +1,9 @@
using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Docs.Extensions;
using Docs.Shortcodes; using Docs.Shortcodes;
using Docs.Utilities;
using Microsoft.Extensions.DependencyInjection;
using Statiq.App; using Statiq.App;
using Statiq.Common; using Statiq.Common;
using Statiq.Core; using Statiq.Core;
@ -15,14 +19,28 @@ namespace Docs
.AddSetting(Keys.Host, "spectreconsole.net") .AddSetting(Keys.Host, "spectreconsole.net")
.AddSetting(Keys.LinksUseHttps, true) .AddSetting(Keys.LinksUseHttps, true)
.AddSetting(Constants.EditLink, ConfigureEditLink()) .AddSetting(Constants.EditLink, ConfigureEditLink())
.AddSetting(Constants.SourceFiles, new List<string>
{
"../../src/Spectre.Console/**/{!bin,!obj,!packages,!*.Tests,}/**/*.cs",
"../../src/Spectre.Console.ImageSharp/**/{!bin,!obj,!packages,!*.Tests,}/**/*.cs"
})
.AddSetting(Constants.ExampleSourceFiles, new List<string>
{
"../../examples/**/{!bin,!obj,!packages,!*.Tests,}/**/*.cs",
}
)
.ConfigureServices(i =>
{
i.AddSingleton(new TypeNameLinks());
})
.ConfigureSite("spectreconsole", "spectre.console", "main") .ConfigureSite("spectreconsole", "spectre.console", "main")
.ConfigureDeployment(deployBranch: "docs") .ConfigureDeployment(deployBranch: "docs")
.AddShortcode("Children", typeof(ChildrenShortcode)) .AddShortcode("Children", typeof(ChildrenShortcode))
.AddShortcode("ColorTable", typeof(ColorTableShortcode)) .AddShortcode("ColorTable", typeof(ColorTableShortcode))
.AddShortcode("EmojiTable", typeof(EmojiTableShortcode)) .AddShortcode("EmojiTable", typeof(EmojiTableShortcode))
.AddShortcode("Alert", typeof(AlertShortcode)) .AddShortcode("Alert", typeof(AlertShortcode))
.AddShortcode("AsciiCast", typeof(AsciiCastShortcode)) .AddShortcode("AsciiCast", typeof(AsciiCastShortcode))
.AddShortcode("Example", typeof(ExampleSnippet))
.AddPipelines() .AddPipelines()
.BuildPipeline( .BuildPipeline(
"Bootstrap", "Bootstrap",

View File

@ -1,3 +1,3 @@
@{ @{
Layout = @"/_layout.cshtml"; Layout = @"_layout.cshtml";
} }

View File

@ -1,137 +1,265 @@
@using Docs.Extensions
@using Statiq.CodeAnalysis
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=Edge"> <meta http-equiv="X-UA-Compatible" content="IE=Edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="@Context.GetLink("/assets/styles.css")" rel="stylesheet" /> <link href="@Context.GetLink("/assets/styles.css")" rel="stylesheet"/>
<link rel="preconnect" href="https://fonts.gstatic.com" /> <link rel="preconnect" href="https://fonts.gstatic.com"/>
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;700&display=swap" rel="stylesheet" /> <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;700&display=swap" rel="stylesheet"/>
<link rel="apple-touch-icon" sizes="180x180" href="@Context.GetLink("/assets/favicons/apple-touch-icon.png")"> <link rel="apple-touch-icon" sizes="180x180" href="@Context.GetLink("/assets/favicons/apple-touch-icon.png")">
<link rel="icon" type="image/png" sizes="32x32" href="@Context.GetLink("/assets/favicons/favicon-32x32.png")"> <link rel="icon" type="image/png" sizes="32x32" href="@Context.GetLink("/assets/favicons/favicon-32x32.png")">
<link rel="icon" type="image/png" sizes="16x16" href="@Context.GetLink("/assets/favicons/favicon-16x16.png")"> <link rel="icon" type="image/png" sizes="16x16" href="@Context.GetLink("/assets/favicons/favicon-16x16.png")">
@{ @{
string title = Document.ContainsKey(Keys.Title) ? $"Spectre.Console - {Document.GetString(Keys.Title)}" : "Spectre.Console"; string title = Document.ContainsKey(Keys.Title) ? $"Spectre.Console - {Document.GetString(Keys.Title)}" : "Spectre.Console";
string description = Document.ContainsKey(Constants.Description) ? Document.GetString(Constants.Description) : "Spectre.Console is a .NET Standard 2.0 library that makes it easier to create beautiful console applications"; string description = Document.ContainsKey(Constants.Description) ? Document.GetString(Constants.Description) : "Spectre.Console is a .NET Standard 2.0 library that makes it easier to create beautiful console applications";
var card = Outputs.FirstOrDefault(i => i.GetString("DocId") == Model.Id.ToString()); var card = Context.FindCard(Model.Id);
var urlBase = $"https://{Document.GetString(Keys.Host)}/"; var urlBase = $"https://{Document.GetString(Keys.Host)}/";
} }
<title>@title</title> <title>@title</title>
<meta name="description" content="@description" /> <meta name="description" content="@description"/>
<meta name="xref" content="@HtmlEncoder.Encode(Document.GetString(WebKeys.Xref))" />
@if(card != null){
<meta name="twitter:card" content="summary_large_image" />
<meta name="og:title" content="@title" />
<meta name="og:description" content="@description" />
<meta name="og:image" content="@(urlBase + card.Destination)" />
}
</head>
<body class="antialiased text-gray-600 min-h-full flex flex-col bg-gray-50">
<header class="flex-none text-sm font-medium bg-gradient-to-b from-gray-200 to-gray-100 ring-1 ring-gray-900 ring-opacity-5 shadow py-2 md:py-4">
<nav class="flex flex-row container mx-auto items-center">
<a class="flex flex-row items-center" href="@Context.GetLink("/")">
<img id="logo" class="w-auto h-10 md:h-12" height="48" width="48" src="@Context.GetLink("/assets/logo.svg")" alt="Spectre.Console">
<span class="text-lg md:text-2xl font-light ml-2 lg:ml-4 font-mono tracking-tighter">Spectre.Console</span>
</a>
<div class="ml-auto">
<ul class="flex flex-row">
<li>
<a class="flex flex-row items-center text-red-700" href="https://github.com/sponsors/patriksvensson">
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<title>Sponsor</title>
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z" />
</svg>
<span class="hidden sm:block">Sponsor</span>
</a>
</li>
<li class="ml-4">
<a class="flex flex-row items-center text-gray-600" href="https://github.com/spectreconsole/spectre.console">
<svg role="img" class="h-6 w-6 mr-2" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<title>GitHub icon</title>
<path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg>
<span class="hidden sm:block">GitHub</span>
</a>
</li>
</ul>
</div>
</nav>
</header>
<main class="container mx-auto pt-4 md:pt-8 w-full">
<div class="flex flex-col-reverse lg:flex-row">
<nav class="flex-none font-light text-sm xl:text-base sm:mr-16 mt-8 pt-6 lg:mt-0 lg:pt-0 border-t border-gray-300 lg:border-t-0">
@{
IDocument root = OutputPages["index.html"].First();
<div class="text-xl @(Document.IdEquals(root) ? "font-bold" : null)">
@if(root.ShowLink())
{
@Html.DocumentLink(root)
}
else
{
@root.GetTitle()
}
</div>
@foreach (IDocument document in OutputPages.GetChildrenOf(root).OrderBy(i => i.GetInt("Order")).OnlyVisible())
{
if(string.IsNullOrWhiteSpace(document.GetTitle()))
{
continue;
}
DocumentList<IDocument> documentChildren = OutputPages.GetChildrenOf(document);
<div class="text-blue-700 mt-4">
@if(document.ShowLink())
{
@Html.DocumentLink(document)
}
else
{
@document.GetTitle()
}
</div>
@if (documentChildren.OnlyVisible().Any())
{
<div class="ml-2 flex flex-row flex-wrap lg:flex-col border-separate">
@foreach (IDocument child in documentChildren.OnlyVisible())
{
<div class="mt-2 mr-4 @(Document.IdEquals(child) ? "font-bold" : null)">
@Html.DocumentLink(child)
</div>
}
</div>
}
}
}
</nav>
<article class="flex-1 min-w-0">
<header class="text-gray-800 mb-4">
<h1 class="text-4xl font-extrabold">@(Document.GetString(Keys.Title) ?? Document.GetTitle())</h1>
@RenderSection("subheading", required: false)
</header>
<div class="prose max-w-none prose-sm lg:prose lg:max-w-none 2xl:prose-xl 2xl:max-w-none text-gray-700 font-light">
@RenderBody()
</div>
</article>
</div>
</main>
<footer class="py-4 md:py-8 mt-8 bg-gray-100 text-sm border-t border-gray-200">
<div class="container">
<div class="flex flex-row">
<span>© @DateTime.Today.Year Patrik Svensson, Phil Scott</span>
<span class="ml-auto">@VersionUtilities.GetVersion()</span>
</div>
</div>
</footer>
@if (card != null)
{
<meta name="twitter:card" content="summary_large_image"/>
<meta name="og:title" content="@title"/>
<meta name="og:description" content="@description"/>
<meta name="og:image" content="@(urlBase + card)"/>
}
<script> <script>
if (localStorage.theme === 'dark' || (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
document.documentElement.classList.add('dark');
} else {
document.documentElement.classList.remove('dark');
}
</script>
</head>
<body class="antialiased text-slate-800 dark:text-slate-200 bg-slate-100 dark:bg-slate-800 transition-colors min-h-full flex flex-col">
<header class="flex-none sticky top-0 z-40 text-sm font-medium bg-slate-200 backdrop-blur dark:bg-slate-800 ring-1 ring-slate-900 dark:ring-slate-700 ring-opacity-5 shadow-lg py-2 md:py-4">
<nav class="flex flex-row container mx-auto items-center">
<a class="flex flex-row items-center" href="@Context.GetLink("/")">
<svg xmlns="http://www.w3.org/2000/svg"
id="logo" class="w-auto h-10 md:h-12 fill-slate-700 dark:fill-slate-400 dark:stroke-slate-900" height="48" width="48" viewBox="0 0 1270.000000 1270.000000"
preserveAspectRatio="xMidYMid meet">
<metadata>
Created by potrace 1.16, written by Peter Selinger 2001-2019
</metadata>
<g transform="translate(0.000000,1270.000000) scale(0.100000,-0.100000)">
<path d="M799 10610 c-199 -48 -354 -191 -414 -383 l-25 -78 0 -3084 0 -3084
25 -79 c45 -141 155 -270 289 -335 124 -61 -80 -57 2819 -57 l2646 0 5 -43 c3
-23 8 -71 11 -105 13 -137 88 -334 179 -471 57 -85 187 -219 247 -254 25 -15
76 -34 112 -43 87 -22 163 -7 246 46 120 78 195 211 234 411 l23 124 14 -55
c63 -263 172 -511 326 -741 94 -142 229 -291 313 -348 272 -185 583 -197 750
-30 66 67 84 109 89 215 4 90 4 91 -51 230 -108 276 -137 477 -122 868 l7 196
77 0 c55 0 118 -11 229 -39 l154 -38 50 -84 c103 -172 221 -427 277 -599 38
-120 70 -274 86 -412 8 -75 21 -155 29 -178 37 -106 117 -199 220 -253 51 -26
202 -35 283 -17 83 18 193 97 268 192 157 199 256 485 286 825 11 122 6 524
-7 583 -5 24 -1 26 62 43 64 16 67 16 80 0 39 -50 109 -215 149 -351 25 -85
55 -174 67 -199 73 -156 261 -206 441 -117 65 32 110 70 159 135 128 169 178
414 157 764 -8 143 -38 350 -55 376 -2 4 7 25 22 46 77 112 168 344 200 504
l16 86 87 28 c188 60 391 170 498 269 132 122 183 230 183 383 0 71 -5 98 -24
138 -24 52 -82 112 -138 141 -52 28 -205 30 -378 5 -80 -11 -179 -23 -220 -27
l-75 -6 -29 56 c-33 65 -137 182 -211 236 -75 55 -156 94 -382 181 -110 43
-221 87 -245 100 -54 27 -92 69 -125 138 -25 52 -26 59 -20 180 4 69 16 200
26 291 52 430 53 809 5 1170 -54 405 -249 740 -569 979 -136 102 -297 190
-419 231 l-36 12 0 433 c0 433 0 434 -25 512 -52 167 -171 292 -341 360 l-69
28 -4215 2 c-2318 0 -4231 -3 -4251 -7z m8363 -1476 c417 -53 735 -193 962
-423 98 -98 155 -175 210 -282 84 -160 117 -292 141 -559 28 -313 17 -684 -30
-1025 -9 -60 -18 -164 -22 -230 -10 -208 22 -314 136 -452 76 -91 124 -118
391 -218 307 -116 377 -155 450 -249 23 -31 41 -58 39 -60 -2 -2 -47 8 -99 21
-131 35 -268 36 -360 3 -132 -47 -248 -116 -364 -218 -163 -143 -516 -488
-703 -687 -350 -372 -504 -514 -701 -644 -348 -231 -878 -408 -1322 -442 -409
-31 -796 45 -1059 208 -111 69 -249 210 -292 298 -32 65 -34 76 -33 165 1 104
23 178 85 287 75 131 137 194 430 441 181 152 251 295 250 511 -1 152 -16 223
-117 560 -35 117 -61 217 -58 222 3 5 20 9 38 9 55 0 217 31 261 50 53 23 103
73 132 131 43 88 56 187 59 437 2 266 -1 258 91 292 108 40 254 21 330 -45 35
-30 35 -32 53 -170 41 -311 106 -484 206 -546 48 -29 168 -48 381 -59 188 -10
432 -1 548 20 76 14 206 56 266 86 64 32 122 101 144 170 15 49 17 82 12 253
-5 198 -27 398 -52 482 -42 146 -125 221 -290 265 -57 15 -108 19 -268 19
l-197 0 0 45 c0 120 -37 255 -82 300 -76 77 -210 5 -291 -157 -31 -60 -67
-184 -67 -229 0 -27 -6 -34 -41 -50 -65 -29 -159 -98 -195 -144 -34 -43 -67
-119 -79 -181 l-6 -35 -57 28 c-114 57 -270 58 -379 2 -61 -31 -70 -21 -49 54
33 118 16 442 -29 536 -38 79 -114 84 -188 12 -68 -66 -136 -230 -137 -330 l0
-29 -61 7 c-34 3 -93 6 -131 6 l-69 0 6 48 c14 97 56 282 84 368 155 475 486
821 963 1008 108 42 308 94 430 110 62 9 124 17 138 20 76 11 479 5 592 -10z
m-7029 -78 c18 -8 261 -243 569 -552 582 -584 560 -559 543 -651 -6 -33 -69
-101 -523 -557 -553 -554 -564 -564 -644 -551 -89 15 -151 110 -128 198 10 37
65 95 463 495 l452 452 -472 473 c-414 414 -472 477 -478 510 -25 132 98 235
218 183z m7169 -1405 c164 -57 201 -136 234 -502 37 -414 9 -486 -212 -558
-155 -50 -298 -64 -579 -57 -249 6 -398 23 -439 50 -95 62 -177 346 -180 621
-1 135 0 142 28 203 50 109 148 179 304 218 149 37 329 53 567 50 191 -2 216
-4 277 -25z m-2002 -174 c95 -34 118 -52 152 -114 52 -94 63 -159 62 -368 -1
-358 -44 -479 -187 -520 -146 -42 -612 -65 -727 -36 -153 38 -196 98 -226 316
-16 120 -31 487 -21 527 9 35 89 121 140 151 99 58 228 76 522 73 200 -2 214
-3 285 -29z m-1604 -443 c45 -33 67 -70 71 -121 5 -59 -25 -117 -77 -147 -35
-21 -47 -21 -980 -24 -520 -2 -964 0 -988 3 -57 8 -116 60 -130 115 -19 75 12
146 78 182 34 17 75 18 1017 16 974 -3 982 -3 1009 -24z m5329 -2140 c66 -7
173 -14 237 -14 103 0 146 5 247 26 24 5 24 5 18 -64 -15 -159 -89 -371 -180
-515 l-43 -68 -57 113 c-72 145 -160 261 -318 422 l-126 128 51 -7 c28 -3 105
-13 171 -21z m-812 -652 c53 -41 140 -115 193 -165 96 -91 224 -231 224 -245
0 -5 -30 -18 -67 -30 -79 -25 -305 -84 -308 -80 -1 2 -12 53 -24 113 -28 135
-70 268 -127 402 -24 57 -44 106 -44 109 0 9 43 -20 153 -104z m-1173 -560
c-9 -4 -271 61 -315 78 -29 11 -28 12 79 55 59 24 111 46 114 49 3 3 33 -36
67 -87 34 -50 59 -93 55 -95z"/>
</g>
</svg>
<span class="text-lg md:text-2xl font-light ml-2 lg:ml-4 font-mono tracking-tighter">Spectre.Console</span>
</a>
<div class="ml-auto">
<ul class="flex flex-row">
<li>
<button aria-label="Toggle Dark Mode" class="mr-4 dark:text-yellow-300 stroke-1 opacity-80" onclick="swapTheme()">
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z"/>
</svg>
</button>
</li>
<li>
<a class="flex flex-row items-center text-rose-700 dark:text-rose-500" href="https://github.com/sponsors/patriksvensson">
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 mr-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<title>Sponsor</title>
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z"/>
</svg>
<span class="hidden sm:block">Sponsor</span>
</a>
</li>
<li class="ml-4">
<a class="flex flex-row items-center text-gray-600 fill-slate-200 stroke-slate-800 fill-slate-900 dark:stroke-slate-500 dark:fill-slate-300 dark:text-slate-300" href="https://github.com/spectreconsole/spectre.console">
<svg role="img" class="h-6 w-6 mr-1" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<title>GitHub icon</title>
<path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/>
</svg>
<span class="hidden sm:block">GitHub</span>
</a>
</li>
</ul>
</div>
</nav>
</header>
<main class="container mx-auto pt-8 w-full">
<div class="flex flex-col-reverse lg:flex-row">
<nav class="flex-none font-light text-sm xl:text-base sm:mr-16 mt-8 pt-6 lg:mt-0 lg:pt-0 lg:pb-10 border-t border-gray-300 lg:border-t-0">
@{
var sidebar = Context.GetSidebar();
var root = sidebar.Node;
<div class="text-xl @(Document.IdEquals(root) ? "font-bold" : null)">
@if (sidebar.ShowLink)
{
@Html.DocumentLink(root)
}
else
{
@sidebar.Title;
}
</div>
@foreach (var sidebarItem in sidebar.Leafs)
{
var document = sidebarItem.Node;
if (string.IsNullOrWhiteSpace(sidebarItem.Title))
{
continue;
}
var documentChildren = sidebarItem.Leafs;
<div class="text-teal-800 font-medium dark:text-teal-400 mt-4">
@if (sidebarItem.ShowLink)
{
@Html.DocumentLink(document)
}
else
{
@sidebarItem.Title;
}
</div>
@if (documentChildren.Any())
{
<div class="ml-2 flex flex-row flex-wrap lg:flex-col border-separate">
@foreach (var childItem in documentChildren)
{
var child = childItem.Node;
<div class="mt-2 mr-4 @(Document.IdEquals(child) ? "font-bold" : null)">
@Html.DocumentLink(child)
</div>
}
</div>
}
}
}
</nav>
<article class="flex-1 min-w-0">
<header class="text-slate-900 dark:text-slate-50 mb-4">
@RenderSection("header", required: false)
@if (!IsSectionDefined("header"))
{
<h1 class="text-4xl font-extrabold">@(Document.GetString(Keys.Title) ?? Document.GetTitle())</h1>
}
@RenderSection("subheading", required: false)
</header>
<div class="prose prose-slate dark:prose-invert max-w-full font-light lg:leading-loose">
@RenderBody()
@{
var referenceLinks = Model.GetList<string>(Constants.ApiReference);
if (referenceLinks != null)
{
<h3>References</h3>
<ul>
@foreach (var link in referenceLinks)
{
if (Context.TryGetXrefDocument(link, out var refDoc, out string error))
{
<li>
@{
var kind = refDoc.GetString(CodeAnalysisKeys.SpecificKind);
var prefix = string.Empty;
var containingType = @refDoc.GetDocument(CodeAnalysisKeys.ContainingType);
if (containingType != null)
{
prefix = containingType.GetString(CodeAnalysisKeys.DisplayName) + ".";
}
}
@if (!string.IsNullOrWhiteSpace(prefix)){ <span class="text-slate-600 dark:text-slate-400">@prefix</span>}@Html.DocumentLink(refDoc, refDoc.GetString(CodeAnalysisKeys.DisplayName) ?? refDoc.GetTitle()) <span class="ml-4 uppercase text-xs text-slate-700 dark:text-slate-400">@kind</span>
</li>
}
else
{
Context.LogWarning(Model, $"Error finding xref for {link} - {error}");
}
}
</ul>
}
}
</div>
</article>
</div>
</main>
<footer class="py-4 md:py-8 mt-8 bg-gray-100 dark:bg-slate-800 text-sm border-t border-gray-200 dark:border-slate-700">
<div class="container">
<div class="flex flex-row">
<span>© @DateTime.Today.Year Patrik Svensson, Phil Scott</span>
<span class="ml-auto">@VersionUtilities.GetVersion()</span>
</div>
</div>
</footer>
<script>
// adapted from https://www.w3schools.com/howto/howto_js_filter_table.asp // adapted from https://www.w3schools.com/howto/howto_js_filter_table.asp
function search(input, searchTarget, columnIndex) { function search(input, searchTarget, columnIndex) {
// Declare variables // Declare variables
@ -154,13 +282,25 @@
} }
} }
</script> </script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.23.0/prism.min.js" integrity="sha512-YBk7HhgDZvBxmtOfUdvX0z8IH2d10Hp3aEygaMNhtF8fSOvBZ16D/1bXZTJV6ndk/L/DlXxYStP8jrF77v2MIg==" crossorigin="anonymous"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.23.0/prism.min.js" integrity="sha512-YBk7HhgDZvBxmtOfUdvX0z8IH2d10Hp3aEygaMNhtF8fSOvBZ16D/1bXZTJV6ndk/L/DlXxYStP8jrF77v2MIg==" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.23.0/plugins/autoloader/prism-autoloader.min.js" integrity="sha512-zc7WDnCM3aom2EziyDIRAtQg1mVXLdILE09Bo+aE1xk0AM2c2cVLfSW9NrxE5tKTX44WBY0Z2HClZ05ur9vB6A==" crossorigin="anonymous"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.23.0/plugins/autoloader/prism-autoloader.min.js" integrity="sha512-zc7WDnCM3aom2EziyDIRAtQg1mVXLdILE09Bo+aE1xk0AM2c2cVLfSW9NrxE5tKTX44WBY0Z2HClZ05ur9vB6A==" crossorigin="anonymous"></script>
<script src="@Context.GetLink("/assets/asciinema-player.js")"></script> <script src="@Context.GetLink("/assets/asciinema-player.js")"></script>
<script> <script>
document.querySelectorAll('asciinema-player').forEach(cast => { document.querySelectorAll('asciinema-player').forEach(cast => {
AsciinemaPlayer.create(cast.attributes['src'].value, cast, {autoplay: true, fit: 'none', fontSize: 'inherit'}); AsciinemaPlayer.create(cast.attributes['src'].value, cast, {autoplay: true, fit: 'none', fontSize: 'inherit'});
}); });
</script> </script>
</body>
<script>
function swapTheme(){
if (document.documentElement.classList.contains('dark')) {
document.documentElement.classList.remove('dark');
localStorage.theme = 'light';
} else {
document.documentElement.classList.add('dark');
localStorage.theme = 'dark';
}
}
</script>
</body>
</html> </html>

View File

@ -1,7 +1,7 @@
@inherits StatiqRazorPage<IDocument> @inherits StatiqRazorPage<IDocument>
@{ @{
Layout = @"/_layout.cshtml"; Layout = @"../../_layout.cshtml";
} }

View File

@ -0,0 +1,19 @@
@using Statiq.CodeAnalysis
@using Docs.Pipelines
@using Docs.Extensions
@foreach (IGrouping<string, IDocument> typeGroup
in Outputs.FromPipeline(nameof(Api))
.Where(x => x.GetBool(CodeAnalysisKeys.IsResult)
&& x.GetString(CodeAnalysisKeys.Kind) == "NamedType"
&& Document.IdEquals(x.GetDocument(CodeAnalysisKeys.ContainingAssembly)))
.GroupBy(x => x.GetString(CodeAnalysisKeys.SpecificKind))
.OrderBy(x => x.Key))
{
<h2>@typeGroup.Key</h2>
@foreach (var type in typeGroup)
{
<ul>
<li>@Context.GetTypeLink(type)</li>
</ul>
}
}

View File

@ -0,0 +1,4 @@
@await Html.PartialAsync("../Sections/_Syntax.cshtml")
@await Html.PartialAsync("../Sections/_Examples.cshtml")
@await Html.PartialAsync("../Sections/_Remarks.cshtml")
@await Html.PartialAsync("../Sections/_SeeAlso.cshtml")

View File

@ -0,0 +1,9 @@
@await Html.PartialAsync("../Sections/_Summary.cshtml")
@await Html.PartialAsync("../Sections/_Syntax.cshtml")
@await Html.PartialAsync("../Sections/_SymbolInfo.cshtml")
@await Html.PartialAsync("../Sections/_Examples.cshtml")
@await Html.PartialAsync("../Sections/_Remarks.cshtml")
@await Html.PartialAsync("../Sections/_Attributes.cshtml")
@await Html.PartialAsync("../Sections/_Parameters.cshtml")
@await Html.PartialAsync("../Sections/_Value.cshtml")
@await Html.PartialAsync("../Sections/_SeeAlso.cshtml")

View File

@ -0,0 +1,10 @@
@await Html.PartialAsync("../Sections/_Summary.cshtml")
@await Html.PartialAsync("../Sections/_Syntax.cshtml")
@await Html.PartialAsync("../Sections/_SymbolInfo.cshtml")
@await Html.PartialAsync("../Sections/_Examples.cshtml")
@await Html.PartialAsync("../Sections/_Remarks.cshtml")
@await Html.PartialAsync("../Sections/_Attributes.cshtml")
@await Html.PartialAsync("../Sections/_TypeParameters.cshtml")
@await Html.PartialAsync("../Sections/_Parameters.cshtml")
@await Html.PartialAsync("../Sections/_ReturnValue.cshtml")
@await Html.PartialAsync("../Sections/_SeeAlso.cshtml")

View File

@ -0,0 +1,15 @@
@await Html.PartialAsync("../Sections/_Summary.cshtml")
@await Html.PartialAsync("../Sections/_Syntax.cshtml")
@await Html.PartialAsync("../Sections/_SymbolInfo.cshtml")
@await Html.PartialAsync("../Sections/_Examples.cshtml")
@await Html.PartialAsync("../Sections/_Remarks.cshtml")
@await Html.PartialAsync("../Sections/_Attributes.cshtml")
@await Html.PartialAsync("../Sections/_TypeParameters.cshtml")
@await Html.PartialAsync("../Sections/_Constructors.cshtml")
@await Html.PartialAsync("../Sections/_Events.cshtml")
@await Html.PartialAsync("../Sections/_Fields.cshtml")
@await Html.PartialAsync("../Sections/_Properties.cshtml")
@await Html.PartialAsync("../Sections/_Methods.cshtml")
@await Html.PartialAsync("../Sections/_ExtensionMethods.cshtml")
@await Html.PartialAsync("../Sections/_Operators.cshtml")
@await Html.PartialAsync("../Sections/_SeeAlso.cshtml")

View File

@ -0,0 +1,25 @@
@using Statiq.CodeAnalysis
@using Docs.Extensions
@await Html.PartialAsync("../Sections/_Summary.cshtml")
@{
foreach (IGrouping<string, IDocument> typeGroup
in Document.GetDocuments(CodeAnalysisKeys.MemberTypes)
.Where(x => x.GetBool(CodeAnalysisKeys.IsResult) && x.GetString(CodeAnalysisKeys.Kind) == "NamedType")
.GroupBy(x => x.GetString(CodeAnalysisKeys.SpecificKind)))
{
<h3>@typeGroup.Key</h3>
<div class="doc-summary short-term">
<div>
<dl>
@foreach (var type in typeGroup.OrderBy(x => x.GetString(CodeAnalysisKeys.DisplayName)).ToList())
{
<div>
<dt>@Context.GetTypeLink(type)</dt>
<dd>@Html.Raw(type.GetString(CodeAnalysisKeys.Summary))</dd>
</div>
}
</dl>
</div>
</div>
}
}

View File

@ -0,0 +1,9 @@
@await Html.PartialAsync("../Sections/_Summary.cshtml")
@await Html.PartialAsync("../Sections/_Syntax.cshtml")
@await Html.PartialAsync("../Sections/_SymbolInfo.cshtml")
@await Html.PartialAsync("../Sections/_Examples.cshtml")
@await Html.PartialAsync("../Sections/_Remarks.cshtml")
@await Html.PartialAsync("../Sections/_Attributes.cshtml")
@await Html.PartialAsync("../Sections/_Parameters.cshtml")
@await Html.PartialAsync("../Sections/_Value.cshtml")
@await Html.PartialAsync("../Sections/_SeeAlso.cshtml")

View File

@ -0,0 +1,26 @@
@using Statiq.CodeAnalysis
@using Docs.Extensions
@{
IReadOnlyList<IDocument> attributes = Document.GetDocumentList(CodeAnalysisKeys.Attributes);
if (attributes?.Count > 0)
{
<h3>Attributes</h3>
<div class="doc-summary">
<div>
<dl>
@foreach (var attribute in attributes)
{
var type = attribute.GetDocument(CodeAnalysisKeys.Type);
<div>
<dt>
@Context.GetTypeLink(type)
</dt>
<dd>@Html.Raw(type.GetString(CodeAnalysisKeys.Summary))</dd>
</div>
}
</dl>
</div>
</div>
}
}

View File

@ -0,0 +1,22 @@
@using Statiq.CodeAnalysis
@using Microsoft.AspNetCore.Html
@if(Document.GetBool(CodeAnalysisKeys.HasConstantValue))
{
var constantValue = Document.Get(CodeAnalysisKeys.ConstantValue);
<h3>Constant Value</h3>
<div class="doc-summary">
<div>
<dl>
<div>
<dt>
@(new HtmlString(constantValue?.ToString() ?? "null"))
</dt>
<dd>@(new HtmlString(constantValue?.GetType().Name ?? string.Empty))</dd>
</div>
</dl>
</div>
</div>
}

View File

@ -0,0 +1,6 @@
namespace Docs.input.api.Sections;
public class _ConstantValue_cshtml
{
}

View File

@ -0,0 +1,29 @@
@using Statiq.CodeAnalysis
@using Docs.Extensions
@{
var constructors = Document.GetDocumentList(CodeAnalysisKeys.Constructors)
?.Where(x => x.GetBool(CodeAnalysisKeys.IsResult))
.OrderBy(x => x.GetString(CodeAnalysisKeys.DisplayName))
.ToList();
if (constructors?.Count > 0)
{
<h3>Constructors</h3>
<div class="doc-summary">
<div>
<dl>
@foreach (var constructor in constructors)
{
<div>
<dt>
@constructor.GetModifiers() @Context.GetTypeLink(constructor, false)
</dt>
<dd>@Html.Raw(constructor.GetString(CodeAnalysisKeys.Summary))</dd>
</div>
}
</dl>
</div>
</div>
}
}

View File

View File

@ -0,0 +1,9 @@
@using Statiq.CodeAnalysis
@{
var examples = Document.GetString(CodeAnalysisKeys.Example);
if (!examples.IsNullOrWhiteSpace())
{
<h3>Examples</h3>
<div>@Html.Raw(examples)</div>
}
}

View File

@ -0,0 +1,40 @@
@using Statiq.CodeAnalysis
@using Docs.Extensions
@using Microsoft.CodeAnalysis
@{
var modelSymbol = Document.Get<ITypeSymbol>(CodeAnalysisKeys.Symbol);
IReadOnlyList<IDocument> methods = Document.GetDocumentList(CodeAnalysisKeys.ExtensionMethods)
?.Where(x => x.GetBool(CodeAnalysisKeys.IsResult))
.OrderBy(x => x.GetString(CodeAnalysisKeys.DisplayName))
.ToList();
if (methods?.Count > 0)
{
<h3>Extension Methods</h3>
<div class="doc-summary">
<div>
<dl>
@foreach (var method in methods)
{
ISymbol reducedSymbol = method.Get<IMethodSymbol>(CodeAnalysisKeys.Symbol)?.ReduceExtensionMethod(modelSymbol);
string reducedName = reducedSymbol?.ToDisplayString(new SymbolDisplayFormat(
typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypes,
genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters,
parameterOptions: SymbolDisplayParameterOptions.IncludeType,
memberOptions: SymbolDisplayMemberOptions.IncludeParameters,
miscellaneousOptions: SymbolDisplayMiscellaneousOptions.UseSpecialTypes));
<div>
<dt>
@method.GetModifiers(skipStatic:true) @method.GetDocument(CodeAnalysisKeys.ReturnType).GetString(CodeAnalysisKeys.DisplayName) @Context.GetTypeLink(method,reducedName, false)
</dt>
<dd>@Html.Raw(method.GetString(CodeAnalysisKeys.Summary))</dd>
</div>
}
</dl>
</div>
</div>
}
}

View File

@ -0,0 +1,59 @@
@using Statiq.CodeAnalysis
@using Microsoft.AspNetCore.Html
@using Docs.Extensions
@{
var isEnum = Document.GetString(CodeAnalysisKeys.SpecificKind) == "Enum";
IReadOnlyList<IDocument> fields;
if (isEnum)
{
fields = Document.GetDocumentList(CodeAnalysisKeys.Members)?.Where(x => x.GetBool(CodeAnalysisKeys.IsResult) && x.GetString(CodeAnalysisKeys.Kind) == "Field")
.OrderBy(x => x.Get(CodeAnalysisKeys.ConstantValue) as int? ?? 0)
.ToList();
}
else
{
fields = Document.GetDocumentList(CodeAnalysisKeys.Members)?.Where(x => x.GetBool(CodeAnalysisKeys.IsResult) && x.GetString(CodeAnalysisKeys.Kind) == "Field")
.OrderBy(x => x.GetString(CodeAnalysisKeys.DisplayName))
.ToList();
}
if (fields?.Count > 0)
{
<h3>Fields</h3>
<div class="doc-summary">
<div>
<dl>
@foreach (var field in fields)
{
<div>
<dt>
<div class="flex flex-row">
<div class="w-4/5">
@if (isEnum)
{
@Context.GetTypeLink(field, false)
}
else
{
@field.GetModifiers() @Context.GetTypeLink(field.GetDocument(CodeAnalysisKeys.Type))
@Context.GetTypeLink(field, false)
}
</div>
<div>
@(field.GetBool(CodeAnalysisKeys.HasConstantValue) ? new HtmlString(field.Get(CodeAnalysisKeys.ConstantValue)?.ToString() ?? "null") : new HtmlString(string.Empty))
</div>
</div>
</dt>
<dd>
@Html.Raw(field.GetString(CodeAnalysisKeys.Summary))
</dd>
</div>
}
</dl>
</div>
</div>
}
}

View File

@ -0,0 +1,30 @@
@using Statiq.CodeAnalysis
@using Docs.Extensions
@{
IReadOnlyList<IDocument> methods = Model.GetDocumentList(CodeAnalysisKeys.Members)
?.Where(x => x.GetBool(CodeAnalysisKeys.IsResult) && x.GetString(CodeAnalysisKeys.Kind) == "Method")
.OrderBy(x => x.GetString(CodeAnalysisKeys.DisplayName))
.ToList();
if (methods?.Count > 0)
{
<h3>Methods</h3>
<div class="doc-summary">
<div>
<dl>
@foreach (var method in methods)
{
<div>
<dt>
@method.GetModifiers() @method.GetDocument(CodeAnalysisKeys.ReturnType).GetString(CodeAnalysisKeys.DisplayName) @Context.GetTypeLink(method, false)
</dt>
<dd>@Html.Raw(method.GetString(CodeAnalysisKeys.Summary))</dd>
</div>
}
</dl>
</div>
</div>
}
}

View File

@ -0,0 +1,25 @@
@using Statiq.CodeAnalysis
@using Docs.Extensions
@{
var parameters = Model.GetDocumentList(CodeAnalysisKeys.Parameters);
var paramComments = Model.GetList<ReferenceComment>(CodeAnalysisKeys.Params);
if (parameters?.Count > 0)
{
<h3>Parameters</h3>
<div class="doc-summary">
<div>
<dl>
@foreach (var parameter in parameters)
{
<div>
<dt>
@Context.GetTypeLink(parameter.GetDocument(CodeAnalysisKeys.Type)) <span class="identifier">@parameter.GetString(CodeAnalysisKeys.Name)</span>
</dt>
<dd>@Html.Raw(paramComments?.Where(x => x.Name.Equals(parameter.GetString(CodeAnalysisKeys.Name))).Select(x => x.Html).FirstOrDefault()) </dd>
</div>
}
</dl>
</div>
</div>
}
}

View File

@ -0,0 +1,30 @@
@using Statiq.CodeAnalysis
@using Docs.Extensions
@{
IReadOnlyList<IDocument> properties = Model.GetDocumentList(CodeAnalysisKeys.Members)
?.Where(x => x.GetBool(CodeAnalysisKeys.IsResult) && x.GetString(CodeAnalysisKeys.Kind) == "Property")
.OrderBy(x => x.GetString(CodeAnalysisKeys.DisplayName))
.ToList();
if (properties?.Count > 0)
{
<h3>Properties</h3>
<div class="doc-summary">
<div>
<dl>
@foreach (var property in properties)
{
<div>
<dt>
@property.GetModifiers() @property.GetDocument(CodeAnalysisKeys.Type).GetString(CodeAnalysisKeys.DisplayName) @Context.GetTypeLink(property, false)
</dt>
<dd>@Html.Raw(property.GetString(CodeAnalysisKeys.Summary))</dd>
</div>
}
</dl>
</div>
</div>
}
}

View File

@ -0,0 +1,9 @@
@using Statiq.CodeAnalysis
@{
var remarks = Document.GetString(CodeAnalysisKeys.Remarks);
if (!remarks.IsNullOrWhiteSpace())
{
<h3>Remarks</h3>
<div>@Html.Raw(remarks)</div>
}
}

View File

@ -0,0 +1,23 @@
@using Statiq.CodeAnalysis
@using Docs.Extensions
@{
var returnType = Model.GetDocument(CodeAnalysisKeys.ReturnType);
var returns = Model.GetString(CodeAnalysisKeys.Returns);
if ((returnType != null && returnType.GetString(CodeAnalysisKeys.DisplayName) != "void") || !string.IsNullOrWhiteSpace(returns))
{
<h3>Returns</h3>
<div class="doc-summary">
<div>
<dl>
<div>
<dt>
@Context.GetTypeLink(returnType, false)
</dt>
<dd></dd>
</div>
</dl>
</div>
</div>
}
}

View File

@ -0,0 +1,14 @@
@using Statiq.CodeAnalysis
@{
var seeAlso = Document.GetList<string>(CodeAnalysisKeys.SeeAlso);
if (seeAlso?.Count > 0)
{
<h3 id="SeeAlso">See Also</h3>
<ul>
@foreach (string seeAlsoComment in seeAlso)
{
<li>@Html.Raw(seeAlsoComment)</li>
}
</ul>
}
}

View File

@ -0,0 +1,7 @@
@{
var summary = Document.GetString("Summary");
if (!summary.IsNullOrWhiteSpace())
{
<div class="my-4 md:my-8">@Html.Raw(summary)</div>
}
}

View File

@ -0,0 +1,131 @@
@using Statiq.CodeAnalysis
@using Docs.Extensions
@{
var containingAssembly = Document.GetDocument(CodeAnalysisKeys.ContainingAssembly);
var containingNamespace = Document.GetDocument(CodeAnalysisKeys.ContainingNamespace);
var containingType = Document.GetDocument(CodeAnalysisKeys.ContainingType);
var type = Document.GetDocument(CodeAnalysisKeys.Type);
var overridden = Document.GetDocument(CodeAnalysisKeys.Overridden);
IReadOnlyList<IDocument> allInterfaces = Document.GetDocumentList(CodeAnalysisKeys.AllInterfaces);
IReadOnlyList<IDocument> baseTypes = Document.GetDocumentList(CodeAnalysisKeys.BaseTypes)?
.Where(i => !i.GetString(CodeAnalysisKeys.QualifiedName).Equals("System.Object"))
.Reverse()
.ToList();
IReadOnlyList<IDocument> derivedTypes = Document.GetDocumentList(CodeAnalysisKeys.DerivedTypes);
IReadOnlyList<IDocument> implementingTypes = Document.GetDocumentList(CodeAnalysisKeys.ImplementingTypes);
if (containingAssembly is object
|| containingNamespace is object
|| allInterfaces?.Count > 0
|| baseTypes?.Count > 0
|| derivedTypes?.Count > 0
|| implementingTypes?.Count > 0)
{
<div class="doc-summary tiny-term">
<div>
<dl>
@if (containingAssembly != null)
{
<div>
<dt>Assembly</dt>
<dd>containingAssembly</dd>
</div>
}
@if (containingNamespace != null)
{
<div>
<dt>Namespace</dt>
<dd>@Context.GetTypeLink(containingNamespace)</dd>
</div>
}
@if (containingType != null)
{
<div>
<dt>Containing Type</dt>
<dd>@Context.GetTypeLink(containingType)</dd>
</div>
}
@if (overridden != null)
{
<div>
<dt>Overridden</dt>
<dd>@Context.GetTypeLink(overridden)</dd>
</div>
}
@if (allInterfaces?.Count > 0)
{
<div>
<dt>Interfaces</dt>
<dd>
<ul class="list-unstyled">
@foreach (var interfaceDocument in allInterfaces)
{
<li>@Context.GetTypeLink(interfaceDocument)</li>
}
</ul>
</dd>
</div>
}
@if (baseTypes?.Count > 0)
{
<div>
<dt>Base Types</dt>
<dd>
<ul class="list-unstyled">
@foreach (var baseType in baseTypes)
{
<li>@Context.GetTypeLink(baseType)</li>
}
</ul>
</dd>
</div>
}
@if (derivedTypes?.Count > 0)
{
<div>
<dt>Derived Types</dt>
<dd>
<ul class="list-unstyled">
@foreach (var derivedType in derivedTypes)
{
<li>@Context.GetTypeLink(derivedType)</li>
}
</ul>
</dd>
</div>
}
@if (implementingTypes?.Count > 0)
{
<div>
<dt>Implementing Types</dt>
<dd>
<ul class="list-unstyled">
@foreach (var implementingType in implementingTypes)
{
<li>@Context.GetTypeLink(implementingType)</li>
}
</ul>
</dd>
</div>
}
@if (type != null)
{
<div>
<dt>@Document.GetString(CodeAnalysisKeys.Kind) Type</dt>
<dd>@Context.GetTypeLink(type)</dd>
</div>
}
</dl>
</div>
</div>
}
}

View File

@ -0,0 +1,8 @@
@using Statiq.CodeAnalysis
@{
string syntax = Document.GetString(CodeAnalysisKeys.Syntax);
if (!syntax.IsNullOrWhiteSpace())
{
<pre class="language-csharp"><code class="language-csharp">@syntax</code></pre>
}
}

View File

@ -0,0 +1,26 @@
@using Statiq.CodeAnalysis
@{
var typeParameters = Model.GetDocumentList(CodeAnalysisKeys.TypeParameters);
var typeParams = Model.GetList<ReferenceComment>(CodeAnalysisKeys.TypeParams);
if (typeParameters?.Count > 0)
{
<h3>Parameters</h3>
<div class="doc-summary">
<div>
<dl>
@foreach (var typeParam in typeParameters)
{
<div>
<dt>
<code>@typeParam.GetString(CodeAnalysisKeys.Name)</code>
</dt>
<dd>@Html.Raw(typeParams?.Where(x => x.Name.Equals(typeParam.GetString(CodeAnalysisKeys.Name))).Select(x => x.Html).FirstOrDefault()) </dd>
</div>
}
</dl>
</div>
</div>
}
}

View File

@ -0,0 +1,12 @@
@using Statiq.CodeAnalysis
@using Docs.Extensions
@{
IDocument type = Document.GetDocument(CodeAnalysisKeys.Type);
string value = Document.GetString(CodeAnalysisKeys.Value);
}
@if (type is object && !string.IsNullOrWhiteSpace(value))
{
<p>@Context.GetTypeLink(type)</p>
<p>@Html.Raw(value)</p>
}

View File

@ -0,0 +1,48 @@
@using Statiq.CodeAnalysis
@using Docs.Extensions
@inherits StatiqRazorPage<IDocument>
@{
Layout = @"../_layout.cshtml";
}
@section header{
<h1 class="text-4xl align-baseline font-extrabold">
@Document.GetString(CodeAnalysisKeys.DisplayName) <span class="text-2xl text-uppercase text-sky-600 dark:text-sky-400">@Document.GetString(CodeAnalysisKeys.SpecificKind)</span>
</h1>
<nav class="flex mt-2" aria-label="Breadcrumb">
<ol class="flex flex-col sm:flex-row sm:items-center space-x-2 lg:space-x-3">
@{
var isFirst = true;
}
@foreach (var parent in Context.GetExecutionCache("sidebar", ctx => ctx.OutputPages).GetAncestorsOf(Document, Document.IdEquals(Model)).Reverse().Skip(1))
{
<li>
<div class="flex items-center">
@if (isFirst)
{
isFirst = false;
}
else
{
<svg class="flex-shrink-0 h-5 w-5 mr-2 lg:mr-3 text-slate-400 dark:text-slate-500" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd"/>
</svg>
}
<span class="font-light text-sm text-slate-600 dark:text-slate-300" >@Html.DocumentLink(parent, parent.GetString(WebKeys.Title, parent.GetTitle()))</span>
</div>
</li>
}
</ol>
</nav>
}
@await Html.PartialAsync($"Kind/_{Model.GetString(CodeAnalysisKeys.Kind)}.cshtml", Model)
@{
IgnoreBody();
}

View File

@ -0,0 +1,11 @@
Title: API Reference
Order: 10000
---
<p>The Spectre.Console API reference is organized by namespace. Each namespace has one or more classes for working with Console applications.</p>
<ul>
@foreach (var child in OutputPages.GetChildrenOf(Document).OrderBy(i => i.GetTitle()))
{
<li>@Html.DocumentLink(child)</li>
}
</ul>

View File

@ -1,7 +1,6 @@
Title: Appendix Title: Appendix
Order: 100 Order: 100
--- ---
<h1>Sections</h1> <h1>Sections</h1>
<ul> <ul>

View File

@ -1,3 +1,3 @@
{"version": 2, "width": 122, "height": 12, "title": "custom-colors-exception (plain)", "env": {"TERM": "Spectre.Console"}} {"version": 2, "width": 102, "height": 12, "title": "custom-colors-exception (plain)", "env": {"TERM": "Spectre.Console"}}
[0, "o", "\u001B[37mInvalidOperationException\u001B[0m: \u001B[37mWhaaat?\u001B[0m\r\n \u001B[37mInvalidCredentialException\u001B[0m: \u001B[37mThe credentials are invalid.\u001B[0m \r\n \u001B[37mat\u001B[0m \u001B[31mvoid\u001B[0m \u001B[31mCheckCredentials\u001B[0m\u001B[37m(\u001B[0m\u001B[31mint\u001B[0m \u001B[37mqux\u001B[0m, \u001B[31mstring[,]\u001B[0m \u001B[37mcorgi)\u001B[0m \u001B[37min\u001B[0m \u001B]8;id=1042481981;file://phil-adler/R:/phil-scott/spectre.console/resources/scripts/Generator/Commands/AsciiCast/Samples/Exceptions.cs\u001B\\\u001B[31mExceptions.cs\u001B[0m\u001B]8;;\u001B\\\u001B[37m:\u001B[0m\u001B[37m75\u001B[0m \r\n \u001B[37mat\u001B[0m \u001B[31mvoid\u001B[0m \u001B[31mDoMagic\u001B[0m\u001B[37m(\u001B[0m\u001B[31mint\u001B[0m \u001B[37mfoo\u001B[0m, \u001B[31mstring[,]\u001B[0m \u001B[37mbar)\u001B[0m \u001B[37min\u001B[0m \u001B]8;id=23697541;file://phil-adler/R:/phil-scott/spectre.console/resources/scripts/Generator/Commands/AsciiCast/Samples/Exceptions.cs\u001B\\\u001B[31mExceptions.cs\u001B[0m\u001B]8;;\u001B\\\u001B[37m:\u001B[0m\u001B[37m65\u001B[0m \r\n \u001B[37mat\u001B[0m \u001B[31mvoid\u001B[0m \u001B[31mDoMagic\u001B[0m\u001B[37m(\u001B[0m\u001B[31mint\u001B[0m \u001B[37mfoo\u001B[0m, \u001B[31mstring[,]\u001B[0m \u001B[37mbar)\u001B[0m \u001B[37min\u001B[0m \u001B]8;id=859179850;file://phil-adler/R:/phil-scott/spectre.console/resources/scripts/Generator/Commands/AsciiCast/Samples/Exceptions.cs\u001B\\\u001B[31mExceptions.cs\u001B[0m\u001B]8;;\u001B\\\u001B[37m:\u001B[0m\u001B[37m69\u001B[0m \r\n \u001B[37mat\u001B[0m \u001B[31mctor\u001B[0m\u001B[37m()\u001B[0m \u001B[37min\u001B[0m \u001B]8;id=835958343;file://phil-adler/R:/phil-scott/spectre.console/resources/scripts/Generator/Commands/AsciiCast/Samples/Exceptions.cs\u001B\\\u001B[31mExceptions.cs\u001B[0m\u001B]8;;\u001B\\\u001B[37m:\u001B[0m\u001B[37m19\u001B[0m \r\n"] [0, "o", "\u001B[37mInvalidOperationException\u001B[0m: \u001B[37mWhaaat?\u001B[0m\r\n \u001B[37mInvalidCredentialException\u001B[0m: \u001B[37mThe credentials are invalid.\u001B[0m \r\n \u001B[37mat\u001B[0m \u001B[31mvoid\u001B[0m \u001B[31mCheckCredentials\u001B[0m\u001B[37m(\u001B[0m\u001B[31mint\u001B[0m \u001B[37mqux\u001B[0m, \u001B[31mstring[,]\u001B[0m \u001B[37mcorgi)\u001B[0m \u001B[37min\u001B[0m \u001B]8;id=496927177;file://phil-adler/R:/phil-scott/spectre.console/resources/scripts/Generator/Commands/AsciiCast/Samples/Exceptions.cs\u001B\\\u001B[31mExceptions.cs\u001B[0m\u001B]8;;\u001B\\\u001B[37m:\u001B[0m\u001B[37m76\u001B[0m \r\n \u001B[37mat\u001B[0m \u001B[31mvoid\u001B[0m \u001B[31mDoMagic\u001B[0m\u001B[37m(\u001B[0m\u001B[31mint\u001B[0m \u001B[37mfoo\u001B[0m, \u001B[31mstring[,]\u001B[0m \u001B[37mbar)\u001B[0m \u001B[37min\u001B[0m \u001B]8;id=260293059;file://phil-adler/R:/phil-scott/spectre.console/resources/scripts/Generator/Commands/AsciiCast/Samples/Exceptions.cs\u001B\\\u001B[31mExceptions.cs\u001B[0m\u001B]8;;\u001B\\\u001B[37m:\u001B[0m\u001B[37m66\u001B[0m \r\n \u001B[37mat\u001B[0m \u001B[31mvoid\u001B[0m \u001B[31mDoMagic\u001B[0m\u001B[37m(\u001B[0m\u001B[31mint\u001B[0m \u001B[37mfoo\u001B[0m, \u001B[31mstring[,]\u001B[0m \u001B[37mbar)\u001B[0m \u001B[37min\u001B[0m \u001B]8;id=311730381;file://phil-adler/R:/phil-scott/spectre.console/resources/scripts/Generator/Commands/AsciiCast/Samples/Exceptions.cs\u001B\\\u001B[31mExceptions.cs\u001B[0m\u001B]8;;\u001B\\\u001B[37m:\u001B[0m\u001B[37m70\u001B[0m \r\n \u001B[37mat\u001B[0m \u001B[31mctor\u001B[0m\u001B[37m()\u001B[0m \u001B[37min\u001B[0m \u001B]8;id=661850274;file://phil-adler/R:/phil-scott/spectre.console/resources/scripts/Generator/Commands/AsciiCast/Samples/Exceptions.cs\u001B\\\u001B[31mExceptions.cs\u001B[0m\u001B]8;;\u001B\\\u001B[37m:\u001B[0m\u001B[37m20\u001B[0m \r\n"]

View File

@ -1,3 +1,3 @@
{"version": 2, "width": 122, "height": 12, "title": "custom-colors-exception (rich)", "env": {"TERM": "Spectre.Console"}} {"version": 2, "width": 102, "height": 12, "title": "custom-colors-exception (rich)", "env": {"TERM": "Spectre.Console"}}
[0, "o", "\u001B[38;5;8mInvalidOperationException\u001B[0m: \u001B[38;5;15mWhaaat?\u001B[0m\r\n \u001B[38;5;8mInvalidCredentialException\u001B[0m: \u001B[38;5;15mThe credentials are invalid.\u001B[0m \r\n \u001B[38;5;8mat\u001B[0m \u001B[38;5;9mvoid\u001B[0m \u001B[38;5;9mCheckCredentials\u001B[0m\u001B[38;5;230m(\u001B[0m\u001B[38;5;9mint\u001B[0m \u001B[38;5;230mqux\u001B[0m, \u001B[38;5;9mstring[,]\u001B[0m \u001B[38;5;230mcorgi)\u001B[0m \u001B[38;5;8min\u001B[0m \u001B]8;id=794652377;file://phil-adler/R:/phil-scott/spectre.console/resources/scripts/Generator/Commands/AsciiCast/Samples/Exceptions.cs\u001B\\\u001B[38;5;9mExceptions.cs\u001B[0m\u001B]8;;\u001B\\\u001B[38;5;8m:\u001B[0m\u001B[38;5;230m75\u001B[0m \r\n \u001B[38;5;8mat\u001B[0m \u001B[38;5;9mvoid\u001B[0m \u001B[38;5;9mDoMagic\u001B[0m\u001B[38;5;230m(\u001B[0m\u001B[38;5;9mint\u001B[0m \u001B[38;5;230mfoo\u001B[0m, \u001B[38;5;9mstring[,]\u001B[0m \u001B[38;5;230mbar)\u001B[0m \u001B[38;5;8min\u001B[0m \u001B]8;id=1790687506;file://phil-adler/R:/phil-scott/spectre.console/resources/scripts/Generator/Commands/AsciiCast/Samples/Exceptions.cs\u001B\\\u001B[38;5;9mExceptions.cs\u001B[0m\u001B]8;;\u001B\\\u001B[38;5;8m:\u001B[0m\u001B[38;5;230m65\u001B[0m \r\n \u001B[38;5;8mat\u001B[0m \u001B[38;5;9mvoid\u001B[0m \u001B[38;5;9mDoMagic\u001B[0m\u001B[38;5;230m(\u001B[0m\u001B[38;5;9mint\u001B[0m \u001B[38;5;230mfoo\u001B[0m, \u001B[38;5;9mstring[,]\u001B[0m \u001B[38;5;230mbar)\u001B[0m \u001B[38;5;8min\u001B[0m \u001B]8;id=1362560761;file://phil-adler/R:/phil-scott/spectre.console/resources/scripts/Generator/Commands/AsciiCast/Samples/Exceptions.cs\u001B\\\u001B[38;5;9mExceptions.cs\u001B[0m\u001B]8;;\u001B\\\u001B[38;5;8m:\u001B[0m\u001B[38;5;230m69\u001B[0m \r\n \u001B[38;5;8mat\u001B[0m \u001B[38;5;9mctor\u001B[0m\u001B[38;5;230m()\u001B[0m \u001B[38;5;8min\u001B[0m \u001B]8;id=618029590;file://phil-adler/R:/phil-scott/spectre.console/resources/scripts/Generator/Commands/AsciiCast/Samples/Exceptions.cs\u001B\\\u001B[38;5;9mExceptions.cs\u001B[0m\u001B]8;;\u001B\\\u001B[38;5;8m:\u001B[0m\u001B[38;5;230m19\u001B[0m \r\n"] [0, "o", "\u001B[38;5;8mInvalidOperationException\u001B[0m: \u001B[38;5;15mWhaaat?\u001B[0m\r\n \u001B[38;5;8mInvalidCredentialException\u001B[0m: \u001B[38;5;15mThe credentials are invalid.\u001B[0m \r\n \u001B[38;5;8mat\u001B[0m \u001B[38;5;9mvoid\u001B[0m \u001B[38;5;9mCheckCredentials\u001B[0m\u001B[38;5;230m(\u001B[0m\u001B[38;5;9mint\u001B[0m \u001B[38;5;230mqux\u001B[0m, \u001B[38;5;9mstring[,]\u001B[0m \u001B[38;5;230mcorgi)\u001B[0m \u001B[38;5;8min\u001B[0m \u001B]8;id=960633358;file://phil-adler/R:/phil-scott/spectre.console/resources/scripts/Generator/Commands/AsciiCast/Samples/Exceptions.cs\u001B\\\u001B[38;5;9mExceptions.cs\u001B[0m\u001B]8;;\u001B\\\u001B[38;5;8m:\u001B[0m\u001B[38;5;230m76\u001B[0m \r\n \u001B[38;5;8mat\u001B[0m \u001B[38;5;9mvoid\u001B[0m \u001B[38;5;9mDoMagic\u001B[0m\u001B[38;5;230m(\u001B[0m\u001B[38;5;9mint\u001B[0m \u001B[38;5;230mfoo\u001B[0m, \u001B[38;5;9mstring[,]\u001B[0m \u001B[38;5;230mbar)\u001B[0m \u001B[38;5;8min\u001B[0m \u001B]8;id=93980157;file://phil-adler/R:/phil-scott/spectre.console/resources/scripts/Generator/Commands/AsciiCast/Samples/Exceptions.cs\u001B\\\u001B[38;5;9mExceptions.cs\u001B[0m\u001B]8;;\u001B\\\u001B[38;5;8m:\u001B[0m\u001B[38;5;230m66\u001B[0m \r\n \u001B[38;5;8mat\u001B[0m \u001B[38;5;9mvoid\u001B[0m \u001B[38;5;9mDoMagic\u001B[0m\u001B[38;5;230m(\u001B[0m\u001B[38;5;9mint\u001B[0m \u001B[38;5;230mfoo\u001B[0m, \u001B[38;5;9mstring[,]\u001B[0m \u001B[38;5;230mbar)\u001B[0m \u001B[38;5;8min\u001B[0m \u001B]8;id=293733654;file://phil-adler/R:/phil-scott/spectre.console/resources/scripts/Generator/Commands/AsciiCast/Samples/Exceptions.cs\u001B\\\u001B[38;5;9mExceptions.cs\u001B[0m\u001B]8;;\u001B\\\u001B[38;5;8m:\u001B[0m\u001B[38;5;230m70\u001B[0m \r\n \u001B[38;5;8mat\u001B[0m \u001B[38;5;9mctor\u001B[0m\u001B[38;5;230m()\u001B[0m \u001B[38;5;8min\u001B[0m \u001B]8;id=762297770;file://phil-adler/R:/phil-scott/spectre.console/resources/scripts/Generator/Commands/AsciiCast/Samples/Exceptions.cs\u001B\\\u001B[38;5;9mExceptions.cs\u001B[0m\u001B]8;;\u001B\\\u001B[38;5;8m:\u001B[0m\u001B[38;5;230m20\u001B[0m \r\n"]

View File

@ -1,3 +1,3 @@
{"version": 2, "width": 122, "height": 12, "title": "default-exception (plain)", "env": {"TERM": "Spectre.Console"}} {"version": 2, "width": 102, "height": 12, "title": "default-exception (plain)", "env": {"TERM": "Spectre.Console"}}
[0, "o", "\u001B[37mSystem.\u001B[0m\u001B[37mInvalidOperationException\u001B[0m: \u001B[1;31mWhaaat?\u001B[0m\r\n \u001B[37mSystem.Security.Authentication.\u001B[0m\u001B[37mInvalidCredentialException\u001B[0m: \u001B[1;31mThe credentials are invalid.\u001B[0m \r\n \u001B[37mat\u001B[0m \u001B[34mvoid\u001B[0m \u001B[37mGenerator.Commands.Samples.Exceptions.\u001B[0m\u001B[37mCheckCredentials\u001B[0m\u001B[37m(\u001B[0m\u001B[34mint\u001B[0m \u001B[37mqux\u001B[0m, \u001B[34mstring[,]\u001B[0m \u001B[37mcorgi)\u001B[0m \u001B[37min\u001B[0m \u001B[1;37mExceptions.cs\u001B[0m\u001B[37m:\u001B[0m\u001B[34m75\u001B[0m \r\n \u001B[37mat\u001B[0m \u001B[34mvoid\u001B[0m \u001B[37mGenerator.Commands.Samples.Exceptions.\u001B[0m\u001B[37mDoMagic\u001B[0m\u001B[37m(\u001B[0m\u001B[34mint\u001B[0m \u001B[37mfoo\u001B[0m, \u001B[34mstring[,]\u001B[0m \u001B[37mbar)\u001B[0m \u001B[37min\u001B[0m \u001B[1;37mExceptions.cs\u001B[0m\u001B[37m:\u001B[0m\u001B[34m65\u001B[0m \r\n \u001B[37mat\u001B[0m \u001B[34mvoid\u001B[0m \u001B[37mGenerator.Commands.Samples.Exceptions.\u001B[0m\u001B[37mDoMagic\u001B[0m\u001B[37m(\u001B[0m\u001B[34mint\u001B[0m \u001B[37mfoo\u001B[0m, \u001B[34mstring[,]\u001B[0m \u001B[37mbar)\u001B[0m \u001B[37min\u001B[0m \u001B[1;37mExceptions.cs\u001B[0m\u001B[37m:\u001B[0m\u001B[34m69\u001B[0m \r\n \u001B[37mat\u001B[0m \u001B[37mGenerator.Commands.Samples.Exceptions.BaseExceptionSample..\u001B[0m\u001B[37mctor\u001B[0m\u001B[37m()\u001B[0m \u001B[37min\u001B[0m \u001B[1;37mExceptions.cs\u001B[0m\u001B[37m:\u001B[0m\u001B[34m19\u001B[0m \r\n"] [0, "o", "\u001B[37mSystem.\u001B[0m\u001B[37mInvalidOperationException\u001B[0m: \u001B[1;31mWhaaat?\u001B[0m\r\n \u001B[37mSystem.Security.Authentication.\u001B[0m\u001B[37mInvalidCredentialException\u001B[0m: \u001B[1;31mThe credentials are invalid.\u001B[0m \r\n \u001B[37mat\u001B[0m \u001B[34mvoid\u001B[0m \u001B[37mSamples.Exceptions.\u001B[0m\u001B[37mCheckCredentials\u001B[0m\u001B[37m(\u001B[0m\u001B[34mint\u001B[0m \u001B[37mqux\u001B[0m, \u001B[34mstring[,]\u001B[0m \u001B[37mcorgi)\u001B[0m \u001B[37min\u001B[0m \u001B[1;37mExceptions.cs\u001B[0m\u001B[37m:\u001B[0m\u001B[34m76\u001B[0m \r\n \u001B[37mat\u001B[0m \u001B[34mvoid\u001B[0m \u001B[37mSamples.Exceptions.\u001B[0m\u001B[37mDoMagic\u001B[0m\u001B[37m(\u001B[0m\u001B[34mint\u001B[0m \u001B[37mfoo\u001B[0m, \u001B[34mstring[,]\u001B[0m \u001B[37mbar)\u001B[0m \u001B[37min\u001B[0m \u001B[1;37mExceptions.cs\u001B[0m\u001B[37m:\u001B[0m\u001B[34m66\u001B[0m \r\n \u001B[37mat\u001B[0m \u001B[34mvoid\u001B[0m \u001B[37mSamples.Exceptions.\u001B[0m\u001B[37mDoMagic\u001B[0m\u001B[37m(\u001B[0m\u001B[34mint\u001B[0m \u001B[37mfoo\u001B[0m, \u001B[34mstring[,]\u001B[0m \u001B[37mbar)\u001B[0m \u001B[37min\u001B[0m \u001B[1;37mExceptions.cs\u001B[0m\u001B[37m:\u001B[0m\u001B[34m70\u001B[0m \r\n \u001B[37mat\u001B[0m \u001B[37mSamples.Exceptions.BaseExceptionSample..\u001B[0m\u001B[37mctor\u001B[0m\u001B[37m()\u001B[0m \u001B[37min\u001B[0m \u001B[1;37mExceptions.cs\u001B[0m\u001B[37m:\u001B[0m\u001B[34m20\u001B[0m \r\n"]

View File

@ -1,3 +1,3 @@
{"version": 2, "width": 122, "height": 12, "title": "default-exception (rich)", "env": {"TERM": "Spectre.Console"}} {"version": 2, "width": 102, "height": 12, "title": "default-exception (rich)", "env": {"TERM": "Spectre.Console"}}
[0, "o", "\u001B[38;5;7mSystem.\u001B[0m\u001B[38;5;15mInvalidOperationException\u001B[0m: \u001B[1;38;5;9mWhaaat?\u001B[0m\r\n \u001B[38;5;7mSystem.Security.Authentication.\u001B[0m\u001B[38;5;15mInvalidCredentialException\u001B[0m: \u001B[1;38;5;9mThe credentials are invalid.\u001B[0m \r\n \u001B[38;5;8mat\u001B[0m \u001B[38;5;12mvoid\u001B[0m \u001B[38;5;7mGenerator.Commands.Samples.Exceptions.\u001B[0m\u001B[38;5;11mCheckCredentials\u001B[0m\u001B[38;5;7m(\u001B[0m\u001B[38;5;12mint\u001B[0m \u001B[38;5;7mqux\u001B[0m, \u001B[38;5;12mstring[,]\u001B[0m \u001B[38;5;7mcorgi)\u001B[0m \u001B[38;5;8min\u001B[0m \u001B[1;38;5;11mExceptions.cs\u001B[0m\u001B[38;5;8m:\u001B[0m\u001B[38;5;12m75\u001B[0m \r\n \u001B[38;5;8mat\u001B[0m \u001B[38;5;12mvoid\u001B[0m \u001B[38;5;7mGenerator.Commands.Samples.Exceptions.\u001B[0m\u001B[38;5;11mDoMagic\u001B[0m\u001B[38;5;7m(\u001B[0m\u001B[38;5;12mint\u001B[0m \u001B[38;5;7mfoo\u001B[0m, \u001B[38;5;12mstring[,]\u001B[0m \u001B[38;5;7mbar)\u001B[0m \u001B[38;5;8min\u001B[0m \u001B[1;38;5;11mExceptions.cs\u001B[0m\u001B[38;5;8m:\u001B[0m\u001B[38;5;12m65\u001B[0m \r\n \u001B[38;5;8mat\u001B[0m \u001B[38;5;12mvoid\u001B[0m \u001B[38;5;7mGenerator.Commands.Samples.Exceptions.\u001B[0m\u001B[38;5;11mDoMagic\u001B[0m\u001B[38;5;7m(\u001B[0m\u001B[38;5;12mint\u001B[0m \u001B[38;5;7mfoo\u001B[0m, \u001B[38;5;12mstring[,]\u001B[0m \u001B[38;5;7mbar)\u001B[0m \u001B[38;5;8min\u001B[0m \u001B[1;38;5;11mExceptions.cs\u001B[0m\u001B[38;5;8m:\u001B[0m\u001B[38;5;12m69\u001B[0m \r\n \u001B[38;5;8mat\u001B[0m \u001B[38;5;7mGenerator.Commands.Samples.Exceptions.BaseExceptionSample..\u001B[0m\u001B[38;5;11mctor\u001B[0m\u001B[38;5;7m()\u001B[0m \u001B[38;5;8min\u001B[0m \u001B[1;38;5;11mExceptions.cs\u001B[0m\u001B[38;5;8m:\u001B[0m\u001B[38;5;12m19\u001B[0m \r\n"] [0, "o", "\u001B[38;5;7mSystem.\u001B[0m\u001B[38;5;15mInvalidOperationException\u001B[0m: \u001B[1;38;5;9mWhaaat?\u001B[0m\r\n \u001B[38;5;7mSystem.Security.Authentication.\u001B[0m\u001B[38;5;15mInvalidCredentialException\u001B[0m: \u001B[1;38;5;9mThe credentials are invalid.\u001B[0m \r\n \u001B[38;5;8mat\u001B[0m \u001B[38;5;12mvoid\u001B[0m \u001B[38;5;7mSamples.Exceptions.\u001B[0m\u001B[38;5;11mCheckCredentials\u001B[0m\u001B[38;5;7m(\u001B[0m\u001B[38;5;12mint\u001B[0m \u001B[38;5;7mqux\u001B[0m, \u001B[38;5;12mstring[,]\u001B[0m \u001B[38;5;7mcorgi)\u001B[0m \u001B[38;5;8min\u001B[0m \u001B[1;38;5;11mExceptions.cs\u001B[0m\u001B[38;5;8m:\u001B[0m\u001B[38;5;12m76\u001B[0m \r\n \u001B[38;5;8mat\u001B[0m \u001B[38;5;12mvoid\u001B[0m \u001B[38;5;7mSamples.Exceptions.\u001B[0m\u001B[38;5;11mDoMagic\u001B[0m\u001B[38;5;7m(\u001B[0m\u001B[38;5;12mint\u001B[0m \u001B[38;5;7mfoo\u001B[0m, \u001B[38;5;12mstring[,]\u001B[0m \u001B[38;5;7mbar)\u001B[0m \u001B[38;5;8min\u001B[0m \u001B[1;38;5;11mExceptions.cs\u001B[0m\u001B[38;5;8m:\u001B[0m\u001B[38;5;12m66\u001B[0m \r\n \u001B[38;5;8mat\u001B[0m \u001B[38;5;12mvoid\u001B[0m \u001B[38;5;7mSamples.Exceptions.\u001B[0m\u001B[38;5;11mDoMagic\u001B[0m\u001B[38;5;7m(\u001B[0m\u001B[38;5;12mint\u001B[0m \u001B[38;5;7mfoo\u001B[0m, \u001B[38;5;12mstring[,]\u001B[0m \u001B[38;5;7mbar)\u001B[0m \u001B[38;5;8min\u001B[0m \u001B[1;38;5;11mExceptions.cs\u001B[0m\u001B[38;5;8m:\u001B[0m\u001B[38;5;12m70\u001B[0m \r\n \u001B[38;5;8mat\u001B[0m \u001B[38;5;7mSamples.Exceptions.BaseExceptionSample..\u001B[0m\u001B[38;5;11mctor\u001B[0m\u001B[38;5;7m()\u001B[0m \u001B[38;5;8min\u001B[0m \u001B[1;38;5;11mExceptions.cs\u001B[0m\u001B[38;5;8m:\u001B[0m\u001B[38;5;12m20\u001B[0m \r\n"]

View File

@ -1,5 +1,5 @@
{"version": 2, "width": 122, "height": 24, "title": "figlet (plain)", "env": {"TERM": "Spectre.Console"}} {"version": 2, "width": 102, "height": 24, "title": "figlet (plain)", "env": {"TERM": "Spectre.Console"}}
[0, "o", "\u001B[31m _ __ _ _ _ _ \u001B[0m \r\n\u001B[31m | | ___ / _| | |_ __ _ | | (_) __ _ _ __ ___ __| |\u001B[0m \r\n\u001B[31m | | / _ \\ | |_ | __| / _\u0060 | | | | | / _\u0060 | | \u0027_ \\ / _ \\ / _\u0060 |\u001B[0m \r\n\u001B[31m | |___ | __/ | _| | |_ | (_| | | | | | | (_| | | | | | | __/ | (_| |\u001B[0m \r\n\u001B[31m |_____| \\___| |_| \\__| \\__,_| |_| |_| \\__, | |_| |_| \\___| \\__,_|\u001B[0m \r\n\u001B[31m |___/ \u001B[0m \r\n"] [0, "o", "\u001B[31m _ __ _ _ _ _ \u001B[0m \r\n\u001B[31m | | ___ / _| | |_ __ _ | | (_) __ _ _ __ ___ __| |\u001B[0m \r\n\u001B[31m | | / _ \\ | |_ | __| / _\u0060 | | | | | / _\u0060 | | \u0027_ \\ / _ \\ / _\u0060 |\u001B[0m \r\n\u001B[31m | |___ | __/ | _| | |_ | (_| | | | | | | (_| | | | | | | __/ | (_| |\u001B[0m \r\n\u001B[31m |_____| \\___| |_| \\__| \\__,_| |_| |_| \\__, | |_| |_| \\___| \\__,_|\u001B[0m \r\n\u001B[31m |___/ \u001B[0m \r\n"]
[0, "o", " \u001B[32m ____ _ _ \u001B[0m \r\n \u001B[32m / ___| ___ _ __ | |_ ___ _ __ ___ __| |\u001B[0m \r\n \u001B[32m | | / _ \\ | \u0027_ \\ | __| / _ \\ | \u0027__| / _ \\ / _\u0060 |\u001B[0m \r\n \u001B[32m | |___ | __/ | | | | | |_ | __/ | | | __/ | (_| |\u001B[0m \r\n \u001B[32m \\____| \\___| |_| |_| \\__| \\___| |_| \\___| \\__,_|\u001B[0m \r\n \u001B[32m \u001B[0m \r\n"] [0.016, "o", " \u001B[32m ____ _ _ \u001B[0m \r\n \u001B[32m / ___| ___ _ __ | |_ ___ _ __ ___ __| |\u001B[0m \r\n \u001B[32m | | / _ \\ | \u0027_ \\ | __| / _ \\ | \u0027__| / _ \\ / _\u0060 |\u001B[0m \r\n \u001B[32m | |___ | __/ | | | | | |_ | __/ | | | __/ | (_| |\u001B[0m \r\n \u001B[32m \\____| \\___| |_| |_| \\__| \\___| |_| \\___| \\__,_|\u001B[0m \r\n \u001B[32m \u001B[0m \r\n"]
[0, "o", " \u001B[34m ____ _ _ _ _ _ _ \u001B[0m\r\n \u001B[34m | _ \\ (_) __ _ | |__ | |_ __ _ | | (_) __ _ _ __ ___ __| |\u001B[0m\r\n \u001B[34m | |_) | | | / _\u0060 | | \u0027_ \\ | __| / _\u0060 | | | | | / _\u0060 | | \u0027_ \\ / _ \\ / _\u0060 |\u001B[0m\r\n \u001B[34m | _ \u003C | | | (_| | | | | | | |_ | (_| | | | | | | (_| | | | | | | __/ | (_| |\u001B[0m\r\n \u001B[34m |_| \\_\\ |_| \\__, | |_| |_| \\__| \\__,_| |_| |_| \\__, | |_| |_| \\___| \\__,_|\u001B[0m\r\n \u001B[34m |___/ |___/ \u001B[0m\r\n"] [0.016, "o", " \u001B[34m ____ _ _ _ _ _ _ \u001B[0m\r\n \u001B[34m | _ \\ (_) __ _ | |__ | |_ __ _ | | (_) __ _ _ __ ___ __| |\u001B[0m\r\n \u001B[34m | |_) | | | / _\u0060 | | \u0027_ \\ | __| / _\u0060 | | | | | / _\u0060 | | \u0027_ \\ / _ \\ / _\u0060 |\u001B[0m\r\n \u001B[34m | _ \u003C | | | (_| | | | | | | |_ | (_| | | | | | | (_| | | | | | | __/ | (_| |\u001B[0m\r\n \u001B[34m |_| \\_\\ |_| \\__, | |_| |_| \\__| \\__,_| |_| |_| \\__, | |_| |_| \\___| \\__,_|\u001B[0m\r\n \u001B[34m |___/ |___/ \u001B[0m\r\n"]

View File

@ -1,5 +1,5 @@
{"version": 2, "width": 122, "height": 24, "title": "figlet (rich)", "env": {"TERM": "Spectre.Console"}} {"version": 2, "width": 102, "height": 24, "title": "figlet (rich)", "env": {"TERM": "Spectre.Console"}}
[0, "o", "\u001B[38;5;9m _ __ _ _ _ _ \u001B[0m \r\n\u001B[38;5;9m | | ___ / _| | |_ __ _ | | (_) __ _ _ __ ___ __| |\u001B[0m \r\n\u001B[38;5;9m | | / _ \\ | |_ | __| / _\u0060 | | | | | / _\u0060 | | \u0027_ \\ / _ \\ / _\u0060 |\u001B[0m \r\n\u001B[38;5;9m | |___ | __/ | _| | |_ | (_| | | | | | | (_| | | | | | | __/ | (_| |\u001B[0m \r\n\u001B[38;5;9m |_____| \\___| |_| \\__| \\__,_| |_| |_| \\__, | |_| |_| \\___| \\__,_|\u001B[0m \r\n\u001B[38;5;9m |___/ \u001B[0m \r\n"] [0, "o", "\u001B[38;5;9m _ __ _ _ _ _ \u001B[0m \r\n\u001B[38;5;9m | | ___ / _| | |_ __ _ | | (_) __ _ _ __ ___ __| |\u001B[0m \r\n\u001B[38;5;9m | | / _ \\ | |_ | __| / _\u0060 | | | | | / _\u0060 | | \u0027_ \\ / _ \\ / _\u0060 |\u001B[0m \r\n\u001B[38;5;9m | |___ | __/ | _| | |_ | (_| | | | | | | (_| | | | | | | __/ | (_| |\u001B[0m \r\n\u001B[38;5;9m |_____| \\___| |_| \\__| \\__,_| |_| |_| \\__, | |_| |_| \\___| \\__,_|\u001B[0m \r\n\u001B[38;5;9m |___/ \u001B[0m \r\n"]
[0, "o", " \u001B[38;5;2m ____ _ _ \u001B[0m \r\n \u001B[38;5;2m / ___| ___ _ __ | |_ ___ _ __ ___ __| |\u001B[0m \r\n \u001B[38;5;2m | | / _ \\ | \u0027_ \\ | __| / _ \\ | \u0027__| / _ \\ / _\u0060 |\u001B[0m \r\n \u001B[38;5;2m | |___ | __/ | | | | | |_ | __/ | | | __/ | (_| |\u001B[0m \r\n \u001B[38;5;2m \\____| \\___| |_| |_| \\__| \\___| |_| \\___| \\__,_|\u001B[0m \r\n \u001B[38;5;2m \u001B[0m \r\n"] [0, "o", " \u001B[38;5;2m ____ _ _ \u001B[0m \r\n \u001B[38;5;2m / ___| ___ _ __ | |_ ___ _ __ ___ __| |\u001B[0m \r\n \u001B[38;5;2m | | / _ \\ | \u0027_ \\ | __| / _ \\ | \u0027__| / _ \\ / _\u0060 |\u001B[0m \r\n \u001B[38;5;2m | |___ | __/ | | | | | |_ | __/ | | | __/ | (_| |\u001B[0m \r\n \u001B[38;5;2m \\____| \\___| |_| |_| \\__| \\___| |_| \\___| \\__,_|\u001B[0m \r\n \u001B[38;5;2m \u001B[0m \r\n"]
[0, "o", " \u001B[38;5;12m ____ _ _ _ _ _ _ \u001B[0m\r\n \u001B[38;5;12m | _ \\ (_) __ _ | |__ | |_ __ _ | | (_) __ _ _ __ ___ __| |\u001B[0m\r\n \u001B[38;5;12m | |_) | | | / _\u0060 | | \u0027_ \\ | __| / _\u0060 | | | | | / _\u0060 | | \u0027_ \\ / _ \\ / _\u0060 |\u001B[0m\r\n \u001B[38;5;12m | _ \u003C | | | (_| | | | | | | |_ | (_| | | | | | | (_| | | | | | | __/ | (_| |\u001B[0m\r\n \u001B[38;5;12m |_| \\_\\ |_| \\__, | |_| |_| \\__| \\__,_| |_| |_| \\__, | |_| |_| \\___| \\__,_|\u001B[0m\r\n \u001B[38;5;12m |___/ |___/ \u001B[0m\r\n"] [0, "o", " \u001B[38;5;12m ____ _ _ _ _ _ _ \u001B[0m\r\n \u001B[38;5;12m | _ \\ (_) __ _ | |__ | |_ __ _ | | (_) __ _ _ __ ___ __| |\u001B[0m\r\n \u001B[38;5;12m | |_) | | | / _\u0060 | | \u0027_ \\ | __| / _\u0060 | | | | | / _\u0060 | | \u0027_ \\ / _ \\ / _\u0060 |\u001B[0m\r\n \u001B[38;5;12m | _ \u003C | | | (_| | | | | | | |_ | (_| | | | | | | (_| | | | | | | __/ | (_| |\u001B[0m\r\n \u001B[38;5;12m |_| \\_\\ |_| \\__, | |_| |_| \\__| \\__,_| |_| |_| \\__, | |_| |_| \\___| \\__,_|\u001B[0m\r\n \u001B[38;5;12m |___/ |___/ \u001B[0m\r\n"]

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,3 +1,3 @@
{"version": 2, "width": 122, "height": 12, "title": "shortened-exception (plain)", "env": {"TERM": "Spectre.Console"}} {"version": 2, "width": 102, "height": 12, "title": "shortened-exception (plain)", "env": {"TERM": "Spectre.Console"}}
[0, "o", "\u001B[37mInvalidOperationException\u001B[0m: \u001B[1;31mWhaaat?\u001B[0m\r\n \u001B[37mInvalidCredentialException\u001B[0m: \u001B[1;31mThe credentials are invalid.\u001B[0m \r\n \u001B[37mat\u001B[0m \u001B[34mvoid\u001B[0m \u001B[37mCheckCredentials\u001B[0m\u001B[37m(\u001B[0m\u001B[34mint\u001B[0m \u001B[37mqux\u001B[0m, \u001B[34mstring[,]\u001B[0m \u001B[37mcorgi)\u001B[0m \u001B[37min\u001B[0m \u001B]8;id=17125006;file://phil-adler/R:/phil-scott/spectre.console/resources/scripts/Generator/Commands/AsciiCast/Samples/Exceptions.cs\u001B\\\u001B[1;37mExceptions.cs\u001B[0m\u001B]8;;\u001B\\\u001B[37m:\u001B[0m\u001B[34m75\u001B[0m \r\n \u001B[37mat\u001B[0m \u001B[34mvoid\u001B[0m \u001B[37mDoMagic\u001B[0m\u001B[37m(\u001B[0m\u001B[34mint\u001B[0m \u001B[37mfoo\u001B[0m, \u001B[34mstring[,]\u001B[0m \u001B[37mbar)\u001B[0m \u001B[37min\u001B[0m \u001B]8;id=1265662737;file://phil-adler/R:/phil-scott/spectre.console/resources/scripts/Generator/Commands/AsciiCast/Samples/Exceptions.cs\u001B\\\u001B[1;37mExceptions.cs\u001B[0m\u001B]8;;\u001B\\\u001B[37m:\u001B[0m\u001B[34m65\u001B[0m \r\n \u001B[37mat\u001B[0m \u001B[34mvoid\u001B[0m \u001B[37mDoMagic\u001B[0m\u001B[37m(\u001B[0m\u001B[34mint\u001B[0m \u001B[37mfoo\u001B[0m, \u001B[34mstring[,]\u001B[0m \u001B[37mbar)\u001B[0m \u001B[37min\u001B[0m \u001B]8;id=727179011;file://phil-adler/R:/phil-scott/spectre.console/resources/scripts/Generator/Commands/AsciiCast/Samples/Exceptions.cs\u001B\\\u001B[1;37mExceptions.cs\u001B[0m\u001B]8;;\u001B\\\u001B[37m:\u001B[0m\u001B[34m69\u001B[0m \r\n \u001B[37mat\u001B[0m \u001B[37mctor\u001B[0m\u001B[37m()\u001B[0m \u001B[37min\u001B[0m \u001B]8;id=276367595;file://phil-adler/R:/phil-scott/spectre.console/resources/scripts/Generator/Commands/AsciiCast/Samples/Exceptions.cs\u001B\\\u001B[1;37mExceptions.cs\u001B[0m\u001B]8;;\u001B\\\u001B[37m:\u001B[0m\u001B[34m19\u001B[0m \r\n"] [0, "o", "\u001B[37mInvalidOperationException\u001B[0m: \u001B[1;31mWhaaat?\u001B[0m\r\n \u001B[37mInvalidCredentialException\u001B[0m: \u001B[1;31mThe credentials are invalid.\u001B[0m \r\n \u001B[37mat\u001B[0m \u001B[34mvoid\u001B[0m \u001B[37mCheckCredentials\u001B[0m\u001B[37m(\u001B[0m\u001B[34mint\u001B[0m \u001B[37mqux\u001B[0m, \u001B[34mstring[,]\u001B[0m \u001B[37mcorgi)\u001B[0m \u001B[37min\u001B[0m \u001B]8;id=418863998;file://phil-adler/R:/phil-scott/spectre.console/resources/scripts/Generator/Commands/AsciiCast/Samples/Exceptions.cs\u001B\\\u001B[1;37mExceptions.cs\u001B[0m\u001B]8;;\u001B\\\u001B[37m:\u001B[0m\u001B[34m76\u001B[0m \r\n \u001B[37mat\u001B[0m \u001B[34mvoid\u001B[0m \u001B[37mDoMagic\u001B[0m\u001B[37m(\u001B[0m\u001B[34mint\u001B[0m \u001B[37mfoo\u001B[0m, \u001B[34mstring[,]\u001B[0m \u001B[37mbar)\u001B[0m \u001B[37min\u001B[0m \u001B]8;id=1618669281;file://phil-adler/R:/phil-scott/spectre.console/resources/scripts/Generator/Commands/AsciiCast/Samples/Exceptions.cs\u001B\\\u001B[1;37mExceptions.cs\u001B[0m\u001B]8;;\u001B\\\u001B[37m:\u001B[0m\u001B[34m66\u001B[0m \r\n \u001B[37mat\u001B[0m \u001B[34mvoid\u001B[0m \u001B[37mDoMagic\u001B[0m\u001B[37m(\u001B[0m\u001B[34mint\u001B[0m \u001B[37mfoo\u001B[0m, \u001B[34mstring[,]\u001B[0m \u001B[37mbar)\u001B[0m \u001B[37min\u001B[0m \u001B]8;id=112095567;file://phil-adler/R:/phil-scott/spectre.console/resources/scripts/Generator/Commands/AsciiCast/Samples/Exceptions.cs\u001B\\\u001B[1;37mExceptions.cs\u001B[0m\u001B]8;;\u001B\\\u001B[37m:\u001B[0m\u001B[34m70\u001B[0m \r\n \u001B[37mat\u001B[0m \u001B[37mctor\u001B[0m\u001B[37m()\u001B[0m \u001B[37min\u001B[0m \u001B]8;id=1341248185;file://phil-adler/R:/phil-scott/spectre.console/resources/scripts/Generator/Commands/AsciiCast/Samples/Exceptions.cs\u001B\\\u001B[1;37mExceptions.cs\u001B[0m\u001B]8;;\u001B\\\u001B[37m:\u001B[0m\u001B[34m20\u001B[0m \r\n"]

View File

@ -1,3 +1,3 @@
{"version": 2, "width": 122, "height": 12, "title": "shortened-exception (rich)", "env": {"TERM": "Spectre.Console"}} {"version": 2, "width": 102, "height": 12, "title": "shortened-exception (rich)", "env": {"TERM": "Spectre.Console"}}
[0, "o", "\u001B[38;5;15mInvalidOperationException\u001B[0m: \u001B[1;38;5;9mWhaaat?\u001B[0m\r\n \u001B[38;5;15mInvalidCredentialException\u001B[0m: \u001B[1;38;5;9mThe credentials are invalid.\u001B[0m \r\n \u001B[38;5;8mat\u001B[0m \u001B[38;5;12mvoid\u001B[0m \u001B[38;5;11mCheckCredentials\u001B[0m\u001B[38;5;7m(\u001B[0m\u001B[38;5;12mint\u001B[0m \u001B[38;5;7mqux\u001B[0m, \u001B[38;5;12mstring[,]\u001B[0m \u001B[38;5;7mcorgi)\u001B[0m \u001B[38;5;8min\u001B[0m \u001B]8;id=339131903;file://phil-adler/R:/phil-scott/spectre.console/resources/scripts/Generator/Commands/AsciiCast/Samples/Exceptions.cs\u001B\\\u001B[1;38;5;11mExceptions.cs\u001B[0m\u001B]8;;\u001B\\\u001B[38;5;8m:\u001B[0m\u001B[38;5;12m75\u001B[0m \r\n \u001B[38;5;8mat\u001B[0m \u001B[38;5;12mvoid\u001B[0m \u001B[38;5;11mDoMagic\u001B[0m\u001B[38;5;7m(\u001B[0m\u001B[38;5;12mint\u001B[0m \u001B[38;5;7mfoo\u001B[0m, \u001B[38;5;12mstring[,]\u001B[0m \u001B[38;5;7mbar)\u001B[0m \u001B[38;5;8min\u001B[0m \u001B]8;id=619495582;file://phil-adler/R:/phil-scott/spectre.console/resources/scripts/Generator/Commands/AsciiCast/Samples/Exceptions.cs\u001B\\\u001B[1;38;5;11mExceptions.cs\u001B[0m\u001B]8;;\u001B\\\u001B[38;5;8m:\u001B[0m\u001B[38;5;12m65\u001B[0m \r\n \u001B[38;5;8mat\u001B[0m \u001B[38;5;12mvoid\u001B[0m \u001B[38;5;11mDoMagic\u001B[0m\u001B[38;5;7m(\u001B[0m\u001B[38;5;12mint\u001B[0m \u001B[38;5;7mfoo\u001B[0m, \u001B[38;5;12mstring[,]\u001B[0m \u001B[38;5;7mbar)\u001B[0m \u001B[38;5;8min\u001B[0m \u001B]8;id=262041026;file://phil-adler/R:/phil-scott/spectre.console/resources/scripts/Generator/Commands/AsciiCast/Samples/Exceptions.cs\u001B\\\u001B[1;38;5;11mExceptions.cs\u001B[0m\u001B]8;;\u001B\\\u001B[38;5;8m:\u001B[0m\u001B[38;5;12m69\u001B[0m \r\n \u001B[38;5;8mat\u001B[0m \u001B[38;5;11mctor\u001B[0m\u001B[38;5;7m()\u001B[0m \u001B[38;5;8min\u001B[0m \u001B]8;id=511470544;file://phil-adler/R:/phil-scott/spectre.console/resources/scripts/Generator/Commands/AsciiCast/Samples/Exceptions.cs\u001B\\\u001B[1;38;5;11mExceptions.cs\u001B[0m\u001B]8;;\u001B\\\u001B[38;5;8m:\u001B[0m\u001B[38;5;12m19\u001B[0m \r\n"] [0, "o", "\u001B[38;5;15mInvalidOperationException\u001B[0m: \u001B[1;38;5;9mWhaaat?\u001B[0m\r\n \u001B[38;5;15mInvalidCredentialException\u001B[0m: \u001B[1;38;5;9mThe credentials are invalid.\u001B[0m \r\n \u001B[38;5;8mat\u001B[0m \u001B[38;5;12mvoid\u001B[0m \u001B[38;5;11mCheckCredentials\u001B[0m\u001B[38;5;7m(\u001B[0m\u001B[38;5;12mint\u001B[0m \u001B[38;5;7mqux\u001B[0m, \u001B[38;5;12mstring[,]\u001B[0m \u001B[38;5;7mcorgi)\u001B[0m \u001B[38;5;8min\u001B[0m \u001B]8;id=248520178;file://phil-adler/R:/phil-scott/spectre.console/resources/scripts/Generator/Commands/AsciiCast/Samples/Exceptions.cs\u001B\\\u001B[1;38;5;11mExceptions.cs\u001B[0m\u001B]8;;\u001B\\\u001B[38;5;8m:\u001B[0m\u001B[38;5;12m76\u001B[0m \r\n \u001B[38;5;8mat\u001B[0m \u001B[38;5;12mvoid\u001B[0m \u001B[38;5;11mDoMagic\u001B[0m\u001B[38;5;7m(\u001B[0m\u001B[38;5;12mint\u001B[0m \u001B[38;5;7mfoo\u001B[0m, \u001B[38;5;12mstring[,]\u001B[0m \u001B[38;5;7mbar)\u001B[0m \u001B[38;5;8min\u001B[0m \u001B]8;id=122011838;file://phil-adler/R:/phil-scott/spectre.console/resources/scripts/Generator/Commands/AsciiCast/Samples/Exceptions.cs\u001B\\\u001B[1;38;5;11mExceptions.cs\u001B[0m\u001B]8;;\u001B\\\u001B[38;5;8m:\u001B[0m\u001B[38;5;12m66\u001B[0m \r\n \u001B[38;5;8mat\u001B[0m \u001B[38;5;12mvoid\u001B[0m \u001B[38;5;11mDoMagic\u001B[0m\u001B[38;5;7m(\u001B[0m\u001B[38;5;12mint\u001B[0m \u001B[38;5;7mfoo\u001B[0m, \u001B[38;5;12mstring[,]\u001B[0m \u001B[38;5;7mbar)\u001B[0m \u001B[38;5;8min\u001B[0m \u001B]8;id=732431604;file://phil-adler/R:/phil-scott/spectre.console/resources/scripts/Generator/Commands/AsciiCast/Samples/Exceptions.cs\u001B\\\u001B[1;38;5;11mExceptions.cs\u001B[0m\u001B]8;;\u001B\\\u001B[38;5;8m:\u001B[0m\u001B[38;5;12m70\u001B[0m \r\n \u001B[38;5;8mat\u001B[0m \u001B[38;5;11mctor\u001B[0m\u001B[38;5;7m()\u001B[0m \u001B[38;5;8min\u001B[0m \u001B]8;id=1471369749;file://phil-adler/R:/phil-scott/spectre.console/resources/scripts/Generator/Commands/AsciiCast/Samples/Exceptions.cs\u001B\\\u001B[1;38;5;11mExceptions.cs\u001B[0m\u001B]8;;\u001B\\\u001B[38;5;8m:\u001B[0m\u001B[38;5;12m20\u001B[0m \r\n"]

View File

@ -7,8 +7,7 @@
<metadata> <metadata>
Created by potrace 1.16, written by Peter Selinger 2001-2019 Created by potrace 1.16, written by Peter Selinger 2001-2019
</metadata> </metadata>
<g transform="translate(0.000000,1270.000000) scale(0.100000,-0.100000)" <g transform="translate(0.000000,1270.000000) scale(0.100000,-0.100000)">
fill="#000000" stroke="none">
<path d="M799 10610 c-199 -48 -354 -191 -414 -383 l-25 -78 0 -3084 0 -3084 <path d="M799 10610 c-199 -48 -354 -191 -414 -383 l-25 -78 0 -3084 0 -3084
25 -79 c45 -141 155 -270 289 -335 124 -61 -80 -57 2819 -57 l2646 0 5 -43 c3 25 -79 c45 -141 155 -270 289 -335 124 -61 -80 -57 2819 -57 l2646 0 5 -43 c3
-23 8 -71 11 -105 13 -137 88 -334 179 -471 57 -85 187 -219 247 -254 25 -15 -23 8 -71 11 -105 13 -137 88 -334 179 -471 57 -85 187 -219 247 -254 25 -15

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

View File

@ -1,6 +1,4 @@
@inherits StatiqRazorPage<IDocument> @inherits StatiqRazorPage<IDocument>
@model IDocument
@{ @{
var older = Model.GetDocument(Keys.Next); var older = Model.GetDocument(Keys.Next);

View File

@ -1,5 +1,5 @@
@inherits StatiqRazorPage<IEnumerable<IDocument>> @inherits StatiqRazorPage<IEnumerable<IDocument>>
@foreach (var post in Model) @foreach (var post in Model ?? Array.Empty<IDocument>())
{ {
<div> <div>
<h3 class="mb-0"><a href="@Context.GetLink(post)">@post.GetString("Title")</a></h3> <h3 class="mb-0"><a href="@Context.GetLink(post)">@post.GetString("Title")</a></h3>
@ -19,7 +19,7 @@
@if (category != null) { @if (category != null) {
var categoryUrl = @Context.GetLink($"blog/{NormalizedPath.OptimizeFileName(category)}/index.html"); var categoryUrl = @Context.GetLink($"blog/{NormalizedPath.OptimizeFileName(category)}/index.html");
<span> <span>
to <a class="text-blue-800 underline" href="@categoryUrl"> to <a href="@categoryUrl">
@category @category
</a> </a>
</span> </span>

View File

@ -20,7 +20,7 @@
} }
@if (category != null) { @if (category != null) {
<span> <span>
to <a class="text-blue-800 underline" href="@Context.GetLink($"blog/{NormalizedPath.OptimizeFileName(@category)}/index.html")"> to <a href="@Context.GetLink($"blog/{NormalizedPath.OptimizeFileName(@category)}/index.html")">
@category @category
</a> </a>
</span> </span>

View File

@ -1,6 +1,9 @@
Title: CommandApp Title: CommandApp
Order: 2 Order: 2
Description: "**CommandApp** is the entry point for a *Spectre.Console.Cli* command line application. It is used to configure the settings and commands used for execution of the application." Description: "**CommandApp** is the entry point for a *Spectre.Console.Cli* command line application. It is used to configure the settings and commands used for execution of the application."
Reference:
- T:Spectre.Console.Cli.CommandApp
- T:Spectre.Console.Cli.CommandApp`1
--- ---
`CommandApp` is the entry point for a `Spectre.Console.Cli` command line application. It is used to configure the settings and commands used for execution of the application. Most `Spectre.Console.Cli` applications will need to specify a custom configuration using the `Configure` method. `CommandApp` is the entry point for a `Spectre.Console.Cli` command line application. It is used to configure the settings and commands used for execution of the application. Most `Spectre.Console.Cli` applications will need to specify a custom configuration using the `Configure` method.

View File

@ -1,9 +1,12 @@
Title: Creating Commands Title: Creating Commands
Order: 6 Order: 6
Description: "How to create commands for *Spectre.Console.Cli*" Description: "How to create commands for *Spectre.Console.Cli*"
Reference:
- T:Spectre.Console.Cli.AsyncCommand`1
- T:Spectre.Console.Cli.Command`1
--- ---
Commands in `Spectre.Console.Cli` are defined by creating a class that inherits from either `Spectre.Console.Cli.Command<TSettings>` or `Spectre.Console.Cli.AsyncCommand<TSettings>`. `Command<TSettings>` must implement an `Execute` method that returns an int where as `AsyncCommand<TSettings>` must implement `ExecuteAsync` returning `Task<int>`. Commands in `Spectre.Console.Cli` are defined by creating a class that inherits from either `Command<TSettings>` or `AsyncCommand<TSettings>`. `Command<TSettings>` must implement an `Execute` method that returns an int where as `AsyncCommand<TSettings>` must implement `ExecuteAsync` returning `Task<int>`.
```csharp ```csharp
public class HelloCommand : Command<HelloCommand.Settings> public class HelloCommand : Command<HelloCommand.Settings>

View File

@ -1,6 +1,10 @@
Title: Specifying Settings Title: Specifying Settings
Order: 5 Order: 5
Description: "How to define command line argument settings for your *Spectre.Console.Cli* Commands" Description: "How to define command line argument settings for your *Spectre.Console.Cli* Commands"
Reference:
- T:Spectre.Console.Cli.CommandSettings
- T:Spectre.Console.Cli.CommandArgumentAttribute
- T:Spectre.Console.Cli.CommandOptionAttribute
--- ---
Settings for `Spectre.Console.Cli` commands are defined via classes that inherit from `CommandSettings`. Attributes are used to indicate how the parser interprets the command line arguments and create a runtime instance of the settings to be used. Settings for `Spectre.Console.Cli` commands are defined via classes that inherit from `CommandSettings`. Attributes are used to indicate how the parser interprets the command line arguments and create a runtime instance of the settings to be used.

View File

@ -4,6 +4,10 @@ Description: "Exceptions aren't always readable when viewed in the terminal. You
Highlights: Highlights:
- Color coded output. - Color coded output.
- Shorten long identifiers and paths. - Shorten long identifiers and paths.
Reference:
- M:Spectre.Console.AnsiConsole.WriteException(System.Exception,Spectre.Console.ExceptionFormats)
- M:Spectre.Console.AnsiConsole.WriteException(System.Exception,Spectre.Console.ExceptionSettings)
--- ---
Exceptions aren't always readable when viewed in the terminal. Exceptions aren't always readable when viewed in the terminal.

View File

@ -1,4 +1,4 @@
Title: Welcome Title: Welcome!
Description: Spectre.Console is a .NET Standard 2.0 library that makes it easier to create beautiful console applications. Description: Spectre.Console is a .NET Standard 2.0 library that makes it easier to create beautiful console applications.
Order: 0 Order: 0
--- ---

View File

@ -4,13 +4,15 @@ Description: "*Spectre.Console* can update arbitrary widgets in-place."
Highlights: Highlights:
- Update tables or graphs with new updates. - Update tables or graphs with new updates.
- Create a custom progress bar that extends the existing control. - Create a custom progress bar that extends the existing control.
Reference:
- T:Spectre.Console.LiveDisplay
- M:Spectre.Console.AnsiConsole.Live(Spectre.Console.Rendering.IRenderable)
--- ---
Spectre.Console can update arbitrary widgets in-place. Spectre.Console can update arbitrary widgets in-place using the [Live Display](xref:T:Spectre.Console.LiveDisplay) widget.
<?# AsciiCast cast="live" /?> <?# AsciiCast cast="live" /?>
<?# Alert ?> <?# Alert ?>
The live display is not The live display is not
thread safe, and using it together with other interactive components such as thread safe, and using it together with other interactive components such as

View File

@ -6,6 +6,9 @@ Highlights:
- Custom styling of progress bars. - Custom styling of progress bars.
- Multiple predefined columns such as Throughput, Estimated Time Remaining, and more. - Multiple predefined columns such as Throughput, Estimated Time Remaining, and more.
- Fallback for non-interactive consoles such as CI runners. - Fallback for non-interactive consoles such as CI runners.
Reference:
- T:Spectre.Console.Progress
- M:Spectre.Console.AnsiConsole.Progress
--- ---
Spectre.Console can display information about long running tasks in the console. Spectre.Console can display information about long running tasks in the console.

View File

@ -5,6 +5,9 @@ Description: "*Spectre.Console* can display information about long running tasks
Highlights: Highlights:
- Custom spinner control for running tasks. - Custom spinner control for running tasks.
- Fallback for non-interactive consoles such as CI runners. - Fallback for non-interactive consoles such as CI runners.
Reference:
- T:Spectre.Console.Status
- M:Spectre.Console.AnsiConsole.Status
--- ---
Spectre.Console can display information about long running tasks in the console. Spectre.Console can display information about long running tasks in the console.

View File

@ -5,6 +5,10 @@ Highlights:
- Easily add *color*. - Easily add *color*.
- Add hyperlinks to for supported terminals. - Add hyperlinks to for supported terminals.
- Emoji 🚀 parsing. - Emoji 🚀 parsing.
Reference:
- M:Spectre.Console.AnsiConsole.Markup(System.String)
- M:Spectre.Console.AnsiConsole.MarkupLine(System.String)
- T:Spectre.Console.Markup
--- ---
The `Markup` class allows you to output rich text to the console. The `Markup` class allows you to output rich text to the console.

View File

@ -12,8 +12,7 @@ one or many items from a provided list.
<?# AsciiCast cast="multi-selection" /?> <?# AsciiCast cast="multi-selection" /?>
<?# Alert ?> The use of prompts <?# Alert ?> The use of prompts inside status or progress displays is not supported.
insides status or progress displays is not supported.
<?#/ Alert ?> <?#/ Alert ?>
## Usage ## Usage

View File

@ -1,6 +1,9 @@
Title: Selection Title: Selection
Order: 1 Order: 1
Description: "The **SelectionPrompt** can be used when you want the user to select a single item from a provided list." Description: "The **SelectionPrompt** can be used when you want the user to select a single item from a provided list."
Reference:
- T:Spectre.Console.SelectionPrompt`1
- M:Spectre.Console.AnsiConsole.Prompt``1(Spectre.Console.IPrompt{``0})
--- ---
The `SelectionPrompt` can be used when you want the user to select The `SelectionPrompt` can be used when you want the user to select

View File

@ -21,26 +21,15 @@ you can use the `Prompt<TResult>`.
## Confirmation ## Confirmation
```csharp <?# Example symbol="M:Prompt.Program.AskConfirmation" project="Prompt" /?>
if (!AnsiConsole.Confirm("Run example?"))
{
return;
}
```
```text ```text
Run example? [y/n] (y): _ Run prompt example? [y/n] (y): _
``` ```
## Simple ## Simple
```csharp <?# Example symbol="M:Prompt.Program.AskName" project="Prompt" /?>
// Ask for the user's name
string name = AnsiConsole.Ask<string>("What's your [green]name[/]?");
// Ask for the user's age
int age = AnsiConsole.Ask<int>("What's your [green]age[/]?");
```
```text ```text
What's your name? Patrik What's your name? Patrik
@ -49,15 +38,7 @@ What's your age? 37
## Choices ## Choices
```csharp <?# Example symbol="M:Prompt.Program.AskFruit" project="Prompt" /?>
var fruit = AnsiConsole.Prompt(
new TextPrompt<string>("What's your [green]favorite fruit[/]?")
.InvalidChoiceMessage("[red]That's not a valid fruit[/]")
.DefaultValue("Orange")
.AddChoice("Apple")
.AddChoice("Banana")
.AddChoice("Orange"));
```
```text ```text
What's your favorite fruit? [Apple/Banana/Orange] (Orange): _ What's your favorite fruit? [Apple/Banana/Orange] (Orange): _
@ -65,19 +46,7 @@ What's your favorite fruit? [Apple/Banana/Orange] (Orange): _
## Validation ## Validation
```csharp <?# Example symbol="M:Prompt.Program.AskAge" project="Prompt" /?>
var age = AnsiConsole.Prompt(
new TextPrompt<int>("What's the secret number?")
.Validate(age =>
{
return age switch
{
< 99 => ValidationResult.Error("[red]Too low[/]"),
> 99 => ValidationResult.Error("[red]Too high[/]"),
_ => ValidationResult.Success(),
};
}));
```
```text ```text
What's the secret number? 32 What's the secret number? 32
@ -89,12 +58,8 @@ What's the secret number? _
## Secrets ## Secrets
```csharp <?# Example symbol="M:Prompt.Program.AskPassword" project="Prompt" /?>
var password = AnsiConsole.Prompt(
new TextPrompt<string>("Enter [green]password[/]")
.PromptStyle("red")
.Secret());
```
```text ```text
Enter password: ************_ Enter password: ************_
@ -102,11 +67,7 @@ Enter password: ************_
## Optional ## Optional
```csharp <?# Example symbol="M:Prompt.Program.AskColor" project="Prompt" /?>
var color = AnsiConsole.Prompt(
new TextPrompt<string>("[grey][[Optional]][/] [green]Favorite color[/]?")
.AllowEmpty());
```
```text ```text
[Optional] Favorite color? _ [Optional] Favorite color? _

View File

@ -1,17 +1,15 @@
const defaultTheme = require("tailwindcss/defaultTheme"); const defaultTheme = require("tailwindcss/defaultTheme");
const colors = require("tailwindcss/colors");
module.exports = { module.exports = {
purge: ["./output/**/*.html"], content: ["./output/**/*.html"],
mode: 'jit', darkMode: "class",
darkMode: false, // or 'media' or 'class'
theme: { theme: {
extend: { extend: {
fontFamily: { fontFamily: {
sans: ["Poppins", ...defaultTheme.fontFamily.sans], sans: ["Poppins", ...defaultTheme.fontFamily.sans],
mono: ["ui-monospace", "Cascadia Mono", "Cascadia Code", "Menlo", "Consolas", "Liberation Mono", "Lucida Console", "WebCascadiaMonoPL", "monospace"], mono: ["ui-monospace", "Cascadia Mono", "Cascadia Code", "Menlo", "Consolas", "Liberation Mono", "Lucida Console", "WebCascadiaMonoPL", "monospace"],
}, },
container: { container: ({theme}) => ({
center: true, center: true,
padding: { padding: {
DEFAULT: "2rem", DEFAULT: "2rem",
@ -20,35 +18,61 @@ module.exports = {
xl: "5rem", xl: "5rem",
"2xl": "6rem", "2xl": "6rem",
}, },
}, screens: {
sm: theme("spacing.full"),
md: theme("spacing.full"),
lg: "1280px",
xl: "1400px",
},
}),
typography: (theme) => ({ typography: (theme) => ({
DEFAULT: { DEFAULT: {
css: { css: {
color: defaultTheme.colors.gray[900], h2: {
a: { marginTop: '1.4em',
color: defaultTheme.colors.blue[700], marginBottom: `.2em`,
fontWeight: defaultTheme.fontWeight.normal,
"&:hover": {
color: defaultTheme.colors.blue[600],
},
}, },
"pre code": { h3: {
fontWeight: defaultTheme.fontWeight.light, marginTop: '2.4em',
lineHeight: '1.4',
},
pre: {
fontWeight: theme("fontWeight.light"),
borderRadius: theme('borderRadius.xl'),
borderWidth: '1px',
borderColor: theme('colors.slate.700'),
color: theme('colors.slate.50'),
boxShadow: theme('boxShadow.md'),
lineHeight: '1.3',
},
'p + pre, p + asciinema-player pre': {
marginTop: `${-4 / 14}em`,
},
'pre + pre': {
marginTop: `${-16 / 14}em`,
}, },
code: { code: {
color: defaultTheme.colors.blue[900], fontWeight: theme("fontWeight.normal"),
fontWeight: defaultTheme.fontWeight.normal, fontSize: 'inherit',
}, },
"code::before": { "code::before": {
content: "&nbsp;", content: "&nbsp;",
}, },
"code::after": { "code::after": {
content: "&nbsp;", content: "&nbsp;",
}, },
h2: { td: {
marginTop: "1em", overflowWrap: "anywhere",
marginBottom: ".5em" },
} a: {
fontWeight: theme('fontWeight.light'),
textDecoration: 'none',
borderBottom: `1px solid ${theme('colors.teal.600')}`,
},
'a:hover': {
borderBottomWidth: '2px',
},
}, },
}, },
}), }),

File diff suppressed because it is too large Load Diff

View File

@ -5,6 +5,8 @@ Highlights:
- Custom colors - Custom colors
- Labels - Labels
- Use your own data with a converter. - Use your own data with a converter.
Reference: T:Spectre.Console.BarChart
--- ---
Use `BarChart` to render bar charts to the console. Use `BarChart` to render bar charts to the console.

View File

@ -6,6 +6,8 @@ Highlights:
- Include highlighted events. - Include highlighted events.
- Culture aware. - Culture aware.
- Custom headers. - Custom headers.
Reference: T:Spectre.Console.Calendar
--- ---
The `Calendar` is used to render a calendar to the terminal. The `Calendar` is used to render a calendar to the terminal.

View File

@ -1,6 +1,7 @@
Title: Canvas Image Title: Canvas Image
Order: 70 Order: 70
Description: "Use *ImageSharp* to parse images and render them as Ascii art to the console." Description: "Use *ImageSharp* to parse images and render them as Ascii art to the console."
Reference: T:Spectre.Console.CanvasImage
--- ---
To add [ImageSharp](https://github.com/SixLabors/ImageSharp) superpowers to To add [ImageSharp](https://github.com/SixLabors/ImageSharp) superpowers to

View File

@ -1,6 +1,7 @@
Title: Canvas Title: Canvas
Order: 60 Order: 60
Description: "**Canvas** is a widget that allows you to render arbitrary pixels to the console." Description: "**Canvas** is a widget that allows you to render arbitrary pixels to the console."
Reference: T:Spectre.Console.Canvas
--- ---
`Canvas` is a widget that allows you to render arbitrary "pixels" `Canvas` is a widget that allows you to render arbitrary "pixels"

View File

@ -2,6 +2,7 @@ Title: Figlet
Order: 50 Order: 50
RedirectFrom: figlet RedirectFrom: figlet
Description: "*Spectre.Console* can render FIGlet text by using the **FigletText** class." Description: "*Spectre.Console* can render FIGlet text by using the **FigletText** class."
Reference: T:Spectre.Console.FigletText
--- ---
Spectre.Console can render [FIGlet](http://www.figlet.org/) text by using the `FigletText` class. Spectre.Console can render [FIGlet](http://www.figlet.org/) text by using the `FigletText` class.

View File

@ -5,6 +5,7 @@ Description: "The **Rule** class is used to render a horizontal rule (line) to t
Highlights: Highlights:
- Custom colors for line and title. - Custom colors for line and title.
- Specify left, center or right aligned title. - Specify left, center or right aligned title.
Reference: T:Spectre.Console.Rule
--- ---

View File

@ -2,6 +2,7 @@ Title: Table
Order: 0 Order: 0
RedirectFrom: tables RedirectFrom: tables
Description: "Tables are a perfect way of displaying tabular data in a terminal. *Spectre.Console* is super smart about rendering tables and will adjust all columns to fit whatever is inside them." Description: "Tables are a perfect way of displaying tabular data in a terminal. *Spectre.Console* is super smart about rendering tables and will adjust all columns to fit whatever is inside them."
Reference: T:Spectre.Console.Table
--- ---
Tables are a perfect way of displaying tabular data in a terminal. Tables are a perfect way of displaying tabular data in a terminal.

View File

@ -4,6 +4,8 @@ Description: "The **Tree** widget can be used to render hierarchical data."
Highlights: Highlights:
- Custom colors and styles for guidelines. - Custom colors and styles for guidelines.
- Include any *Spectre.Console* widgets as child nodes. - Include any *Spectre.Console* widgets as child nodes.
Reference: T:Spectre.Console.Tree
--- ---
The `Tree` widget can be used to render hierarchical data. The `Tree` widget can be used to render hierarchical data.

1154
docs/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -4,7 +4,7 @@
"description": "Docs for Spectre.Console", "description": "Docs for Spectre.Console",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
"build:tailwind": "tailwind build ./input/tailwind.css -c ./input/tailwind.config.js -o ./output/assets/styles.css", "build:tailwind": "tailwind build -i ./input/tailwind.css -c ./input/tailwind.config.js -o ./output/assets/styles.css",
"build": "cross-env NODE_ENV=production dotnet run -- -o public" "build": "cross-env NODE_ENV=production dotnet run -- -o public"
}, },
"repository": { "repository": {
@ -12,14 +12,14 @@
}, },
"license": "MIT", "license": "MIT",
"devDependencies": { "devDependencies": {
"@tailwindcss/forms": "^0.3.4", "@tailwindcss/forms": "^0.4.0",
"@tailwindcss/typography": "^0.4.1", "@tailwindcss/typography": "^0.5.1",
"asciinema-player": "^3.0.0-rc.1", "asciinema-player": "^3.0.0-beta.4",
"autoprefixer": "^10.4.0", "autoprefixer": "^10.4.0",
"cross-env": "^7.0.3", "cross-env": "^7.0.3",
"playwright": "^1.16.3", "playwright": "^1.18.1",
"postcss": "^8.4.4", "postcss": "^8.4.4",
"postcss-cli": "^8.3.1", "postcss-cli": "^8.3.1",
"tailwindcss": "^2.2.19" "tailwindcss": "^3.0.19"
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -2,14 +2,26 @@ namespace Docs
{ {
public static class Constants public static class Constants
{ {
public const string NoContainer = nameof(NoContainer);
public const string NoSidebar = nameof(NoSidebar);
public const string NoLink = nameof(NoLink); public const string NoLink = nameof(NoLink);
public const string Topic = nameof(Topic);
public const string EditLink = nameof(EditLink); public const string EditLink = nameof(EditLink);
public const string Description = nameof(Description); public const string Description = nameof(Description);
public const string Hidden = nameof(Hidden); public const string Hidden = nameof(Hidden);
/// <summary>
/// Indicates where to locate source files for the API documentation.
/// By default the globbing pattern "src/**/{!bin,!obj,!packages,!*.Tests,}/**/*.cs"
/// is used which searches for all "*.cs" files at any depth under a "src" folder
/// but not under "bin", "obj", "packages" or "Tests" folders. You can specify
/// your own globbing pattern (or more than one globbing pattern) if your source
/// files are found elsewhere.
/// </summary>
/// <type><see cref="string"/> or <c>IEnumerable&lt;string&gt;</c></type>
public const string SourceFiles = nameof(SourceFiles);
public const string ExampleSourceFiles = nameof(ExampleSourceFiles);
public const string ApiReference = "Reference";
public static class Emojis public static class Emojis
{ {
public const string Root = "EMOJIS_ROOT"; public const string Root = "EMOJIS_ROOT";
@ -33,12 +45,5 @@ namespace Docs
public const string GitHubToken = "GITHUB_TOKEN"; public const string GitHubToken = "GITHUB_TOKEN";
public const string TargetBranch = "DEPLOYMENT_TARGET_BRANCH"; public const string TargetBranch = "DEPLOYMENT_TARGET_BRANCH";
} }
public static class Sections
{
public const string Splash = nameof(Splash);
public const string Sidebar = nameof(Sidebar);
public const string Subtitle = nameof(Subtitle);
}
} }
} }

View File

@ -1,9 +1,7 @@
using Statiq.App; using Statiq.App;
using Statiq.Common; using Statiq.Common;
using System.Collections.Generic;
using System.Linq;
namespace Docs namespace Docs.Extensions
{ {
public static class BootstrapperExtensions public static class BootstrapperExtensions
{ {

View File

@ -1,8 +1,9 @@
using Statiq.Common;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Statiq.CodeAnalysis;
using Statiq.Common;
namespace Docs namespace Docs.Extensions
{ {
public static class DocumentExtensions public static class DocumentExtensions
{ {
@ -25,5 +26,40 @@ namespace Docs
{ {
return source.Where(x => x.IsVisible()); return source.Where(x => x.IsVisible());
} }
public static string GetModifiers(this IDocument document) => document.GetModifiers(false);
public static string GetModifiers(this IDocument document, bool skipStatic)
{
var modifiers = new List<string>();
var accessibility = document.GetString(CodeAnalysisKeys.Accessibility).ToLower();
if (accessibility != "public")
{
modifiers.Add(accessibility);
}
// for some things, like ExtensionMethods, static will always be set.
if (!skipStatic && document.GetBool(CodeAnalysisKeys.IsStatic))
{
modifiers.Add("static");
}
if (document.GetBool(CodeAnalysisKeys.IsVirtual))
{
modifiers.Add("virtual");
}
if (document.GetBool(CodeAnalysisKeys.IsAbstract))
{
modifiers.Add("abstract");
}
if (document.GetBool(CodeAnalysisKeys.IsOverride))
{
modifiers.Add("override");
}
return string.Join(' ', modifiers);
}
} }
} }

View File

@ -0,0 +1,228 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Net;
using Docs.Pipelines;
using Microsoft.AspNetCore.Html;
using Statiq.CodeAnalysis;
using Statiq.Common;
namespace Docs.Extensions;
public static class IExecutionContextExtensions
{
private static readonly object _executionCacheLock = new();
private static readonly ConcurrentDictionary<string, object> _executionCache = new();
private static Guid _lastExecutionId = Guid.Empty;
public record SidebarItem(IDocument Node, string Title, bool ShowLink, ImmutableList<SidebarItem> Leafs);
public static bool TryGetCommentIdDocument(this IExecutionContext context, string commentId, out IDocument document,
out string error)
{
context.ThrowIfNull(nameof(context));
if (string.IsNullOrWhiteSpace(commentId))
{
document = default;
error = default;
return false;
}
var documents = context.GetExecutionCache(nameof(TryGetCommentIdDocument), ctx => ctx.Outputs.FromPipeline(nameof(ExampleSyntax)).Flatten());
var matches = documents
.Where(x => x.GetString(CodeAnalysisKeys.CommentId)?.Equals(commentId, StringComparison.OrdinalIgnoreCase) == true)
.ToImmutableDocumentArray();
if (matches.Length == 1)
{
document = matches[0];
error = default;
return true;
}
document = default;
error = matches.Length > 1
? $"Multiple ambiguous matching documents found for commentId \"{commentId}\""
: $"Couldn't find document with xref \"{commentId}\"";
return false;
}
public static T GetExecutionCache<T>(this IExecutionContext context, string key, Func<IExecutionContext, T> getter)
{
lock (_executionCacheLock)
{
if (_lastExecutionId != context.ExecutionId)
{
_executionCache.Clear();
_lastExecutionId = context.ExecutionId;
}
return (T)_executionCache.GetOrAdd(key, valueFactory: _ => getter.Invoke(context));
}
}
public static NormalizedPath FindCard(this IExecutionContext context, Guid docId)
{
var cardLookups = context.GetExecutionCache(nameof(FindCard), ctx =>
{
return ctx.Outputs
.Select(i => new { DocId = i.GetString("DocId"), Destination = i.Destination })
.Where(i => i.DocId != null)
.ToDictionary(i => i.DocId, i => i.Destination);
});
return !cardLookups.ContainsKey(docId.ToString()) ? null : cardLookups[docId.ToString()];
}
public static SidebarItem GetSidebar(this IExecutionContext context)
{
return context.GetExecutionCache(nameof(GetSidebar), ctx =>
{
var outputPages = ctx.OutputPages;
var root = outputPages["index.html"][0];
var children = outputPages
.GetChildrenOf(root)
.OrderBy(i => i.GetInt("Order"))
.OnlyVisible().Select(child =>
{
var showLink = child.ShowLink();
var children = outputPages
.GetChildrenOf(child)
.OnlyVisible()
.Select(subChild =>
new SidebarItem(subChild, subChild.GetTitle(), true, ImmutableList<SidebarItem>.Empty))
.ToImmutableList();
return new SidebarItem(child, child.GetTitle(), showLink, children);
}).ToImmutableList();
return new SidebarItem(root, root.GetTitle(), false, children);
});
}
public static HtmlString GetTypeLink(this IExecutionContext context, IDocument document) =>
context.GetTypeLink(document, null, true);
public static HtmlString GetTypeLink(this IExecutionContext context, IDocument document, bool linkTypeArguments) =>
context.GetTypeLink(document, null, linkTypeArguments);
public static HtmlString GetTypeLink(this IExecutionContext context, IDocument document, string name) =>
context.GetTypeLink(document, name, true);
public static HtmlString GetTypeLink(this IExecutionContext context, IDocument document, string name,
bool linkTypeArguments)
{
name ??= document.GetString(CodeAnalysisKeys.DisplayName);
// Link nullable types to their type argument
if (document.GetString(CodeAnalysisKeys.Name) == "Nullable")
{
var nullableType = document.GetDocumentList(CodeAnalysisKeys.TypeArguments)?.FirstOrDefault();
if (nullableType != null)
{
return context.GetTypeLink(nullableType, name);
}
}
// If it wasn't nullable, format the name
name = context.GetFormattedHtmlName(name);
// Link the type and type parameters separately for generic types
IReadOnlyList<IDocument> typeArguments = document.GetDocumentList(CodeAnalysisKeys.TypeArguments);
if (typeArguments?.Count > 0)
{
// Link to the original definition of the generic type
document = document.GetDocument(CodeAnalysisKeys.OriginalDefinition) ?? document;
if (linkTypeArguments)
{
// Get the type argument positions
var begin = name.IndexOf("<wbr>&lt;", StringComparison.Ordinal) + 9;
var openParen = name.IndexOf("&gt;<wbr>(", StringComparison.Ordinal);
var end = name.LastIndexOf("&gt;<wbr>", openParen == -1 ? name.Length : openParen,
StringComparison.Ordinal); // Don't look past the opening paren if there is one
if (begin == -1 || end == -1)
{
return new HtmlString(name);
}
// Remove existing type arguments and insert linked type arguments (do this first to preserve original indexes)
name = name
.Remove(begin, end - begin)
.Insert(begin,
string.Join(", <wbr>", typeArguments.Select(x => context.GetTypeLink(x, true).Value)));
// Insert the link for the type
if (!document.Destination.IsNullOrEmpty)
{
name = name.Insert(begin - 9, "</a>").Insert(0, $"<a href=\"{context.GetLink(document)}\">");
}
return new HtmlString(name);
}
}
// If it's a type parameter, create an anchor link to the declaring type's original definition
if (document.GetString(CodeAnalysisKeys.Kind) == "TypeParameter")
{
var declaringType = document.GetDocument(CodeAnalysisKeys.DeclaringType)
?.GetDocument(CodeAnalysisKeys.OriginalDefinition);
if (declaringType != null)
{
return new HtmlString(declaringType.Destination.IsNullOrEmpty
? name
: $"<a href=\"{context.GetLink(declaringType)}#typeparam-{document["Name"]}\">{name}</a>");
}
}
return new HtmlString(document.Destination.IsNullOrEmpty
? name
: $"<a href=\"{context.GetLink(document)}\">{name}</a>");
}
/// <summary>
/// Formats a symbol or other name by encoding HTML characters and
/// adding HTML break elements as appropriate.
/// </summary>
/// <param name="context">The execution context.</param>
/// <param name="name">The name to format.</param>
/// <returns>The name formatted for use in HTML.</returns>
public static string GetFormattedHtmlName(this IExecutionContext context, string name)
{
if (name == null)
{
return string.Empty;
}
// Encode and replace .()<> with word break opportunities
name = WebUtility.HtmlEncode(name)
.Replace(".", "<wbr>.")
.Replace("(", "<wbr>(")
.Replace(")", ")<wbr>")
.Replace(", ", ", <wbr>")
.Replace("&lt;", "<wbr>&lt;")
.Replace("&gt;", "&gt;<wbr>");
// Add additional break opportunities in long un-broken segments
var segments = name.Split(new[] { "<wbr>" }, StringSplitOptions.None).ToList();
var replaced = false;
for (var c = 0; c < segments.Count; c++)
{
if (segments[c].Length > 20)
{
segments[c] = new string(segments[c]
.SelectMany(
(x, i) => char.IsUpper(x) && i != 0 ? new[] { '<', 'w', 'b', 'r', '>', x } : new[] { x })
.ToArray());
replaced = true;
}
}
return replaced ? string.Join("<wbr>", segments) : name;
}
}

View File

@ -1,4 +1,4 @@
namespace Docs namespace Docs.Extensions
{ {
public static class StringExtensions public static class StringExtensions
{ {

View File

@ -1,6 +1,4 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text;
using Newtonsoft.Json; using Newtonsoft.Json;
namespace Docs.Models namespace Docs.Models

View File

@ -0,0 +1,151 @@
using System.Linq;
using System.Net;
using Docs.Utilities;
using Microsoft.Extensions.DependencyInjection;
using Statiq.CodeAnalysis;
using Statiq.Common;
using Statiq.Core;
using Statiq.Web;
using Statiq.Web.Pipelines;
namespace Docs.Pipelines;
/// <summary>
/// Loads source files.
/// </summary>
public class Code : Pipeline
{
public Code()
{
InputModules = new ModuleList(
new ReadFiles(
Config.FromSettings(settings
=> settings.GetList<string>(Constants.SourceFiles).AsEnumerable())));
}
}
/// <summary>
/// Loads source files.
/// </summary>
public class ExampleCode : Pipeline
{
public ExampleCode()
{
Dependencies.Add(nameof(Code));
InputModules = new ModuleList(
new ReadFiles(
Config.FromSettings(settings
=> settings.GetList<string>(Constants.ExampleSourceFiles).AsEnumerable())));
}
}
/// <summary>
/// Uses Roslyn to analyze any source files loaded in the previous
/// pipeline along with any specified assemblies. This pipeline
/// results in documents that represent Roslyn symbols.
/// </summary>
public class ExampleSyntax : Pipeline
{
public ExampleSyntax()
{
Dependencies.Add(nameof(ExampleCode));
DependencyOf.Add(nameof(Content));
ProcessModules = new ModuleList
{
new ConcatDocuments(nameof(Code)),
new ConcatDocuments(nameof(ExampleCode)),
new CacheDocuments(
new AnalyzeCSharp()
.WhereNamespaces(true)
.WherePublic()
.WithCssClasses("code", "cs")
.WithDestinationPrefix("syntax")
.WithAssemblySymbols()
// we need to load Spectre.Console for compiling, but we don't need to process it in Statiq
.WhereNamespaces(i => !i.StartsWith("Spectre.Console"))
.WithImplicitInheritDoc(false),
new ExecuteConfig(Config.FromDocument((doc, _) =>
{
// Add metadata
var metadataItems = new MetadataItems
{
// Calculate an xref that includes a "api-" prefix to avoid collisions
{ WebKeys.Xref, "syntax-" + doc.GetString(CodeAnalysisKeys.CommentId) },
};
var contentProvider = doc.ContentProvider;
return doc.Clone(metadataItems, contentProvider);
}))).WithoutSourceMapping()
};
}
}
/// <summary>
/// Generates API documentation pipeline.
/// </summary>
public class Api : Pipeline
{
public Api()
{
Dependencies.Add(nameof(Code));
DependencyOf.Add(nameof(Content));
ProcessModules = new ModuleList
{
new ConcatDocuments(nameof(Code)),
new CacheDocuments(
new AnalyzeCSharp()
.WhereNamespaces(ns => ns.StartsWith("Spectre.Console") && !ns.Contains("Analyzer") &&
!ns.Contains("Testing") && !ns.Contains("Examples"))
.WherePublic(true)
.WithCssClasses("code", "cs")
.WithDestinationPrefix("api")
.WithAssemblySymbols()
.WithImplicitInheritDoc(false),
new ExecuteConfig(Config.FromDocument((doc, ctx) =>
{
// Calculate a type name to link lookup for auto linking
string name = null;
var kind = doc.GetString(CodeAnalysisKeys.Kind);
switch (kind)
{
case "NamedType":
name = doc.GetString(CodeAnalysisKeys.DisplayName);
break;
case "Method":
var containingType = doc.GetDocument(CodeAnalysisKeys.ContainingType);
if (containingType != null)
{
name =
$"{containingType.GetString(CodeAnalysisKeys.DisplayName)}.{doc.GetString(CodeAnalysisKeys.DisplayName)}";
}
break;
}
if (name != null)
{
var typeNameLinks = ctx.GetRequiredService<TypeNameLinks>();
typeNameLinks.Links.AddOrUpdate(WebUtility.HtmlEncode(name), ctx.GetLink(doc),
(_, _) => string.Empty);
}
// Add metadata
var metadataItems = new MetadataItems
{
{ WebKeys.Xref, doc.GetString(CodeAnalysisKeys.CommentId) },
{ WebKeys.Layout, "api/_layout.cshtml" },
{ Constants.Hidden, true }
};
var contentProvider = doc.ContentProvider.CloneWithMediaType(MediaTypes.Html);
metadataItems.Add(WebKeys.ContentType, ContentType.Content);
return doc.Clone(metadataItems, contentProvider);
}))).WithoutSourceMapping()
};
}
}

View File

@ -1,5 +1,3 @@
using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using Docs.Models; using Docs.Models;
using Statiq.Common; using Statiq.Common;
@ -14,7 +12,7 @@ namespace Docs.Pipelines
InputModules = new ModuleList InputModules = new ModuleList
{ {
new ExecuteConfig( new ExecuteConfig(
Config.FromContext(ctx => { Config.FromContext(_ => {
return new ReadWeb(Constants.Colors.Url); return new ReadWeb(Constants.Colors.Url);
})) }))
}; };
@ -22,7 +20,7 @@ namespace Docs.Pipelines
ProcessModules = new ModuleList ProcessModules = new ModuleList
{ {
new ExecuteConfig( new ExecuteConfig(
Config.FromDocument(async (doc, ctx) => Config.FromDocument(async (doc, _) =>
{ {
var data = Color.Parse(await doc.GetContentStringAsync()).ToList(); var data = Color.Parse(await doc.GetContentStringAsync()).ToList();
return data.ToDocument(Constants.Colors.Root); return data.ToDocument(Constants.Colors.Root);

View File

@ -1,10 +1,9 @@
using Statiq.Common; using Statiq.Common;
using Statiq.Core;
using Statiq.Web.GitHub; using Statiq.Web.GitHub;
namespace Docs.Pipelines namespace Docs.Pipelines
{ {
public class DeploymentPipeline : Pipeline public class DeploymentPipeline : Statiq.Core.Pipeline
{ {
public DeploymentPipeline() public DeploymentPipeline()
{ {

View File

@ -1,4 +1,3 @@
using System.Collections.Generic;
using Docs.Models; using Docs.Models;
using Docs.Modules; using Docs.Modules;
using Statiq.Common; using Statiq.Common;
@ -13,7 +12,7 @@ namespace Docs.Pipelines
InputModules = new ModuleList InputModules = new ModuleList
{ {
new ExecuteConfig( new ExecuteConfig(
Config.FromContext(ctx => { Config.FromContext(_ => {
return new ReadEmbedded( return new ReadEmbedded(
typeof(EmojiPipeline).Assembly, typeof(EmojiPipeline).Assembly,
"Docs/src/Data/emojis.json"); "Docs/src/Data/emojis.json");
@ -23,7 +22,7 @@ namespace Docs.Pipelines
ProcessModules = new ModuleList ProcessModules = new ModuleList
{ {
new ExecuteConfig( new ExecuteConfig(
Config.FromDocument(async (doc, ctx) => Config.FromDocument(async (doc, _) =>
{ {
var data = Emoji.Parse(await doc.GetContentStringAsync()); var data = Emoji.Parse(await doc.GetContentStringAsync());
return data.ToDocument(Constants.Emojis.Root); return data.ToDocument(Constants.Emojis.Root);

View File

@ -1,6 +1,5 @@
using System.Collections.Generic; using System.Collections.Generic;
using Statiq.Common; using Statiq.Common;
using System.Xml.Linq;
namespace Docs.Shortcodes namespace Docs.Shortcodes
{ {
@ -8,7 +7,6 @@ namespace Docs.Shortcodes
{ {
public override ShortcodeResult Execute(KeyValuePair<string, string>[] args, string content, IDocument document, IExecutionContext context) public override ShortcodeResult Execute(KeyValuePair<string, string>[] args, string content, IDocument document, IExecutionContext context)
{ {
return $"<div class=\"alert-warning\">{content}</div>"; return $"<div class=\"alert-warning\">{content}</div>";
} }
} }

View File

@ -1,6 +1,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using Statiq.Common; using Statiq.Common;
using System.Xml.Linq; using System.Xml.Linq;
using Docs.Extensions;
namespace Docs.Shortcodes namespace Docs.Shortcodes
{ {

View File

@ -1,4 +1,3 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Statiq.Common; using Statiq.Common;
@ -10,8 +9,6 @@ namespace Docs.Shortcodes
{ {
public class ColorTableShortcode : SyncShortcode public class ColorTableShortcode : SyncShortcode
{ {
private const string ColorStyle = "display: inline-block;width: 60px; height: 15px;";
public override ShortcodeResult Execute(KeyValuePair<string, string>[] args, string content, IDocument document, IExecutionContext context) public override ShortcodeResult Execute(KeyValuePair<string, string>[] args, string content, IDocument document, IExecutionContext context)
{ {
// Get the definition. // Get the definition.

View File

@ -1,4 +1,3 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Statiq.Common; using Statiq.Common;
@ -31,7 +30,6 @@ namespace Docs.Shortcodes
foreach (var emoji in emojis) foreach (var emoji in emojis)
{ {
var code = emoji.Code.Replace("U+0000", "U+").Replace("U+000", "U+");
var icon = $"&#x{emoji.Code.Replace("U+", string.Empty)};"; var icon = $"&#x{emoji.Code.Replace("U+", string.Empty)};";
var row = new XElement("tr", new XAttribute("class", "search-row")); var row = new XElement("tr", new XAttribute("class", "search-row"));

View File

@ -0,0 +1,43 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Docs.Extensions;
using Docs.Utilities;
using Microsoft.CodeAnalysis;
using Statiq.CodeAnalysis;
using Statiq.Common;
namespace Docs.Shortcodes;
public class ExampleSnippet : Shortcode
{
protected const string Solution = nameof(Solution);
protected const string Project = nameof(Project);
protected const string Symbol = nameof(Symbol);
protected const string BodyOnly = nameof(BodyOnly);
public override async Task<ShortcodeResult> ExecuteAsync(KeyValuePair<string, string>[] args, string content,
IDocument document, IExecutionContext context)
{
var props = args.ToDictionary(Solution, Project, Symbol, BodyOnly);
var symbolName = props.GetString(Symbol);
var bodyOnly = props.Get<bool?>(BodyOnly) ?? symbolName.StartsWith("m:", StringComparison.InvariantCultureIgnoreCase);
if (!context.TryGetCommentIdDocument(symbolName, out var apiDocument, out _))
{
return string.Empty;
}
var options = HighlightService.HighlightOption.All;
if (bodyOnly)
{
options = HighlightService.HighlightOption.Body;
}
var comp = apiDocument.Get<Compilation>(CodeAnalysisKeys.Compilation);
var symbol = apiDocument.Get<ISymbol>(CodeAnalysisKeys.Symbol);
var highlightElement = await HighlightService.Highlight(comp, symbol, options);
ShortcodeResult shortcodeResult = $"<pre><code>{highlightElement}</code></pre>";
return shortcodeResult;
}
}

View File

@ -1,6 +1,5 @@
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages; using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
namespace Docs.SocialCards{ namespace Docs.SocialCards{
public class SocialCardModel : PageModel public class SocialCardModel : PageModel
@ -17,13 +16,6 @@ namespace Docs.SocialCards{
[BindProperty(Name = "footer", SupportsGet = true)] [BindProperty(Name = "footer", SupportsGet = true)]
public string Footer { get; set; } public string Footer { get; set; }
private readonly ILogger<SocialCardModel> _logger;
public SocialCardModel(ILogger<SocialCardModel> logger)
{
_logger = logger;
}
public void OnGet() public void OnGet()
{ {
} }

View File

@ -0,0 +1,234 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Classification;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
namespace Docs.Utilities;
internal static class HighlightService
{
internal enum HighlightOption
{
All,
Body
}
private static readonly AdhocWorkspace _emptyWorkspace = new();
public static async Task<string> Highlight(Compilation compilation, ISymbol symbol, HighlightOption option = HighlightOption.All)
{
var syntaxReference = symbol.DeclaringSyntaxReferences.FirstOrDefault();
if (syntaxReference == null)
{
return null;
}
var syntax = await syntaxReference.GetSyntaxAsync();
var indent = GetIndent(syntax.GetLeadingTrivia());
var model = compilation.GetSemanticModel(syntaxReference.SyntaxTree);
var methodWithBodySyntax = syntax as BaseMethodDeclarationSyntax;
TextSpan textSpan;
switch (option)
{
case HighlightOption.Body when methodWithBodySyntax is { Body: { } }:
{
syntax = methodWithBodySyntax.Body;
indent = GetIndent(methodWithBodySyntax.Body.Statements.First().GetLeadingTrivia());
textSpan = TextSpan.FromBounds(syntax.Span.Start + 1, syntax.Span.End - 1);
break;
}
case HighlightOption.Body when methodWithBodySyntax is { ExpressionBody: { } }:
{
syntax = methodWithBodySyntax.ExpressionBody;
textSpan = syntax.Span;
break;
}
case HighlightOption.All:
default:
textSpan = syntax.Span;
break;
}
var text = await syntaxReference.SyntaxTree.GetTextAsync();
// we need a workspace, but it seems it is only used to resolve a few services and nothing else so an empty one will suffice
return HighlightElement(_emptyWorkspace, model, text, textSpan, indent);
}
private static int GetIndent(SyntaxTriviaList leadingTrivia)
{
var whitespace = leadingTrivia.FirstOrDefault(i => i.Kind() == SyntaxKind.WhitespaceTrivia);
return whitespace == default ? 0 : whitespace.Span.Length;
}
private static string HighlightElement(Workspace workspace, SemanticModel semanticModel, SourceText fullSourceText,
TextSpan textSpan, int indent)
{
var classifiedSpans = Classifier.GetClassifiedSpans(semanticModel, textSpan, workspace);
return HighlightElement(classifiedSpans, fullSourceText, indent);
}
private static string HighlightElement(IEnumerable<ClassifiedSpan> classifiedSpans, SourceText fullSourceText, int indent)
{
var ranges = classifiedSpans.Select(classifiedSpan =>
new Range(classifiedSpan.ClassificationType, classifiedSpan.TextSpan, fullSourceText)).ToList();
// the classified text won't include the whitespace so we need to add to fill in those gaps.
ranges = FillGaps(fullSourceText, ranges).ToList();
var sb = new StringBuilder();
foreach (var range in ranges)
{
var cssClass = ClassificationTypeToPrismClass(range.ClassificationType);
if (string.IsNullOrWhiteSpace(cssClass))
{
sb.Append(range.Text);
}
else
{
// include the prism css class but also include the roslyn classification.
sb.Append(
$"<span class=\"token {cssClass} roslyn-{range.ClassificationType.Replace(" ", "-")}\">{range.Text}</span>");
}
}
// there might be a way to do this with roslyn, but for now we'll just normalize everything off of the length of the
// leading trivia of the element we are looking at.
var indentString = new string(' ', indent);
var allLines = sb.ToString()
.ReplaceLineEndings()
.Split(Environment.NewLine)
.Select(i => i.StartsWith(indentString) == false ? i : i[indent..]);
return string.Join(Environment.NewLine, allLines);
}
private static string ClassificationTypeToPrismClass(string rangeClassificationType)
{
if (rangeClassificationType == null)
return string.Empty;
switch (rangeClassificationType)
{
case ClassificationTypeNames.Identifier:
return "symbol";
case ClassificationTypeNames.LocalName:
return "variable";
case ClassificationTypeNames.ParameterName:
case ClassificationTypeNames.PropertyName:
case ClassificationTypeNames.EnumMemberName:
case ClassificationTypeNames.FieldName:
return "property";
case ClassificationTypeNames.ClassName:
case ClassificationTypeNames.StructName:
case ClassificationTypeNames.RecordClassName:
case ClassificationTypeNames.RecordStructName:
case ClassificationTypeNames.InterfaceName:
case ClassificationTypeNames.DelegateName:
case ClassificationTypeNames.EnumName:
case ClassificationTypeNames.ModuleName:
case ClassificationTypeNames.TypeParameterName:
return "title.class";
case ClassificationTypeNames.MethodName:
case ClassificationTypeNames.ExtensionMethodName:
return "title.function";
case ClassificationTypeNames.Comment:
return "comment";
case ClassificationTypeNames.Keyword:
case ClassificationTypeNames.ControlKeyword:
case ClassificationTypeNames.PreprocessorKeyword:
return "keyword";
case ClassificationTypeNames.StringLiteral:
case ClassificationTypeNames.VerbatimStringLiteral:
return "string";
case ClassificationTypeNames.NumericLiteral:
return "number";
case ClassificationTypeNames.Operator:
case ClassificationTypeNames.StringEscapeCharacter:
return "operator";
case ClassificationTypeNames.Punctuation:
return "punctuation";
case ClassificationTypeNames.StaticSymbol:
return string.Empty;
case ClassificationTypeNames.XmlDocCommentComment:
case ClassificationTypeNames.XmlDocCommentDelimiter:
case ClassificationTypeNames.XmlDocCommentName:
case ClassificationTypeNames.XmlDocCommentText:
case ClassificationTypeNames.XmlDocCommentAttributeName:
case ClassificationTypeNames.XmlDocCommentAttributeQuotes:
case ClassificationTypeNames.XmlDocCommentAttributeValue:
case ClassificationTypeNames.XmlDocCommentEntityReference:
case ClassificationTypeNames.XmlDocCommentProcessingInstruction:
case ClassificationTypeNames.XmlDocCommentCDataSection:
return "comment";
default:
return rangeClassificationType.Replace(" ", "-");
}
}
private static IEnumerable<Range> FillGaps(SourceText text, IList<Range> ranges)
{
const string WhitespaceClassification = null;
var current = ranges.First().TextSpan.Start;
var end = ranges.Last().TextSpan.End;
Range previous = null;
foreach (var range in ranges)
{
var start = range.TextSpan.Start;
if (start > current)
{
yield return new Range(WhitespaceClassification, TextSpan.FromBounds(current, start), text);
}
if (previous == null || range.TextSpan != previous.TextSpan)
{
yield return range;
}
previous = range;
current = range.TextSpan.End;
}
if (current < end)
{
yield return new Range(WhitespaceClassification, TextSpan.FromBounds(current, end), text);
}
}
private class Range
{
private ClassifiedSpan ClassifiedSpan { get; }
public string Text { get; }
public Range(string classification, TextSpan span, SourceText text) :
this(classification, span, text.GetSubText(span).ToString())
{
}
private Range(string classification, TextSpan span, string text) :
this(new ClassifiedSpan(classification, span), text)
{
}
private Range(ClassifiedSpan classifiedSpan, string text)
{
ClassifiedSpan = classifiedSpan;
Text = text;
}
public string ClassificationType => ClassifiedSpan.ClassificationType;
public TextSpan TextSpan => ClassifiedSpan.TextSpan;
}
}

View File

@ -0,0 +1,8 @@
using System.Collections.Concurrent;
namespace Docs.Utilities;
public class TypeNameLinks
{
public ConcurrentDictionary<string, string> Links { get; } = new ConcurrentDictionary<string, string>();
}

View File

@ -1,8 +1,5 @@
using System;
using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Reflection; using System.Reflection;
using System.Text;
namespace Docs.Utilities namespace Docs.Utilities
{ {

View File

@ -1,7 +1,7 @@
using System.ComponentModel; using System.ComponentModel;
using Spectre.Console.Cli; using Spectre.Console.Cli;
namespace Spectre.Console.Examples; namespace Delegates;
public static partial class Program public static partial class Program
{ {

View File

@ -1,6 +1,7 @@
using Spectre.Console;
using Spectre.Console.Cli; using Spectre.Console.Cli;
namespace Spectre.Console.Examples; namespace Delegates;
public static partial class Program public static partial class Program
{ {

View File

@ -2,7 +2,7 @@ using System.ComponentModel;
using Demo.Utilities; using Demo.Utilities;
using Spectre.Console.Cli; using Spectre.Console.Cli;
namespace Demo.Commands; namespace Demo.Commands.Add;
[Description("Add a NuGet package reference to the project.")] [Description("Add a NuGet package reference to the project.")]
public sealed class AddPackageCommand : Command<AddPackageCommand.Settings> public sealed class AddPackageCommand : Command<AddPackageCommand.Settings>

View File

@ -2,7 +2,7 @@ using System.ComponentModel;
using Demo.Utilities; using Demo.Utilities;
using Spectre.Console.Cli; using Spectre.Console.Cli;
namespace Demo.Commands; namespace Demo.Commands.Add;
public sealed class AddReferenceCommand : Command<AddReferenceCommand.Settings> public sealed class AddReferenceCommand : Command<AddReferenceCommand.Settings>
{ {

View File

@ -1,7 +1,7 @@
using System.ComponentModel; using System.ComponentModel;
using Spectre.Console.Cli; using Spectre.Console.Cli;
namespace Demo.Commands; namespace Demo.Commands.Add;
public abstract class AddSettings : CommandSettings public abstract class AddSettings : CommandSettings
{ {

View File

@ -2,7 +2,7 @@ using System.ComponentModel;
using Demo.Utilities; using Demo.Utilities;
using Spectre.Console.Cli; using Spectre.Console.Cli;
namespace Demo.Commands; namespace Demo.Commands.Run;
[Description("Build and run a .NET project output.")] [Description("Build and run a .NET project output.")]
public sealed class RunCommand : Command<RunCommand.Settings> public sealed class RunCommand : Command<RunCommand.Settings>

Some files were not shown because too many files have changed in this diff Show More