├── .editorconfig ├── .gitignore ├── LICENSE.txt ├── NuGet.config ├── Publish.ps1 ├── README.md ├── ZenSharp.Core ├── GenerateTree.n ├── LiveTemplateMatcher.n ├── Parser │ ├── ConcatRule.n │ ├── ErrorContextLocator.n │ ├── LeafRule.n │ ├── LtgParser.n │ ├── ParsingException.n │ ├── Rule.n │ └── TreePart.n ├── Properties │ └── AssemblyInfo.n ├── Utils │ ├── Identifier.n │ ├── ListExtensions.n │ ├── MultiDict.n │ └── RuleFactory.n ├── ZenSharp.Core.Tests │ ├── Data │ │ └── jack.ltg │ ├── Doc │ │ └── RailroadGenerator.cs │ ├── ExpandTestGenerator.cs │ ├── ExpandTestGenerator.tt │ ├── GetContextTests.cs │ ├── LeafRulesMatchTest.cs │ ├── LiveTemplateMatcherTests.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── TestParser.cs │ ├── ZenSharp.Core.Tests.csproj │ └── packages.config ├── ZenSharp.Core.nproj ├── build.bat └── ltg.vim ├── ZenSharp.Integration ├── CSharpExtendedScopeProvider.cs ├── EditConfigActionHandler.cs ├── Extension │ ├── LeafSubstitution.cs │ └── MatchResultExtension.cs ├── LtgConfigWatcher.cs ├── Option │ ├── ExceptionConverter.cs │ ├── ZenSettingsPage.xaml │ └── ZenSettingsPage.xaml.cs ├── Templates.ltg ├── ZenSharp.Integration.csproj ├── ZenSharpItemsProvider.cs ├── ZenSharpLookupItem.cs ├── ZenSharpSettings.cs ├── ZoneMarker.cs ├── app.config └── resharper_macros.71.txt ├── ZenSharp.nuspec ├── ZenSharp.sln ├── build.bat ├── buildNuPack.ps1 ├── dependencies.json ├── doc ├── railroad-diagrams.css ├── railroad-diagrams.js ├── sample.html ├── screen1.gif └── screen2.gif └── patchAssemblyInfo.ps1 /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | insert_final_newline = true 6 | 7 | [*.cs] 8 | indent_size = 4 9 | 10 | [*.{js,ts}] 11 | indent_size = 4 12 | 13 | [*.{xml,csproj,targets,props,nuspec,resx}] 14 | indent_size = 2 15 | 16 | [*.json] 17 | indent_size = 2 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | #ignore thumbnails created by windows 3 | Thumbs.db 4 | #Ignore files build by Visual Studio 5 | 6 | *.obj 7 | *.exe 8 | *.pdb 9 | *.user 10 | *.aps 11 | *.pch 12 | *.vspscc 13 | *_i.c 14 | *_p.c 15 | *.ncb 16 | *.suo 17 | *.tlb 18 | *.tlh 19 | *.bak 20 | *.cache 21 | *.ilk 22 | *.log 23 | [Bb]in 24 | [Dd]ebug*/ 25 | *.lib 26 | *.sbr 27 | obj/ 28 | [Rr]elease*/ 29 | _ReSharper*/ 30 | [Tt]est[Rr]esult* 31 | packages/ 32 | doc/out.html 33 | 34 | #other 35 | .vs 36 | .idea 37 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright Alexander Ulitin (c) 2019 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /NuGet.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Publish.ps1: -------------------------------------------------------------------------------- 1 | $items = ls .\bin\Release\*.nupkg 2 | $package = $items | Out-GridView -OutputMode Single 3 | if ($package -eq $null){ 4 | throw "Nothing selected" 5 | } 6 | #nuget setApiKey -Source https://resharper-plugins.jetbrains.com 7 | 8 | nuget push "$package" -Source https://plugins.jetbrains.com/ 9 | pause 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ReSharper ZenSharp plugin 2 | ============== 3 | 4 | A shortcuts language for defining [ReSharper](https://www.jetbrains.com/resharper/) live template items. You can 5 | specify your own live template scheme using flexible language. 6 | 7 | ![example1](https://raw.githubusercontent.com/ulex/ZenSharp/master/doc/screen1.gif) 8 | 9 | ![example2](https://raw.githubusercontent.com/ulex/ZenSharp/master/doc/screen2.gif) 10 | 11 | How do I get it? 12 | --- 13 | You can install directly into ReSharper via the Extension Manager in the 14 | ReSharper menu. 15 | 16 | Predefined templates 17 | --- 18 | ZenSharp shipped with a lot of standard templates. 19 | 20 | `$END$` means cursor position after expand template by pressing Tab. 21 | 22 | **Examples** in scope, where method definition is allowed: 23 | 24 | 25 | | shortcut | expand to | how to memo | 26 | |----------|--------------------------------------------------------|-----------------------------------------------------------------------------| 27 | | pps | `public string $name$ { get; private set; } $END$` | **p**ublic **p**roperty **s**tring | 28 | | ppsAge | `public string Age {get; private set;} $END$` | **p**ublic **p**roperty **s**tring Name | 29 | | pps+ | `public string $name$ { get; set; } $END$` | **p**ublic **p**roperty **s**tring more access! | 30 | | ppsA+p | `public string A {get; protected set;} $END$` | **p**ublic **p**roperty **s**tring more access!**p**rotected | 31 | | \_rs | `private readonly string $name$; $END$ ` | [**_** is private] **r**eadonly **s**tring | 32 | | pvm | `public virtual void $name$($END$) { } ` | **p**ublic **v**irtual **m**ethod | 33 | | pM\~s | `public static IEnumerable $name$($END$) { } ` | public [static **M**ethod] _returning_ [**\~** is IEnumerable] of **s**tring | 34 | | pamb | `public abstract bool $name$($END$) { } ` | **p**ublic **a**bstract **m**ethod **b**ool | 35 | | pmiaTest | `public int[] Test() { $END$ }` | **p**ublic **m**ethod _returning_ **i**nt **a**rray Name | 36 | 37 | 38 | 39 | **Examples** where type declaration is allowed: 40 | 41 | | shortcut | expand to | how to memo | 42 | |----------|------------------------------------------|---------------------------------| 43 | | pi | `public interface $name$ { $END$ }` | **p**ublic **i**nterface | 44 | | psc | `public sealed class $name$ { $END$ }` | **p**ublic **s**ealed **c**lass | 45 | | pc:t | `public class $name$ : $type$ { $END$ }` | **p**ublic **c**lass **:t**ype | 46 | | ie | `internal enum $name$ { $END$ }` | **i**nternal **e**num | 47 | 48 | **Hint**: you can always write variable name after shortcut. For example, you can type `ppsPropertyName` and 49 | by pressing tab it magically expand to `public string PropertyName {get; set; }`. 50 | 51 | 52 | #### Access 53 | | shortcut | expand to | 54 | |----------|-----------| 55 | | p | public | 56 | | _ | private | 57 | | i | internal | 58 | | P | protected | 59 | 60 | 61 | #### Types 62 | | shortcut | expand to | note | 63 | |----------|-----------|-------------------------------------------------| 64 | | t | $type$ | ask user for custom type after expand | 65 | | sa | string[] | any prim type end with `a` — array of this type | 66 | | b? | bool? | any prim type end with `?` — Nullable type | 67 | 68 | 69 | ##### Primitive types 70 | | shortcut | expand to | 71 | |----------|-----------| 72 | | s | string | 73 | | by | byte | 74 | | b | bool | 75 | | dt | DateTime | 76 | | d | double | 77 | | i | int | 78 | | ui | uint | 79 | | g | Guid | 80 | | dc | decimal | 81 | | b? | bool? | 82 | 83 | 84 | ##### Generic types 85 | | shortcut | expand to | 86 | |----------|-----------------| 87 | | l | IList | 88 | | ~ | IEnumerable | 89 | | sl | SortedList | 90 | | di | Dictionary | 91 | 92 | ##### NUnit attributes ##### 93 | Some useful examples to help wring NUnit tests: 94 | [repo](https://github.com/ulex/ZenSharp/blob/master/ZenSharp.Integration/Templates.ltg) today) 95 | 96 | 97 | | shortcut | expand to | 98 | |------------------------|-------------------------------------------------------------| 99 | | **su**pmSetup | `[SetUp] public void Setup() { $END$ }` | 100 | | **tfsu**pmFixtureSetup | `[TestFixtureSetUp] public void FixtureSetup() { $END$ }` | 101 | | **tftd**FixtureDown | `[TestFixtureTearDown] public void FixtureDown() { $END$ }` | 102 | | **td**pmTearDown | `[TearDown] public void Test() { $END$ }` | 103 | | **tc**pmTest | `[TestCase] public void Test() { $END$ }` | 104 | | **t**pmTest | `[Test] public void Test() { $END$ }` | 105 | 106 | Rules 107 | --- 108 | Simplest rule for expand text `cw` into `System.Console.WriteLine($END$)`(this 109 | rule is ordinary ReSharper live template) will looks like `start ::= 110 | "cw"="System.Console.WriteLine($END$)"` 111 | 112 | More complex rule, a sort of predefined live template for define class in scope, 113 | where class declaration is allowed. In ordinary live templates, if you want to 114 | specify class access before executing live template, you must define 115 | independent live templates one for `"public class"`=`pc`, another for `"internal class"=ic` 116 | But class can be also be sealed. Or static. And same access modifier can be 117 | applied to interface and enum. 118 | 119 | In ZenSharp config you can simple define rules like formal grammar. 120 | For class declaration this definition will looks like: 121 | 122 | space ::= " " 123 | cursor ::= "$END$" 124 | identifier ::= 125 | 126 | access ::= (internal=i | public=p | private=_ | protected=P) space 127 | class ::= access ["sealed "=s] ("class"=c | "static class"=C) space body 128 | body ::= identifier "{" cursor "}" 129 | 130 | scope "InCSharpTypeAndNamespace" 131 | { 132 | start = class | interface 133 | } 134 | 135 | More complex example available in predefined templates file. 136 | 137 | How to compile 138 | --- 139 | ZenSharp written in C# and Nemerle programming language. You can install it from Nemerle website http://nemerle.org/Downloads . 140 | ZenSharp depend on nuget packages ReSharper.SDK and nunit.framwork. Use nuget package restore for them. 141 | 142 | After this, ZenSharp can be built either msbuild or Visual Studio. 143 | 144 | External links 145 | --- 146 | https://blog.jetbrains.com/dotnet/2015/12/22/end-of-year-round-up-of-resharper-10-extensions/ 147 | https://garyng.github.io/gtil-gitbook/ReSharper/resharper-plugin-zensharp.html 148 | 149 | 150 | 163 | -------------------------------------------------------------------------------- /ZenSharp.Core/GenerateTree.n: -------------------------------------------------------------------------------- 1 | using Nemerle; 2 | using Nemerle.Collections; 3 | using Nemerle.Text; 4 | using Nemerle.Utility; 5 | 6 | using System; 7 | using System.Linq; 8 | using System.Text; 9 | using System.Collections.Generic; 10 | 11 | namespace Github.Ulex.ZenSharp.Core 12 | { 13 | [Record] 14 | public class GenerateTree 15 | { 16 | public GlobalRules : list[Rule]; 17 | public Scopes : list[TreePart.Scope]; 18 | 19 | public GetScope(scopename : string) : TreePart.Scope 20 | { 21 | def scope = Scopes.Find(a => a.Name == scopename); 22 | if (!scope.IsSome) 23 | throw Exception($"scope with name $scopename does not exist") 24 | else 25 | scope.Value; 26 | } 27 | 28 | public IsScopeExist(scopename : string) : bool 29 | { 30 | def scope = Scopes.Find(a => a.Name == scopename); 31 | scope.IsSome; 32 | } 33 | 34 | public GetRule(rulename : string, scopeRules : list[Rule]) : Rule 35 | { 36 | def rule = scopeRules.Find(r => r.Name == rulename); 37 | if (rule.IsSome) 38 | rule.Value 39 | else 40 | throw Exception($"Non-terminal rule '$rulename' does not exist"); 41 | } 42 | 43 | public GetStartRule(scope : TreePart.Scope) : Rule 44 | { 45 | def startRule = scope.Rules.Find(a => a.Name == "start"); 46 | if (!startRule.IsSome) 47 | throw Exception($"Start rule for scope $(scope.Name) does not exist") 48 | else 49 | startRule.Value; 50 | } 51 | 52 | GetTemplatesRule(rule : Rule, scopeRules : list[Rule]): IEnumerable[list[LeafRule]] 53 | { 54 | foreach (crule in rule.Rules) 55 | { 56 | foreach (gen in GetTemplatesLr(crule.Rules, scopeRules)) yield gen; 57 | } 58 | } 59 | 60 | GetTemplatesLr(leafRules : list[LeafRule], scopeRules : list[Rule]) : IEnumerable[list[LeafRule]] 61 | { 62 | def (left, current, right) = leafRules.SplitFirst(lr => lr is LeafRule.NonTerminal); 63 | match (current) { 64 | | Some ( x is LeafRule.NonTerminal ) => 65 | { 66 | def rule = GetRule(x.Value, scopeRules); 67 | 68 | // Expand first non-terminal rule 69 | foreach (expand in GetTemplatesRule(rule, scopeRules)) 70 | // Expand tail rules 71 | foreach (rightExpand in GetTemplatesLr(right, scopeRules)) 72 | yield left + expand + rightExpand; 73 | } 74 | | None => yield leafRules 75 | } 76 | } 77 | 78 | public ExtendWithAnotherTree(tree : GenerateTree, namePrefix : string) : GenerateTree 79 | { 80 | def prefix = namePrefix + ":"; 81 | 82 | def patchLeafRule(leaf) 83 | { 84 | match (leaf){ 85 | | x is LeafRule.NonTerminal => LeafRule.NonTerminal(prefix + x.Value); 86 | | x => x; 87 | } 88 | } 89 | 90 | def patchRule(rule) { 91 | rule.Patch(prefix + rule.Name, patchLeafRule); 92 | } 93 | 94 | def patchScope(scope){ 95 | TreePart.Scope(scope.Rules.Select(patchRule).NToList(), scope.Name); 96 | } 97 | 98 | def newGlobalRules = tree.GlobalRules.Select(patchRule).NToList(); 99 | def updatedScopes = tree.Scopes.Select(patchScope).NToList(); 100 | 101 | GenerateTree(GlobalRules + newGlobalRules, Scopes + updatedScopes); 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /ZenSharp.Core/LiveTemplateMatcher.n: -------------------------------------------------------------------------------- 1 | using Nemerle; 2 | using Nemerle.Collections; 3 | using Nemerle.Text; 4 | using Nemerle.Utility; 5 | 6 | using System; 7 | using System.Collections.Generic; 8 | using System.Linq; 9 | 10 | namespace Github.Ulex.ZenSharp.Core 11 | { 12 | public class LiveTemplateMatcher 13 | { 14 | private _tree : GenerateTree; 15 | 16 | public this(tree : GenerateTree) { 17 | _tree = tree; 18 | } 19 | 20 | [Record] 21 | public class MatchResult { 22 | public Success : bool { get; private set; } 23 | public Tail : string { get; private set }; 24 | public Rules : list[LeafRule] { get; private set; } 25 | 26 | public this(mr : bool) { 27 | Success = mr; 28 | } 29 | 30 | public Expand(prefix : string) : string { 31 | def builder = System.Text.StringBuilder(); 32 | foreach (r in ReMatchLeafs(prefix)){ 33 | _ = builder.Append(r.Expand) 34 | } 35 | builder.ToString(); 36 | } 37 | 38 | public ReMatchLeafs(prefix : string) : IEnumerable[LeafRule.LeafMatchResult]{ 39 | def loop(tail, input, acc){ 40 | match (tail){ 41 | | x :: xs => {def matchResult = x.Match(input); loop(xs, matchResult.Crop(input), matchResult :: acc); } 42 | | _ => acc 43 | } 44 | } 45 | loop(Rules, prefix, []).Reverse(); 46 | } 47 | } 48 | 49 | public class MatchResultWithSuggestion : MatchResult { 50 | public Suggestion : MatchResult; 51 | 52 | public this(success : bool, tail : string, rules : list[LeafRule], suggestion : MatchResult) 53 | { 54 | base(success, tail, rules); 55 | // choose best fit 56 | if (suggestion == null || tail.Length < suggestion.Tail.Length){ 57 | Suggestion = this; 58 | } else{ 59 | Suggestion = suggestion; 60 | } 61 | } 62 | 63 | public this(mr : MatchResult, suggestion : MatchResult){ 64 | this(mr.Success, mr.Tail, mr.Rules, suggestion); 65 | } 66 | } 67 | 68 | public Match (prefix : string, scopename : string) : MatchResultWithSuggestion 69 | { 70 | def scope = _tree.GetScope(scopename); 71 | 72 | // scope rules can override global rules 73 | def scopeRules = scope.Rules + _tree.GlobalRules; 74 | 75 | // circle reference fix 76 | mutable tryMatchRuleVar; 77 | 78 | def tryMatchLeafRule(rule : LeafRule, acc){ 79 | match (rule){ 80 | | x is LeafRule.NonTerminal => tryMatchRuleVar(_tree.GetRule(x.Value, scopeRules).Rules, acc); 81 | | x is LeafRule.InsideRule => tryMatchRuleVar(x.Rules, acc); 82 | | lr => { 83 | def leafMatch = lr.Match(acc.Tail); 84 | MatchResultWithSuggestion(leafMatch.Success, leafMatch.Crop(acc.Tail), rule :: acc.Rules, acc.Suggestion) 85 | } 86 | } 87 | } 88 | 89 | def tryMatchConcatRule (rules : list[LeafRule], acc){ 90 | match (rules) { 91 | | x :: xs => { 92 | def r = tryMatchLeafRule(x, acc); 93 | if (!r.Success) 94 | r 95 | else 96 | tryMatchConcatRule(xs, r); 97 | } 98 | | _ => acc; 99 | } 100 | } 101 | 102 | def tryMatchRule (rules : list[ConcatRule], acc){ 103 | match (rules) { 104 | | x :: xs => 105 | { 106 | def r = tryMatchConcatRule(x.Rules, acc); 107 | if (r.Success) 108 | r 109 | else 110 | tryMatchRule(xs, MatchResultWithSuggestion(acc, r.Suggestion)); 111 | }; 112 | | _ => MatchResultWithSuggestion(false, acc.Tail, acc.Rules, acc.Suggestion); 113 | } 114 | } 115 | tryMatchRuleVar = tryMatchRule; 116 | 117 | def iSuggest = MatchResult(false, prefix, []); 118 | def result = tryMatchRule(_tree.GetStartRule(scope).Rules, MatchResultWithSuggestion(true, prefix, [], iSuggest)); 119 | 120 | def suggestion = MatchResult(result.Suggestion.Success, result.Suggestion.Tail, result.Suggestion.Rules.Reverse()); 121 | MatchResultWithSuggestion(result.Success, result.Tail, result.Rules.Reverse(), suggestion); 122 | } 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /ZenSharp.Core/Parser/ConcatRule.n: -------------------------------------------------------------------------------- 1 | using Nemerle; 2 | using Nemerle.Collections; 3 | using Nemerle.Text; 4 | using Nemerle.Utility; 5 | using Nemerle.Peg; 6 | 7 | using System; 8 | using System.Console; 9 | using System.Collections.Generic; 10 | 11 | namespace Github.Ulex.ZenSharp.Core 12 | { 13 | [Record] 14 | public class ConcatRule 15 | { 16 | public Rules : list[LeafRule]; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /ZenSharp.Core/Parser/ErrorContextLocator.n: -------------------------------------------------------------------------------- 1 | using Nemerle; 2 | using Nemerle.Collections; 3 | using Nemerle.Text; 4 | using Nemerle.Utility; 5 | 6 | using System; 7 | using System.Collections.Generic; 8 | using System.Linq; 9 | 10 | namespace Github.Ulex.ZenSharp.Core 11 | { 12 | public module ErrorContextLocator 13 | { 14 | public GetContext(input : string, index : int) : string { 15 | if (index >= input.Length){ 16 | "At the end of file"; 17 | } else { 18 | def nextInd = input.IndexOf('\n', index); 19 | def prevInd = input.LastIndexOf('\n', index); 20 | def prev = if (prevInd == -1) 0 else prevInd; 21 | def length = if (nextInd == -1) input.Length - prev else nextInd - prev; 22 | 23 | def lineNu = input.Substring(0, index).Count(ch => ch == '\n') + 1; 24 | 25 | string.Format("Error at line {0}, column {1}: cant parse {2}{3} ", 26 | lineNu, 27 | index - prev, 28 | Environment.NewLine, 29 | input.Substring(prev, length)); 30 | } 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /ZenSharp.Core/Parser/LeafRule.n: -------------------------------------------------------------------------------- 1 | using Nemerle; 2 | using Nemerle.Collections; 3 | using Nemerle.Text; 4 | using Nemerle.Utility; 5 | using Nemerle.Peg; 6 | 7 | using System; 8 | using System.Linq; 9 | using System.Console; 10 | using System.Collections.Generic; 11 | 12 | 13 | namespace Github.Ulex.ZenSharp.Core 14 | { 15 | public variant LeafRule 16 | { 17 | | String { 18 | Value : string; 19 | public override ToString() : string { $"String<$Value>"; } 20 | public override Match(_ : string) : LeafMatchResult { 21 | LeafMatchResult(true, "", Value, this) 22 | } 23 | } 24 | | NonTerminal { 25 | Value : string; 26 | public override ToString() : string { $"NonTerminal<$Value>"; } 27 | public override Match(_ : string) : LeafMatchResult { 28 | throw NotImplementedException(); 29 | } 30 | } 31 | | InsideRule { 32 | public override ToString() : string { "InsideRule<>"; } 33 | public Rules : list[ConcatRule]; 34 | public override Match(_ : string) : LeafMatchResult { 35 | throw NotImplementedException(); 36 | } 37 | } 38 | | ExpandRule { 39 | Short : string; 40 | Expand : string; 41 | public override ToString() : string { $"ExpandRule<$Short,$Expand>"; } 42 | public override Match(input : string) : LeafMatchResult { 43 | if (input.StartsWith(Short) && input.Length > 0) 44 | LeafMatchResult(true, Short, Expand, this); 45 | else 46 | LeafMatchResult(false); 47 | } 48 | } 49 | | Substitution { 50 | Name : string; 51 | Params: list[(string * string)]; 52 | 53 | public Item[s : string] : string{ 54 | get{ 55 | def v = Params.Find(k => k[0] == s); 56 | if (v.IsSome) v.Value[1] else null; 57 | } 58 | } 59 | private Prop[T](prop : string, default : T) : T { 60 | def val = this[prop]; 61 | if (val != null) Convert.ChangeType(val, typeof(T), Globalization.CultureInfo.InvariantCulture) :> T; 62 | else default; 63 | } 64 | 65 | public Default : string { 66 | get{ 67 | Prop("default", null); 68 | } 69 | } 70 | 71 | public Expand : string { 72 | get{ 73 | Prop("expand", null); 74 | } 75 | } 76 | 77 | public Short : string { 78 | get{ 79 | Prop("short", null); 80 | } 81 | } 82 | 83 | public CanBeNull : bool{ 84 | get{ 85 | !String.IsNullOrEmpty(Default); 86 | } 87 | } 88 | 89 | public override Match (input : string) : LeafMatchResult { 90 | def loop(pos){ 91 | if (pos >= input.Length || !Identifier.IsIdentifier(input[pos])) 92 | pos; 93 | else 94 | loop(pos + 1); 95 | } 96 | 97 | if (Short != null && Expand != null){ 98 | def em = LeafRule.ExpandRule(Short,Expand).Match(input); 99 | LeafMatchResult(em.Success, em.Short, em.Expand, this); 100 | } 101 | else 102 | { 103 | def matchedCount = loop(0); 104 | if (matchedCount != 0){ 105 | def matchString = input.Substring(0, matchedCount); 106 | LeafMatchResult(true, matchString, matchString, this); 107 | } 108 | else if (CanBeNull) 109 | LeafMatchResult(true, "", Default, this); 110 | else 111 | LeafMatchResult(false); 112 | } 113 | } 114 | 115 | public override ToString() : string { 116 | def kvpFormat(kvp: string * string) { string.Format("{0}={1}", kvp[0], kvp[1]); } 117 | string.Format("Substitution<{0}:{1}>", Name, string.Join(", ", Params.Map(kvpFormat))); 118 | } 119 | } 120 | 121 | [Record] 122 | public class LeafMatchResult { 123 | public Success : bool; 124 | public Short : string; 125 | public Expand : string; 126 | public This : LeafRule; 127 | 128 | public this(success : bool){ 129 | Success = success; 130 | } 131 | 132 | public Crop(input : string) : string { 133 | if (String.IsNullOrEmpty(input) || String.IsNullOrEmpty(Short)) 134 | input; 135 | else 136 | input.Remove(0, Short.Length); 137 | } 138 | } 139 | 140 | public abstract Match (input : string) : LeafMatchResult; 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /ZenSharp.Core/Parser/LtgParser.n: -------------------------------------------------------------------------------- 1 | using Nemerle; 2 | using Nemerle.Collections; 3 | using Nemerle.Text; 4 | using Nemerle.Utility; 5 | using Nemerle.Peg; 6 | 7 | using System; 8 | using System.Linq; 9 | using System.Console; 10 | using System.Collections.Generic; 11 | 12 | namespace Github.Ulex.ZenSharp.Core 13 | { 14 | [PegGrammar(Options = EmitDebugSources, start, 15 | grammar 16 | { 17 | start : GenerateTree = generate+; 18 | generate: TreePart = sn (rules / scope / comment); 19 | // Todo: comment to lexer parsing level 20 | comment : TreePart = s "//" (!newLine [Any])* sn; 21 | 22 | newLineCharacter : void = '\n' / '\r' / '\u2028' / '\u2029'; 23 | newLineWindows : void = "\r\n"; 24 | newLine : void = newLineWindows / newLineCharacter; 25 | whitespace : void = [Zs] / '\t' / '\v' / '\f'; 26 | space : void = whitespace / newLine; 27 | s : void = whitespace*; 28 | sn : void = space*; 29 | vmark : void = '|'; 30 | describeMark : void = "::="; 31 | 32 | stringChar : string = !"\"" [Any]; 33 | quoteEscapeSequence : string = "\"\""; 34 | str : string = (quoteEscapeSequence / stringChar)*; 35 | stringDecl : string = '@'? '"' (str) '"'; 36 | identifier : string = ([Lu, Ll, Lt, Lm, Lo, Nl, Nd] / '_')+; 37 | stridentifier : string = stringDecl / identifier; 38 | 39 | scope : TreePart = "scope" s stringDecl s '{' sn (rules / comment)* '}' sn; 40 | 41 | rules : TreePart = rule sn (rule sn)*; 42 | expandRule : LeafRule = terminal / nonterminal / maybeNonterminal / maybeBrackets / brackets; 43 | maybeBrackets : LeafRule = "(" s ruleBody s ")?"; 44 | brackets : LeafRule = "(" s ruleBody s ")"; 45 | concatRule : ConcatRule = expandRule (s expandRule)*; 46 | ruleBody : list[ConcatRule] = concatRule (sn vmark sn concatRule)*; 47 | rule : Rule = identifier s describeMark sn vmark? s ruleBody; 48 | leafShortCut : LeafRule = stridentifier s '=' s stridentifier; 49 | terminalString : LeafRule = stringDecl; 50 | terminal : LeafRule = leafShortCut / substituion / terminalString; 51 | substituion : LeafRule = "<" s (identifier) s (substituionPar s)* ">"; 52 | substituionPar : string * string = identifier s "=" s stringDecl; 53 | 54 | nonterminal : LeafRule = identifier; 55 | maybeNonterminal : LeafRule = identifier "?"; 56 | } 57 | )] 58 | public class LtgParser 59 | { 60 | comment(_ : NToken, _ : NToken) : TreePart { 61 | null; 62 | } 63 | 64 | substituion(_ : NToken, name : string, options : List[(string * string)], _ : NToken) : LeafRule 65 | { 66 | LeafRule.Substitution(name, options.AsList()); 67 | } 68 | 69 | substituionPar(k : string, _ : NToken, v : string) : (string * string) 70 | { 71 | (k,v); 72 | } 73 | 74 | scope(_ : NToken, name : string, _ : NToken, rules : List[TreePart], _ : NToken) : TreePart{ 75 | def loop(rules : list[TreePart], acc : list[Rule]) { 76 | match (rules){ 77 | | null :: xs => loop(xs, acc) 78 | | x :: xs => acc + loop(xs, acc + (x :> TreePart.RuleList).Rules) 79 | | _ => acc 80 | } 81 | } 82 | TreePart.Scope(loop(NList.AsList(rules), []), name); 83 | } 84 | 85 | rules(first : Rule, tail : List[Rule]) : TreePart{ 86 | TreePart.RuleList(first :: tail.AsList()); 87 | } 88 | 89 | concatRule(first : LeafRule, tail : List[LeafRule]) : ConcatRule{ 90 | ConcatRule(first :: tail.AsList()); 91 | } 92 | 93 | ruleBody (crule : ConcatRule, tail : List[ConcatRule]): list[ConcatRule]{ 94 | crule :: tail.AsList(); 95 | } 96 | rule (id : string, rules : list[ConcatRule]): Rule{ 97 | Rule(id, rules) 98 | } 99 | leafShortCut (expand : string, _ : NToken, sho : string) : LeafRule{ 100 | LeafRule.ExpandRule(sho, expand); 101 | } 102 | 103 | terminalString (decl : string) : LeafRule{ 104 | LeafRule.String(decl); 105 | } 106 | 107 | maybeNonterminal (id : string, _ : NToken) : LeafRule{ 108 | LeafRule.InsideRule([ConcatRule([LeafRule.NonTerminal(id)]), ConcatRule([])]) 109 | } 110 | 111 | nonterminal (id : string) : LeafRule{ 112 | LeafRule.NonTerminal(id) 113 | } 114 | 115 | brackets(_ : NToken, ruleBody : list[ConcatRule], _ : NToken) : LeafRule{ 116 | LeafRule.InsideRule(ruleBody); 117 | } 118 | 119 | maybeBrackets(_ : NToken, ruleBody : list[ConcatRule], _ : NToken) : LeafRule{ 120 | def parseablePart = ConcatRule([LeafRule.InsideRule(ruleBody)]); 121 | def emptyAlternative = ConcatRule([]); 122 | LeafRule.InsideRule([parseablePart, emptyAlternative]); 123 | } 124 | 125 | identifier (sequence : NToken) : string { 126 | GetText(sequence); 127 | } 128 | private quoteEscapeSequence(_ : NToken) : string{ 129 | "\""; 130 | } 131 | 132 | private stringChar (text : NToken) : string{ 133 | GetText(text) 134 | } 135 | 136 | private str(parts : List[string]) : string{ 137 | System.String.Concat(parts); 138 | } 139 | 140 | stringDecl(_ : NToken, _ : NToken, inside : string, _ : NToken) : string{ 141 | inside; 142 | } 143 | 144 | start(declaration : List[TreePart]) : GenerateTree{ 145 | // todo: use native nemerle list 146 | def globalRules = List(); 147 | def scopes = List(); 148 | foreach (treePart in declaration) 149 | { 150 | match (treePart){ 151 | | scope is TreePart.Scope => scopes.Add(scope) 152 | | rules is TreePart.RuleList => globalRules.Add(rules) 153 | | _ => () 154 | } 155 | } 156 | GenerateTree($[y | x in globalRules, y in x.Rules], scopes.AsList()); 157 | } 158 | 159 | public ParseAll(input : string) : GenerateTree { 160 | def d = LtgParser(); 161 | def (count, parseresult) = d.TryParse(input); 162 | 163 | if(count == input.Length && parseresult != null) 164 | { 165 | parseresult; 166 | } 167 | else 168 | { 169 | def context = ErrorContextLocator.GetContext(input, count + 1); 170 | throw ParsingException($"Parsing error. Parsed part is <$context>", input, count); 171 | } 172 | } 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /ZenSharp.Core/Parser/ParsingException.n: -------------------------------------------------------------------------------- 1 | using Nemerle; 2 | using Nemerle.Collections; 3 | using Nemerle.Text; 4 | using Nemerle.Utility; 5 | 6 | using System; 7 | using System.Collections.Generic; 8 | using System.Linq; 9 | 10 | namespace Github.Ulex.ZenSharp.Core 11 | { 12 | public class ParsingException : Exception 13 | { 14 | public Input : string { get; set; }; 15 | public ParsedCount: int { get; set; }; 16 | 17 | public this(message : string, input : string, parsedCount : int){ 18 | base(message); 19 | Input = input; 20 | ParsedCount = parsedCount; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /ZenSharp.Core/Parser/Rule.n: -------------------------------------------------------------------------------- 1 | using Nemerle; 2 | using Nemerle.Collections; 3 | using Nemerle.Text; 4 | using Nemerle.Utility; 5 | using Nemerle.Peg; 6 | 7 | using System; 8 | using System.Console; 9 | using System.Collections.Generic; 10 | 11 | namespace Github.Ulex.ZenSharp.Core 12 | { 13 | [Record] 14 | public class Rule 15 | { 16 | public Name : string; 17 | public Rules : list[ConcatRule]; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /ZenSharp.Core/Parser/TreePart.n: -------------------------------------------------------------------------------- 1 | using Nemerle; 2 | using Nemerle.Collections; 3 | using Nemerle.Text; 4 | using Nemerle.Utility; 5 | using Nemerle.Peg; 6 | 7 | using System; 8 | using System.Console; 9 | using System.Collections.Generic; 10 | 11 | namespace Github.Ulex.ZenSharp.Core 12 | { 13 | [Record] 14 | public variant TreePart 15 | { 16 | | RuleList 17 | | Scope { 18 | Name : string; 19 | } 20 | public Rules : list[Rule]; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /ZenSharp.Core/Properties/AssemblyInfo.n: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | [assembly: Nemerle.Macro.Resource(@"Properties\Resources.resx")] 6 | [assembly: Nemerle.Macro.Settings(@"Properties\Settings.settings")] 7 | 8 | // General Information about an assembly is controlled through the following 9 | // set of attributes. Change these attribute values to modify the information 10 | // associated with an assembly. 11 | [assembly: AssemblyTitle("ZenSharp.Core")] 12 | [assembly: AssemblyDescription("")] 13 | [assembly: AssemblyConfiguration("")] 14 | [assembly: AssemblyCompany("Alexander Ulitin")] 15 | [assembly: AssemblyProduct("ZenSharp.Core")] 16 | [assembly: AssemblyCopyright("")] 17 | [assembly: AssemblyTrademark("")] 18 | [assembly: AssemblyCulture("")] 19 | 20 | // Setting ComVisible to false makes the types in this assembly not visible 21 | // to COM components. If you need to access a type in this assembly from 22 | // COM, set the ComVisible attribute to true on that type. 23 | [assembly: ComVisible(false)] 24 | 25 | // The following GUID is for the ID of the typelib if this project is exposed to COM 26 | [assembly: Guid("efa574e2-de9c-4017-bb5c-8fc4cd8d5e80")] 27 | 28 | // Version information for an assembly consists of the following four values: 29 | // 30 | // Major Version 31 | // Minor Version 32 | // Build Number 33 | // Revision 34 | // 35 | [assembly: AssemblyVersion("1.0.*")] 36 | [assembly: AssemblyFileVersion("1.0.*")] 37 | -------------------------------------------------------------------------------- /ZenSharp.Core/Utils/Identifier.n: -------------------------------------------------------------------------------- 1 | using Nemerle; 2 | using Nemerle.Collections; 3 | using Nemerle.Text; 4 | using Nemerle.Utility; 5 | using Nemerle.Peg; 6 | 7 | using System; 8 | using System.Collections.Generic; 9 | using System.Linq; 10 | 11 | namespace Github.Ulex.ZenSharp.Core 12 | { 13 | module Identifier 14 | { 15 | public IsIdentifier(this rs : char) : bool { 16 | // ToDo: use range clasess from c# lexer specification 17 | Char.IsLetterOrDigit(rs) || rs == '_'; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ZenSharp.Core/Utils/ListExtensions.n: -------------------------------------------------------------------------------- 1 | using Nemerle; 2 | using Nemerle.Collections; 3 | using Nemerle.Text; 4 | using Nemerle.Utility; 5 | 6 | namespace Github.Ulex.ZenSharp.Core 7 | { 8 | module ListExtensions 9 | { 10 | public SplitFirst[T](this l : list[T], pred : T -> bool) : list[T] * option[T] * list[T] 11 | { 12 | def loop(acc : list[T], ls : list[T], predicate : T->bool){ 13 | match (ls){ 14 | | x :: xs => if (predicate(x)) (acc.Rev(), Some(x), xs) else loop(x::acc, xs, predicate) 15 | | [] => (acc.Rev(), None(), []) 16 | } 17 | } 18 | loop ([], l, pred) 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /ZenSharp.Core/Utils/MultiDict.n: -------------------------------------------------------------------------------- 1 | using Nemerle; 2 | using Nemerle.Collections; 3 | using Nemerle.Text; 4 | using Nemerle.Utility; 5 | 6 | using System; 7 | using SCG = System.Collections.Generic; 8 | using System.Linq; 9 | 10 | namespace Github.Ulex.ZenSharp.Core 11 | { 12 | public class MultiDict[K,V] : Hashtable[K, list[V]] 13 | { 14 | public AddMulti(key : K, val : V) : void 15 | { 16 | match (Get(key)){ 17 | | None => this.Set(key, [val]) 18 | | Some (x) => this.Set(key, val :: x) 19 | } 20 | } 21 | 22 | public Longer2() : SCG.IEnumerable[K * list[V]] 23 | { 24 | foreach (kvp in this) 25 | { 26 | match (kvp.Value){ 27 | | _ :: _ :: _ => yield (kvp.Key, kvp.Value) 28 | | _ => () 29 | } 30 | } 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /ZenSharp.Core/Utils/RuleFactory.n: -------------------------------------------------------------------------------- 1 | using Nemerle; 2 | using Nemerle.Collections; 3 | using Nemerle.Text; 4 | using Nemerle.Utility; 5 | 6 | using System; 7 | using System.Collections.Generic; 8 | using System.Linq; 9 | 10 | namespace Github.Ulex.ZenSharp.Core 11 | { 12 | module RuleFactory 13 | { 14 | public Patch(this rule : Rule, newname : string, patch : Func[LeafRule, LeafRule]): Rule 15 | { 16 | def patchConcat(crule) 17 | { 18 | ConcatRule(crule.Rules.Select(patch).NToList()); 19 | } 20 | 21 | Rule(newname, rule.Rules.Select(patchConcat).NToList()) 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /ZenSharp.Core/ZenSharp.Core.Tests/Data/jack.ltg: -------------------------------------------------------------------------------- 1 | // This is the house that Jack built. 2 | // This is the cheese that lay in the house that Jack built. 3 | // This is the rat that ate the cheese 4 | // That lay in the house that Jack built. 5 | 6 | tjb ::= "that Jack built"=tjb 7 | thisis ::= "This is the"=tit 8 | s ::= " " 9 | sentence ::= $sencence par="value" par2="sample" $ 10 | sep ::= ", "="," 11 | 12 | scope "house" { 13 | base ::= thisis s sentence 14 | start ::= base | base sep tjb 15 | // Test: tithouse -> This is the house 16 | // Test: tithouse,tjb -> This is the house 17 | } 18 | -------------------------------------------------------------------------------- /ZenSharp.Core/ZenSharp.Core.Tests/Doc/RailroadGenerator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.CodeDom.Compiler; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Text.RegularExpressions; 8 | 9 | using Github.Ulex.ZenSharp.Core; 10 | 11 | using Nemerle.Core; 12 | 13 | using NUnit.Framework; 14 | 15 | namespace ZenSharp.Core.Tests.Doc 16 | { 17 | [TestFixture] 18 | [Explicit] 19 | internal sealed class RailroadGenerator 20 | { 21 | private GenerateTree _tree; 22 | 23 | private IEnumerable _globalRules; 24 | 25 | private readonly HashSet _alwaysExpandRules = new HashSet() 26 | { 27 | "space", 28 | "methodBody", 29 | "methodArgs", 30 | "access", 31 | "SCG", 32 | //"type", 33 | "primType", 34 | "generic", 35 | "suggType", 36 | "propertyBody", 37 | "cursor", 38 | "classBody" 39 | }; 40 | 41 | private readonly HashSet _ignoredStrings = new HashSet() { " " }; 42 | 43 | private const string TemplatesRelativePath = SolutionDir + @"ZenSharp.Integration\Templates.ltg"; 44 | 45 | private const string SolutionDir = @"..\..\"; 46 | 47 | public const string OutFile = DocDir + "out.html"; 48 | 49 | private const string DocDir = SolutionDir + "doc\\"; 50 | 51 | [OneTimeSetUp] 52 | public void FixtureSetup() 53 | { 54 | _tree = new LtgParser().Parse(File.ReadAllText(TemplatesRelativePath)).Value; 55 | } 56 | 57 | [Test] 58 | public void DumpNodes() 59 | { 60 | using (var dump = new StreamWriter(OutFile)) 61 | { 62 | dump.WriteLine(@""); 63 | dump.WriteLine(@""); 64 | dump.WriteLine(@""); 65 | dump.WriteLine(@""); 66 | 67 | _globalRules = _tree.GlobalRules; 68 | 69 | foreach (var scope in _tree.Scopes) 70 | { 71 | _globalRules = scope.Rules.Concat(_tree.GlobalRules); 72 | 73 | dump.WriteLine("

