Update emoji support

* Add constants for emojis
* Move emoji shortcode rendering to Markup
* Add documentation
* Add example
* Add tests
This commit is contained in:
Patrik Svensson 2020-09-18 01:58:55 +02:00 committed by Patrik Svensson
parent 090b30f731
commit eeb3f967b6
38 changed files with 17680 additions and 1878 deletions

View File

@ -69,6 +69,7 @@ jobs:
dotnet example grid
dotnet example panel
dotnet example colors
dotnet example emojis
- name: Build
shell: bash

View File

@ -22,11 +22,23 @@
</None>
</ItemGroup>
<ItemGroup>
<None Remove="src\Data\emojis.json" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="src\Data\emojis.json" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Statiq.Web" Version="1.0.0-beta.5" />
<PackageReference Include="MinVer" PrivateAssets="All" Version="2.3.0" />
</ItemGroup>
<ItemGroup>
<Folder Include="input\assets\images\emojis\" />
</ItemGroup>
<Target Name="Versioning" BeforeTargets="MinVer">
<PropertyGroup Label="Build">
<MinVerDefaultPreReleasePhase>preview</MinVerDefaultPreReleasePhase>

View File

@ -19,6 +19,7 @@ namespace Docs
.ConfigureDeployment(deployBranch: "docs")
.AddShortcode("Children", typeof(ChildrenShortcode))
.AddShortcode("ColorTable", typeof(ColorTableShortcode))
.AddShortcode("EmojiTable", typeof(EmojiTableShortcode))
.AddPipelines()
.RunAsync();

View File

