diff --git a/DotNetTry.sln.DotSettings b/DotNetTry.sln.DotSettings
index 7fa67efcf..c30c28c31 100644
--- a/DotNetTry.sln.DotSettings
+++ b/DotNetTry.sln.DotSettings
@@ -1,2 +1,3 @@
- True
\ No newline at end of file
+ True
+ True
\ No newline at end of file
diff --git a/MLS.Agent.Tests/CommandLine/VerifyCommandTests.cs b/MLS.Agent.Tests/CommandLine/VerifyCommandTests.cs
index 2be4a5b2b..b41e5860e 100644
--- a/MLS.Agent.Tests/CommandLine/VerifyCommandTests.cs
+++ b/MLS.Agent.Tests/CommandLine/VerifyCommandTests.cs
@@ -135,6 +135,41 @@ await VerifyCommand.Do(
$"{root}{Path.DirectorySeparatorChar}doc.md*Line 2:*{root}{Path.DirectorySeparatorChar}Program.cs (in project {root}{Path.DirectorySeparatorChar}some.csproj)*".EnforceLF());
}
+ [Fact]
+ public async Task Fails_if_language_is_not_compatible_with_backing_project()
+ {
+ var root = Create.EmptyWorkspace(isRebuildablePackage: true).Directory;
+
+ var directoryAccessor = new InMemoryDirectoryAccessor(root, root)
+ {
+ ("some.csproj", CsprojContents),
+ ("Program.cs", CompilingProgramCs),
+ ("support.fs", "let a = 0"),
+ ("doc.md", @"
+```fs --source-file support.fs --project some.csproj
+```
+")
+ }.CreateFiles();
+
+ var console = new TestConsole();
+
+ await VerifyCommand.Do(
+ new VerifyOptions(root),
+ console,
+ () => directoryAccessor,
+ PackageRegistry.CreateForTryMode(root));
+
+ _output.WriteLine(console.Out.ToString());
+
+ console.Out
+ .ToString()
+ .EnforceLF()
+ .Trim()
+ .Should()
+ .Match(
+ $"*Build failed as project {root}{Path.DirectorySeparatorChar}some.csproj is not compatible with language fsharp*".EnforceLF());
+ }
+
[Fact]
public async Task When_non_editable_code_blocks_do_not_contain_errors_then_validation_succeeds()
{
diff --git a/MLS.Agent.Tests/Markdown/CodeBlockAnnotationExtensionTests.cs b/MLS.Agent.Tests/Markdown/CodeBlockAnnotationExtensionTests.cs
index 879dd7bca..4361fc778 100644
--- a/MLS.Agent.Tests/Markdown/CodeBlockAnnotationExtensionTests.cs
+++ b/MLS.Agent.Tests/Markdown/CodeBlockAnnotationExtensionTests.cs
@@ -67,14 +67,14 @@ static void MyProgram(string[] args)
var document =
$@"```{language} --source-file Program.cs
```";
- string html = (await pipeline.RenderHtmlAsync(document)).EnforceLF();
+ var html = (await pipeline.RenderHtmlAsync(document)).EnforceLF();
html.Should().Contain(fileContent.HtmlEncode().ToString());
}
[Fact]
- public async Task Does_not_insert_code_when_specified_language_is_not_csharp()
+ public async Task Does_not_insert_code_when_specified_language_is_not_supported()
{
- string expectedValue =
+ var expectedValue =
@"
console.log("Hello World");
".EnforceLF();
@@ -90,27 +90,34 @@ public async Task Does_not_insert_code_when_specified_language_is_not_csharp()
html.Should().Contain(expectedValue);
}
- [Fact]
- public async Task Does_not_insert_code_when_csharp_is_specified_but_no_additional_options()
+ [Theory]
+ [InlineData("cs", "language-cs")]
+ [InlineData("csharp", "language-csharp")]
+ [InlineData("c#", "language-c#")]
+ [InlineData("fs", "language-fs")]
+ [InlineData("fsharp", "language-fsharp")]
+ [InlineData("f#", "language-f#")]
+ public async Task Does_not_insert_code_when_supported_language_is_specified_but_no_additional_options(string fenceLanguage, string expectedClass)
{
- string expectedValue =
-@"Console.WriteLine("Hello World");
+ var expectedValue =
+$@"Console.WriteLine("Hello World");
".EnforceLF();
var testDir = TestAssets.SampleConsole;
var directoryAccessor = new InMemoryDirectoryAccessor(testDir);
var pipeline = new MarkdownPipelineBuilder().UseCodeBlockAnnotations(directoryAccessor, Default.PackageFinder).Build();
- var document = @"
-```cs
+ var document = $@"
+```{fenceLanguage}
Console.WriteLine(""Hello World"");
```";
var html = (await pipeline.RenderHtmlAsync(document)).EnforceLF();
html.Should().Contain(expectedValue);
}
+
[Fact]
- public async Task Error_messsage_is_displayed_when_the_linked_file_does_not_exist()
+ public async Task Error_message_is_displayed_when_the_linked_file_does_not_exist()
{
var testDir = TestAssets.SampleConsole;
var directoryAccessor = new InMemoryDirectoryAccessor(testDir)
@@ -190,6 +197,38 @@ public async Task Sets_the_trydotnet_package_attribute_using_the_passed_project_
output.Value.Should().Be(fullProjectPath.FullName);
}
+ [Theory]
+ [InlineData("cs", "Program.cs", "sample.csproj", "csharp")]
+ [InlineData("c#", "Program.cs", "sample.csproj", "csharp")]
+ [InlineData("fs", "Program.fs", "sample.fsproj", "fsharp")]
+ [InlineData("f#", "Program.fs", "sample.fsproj", "fsharp")]
+ public async Task Sets_the_trydotnet_language_attribute_using_the_fence_command(string fenceLanguage, string fileName, string projectName, string expectedLanguage)
+ {
+ var rootDirectory = TestAssets.SampleConsole;
+ var currentDir = new DirectoryInfo(Path.Combine(rootDirectory.FullName, "docs"));
+ var directoryAccessor = new InMemoryDirectoryAccessor(currentDir, rootDirectory)
+ {
+ ($"src/sample/{fileName}", ""),
+ ($"src/sample/{projectName}", "")
+ };
+
+ var pipeline = new MarkdownPipelineBuilder().UseCodeBlockAnnotations(directoryAccessor, Default.PackageFinder).Build();
+
+ var package = $"../src/sample/{projectName}";
+ var document =
+ $@"```{fenceLanguage} --project {package} --source-file ../src/sample/{fileName}
+```";
+
+ var html = (await pipeline.RenderHtmlAsync(document)).EnforceLF();
+
+ var htmlDocument = new HtmlDocument();
+ htmlDocument.LoadHtml(html);
+ var trydotnetLanguage = htmlDocument.DocumentNode
+ .SelectSingleNode("//pre/code").Attributes["data-trydotnet-language"];
+
+ trydotnetLanguage.Value.Should().Be(expectedLanguage);
+ }
+
[Fact]
public async Task Sets_the_trydotnet_package_attribute_using_the_passed_package_option()
{
diff --git a/MLS.Agent/CommandLine/VerifyCommand.cs b/MLS.Agent/CommandLine/VerifyCommand.cs
index fc67c19b3..a421a63f4 100644
--- a/MLS.Agent/CommandLine/VerifyCommand.cs
+++ b/MLS.Agent/CommandLine/VerifyCommand.cs
@@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.CommandLine;
+using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.DotNet.Try.Markdown;
@@ -13,6 +14,7 @@
using WorkspaceServer;
using WorkspaceServer.Servers.Roslyn;
using Buffer = Microsoft.DotNet.Try.Protocol.Buffer;
+using File = Microsoft.DotNet.Try.Protocol.File;
namespace MLS.Agent.CommandLine
{
@@ -135,6 +137,17 @@ async Task ReportCompileResults(
.Select(b => b.ProjectOrPackageName())
.FirstOrDefault(name => !string.IsNullOrWhiteSpace(name));
+ var language = session
+ .Select(b => b.Language())
+ .FirstOrDefault(name => !string.IsNullOrWhiteSpace(name));
+
+ if (!ProjectIsCompatibleWithLanguage( new UriOrFileInfo(projectOrPackageName), language))
+ {
+ SetError();
+
+ console.Out.WriteLine($" Build failed as project {projectOrPackageName} is not compatible with language {language}");
+ }
+
var editableCodeBlocks = session.Where(b => b.Annotations.Editable).ToList();
var buffers = editableCodeBlocks
@@ -165,6 +178,7 @@ async Task ReportCompileResults(
var workspace = new Workspace(
workspaceType: projectOrPackageName,
+ language: language,
files: files.ToArray(),
buffers: buffers.ToArray());
@@ -173,7 +187,7 @@ async Task ReportCompileResults(
var processed = await mergeTransformer.TransformAsync(workspace);
processed = await inliningTransformer.TransformAsync(processed);
- processed = new Workspace(usings: processed.Usings, workspaceType: processed.WorkspaceType, files: processed.Files);
+ processed = new Workspace(usings: processed.Usings, workspaceType: processed.WorkspaceType, language:processed.Language, files: processed.Files);
var result = await workspaceServer.Value.Compile(new WorkspaceRequest(processed));
@@ -257,5 +271,28 @@ void ReportCodeLinkageResults(
}
}
}
+
+ private static bool ProjectIsCompatibleWithLanguage(UriOrFileInfo projectOrPackage, string language)
+ {
+ var supported = true;
+ if (projectOrPackage.IsFile)
+ {
+ var extension = projectOrPackage.FileExtension.ToLowerInvariant();
+ switch (extension)
+ {
+ case ".csproj":
+ supported = StringComparer.OrdinalIgnoreCase.Compare(language, "csharp") == 0;
+ break;
+
+ case ".fsproj":
+ supported = StringComparer.OrdinalIgnoreCase.Compare(language, "fsharp") == 0;
+ break;
+ default:
+ supported = false;
+ break;
+ }
+ }
+ return supported;
+ }
}
}
\ No newline at end of file
diff --git a/MLS.Agent/MLS.Agent.csproj b/MLS.Agent/MLS.Agent.csproj
index 3911a7402..452b99c54 100644
--- a/MLS.Agent/MLS.Agent.csproj
+++ b/MLS.Agent/MLS.Agent.csproj
@@ -129,7 +129,8 @@
+ BeforeTargets="BeforeBuild"
+ Condition="'$(NCrunch)' != '1'">
<_TryDotNetCssExists Condition="Exists('$(MSBuildThisFileDirectory)wwwroot\css\trydotnet.css')">true
@@ -147,7 +148,7 @@
-
+
$(MSBuildThisFileDirectory)..\Microsoft.DotNet.Try.Client
$(MSBuildThisFileDirectory)wwwroot/client
@@ -167,7 +168,8 @@
Inputs="@(TryDotNetJsInput)"
Outputs="$(TryDotNetJsFile);$(TryDotNetJsMap)"
DependsOnTargets="GatherInputs"
- BeforeTargets="BeforeBuild">
+ BeforeTargets="BeforeBuild"
+ Condition="'$(NCrunch)' != '1'">
<_TryDotNetMinJsExists Condition="Exists('$(TryDotNetJsFile)')">true
@@ -189,7 +191,8 @@
Inputs="@(ClientInputFiles)"
Outputs="$(ClientOutputFile)"
DependsOnTargets="GatherInputs"
- BeforeTargets="BeforeBuild">
+ BeforeTargets="BeforeBuild"
+ Condition="'$(NCrunch)' != '1'">
<_TryDotNetClientExists Condition="Exists('$(ClientOutputFile)')">true
diff --git a/MLS.Agent/MLS.Agent.v3.ncrunchproject b/MLS.Agent/MLS.Agent.v3.ncrunchproject
index eb119af1c..069f496c5 100644
--- a/MLS.Agent/MLS.Agent.v3.ncrunchproject
+++ b/MLS.Agent/MLS.Agent.v3.ncrunchproject
@@ -5,6 +5,7 @@
..\Microsoft.DotNet.Try.Client\**.*
..\Microsoft.DotNet.Try.js\**.*
..\Microsoft.DotNet.Try.Styles\**.*
+ wwwroot\**.*
\ No newline at end of file
diff --git a/MLS.Agent/Markdown/AnnotatedCodeBlockExtensions.cs b/MLS.Agent/Markdown/AnnotatedCodeBlockExtensions.cs
index 7531c6268..46b47f40c 100644
--- a/MLS.Agent/Markdown/AnnotatedCodeBlockExtensions.cs
+++ b/MLS.Agent/Markdown/AnnotatedCodeBlockExtensions.cs
@@ -30,5 +30,10 @@ public static string ProjectOrPackageName(this AnnotatedCodeBlock block)
(block.Annotations as LocalCodeBlockAnnotations)?.Project?.FullName ??
block.Annotations?.Package;
}
+ public static string Language(this AnnotatedCodeBlock block)
+ {
+ return
+ block.Annotations?.NormalizedLanguage;
+ }
}
}
\ No newline at end of file
diff --git a/MLS.Agent/Markdown/LocalCodeFenceAnnotationsParser.cs b/MLS.Agent/Markdown/LocalCodeFenceAnnotationsParser.cs
index 16c5f074b..f9a92de56 100644
--- a/MLS.Agent/Markdown/LocalCodeFenceAnnotationsParser.cs
+++ b/MLS.Agent/Markdown/LocalCodeFenceAnnotationsParser.cs
@@ -20,18 +20,24 @@ public class LocalCodeFenceAnnotationsParser : CodeFenceAnnotationsParser
public LocalCodeFenceAnnotationsParser(
IDirectoryAccessor directoryAccessor,
PackageRegistry packageRegistry,
- IDefaultCodeBlockAnnotations defaultAnnotations = null) : base(defaultAnnotations, csharp =>
- {
- AddProjectOption(csharp, directoryAccessor);
- AddSourceFileOption(csharp);
- })
+ IDefaultCodeBlockAnnotations defaultAnnotations = null) : base(defaultAnnotations,
+ csharp =>
+ {
+ AddCsharpProjectOption(csharp, directoryAccessor);
+ AddSourceFileOption(csharp);
+ },
+ fsharp =>
+ {
+ AddFsharpProjectOption(fsharp, directoryAccessor);
+ AddSourceFileOption(fsharp);
+ })
{
_directoryAccessor = directoryAccessor;
_packageRegistry = packageRegistry ?? throw new ArgumentNullException(nameof(packageRegistry));
}
public override CodeFenceOptionsParseResult TryParseCodeFenceOptions(
- string line,
+ string line,
MarkdownParserContext context = null)
{
var result = base.TryParseCodeFenceOptions(line, context);
@@ -57,7 +63,7 @@ protected override ModelBinder CreateModelBinder()
return new ModelBinder(typeof(LocalCodeBlockAnnotations));
}
- private static void AddSourceFileOption(Command csharp)
+ private static void AddSourceFileOption(Command command)
{
var sourceFileArg = new Argument(
result =>
@@ -76,46 +82,58 @@ private static void AddSourceFileOption(Command csharp)
return ArgumentResult.Failure($"Error parsing the filename: {filename}");
})
- {
- Name = "SourceFile",
- Arity = ArgumentArity.ZeroOrOne
- };
+ {
+ Name = "SourceFile",
+ Arity = ArgumentArity.ZeroOrOne
+ };
var sourceFileOption = new Option("--source-file",
argument: sourceFileArg);
- csharp.AddOption(sourceFileOption);
+ command.AddOption(sourceFileOption);
}
- private static void AddProjectOption(
- Command csharp,
+ private static void AddCsharpProjectOption(
+ Command command,
IDirectoryAccessor directoryAccessor)
+ {
+ AddProjectOption(command, directoryAccessor, ".csproj");
+ }
+
+ private static void AddFsharpProjectOption(
+ Command command,
+ IDirectoryAccessor directoryAccessor)
+ {
+ AddProjectOption(command,directoryAccessor, ".fsproj");
+ }
+
+ private static void AddProjectOption(
+ Command command,
+ IDirectoryAccessor directoryAccessor,
+ string projectFileExtension)
{
var projectOptionArgument = new Argument(result =>
- {
- var projectPath = new RelativeFilePath(result.Tokens.Select(t => t.Value).Single());
+ {
+ var projectPath = new RelativeFilePath(result.Tokens.Select(t => t.Value).Single());
- if (directoryAccessor.FileExists(projectPath))
- {
- return ArgumentResult.Success(directoryAccessor.GetFullyQualifiedPath(projectPath));
- }
+ if (directoryAccessor.FileExists(projectPath))
+ {
+ return ArgumentResult.Success(directoryAccessor.GetFullyQualifiedPath(projectPath));
+ }
- return ArgumentResult.Failure($"Project not found: {projectPath.Value}");
- })
- {
- Name = "project",
- Arity = ArgumentArity.ExactlyOne
- };
+ return ArgumentResult.Failure($"Project not found: {projectPath.Value}");
+ })
+ {
+ Name = "project",
+ Arity = ArgumentArity.ExactlyOne
+ };
projectOptionArgument.SetDefaultValue(() =>
{
var rootDirectory = directoryAccessor.GetFullyQualifiedPath(new RelativeDirectoryPath("."));
var projectFiles = directoryAccessor.GetAllFilesRecursively()
- .Where(file =>
- {
- return directoryAccessor.GetFullyQualifiedPath(file.Directory).FullName == rootDirectory.FullName && file.Extension == ".csproj";
- })
- .ToArray();
+ .Where(file => directoryAccessor.GetFullyQualifiedPath(file.Directory).FullName == rootDirectory.FullName && file.Extension == projectFileExtension)
+ .ToArray();
if (projectFiles.Length == 1)
{
@@ -126,9 +144,9 @@ private static void AddProjectOption(
});
var projectOption = new Option("--project",
- argument: projectOptionArgument);
+ argument: projectOptionArgument);
- csharp.Add(projectOption);
+ command.Add(projectOption);
}
}
}
\ No newline at end of file
diff --git a/Microsoft.DotNet.Try.Client/src/IState.ts b/Microsoft.DotNet.Try.Client/src/IState.ts
index 4339a799d..9c9423e8f 100644
--- a/Microsoft.DotNet.Try.Client/src/IState.ts
+++ b/Microsoft.DotNet.Try.Client/src/IState.ts
@@ -140,6 +140,7 @@ export interface IWorkspaceState
export interface IWorkspace {
workspaceType: string;
+ language?: string;
files?: IWorkspaceFile[];
buffers: IWorkspaceBuffer[];
usings?: string[];
diff --git a/Microsoft.DotNet.Try.Markdown/AnnotatedCodeBlock.cs b/Microsoft.DotNet.Try.Markdown/AnnotatedCodeBlock.cs
index f4cf3196c..233d8e975 100644
--- a/Microsoft.DotNet.Try.Markdown/AnnotatedCodeBlock.cs
+++ b/Microsoft.DotNet.Try.Markdown/AnnotatedCodeBlock.cs
@@ -15,7 +15,7 @@ namespace Microsoft.DotNet.Try.Markdown
{
public class AnnotatedCodeBlock : FencedCodeBlock
{
- protected readonly List _diagnostics = new List();
+ private readonly List _diagnostics = new List();
private string _sourceCode;
private bool _initialized;
@@ -99,7 +99,7 @@ protected virtual async Task AddAttributes(CodeBlockAnnotations annotations)
AddAttributeIfNotNull("data-trydotnet-region", annotations.Region);
AddAttributeIfNotNull("data-trydotnet-session-id", annotations.Session);
- AddAttribute("class", $"language-{annotations.Language}");
+ AddAttribute("class", $"language-{annotations.NormalizedLanguage}");
}
public void RenderTo(
diff --git a/Microsoft.DotNet.Try.Markdown/AnnotatedCodeBlockParser.cs b/Microsoft.DotNet.Try.Markdown/AnnotatedCodeBlockParser.cs
index 6acbf3b98..6d13fa73b 100644
--- a/Microsoft.DotNet.Try.Markdown/AnnotatedCodeBlockParser.cs
+++ b/Microsoft.DotNet.Try.Markdown/AnnotatedCodeBlockParser.cs
@@ -10,12 +10,12 @@ namespace Microsoft.DotNet.Try.Markdown
{
public class AnnotatedCodeBlockParser : FencedBlockParserBase
{
- private readonly CodeFenceAnnotationsParser codeFenceAnnotationsParser;
+ private readonly CodeFenceAnnotationsParser _codeFenceAnnotationsParser;
private int _order;
public AnnotatedCodeBlockParser(CodeFenceAnnotationsParser codeFenceAnnotationsParser)
{
- this.codeFenceAnnotationsParser = codeFenceAnnotationsParser ?? throw new ArgumentNullException(nameof(codeFenceAnnotationsParser));
+ _codeFenceAnnotationsParser = codeFenceAnnotationsParser ?? throw new ArgumentNullException(nameof(codeFenceAnnotationsParser));
OpeningCharacters = new[] { '`' };
InfoParser = ParseCodeOptions;
}
@@ -30,7 +30,7 @@ protected bool ParseCodeOptions(BlockProcessor state, ref StringSlice line, IFen
return false;
}
- var result = codeFenceAnnotationsParser.TryParseCodeFenceOptions(line.ToString(),
+ var result = _codeFenceAnnotationsParser.TryParseCodeFenceOptions(line.ToString(),
state.Context);
switch (result)
diff --git a/Microsoft.DotNet.Try.Markdown/CodeBlockAnnotations.cs b/Microsoft.DotNet.Try.Markdown/CodeBlockAnnotations.cs
index 3b03f7175..8163fd4c4 100644
--- a/Microsoft.DotNet.Try.Markdown/CodeBlockAnnotations.cs
+++ b/Microsoft.DotNet.Try.Markdown/CodeBlockAnnotations.cs
@@ -4,7 +4,9 @@
using System;
using System.CommandLine;
using System.Linq;
+using System.Text.RegularExpressions;
using System.Threading.Tasks;
+using System.Xml;
namespace Microsoft.DotNet.Try.Markdown
{
@@ -37,18 +39,23 @@ public CodeBlockAnnotations(
{
Session = $"Run{++_sessionIndex}";
}
+
+ NormalizedLanguage = parseResult?.CommandResult.Name;
+ Language = parseResult?.Tokens.First().Value;
+ RunArgs = runArgs ?? Untokenize(parseResult);
}
public virtual string Package { get; }
public RelativeFilePath DestinationFile { get; }
public string Region { get; }
- public string RunArgs { get; set; }
+ public string RunArgs { get; }
public ParseResult ParseResult { get; }
public string PackageVersion { get; }
public string Session { get; }
public bool Editable { get; }
public bool Hidden { get; }
- public string Language { get; set; }
+ public string Language { get; }
+ public string NormalizedLanguage { get; }
public virtual Task TryGetExternalContent() =>
Task.FromResult(CodeBlockContentFetchResult.None);
@@ -65,7 +72,22 @@ public virtual Task AddAttributes(AnnotatedCodeBlock block)
block.AddAttribute("data-trydotnet-package-version", PackageVersion);
}
+ if (!string.IsNullOrWhiteSpace(NormalizedLanguage))
+ {
+ block.AddAttribute("data-trydotnet-language", NormalizedLanguage);
+ }
+
return Task.CompletedTask;
}
+
+ private static string Untokenize(ParseResult result) =>
+ result == null
+ ? null
+ : string.Join(" ", result.Tokens
+ .Select(t => t.Value)
+ .Skip(1)
+ .Select(t => Regex.IsMatch(t, @".*\s.*")
+ ? $"\"{t}\""
+ : t));
}
}
\ No newline at end of file
diff --git a/Microsoft.DotNet.Try.Markdown/CodeFenceAnnotationsParser.cs b/Microsoft.DotNet.Try.Markdown/CodeFenceAnnotationsParser.cs
index 049126ddc..81dd7cd8a 100644
--- a/Microsoft.DotNet.Try.Markdown/CodeFenceAnnotationsParser.cs
+++ b/Microsoft.DotNet.Try.Markdown/CodeFenceAnnotationsParser.cs
@@ -13,18 +13,20 @@ namespace Microsoft.DotNet.Try.Markdown
{
public class CodeFenceAnnotationsParser
{
- private readonly IDefaultCodeBlockAnnotations defaultAnnotations;
+ private readonly IDefaultCodeBlockAnnotations _defaultAnnotations;
private readonly Parser _parser;
private readonly Lazy _modelBinder;
- private string packageOptionName = "--package";
- private string packageVersionOptionName = "--package-version";
+ private HashSet _supportedLanguages;
+ private const string PackageOptionName = "--package";
+ private const string PackageVersionOptionName = "--package-version";
public CodeFenceAnnotationsParser(
IDefaultCodeBlockAnnotations defaultAnnotations = null,
- Action configureCsharpCommand = null)
+ Action configureCsharpCommand = null,
+ Action configureFsharpCommand = null)
{
- this.defaultAnnotations = defaultAnnotations;
- _parser = CreateOptionsParser(configureCsharpCommand);
+ _defaultAnnotations = defaultAnnotations;
+ _parser = CreateOptionsParser(configureCsharpCommand, configureFsharpCommand);
_modelBinder = new Lazy(CreateModelBinder);
}
@@ -37,21 +39,21 @@ public virtual CodeFenceOptionsParseResult TryParseCodeFenceOptions(
if (parserContext.TryGetDefaultCodeBlockAnnotations(out var defaults))
{
if (defaults.Package != null &&
- !line.Contains(packageOptionName))
+ !line.Contains(PackageOptionName))
{
- line += $" {packageOptionName} {defaults.Package}";
+ line += $" {PackageOptionName} {defaults.Package}";
}
if (defaults.PackageVersion != null &&
- !line.Contains(packageVersionOptionName))
+ !line.Contains(PackageVersionOptionName))
{
- line += $" {packageVersionOptionName} {defaults.PackageVersion}";
+ line += $" {PackageVersionOptionName} {defaults.PackageVersion}";
}
}
var result = _parser.Parse(line);
- if (result.CommandResult.Name != "csharp" ||
+ if (!_supportedLanguages.Contains(result.CommandResult.Name) ||
result.Tokens.Count == 1)
{
return CodeFenceOptionsParseResult.None;
@@ -61,58 +63,61 @@ public virtual CodeFenceOptionsParseResult TryParseCodeFenceOptions(
{
return CodeFenceOptionsParseResult.Failed(new List(result.Errors.Select(e => e.Message)));
}
- else
- {
- var annotations = (CodeBlockAnnotations) _modelBinder.Value.CreateInstance(new BindingContext(result));
- annotations.Language = result.Tokens.First().Value;
- annotations.RunArgs = Untokenize(result);
+ var annotations = (CodeBlockAnnotations)_modelBinder.Value.CreateInstance(new BindingContext(result));
- return CodeFenceOptionsParseResult.Succeeded(annotations);
- }
+ return CodeFenceOptionsParseResult.Succeeded(annotations);
}
- private static string Untokenize(ParseResult result) =>
- string.Join(" ", result.Tokens
- .Select(t => t.Value)
- .Skip(1)
- .Select(t => Regex.IsMatch(t, @".*\s.*")
- ? $"\"{t}\""
- : t));
+ private Parser CreateOptionsParser(
+ Action configureCsharpCommand = null,
+ Action configureFsharpCommand = null)
+ {
+
+ var languageCommands = new[]
+ {
+ CreateCsharpCommand(configureCsharpCommand),
+ CreateFsharpCommand(configureFsharpCommand)
+ };
+ _supportedLanguages = new HashSet(languageCommands.Select(c => c.Name));
+ return new Parser(new RootCommand(symbols: languageCommands));
+ }
- private Parser CreateOptionsParser(Action configureCsharpCommand = null)
+ private IEnumerable