{0}

", scope.Name); 74 | foreach (var rule in scope.Rules.Where(f => !_alwaysExpandRules.Contains(f.Name))) 75 | { 76 | WriteH2Script(dump, rule.Name, DumpConcatRules(rule.Rules)); 77 | } 78 | 79 | } 80 | 81 | dump.WriteLine("

Global

"); 82 | foreach (var rule in _globalRules) 83 | { 84 | WriteH2Script(dump, rule.Name, DumpConcatRules(rule.Rules)); 85 | } 86 | 87 | dump.WriteLine(@""); 88 | } 89 | } 90 | 91 | private void WriteH2Script(StreamWriter dump, string name, string script) 92 | { 93 | dump.WriteLine("

{0}

", name); 94 | dump.WriteLine(""); 97 | } 98 | 99 | public string DumpConcatRules(IEnumerable concatRules) 100 | { 101 | var list = new List(); 102 | foreach (var concatRule in concatRules) 103 | { 104 | list.Add(DumpConcatRule(concatRule)); 105 | } 106 | return string.Format("Choice(0, {0})", string.Join(",", list)); 107 | } 108 | 109 | private string DumpConcatRule(ConcatRule concatRule) 110 | { 111 | var listlr = new List(); 112 | foreach (var leafRule in concatRule.Rules) 113 | { 114 | var item = Dump(leafRule as LeafRule.String) ?? 115 | Dump(leafRule as LeafRule.Substitution) ?? 116 | Dump(leafRule as LeafRule.ExpandRule) ?? 117 | Dump(leafRule as LeafRule.InsideRule) ?? 118 | Dump(leafRule as LeafRule.NonTerminal); 119 | if (item != null) listlr.Add(item); 120 | } 121 | return string.Format("Sequence({0})", string.Join(",", listlr)); 122 | } 123 | 124 | private string Dump(LeafRule.InsideRule leafRule) 125 | { 126 | if (leafRule == null) return null; 127 | return DumpConcatRules(leafRule.Rules.ToArray()); 128 | // return string.Format("NonTerminal('{0}')", leafRule.) 129 | } 130 | 131 | private string Dump(LeafRule.NonTerminal leafRule) 132 | { 133 | if (leafRule == null) return null; 134 | if (_alwaysExpandRules.Contains(leafRule.Value)) 135 | { 136 | return DumpConcatRules(_globalRules.First(r => r.Name == leafRule.Value).Rules); 137 | } 138 | return string.Format("NonTerminal('{0}')", leafRule.Value); 139 | } 140 | 141 | private string Dump(LeafRule.ExpandRule leafRule) 142 | { 143 | if (leafRule == null) return null; 144 | return string.Format("NonTerminal('{0} = {1}')", leafRule.Expand, leafRule.Short); 145 | } 146 | 147 | private string Dump(LeafRule.String leafRule) 148 | { 149 | if (leafRule == null) return null; 150 | 151 | if (_ignoredStrings.Contains(leafRule.Value)) 152 | { 153 | return null; 154 | } 155 | 156 | var escapeNsNames = Regex.Replace(leafRule.Value, "[\\w.]+\\.", String.Empty); 157 | return string.Format("Terminal('{0}')", escapeNsNames); 158 | } 159 | 160 | private string Dump(LeafRule.Substitution leafRule) 161 | { 162 | if (leafRule == null) return null; 163 | return string.Format("NonTerminal('{0}{1}')", leafRule.Expand, leafRule.Short); 164 | } 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /ZenSharp.Core/ZenSharp.Core.Tests/ExpandTestGenerator.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | using System; 11 | using Github.Ulex.ZenSharp.Core; 12 | using NUnit.Framework; 13 | 14 | namespace ZenSharp.Core.Tests 15 | { 16 | [TestFixture] 17 | public class TemplatesTests 18 | { 19 | #region Input of ltg 20 | public string _content = @"// C# templates 21 | // Sample file 22 | space ::= "" "" 23 | cursor ::= ""$END$"" 24 | cursorb ::= ""("" cursor "")"" 25 | // Resharper macros: 26 | identifier ::= 27 | identifier2 ::= 28 | // 29 | // Types: 30 | // 31 | suggType ::= 32 | 33 | // Primive types: 34 | maybeType ::= type | ""void"" 35 | type ::= generic | primType (""?""=""?"")? (""[]""=a)? | suggType 36 | primType ::= string=s | byte=by | bool=b | ""System.DateTime""=dt | decimal=dc | double=d | int=i | uint=ui | ""System.Guid""=g | ""System.Uri""=u | ""System.Xml.Linq.XElement""=x | 37 | object=o 38 | taskType ::= ""System.Threading.Tasks.Task"" 39 | 40 | // Complex types: 41 | generic1 ::= (SCG ""."" (""IList""=l | ""IEnumerable""=""~"")) ""<"" type "">"" 42 | generic2 ::= (SCG ""."" (""SortedList""=sl | ""IDictionary""=di)) ""<"" type "", "" type "">"" 43 | SCG ::= ""System.Collections.Generic"" 44 | generic ::= generic1 | generic2 45 | 46 | 47 | access ::= (internal=i | public=p | private=_ | protected=P) space 48 | 49 | // Auto properties: 50 | property ::= access (""abstract ""=ap | ""static ""=P | ""virtual ""=vp | """"=p) type space identifier propertyBody cursor 51 | propertyBody ::= ""{ get;"" propertySetAccessor "" set; }"" 52 | propertySetAccessor ::= ""protected ""=""+p"" | """"=""+"" | ""private "" 53 | 54 | // Methods: 55 | methodAttributes ::= 56 | | ""[NUnit.Framework.SetUpAttribute]""=su 57 | | ""[NUnit.Framework.TestFixtureSetUpAttribute]""=tfsu 58 | | ""[NUnit.Framework.TestFixtureTearDownAttribute]""=tftd 59 | | ""[NUnit.Framework.TearDownAttribute]""=td 60 | | ""[NUnit.Framework.TestCaseAttribute]""=tc 61 | | ""[NUnit.Framework.TestAttribute]""=t 62 | method_async ::= (methodAttributes)? access ""async"" space (""virtual ""=vm | ""abstract ""=am | ""static ""=M | """"=m) (taskType ""<""=T type "">"" | taskType """"=T) space identifier methodArgs methodBody 63 | method_generic ::= (methodAttributes)? access (""virtual ""=vm | ""abstract ""=am | ""static ""=M | """"=m) (type | ""void"") space identifier methodArgs methodBody 64 | method ::= method_async | method_generic 65 | methodBody ::= "" { "" cursor "" }"" 66 | methodArgs ::= ""("" ((""""="","" | """"=""("") arg)? "")"" 67 | arg ::= primType "" "" identifier2 68 | 69 | // Consts: 70 | const ::= access ""const ""=c primType space identifier ""= """""" identifier """""";"" 71 | 72 | // Fields: 73 | field ::= access (""readonly ""=r)? type space identifier (""=""=""="" identifier2 "";"" | "";"") 74 | 75 | // Classes: 76 | classAtributes ::= (""[NUnit.Framework.TestFixtureAttribute]"" = tf)? 77 | class ::= classAtributes access (""sealed ""=s)? (""class""=c | ""static class""=C) space classBody 78 | classBody ::= identifier ("" : ""="":"" type)? ""{"" cursor ""}"" 79 | 80 | //Enums: 81 | enum ::= access space ""enum""=e space identifier ""{"" cursor ""}"" 82 | 83 | scope ""InCSharpClass"" { 84 | start ::= method | property | field | const | other 85 | 86 | other ::= 87 | | class 88 | | """"=dbset ""public DBSet<"" identifier "" > "" identifier ""s {get; set; }"" 89 | } 90 | 91 | scope ""InCSharpTypeAndNamespace"" { 92 | start ::= 93 | | class 94 | | interface 95 | | enum 96 | 97 | interface ::= access ""interface""=i space classBody 98 | } 99 | 100 | scope ""InCSharpInterface"" { 101 | start ::= 102 | | type space identifier propertyBody cursor 103 | | method 104 | | property 105 | 106 | propertyBody ::= ""{ get; }"" | ""{ get; set; }""=""+"" 107 | access ::= """" 108 | methodBody ::= "";"" 109 | } 110 | 111 | scope ""InCSharpStruct"" { 112 | // start ::= """" 113 | } 114 | 115 | scope ""InCSharpStatement"" { 116 | start ::= 117 | | ""if (""=ifr identifier "" == null) return;"" 118 | | ""Log.""=l (Fatal=f | Info=i | Error=e | Trace=t | Debug=d) ""("""""" cursor """""");"" 119 | } 120 | "; 121 | #endregion Input of ltg 122 | private GenerateTree _tree; 123 | private LiveTemplateMatcher _ltm; 124 | [OneTimeSetUp] 125 | public void LoadTree() 126 | { 127 | _tree = new LtgParser().ParseAll(_content); 128 | _ltm = new LiveTemplateMatcher(_tree); 129 | } 130 | 131 | } 132 | [TestFixture] 133 | public class jackTests 134 | { 135 | #region Input of ltg 136 | public string _content = @"// This is the house that Jack built. 137 | // This is the cheese that lay in the house that Jack built. 138 | // This is the rat that ate the cheese 139 | // That lay in the house that Jack built. 140 | 141 | tjb ::= ""that Jack built""=tjb 142 | thisis ::= ""This is the""=tit 143 | s ::= "" "" 144 | sentence ::= $sencence par=""value"" par2=""sample"" $ 145 | sep ::= "", ""="","" 146 | 147 | scope ""house"" { 148 | base ::= thisis s sentence 149 | start ::= base | base sep tjb 150 | // Test: tithouse -> This is the house 151 | // Test: tithouse,tjb -> This is the house 152 | } 153 | "; 154 | #endregion Input of ltg 155 | private GenerateTree _tree; 156 | private LiveTemplateMatcher _ltm; 157 | [OneTimeSetUp] 158 | public void LoadTree() 159 | { 160 | _tree = new LtgParser().ParseAll(_content); 161 | _ltm = new LiveTemplateMatcher(_tree); 162 | } 163 | 164 | 165 | [Test] 166 | public void Testtithouse_Thisisthehouse() 167 | { 168 | string input = @"tithouse"; 169 | var m = _ltm.Match(input, @"house"); 170 | var expand = m.Expand(input); 171 | Assert.IsTrue(m.Success); 172 | Assert.AreEqual(string.Empty, m.Tail, "Tail is not empty"); 173 | Assert.AreEqual(@"This is the house", expand, "Expand diffs"); 174 | } 175 | 176 | [Test] 177 | public void Testtithousetjb_Thisisthehouse() 178 | { 179 | string input = @"tithouse,tjb"; 180 | var m = _ltm.Match(input, @"house"); 181 | var expand = m.Expand(input); 182 | Assert.IsTrue(m.Success); 183 | Assert.AreEqual(string.Empty, m.Tail, "Tail is not empty"); 184 | Assert.AreEqual(@"This is the house", expand, "Expand diffs"); 185 | } 186 | } 187 | } 188 | 189 | 190 | -------------------------------------------------------------------------------- /ZenSharp.Core/ZenSharp.Core.Tests/ExpandTestGenerator.tt: -------------------------------------------------------------------------------- 1 | <#@ template debug="false" hostspecific="true" language="C#" #> 2 | <#@ assembly name="System.Core" #> 3 | <#@ import namespace="System.IO" #> 4 | <#@ import namespace="System.Linq" #> 5 | <#@ import namespace="System.Text" #> 6 | <#@ import namespace="System.Collections.Generic" #> 7 | <#@ import namespace="System.Text.RegularExpressions" #> 8 | <#@ output extension=".cs" #> 9 | //------------------------------------------------------------------------------ 10 | // 11 | // This code was generated by a tool. 12 | // Runtime Version:<#= System.Environment.Version #> 13 | // 14 | // Changes to this file may cause incorrect behavior and will be lost if 15 | // the code is regenerated. 16 | // 17 | //------------------------------------------------------------------------------ 18 | using System; 19 | using Github.Ulex.ZenSharp.Core; 20 | using NUnit.Framework; 21 | 22 | namespace ZenSharp.Core.Tests 23 | { 24 | <# 25 | string folderTest = Host.ResolvePath("Data"); 26 | string folder = Host.ResolvePath("../../ZenSharp.Integration"); 27 | var ltgFiles = Directory.GetFiles(folder, "*.ltg").Concat(Directory.GetFiles(folderTest)).Select(LtgFileInfo.FromFile); 28 | foreach (var file in ltgFiles) { #> 29 | [TestFixture] 30 | public class <#= file.FileName #>Tests 31 | { 32 | #region Input of ltg 33 | public string _content = <#= file.ContentString #>; 34 | #endregion Input of ltg 35 | private GenerateTree _tree; 36 | private LiveTemplateMatcher _ltm; 37 | [TestFixtureSetUp] 38 | public void LoadTree() 39 | { 40 | _tree = new LtgParser().ParseAll(_content); 41 | _ltm = new LiveTemplateMatcher(_tree); 42 | } 43 | <# foreach (var test in file.Tests) {#> 44 | 45 | 46 | [Test] 47 | public void Test<#= test.TestName #>() 48 | { 49 | string input = <#= test.Short #>; 50 | var m = _ltm.Match(input, <#= test.Scope #>); 51 | var expand = m.Expand(input); 52 | Assert.IsTrue(m.Success); 53 | Assert.AreEqual(string.Empty, m.Tail, "Tail is not empty"); 54 | Assert.AreEqual(<#= test.Expand #>, expand, "Expand diffs"); 55 | }<#}#> 56 | 57 | } 58 | <#} // end file foreach 59 | #> 60 | } 61 | 62 | 63 | <#+ 64 | 65 | public sealed class LtgFileInfo 66 | { 67 | public string Path { get; private set; } 68 | public string FileName { get {return System.IO.Path.GetFileNameWithoutExtension(Path);} } 69 | public string ContentString { get; private set; } 70 | public IEnumerable Tests{get; private set;} 71 | 72 | public static LtgFileInfo FromFile(string path) 73 | { 74 | var content = File.ReadAllText(path); 75 | var tests = new List(); 76 | var lines = content.Split(new []{Environment.NewLine}, StringSplitOptions.None); 77 | 78 | string curscope = ""; 79 | foreach (var line in lines) { 80 | var scopeMatch = Regex.Match(line, "scope \"([^\"]*)\""); 81 | if (scopeMatch.Success) curscope = scopeMatch.Groups[1].Value; 82 | 83 | var match = Regex.Match(line, "// ?Test: ?([^-]*)->(.*)$"); 84 | if (match.Success) 85 | { 86 | tests.Add(new TestInfo { 87 | Short = ToDeclStr(match.Groups[1].Value.Trim()), 88 | Expand = ToDeclStr(match.Groups[2].Value.Trim()), 89 | Scope = ToDeclStr(curscope) 90 | }); 91 | } 92 | } 93 | 94 | return new LtgFileInfo() 95 | { 96 | Path = path, 97 | Tests = tests, 98 | ContentString = ToDeclStr(content) 99 | }; 100 | } 101 | public static string ToDeclStr(string input) 102 | { 103 | return "@\"" + input.Replace("\"", "\"\"") + "\""; 104 | } 105 | 106 | public class TestInfo 107 | { 108 | public string Scope { get; set; } 109 | public string Short { get; set; } 110 | public string Expand { get; set; } 111 | public string TestName { get { return new string((Short + "_" + Expand).Where(ch => Char.IsLetter(ch) || ch == '-' || ch == '_').ToArray()); } } 112 | } 113 | } 114 | #> 115 | -------------------------------------------------------------------------------- /ZenSharp.Core/ZenSharp.Core.Tests/GetContextTests.cs: -------------------------------------------------------------------------------- 1 | using System; using Github.Ulex.ZenSharp.Core; using NUnit.Framework; namespace ZenSharp.Core.Tests { [TestFixture] internal sealed class GetContextTests { string _testFile = new TemplatesTests()._content; [Test] public void TestGetContextForAnyPosition() { for (int i = 0; i < _testFile.Length + 4; i++) { Console.WriteLine(ErrorContextLocator.GetContext(_testFile, i)); } } } } -------------------------------------------------------------------------------- /ZenSharp.Core/ZenSharp.Core.Tests/LeafRulesMatchTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | using NUnit.Framework; 5 | using Github.Ulex.ZenSharp.Core; 6 | using N = Nemerle.Builtins; 7 | 8 | using Nemerle.Collections; 9 | 10 | namespace ZenSharp.Core.Tests 11 | { 12 | internal sealed class LeafRulesMatchTest 13 | { 14 | [Test] 15 | public void TestExpandRule() 16 | { 17 | var rule = new LeafRule.ExpandRule("short7", "expand"); 18 | Assert.AreEqual(rule.Match("short7ending").Short, "short7"); 19 | Assert.AreEqual(rule.Match("short7ending").Expand, "expand"); 20 | Assert.AreEqual(rule.Match("short7").Short, "short7"); 21 | Assert.AreEqual(rule.Match("short7short7").Short, "short7"); 22 | Assert.IsFalse(rule.Match("wr").Success); 23 | } 24 | 25 | [Test] 26 | public void TestNonTerminal() 27 | { 28 | Assert.Throws(() => 29 | { 30 | var rule = new LeafRule.NonTerminal("short7"); 31 | rule.Match("wr"); 32 | }); 33 | } 34 | 35 | [Test] 36 | public void TestSubstitution() 37 | { 38 | var rule = new LeafRule.Substitution("hello", new List>().AsList()); 39 | Assert.AreEqual(rule.Match("short7").Short, "short7"); 40 | Assert.AreEqual(rule.Match("wr").Short, "wr"); 41 | Assert.AreEqual(rule.Match("wr,aa").Short, "wr"); 42 | Assert.AreEqual(rule.Match("wr`aa").Short, "wr"); 43 | Assert.AreEqual(rule.Match("wr~aa").Short, "wr"); 44 | } 45 | 46 | 47 | [Test] 48 | public void TestString() 49 | { 50 | var rule = new LeafRule.String("short7"); 51 | Assert.IsTrue(rule.Match("wr").Success); 52 | Assert.AreEqual(rule.Match("wr").Expand, "short7"); 53 | Assert.AreEqual(rule.Match("wr").Short, ""); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /ZenSharp.Core/ZenSharp.Core.Tests/LiveTemplateMatcherTests.cs: -------------------------------------------------------------------------------- 1 | using System.Security; 2 | 3 | using Github.Ulex.ZenSharp.Core; 4 | 5 | using Nemerle.Collections; 6 | 7 | using NUnit.Framework; 8 | 9 | namespace ZenSharp.Core.Tests 10 | { 11 | [TestFixture] 12 | internal sealed class LiveTemplateMatcherTests 13 | { 14 | private const string Scopename = "scopename"; 15 | 16 | [Test] 17 | public void TestLiveTemplateMatcherTests() 18 | { 19 | var concatRule = new ConcatRule(new LeafRule[] { new LeafRule.ExpandRule("some", "Expand"), new LeafRule.ExpandRule("2", "2") }.NToList()); 20 | 21 | var concatRuleAlt = new ConcatRule(new LeafRule[] { new LeafRule.ExpandRule("some", "Expand3"), new LeafRule.ExpandRule("3", "3") }.NToList()); 22 | 23 | var mresult = MatcherFromRule(StartRule(concatRule, concatRuleAlt)).Match("some3", Scopename); 24 | 25 | Assert.IsFalse(mresult.Success); 26 | Assert.IsTrue(string.IsNullOrEmpty(mresult.Tail)); 27 | } 28 | 29 | private static Rule StartRule(params ConcatRule[] concatRules) 30 | { 31 | return new Rule("start", concatRules.ToNList()); 32 | } 33 | 34 | private static LiveTemplateMatcher MatcherFromRule(Rule rule) 35 | { 36 | var globalRules = NList.FromArray(new Rule[0]); 37 | var scope = new TreePart.Scope(new[] { rule }.NToList(), Scopename); 38 | 39 | var st = new LiveTemplateMatcher(new GenerateTree(globalRules, new[] { scope }.NToList())); 40 | return st; 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /ZenSharp.Core/ZenSharp.Core.Tests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("ZenSharp.Core.Tests")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("ZenSharp.Core.Tests")] 13 | [assembly: AssemblyCopyright("Copyright © 2014")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("36334361-e500-4240-b889-0742da1187f6")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.*")] 36 | [assembly: AssemblyFileVersion("1.0.*")] 37 | -------------------------------------------------------------------------------- /ZenSharp.Core/ZenSharp.Core.Tests/TestParser.cs: -------------------------------------------------------------------------------- 1 | using Github.Ulex.ZenSharp.Core; 2 | 3 | using NUnit.Framework; 4 | 5 | namespace ZenSharp.Core.Tests 6 | { 7 | internal sealed class TestParser 8 | { 9 | public const string grammar1 = @" 10 | 11 | "; 12 | 13 | [Test] 14 | public void TestTestParser() 15 | { 16 | var parser = new LtgParser(); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /ZenSharp.Core/ZenSharp.Core.Tests/ZenSharp.Core.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | Debug 7 | AnyCPU 8 | {1390A507-A540-4FCD-B2F5-5455D21F35F6} 9 | Library 10 | Properties 11 | ZenSharp.Core.Tests 12 | ZenSharp.Core.Tests 13 | v4.5 14 | 512 15 | 16 | 17 | 18 | true 19 | full 20 | false 21 | ..\..\bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | false 26 | 27 | 28 | pdbonly 29 | true 30 | ..\..\bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | false 35 | 36 | 37 | 38 | ..\..\packages\AsyncBridge.Net35.0.2.0\lib\net35-Client\AsyncBridge.Net35.dll 39 | 40 | 41 | ..\..\packages\JetBrains.Lifetimes.2021.1.0\lib\net35\JetBrains.Lifetimes.dll 42 | 43 | 44 | 45 | 46 | ..\..\packages\NUnit.3.11.0\lib\net45\nunit.framework.dll 47 | True 48 | 49 | 50 | 51 | 52 | ..\..\packages\TaskParallelLibrary.1.0.2856.0\lib\Net35\System.Threading.dll 53 | True 54 | True 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | True 66 | True 67 | ExpandTestGenerator.tt 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | TextTemplatingFileGenerator 79 | ExpandTestGenerator.cs 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | {efa574e2-de9c-4017-bb5c-8fc4cd8d5e80} 89 | ZenSharp.Core 90 | 91 | 92 | 93 | 94 | 95 | This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105.The missing file is {0}. 96 | 97 | 98 | 99 | 106 | -------------------------------------------------------------------------------- /ZenSharp.Core/ZenSharp.Core.Tests/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /ZenSharp.Core/ZenSharp.Core.nproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | 8.0.30703 7 | 2.0 8 | efa574e2-de9c-4017-bb5c-8fc4cd8d5e80 9 | Library 10 | Properties 11 | Github.Ulex.ZenSharp.Core 12 | ZenSharp.Core 13 | v4.6.1 14 | 512 15 | true 16 | Net-4.0 17 | $(ProgramFiles)\Nemerle 18 | $(NemerleBinPathRoot)\$(NemerleVersion) 19 | ZenSharp.Core 20 | 21 | 22 | 23 | 24 | true 25 | false 26 | ..\bin\Debug\ 27 | DEBUG;TRACE 28 | prompt 29 | 4 30 | 31 | 32 | false 33 | true 34 | ..\bin\Release\ 35 | TRACE 36 | prompt 37 | 4 38 | $(OutputPath)\$(AssemblyName).xml 39 | 40 | 41 | 42 | Nemerle.Peg.Macros 43 | Nemerle.Peg.Macros.dll 44 | $(Nemerle)\Nemerle.Peg.Macros.dll 45 | True 46 | False 47 | 48 | 49 | 50 | Nemerle 51 | Nemerle.dll 52 | $(Nemerle)\Nemerle.dll 53 | True 54 | False 55 | 56 | 57 | Nemerle.Peg 58 | Nemerle.Peg.dll 59 | $(Nemerle)\Nemerle.Peg.dll 60 | True 61 | False 62 | 63 | 64 | 65 | System.Core 66 | System.Core.dll 67 | ..\..\..\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\System.Core.dll 68 | 69 | 70 | 71 | 72 | 73 | 74 | Code 75 | 76 | 77 | Code 78 | 79 | 80 | Code 81 | 82 | 83 | Code 84 | 85 | 86 | Code 87 | 88 | 89 | Code 90 | 91 | 92 | Code 93 | 94 | 95 | Code 96 | 97 | 98 | 99 | Code 100 | 101 | 102 | Code 103 | 104 | 105 | Code 106 | 107 | 108 | Code 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 125 | -------------------------------------------------------------------------------- /ZenSharp.Core/build.bat: -------------------------------------------------------------------------------- 1 | @SET PATH=%PATH%;C:\Program Files (x86)\Nemerle\net-4.0 2 | @SET PATH=%PATH%;C:\Windows\Microsoft.NET\Framework64\v4.0.30319 3 | 4 | msbuild /t:Build /p:Configuration=Debug ZenSharp.Core.nproj 5 | -------------------------------------------------------------------------------- /ZenSharp.Core/ltg.vim: -------------------------------------------------------------------------------- 1 | " Vim syntax file 2 | " Language: BNF 3 | " Maintainer: Michael Brailsford, Alexander Ulitin 4 | " Last Change: Arpril 03, 2014 5 | 6 | " Quit when a syntax file was already loaded {{{ 7 | if version < 600 8 | syntax clear 9 | elseif exists("b:current_syntax") 10 | finish 11 | endif 12 | "}}} 13 | 14 | syn match bnfNonTerminal "\a\w*" 15 | syn region bnfProduction start="^\s*\a" end="::="me=e-3 16 | syn region bnfComment start="^\s*//" end="$" 17 | syn region ltgSub start="<\s*" end="\>" contains=bnfString 18 | syn match bnfOr "|\|{\|}\|=" 19 | syn match bnfSeperator "::=" 20 | syn match bnfComment "#.*$" 21 | syn region bnfString start=+"+ skip=+""+ end=+"+ 22 | 23 | syn match bnfTerminal "\\w" 24 | syn keyword bnfScopeKw scope contained 25 | syn match bnfScope #scope[^{]*{# contains=bnfScopeKw,bnfOr,bnfString 26 | 27 | hi link bnfNonTerminal Type 28 | hi link bnfProduction Identifier 29 | hi link bnfOr Operator 30 | hi link bnfSeperator PreProc 31 | hi link bnfTerminal Constant 32 | hi link bnfComment Comment 33 | hi link bnfScopeKw Keyword 34 | hi link bnfTerminalRange bnfTerminal 35 | hi link bnfString String 36 | hi link bnfLiteral String 37 | hi link ltgSub Conditional 38 | 39 | -------------------------------------------------------------------------------- /ZenSharp.Integration/CSharpExtendedScopeProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using JetBrains.Application; 5 | using JetBrains.DocumentModel; 6 | using JetBrains.ReSharper.Feature.Services.CSharp.CodeCompletion; 7 | using JetBrains.ReSharper.Feature.Services.LiveTemplates.Context; 8 | using JetBrains.ReSharper.Feature.Services.LiveTemplates.LiveTemplates; 9 | using JetBrains.ReSharper.Psi; 10 | using JetBrains.ReSharper.Psi.CSharp; 11 | using JetBrains.ReSharper.Psi.CSharp.Tree; 12 | using JetBrains.ReSharper.Psi.Files; 13 | using JetBrains.ReSharper.Psi.Tree; 14 | using JetBrains.ReSharper.Resources.Shell; 15 | 16 | namespace Github.Ulex.ZenSharp.Integration 17 | { 18 | [ShellComponent] 19 | public sealed class CSharpExtendedScopeProvider 20 | { 21 | /// 22 | /// Too lazy to implement full ITemplateScopePoint 23 | /// 24 | public IEnumerable ProvideScopePoints(TemplateAcceptanceContext tacContext) 25 | { 26 | var solution = tacContext.Solution; 27 | var document = tacContext.SelectionRange.Document; 28 | if (document == null) 29 | { 30 | return Array.Empty(); 31 | } 32 | var psiSource = tacContext.SourceFile; 33 | if (psiSource == null) 34 | { 35 | return Array.Empty(); 36 | } 37 | 38 | var points = new List(); 39 | using (ReadLockCookie.Create()) 40 | { 41 | var psiFiles = solution.GetPsiServices().Files; 42 | if (!psiFiles.AllDocumentsAreCommitted) 43 | { 44 | psiFiles.CommitAllDocuments(); 45 | } 46 | int caretOffset = tacContext.CaretOffset.Offset; 47 | string prefix = LiveTemplatesManager.GetPrefix(document, caretOffset); 48 | var documentRange = new DocumentRange(document, caretOffset - prefix.Length); 49 | if (!documentRange.IsValid()) 50 | { 51 | return Enumerable.Empty(); 52 | } 53 | 54 | points.Add(psiSource.PrimaryPsiLanguage.Name); 55 | 56 | var file = psiSource.GetPsiFile(documentRange); 57 | if (file == null || !Equals(file.Language, CSharpLanguage.Instance)) 58 | { 59 | return points; 60 | } 61 | var element = file.FindTokenAt(document, caretOffset - prefix.Length); 62 | if (element == null) 63 | { 64 | return points; 65 | } 66 | 67 | points.Add("InCSharpFile"); 68 | var treeNode = element; 69 | 70 | if (treeNode.GetContainingNode(true) != null) return points; 71 | 72 | if (treeNode is ICSharpCommentNode || treeNode is IPreprocessorDirective) 73 | { 74 | treeNode = treeNode.PrevSibling; 75 | } 76 | if (treeNode == null) 77 | { 78 | return points; 79 | } 80 | 81 | var context = CSharpReparseContext.FindContext(treeNode); 82 | if (context == null) 83 | { 84 | return points; 85 | } 86 | 87 | if (treeNode.GetContainingNode() != null) 88 | { 89 | points.Add("InCSharpEnum"); 90 | } 91 | 92 | var containingType = treeNode.GetContainingNode(true); 93 | if (containingType == null && TestNode(context, "namespace N {}", false)) 94 | { 95 | points.Add("InCSharpTypeAndNamespace"); 96 | } 97 | else if (TestNode(context, "void foo() {}", false)) 98 | { 99 | points.Add("InCSharpTypeMember"); 100 | // Extend here: 101 | // Already in type member, 102 | if (treeNode.GetContainingNode() != null) 103 | { 104 | points.Add("InCSharpInterface"); 105 | } 106 | if (treeNode.GetContainingNode() != null) 107 | { 108 | points.Add("InCSharpClass"); 109 | } 110 | if (treeNode.GetContainingNode() != null) 111 | { 112 | points.Add("InCSharpStruct"); 113 | } 114 | if (treeNode.GetContainingNode() != null) 115 | { 116 | points.Add("InCSharpRecord"); 117 | } 118 | } 119 | else 120 | { 121 | bool acceptsExpression = TestNode(context, "a++", true); 122 | if (TestNode(context, "break;", false)) 123 | { 124 | points.Add("InCSharpStatement"); 125 | } 126 | else if (acceptsExpression) 127 | { 128 | points.Add("InCSharpExpression"); 129 | } 130 | if (!acceptsExpression && TestNode(context, "select x", false)) 131 | { 132 | points.Add("InCSharpQuery"); 133 | } 134 | } 135 | } 136 | 137 | return points; 138 | } 139 | 140 | private static bool TestNode(CSharpReparseContext context, string text, bool strictStart = false) 141 | where T : ITreeNode 142 | { 143 | var node = context.Parse(text); 144 | var tokenAt1 = node.FindTokenAt(new TreeOffset(context.WholeTextLength - 1)); 145 | var treeTextOffset = new TreeOffset(context.OriginalTextLength); 146 | var tokenAt2 = node.FindTokenAt(treeTextOffset); 147 | if (tokenAt1 == null || tokenAt2 == null) 148 | { 149 | return false; 150 | } 151 | var errorNodeFinder = new ErrorNodeFinder(tokenAt1); 152 | errorNodeFinder.FindLastError(node); 153 | if (errorNodeFinder.Error != null 154 | && errorNodeFinder.Error.GetTreeStartOffset().Offset >= context.OriginalTextLength) 155 | { 156 | return false; 157 | } 158 | ITreeNode commonParent = tokenAt2.FindCommonParent(tokenAt1); 159 | if (!(commonParent is T)) 160 | { 161 | return false; 162 | } 163 | if (strictStart) 164 | { 165 | return commonParent.GetTreeTextRange().StartOffset == treeTextOffset; 166 | } 167 | return true; 168 | } 169 | } 170 | } 171 | -------------------------------------------------------------------------------- /ZenSharp.Integration/EditConfigActionHandler.cs: -------------------------------------------------------------------------------- 1 | using JetBrains.Application.DataContext; 2 | using JetBrains.Application.Settings; 3 | using JetBrains.Application.UI.Actions; 4 | using JetBrains.Application.UI.Actions.MenuGroups; 5 | using JetBrains.Application.UI.ActionsRevised.Menu; 6 | using JetBrains.Application.UI.ActionSystem.ActionsRevised.Menu; 7 | using JetBrains.Diagnostics; 8 | using JetBrains.IDE; 9 | using JetBrains.ProjectModel; 10 | using JetBrains.ProjectModel.DataContext; 11 | using JetBrains.ReSharper.Resources.Shell; 12 | using JetBrains.Util; 13 | 14 | namespace Github.Ulex.ZenSharp.Integration 15 | { 16 | [ActionGroup(ActionGroupInsertStyles.Embedded)] 17 | public class ZenSharpGroup : IAction, IInsertLast 18 | { 19 | public ZenSharpGroup(Separator sep, EditConfigActionHandler handler) 20 | { 21 | } 22 | } 23 | 24 | [Action("Edit ZenSharp templates")] 25 | public class EditConfigActionHandler : IExecutableAction 26 | { 27 | public bool Update(IDataContext context, ActionPresentation presentation, DelegateUpdate nextUpdate) 28 | { 29 | var solution = context.GetData(ProjectModelDataConstants.SOLUTION); 30 | return solution != null; 31 | } 32 | 33 | public void Execute(IDataContext context, DelegateExecute nextExecute) 34 | { 35 | var store = Shell.Instance.GetComponent(); 36 | var ctx = store.BindToContextTransient(ContextRange.ApplicationWide); 37 | var settings = ctx.GetKey(SettingsOptimization.DoMeSlowly); 38 | 39 | var solution = context.GetData(ProjectModelDataConstants.SOLUTION).NotNull("solution != null"); 40 | var fsp = VirtualFileSystemPath.CreateByCanonicalPath(ZenSharpSettings.GetTreePath(settings.TreeFilename), InteractionContext.Local); 41 | solution.GetComponent().OpenFileAsync(fsp, OpenFileOptions.DefaultActivate); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /ZenSharp.Integration/Extension/LeafSubstitution.cs: -------------------------------------------------------------------------------- 1 | using Github.Ulex.ZenSharp.Core; 2 | 3 | namespace Github.Ulex.ZenSharp.Integration.Extension 4 | { 5 | internal static class LeafSubstitution 6 | { 7 | public static string Macros(this LeafRule.Substitution rule) 8 | { 9 | return rule["macros"]; 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /ZenSharp.Integration/Extension/MatchResultExtension.cs: -------------------------------------------------------------------------------- 1 | using Github.Ulex.ZenSharp.Core; 2 | 3 | namespace Github.Ulex.ZenSharp.Integration.Extension 4 | { 5 | internal static class MatchResultExtension 6 | { 7 | public static string ExpandDisplay(this LiveTemplateMatcher.MatchResult match, string prefix) 8 | { 9 | return match.Expand(prefix).Replace("$END$", string.Empty); 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /ZenSharp.Integration/LtgConfigWatcher.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using Github.Ulex.ZenSharp.Core; 4 | using JetBrains.Application; 5 | using JetBrains.Application.Settings; 6 | using JetBrains.DataFlow; 7 | using JetBrains.Lifetimes; 8 | using JetBrains.Util; 9 | using JetBrains.Util.Logging; 10 | 11 | namespace Github.Ulex.ZenSharp.Integration 12 | { 13 | [ShellComponent] 14 | internal sealed class LtgConfigWatcher : IDisposable 15 | { 16 | private static readonly ILogger Log = Logger.GetLogger(typeof(LtgConfigWatcher)); 17 | 18 | private readonly IContextBoundSettingsStoreLive _boundSettings; 19 | 20 | private FileSystemWatcher _watcher; 21 | 22 | private GenerateTree _tree; 23 | private IProperty _filepath; 24 | 25 | public LtgConfigWatcher(Lifetime lifetime, ISettingsStore settingsStore) 26 | { 27 | _boundSettings = settingsStore.BindToContextLive(lifetime, ContextRange.ApplicationWide); 28 | _filepath = _boundSettings.GetValueProperty(lifetime, _boundSettings.Schema.GetScalarEntry((ZenSharpSettings s) => s.TreeFilename), null); 29 | 30 | _filepath.Change.Advise_HasNew(lifetime, v => Initialize(v.New)); 31 | } 32 | 33 | private void Initialize(string settingsPath) 34 | { 35 | var path = ZenSharpSettings.GetTreePath(settingsPath); 36 | try 37 | { 38 | ReinitializeWatcher(path); 39 | WriteDefaultTemplates(path); 40 | Reload(path); 41 | } 42 | catch (Exception e) 43 | { 44 | Log.Error(e); 45 | } 46 | } 47 | 48 | private void WriteDefaultTemplates(string path) 49 | { 50 | if (!File.Exists(path)) 51 | { 52 | Log.Info("Saving default templates to {0}", path); 53 | using (var resStream = typeof(LtgConfigWatcher).Assembly.GetManifestResourceStream("Github.Ulex.ZenSharp.Integration.Templates.ltg")) 54 | { 55 | if (resStream != null) 56 | { 57 | using (var fstream = File.OpenWrite(path)) 58 | { 59 | resStream.CopyTo(fstream); 60 | } 61 | } 62 | } 63 | } 64 | } 65 | 66 | public void ReinitializeWatcher(string path) 67 | { 68 | if (_watcher != null) 69 | { 70 | var watcher = _watcher; 71 | _watcher = null; 72 | watcher.Dispose(); 73 | } 74 | 75 | var directoryName = Path.GetDirectoryName(path); 76 | Log.Info("Create file system watcher on directory {0}", directoryName); 77 | _watcher = new FileSystemWatcher(directoryName, "*.ltg") 78 | { 79 | EnableRaisingEvents = true, 80 | 81 | // visual studio 2013 save file to temporary and rename it 82 | NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.CreationTime 83 | }; 84 | _watcher.Changed += (sender, args) => SafeReload(path); 85 | } 86 | 87 | private void SafeReload(string path) 88 | { 89 | try 90 | { 91 | Log.Info("Reloading config from {0}", path); 92 | Reload(path); 93 | } 94 | catch (Exception e) 95 | { 96 | Log.Error("Error updating ltg config:"); 97 | MessageBox.ShowError(string.Format("Sorry for this stupid notification type, but some problem occupied when loading ZenSharp config: {0}", e.Message), "ZenSharp error"); 98 | } 99 | } 100 | 101 | public GenerateTree Tree 102 | { 103 | get 104 | { 105 | return _tree; 106 | } 107 | } 108 | 109 | public void Reload(string file) 110 | { 111 | try 112 | { 113 | var path = file; 114 | _tree = new LtgParser().ParseAll(File.ReadAllText(path)); 115 | Log.Info("Config reloaded from {0}", path); 116 | } 117 | catch (Exception e) 118 | { 119 | Log.Error("Error loading config", e); 120 | throw; 121 | } 122 | } 123 | 124 | public void Dispose() 125 | { 126 | _watcher.Dispose(); 127 | } 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /ZenSharp.Integration/Option/ExceptionConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.Windows.Data; 4 | 5 | namespace Github.Ulex.ZenSharp.Integration 6 | { 7 | internal sealed class ExceptionConverter : IValueConverter 8 | { 9 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 10 | { 11 | var exception = value as Exception; 12 | if (exception == null || targetType != typeof(string)) 13 | { 14 | return null; 15 | } 16 | 17 | return string.Format("{0}{1}{2}", exception.Message, Environment.NewLine, exception.StackTrace); 18 | } 19 | 20 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 21 | { 22 | throw new NotImplementedException(); 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /ZenSharp.Integration/Option/ZenSettingsPage.xaml: -------------------------------------------------------------------------------- 1 |  11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | Documentation and source code available at: 30 | 31 | https://github.com/ulex/ZenSharp 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /ZenSharp.Integration/Option/ZenSettingsPage.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Diagnostics; 4 | using System.Runtime.CompilerServices; 5 | using System.Windows; 6 | using System.Windows.Navigation; 7 | using JetBrains.Application.Settings; 8 | using JetBrains.Application.UI.Options; 9 | using JetBrains.Application.UI.Options.OptionPages; 10 | using JetBrains.Application.UI.Options.Options.ThemedIcons; 11 | using JetBrains.DataFlow; 12 | using JetBrains.Lifetimes; 13 | using JetBrains.Util; 14 | using JetBrains.Util.Logging; 15 | using Microsoft.Win32; 16 | 17 | namespace Github.Ulex.ZenSharp.Integration 18 | { 19 | /// 20 | /// Interaction logic for ZenSettingsPage.xaml 21 | /// 22 | [OptionsPage(pageId, "ZenSharp", typeof(OptionsThemedIcons.Plugins), ParentId = EnvironmentPage.Pid)] 23 | public partial class ZenSettingsPage : IOptionsPage 24 | { 25 | private const string pageId = "ZenSettingsPageId"; 26 | 27 | private static readonly ILogger Log = Logger.GetLogger(typeof(ZenSettingsPage)); 28 | 29 | public IProperty Path { get; private set; } 30 | 31 | public ZenSettingsPage(Lifetime lifetime, OptionsSettingsSmartContext settings) 32 | { 33 | Path = new Property("Path"); 34 | settings.SetBinding(lifetime, (ZenSharpSettings s) => s.TreeFilename, Path); 35 | InitializeComponent(); 36 | Id = pageId; 37 | // show exception info if any 38 | OnOk(); 39 | } 40 | 41 | public string Id { get; } 42 | 43 | public bool OnOk() 44 | { 45 | return true; 46 | } 47 | 48 | private void ButtonBase_OnClick(object sender, RoutedEventArgs e) 49 | { 50 | try 51 | { 52 | var dialog = new OpenFileDialog() { CheckFileExists = true, DefaultExt = "ltg", ValidateNames = true }; 53 | if (dialog.ShowDialog() == true) 54 | { 55 | Path.Value = dialog.FileName; 56 | } 57 | } 58 | catch (Exception exception) 59 | { 60 | Log.Error("Unexcpected error", exception); 61 | } 62 | } 63 | 64 | private void Hyperlink_OnRequestNavigate(object sender, RequestNavigateEventArgs e) 65 | { 66 | Process.Start(new ProcessStartInfo(e.Uri.AbsoluteUri)); 67 | e.Handled = true; 68 | } 69 | 70 | public event PropertyChangedEventHandler PropertyChanged; 71 | 72 | // [NotifyPropertyChangedInvocator] 73 | protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) 74 | { 75 | PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /ZenSharp.Integration/Templates.ltg: -------------------------------------------------------------------------------- 1 | // C# templates 2 | // Sample file 3 | space ::= " " 4 | cursor ::= "$END$" 5 | cursorb ::= "(" cursor ")" 6 | // Resharper macros: 7 | identifier ::= 8 | identifier2 ::= 9 | // 10 | // Types: 11 | // 12 | suggType ::= 13 | 14 | // Primive types: 15 | maybeType ::= type | "void" 16 | type ::= generic | primType ("?"="?")? ("[]"=a)? | suggType 17 | primType ::= string=s | byte=by | bool=b | "System.DateTime"=dt | decimal=dc | double=d | int=i | uint=ui | "System.Guid"=g | "System.Uri"=u | "System.Xml.Linq.XElement"=x | 18 | object=o 19 | taskType ::= "System.Threading.Tasks.Task" 20 | 21 | // Complex types: 22 | generic1 ::= (SCG "." ("IList"=l | "IEnumerable"="~")) "<" type ">" 23 | generic2 ::= (SCG "." ("SortedList"=sl | "IDictionary"=di)) "<" type ", " type ">" 24 | SCG ::= "System.Collections.Generic" 25 | generic ::= generic1 | generic2 26 | 27 | 28 | access ::= (internal=i | public=p | private=_ | protected=P) space 29 | 30 | // Auto properties: 31 | property ::= access ("abstract "=ap | "static "=P | "virtual "=vp | ""=p) type space identifier propertyBody cursor 32 | propertyBody ::= "{ get;" propertySetAccessor " set; }" 33 | propertySetAccessor ::= "protected "="+p" | ""="+" | "private " 34 | 35 | // Methods: 36 | methodAttributes ::= 37 | | "[NUnit.Framework.SetUpAttribute]"=su 38 | | "[NUnit.Framework.TestFixtureSetUpAttribute]"=tfsu 39 | | "[NUnit.Framework.TestFixtureTearDownAttribute]"=tftd 40 | | "[NUnit.Framework.TearDownAttribute]"=td 41 | | "[NUnit.Framework.TestCaseAttribute]"=tc 42 | | "[NUnit.Framework.TestAttribute]"=t 43 | method_async ::= (methodAttributes)? access "async" space ("virtual "=vm | "abstract "=am | "static "=M | ""=m) (taskType "<"=T type ">" | taskType ""=T) space identifier methodArgs methodBody 44 | method_generic ::= (methodAttributes)? access ("virtual "=vm | "abstract "=am | "static "=M | ""=m) (type | "void") space identifier methodArgs methodBody 45 | method ::= method_async | method_generic 46 | methodBody ::= " { " cursor " }" 47 | methodArgs ::= "(" ((""="," | ""="(") arg)? ")" 48 | arg ::= primType " " identifier2 49 | 50 | // Consts: 51 | const ::= access "const "=c primType space identifier "= """ identifier """;" 52 | 53 | // Fields: 54 | field ::= access ("readonly "=r)? type space identifier ("="="=" identifier2 ";" | ";") 55 | 56 | // Classes: 57 | classAtributes ::= ("[NUnit.Framework.TestFixtureAttribute]" = tf)? 58 | class ::= classAtributes access ("sealed "=S)? ("class"=c | "static class"=C) space classBody 59 | classBody ::= identifier (" : "=":" type)? "{" cursor "}" 60 | 61 | // Records: 62 | record ::= access ("abstract "=a | "sealed "=S | "readonly "=r)? "record "=R ("struct "=s)? identifier recordArgsList record_inheritance ";" 63 | record_inheritance ::= (" : "=":" type "( " cursor " )")? 64 | recordArgsList ::= "(" ((""="," | ""="(") recordArg)? ")" 65 | recordArg ::= type " " identifier2 (", "="," recordArg)? 66 | 67 | //Enums: 68 | enum ::= access space "enum"=e space identifier "{" cursor "}" 69 | 70 | scope "InCSharpClass" { 71 | start ::= method | property | field | const | other 72 | 73 | other ::= 74 | | class 75 | | ""=dbset "public DBSet<" identifier " > " identifier "s {get; set; }" 76 | | enum 77 | | record 78 | } 79 | 80 | scope "InCSharpRecord" { 81 | start ::= property 82 | } 83 | 84 | scope "InCSharpTypeAndNamespace" { 85 | start ::= 86 | | class 87 | | interface 88 | | enum 89 | | record 90 | 91 | interface ::= access "interface"=i space classBody 92 | } 93 | 94 | scope "InCSharpInterface" { 95 | start ::= 96 | | type space identifier propertyBody cursor 97 | | method 98 | | property 99 | 100 | propertyBody ::= "{ get; }" | "{ get; set; }"="+" 101 | access ::= "" 102 | methodBody ::= ";" 103 | } 104 | 105 | scope "InCSharpStruct" { 106 | // start ::= "" 107 | } 108 | 109 | scope "InCSharpStatement" { 110 | start ::= 111 | | "if ("=ifr identifier " == null) return;" 112 | | "Log."=l (Fatal=f | Info=i | Error=e | Trace=t | Debug=d) "(""" cursor """);" 113 | } 114 | -------------------------------------------------------------------------------- /ZenSharp.Integration/ZenSharp.Integration.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | Library 4 | Github.Ulex.ZenSharp.Integration 5 | ZenSharp.Integration 6 | net472-windows 7 | true 8 | latest 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 2024.3.0-eap01 17 | runtime; build; native; contentfiles; analyzers 18 | all 19 | 20 | 21 | False 22 | ..\bin\Release\ZenSharp.Core.dll 23 | 24 | 25 | -------------------------------------------------------------------------------- /ZenSharp.Integration/ZenSharpItemsProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using JetBrains.DocumentModel; 4 | using JetBrains.ProjectModel; 5 | using JetBrains.ReSharper.Feature.Services.CodeCompletion.Infrastructure; 6 | using JetBrains.ReSharper.Feature.Services.CodeCompletion.Infrastructure.LookupItems; 7 | using JetBrains.ReSharper.Feature.Services.CSharp.CodeCompletion.Infrastructure; 8 | using JetBrains.ReSharper.Feature.Services.LiveTemplates.Context; 9 | using JetBrains.ReSharper.Feature.Services.LiveTemplates.Settings; 10 | using JetBrains.ReSharper.Feature.Services.LiveTemplates.Templates; 11 | using JetBrains.ReSharper.Feature.Services.Resources; 12 | using JetBrains.ReSharper.Psi; 13 | using JetBrains.ReSharper.Resources.Shell; 14 | using JetBrains.TextControl; 15 | using JetBrains.Util; 16 | using JetBrains.Util.Logging; 17 | 18 | namespace Github.Ulex.ZenSharp.Integration 19 | { 20 | [Language(typeof(KnownLanguage))] 21 | internal class ZenSharpItemsProvider : ItemsProviderOfSpecificContext 22 | { 23 | private static readonly ILogger Log = Logger.GetLogger(typeof(ZenSharpItemsProvider)); 24 | 25 | protected override bool IsAvailable(ISpecificCodeCompletionContext context) 26 | { 27 | if (context is CSharpCodeCompletionContext csContext && csContext.ReplaceRangeWithJoinedArguments.Length == 0) 28 | return false; 29 | 30 | return true; 31 | } 32 | 33 | protected override bool AddLookupItems(ISpecificCodeCompletionContext context, IItemsCollector collector) 34 | { 35 | Log.Info("Add lookupitems"); 36 | 37 | var solution = context.BasicContext.Solution; 38 | 39 | var ltgConfig = Shell.Instance.GetComponent(); 40 | 41 | var iconManager = solution.GetComponent(); 42 | var provider = solution.GetComponent(); 43 | var textControl = context.BasicContext.TextControl; 44 | 45 | var offset = textControl.Caret.Offset(); 46 | var templateContext = new TemplateAcceptanceContext( 47 | solution, 48 | new DocumentOffset(textControl.Document, offset), 49 | new DocumentRange(textControl.Document, offset)); 50 | 51 | var scopePoints = provider.ProvideScopePoints(templateContext); 52 | if (ltgConfig.Tree != null) 53 | { 54 | var template = new Template("", "", "", true, true, false, new[] {TemplateApplicability.Live}) 55 | { 56 | UID = Guid.NewGuid() 57 | }; 58 | var scopes = scopePoints.ToList(); 59 | Log.Trace("Current scopes: {0}", string.Join(",", scopes)); 60 | 61 | if (scopes.Any(scopename => ltgConfig.Tree.IsScopeExist(scopename))) 62 | { 63 | var iconId = iconManager.ExtendToTypicalSize(ServicesThemedIcons.LiveTemplate.Id); 64 | collector.Add(new ZenSharpLookupItem(template, ltgConfig.Tree, scopes, iconId)); 65 | return true; 66 | } 67 | else 68 | { 69 | return false; 70 | } 71 | } 72 | Log.Warn("Lookup item for completion is not added, because ZenSharp expand tree is not loaded."); 73 | return false; 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /ZenSharp.Integration/ZenSharpLookupItem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using Github.Ulex.ZenSharp.Core; 5 | using Github.Ulex.ZenSharp.Integration.Extension; 6 | using JetBrains.Diagnostics; 7 | using JetBrains.ReSharper.Feature.Services.CodeCompletion.Infrastructure.LookupItems; 8 | using JetBrains.ReSharper.Feature.Services.CodeCompletion.Infrastructure.Match; 9 | using JetBrains.ReSharper.Feature.Services.LiveTemplates; 10 | using JetBrains.ReSharper.Feature.Services.LiveTemplates.Templates; 11 | using JetBrains.ReSharper.Feature.Services.LiveTemplates.Util; 12 | using JetBrains.ReSharper.Resources.Shell; 13 | using JetBrains.Text; 14 | using JetBrains.UI.Icons; 15 | using JetBrains.UI.RichText; 16 | using JetBrains.Util; 17 | using JetBrains.Util.Logging; 18 | // using LoggingLevel = JetBrains.Diagnostics.LoggingLevel; 19 | 20 | namespace Github.Ulex.ZenSharp.Integration 21 | { 22 | /// 23 | /// todo: remove inherence 24 | /// 25 | 26 | internal class ZenSharpLookupItem : TemplateLookupItem, ILookupItem 27 | { 28 | private static readonly ILogger Log = Logger.GetLogger(typeof(ZenSharpLookupItem)); 29 | 30 | private readonly IEnumerable _scopes; 31 | 32 | /// 33 | /// todo: remove 34 | /// 35 | private readonly Template _template; 36 | 37 | private readonly GenerateTree _tree; 38 | 39 | private readonly IconId _iconId; 40 | 41 | private string _displayName; 42 | 43 | public ZenSharpLookupItem(Template template, GenerateTree tree, IEnumerable scopes, IconId iconId) 44 | : base(template, true, Shell.Instance.GetComponent()) 45 | { 46 | _tree = tree; 47 | _scopes = scopes; 48 | _template = template; 49 | Log.Info("Creating ZenSharpLookupItem with template = {0}", template); 50 | _iconId = iconId; 51 | _displayName = _template.Text; 52 | } 53 | 54 | RichText ILookupItem.DisplayName 55 | { 56 | get { return new RichText(_displayName); } 57 | } 58 | 59 | bool ILookupItem.CanShrink 60 | { 61 | get { return true; } 62 | } 63 | 64 | IconId ILookupItem.Image 65 | { 66 | get { return _iconId; } 67 | } 68 | 69 | bool ILookupItem.IsDynamic 70 | { 71 | get { return true; } 72 | } 73 | 74 | bool ILookupItem.AcceptIfOnlyMatched(LookupItemAcceptanceContext itemAcceptanceContext) 75 | { 76 | return true; 77 | } 78 | 79 | MatchingResult ILookupItem.Match(PrefixMatcher prefixMatcher) 80 | { 81 | string prefix = prefixMatcher.Prefix; 82 | if (string.IsNullOrEmpty(prefix)) return null; 83 | 84 | Log.Info("Match prefix = {0}", prefix); 85 | if (_tree == null) 86 | { 87 | Log.Error("Expand tree is null, return."); 88 | return null; 89 | } 90 | 91 | var matcher = new LiveTemplateMatcher(_tree); 92 | var matchedScopes = _scopes.Where(s => _tree.IsScopeExist(s)).ToList(); 93 | Log.Trace("Matched scopes = {0}", string.Join(", ", matchedScopes)); 94 | 95 | if (matchedScopes.Count == 0) 96 | { 97 | return null; 98 | } 99 | 100 | foreach (var scope in matchedScopes) 101 | { 102 | try 103 | { 104 | var matchingResult = GetMatchingResult(prefix, matcher, scope); 105 | if (matchingResult != null) 106 | { 107 | return matchingResult; 108 | } 109 | } 110 | catch (Exception e) 111 | { 112 | Log.LogException(LoggingLevel.ERROR, e, ExceptionOrigin.Assertion, "Exception during match"); 113 | return null; 114 | } 115 | } 116 | return null; 117 | } 118 | 119 | private MatchingResult GetMatchingResult(string prefix, LiveTemplateMatcher matcher, string scopeName) 120 | { 121 | var matchResult = matcher.Match(prefix, scopeName); 122 | if (matchResult.Success) 123 | { 124 | FillText(prefix, matchResult); 125 | Log.Info("Successfull match in scope [{1}]. Return [{0}]", matchResult, scopeName); 126 | return CreateMatchingResult(prefix); 127 | } 128 | else if (matchResult.Suggestion != null && string.IsNullOrEmpty(matchResult.Suggestion.Tail)) 129 | { 130 | FillText(prefix, matchResult.Suggestion); 131 | Log.Info("Suggestion match in scope [{1}] with result [{0}]", matchResult, scopeName); 132 | 133 | return CreateMatchingResult(prefix); 134 | } 135 | else 136 | { 137 | Log.Info("No completition found for {0} in scope {1}", prefix, scopeName); 138 | return null; 139 | } 140 | } 141 | 142 | private static MatchingResult CreateMatchingResult(string prefix) 143 | { 144 | // todo: review parameters 145 | var enableAllFlags = MatcherScore.Highest - 1; 146 | return new MatchingResult(prefix.Length, 1, enableAllFlags); 147 | } 148 | 149 | private string FillText(string prefix, LiveTemplateMatcher.MatchResult matchResult) 150 | { 151 | var matchExpand = matchResult.Expand(prefix); 152 | Log.Trace("Template text: {0}", matchExpand); 153 | if (!string.IsNullOrEmpty(matchExpand)) 154 | { 155 | _template.Text = matchExpand; 156 | _displayName = matchResult.ExpandDisplay(prefix); 157 | 158 | FillMacros(prefix, matchResult); 159 | } 160 | return matchExpand; 161 | } 162 | 163 | private void FillMacros(string prefix, LiveTemplateMatcher.MatchResult matchResult) 164 | { 165 | _template.Fields.Clear(); 166 | var appliedRules = matchResult.ReMatchLeafs(prefix); 167 | var appliedSubsNames = new List(); 168 | foreach (var subst in appliedRules.Where(ar => ar.This is LeafRule.Substitution)) 169 | { 170 | var rule = (LeafRule.Substitution)subst.This; 171 | if (!appliedSubsNames.Contains(rule.Name)) 172 | { 173 | appliedSubsNames.Add(rule.Name); 174 | 175 | var macros = rule.Macros(); 176 | if (string.IsNullOrEmpty(macros)) 177 | { 178 | macros = "complete()"; 179 | } 180 | else 181 | { 182 | macros = macros.Replace("\\0", subst.Short); 183 | } 184 | Log.Trace("Place holder macro: {0}, {1}", macros, rule.Name); 185 | _template.Fields.Add(new TemplateField(rule.Name, macros, 0)); 186 | } 187 | } 188 | } 189 | } 190 | } 191 | -------------------------------------------------------------------------------- /ZenSharp.Integration/ZenSharpSettings.cs: -------------------------------------------------------------------------------- 1 | using JetBrains.Util; 2 | 3 | using System; 4 | using System.IO; 5 | using JetBrains.Application.Settings; 6 | using JetBrains.ReSharper.Resources.Settings; 7 | 8 | namespace Github.Ulex.ZenSharp.Integration 9 | { 10 | [SettingsKey(typeof(PatternsAndTemplatesSettingsKey), "ZenSharp settings")] 11 | public sealed class ZenSharpSettings 12 | { 13 | [SettingsEntry("Templates.ltg", "Path to ltg file")] 14 | public string TreeFilename { get; set; } 15 | 16 | public static string GetTreePath(string treeFilename) 17 | { 18 | if (treeFilename.IsNullOrEmpty()) 19 | { 20 | return null; 21 | } 22 | if (!string.IsNullOrEmpty(treeFilename) && Path.IsPathRooted(treeFilename)) 23 | { 24 | return treeFilename; 25 | } 26 | else 27 | { 28 | return Path.Combine(DefaultDir, treeFilename); 29 | } 30 | } 31 | 32 | private static string DefaultDir 33 | { 34 | get 35 | { 36 | // todo: store ltg iside ReSharper config 37 | return Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); 38 | } 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /ZenSharp.Integration/ZoneMarker.cs: -------------------------------------------------------------------------------- 1 | using JetBrains.Application.BuildScript.Application.Zones; 2 | using JetBrains.Platform.VisualStudio.Protocol.Zones; 3 | using JetBrains.ReSharper.Psi.CSharp; 4 | using JetBrains.TextControl; 5 | 6 | namespace Github.Ulex.ZenSharp.Integration 7 | { 8 | [ZoneDefinition(ZoneFlags.AutoEnable)] 9 | [ZoneDefinitionConfigurableFeature("ZenSharp", "ZenSharp auto completion", false)] 10 | public interface IZenSharpZoneDefinition : IZone, IRequire, IRequire, ILanguageCSharpZone 11 | { 12 | } 13 | 14 | [ZoneMarker] 15 | public class ZoneMarker : IRequire 16 | { 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /ZenSharp.Integration/app.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | Templates.ltg 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /ZenSharp.Integration/resharper_macros.71.txt: -------------------------------------------------------------------------------- 1 | // getCreationTime 2 | // Date and time when the file was created in specified {#0:format} 3 | // Evaluates file creation date and time 4 | // P: String 5 | 6 | // list 7 | // {#0:Comma-delimited list of values} 8 | // Displays the specified list of values. 9 | // P: String 10 | 11 | // spacestounderstrokes 12 | // Value of {#0:another variable}, where spaces will be replaced with '_' 13 | // Changes spaces to '_' (i.e. "do something usefull" into "do_something_usefull" 14 | // P: VariableReference 15 | 16 | // arrayVariable 17 | // Suggest an array variable 18 | // Suggests variable which type is array type 19 | 20 | // fixedTypeName 21 | // Insert reference to {#0:type} 22 | // Evaluates to selected type name. 23 | // P: Type 24 | 25 | // capitalize 26 | // Value of {#0:another variable} with the first character in upper case 27 | // Capitalizes string value (i.e. changes case of the first letter to upper) 28 | // P: VariableReference 29 | 30 | // clipboard 31 | // Clipboard content 32 | // Evaluates to current textual clipboard content 33 | 34 | // complete 35 | // Execute basic completion 36 | // Show basic code completion list at the point where the variable is evaluated 37 | 38 | // completeSmart 39 | // Execute smart completion 40 | // Show smart code completion list at the point where the variable is evaluated 41 | 42 | // completeType 43 | // Execute type completion 44 | // Show type completion list at the point where the variable is evaluated 45 | // P: Type 46 | 47 | // constant 48 | // {#0:Constant value} 49 | // Evaluates to the specified constant value. 50 | // P: String 51 | 52 | // typeMember 53 | // Containing type member name 54 | // Evaluates to short name of the most inner containing type member (e.g. method or property). 55 | 56 | // typeName 57 | // Containing type name 58 | // Evaluates to short name of the most inner containing type. 59 | 60 | // context 61 | // Provides list of items describing current context 62 | // Provides list of items describing current context. This includes file name, containing type name, namespace name, etc. 63 | 64 | // getCurrentDate 65 | // Current date in specified {#0:format} 66 | // Evaluates current date 67 | // P: String 68 | 69 | // getCurrentTime 70 | // Current date and time in specified {#0:format} 71 | // Evaluates current date 72 | // P: String 73 | 74 | // getCurrentNamespace 75 | // Containing namespace 76 | // Evaluates name of the containing namespace 77 | 78 | // decapitalize 79 | // Value of {#0:another variable} with the first character in lower case 80 | // Decapitalizes string value (i.e. changes case of the first letter to lower) 81 | // P: VariableReference 82 | 83 | // getDefaultNamespace 84 | // Default namespace 85 | // Gets default namespace for the current project 86 | 87 | // fileDefaultNamespace 88 | // Default namespace for current file 89 | // Gets default namespace for the current file 90 | 91 | // getFileName 92 | // Current file name 93 | // Evaluates current file name 94 | 95 | // getFileNameWithoutExtension 96 | // Current file name without extension 97 | // Evaluates current file name without extension 98 | 99 | // getFullUserName 100 | // Full user name of the current user 101 | // Evaluates full name of the current user 102 | 103 | // guessElementType 104 | // Guess element type of collection represented by {#0:variable} 105 | // Analyzes code and guesses type of element of a collection. 106 | // P: VariableReference 107 | 108 | // guessExpectedElementType 109 | // Guess element type for expected collection type 110 | // Guess element type if a collection type is expected at this point 111 | 112 | // guessExpectedType 113 | // Guess type expected at this point 114 | // Guess type expected at this point 115 | // P: Type 116 | 117 | // guessKeyType 118 | // Guess key type of dictionary represented by {#0:variable} 119 | // Analyzes code and guesses type of key of a dictionary collection. 120 | // P: VariableReference 121 | 122 | // guessValueType 123 | // Guess value type of dictionary represented by {#0:variable} 124 | // Analyzes code and guesses type of value of a dictionary collection. 125 | // P: VariableReference 126 | 127 | // guid 128 | // New GUID 129 | // Generates new Globally Unique Identifier (GUID) 130 | 131 | // lineNumber 132 | // Current line number 133 | // Evaluates to number of the line macro is evaluated at. 134 | 135 | // getOutputName 136 | // Current project output assembly name 137 | // Evaluates output assembly name for the current project 138 | 139 | // parameterOfType 140 | // Suggest parameter of {#0:type} 141 | // Suggests parameters of the specified type. 142 | // P: Type 143 | 144 | // getProjectName 145 | // Name of the current project 146 | // Evaluates current project name 147 | 148 | // getSolutionName 149 | // Current solution name 150 | // Evaluates current solution name 151 | 152 | // enumerableVariable 153 | // Suggest enumerable variable 154 | // Suggests visible variable that can be enumerated (that is, used in foreach loop as collection) 155 | 156 | // suggestIndexVariable 157 | // Suggest name for an index variable 158 | // Suggests non-used name which can be used for an index variable at the evaluation point. 159 | 160 | // suggestVariableName 161 | // Suggest name for a variable 162 | // When exectuted in variable declaration (where variable name should stand), suggests name for the variable. 163 | 164 | // variableOfType 165 | // Suggest variable of {#0:type} 166 | // Suggests variables of the specified type. 167 | // P: Type 168 | 169 | // suggestVariableType 170 | // Suggest type for a new variable 171 | // Suggest type for a new variable declared in the template 172 | 173 | // getUserName 174 | // Short name of the current user 175 | // Evaluates current user name 176 | 177 | // dependancyPropertyType 178 | // DependencyProperty type 179 | // Evaluates to dependency property type specific to current framework 180 | 181 | // suggestAttributeNameByTag 182 | // Suggests attribute name by tag 183 | // Suggests attribute name used in the same tags in current document 184 | 185 | // suggestAttributeValue 186 | // Suggest attribute value 187 | // Suggest attribute value for current html tag attribute 188 | 189 | // suggestTagName 190 | // Suggests tag name 191 | // Suggests tag name used in current document 192 | 193 | // AspMasterpageContentGenerator 194 | // ASP.NET Masterpage content generator 195 | // Generate content for masterpage content placeholders at the point where the variable is evaluated 196 | 197 | // AspMvcController 198 | // ASP.NET MVC Controller 199 | // Show completion list with available ASP.NET MVC Controllers at the point where the variable is evaluated 200 | 201 | // AspMvcAction 202 | // ASP.NET MVC Action 203 | // Show completion list with available ASP.NET MVC Actions at the point where the variable is evaluated 204 | 205 | // runAtServer 206 | // Insert runat="server" if server-side tag selected 207 | // Insert runat="server" if server-side tag selected 208 | 209 | // fileheader 210 | // File header 211 | // Inserts the file header specified in the ReSharper options. 212 | 213 | // castToLeftSideType 214 | // Cast to the required type (if the cast is necessary) 215 | // Inserts (if required) cast to the type which is expected at the left side of assignment expression. 216 | 217 | // fullTagName 218 | // Full tag name 219 | // Inserts full name of containing tag 220 | 221 | // suggestXmlAttributeNameByTag 222 | // Suggests XML attribute name by tag 223 | // Suggests XML attribute name used in the same tags in current document 224 | 225 | // suggestAttributeName 226 | // Suggests XML attribute name 227 | // Suggests XML attribute name used in current document 228 | 229 | // suggestXmlTagName 230 | // Suggests XML tag name 231 | // Suggests XML tag name used in current document 232 | 233 | // tagName 234 | // Tag name 235 | // Inserts name of containing tag without namespace 236 | 237 | // tagNamespace 238 | // Tag namespace 239 | // Inserts namespace of containing tag 240 | 241 | -------------------------------------------------------------------------------- /ZenSharp.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $PackageId$ 5 | $PackageVersion$ 6 | ZenSharp auto completion plugin 7 | Alexander Ulitin 8 | 9 | A shortcuts language for defining ReSharper live template items. You can specify your own live template scheme using flexible language. 10 | Free and open source. For more information, see Github. 11 | 12 | 13 | Support 2024.3 eap 1 + 14 | 15 | Alexander Ulitin 16 | livetemplates code completion ltg 17 | https://github.com/ulex/ZenSharp 18 | https://raw.github.com/ulex/IntroduceNsAlias/master/icon.png 19 | https://opensource.org/licenses/MIT 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /ZenSharp.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.0.31521.260 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{EDCC3B85-0BAD-11DB-BC1A-00112FDE8B61}") = "ZenSharp.Core", "ZenSharp.Core\ZenSharp.Core.nproj", "{EFA574E2-DE9C-4017-BB5C-8FC4CD8D5E80}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ZenSharp.Core.Tests", "ZenSharp.Core\ZenSharp.Core.Tests\ZenSharp.Core.Tests.csproj", "{1390A507-A540-4FCD-B2F5-5455D21F35F6}" 9 | EndProject 10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{DAADCB1B-EC51-4030-A54B-C037312AC013}" 11 | EndProject 12 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{7D63C907-EF8D-43B0-B94A-18A316C8D6C0}" 13 | ProjectSection(SolutionItems) = preProject 14 | build.bat = build.bat 15 | buildNuPack.ps1 = buildNuPack.ps1 16 | ZenSharp.nuspec = ZenSharp.nuspec 17 | EndProjectSection 18 | EndProject 19 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ZenSharp.Integration", "ZenSharp.Integration\ZenSharp.Integration.csproj", "{0F533A6E-E130-11E4-88A7-74D435B9EFD1}" 20 | EndProject 21 | Global 22 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 23 | Debug|Any CPU = Debug|Any CPU 24 | Release|Any CPU = Release|Any CPU 25 | EndGlobalSection 26 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 27 | {EFA574E2-DE9C-4017-BB5C-8FC4CD8D5E80}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 28 | {EFA574E2-DE9C-4017-BB5C-8FC4CD8D5E80}.Debug|Any CPU.Build.0 = Debug|Any CPU 29 | {EFA574E2-DE9C-4017-BB5C-8FC4CD8D5E80}.Release|Any CPU.ActiveCfg = Release|Any CPU 30 | {EFA574E2-DE9C-4017-BB5C-8FC4CD8D5E80}.Release|Any CPU.Build.0 = Release|Any CPU 31 | {1390A507-A540-4FCD-B2F5-5455D21F35F6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 32 | {1390A507-A540-4FCD-B2F5-5455D21F35F6}.Debug|Any CPU.Build.0 = Debug|Any CPU 33 | {1390A507-A540-4FCD-B2F5-5455D21F35F6}.Release|Any CPU.ActiveCfg = Release|Any CPU 34 | {0F533A6E-E130-11E4-88A7-74D435B9EFD1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 35 | {0F533A6E-E130-11E4-88A7-74D435B9EFD1}.Debug|Any CPU.Build.0 = Debug|Any CPU 36 | {0F533A6E-E130-11E4-88A7-74D435B9EFD1}.Release|Any CPU.ActiveCfg = Release|Any CPU 37 | {0F533A6E-E130-11E4-88A7-74D435B9EFD1}.Release|Any CPU.Build.0 = Release|Any CPU 38 | EndGlobalSection 39 | GlobalSection(SolutionProperties) = preSolution 40 | HideSolutionNode = FALSE 41 | EndGlobalSection 42 | GlobalSection(NestedProjects) = preSolution 43 | {0F533A6E-E130-11E4-88A7-74D435B9EFD1} = {7D63C907-EF8D-43B0-B94A-18A316C8D6C0} 44 | EndGlobalSection 45 | GlobalSection(ExtensibilityGlobals) = postSolution 46 | SolutionGuid = {749E95FE-73F6-40C5-8C5F-D462882FEEB7} 47 | EndGlobalSection 48 | EndGlobal 49 | -------------------------------------------------------------------------------- /build.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | REM SET PATH=%PATH%;C:\Windows\Microsoft.NET\Framework64\v4.0.30319 3 | SET PATH=C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\MSBuild\Current\Bin;%PATH% 4 | SET HostFullIdentifier= 5 | 6 | if not defined version set /P VERSION=Version: 7 | 8 | 9 | powershell -ExecutionPolicy bypass .\patchAssemblyInfo.ps1 %VERSION% || goto :error 10 | msbuild /t:Build /p:Configuration=Release ZenSharp.sln || goto :error 11 | powershell.exe -ExecutionPolicy ByPass -File ".\buildNuPack.ps1" || goto :error 12 | powershell -ExecutionPolicy bypass .\patchAssemblyInfo.ps1 1.0.* || goto :error 13 | pause 14 | goto :EOF 15 | 16 | :error 17 | echo "Failded with error #%errorlevel%. 18 | exit /b %errorlevel% 19 | pause 20 | -------------------------------------------------------------------------------- /buildNuPack.ps1: -------------------------------------------------------------------------------- 1 | pushd $args[0] 2 | 3 | $nuspec = ".\ZenSharp.nuspec" 4 | $version = [System.Diagnostics.FileVersionInfo]::GetVersionInfo((gi .\bin\Release\ZenSharp.Core.dll).FullName).FileVersion 5 | write-host "Version = $version" 6 | 7 | $packages = @{ 8 | "ZenSharp_R91" = @{ 9 | 'PackageId' = 'Ulex.ZenSharp'; 10 | 'PackageVersion' = $version; 11 | 'DependencyId' = 'Wave'; 12 | 'DependencyVersion' = '243'; 13 | 'IntegrationDll' = 'ZenSharp.Integration\bin\Release\net472-windows\ZenSharp.Integration.dll'; 14 | 'TargetDir' = 'DotFiles\'; 15 | }; 16 | } 17 | foreach ($p in $packages.Values){ 18 | $properties = [String]::Join(";" ,($p.GetEnumerator() | % {("{0}={1}" -f @($_.Key, $_.Value))})) 19 | write-host $properties 20 | #.\ilmerge.bat $p['IntegrationDll'] 21 | nuget.exe pack $nuspec -Properties $properties 22 | } 23 | 24 | Move-Item *.nupkg .\bin\Release -Force 25 | 26 | popd 27 | -------------------------------------------------------------------------------- /dependencies.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "Nemerle", 4 | "version": "1.2.0.547", 5 | "url": "https://github.com/rsdn/nemerle", 6 | "license": "Custom license", 7 | "licenseUrl": "https://github.com/rsdn/nemerle/blob/v1.1/COPYRIGHT" 8 | } 9 | ] 10 | -------------------------------------------------------------------------------- /doc/railroad-diagrams.css: -------------------------------------------------------------------------------- 1 | svg.railroad-diagram { 2 | background-color: hsl(30,20%,95%); 3 | } 4 | svg.railroad-diagram path { 5 | stroke-width: 3; 6 | stroke: black; 7 | fill: rgba(0,0,0,0); 8 | } 9 | svg.railroad-diagram text { 10 | font: bold 14px monospace; 11 | text-anchor: middle; 12 | } 13 | svg.railroad-diagram text.label { 14 | text-anchor: start; 15 | } 16 | svg.railroad-diagram text.comment { 17 | font: italic 12px monospace; 18 | } 19 | svg.railroad-diagram rect { 20 | stroke-width: 3; 21 | stroke: black; 22 | fill: hsl(120,100%,90%); 23 | } 24 | -------------------------------------------------------------------------------- /doc/railroad-diagrams.js: -------------------------------------------------------------------------------- 1 | /* 2 | Railroad Diagrams 3 | by Tab Atkins Jr. (and others) 4 | http://xanthir.com 5 | http://twitter.com/tabatkins 6 | http://github.com/tabatkins/railroad-diagrams 7 | 8 | This document and all associated files in the github project are licensed under CC0: http://creativecommons.org/publicdomain/zero/1.0/ 9 | This means you can reuse, remix, or otherwise appropriate this project for your own use WITHOUT RESTRICTION. 10 | (The actual legal meaning can be found at the above link.) 11 | Don't ask me for permission to use any part of this project, JUST USE IT. 12 | I would appreciate attribution, but that is not required by the license. 13 | */ 14 | 15 | /* 16 | This file uses a module pattern to avoid leaking names into the global scope. 17 | The only accidental leakage is the name "temp". 18 | The exported names can be found at the bottom of this file; 19 | simply change the names in the array of strings to change what they are called in your application. 20 | 21 | As well, several configuration constants are passed into the module function at the bottom of this file. 22 | At runtime, these constants can be found on the Diagram class. 23 | */ 24 | 25 | var temp = (function(options) { 26 | function subclassOf(baseClass, superClass) { 27 | baseClass.prototype = Object.create(superClass.prototype); 28 | baseClass.prototype.$super = superClass.prototype; 29 | } 30 | 31 | function unnull(/* children */) { 32 | return [].slice.call(arguments).reduce(function(sofar, x) { return sofar !== undefined ? sofar : x; }); 33 | } 34 | 35 | function determineGaps(outer, inner) { 36 | var diff = outer - inner; 37 | switch(Diagram.INTERNAL_ALIGNMENT) { 38 | case 'left': return [0, diff]; break; 39 | case 'right': return [diff, 0]; break; 40 | case 'center': 41 | default: return [diff/2, diff/2]; break; 42 | } 43 | } 44 | 45 | function wrapString(value) { 46 | return ((typeof value) == 'string') ? new Terminal(value) : value; 47 | } 48 | 49 | 50 | function SVG(name, attrs, text) { 51 | attrs = attrs || {}; 52 | text = text || ''; 53 | var el = document.createElementNS("http://www.w3.org/2000/svg",name); 54 | for(var attr in attrs) { 55 | el.setAttribute(attr, attrs[attr]); 56 | } 57 | el.textContent = text; 58 | return el; 59 | } 60 | 61 | function FakeSVG(tagName, attrs, text){ 62 | if(!(this instanceof FakeSVG)) return new FakeSVG(tagName, attrs, text); 63 | if(text) this.children = text; 64 | else this.children = []; 65 | this.tagName = tagName; 66 | this.attrs = unnull(attrs, {}); 67 | return this; 68 | }; 69 | FakeSVG.prototype.format = function(x, y, width) { 70 | // Virtual 71 | }; 72 | FakeSVG.prototype.addTo = function(parent) { 73 | if(parent instanceof FakeSVG) { 74 | parent.children.push(this); 75 | return this; 76 | } else { 77 | var svg = this.toSVG(); 78 | parent.appendChild(svg); 79 | return svg; 80 | } 81 | }; 82 | FakeSVG.prototype.toSVG = function() { 83 | var el = SVG(this.tagName, this.attrs); 84 | if(typeof this.children == 'string') { 85 | el.textContent = this.children; 86 | } else { 87 | this.children.forEach(function(e) { 88 | el.appendChild(e.toSVG()); 89 | }); 90 | } 91 | return el; 92 | }; 93 | FakeSVG.prototype.toString = function() { 94 | var str = '<' + this.tagName + ' '; 95 | for(var attr in this.attrs) { 96 | str += attr + '="' + (this.attrs[attr]+'').replace('&', '&').replace('"', '"') + '" '; 97 | } 98 | str += '>'; 99 | if(typeof this.children == 'string') { 100 | str += this.children.replace('&', '&').replace('<', '<'); 101 | } else { 102 | this.children.forEach(function(e) { 103 | str += e; 104 | }); 105 | } 106 | str += ''; 107 | return str; 108 | } 109 | 110 | function Path(x,y) { 111 | if(!(this instanceof Path)) return new Path(x,y); 112 | FakeSVG.call(this, 'path'); 113 | this.attrs.d = "M"+x+' '+y; 114 | } 115 | subclassOf(Path, FakeSVG); 116 | Path.prototype.m = function(x,y) { 117 | this.attrs.d += 'm'+x+' '+y; 118 | return this; 119 | } 120 | Path.prototype.h = function(val) { 121 | this.attrs.d += 'h'+val; 122 | return this; 123 | } 124 | Path.prototype.right = Path.prototype.h; 125 | Path.prototype.left = function(val) { return this.h(-val); } 126 | Path.prototype.v = function(val) { 127 | this.attrs.d += 'v'+val; 128 | return this; 129 | } 130 | Path.prototype.down = Path.prototype.v; 131 | Path.prototype.up = function(val) { return this.v(-val); } 132 | Path.prototype.arc = function(sweep){ 133 | var x = Diagram.ARC_RADIUS; 134 | var y = Diagram.ARC_RADIUS; 135 | if(sweep[0] == 'e' || sweep[1] == 'w') { 136 | x *= -1; 137 | } 138 | if(sweep[0] == 's' || sweep[1] == 'n') { 139 | y *= -1; 140 | } 141 | if(sweep == 'ne' || sweep == 'es' || sweep == 'sw' || sweep == 'wn') { 142 | var cw = 1; 143 | } else { 144 | var cw = 0; 145 | } 146 | this.attrs.d += "a"+Diagram.ARC_RADIUS+" "+Diagram.ARC_RADIUS+" 0 0 "+cw+' '+x+' '+y; 147 | return this; 148 | } 149 | Path.prototype.format = function() { 150 | // All paths in this library start/end horizontally. 151 | // The extra .5 ensures a minor overlap, so there's no seams in bad rasterizers. 152 | this.attrs.d += 'h.5'; 153 | return this; 154 | } 155 | 156 | function Diagram(items) { 157 | if(!(this instanceof Diagram)) return new Diagram([].slice.call(arguments)); 158 | FakeSVG.call(this, 'svg', {class: Diagram.DIAGRAM_CLASS}); 159 | this.items = items.map(wrapString); 160 | this.items.unshift(new Start); 161 | this.items.push(new End); 162 | this.width = this.items.reduce(function(sofar, el) { return sofar + el.width + (el.needsSpace?20:0)}, 0)+1; 163 | this.up = this.items.reduce(function(sofar,el) { return Math.max(sofar, el.up)}, 0); 164 | this.down = this.items.reduce(function(sofar,el) { return Math.max(sofar, el.down)}, 0); 165 | this.formatted = false; 166 | } 167 | subclassOf(Diagram, FakeSVG); 168 | for(var option in options) { 169 | Diagram[option] = options[option]; 170 | } 171 | Diagram.prototype.format = function(paddingt, paddingr, paddingb, paddingl) { 172 | paddingt = unnull(paddingt, 20); 173 | paddingr = unnull(paddingt, 20); 174 | paddingb = unnull(paddingt, 20); 175 | paddingl = unnull(paddingr, 20); 176 | var x = paddingl; 177 | var y = paddingt; 178 | y += this.up; 179 | var g = FakeSVG('g', Diagram.STROKE_ODD_PIXEL_LENGTH ? {transform:'translate(.5 .5)'} : {}); 180 | for(var i = 0; i < this.items.length; i++) { 181 | var item = this.items[i]; 182 | if(item.needsSpace) { 183 | Path(x,y).h(10).addTo(g); 184 | x += 10; 185 | } 186 | item.format(x, y, item.width).addTo(g); 187 | x += item.width; 188 | if(item.needsSpace) { 189 | Path(x,y).h(10).addTo(g); 190 | x += 10; 191 | } 192 | } 193 | this.attrs.width = this.width + paddingl + paddingr; 194 | this.attrs.height = this.up + this.down + paddingt + paddingb; 195 | g.addTo(this); 196 | this.formatted = true; 197 | return this; 198 | } 199 | Diagram.prototype.addTo = function(parent) { 200 | parent = parent || document.body; 201 | return this.$super.addTo.call(this, parent); 202 | } 203 | Diagram.prototype.toSVG = function() { 204 | if (!this.formatted) { 205 | this.format(); 206 | } 207 | return this.$super.toSVG.call(this); 208 | } 209 | Diagram.prototype.toString = function() { 210 | if (!this.formatted) { 211 | this.format(); 212 | } 213 | return this.$super.toString.call(this); 214 | } 215 | 216 | function Sequence(items) { 217 | if(!(this instanceof Sequence)) return new Sequence([].slice.call(arguments)); 218 | FakeSVG.call(this, 'g'); 219 | this.items = items.map(wrapString); 220 | this.width = this.items.reduce(function(sofar, el) { return sofar + el.width + (el.needsSpace?20:0)}, 0); 221 | this.up = this.items.reduce(function(sofar,el) { return Math.max(sofar, el.up)}, 0); 222 | this.down = this.items.reduce(function(sofar,el) { return Math.max(sofar, el.down)}, 0); 223 | } 224 | subclassOf(Sequence, FakeSVG); 225 | Sequence.prototype.format = function(x,y,width) { 226 | // Hook up the two sides if this is narrower than its stated width. 227 | var gaps = determineGaps(width, this.width); 228 | Path(x,y).h(gaps[0]).addTo(this); 229 | Path(x+gaps[0]+this.width,y).h(gaps[1]).addTo(this); 230 | x += gaps[0]; 231 | 232 | for(var i = 0; i < this.items.length; i++) { 233 | var item = this.items[i]; 234 | if(item.needsSpace) { 235 | Path(x,y).h(10).addTo(this); 236 | x += 10; 237 | } 238 | item.format(x, y, item.width).addTo(this); 239 | x += item.width; 240 | if(item.needsSpace) { 241 | Path(x,y).h(10).addTo(this); 242 | x += 10; 243 | } 244 | } 245 | return this; 246 | } 247 | 248 | function Choice(normal, items) { 249 | if(!(this instanceof Choice)) return new Choice(normal, [].slice.call(arguments,1)); 250 | FakeSVG.call(this, 'g'); 251 | this.normal = normal; 252 | this.items = items.map(wrapString); 253 | this.width = this.items.reduce(function(sofar, el){return Math.max(sofar, el.width)},0) + Diagram.ARC_RADIUS*4; 254 | this.up = this.down = 0; 255 | for(var i = 0; i < this.items.length; i++) { 256 | var item = this.items[i]; 257 | if(i < normal) { this.up += Math.max(Diagram.ARC_RADIUS,item.up + item.down + Diagram.VERTICAL_SEPARATION); } 258 | if(i == normal) { this.up += Math.max(Diagram.ARC_RADIUS, item.up); this.down += Math.max(Diagram.ARC_RADIUS, item.down); } 259 | if(i > normal) { this.down += Math.max(Diagram.ARC_RADIUS,Diagram.VERTICAL_SEPARATION + item.up + item.down); } 260 | } 261 | } 262 | subclassOf(Choice, FakeSVG); 263 | Choice.prototype.format = function(x,y,width) { 264 | // Hook up the two sides if this is narrower than its stated width. 265 | var gaps = determineGaps(width, this.width); 266 | Path(x,y).h(gaps[0]).addTo(this); 267 | Path(x+gaps[0]+this.width,y).h(gaps[1]).addTo(this); 268 | x += gaps[0]; 269 | 270 | var last = this.items.length -1; 271 | var innerWidth = this.width - Diagram.ARC_RADIUS*4; 272 | 273 | // Do the elements that curve above 274 | for(var i = this.normal - 1; i >= 0; i--) { 275 | var item = this.items[i]; 276 | if( i == this.normal - 1 ) { 277 | var distanceFromY = Math.max(Diagram.ARC_RADIUS*2, this.items[i+1].up + Diagram.VERTICAL_SEPARATION + item.down); 278 | } 279 | Path(x,y).arc('se').up(distanceFromY - Diagram.ARC_RADIUS*2).arc('wn').addTo(this); 280 | item.format(x+Diagram.ARC_RADIUS*2,y - distanceFromY,innerWidth).addTo(this); 281 | Path(x+Diagram.ARC_RADIUS*2+innerWidth, y-distanceFromY).arc('ne').down(distanceFromY - Diagram.ARC_RADIUS*2).arc('ws').addTo(this); 282 | distanceFromY += Math.max(Diagram.ARC_RADIUS, item.up + Diagram.VERTICAL_SEPARATION + (i == 0 ? 0 : this.items[i-1].down)); 283 | } 284 | 285 | // Do the straight-line path. 286 | Path(x,y).right(Diagram.ARC_RADIUS*2).addTo(this); 287 | this.items[this.normal].format(x+Diagram.ARC_RADIUS*2, y, innerWidth).addTo(this); 288 | Path(x+Diagram.ARC_RADIUS*2+innerWidth, y).right(Diagram.ARC_RADIUS*2).addTo(this); 289 | 290 | // Do the elements that curve below 291 | for(var i = this.normal+1; i <= last; i++) { 292 | var item = this.items[i]; 293 | if( i == this.normal + 1 ) { 294 | var distanceFromY = Math.max(Diagram.ARC_RADIUS*2, this.items[i-1].down + Diagram.VERTICAL_SEPARATION + item.up); 295 | } 296 | Path(x,y).arc('ne').down(distanceFromY - Diagram.ARC_RADIUS*2).arc('ws').addTo(this); 297 | item.format(x+Diagram.ARC_RADIUS*2, y+distanceFromY, innerWidth).addTo(this); 298 | Path(x+Diagram.ARC_RADIUS*2+innerWidth, y+distanceFromY).arc('se').up(distanceFromY - Diagram.ARC_RADIUS*2).arc('wn').addTo(this); 299 | distanceFromY += Math.max(Diagram.ARC_RADIUS, item.down + Diagram.VERTICAL_SEPARATION + (i == last ? 0 : this.items[i+1].up)); 300 | } 301 | 302 | return this; 303 | } 304 | 305 | function Optional(item, skip) { 306 | if( skip === undefined ) 307 | return Choice(1, Skip(), item); 308 | else if ( skip === "skip" ) 309 | return Choice(0, Skip(), item); 310 | else 311 | throw "Unknown value for Optional()'s 'skip' argument."; 312 | } 313 | 314 | function OneOrMore(item, rep) { 315 | if(!(this instanceof OneOrMore)) return new OneOrMore(item, rep); 316 | FakeSVG.call(this, 'g'); 317 | rep = rep || (new Skip); 318 | this.item = wrapString(item); 319 | this.rep = wrapString(rep); 320 | this.width = Math.max(this.item.width, this.rep.width) + Diagram.ARC_RADIUS*2; 321 | this.up = this.item.up; 322 | this.down = Math.max(Diagram.ARC_RADIUS*2, this.item.down + Diagram.VERTICAL_SEPARATION + this.rep.up + this.rep.down); 323 | } 324 | subclassOf(OneOrMore, FakeSVG); 325 | OneOrMore.prototype.needsSpace = true; 326 | OneOrMore.prototype.format = function(x,y,width) { 327 | // Hook up the two sides if this is narrower than its stated width. 328 | var gaps = determineGaps(width, this.width); 329 | Path(x,y).h(gaps[0]).addTo(this); 330 | Path(x+gaps[0]+this.width,y).h(gaps[1]).addTo(this); 331 | x += gaps[0]; 332 | 333 | // Draw item 334 | Path(x,y).right(Diagram.ARC_RADIUS).addTo(this); 335 | this.item.format(x+Diagram.ARC_RADIUS,y,this.width-Diagram.ARC_RADIUS*2).addTo(this); 336 | Path(x+this.width-Diagram.ARC_RADIUS,y).right(Diagram.ARC_RADIUS).addTo(this); 337 | 338 | // Draw repeat arc 339 | var distanceFromY = Math.max(Diagram.ARC_RADIUS*2, this.item.down+Diagram.VERTICAL_SEPARATION+this.rep.up); 340 | Path(x+Diagram.ARC_RADIUS,y).arc('nw').down(distanceFromY-Diagram.ARC_RADIUS*2).arc('ws').addTo(this); 341 | this.rep.format(x+Diagram.ARC_RADIUS, y+distanceFromY, this.width - Diagram.ARC_RADIUS*2).addTo(this); 342 | Path(x+this.width-Diagram.ARC_RADIUS, y+distanceFromY).arc('se').up(distanceFromY-Diagram.ARC_RADIUS*2).arc('en').addTo(this); 343 | 344 | return this; 345 | } 346 | 347 | function ZeroOrMore(item, rep, skip) { 348 | return Optional(OneOrMore(item, rep), skip); 349 | } 350 | 351 | function Start() { 352 | if(!(this instanceof Start)) return new Start(); 353 | FakeSVG.call(this, 'path'); 354 | this.width = 20; 355 | this.up = 10; 356 | this.down = 10; 357 | } 358 | subclassOf(Start, FakeSVG); 359 | Start.prototype.format = function(x,y) { 360 | this.attrs.d = 'M '+x+' '+(y-10)+' v 20 m 10 -20 v 20 m -10 -10 h 20.5'; 361 | return this; 362 | } 363 | 364 | function End() { 365 | if(!(this instanceof End)) return new End(); 366 | FakeSVG.call(this, 'path'); 367 | this.width = 20; 368 | this.up = 10; 369 | this.down = 10; 370 | } 371 | subclassOf(End, FakeSVG); 372 | End.prototype.format = function(x,y) { 373 | this.attrs.d = 'M '+x+' '+y+' h 20 m -10 -10 v 20 m 10 -20 v 20'; 374 | return this; 375 | } 376 | 377 | function Terminal(text) { 378 | if(!(this instanceof Terminal)) return new Terminal(text); 379 | FakeSVG.call(this, 'g'); 380 | this.text = text; 381 | this.width = text.length * 8 + 20; /* Assume that each char is .5em, and that the em is 16px */ 382 | this.up = 11; 383 | this.down = 11; 384 | } 385 | subclassOf(Terminal, FakeSVG); 386 | Terminal.prototype.needsSpace = true; 387 | Terminal.prototype.format = function(x, y, width) { 388 | // Hook up the two sides if this is narrower than its stated width. 389 | var gaps = determineGaps(width, this.width); 390 | Path(x,y).h(gaps[0]).addTo(this); 391 | Path(x+gaps[0]+this.width,y).h(gaps[1]).addTo(this); 392 | x += gaps[0]; 393 | 394 | FakeSVG('rect', {x:x, y:y-11, width:this.width, height:this.up+this.down, rx:10, ry:10}).addTo(this); 395 | FakeSVG('text', {x:x+this.width/2, y:y+4}, this.text).addTo(this); 396 | return this; 397 | } 398 | 399 | function NonTerminal(text) { 400 | if(!(this instanceof NonTerminal)) return new NonTerminal(text); 401 | FakeSVG.call(this, 'g'); 402 | this.text = text; 403 | this.width = text.length * 8 + 20; 404 | this.up = 11; 405 | this.down = 11; 406 | } 407 | subclassOf(NonTerminal, FakeSVG); 408 | NonTerminal.prototype.needsSpace = true; 409 | NonTerminal.prototype.format = function(x, y, width) { 410 | // Hook up the two sides if this is narrower than its stated width. 411 | var gaps = determineGaps(width, this.width); 412 | Path(x,y).h(gaps[0]).addTo(this); 413 | Path(x+gaps[0]+this.width,y).h(gaps[1]).addTo(this); 414 | x += gaps[0]; 415 | 416 | FakeSVG('rect', {x:x, y:y-11, width:this.width, height:this.up+this.down}).addTo(this); 417 | FakeSVG('text', {x:x+this.width/2, y:y+4}, this.text).addTo(this); 418 | return this; 419 | } 420 | 421 | function Comment(text) { 422 | if(!(this instanceof Comment)) return new Comment(text); 423 | FakeSVG.call(this, 'g'); 424 | this.text = text; 425 | this.width = text.length * 7 + 10; 426 | this.up = 11; 427 | this.down = 11; 428 | } 429 | subclassOf(Comment, FakeSVG); 430 | Comment.prototype.needsSpace = true; 431 | Comment.prototype.format = function(x, y, width) { 432 | // Hook up the two sides if this is narrower than its stated width. 433 | var gaps = determineGaps(width, this.width); 434 | Path(x,y).h(gaps[0]).addTo(this); 435 | Path(x+gaps[0]+this.width,y).h(gaps[1]).addTo(this); 436 | x += gaps[0]; 437 | 438 | FakeSVG('text', {x:x+this.width/2, y:y+5, class:'comment'}, this.text).addTo(this); 439 | return this; 440 | } 441 | 442 | function Skip() { 443 | if(!(this instanceof Skip)) return new Skip(); 444 | FakeSVG.call(this, 'g'); 445 | this.width = 0; 446 | this.up = 0; 447 | this.down = 0; 448 | } 449 | subclassOf(Skip, FakeSVG); 450 | Skip.prototype.format = function(x, y, width) { 451 | Path(x,y).right(width).addTo(this); 452 | return this; 453 | } 454 | 455 | return [Diagram, Sequence, Choice, Optional, OneOrMore, ZeroOrMore, Terminal, NonTerminal, Comment, Skip] 456 | })( 457 | { 458 | VERTICAL_SEPARATION: 8, 459 | ARC_RADIUS: 10, 460 | DIAGRAM_CLASS: 'railroad-diagram', 461 | STROKE_ODD_PIXEL_LENGTH: true, 462 | INTERNAL_ALIGNMENT: 'center', 463 | } 464 | ); 465 | 466 | /* 467 | These are the names that the internal classes are exported as. 468 | If you would like different names, adjust them here. 469 | */ 470 | ['Diagram', 'Sequence', 'Choice', 'Optional', 'OneOrMore', 'ZeroOrMore', 'Terminal', 'NonTerminal', 'Comment', 'Skip'] 471 | .forEach(function(e,i) { window[e] = temp[i]; }); -------------------------------------------------------------------------------- /doc/sample.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 |