@ -128,14 +128,28 @@
{
IDocument root = OutputPages["index.html"].First();
<div class="sidebar-nav-item @(Document.IdEquals(root) ? "active" : null)">
@Html.DocumentLink(root)
@if(root.ShowLink())
{
@Html.DocumentLink(root)
}
else
{
@root.GetTitle()
}
</div>
@foreach (IDocument document in OutputPages.GetChildrenOf(root).OnlyVisible())
{
DocumentList<IDocument> documentChildren = OutputPages.GetChildrenOf(document);
<div class="sidebar-nav-item @(Document.IdEquals(document) ? "active" : null) @(documentChildren.Any() ? "has-children" : null)">
@Html.DocumentLink(document)
@if(document.ShowLink())
{
@Html.DocumentLink(document)
}
else
{
@document.GetTitle()
}
</div>
@if (documentChildren.OnlyVisible().Any())

View File

@ -0,0 +1,38 @@
Title: Emojis
Order: 3
---
Please note that what emojis that can be used is completely up to
the operating system and/or terminal you're using, and no guarantees
can be made of how it will look. Calculating the width of emojis
is also not an exact science in many ways, so milage might vary when
used in tables, panels or grids.
To ensure best compatibility, consider only using emojis introduced
before Unicode 13.0 that belongs in the `Emoji_Presentation` category
in the official emoji list at
https://www.unicode.org/Public/UCD/latest/ucd/emoji/emoji-data.txt
# Usage
```csharp
// Markup
AnsiConsole.MarkupLine("Hello :globe_showing_europe_africa:!");
// Constant
var hello = "Hello " + Emoji.Known.GlobeShowingEuropeAfrica;
```
# Replacing emojis in text
```csharp
var phrase = "Mmmm :birthday_cake:";
var rendered = Emoji.Replace(phrase);
```
# Emojis
_The images in the table below might not render correctly in your
browser for the same reasons mentioned in the `Compatibility` section._
<?# EmojiTable /?>

View File

@ -1,3 +1,10 @@
Title: Appendix
Order: 10
---
---
# Sections
* [Styles](xref:styles)
* [Colors](xref:colors)
* [Borders](xref:borders)
* [Emojis](xref:emojis)

View File

@ -2,8 +2,7 @@ Title: Markup
Order: 2
---
In `Spectre.Console` there's a class called `Markup` that
allows you to output rich text to the console.
The class `Markup` allows you to output rich text to the console.
# Syntax
@ -54,6 +53,16 @@ You can set the background color in markup by prefixing the color with
[default on blue]World[/]
```
# Rendering emojis
To output an emoji as part of markup, you can use emoji shortcodes.
```csharp
AnsiConsole.MarkupLine("Hello :globe_showing_europe_africa:!");
```
For a list of emoji, see the [Emojis](xref:styles) appendix section.
# Colors
For a list of colors, see the [Colors](xref:colors) appendix section.

View File

@ -1,14 +1,20 @@
namespace Docs
namespace Docs
{
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 Topic = nameof(Topic);
public const string EditLink = nameof(EditLink);
public const string Description = nameof(Description);
public const string Hidden = nameof(Hidden);
public static class Emojis
{
public const string Root = "EMOJIS_ROOT";
}
public static class Colors
{
public const string Url = "https://raw.githubusercontent.com/spectresystems/spectre.console/main/resources/scripts/Generator/Data/colors.json";

7946
docs/src/Data/emojis.json Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
using Statiq.Common;
using Statiq.Common;
using System.Collections.Generic;
using System.Linq;
@ -16,6 +16,11 @@ namespace Docs
return !document.GetBool(Constants.Hidden, false);
}
public static bool ShowLink(this IDocument document)
{
return !document.GetBool(Constants.NoLink, false);
}
public static IEnumerable<IDocument> OnlyVisible(this IEnumerable<IDocument> source)
{
return source.Where(x => x.IsVisible());

20
docs/src/Models/Emoji.cs Normal file
View File

@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Text;
using Newtonsoft.Json;
namespace Docs.Models
{
public sealed class Emoji
{
public string Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string Code { get; set; }
public static List<Emoji> Parse(string json)
{
return JsonConvert.DeserializeObject<List<Emoji>>(json);
}
}
}

View File

@ -0,0 +1,41 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using Statiq.Common;
namespace Docs.Modules
{
public sealed class ReadEmbedded : Module
{
private readonly System.Reflection.Assembly _assembly;
private readonly string _resource;
public ReadEmbedded(System.Reflection.Assembly assembly, string resource)
{
_assembly = assembly ?? throw new ArgumentNullException(nameof(assembly));
_resource = resource ?? throw new ArgumentNullException(nameof(resource));
}
protected override Task<IEnumerable<IDocument>> ExecuteContextAsync(IExecutionContext context)
{
return Task.FromResult((IEnumerable<IDocument>)new[]
{
context.CreateDocument(ReadResource()),
});
}
private Stream ReadResource()
{
var resourceName = _resource.Replace("/", ".");
var stream = _assembly.GetManifestResourceStream(resourceName);
if (stream == null)
{
throw new InvalidOperationException("Could not load manifest resource stream.");
}
return stream;
}
}
}

View File

@ -26,13 +26,8 @@ namespace Docs.Pipelines
new ExecuteConfig(
Config.FromDocument(async (doc, ctx) =>
{
var colors = Color.Parse(await doc.GetContentStringAsync()).ToList();
var definitions = new List<IDocument> { colors.ToDocument(Constants.Colors.Root) };
return doc.Clone(new MetadataDictionary
{
[Constants.Colors.Root] = definitions
});
var data = Color.Parse(await doc.GetContentStringAsync()).ToList();
return data.ToDocument(Constants.Colors.Root);
}))
};
}

View File

@ -0,0 +1,34 @@
using System.Collections.Generic;
using Docs.Models;
using Docs.Modules;
using Statiq.Common;
using Statiq.Core;
namespace Docs.Pipelines
{
public class EmojiPipeline : Pipeline
{
public EmojiPipeline()
{
InputModules = new ModuleList
{
new ExecuteConfig(
Config.FromContext(ctx => {
return new ReadEmbedded(
typeof(EmojiPipeline).Assembly,
"Docs/src/Data/emojis.json");
}))
};
ProcessModules = new ModuleList
{
new ExecuteConfig(
Config.FromDocument(async (doc, ctx) =>
{
var data = Emoji.Parse(await doc.GetContentStringAsync());
return data.ToDocument(Constants.Emojis.Root);
}))
};
}
}
}

View File

@ -17,11 +17,10 @@ namespace Docs.Shortcodes
// Get the definition.
var colors = context.Outputs
.FromPipeline(nameof(ColorsPipeline))
.First()
.GetChildren(Constants.Colors.Root)
.OfType<ObjectDocument<List<Color>>>()
.First().Object;
// Headers
var table = new XElement("table", new XAttribute("class", "table"));
var header = new XElement("tr", new XAttribute("class", "color-row"));
header.Add(new XElement("th", ""));

View File

@ -0,0 +1,45 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Statiq.Common;
using System.Xml.Linq;
using Docs.Pipelines;
using Docs.Models;
namespace Docs.Shortcodes
{
public class EmojiTableShortcode : SyncShortcode
{
public override ShortcodeResult Execute(KeyValuePair<string, string>[] args, string content, IDocument document, IExecutionContext context)
{
var emojis = context.Outputs
.FromPipeline(nameof(EmojiPipeline))
.OfType<ObjectDocument<List<Emoji>>>()
.First().Object;
// Headers
var table = new XElement("table", new XAttribute("class", "table"));
var header = new XElement("tr", new XAttribute("class", "emoji-row"));
header.Add(new XElement("th", ""));
header.Add(new XElement("th", "Markup"));
header.Add(new XElement("th", "Constant"));
table.Add(header);
foreach (var emoji in emojis)
{
var code = emoji.Code.Replace("U+0000", "U+").Replace("U+000", "U+");
var icon = string.Format("&#x{0};", emoji.Code.Replace("U+", string.Empty));
var row = new XElement("tr");
row.Add(new XElement("td", icon));
row.Add(new XElement("td", new XElement("code", $":{emoji.Id}:")));
row.Add(new XElement("td", new XElement("code", emoji.Name)));
table.Add(row);
}
return table.ToString()
.Replace("&amp;#x", "&#x");
}
}
}

View File

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<IsPackable>false</IsPackable>
<Description>Demonstrates how to render emojis.</Description>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Spectre.Console\Spectre.Console.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,17 @@
using System;
using Spectre.Console;
namespace Emojis
{
public static class Program
{
public static void Main(string[] args)
{
// Markup
AnsiConsole.Render(
new Panel("[yellow]Hello :globe_showing_europe_africa:![/]")
.RoundedBorder()
.SetHeader("Markup"));
}
}
}

View File

@ -12,8 +12,8 @@ namespace Info
.AddRow("[b]:artist_palette: Color system[/]", $"{AnsiConsole.Capabilities.ColorSystem}")
.AddRow("[b]:nail_polish: Supports ansi?[/]", $"{GetEmoji(AnsiConsole.Capabilities.SupportsAnsi)}")
.AddRow("[b]:top_hat: Legacy console?[/]", $"{GetEmoji(AnsiConsole.Capabilities.LegacyConsole)}")
.AddRow("[b]:left-right_arrow: Buffer width[/]", $"{AnsiConsole.Console.Width}")
.AddRow("[b]:up-down_arrow: Buffer height[/]", $"{AnsiConsole.Console.Height}");
.AddRow("[b]:left_right_arrow: Buffer width[/]", $"{AnsiConsole.Console.Width}")
.AddRow("[b]:up_down_arrow: Buffer height[/]", $"{AnsiConsole.Console.Height}");
AnsiConsole.Render(
new Panel(grid)

View File

@ -4,6 +4,7 @@
$Output = Join-Path $PSScriptRoot "Temp"
$Source = Join-Path $PSScriptRoot "/../../src/Spectre.Console"
$Docs = Join-Path $PSScriptRoot "/../../docs/src/Data"
if(!(Test-Path $Output -PathType Container)) {
New-Item -ItemType Directory -Path $Output | Out-Null
@ -11,7 +12,7 @@ if(!(Test-Path $Output -PathType Container)) {
# Generate the files
Push-Location Generator
&dotnet run -- emoji "$Output"
&dotnet run -- emoji "$Output" --input $Output
if(!$?) {
Pop-Location
Throw "An error occured when generating code."
@ -19,4 +20,5 @@ if(!$?) {
Pop-Location
# Copy the files to the correct location
Copy-Item (Join-Path "$Output" "Emoji.Generated.cs") -Destination "$Source/Emoji.Generated.cs"
Copy-Item (Join-Path "$Output" "Emoji.Generated.cs") -Destination "$Source/Emoji.Generated.cs"
Copy-Item (Join-Path "$Output" "emojis.json") -Destination "$Docs/emojis.json"

View File

@ -55,5 +55,8 @@ namespace Generator.Commands
{
[CommandArgument(0, "<OUTPUT>")]
public string Output { get; set; }
[CommandOption("-i|--input <PATH>")]
public string Input { get; set; }
}
}

View File

@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
@ -10,52 +11,72 @@ using Scriban.Runtime;
using Spectre.Cli;
using Spectre.IO;
using Path = Spectre.IO.Path;
using SpectreEnvironment = Spectre.IO.Environment;
namespace Generator.Commands
{
public sealed class EmojiGeneratorCommand : AsyncCommand<GeneratorCommandSettings>
{
private readonly IFileSystem _fileSystem;
private readonly IEnvironment _environment;
private readonly IHtmlParser _parser;
private readonly Dictionary<string, string> _templates = new Dictionary<string, string>
{
{ "Templates/Emoji.Generated.template", "Emoji.Generated.cs" },
{ "Templates/Emoji.Json.template", "emojis.json" },
};
public EmojiGeneratorCommand()
{
_fileSystem = new FileSystem();
_environment = new SpectreEnvironment();
_parser = new HtmlParser();
}
public override async Task<int> ExecuteAsync(CommandContext context, GeneratorCommandSettings settings)
{
var output = new DirectoryPath(settings.Output);
if (!_fileSystem.Directory.Exists(settings.Output))
{
_fileSystem.Directory.Create(settings.Output);
}
var templatePath = new FilePath("Templates/Emoji.Generated.template");
var stream = await FetchEmojis(settings);
var document = await _parser.ParseDocumentAsync(stream);
var emojis = Emoji.Parse(document).OrderBy(x => x.Name)
.Where(emoji => !emoji.HasCombinators)
.ToList();
var emojis = await FetchEmojis("http://www.unicode.org/emoji/charts/emoji-list.html");
// Render all templates
foreach (var (templateFilename, outputFilename) in _templates)
{
var result = await RenderTemplate(new FilePath(templateFilename), emojis);
var result = await RenderTemplate(templatePath, emojis);
var outputPath = output.CombineWithFilePath(templatePath.GetFilename().ChangeExtension(".cs"));
await File.WriteAllTextAsync(outputPath.FullPath, result);
var outputPath = output.CombineWithFilePath(outputFilename);
await File.WriteAllTextAsync(outputPath.FullPath, result);
}
return 0;
}
private async Task<IReadOnlyCollection<Emoji>> FetchEmojis(string url)
private async Task<Stream> FetchEmojis(GeneratorCommandSettings settings)
{
using var http = new HttpClient();
var input = string.IsNullOrEmpty(settings.Input)
? _environment.WorkingDirectory
: new DirectoryPath(settings.Input);
var htmlStream = await http.GetStreamAsync(url);
var file = _fileSystem.File.Retrieve(input.CombineWithFilePath("emoji-list.html"));
if (!file.Exists)
{
using var http = new HttpClient();
using var httpStream = await http.GetStreamAsync("http://www.unicode.org/emoji/charts/emoji-list.html");
using var outStream = file.OpenWrite();
var document = await _parser.ParseDocumentAsync(htmlStream);
await httpStream.CopyToAsync(outStream);
}
return Emoji.Parse(document).OrderBy(x => x.Name).ToList();
return file.OpenRead();
}
private static async Task<string> RenderTemplate(Path path, IReadOnlyCollection<Emoji> emojis)
@ -63,7 +84,6 @@ namespace Generator.Commands
var text = await File.ReadAllTextAsync(path.FullPath);
var template = Template.Parse(text);
var templateContext = new TemplateContext
{
// Because of the insane amount of Emojis,
@ -72,9 +92,7 @@ namespace Generator.Commands
};
var scriptObject = new ScriptObject();
scriptObject.Import(new { Emojis = emojis });
templateContext.PushGlobal(scriptObject);
return await template.RenderAsync(templateContext);

View File

@ -24,6 +24,9 @@
<None Update="Templates\ColorPalette.Generated.template">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="Templates\Emoji.Json.template">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="Templates\Emoji.Generated.template">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
@ -31,6 +34,7 @@
<ItemGroup>
<PackageReference Include="AngleSharp" Version="0.14.0" />
<PackageReference Include="Humanizer.Core" Version="2.8.26" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="Scriban" Version="2.1.3" />
<PackageReference Include="Spectre.Cli" Version="0.36.1-preview.0.6" />

View File

@ -3,6 +3,7 @@ using System.Linq;
using System.Text;
using AngleSharp.Dom;
using AngleSharp.Html.Dom;
using Humanizer;
namespace Generator.Models
{
@ -10,15 +11,22 @@ namespace Generator.Models
{
private static readonly string[] _headers = { "count", "code", "sample", "name" };
private Emoji(string code, string name)
private Emoji(string identifier, string name, string code, string description)
{
Code = code;
Identifier = identifier;
Name = name;
Code = code;
Description = description;
NormalizedCode = Code.Replace("\\U", "U+");
HasCombinators = Code.Split(new[] { "\\U" }, System.StringSplitOptions.RemoveEmptyEntries).Length > 1;
}
public string Identifier { get; set; }
public string Code { get; }
public string NormalizedCode { get; }
public string Name { get; }
public string Description { get; set; }
public bool HasCombinators { get; set; }
public static IEnumerable<Emoji> Parse(IHtmlDocument document)
{
@ -30,13 +38,24 @@ namespace Generator.Models
foreach (var row in rows)
{
var dictionary = _headers
.Zip(row.Cells, (header, cell) => (header, cell.TextContent.Trim()))
.Zip(row.Cells, (header, cell) => (Header: header, cell.TextContent.Trim()))
.ToDictionary(x => x.Item1, x => x.Item2);
var code = TransformCode(dictionary["code"]);
var name = TransformName(dictionary["name"]);
var identifier = TransformName(dictionary["name"])
.Replace("-", "_")
.Replace("(", string.Empty)
.Replace(")", string.Empty);
yield return new Emoji(code, name);
var description = dictionary["name"].Humanize();
var name = identifier
.Replace("1st", "first")
.Replace("2nd", "second")
.Replace("3rd", "third")
.Pascalize();
yield return new Emoji(identifier, name, code, description);
}
}
@ -48,8 +67,14 @@ namespace Generator.Models
.Replace("\u201c", string.Empty)
.Replace("\u201d", string.Empty)
.Replace("\u229b", string.Empty)
.Trim()
.Replace(' ', '_')
.Replace("s", "s")
.Replace("", "_")
.Replace("&", "and")
.Replace("#", "hash")
.Replace("*", "star")
.Replace("!", string.Empty)
.Trim()
.ToLowerInvariant();
}

View File

@ -1,7 +1,7 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Generated {{ date.now | date.to_string `%Y-%m-%d %k:%M` }}
// Generated {{ date.now | date.to_string `%F %R` }}
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.

View File

@ -1,7 +1,7 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Generated {{ date.now | date.to_string `%Y-%m-%d %k:%M` }}
// Generated {{ date.now | date.to_string `%F %R` }}
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.

View File

@ -1,7 +1,7 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Generated {{ date.now | date.to_string `%Y-%m-%d %k:%M` }}
// Generated {{ date.now | date.to_string `%F %R` }}
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.

View File

@ -1,7 +1,7 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Generated {{ date.now | date.to_string `%Y-%m-%d %k:%M` }}
// Generated {{ date.now | date.to_string `%F %R` }}
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
@ -10,20 +10,34 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
namespace Spectre.Console
{
/// <summary>
/// Utility class for working with emojis.
/// Utility for working with emojis.
/// </summary>
internal static partial class Emoji
public static partial class Emoji
{
private static readonly Dictionary<string, string> _emojis
= new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase)
{
{{~ for emoji in emojis }} { "{{ emoji.name }}", "{{ emoji.code }}" },
{{~ for emoji in emojis ~}}
{ "{{ emoji.identifier }}", Emoji.Known.{{ emoji.name }} },
{{~ end ~}}
};
/// <summary>
/// Contains all predefined emojis.
/// </summary>
public static class Known
{
{{- for emoji in emojis }}
/// <summary>
/// Gets the "{{ emoji.identifier }}" emoji.
/// Description: {{ emoji.description }}.
/// </summary>
public const string {{ emoji.name }} = "{{ emoji.code }}";
{{~ end ~}}
}
}
}

View File

@ -0,0 +1,10 @@
[
{{~ for x in 0..(emojis.size-1) ~}}
{
"id": "{{ emojis[x].identifier }}",
"name": "{{ emojis[x].name }}",
"description": "{{ emojis[x].description }}",
"code": "{{ emojis[x].normalized_code }}"
}{{ if x != (emojis.size-1) }},{{ end }}
{{~ end ~}}
]

View File

@ -0,0 +1,44 @@
using Shouldly;
using Xunit;
namespace Spectre.Console.Tests.Unit
{
public sealed class EmojiTests
{
[Fact]
public void Should_Substitute_Emoji_Shortcodes_In_Markdown()
{
// Given
var console = new TestableAnsiConsole(ColorSystem.Standard, AnsiSupport.Yes);
// When
console.Markup("Hello :globe_showing_europe_africa:!");
// Then
console.Output.ShouldBe("Hello 🌍!");
}
[Fact]
public void Should_Contain_Predefined_Emojis()
{
// Given, When
const string result = "Hello " + Emoji.Known.GlobeShowingEuropeAfrica + "!";
// Then
result.ShouldBe("Hello 🌍!");
}
public sealed class TheReplaceMethod
{
[Fact]
public void Should_Replace_Emojis_In_Text()
{
// Given, When
var result = Emoji.Replace("Hello :globe_showing_europe_africa:!");
// Then
result.ShouldBe("Hello 🌍!");
}
}
}
}

View File

@ -33,6 +33,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Borders", "..\examples\Bord
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Links", "..\examples\Links\Links.csproj", "{6AF8C93B-AA41-4F44-8B1B-B8D166576174}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Emojis", "..\examples\Emojis\Emojis.csproj", "{1EABB956-957F-4C1A-8AC0-FD19C8F3C2F2}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -163,6 +165,18 @@ Global
{6AF8C93B-AA41-4F44-8B1B-B8D166576174}.Release|x64.Build.0 = Release|Any CPU
{6AF8C93B-AA41-4F44-8B1B-B8D166576174}.Release|x86.ActiveCfg = Release|Any CPU
{6AF8C93B-AA41-4F44-8B1B-B8D166576174}.Release|x86.Build.0 = Release|Any CPU
{1EABB956-957F-4C1A-8AC0-FD19C8F3C2F2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1EABB956-957F-4C1A-8AC0-FD19C8F3C2F2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1EABB956-957F-4C1A-8AC0-FD19C8F3C2F2}.Debug|x64.ActiveCfg = Debug|Any CPU
{1EABB956-957F-4C1A-8AC0-FD19C8F3C2F2}.Debug|x64.Build.0 = Debug|Any CPU
{1EABB956-957F-4C1A-8AC0-FD19C8F3C2F2}.Debug|x86.ActiveCfg = Debug|Any CPU
{1EABB956-957F-4C1A-8AC0-FD19C8F3C2F2}.Debug|x86.Build.0 = Debug|Any CPU
{1EABB956-957F-4C1A-8AC0-FD19C8F3C2F2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1EABB956-957F-4C1A-8AC0-FD19C8F3C2F2}.Release|Any CPU.Build.0 = Release|Any CPU
{1EABB956-957F-4C1A-8AC0-FD19C8F3C2F2}.Release|x64.ActiveCfg = Release|Any CPU
{1EABB956-957F-4C1A-8AC0-FD19C8F3C2F2}.Release|x64.Build.0 = Release|Any CPU
{1EABB956-957F-4C1A-8AC0-FD19C8F3C2F2}.Release|x86.ActiveCfg = Release|Any CPU
{1EABB956-957F-4C1A-8AC0-FD19C8F3C2F2}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -176,6 +190,7 @@ Global
{225CE0D4-06AB-411A-8D29-707504FE53B3} = {F0575243-121F-4DEE-9F6B-246E26DC0844}
{094245E6-4C94-485D-B5AC-3153E878B112} = {F0575243-121F-4DEE-9F6B-246E26DC0844}
{6AF8C93B-AA41-4F44-8B1B-B8D166576174} = {F0575243-121F-4DEE-9F6B-246E26DC0844}
{1EABB956-957F-4C1A-8AC0-FD19C8F3C2F2} = {F0575243-121F-4DEE-9F6B-246E26DC0844}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {5729B071-67A0-48FB-8B1B-275E6822086C}

View File

@ -1,7 +1,7 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Generated 2020-08-03 15:17
// Generated 2020-09-18 10:42
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.

File diff suppressed because it is too large Load Diff

View File

@ -3,9 +3,9 @@ using System.Text.RegularExpressions;
namespace Spectre.Console
{
/// <summary>
/// Utility class for working with emojis.
/// Utility for working with emojis.
/// </summary>
internal static partial class Emoji
public static partial class Emoji
{
private static readonly Regex _emojiCode = new Regex(@"(:(\S*?):)", RegexOptions.Compiled);

View File

@ -1,7 +1,7 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Generated 2020-08-03 15:17
// Generated 2020-09-18 10:42
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.

View File

@ -1,7 +1,7 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Generated 2020-08-03 15:17
// Generated 2020-09-18 10:42
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.

View File

@ -8,6 +8,12 @@ namespace Spectre.Console.Internal
{
public static Paragraph Parse(string text, Style? style = null)
{
if (text is null)
{
throw new ArgumentNullException(nameof(text));
}
text = Emoji.Replace(text);
style ??= Style.Plain;
var result = new Paragraph();

View File

@ -71,7 +71,7 @@ namespace Spectre.Console.Rendering
throw new ArgumentNullException(nameof(text));
}
Text = Emoji.Replace(text).NormalizeLineEndings();
Text = text.NormalizeLineEndings();
Style = style;
IsLineBreak = lineBreak;
IsWhiteSpace = string.IsNullOrWhiteSpace(text);