diff --git a/Build/.nuke/build.schema.json b/Build/.nuke/build.schema.json index 4915399..d566ae7 100644 --- a/Build/.nuke/build.schema.json +++ b/Build/.nuke/build.schema.json @@ -54,6 +54,9 @@ "MainName": { "type": "string" }, + "MiddleVersions": { + "type": "boolean" + }, "Name": { "type": "string" }, diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e93be7..de6ebe7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,14 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +## [1.0.5] / 2023-05-05 +### Features +- Support C# version 7.3 in Revit 2021+ with `DotNetCompilerPlatform`. +- Gist Download Files and compile. +- Support `CodeDomService` with Defines - `Revit20$$` and `REVIT20$$`. +### Updated +- Update `InfoCenterUtils` to show download update. + ## [1.0.4] / 2023-02-03 ### Updated - Update example `Command` to `Revit Version` @@ -30,6 +38,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - [x] AutoUpdater [vNext]: ../../compare/1.0.0...HEAD +[1.0.5]: ../../compare/1.0.4...1.0.5 [1.0.4]: ../../compare/1.0.3...1.0.4 [1.0.3]: ../../compare/1.0.2...1.0.3 [1.0.2]: ../../compare/1.0.1...1.0.2 diff --git a/README.md b/README.md index 59cb94d..cc7fae7 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,9 @@ This project was generated by the [AppLoader](https://ricaun.com/apploader/) Rev ## Limitations +In Revit 2021+ the `CodeDom.Compiler` uses the (Roslyn)[https://github.com/aspnet/RoslynCodeDomProvider] version compiler. +The Roslyn compiler is a new compiler that supports C# version 6 and above. + `CodeDom.Compiler` only work with C# compiler version `v4.0` maximum, the following features do not work in C# version 4. * Async Features (C# version 5) * String interpolation (C# version 6) diff --git a/RevitAddin.CommandLoader.sln b/RevitAddin.CommandLoader.sln index 64dfdb0..37076df 100644 --- a/RevitAddin.CommandLoader.sln +++ b/RevitAddin.CommandLoader.sln @@ -1,11 +1,11 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.29613.14 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.33424.131 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FD2A9150-BC8F-4112-B3C1-0F6778EB3CBC}") = "RevitAddin.CommandLoader", "RevitAddin.CommandLoader\RevitAddin.CommandLoader.csproj", "{82070359-36DA-4441-A59D-9018B6A8B348}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RevitAddin.CommandLoader", "RevitAddin.CommandLoader\RevitAddin.CommandLoader.csproj", "{82070359-36DA-4441-A59D-9018B6A8B348}" EndProject -Project("{FD2A9150-BC8F-4112-B3C1-0F6778EB3CBC}") = "Build", "Build\Build.csproj", "{34853418-411C-4B27-82AF-DDE5309AEE10}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Build", "Build\Build.csproj", "{34853418-411C-4B27-82AF-DDE5309AEE10}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution", "Solution", "{E6AC2FD0-D488-44FE-9390-3CADFB37E99D}" ProjectSection(SolutionItems) = preProject @@ -16,18 +16,29 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution", "Solution", "{E6 EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU + 2017|Any CPU = 2017|Any CPU + 2021|Any CPU = 2021|Any CPU + Debug 2017|Any CPU = Debug 2017|Any CPU + Debug 2021|Any CPU = Debug 2021|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {82070359-36DA-4441-A59D-9018B6A8B348}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {82070359-36DA-4441-A59D-9018B6A8B348}.Debug|Any CPU.Build.0 = Debug|Any CPU - {82070359-36DA-4441-A59D-9018B6A8B348}.Release|Any CPU.ActiveCfg = Release|Any CPU - {82070359-36DA-4441-A59D-9018B6A8B348}.Release|Any CPU.Build.0 = Release|Any CPU - {34853418-411C-4B27-82AF-DDE5309AEE10}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {34853418-411C-4B27-82AF-DDE5309AEE10}.Release|Any CPU.ActiveCfg = Release|Any CPU + {82070359-36DA-4441-A59D-9018B6A8B348}.2017|Any CPU.ActiveCfg = 2017|Any CPU + {82070359-36DA-4441-A59D-9018B6A8B348}.2017|Any CPU.Build.0 = 2017|Any CPU + {82070359-36DA-4441-A59D-9018B6A8B348}.2021|Any CPU.ActiveCfg = 2021|Any CPU + {82070359-36DA-4441-A59D-9018B6A8B348}.2021|Any CPU.Build.0 = 2021|Any CPU + {82070359-36DA-4441-A59D-9018B6A8B348}.Debug 2017|Any CPU.ActiveCfg = Debug 2017|Any CPU + {82070359-36DA-4441-A59D-9018B6A8B348}.Debug 2017|Any CPU.Build.0 = Debug 2017|Any CPU + {82070359-36DA-4441-A59D-9018B6A8B348}.Debug 2021|Any CPU.ActiveCfg = Debug 2021|Any CPU + {82070359-36DA-4441-A59D-9018B6A8B348}.Debug 2021|Any CPU.Build.0 = Debug 2021|Any CPU + {34853418-411C-4B27-82AF-DDE5309AEE10}.2017|Any CPU.ActiveCfg = Release|Any CPU + {34853418-411C-4B27-82AF-DDE5309AEE10}.2021|Any CPU.ActiveCfg = Release|Any CPU + {34853418-411C-4B27-82AF-DDE5309AEE10}.Debug 2017|Any CPU.ActiveCfg = Debug|Any CPU + {34853418-411C-4B27-82AF-DDE5309AEE10}.Debug 2021|Any CPU.ActiveCfg = Debug|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {98A9768C-D450-4125-8057-441B3C106F5E} + EndGlobalSection EndGlobal diff --git a/RevitAddin.CommandLoader/Extensions/AppName.cs b/RevitAddin.CommandLoader/Extensions/AppName.cs index e279c25..0dae90c 100644 --- a/RevitAddin.CommandLoader/Extensions/AppName.cs +++ b/RevitAddin.CommandLoader/Extensions/AppName.cs @@ -21,5 +21,10 @@ public static string GetInfo() return result; } + + public static string GetUri() + { + return "https://github.com/ricaun-io/RevitAddin.CommandLoader"; + } } } diff --git a/RevitAddin.CommandLoader/Revit/App.cs b/RevitAddin.CommandLoader/Revit/App.cs index 72ad1e6..60e03ab 100644 --- a/RevitAddin.CommandLoader/Revit/App.cs +++ b/RevitAddin.CommandLoader/Revit/App.cs @@ -1,14 +1,14 @@ using Autodesk.Revit.DB; using Autodesk.Revit.UI; -using ricaun.Revit.UI; +using Revit.Async; +using RevitAddin.CommandLoader.Extensions; using ricaun.Revit.Github; +using ricaun.Revit.UI; using System; -using System.Threading.Tasks; -using System.Reflection; -using System.Linq; -using RevitAddin.CommandLoader.Extensions; using System.ComponentModel; -using Revit.Async; +using System.Linq; +using System.Reflection; +using System.Threading.Tasks; namespace RevitAddin.CommandLoader.Revit { @@ -29,7 +29,7 @@ public Result OnStartup(UIControlledApplication application) .SetLargeImage(Properties.Resources.CommandLoader.GetBitmapSource()) .SetToolTip("Open CommandLoader window that compiles Revit code and creates pushbuttons for each `IExternalCommand`, `IExternalCommandAvailability` could be used in the same class to enable the availability features.") .SetLongDescription(AppName.GetInfo()) - .SetContextualHelp("https://github.com/ricaun-io/RevitAddin.CommandLoader"); + .SetContextualHelp(AppName.GetUri()); service = new GithubRequestService("ricaun-io", "RevitAddin.CommandLoader"); @@ -57,6 +57,7 @@ private void ControlledApplication_ApplicationInitialized(object sender, Autodes bool downloadedNewVersion = await service.Initialize(); if (downloadedNewVersion) { + InfoCenterUtils.ShowBalloon("Download New Release!", null, AppName.GetUri()); Console.WriteLine($"RevitAddin.CommandLoader: {downloadedNewVersion}"); } }); diff --git a/RevitAddin.CommandLoader/Revit/CodeSamples.cs b/RevitAddin.CommandLoader/Revit/CodeSamples.cs new file mode 100644 index 0000000..7d33e2f --- /dev/null +++ b/RevitAddin.CommandLoader/Revit/CodeSamples.cs @@ -0,0 +1,146 @@ +using System; +using System.Net.NetworkInformation; +using System.Security.Policy; + +namespace RevitAddin.CommandLoader.Revit +{ + public class CodeSamples + { + public static string CommandVersionGist => "https://gist.github.com/ricaun/200a576c3baa45cba034ceedac1e708e"; + public static string Command => +@"using System; +using System.ComponentModel; +using Autodesk.Revit.Attributes; +using Autodesk.Revit.DB; +using Autodesk.Revit.UI; + +namespace RevitAddin +{ + [DisplayName(""Revit\rVersion"")] + [Description(""Show a Window with the Revit VersionName."")] + [Designer(""/UIFrameworkRes;component/ribbon/images/revit.ico"")] + [Transaction(TransactionMode.Manual)] + public class Command : IExternalCommand, IExternalCommandAvailability + { + public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elementSet) + { + UIApplication uiapp = commandData.Application; + System.Windows.MessageBox.Show(uiapp.Application.VersionName); + return Result.Succeeded; + } + public bool IsCommandAvailable(UIApplication applicationData, CategorySet selectedCategories) + { + return true; + } + } +}"; + + public static string CommandVersion => +@"using System; +using System.ComponentModel; +using Autodesk.Revit.Attributes; +using Autodesk.Revit.DB; +using Autodesk.Revit.UI; + +namespace RevitAddin +{ + [DisplayName(""Revit\rVersion"")] + [Description(""Show a Window with the Revit VersionName."")] + [Designer(""/UIFrameworkRes;component/ribbon/images/revit.ico"")] + [Transaction(TransactionMode.Manual)] + public class CommandVersion : IExternalCommand, IExternalCommandAvailability + { + public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elementSet) + { + UIApplication uiapp = commandData.Application; + System.Windows.MessageBox.Show(uiapp.Application.VersionName); + return Result.Succeeded; + } + public bool IsCommandAvailable(UIApplication applicationData, CategorySet selectedCategories) + { + return true; + } + } +}"; + + public static string CommandDeleteWalls => +@"using System; +using System.Collections.Generic; +using System.Linq; +using System.ComponentModel; +using Autodesk.Revit.ApplicationServices; +using Autodesk.Revit.Attributes; +using Autodesk.Revit.DB; +using Autodesk.Revit.UI; + +namespace RevitAddin +{ + [Transaction(TransactionMode.Manual)] + public class DeleteWalls : IExternalCommand + { + public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements) + { + UIApplication uiapp = commandData.Application; + UIDocument uidoc = uiapp.ActiveUIDocument; + Application app = uiapp.Application; + Document doc = uidoc.Document; + + // Get all walls in the document + List walls = new FilteredElementCollector(doc) + .OfClass(typeof(Wall)) + .Cast() + .ToList(); + + // Delete all walls + using (Transaction trans = new Transaction(doc)) + { + trans.Start(""Delete Walls""); + foreach (Wall wall in walls) + { + doc.Delete(wall.Id); + } + trans.Commit(); + } + return Result.Succeeded; + } + } +}"; + + public static string CommandTask => +@"using System; +using System.ComponentModel; +using System.Threading.Tasks; +using Autodesk.Revit.Attributes; +using Autodesk.Revit.DB; +using Autodesk.Revit.UI; + +namespace RevitAddin +{ + [DisplayName(""Task"")] + [Designer(""/UIFrameworkRes;component/ribbon/images/revit.ico"")] + [Transaction(TransactionMode.Manual)] + public class CommandTask : IExternalCommand, IExternalCommandAvailability + { + public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elementSet) + { + UIApplication uiapp = commandData.Application; + + Task.Run(async () => + { + await Task.Delay(100); + System.Windows.MessageBox.Show(uiapp.Application.VersionName); + }); + + return Result.Succeeded; + } + public bool IsCommandAvailable(UIApplication applicationData, CategorySet selectedCategories) + { + return true; + } + } +}"; + } +} + + + diff --git a/RevitAddin.CommandLoader/Revit/Commands/Command.cs b/RevitAddin.CommandLoader/Revit/Commands/Command.cs index a6d1cf5..78a23b7 100644 --- a/RevitAddin.CommandLoader/Revit/Commands/Command.cs +++ b/RevitAddin.CommandLoader/Revit/Commands/Command.cs @@ -3,6 +3,7 @@ using Autodesk.Revit.UI; using System; using System.ComponentModel; +using System.Threading.Tasks; namespace RevitAddin.CommandLoader.Revit.Commands { diff --git a/RevitAddin.CommandLoader/Revit/Commands/CommandTest.cs b/RevitAddin.CommandLoader/Revit/Commands/CommandTest.cs index ce2d4d0..30ce3a2 100644 --- a/RevitAddin.CommandLoader/Revit/Commands/CommandTest.cs +++ b/RevitAddin.CommandLoader/Revit/Commands/CommandTest.cs @@ -3,6 +3,8 @@ using Autodesk.Revit.UI; using RevitAddin.CommandLoader.Services; using System.ComponentModel; +using System.IO; +using System.Reflection; namespace RevitAddin.CommandLoader.Revit.Commands { @@ -14,72 +16,14 @@ public Result Execute(ExternalCommandData commandData, ref string message, Eleme { UIApplication uiapp = commandData.Application; - - var source = @" -using System; -using System.Collections.Generic; -using System.Linq; -using System.ComponentModel; -using Autodesk.Revit.ApplicationServices; -using Autodesk.Revit.Attributes; -using Autodesk.Revit.DB; -using Autodesk.Revit.UI; - -namespace Revit_Delete_Walls -{ - [Transaction(TransactionMode.Manual)] - public class DeleteWalls2 : IExternalCommand - { - public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements) - { - UIApplication uiapp = commandData.Application; - UIDocument uidoc = uiapp.ActiveUIDocument; - Application app = uiapp.Application; - Document doc = uidoc.Document; - - // Get all walls in the document - List walls = new FilteredElementCollector(doc) - .OfClass(typeof(Wall)) - .Cast() - .ToList(); - - // Delete all walls - using (Transaction trans = new Transaction(doc)) - { - trans.Start(""Delete Walls""); - foreach (Wall wall in walls) - { - doc.Delete(wall.Id); - } - trans.Commit(); - } - - return Result.Succeeded; - } - } - [DisplayName(""Command Name"")] - [Description(""This is a command tooltip"")] - [Designer("" / UIFrameworkRes;component/ribbon/images/revit.ico"")] - [Transaction(TransactionMode.Manual)] - public class Command : IExternalCommand, IExternalCommandAvailability - { - public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elementSet) - { - UIApplication uiapp = commandData.Application; - System.Windows.MessageBox.Show(uiapp.Application.VersionName); - return Result.Succeeded; - } - public bool IsCommandAvailable(UIApplication applicationData, CategorySet selectedCategories) - { - return true; - } - } -} -"; - try { - var assembly = new CodeDomService().GenerateCode(source); + CodeDomService codeDomService = new CodeDomService(); + var assembly = codeDomService.GenerateCode( + CodeSamples.CommandVersion, + CodeSamples.CommandTask, + CodeSamples.CommandDeleteWalls); + App.CreateCommands(assembly); } catch (System.Exception ex) @@ -87,8 +31,6 @@ public bool IsCommandAvailable(UIApplication applicationData, CategorySet select System.Windows.MessageBox.Show(ex.ToString()); } - //System.Windows.MessageBox.Show(uiapp.Application.VersionName); - return Result.Succeeded; } diff --git a/RevitAddin.CommandLoader/Revit/Commands/CommandTestGist.cs b/RevitAddin.CommandLoader/Revit/Commands/CommandTestGist.cs new file mode 100644 index 0000000..7188f96 --- /dev/null +++ b/RevitAddin.CommandLoader/Revit/Commands/CommandTestGist.cs @@ -0,0 +1,37 @@ +using Autodesk.Revit.Attributes; +using Autodesk.Revit.DB; +using Autodesk.Revit.UI; +using RevitAddin.CommandLoader.Services; +using System; +using System.ComponentModel; + +namespace RevitAddin.CommandLoader.Revit.Commands +{ + [DisplayName("Command Test - Compile Gist")] + [Transaction(TransactionMode.Manual)] + public class CommandTestGist : IExternalCommand + { + public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elementSet) + { + UIApplication uiapp = commandData.Application; + + var gistUrl = "https://gist.github.com/ricaun/4f62b8650d29f1ff837e7e77f9e8b552"; + + GistGithubUtils.TryGetGistString(gistUrl, out string gistContent); + + try + { + CodeDomService codeDomService = new CodeDomService() { UseLegacyCodeDom = true }; + var assembly = codeDomService.GenerateCode(gistContent); + + App.CreateCommands(assembly); + } + catch (System.Exception ex) + { + System.Windows.MessageBox.Show(ex.ToString()); + } + + return Result.Succeeded; + } + } +} diff --git a/RevitAddin.CommandLoader/Revit/Commands/CommandTestGistFiles.cs b/RevitAddin.CommandLoader/Revit/Commands/CommandTestGistFiles.cs new file mode 100644 index 0000000..1868606 --- /dev/null +++ b/RevitAddin.CommandLoader/Revit/Commands/CommandTestGistFiles.cs @@ -0,0 +1,37 @@ +using Autodesk.Revit.Attributes; +using Autodesk.Revit.DB; +using Autodesk.Revit.UI; +using RevitAddin.CommandLoader.Services; +using System.ComponentModel; + +namespace RevitAddin.CommandLoader.Revit.Commands +{ + [DisplayName("Command Test - Compile Gist Files")] + [Transaction(TransactionMode.Manual)] + public class CommandTestGistFiles : IExternalCommand + { + public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elementSet) + { + UIApplication uiapp = commandData.Application; + + var gistUrlFiles = "https://gist.github.com/ricaun/14ec0730e7efb3cc737f2134475e2539"; + + GistGithubUtils.TryGetGistFilesContent(gistUrlFiles, out string[] gistFilesContent); + + try + { + CodeDomService codeDomService = new CodeDomService(); + var assembly = codeDomService.GenerateCode(gistFilesContent); + + App.CreateCommands(assembly); + } + catch (System.Exception ex) + { + System.Windows.MessageBox.Show(ex.ToString()); + } + + return Result.Succeeded; + } + } + +} diff --git a/RevitAddin.CommandLoader/Revit/InfoCenterUtils.cs b/RevitAddin.CommandLoader/Revit/InfoCenterUtils.cs new file mode 100644 index 0000000..00e73e9 --- /dev/null +++ b/RevitAddin.CommandLoader/Revit/InfoCenterUtils.cs @@ -0,0 +1,18 @@ +using System; + +namespace RevitAddin.CommandLoader.Revit +{ + public static class InfoCenterUtils + { + public static void ShowBalloon(string title, string category = null, string uriString = null) + { + if (title == null) return; + Autodesk.Internal.InfoCenter.ResultItem ri = new Autodesk.Internal.InfoCenter.ResultItem(); + ri.Category = category ?? typeof(InfoCenterUtils).Assembly.GetName().Name; + ri.Title = title.Trim(); + if (Uri.TryCreate(uriString, UriKind.RelativeOrAbsolute, out Uri uri)) + ri.Uri = uri; + Autodesk.Windows.ComponentManager.InfoCenterPaletteManager.ShowBalloon(ri); + } + } +} diff --git a/RevitAddin.CommandLoader/RevitAddin.CommandLoader.csproj b/RevitAddin.CommandLoader/RevitAddin.CommandLoader.csproj index 12f915d..3ff7be4 100644 --- a/RevitAddin.CommandLoader/RevitAddin.CommandLoader.csproj +++ b/RevitAddin.CommandLoader/RevitAddin.CommandLoader.csproj @@ -8,9 +8,7 @@ latest false None - - Debug; Release; - + Debug 2017;2017;Debug 2021;2021 @@ -68,7 +66,7 @@ true - bin\Release\ + bin\Release\$(RevitVersion)\ REVIT$(RevitVersion) MSB3052 None @@ -91,7 +89,7 @@ RevitAddin.CommandLoader - 1.0.4 + 1.0.5 {82070359-36DA-4441-A59D-9018B6A8B348} @@ -117,6 +115,10 @@ Copyright © $(CopyrightYears) $(Company) + + + + diff --git a/RevitAddin.CommandLoader/Sevices/CodeDomService.cs b/RevitAddin.CommandLoader/Services/CodeDomService.cs similarity index 66% rename from RevitAddin.CommandLoader/Sevices/CodeDomService.cs rename to RevitAddin.CommandLoader/Services/CodeDomService.cs index 002b543..5cca921 100644 --- a/RevitAddin.CommandLoader/Sevices/CodeDomService.cs +++ b/RevitAddin.CommandLoader/Services/CodeDomService.cs @@ -1,8 +1,8 @@ -using Microsoft.CSharp; -using System; +using System; using System.CodeDom; using System.CodeDom.Compiler; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Reflection; @@ -10,21 +10,33 @@ namespace RevitAddin.CommandLoader.Services { public class CodeDomService { - public Assembly GenerateCode(string source) + public bool UseLegacyCodeDom { get; set; } + public string CompilerOptions { get; set; } + public CodeDomService SetDefines(params string[] defines) { - var targetUnit = new CodeSnippetCompileUnit(source); - return GenerateCode(targetUnit); + CompilerOptions += $" /define:{string.Join(";", defines).Replace(" ", "")}"; + return this; + } + public Assembly GenerateCode(params string[] sources) + { + var compilationUnits = sources + .Select(s => new CodeSnippetCompileUnit(s)) + .ToArray(); + + return GenerateCode(compilationUnits); } public Assembly GenerateCode(params CodeCompileUnit[] compilationUnits) { - CodeDomProvider provider = new CSharpCodeProvider(); + CodeDomProvider provider = CodeProviderService.GetCSharpCodeProvider(UseLegacyCodeDom); CompilerParameters compilerParametes = new CompilerParameters(); compilerParametes.GenerateExecutable = false; compilerParametes.IncludeDebugInformation = false; compilerParametes.GenerateInMemory = false; + compilerParametes.CompilerOptions = CompilerOptions; + #region Add GetReferencedAssemblies var assemblyNames = Assembly.GetExecutingAssembly().GetReferencedAssemblies(); var nameAssemblies = new Dictionary(); diff --git a/RevitAddin.CommandLoader/Services/CodeProviderService.cs b/RevitAddin.CommandLoader/Services/CodeProviderService.cs new file mode 100644 index 0000000..5105b4b --- /dev/null +++ b/RevitAddin.CommandLoader/Services/CodeProviderService.cs @@ -0,0 +1,54 @@ +using Microsoft.CSharp; +using System.CodeDom.Compiler; +using System.Collections.Generic; +using System.IO; + +namespace RevitAddin.CommandLoader.Services +{ + public class CodeProviderService + { + public static CodeDomProvider GetCSharpCodeProvider(bool useLegacyCodeDom = false) + { +#if NET48_OR_GREATER + if (!useLegacyCodeDom) + { + return NewCSharpCodeProvider(); + } +#endif + return new CSharpCodeProvider(); + } + +#if NET48_OR_GREATER + /// + /// NewCSharpCodeProvider + /// https://github.com/aspnet/RoslynCodeDomProvider + /// + /// + internal static CodeDomProvider NewCSharpCodeProvider() + { + var compilerSettings = new ProviderOptions() + { + CompilerFullPath = CompilerFullPath(@"roslyn/csc.exe"), + CompilerServerTimeToLive = 300 + }; + return new Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider(compilerSettings); + } + internal class ProviderOptions : Microsoft.CodeDom.Providers.DotNetCompilerPlatform.IProviderOptions + { + public string CompilerFullPath { get; set; } + public int CompilerServerTimeToLive { get; set; } + public string CompilerVersion { get; set; } + public bool WarnAsError { get; set; } + public bool UseAspNetSettings { get; set; } + public IDictionary AllOptions { get; set; } + } + private static string CompilerFullPath(string relativePath) + { + string frameworkFolder = Path.GetDirectoryName(typeof(CodeDomService).Assembly.Location); + string compilerFullPath = Path.Combine(frameworkFolder, relativePath); + + return compilerFullPath; + } +#endif + } +} \ No newline at end of file diff --git a/RevitAddin.CommandLoader/Services/GistGithubUtils.cs b/RevitAddin.CommandLoader/Services/GistGithubUtils.cs new file mode 100644 index 0000000..d2194a2 --- /dev/null +++ b/RevitAddin.CommandLoader/Services/GistGithubUtils.cs @@ -0,0 +1,111 @@ +using Autodesk.Revit.Exceptions; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Media.Animation; + +namespace RevitAddin.CommandLoader.Services +{ + public class GistGithubUtils + { + public static bool TryGetGistString(string url, out string output) + { + output = ""; + if (url.IndexOf("gist.github", StringComparison.InvariantCultureIgnoreCase) > -1) + { + url = url.Trim('/'); + if (url.IndexOf("/raw", StringComparison.InvariantCultureIgnoreCase) == -1) + { + url += "/raw"; + } + output = GetString(url); + return true; + } + return false; + } + + public static bool TryGetGistId(string url, out string id) + { + id = ""; + if (url.IndexOf("gist.github", StringComparison.InvariantCultureIgnoreCase) > -1) + { + url = url.Trim('/'); + id = url.Split('/').Last(); + return true; + } + return false; + } + + public static bool TryGetGistFilesContent(string url, out string[] contents) + { + contents = null; + if (TryGetGistModel(url, out GistModel gistModel)) + { + if (gistModel is not null) + { + contents = gistModel.files.Values.Select(e => e.content).ToArray(); + return contents.Length > 0; + } + } + return false; + } + + public static bool TryGetGistModel(string url, out GistModel gistModel) + { + gistModel = null; + if (TryGetGistId(url, out string gistId)) + { + var content = GetGistString(gistId); + if (content is null) + return false; + + try + { + var jsonService = new JsonService(); + gistModel = jsonService.Deserialize(content); + } + catch { } + + return gistModel is not null; + } + return false; + } + + private static string GetGistString(string id) + { + try + { + return GetString($"https://api.github.com/gists/{id}"); + } + catch { } + return null; + } + + private static string GetString(string url) + { + using (var client = new System.Net.WebClient()) + { + client.Headers.Add(System.Net.HttpRequestHeader.UserAgent, typeof(GistGithubUtils).Assembly.GetName().Name); + return client.DownloadString(url); + } + } + } + + public class GistModel + { + public string Id { get; set; } + public Dictionary files { set; get; } + + public class File + { + public double size { set; get; } + public string filename { set; get; } + public string raw_url { set; get; } + public string language { set; get; } + public string content { set; get; } + } + } +} + diff --git a/RevitAddin.CommandLoader/Services/JsonService.cs b/RevitAddin.CommandLoader/Services/JsonService.cs new file mode 100644 index 0000000..abb5b9b --- /dev/null +++ b/RevitAddin.CommandLoader/Services/JsonService.cs @@ -0,0 +1,127 @@ +using Newtonsoft.Json; + +namespace RevitAddin.CommandLoader.Services +{ + /// + /// JsonService + /// + public class JsonService : JsonService, IJsonService + { + + } + + /// + /// JsonService + /// + /// + public class JsonService : IJsonService + { + private readonly JsonSerializerSettings settings; + /// + /// JsonService + /// + public JsonService() + { + settings = new JsonSerializerSettings(); + } + + /// + /// Get JsonSerializerSettings + /// + /// + public JsonSerializerSettings GetSettings() => settings; + + /// + /// Serialize + /// + /// + /// + public string Serialize(TJson value) + { + return SerializeObject(value); + } + + /// + /// SerializeObject + /// + /// + /// + /// + public string SerializeObject(T value) + { + return JsonConvert.SerializeObject(value, settings); + } + + /// + /// Deserialize + /// + /// + /// + public TJson Deserialize(string value) + { + return DeserializeObject(value); + } + + /// + /// DeserializeObject + /// + /// + /// + /// + public T DeserializeObject(string value) + { + return JsonConvert.DeserializeObject(value, settings); + } + } + + /// + /// IJsonService + /// + public interface IJsonService : IJsonService + { + + } + + /// + /// IJsonService + /// + /// + public interface IJsonService + { + /// + /// GetSettings + /// + /// + JsonSerializerSettings GetSettings(); + + /// + /// Serialize + /// + /// + /// + string Serialize(TJson value); + + /// + /// SerializeObject + /// + /// + /// + /// + string SerializeObject(T value); + + /// + /// Deserialize + /// + /// + /// + TJson Deserialize(string value); + + /// + /// DeserializeObject + /// + /// + /// + /// + T DeserializeObject(string value); + } +} diff --git a/RevitAddin.CommandLoader/ViewModels/CompileViewModel.cs b/RevitAddin.CommandLoader/ViewModels/CompileViewModel.cs index 1c50d61..02fbbf6 100644 --- a/RevitAddin.CommandLoader/ViewModels/CompileViewModel.cs +++ b/RevitAddin.CommandLoader/ViewModels/CompileViewModel.cs @@ -1,4 +1,5 @@ -using Revit.Async; +using Newtonsoft.Json.Bson; +using Revit.Async; using RevitAddin.CommandLoader.Extensions; using RevitAddin.CommandLoader.Revit; using RevitAddin.CommandLoader.Services; @@ -18,7 +19,13 @@ public class CompileViewModel : ObservableObject #endregion #region Public Properties - public string Text { get; set; } = GetText(); + public string Text { get; set; } = +#if DEBUG + CodeSamples.CommandVersionGist; +#else + CodeSamples.Command; +#endif + public bool UseLegacyCodeDom { get; set; } = false; public bool EnableText { get; set; } = true; public IAsyncRelayCommand Command => new AsyncRelayCommand(CompileText); #endregion @@ -42,6 +49,7 @@ public void Show() Window.DataContext = this; Window.SetAutodeskOwner(); Window.Closed += (s, e) => { Window = null; }; + InitializeCompile(); } Window?.Show(); Window?.Activate(); @@ -52,13 +60,37 @@ public void Show() private async Task CompileText() { EnableText = false; + + var sources = new[] { Text }; + + if (GistGithubUtils.TryGetGistString(Text, out string gistOutput)) + { + sources = new[] { gistOutput }; + } + if (GistGithubUtils.TryGetGistFilesContent(Text, out string[] gistContents)) + { + sources = gistContents; + } + try { - await RevitTask.RunAsync(() => + await RevitTask.RunAsync((uiapp) => { + var version = uiapp.Application.VersionNumber; try { - var assembly = new CodeDomService().GenerateCode(Text); + var codeDomService = new CodeDomService() + { + UseLegacyCodeDom = UseLegacyCodeDom + }; + + var assembly = codeDomService +#if DEBUG + .SetDefines("DEBUG") +#endif + .SetDefines($"REVIT{version}", $"Revit{version}") + .GenerateCode(sources); + App.CreateCommands(assembly); } catch (System.Exception ex) @@ -73,34 +105,12 @@ await RevitTask.RunAsync(() => } } - private static string GetText() + private void InitializeCompile() { - return @"using System; -using System.ComponentModel; -using Autodesk.Revit.Attributes; -using Autodesk.Revit.DB; -using Autodesk.Revit.UI; - -namespace RevitAddin -{ - [DisplayName(""Revit\rVersion"")] - [Description(""Show a Window with the Revit VersionName."")] - [Designer(""/UIFrameworkRes;component/ribbon/images/revit.ico"")] - [Transaction(TransactionMode.Manual)] - public class Command : IExternalCommand, IExternalCommandAvailability - { - public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elementSet) - { - UIApplication uiapp = commandData.Application; - System.Windows.MessageBox.Show(uiapp.Application.VersionName); - return Result.Succeeded; - } - public bool IsCommandAvailable(UIApplication applicationData, CategorySet selectedCategories) - { - return true; - } - } -}"; + Task.Run(() => + { + new CodeDomService().GenerateCode(CodeSamples.Command); + }); } #endregion } diff --git a/RevitAddin.CommandLoader/Views/CompileView.xaml b/RevitAddin.CommandLoader/Views/CompileView.xaml index f1ec1f2..8f1dc74 100644 --- a/RevitAddin.CommandLoader/Views/CompileView.xaml +++ b/RevitAddin.CommandLoader/Views/CompileView.xaml @@ -23,6 +23,8 @@ VerticalScrollBarVisibility="Visible"> + Command="{Binding Command}" + Content="Compile Code"> +