public
_
private
pr
protected
28 | 29 | -------------------------------------------------------------------------------- /doc/screen1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ulex/ZenSharp/6ffb45b8c817e463be8bd24d822eed87a9844f00/doc/screen1.gif -------------------------------------------------------------------------------- /doc/screen2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ulex/ZenSharp/6ffb45b8c817e463be8bd24d822eed87a9844f00/doc/screen2.gif -------------------------------------------------------------------------------- /patchAssemblyInfo.ps1: -------------------------------------------------------------------------------- 1 | # copyright: http://blogs.msdn.com/b/dotnetinterop/archive/2008/04/21/powershell-script-to-batch-update-assemblyinfo-cs-with-new-version.aspx 2 | # added support to Nemerle Assembly infos 3 | # SetVersion.ps1 4 | # 5 | # Set the version in all the AssemblyInfo.cs or AssemblyInfo.vb files in any subdirectory. 6 | # 7 | # usage: 8 | # from cmd.exe: 9 | # powershell.exe SetVersion.ps1 2.8.3.0 10 | # 11 | # from powershell.exe prompt: 12 | # .\SetVersion.ps1 2.8.3.0 13 | # 14 | # last saved Time-stamp: 15 | # 16 | 17 | 18 | function Usage 19 | { 20 | echo "Usage: "; 21 | echo " from cmd.exe: "; 22 | echo " powershell.exe SetVersion.ps1 2.8.3.0"; 23 | echo " "; 24 | echo " from powershell.exe prompt: "; 25 | echo " .\SetVersion.ps1 2.8.3.0"; 26 | echo " "; 27 | } 28 | 29 | 30 | function Update-SourceVersion 31 | { 32 | Param ([string]$Version) 33 | $NewVersion = 'AssemblyVersion("' + $Version + '")'; 34 | $NewFileVersion = 'AssemblyFileVersion("' + $Version + '")'; 35 | 36 | foreach ($o in $input) 37 | { 38 | Write-output $o.FullName 39 | $TmpFile = $o.FullName + ".tmp" 40 | 41 | get-content $o.FullName | 42 | %{$_ -replace 'AssemblyVersion\("[0-9]+(\.([0-9]+|\*)){1,3}"\)', $NewVersion } | 43 | %{$_ -replace 'AssemblyFileVersion\("[0-9]+(\.([0-9]+|\*)){1,3}"\)', $NewFileVersion } | 44 | Set-Content -Encoding UTF8 $TmpFile 45 | 46 | move-item $TmpFile $o.FullName -force 47 | } 48 | } 49 | 50 | 51 | function Update-AllAssemblyInfoFiles ( $version ) 52 | { 53 | foreach ($file in "AssemblyInfo.cs", "AssemblyInfo.n" ) 54 | { 55 | get-childitem -recurse |? {$_.Name -eq $file} | Update-SourceVersion $version ; 56 | } 57 | } 58 | 59 | 60 | Update-AllAssemblyInfoFiles $args[0]; 61 | --------------------------------------------------------------------------------