diff --git a/readme.md b/readme.md index 95ae3600..94996cc4 100644 --- a/readme.md +++ b/readme.md @@ -13,23 +13,24 @@ There is also a [.net API](/docs/api.md) and an [MsBuild Task](/docs/msbuild.md) ## Installation -Install the dotnet tool https://nuget.org/packages/MarkdownSnippets.Tool/ [![NuGet Status](http://img.shields.io/nuget/v/MarkdownSnippets.Tool.svg?style=flat)](https://www.nuget.org/packages/MarkdownSnippets.Tool/) +Ensure [dotnet CLI is installed](https://docs.microsoft.com/en-us/dotnet/core/tools/). + +**There is known a issue with dotnet tools on macOS and Linux that results in [tools not being discovered in the current path](https://github.com/dotnet/cli/issues/9321). The workaround is to add `~/.dotnet/tools` to the PATH.** + +Install MarkdownSnippets.Tool https://nuget.org/packages/MarkdownSnippets.Tool/ [![NuGet Status](http://img.shields.io/nuget/v/MarkdownSnippets.Tool.svg?style=flat)](https://www.nuget.org/packages/MarkdownSnippets.Tool/) ```ps dotnet tool install -g MarkdownSnippets.Tool ``` - ## Usage ```ps -mdsnippets C:\Code\TheTargetDirectory +mdsnippets C:\Code\TargetDirectory ``` If no directory is passed the current directory will be used, but only if it exists with a git repository directory tree. If not an error is returned. -**There is known a issue on macOS and Linux that results in [dotnet tools not being discovered in the current path](https://github.com/dotnet/cli/issues/9321).** - ### Behavior @@ -47,15 +48,18 @@ When using `mdsource` convention, all references to other files, such as links a ## Defining Snippets -Any code wrapped in a convention based comment will be picked up. The comment needs to start with `startcode` which is followed by the key. The snippet is then terminated by `endcode`. +Any code wrapped in a convention based comment will be picked up. The comment needs to start with `begin-snippet:` which is followed by the key. The snippet is then terminated by `end-snippet`. ``` -// startcode MySnippetName +// begin-snippet: MySnippetName My Snippet Code -// endcode +// end-snippet ``` -Named C# regions will also be picked up, with the name of the region is used as the key. +There is a legacy convention for defining snippets. Where a snippet starts with `startcode` and ends with `endcode`. This convention will be removed in a future release. + + +Named [C# regions](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/preprocessor-directives/preprocessor-region) will also be picked up, with the name of the region is used as the key. ## Using Snippets diff --git a/readme.source.md b/readme.source.md index c3565f3e..17b3a73d 100644 --- a/readme.source.md +++ b/readme.source.md @@ -7,23 +7,24 @@ There is also a [.net API](/docs/api.md) and an [MsBuild Task](/docs/msbuild.md) ## Installation -Install the dotnet tool https://nuget.org/packages/MarkdownSnippets.Tool/ [![NuGet Status](http://img.shields.io/nuget/v/MarkdownSnippets.Tool.svg?style=flat)](https://www.nuget.org/packages/MarkdownSnippets.Tool/) +Ensure [dotnet CLI is installed](https://docs.microsoft.com/en-us/dotnet/core/tools/). + +**There is known a issue with dotnet tools on macOS and Linux that results in [tools not being discovered in the current path](https://github.com/dotnet/cli/issues/9321). The workaround is to add `~/.dotnet/tools` to the PATH.** + +Install MarkdownSnippets.Tool https://nuget.org/packages/MarkdownSnippets.Tool/ [![NuGet Status](http://img.shields.io/nuget/v/MarkdownSnippets.Tool.svg?style=flat)](https://www.nuget.org/packages/MarkdownSnippets.Tool/) ```ps dotnet tool install -g MarkdownSnippets.Tool ``` - ## Usage ```ps -mdsnippets C:\Code\TheTargetDirectory +mdsnippets C:\Code\TargetDirectory ``` If no directory is passed the current directory will be used, but only if it exists with a git repository directory tree. If not an error is returned. -**There is known a issue on macOS and Linux that results in [dotnet tools not being discovered in the current path](https://github.com/dotnet/cli/issues/9321).** - ### Behavior @@ -41,15 +42,18 @@ When using `mdsource` convention, all references to other files, such as links a ## Defining Snippets -Any code wrapped in a convention based comment will be picked up. The comment needs to start with `startcode` which is followed by the key. The snippet is then terminated by `endcode`. +Any code wrapped in a convention based comment will be picked up. The comment needs to start with `begin-snippet:` which is followed by the key. The snippet is then terminated by `end-snippet`. ``` -// startcode MySnippetName +// begin-snippet: MySnippetName My Snippet Code -// endcode +// end-snippet ``` -Named C# regions will also be picked up, with the name of the region is used as the key. +There is a legacy convention for defining snippets. Where a snippet starts with `startcode` and ends with `endcode`. This convention will be removed in a future release. + + +Named [C# regions](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/preprocessor-directives/preprocessor-region) will also be picked up, with the name of the region is used as the key. ## Using Snippets diff --git a/src/Directory.Build.props b/src/Directory.Build.props index afb246d6..9f9b81ec 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -5,7 +5,7 @@ latest CS1591 true - 10.2.1 + 10.3.0 MIT Copyright $([System.DateTime]::UtcNow.ToString(yyyy)). All rights reserved https://raw.githubusercontent.com/SimonCropp/MarkdownSnippets/master/src/icon.png diff --git a/src/MarkdownSnippets/Reading/StartEndTester.cs b/src/MarkdownSnippets/Reading/StartEndTester.cs index 0559d4b9..42ec0759 100644 --- a/src/MarkdownSnippets/Reading/StartEndTester.cs +++ b/src/MarkdownSnippets/Reading/StartEndTester.cs @@ -3,20 +3,23 @@ static class StartEndTester { - static Func isEndCode = IsEndCode; - static Func isEndRegion = IsEndRegion; - internal static bool IsStart(string trimmedLine, string path, out string currentKey, out Func endFunc) { + if (IsBeginSnippet(trimmedLine, path, out currentKey)) + { + endFunc = IsEndSnippet; + return true; + } + if (IsStartCode(trimmedLine, path, out currentKey)) { - endFunc = isEndCode; + endFunc = IsEndCode; return true; } if (IsStartRegion(trimmedLine, path, out currentKey)) { - endFunc = isEndRegion; + endFunc = IsEndRegion; return true; } @@ -34,6 +37,11 @@ static bool IsEndCode(string line) return line.IndexOf("endcode", StringComparison.Ordinal) >= 0; } + static bool IsEndSnippet(string line) + { + return line.IndexOf("end-snippet", StringComparison.Ordinal) >= 0; + } + internal static bool IsStartRegion(string line, string path, out string key) { if (!line.StartsWith("#region ", StringComparison.Ordinal)) @@ -45,6 +53,21 @@ internal static bool IsStartRegion(string line, string path, out string key) return TryExtractParts(substring, line, false, path, out key); } + internal static bool IsBeginSnippet(string line, string path, out string key) + { + var startCodeIndex = line.IndexOf("begin-snippet: ", StringComparison.Ordinal); + if (startCodeIndex == -1) + { + key = null; + return false; + } + var startIndex = startCodeIndex + 15; + var substring = line + .TrimBackCommentChars(startIndex); + return TryExtractParts(substring, line, true, path, out key); + } + + internal static bool IsStartCode(string line, string path, out string key) { var startCodeIndex = line.IndexOf("startcode ", StringComparison.Ordinal); diff --git a/src/Tests/StartEndTesterIsBeginSnippetTests.ShouldThrowForKeyEndingWithSymbol.approved.txt b/src/Tests/StartEndTesterIsBeginSnippetTests.ShouldThrowForKeyEndingWithSymbol.approved.txt new file mode 100644 index 00000000..c73d983a --- /dev/null +++ b/src/Tests/StartEndTesterIsBeginSnippetTests.ShouldThrowForKeyEndingWithSymbol.approved.txt @@ -0,0 +1,4 @@ +Key should not start or end with symbols. +Key: key_ +Path: file +Line: \ No newline at end of file diff --git a/src/Tests/StartEndTesterIsBeginSnippetTests.ShouldThrowForKeyStartingWithSymbol.approved.txt b/src/Tests/StartEndTesterIsBeginSnippetTests.ShouldThrowForKeyStartingWithSymbol.approved.txt new file mode 100644 index 00000000..b576e8c9 --- /dev/null +++ b/src/Tests/StartEndTesterIsBeginSnippetTests.ShouldThrowForKeyStartingWithSymbol.approved.txt @@ -0,0 +1,4 @@ +Key should not start or end with symbols. +Key: _key +Path: file +Line: \ No newline at end of file diff --git a/src/Tests/StartEndTesterIsBeginSnippetTests.cs b/src/Tests/StartEndTesterIsBeginSnippetTests.cs new file mode 100644 index 00000000..acea5140 --- /dev/null +++ b/src/Tests/StartEndTesterIsBeginSnippetTests.cs @@ -0,0 +1,107 @@ +using ApprovalTests; +using MarkdownSnippets; +using Xunit; +using Xunit.Abstractions; + +public class StartEndTesterIsBeginSnippetTests : + TestBase +{ + [Fact] + public void CanExtractFromXml() + { + var isStartCode = StartEndTester.IsBeginSnippet("", "file", out var key); + Assert.True(isStartCode); + Assert.Equal("CodeKey", key); + } + + [Fact] + public void ShouldThrowForNoKey() + { + var exception = Assert.Throws(() => StartEndTester.IsBeginSnippet("", "file", out _)); + Assert.Equal("No Key could be derived. Line: ''.", exception.Message); + } + + [Fact] + public void ShouldNotThrowForNoKeyWithNoSpace() + { + StartEndTester.IsBeginSnippet("", "file", out _); + } + + [Fact] + public void CanExtractFromXmlWithMissingSpaces() + { + var isStartCode = StartEndTester.IsBeginSnippet("", "file", out var key); + Assert.True(isStartCode); + Assert.Equal("CodeKey", key); + } + + [Fact] + public void CanExtractFromXmlWithExtraSpaces() + { + var isStartCode = StartEndTester.IsBeginSnippet("", "file", out var key); + Assert.True(isStartCode); + Assert.Equal("CodeKey", key); + } + + [Fact] + public void CanExtractWithNoTrailingCharacters() + { + var isStartCode = StartEndTester.IsBeginSnippet("", "file", out var key); + Assert.True(isStartCode); + Assert.Equal("Code_Key", key); + } + + [Fact] + public void CanExtractWithDashes() + { + var isStartCode = StartEndTester.IsBeginSnippet("", "file", out var key); + Assert.True(isStartCode); + Assert.Equal("Code-Key", key); + } + + [Fact] + public void ShouldThrowForKeyStartingWithSymbol() + { + var exception = Assert.Throws(() => + StartEndTester.IsBeginSnippet("", "file", out _)); + + Approvals.Verify(exception.Message); + } + + [Fact] + public void ShouldThrowForKeyEndingWithSymbol() + { + var exception = Assert.Throws(() => + StartEndTester.IsBeginSnippet("", "file", out _)); + Approvals.Verify(exception.Message); + } + + [Fact] + public void CanExtractWithDifferentEndComments() + { + var isStartCode = StartEndTester.IsBeginSnippet("/* begin-snippet: CodeKey */", "file", out var key); + Assert.True(isStartCode); + Assert.Equal("CodeKey", key); + } + + [Fact] + public void CanExtractWithDifferentEndCommentsAndNoSpaces() + { + var isStartCode = StartEndTester.IsBeginSnippet("/*begin-snippet: CodeKey */", "file", out var key); + Assert.True(isStartCode); + Assert.Equal("CodeKey", key); + } + + public StartEndTesterIsBeginSnippetTests(ITestOutputHelper output) : + base(output) + { + } +} \ No newline at end of file diff --git a/src/Tests/StartEndTester_IsStartCodeTests.cs b/src/Tests/StartEndTester_IsStartCodeTests.cs index 017a6d47..924062ae 100644 --- a/src/Tests/StartEndTester_IsStartCodeTests.cs +++ b/src/Tests/StartEndTester_IsStartCodeTests.cs @@ -3,7 +3,7 @@ using Xunit; using Xunit.Abstractions; -public class StartEndTester_IsStartCodeTests : +public class StartEndTester_IsStartCodeTests : TestBase { [Fact]