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]