Skip to content
Draft
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
113 commits
Select commit Hold shift + click to select a range
0ecc3de
feat: add pyRevitAssemblyBuilder project to the Loader solution
romangolev Apr 10, 2025
723821c
feat: make assembly put dlls in a correct folder, scanning all availa…
romangolev Apr 11, 2025
355f92e
feat: implement recursive UI builder
romangolev Apr 11, 2025
847c246
fix: UIManagerServite to handle stacked pulldowns correctly
romangolev Apr 14, 2025
fc104aa
feat: update build dlls
romangolev Apr 14, 2025
f659f49
feat: replace DI architecture with plain intantiating of services. re…
romangolev Apr 16, 2025
c916a4a
feat: implement pyRevitExtensionParser csproject
romangolev Apr 18, 2025
aa4fc9d
feat: update dlls
romangolev Apr 18, 2025
aea0787
feat: change unique id to mimic pythonic one, add logic to CommandTyp…
romangolev Apr 18, 2025
41a5955
feat: change assembly generation module to Roslyn
romangolev Apr 20, 2025
2fc4643
feat: mvp c# loader
romangolev Apr 21, 2025
81efe9a
fix: move enums to parser, simplify code by removing wraps
romangolev Apr 23, 2025
3886911
undate binaries
romangolev Apr 23, 2025
038fd01
Switch for .net core Desktop connector API
jmcouffin Apr 11, 2025
e93db34
fix: is_schedule
leyarx Apr 11, 2025
ae30736
Update pyrevit-hosts.json 2026.0.1
jmcouffin Apr 14, 2025
bb06cdc
Update Directory.Build.targets
jmcouffin Apr 14, 2025
987570d
upd
nodatasheet Feb 8, 2024
4ead9b0
add Associated to Others to select_family_parameters
nodatasheet Apr 12, 2025
b6dda98
cleanup
nodatasheet Apr 12, 2025
2972ffc
Update __init__.py
jmcouffin Apr 14, 2025
0ba9785
Adding exitscript option to SelectFromList from pyrevit.forms
iorhanV Apr 10, 2025
52b9424
Update __init__.py - exitscritp handeled in show method
jmcouffin Apr 14, 2025
7f5eadb
Bump golang.org/x/crypto
dependabot[bot] Apr 14, 2025
3fb7b20
fixes commit f81f483
jmcouffin Apr 16, 2025
db6510d
Update __init__.py
jmcouffin Apr 16, 2025
736cfed
Update go.mod mongodb driver
jmcouffin Apr 16, 2025
6ccc8c1
Update go.mod
jmcouffin Apr 16, 2025
8ae818e
missing comma in the docs for CommandSwitchWindow
jonatanjacobsson Apr 17, 2025
4e98317
feat: add pyRevitAssemblyBuilder project to the Loader solution
romangolev Apr 10, 2025
80f6ccf
feat: make assembly put dlls in a correct folder, scanning all availa…
romangolev Apr 11, 2025
1d6da91
feat: implement recursive UI builder
romangolev Apr 11, 2025
fa8fc2b
fix: UIManagerServite to handle stacked pulldowns correctly
romangolev Apr 14, 2025
ba7d564
feat: update build dlls
romangolev Apr 14, 2025
6964633
feat: replace DI architecture with plain intantiating of services. re…
romangolev Apr 16, 2025
46bdaa9
feat: implement pyRevitExtensionParser csproject
romangolev Apr 18, 2025
0546001
feat: update dlls
romangolev Apr 18, 2025
cffdb8a
feat: change unique id to mimic pythonic one, add logic to CommandTyp…
romangolev Apr 18, 2025
b686515
feat: change assembly generation module to Roslyn
romangolev Apr 20, 2025
33b3d75
feat: mvp c# loader
romangolev Apr 21, 2025
18ecf76
fix: move enums to parser, simplify code by removing wraps
romangolev Apr 23, 2025
e8e445a
undate binaries
romangolev Apr 23, 2025
4acf0a9
feat: add a switcher in settings to be able to toglle between python …
romangolev Apr 24, 2025
84ee64b
update dlls
romangolev Apr 24, 2025
1c90cac
merge conflict
romangolev Apr 24, 2025
1b92a55
fix: remove unused dlls
romangolev Apr 25, 2025
f408e57
feat: get back ILPack method for generating assemblies, make a switch…
romangolev Apr 25, 2025
869ed85
update dlls
romangolev Apr 25, 2025
27ca06d
feat: implement availability class generator
romangolev May 3, 2025
2f9b799
fix: improve parsing logic, move command collector to ParsedExtension…
romangolev May 3, 2025
88f0223
upd dlls
romangolev May 3, 2025
b202aa1
feat: parse bundle.yaml and reorder UI Components
romangolev May 6, 2025
525f2f6
fix: use Display name insted of truncated Name for ParsedComponents
romangolev May 7, 2025
3e8596d
feat: add testing bench for parser; add support for slideout
romangolev May 14, 2025
3ca0f22
fix: make sure UI is generated correctly and buttons are executed
romangolev May 15, 2025
faaa8e6
add 2 swichable parameters to settings
romangolev Jun 12, 2025
f785799
fix: clean-up and use config files only
romangolev Jun 16, 2025
aef99de
feat: add support for PanelButtons
romangolev Jun 24, 2025
1f65b01
update dlls
romangolev Jun 24, 2025
1a6ff56
feat: parse title and name with ExtensionParser
romangolev Jul 5, 2025
b46c55b
chore: make a parser for extensions, move config to ExtensionParser
romangolev Jul 6, 2025
b999f2f
fix: read parsed data from script.py correctly
romangolev Jul 8, 2025
ad13740
chore: support parsing for some other configs, split config in 2 files
romangolev Jul 8, 2025
185b0e2
chore: refactor ExtensionParser and implement the logic for loading c…
romangolev Jul 13, 2025
8e5e1f1
feat: improve bundle parser and make it read localized versions of to…
romangolev Sep 28, 2025
35a3633
fix: make all pushbuttons show tooltip
romangolev Sep 28, 2025
8057962
chore: add tests for pulldown component, implement fixes for tooltip …
romangolev Sep 28, 2025
d0168ce
chore: make tests work and make sure they read testing bundle
romangolev Sep 28, 2025
283b4e6
update wip dlls
romangolev Sep 28, 2025
3544d22
chore: refactor tests; tests are now using test bundle
romangolev Oct 8, 2025
917d222
fix: adapt test to check the parser
romangolev Oct 9, 2025
073ac77
feat: enrich test bundle
romangolev Oct 9, 2025
511a8f5
feat: implement icons testing and add test to check the parser
romangolev Oct 9, 2025
f00d80e
fix: make sure the yaml props override defaults from bundle correctly
romangolev Oct 10, 2025
f87944a
feat: implement support for images in UIManager
romangolev Oct 10, 2025
00a5d96
fix: sanitize name to match the command parser logic
romangolev Oct 29, 2025
317d884
feat: parse dark icons
romangolev Oct 29, 2025
8ae47e2
feat: link the image determined with the parser
romangolev Oct 29, 2025
c01af21
fix: correctly detect current Revit theme
romangolev Nov 4, 2025
a5068ae
fix: netfx silent execution bug eliminated
romangolev Nov 5, 2025
d0101c1
chore: adjust props and targets for the pipeline
romangolev Nov 5, 2025
7abde0f
fix: mind the quotes while parsing bundles
romangolev Nov 5, 2025
9968c49
fix: adjust correctly sizes for pulldown images
romangolev Nov 5, 2025
f9416e3
feat: add context feature for the button
romangolev Nov 5, 2025
30b0c75
feat: add a method that writes to the pyRevit output window
romangolev Nov 5, 2025
b071d73
refactor: restore the loading order and call new loader pythonic way
romangolev Nov 5, 2025
0559d77
chore: rebuild dlls
romangolev Nov 5, 2025
708f0a7
feat: add startup script parser
romangolev Nov 10, 2025
de410a3
fix: remedy warnings
romangolev Nov 10, 2025
87f0f48
feat: implement hashing method for dll creation
romangolev Nov 11, 2025
3668d5b
chore: add description for the section of the loading settings
romangolev Nov 13, 2025
d970046
fix: handle nullable cases for the type generator
romangolev Nov 13, 2025
0882b38
fix: add a random seed in order for c# dlls differ from python
romangolev Nov 14, 2025
10bf5cc
feat: add support for lib folders and extensions
romangolev Nov 14, 2025
fbe8a93
fix: make a new line symbol to be parsed for title
romangolev Nov 14, 2025
4c7c940
feat: add support for dividers
romangolev Nov 14, 2025
ddae5b8
feat: add support for urlbutton
romangolev Nov 14, 2025
a28928a
fix: make hashing mechanism distinguish different types of buidls
romangolev Nov 14, 2025
fa401e4
feat: add highlight option to the parser
romangolev Nov 15, 2025
d3de63d
fix: process slideouts by >>> pattern
romangolev Nov 15, 2025
9a66391
feat: implement background support
romangolev Nov 15, 2025
06aa085
feat: add support for start-up scripts
romangolev Nov 15, 2025
1713883
feat: add support for invoke buttons and parse binaries
romangolev Nov 15, 2025
79aa50c
fix: ensure that icons are propagated to child components for pulldowns
romangolev Nov 15, 2025
42c498b
feat: add support for custom overriding title from layout panel
romangolev Nov 15, 2025
a4b45c9
feat: add support for c# scripts and modules support
romangolev Nov 16, 2025
d4c0cb6
feat: add support for linkbutton
romangolev Nov 16, 2025
3708082
refactor: code optimization
romangolev Nov 16, 2025
94e97b8
refactor: improve logging
romangolev Nov 16, 2025
6e52f48
chore: upd dlls
romangolev Nov 16, 2025
e26fa8d
fix: about script name
jmcouffin Nov 17, 2025
78b2916
feat: enhance session management with build strategy support and impr…
jmcouffin Nov 17, 2025
8b5b8e6
chore: update binary files for pyRevit and related libraries
jmcouffin Nov 17, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added bin/netcore/engines/IPY342/Lokad.ILPack.dll
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file modified bin/netcore/engines/IPY342/pyRevitLoader.dll
Binary file not shown.
Binary file modified bin/netcore/engines/IPY342/pyRevitRunner.dll
Binary file not shown.
Binary file added bin/netfx/engines/IPY342/Lokad.ILPack.dll
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file added bin/netfx/engines/IPY342/System.ValueTuple.dll
Binary file not shown.
Binary file not shown.
Binary file modified bin/netfx/engines/IPY342/pyRevitLoader.dll
Binary file not shown.
Binary file modified bin/netfx/engines/IPY342/pyRevitRunner.dll
Binary file not shown.
2 changes: 1 addition & 1 deletion dev/Directory.Build.targets
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
<PyRevitExtDir>$(PyRevitRootDir)\extensions</PyRevitExtDir>

<RevitDevDir>$(PyRevitDevDir)\libs\Revit</RevitDevDir>
<IronPythonStdLibDir>$(PyRevitDevDir)\libs\IronPython\</IronPythonStdLibDir>
<IronPythonStdLibDir>$(PyRevitDevDir)\libs\IronPython</IronPythonStdLibDir>
</PropertyGroup>

<PropertyGroup Condition="$(UseDefaultBin) == 'true'">
Expand Down
3 changes: 2 additions & 1 deletion dev/pyRevitLoader/Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<PropertyGroup Condition="'$(MSBuildProjectName)' != 'pyRevitAssemblyBuilder'">
<UseRevit>true</UseRevit>
<UseWpf>true</UseWpf>
<UseWindowsForms>true</UseWindowsForms>
<UseAssemblyBuilder>true</UseAssemblyBuilder>
<TargetFrameworks>net48;net8.0-windows</TargetFrameworks>

<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
Expand Down
14 changes: 9 additions & 5 deletions dev/pyRevitLoader/Directory.Build.targets
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<None Remove="obj\**" />
</ItemGroup>

<ItemGroup Condition="$(UseRunner)=='' OR $(UseRunner)==False">
<ItemGroup Condition="$(UseLoader)==True">
<Compile Include="..\Source\PyRevitLoaderApplication.cs" Link="Source\PyRevitLoaderApplication.cs"/>
<Compile Include="..\Source\ScriptExecutor.cs" Link="Source\ScriptExecutor.cs"/>
</ItemGroup>
Expand All @@ -17,7 +17,7 @@
<Compile Include="..\Source\ScriptExecutor.cs" Link="Source\ScriptExecutor.cs"/>
</ItemGroup>

<ItemGroup Condition="$(IronPythonVersion.Contains('PR'))">
<ItemGroup Condition="'$(MSBuildProjectName)' != 'pyRevitAssemblyBuilder' AND $(IronPythonVersion.Contains('PR'))">
<Reference Include="IronPython" HintPath="$(PyRevitEnginesDir)\$(IronPythonVersion)\pyRevitLabs.IronPython.dll"/>
<Reference Include="IronPython.Modules" HintPath="$(PyRevitEnginesDir)\$(IronPythonVersion)\pyRevitLabs.IronPython.Modules.dll"/>
<Reference Include="IronPython.SQLite" HintPath="$(PyRevitEnginesDir)\$(IronPythonVersion)\pyRevitLabs.IronPython.SQLite.dll"/>
Expand All @@ -26,15 +26,19 @@
<Reference Include="Microsoft.Scripting" HintPath="$(PyRevitEnginesDir)\$(IronPythonVersion)\pyRevitLabs.Microsoft.Scripting.dll"/>
</ItemGroup>

<ItemGroup Condition="!$(IronPythonVersion.Contains('PR'))">
<ItemGroup Condition="'$(MSBuildProjectName)' != 'pyRevitAssemblyBuilder' AND !$(IronPythonVersion.Contains('PR'))">
<PackageReference Include="IronPython" Version="$(Version)"/>
</ItemGroup>

<ItemGroup>
<Reference Condition="'$(TargetFrameworkIdentifier)' == '.NETFramework'" Include="Microsoft.CSharp"/>
</ItemGroup>

<ItemGroup>

<ItemGroup Condition="'$(UseAssemblyBuilder)' == 'true'">
<ProjectReference Include="..\pyRevitAssemblyBuilder\pyRevitAssemblyBuilder.csproj" />
</ItemGroup>

<ItemGroup Condition="'$(MSBuildProjectName)' != 'pyRevitAssemblyBuilder'">
<EmbeddedResource Include="$(IronPythonStdLibDir)\$(IronPythonStdLib)"/>
</ItemGroup>

Expand Down
72 changes: 70 additions & 2 deletions dev/pyRevitLoader/Source/PyRevitLoaderApplication.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@
using System.Reflection;
using Autodesk.Revit.UI;
using Autodesk.Revit.Attributes;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using pyRevitAssemblyBuilder.AssemblyMaker;
using pyRevitAssemblyBuilder.SessionManager;
using pyRevitAssemblyBuilder.Shared;
using pyRevitAssemblyBuilder.Startup;

/* Note:
* It is necessary that this code object do not have any references to IronPython.
Expand All @@ -28,7 +34,21 @@ Result IExternalApplication.OnStartup(UIControlledApplication application)

try
{
return ExecuteStartupScript(application);
// we need a UIApplication object to assign as `__revit__` in python...
var versionNumber = application.ControlledApplication.VersionNumber;
var fieldName = int.Parse(versionNumber) >= 2017 ? "m_uiapplication" : "m_application";
var fi = application.GetType().GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Instance);

var uiApplication = (UIApplication)fi.GetValue(application);

var executor = new ScriptExecutor(uiApplication);
var result = ExecuteStartupScript(application);
if (result == Result.Failed)
{
TaskDialog.Show("Error Loading pyRevit", executor.Message);
}

return result;
}
catch (Exception ex)
{
Expand All @@ -54,6 +74,13 @@ private static void LoadAssembliesInFolder(string folder)
}

private static Result ExecuteStartupScript(UIControlledApplication uiControlledApplication)
{
//TODO: Implement a switcher here to be able to switch between Python/C# loaders
//return ExecuteStartUpPython(uiControlledApplication);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This commented code indicates a switcher to toggle between Python and C# loaders, but the implementation currently just calls the C# version. Consider implementing this switch with a configuration option so users can choose which loader to use.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think @sanzoghenzo @dosymep @dosymep, should we keep 2 loaders and some sort of a transition period while migrating? I can add a key with a true/false value to the pyRevitConfig.ini in order to switch between them.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that a feature flag is a good idea, it allows is to keep things working the old way while letting beta testers in and ironing out bugs that may (will) pop up.

return ExecuteStartUpCsharp(uiControlledApplication);
}

public static Result ExecuteStartUpPython(UIControlledApplication uiControlledApplication)
{
// we need a UIApplication object to assign as `__revit__` in python...
var versionNumber = uiControlledApplication.ControlledApplication.VersionNumber;
Expand All @@ -76,7 +103,48 @@ private static Result ExecuteStartupScript(UIControlledApplication uiControlledA

return result;
}
public static Result ExecuteStartUpCsharp(UIControlledApplication uiControlledApplication)
{
try
{
var versionNumber = uiControlledApplication.ControlledApplication.VersionNumber;
var fieldName = int.Parse(versionNumber) >= 2017 ? "m_uiapplication" : "m_application";
var fi = uiControlledApplication.GetType().GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Instance);
var uiApplication = (UIApplication)fi.GetValue(uiControlledApplication);

var services = new ServiceCollection();
services.AddLogging(cfg => cfg.AddDebug());

// Add Revit UIApplication to services
services.AddSingleton(uiApplication);

// Add known services
services.AddSingleton<ICommandTypeGenerator, DefaultCommandTypeGenerator>();
services.AddSingleton<IHookManager, DummyHookManager>();
services.AddSingleton<IUIManager, UIManagerService>();
services.AddSingleton<ISessionManager, SessionManagerService>();
services.AddSingleton<IExtensionManager, ExtensionManagerService>();

// Register AssemblyBuilderService with explicit string parameter
services.AddSingleton<AssemblyBuilderService>(sp =>
new AssemblyBuilderService(
sp.GetRequiredService<ICommandTypeGenerator>(),
versionNumber
)
);

var serviceProvider = services.BuildServiceProvider();
var sessionManager = serviceProvider.GetRequiredService<ISessionManager>();
sessionManager.LoadSessionAsync().Wait();

return Result.Succeeded;
}
catch (Exception ex)
{
TaskDialog.Show("Error Starting pyRevit Session", ex.ToString());
return Result.Failed;
}
}
private static string GetStartupScriptPath()
{
var loaderDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
Expand All @@ -90,4 +158,4 @@ Result IExternalApplication.OnShutdown(UIControlledApplication application)
return Result.Succeeded;
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
using System;
using System.IO;
using System.Reflection;
using System.Reflection.Emit;
using pyRevitAssemblyBuilder.Shared;

namespace pyRevitAssemblyBuilder.AssemblyMaker
{
public class AssemblyBuilderService
{
private readonly ICommandTypeGenerator _typeGenerator;
private readonly string _revitVersion;

public AssemblyBuilderService(ICommandTypeGenerator typeGenerator, string revitVersion)
{
_typeGenerator = typeGenerator;
_revitVersion = revitVersion ?? throw new ArgumentNullException(nameof(revitVersion));
}

public ExtensionAssemblyInfo BuildExtensionAssembly(IExtension extension)
{
string extensionHash = GetStableHash(extension.GetHash() + _revitVersion).Substring(0, 16);
string fileName = $"pyRevit_{_revitVersion}_{extensionHash}_{extension.Name}.dll";

string outputDir = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
"pyRevit",
_revitVersion
);
Directory.CreateDirectory(outputDir);

string outputPath = Path.Combine(outputDir, fileName);

var asmName = new AssemblyName(extension.Name)
{
Version = new Version(1, 0, 0, 0)
};

string fileNameWithoutExt = Path.GetFileNameWithoutExtension(outputPath);

#if NETFRAMEWORK
var domain = AppDomain.CurrentDomain;
var asmBuilder = domain.DefineDynamicAssembly(asmName, AssemblyBuilderAccess.RunAndSave, outputDir);
var moduleBuilder = asmBuilder.DefineDynamicModule(fileNameWithoutExt, fileName);
#else
var asmBuilder = AssemblyBuilder.DefineDynamicAssembly(asmName, AssemblyBuilderAccess.Run);
var moduleBuilder = asmBuilder.DefineDynamicModule(fileNameWithoutExt);
#endif

foreach (var cmd in extension.GetAllCommands())
{
_typeGenerator.DefineCommandType(extension, cmd, moduleBuilder);
}

#if NETFRAMEWORK
asmBuilder.Save(fileName);
#else
var generator = new Lokad.ILPack.AssemblyGenerator();
generator.GenerateAssembly(asmBuilder, outputPath);
#endif

return new ExtensionAssemblyInfo(
name: extension.Name,
location: outputPath,
isReloading: CheckIfExtensionAlreadyLoaded(extension.Name)
);
}

private bool CheckIfExtensionAlreadyLoaded(string extensionName)
{
foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
{
if (asm.GetName().Name == extensionName)
return true;
}
return false;
}

private static string GetStableHash(string input)
{
using (var sha1 = System.Security.Cryptography.SHA1.Create())
{
var hash = sha1.ComputeHash(System.Text.Encoding.UTF8.GetBytes(input));
return BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant();
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using System.Reflection.Emit;
using System.Reflection;
using pyRevitAssemblyBuilder.Shared;

namespace pyRevitAssemblyBuilder.AssemblyMaker
{
public class DefaultCommandTypeGenerator : ICommandTypeGenerator
{
public void DefineCommandType(IExtension extension, ICommandComponent command, ModuleBuilder moduleBuilder)
{
var typeBuilder = moduleBuilder.DefineType(
name: command.UniqueId,
attr: TypeAttributes.Public | TypeAttributes.Class
);

var attrBuilder = new CustomAttributeBuilder(
typeof(System.ComponentModel.DescriptionAttribute).GetConstructor(new[] { typeof(string) }),
new object[] { command.Tooltip }
);
typeBuilder.SetCustomAttribute(attrBuilder);

typeBuilder.CreateType();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
namespace pyRevitAssemblyBuilder.AssemblyMaker
{
public class ExtensionAssemblyInfo
{
public string Name { get; }
public string Location { get; }
public bool IsReloading { get; }

public ExtensionAssemblyInfo(string name, string location, bool isReloading)
{
Name = name;
Location = location;
IsReloading = isReloading;
}

public override string ToString()
{
return $"{Name} ({(IsReloading ? "Reloaded" : "Fresh")}) -> {Location}";
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using pyRevitAssemblyBuilder.Shared;
using System.Reflection.Emit;

namespace pyRevitAssemblyBuilder.AssemblyMaker
{
public interface ICommandTypeGenerator
{
void DefineCommandType(IExtension extension, ICommandComponent command, ModuleBuilder moduleBuilder);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using Microsoft.Extensions.DependencyInjection;
using pyRevitAssemblyBuilder.AssemblyMaker;

namespace pyRevitAssemblyBuilder.Startup
{
public static class ServiceRegistration
{
public static IServiceCollection AddAssemblyBuilder(this IServiceCollection services)
{
services.AddSingleton<ICommandTypeGenerator, DefaultCommandTypeGenerator>();
services.AddSingleton<AssemblyBuilderService>();
return services;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using System;
using System.Reflection;
using System.Reflection.Emit;
using pyRevitAssemblyBuilder.Shared;

namespace pyRevitAssemblyBuilder.AssemblyMaker
{
public class TypeMakerService : ICommandTypeGenerator
{
public void DefineCommandType(IExtension extension, ICommandComponent command, ModuleBuilder moduleBuilder)
{
var typeBuilder = moduleBuilder.DefineType(
name: command.UniqueId,
attr: TypeAttributes.Public | TypeAttributes.Class
);

if (!string.IsNullOrEmpty(command.Tooltip))
{
var attrBuilder = new CustomAttributeBuilder(
typeof(System.ComponentModel.DescriptionAttribute).GetConstructor(new[] { typeof(string) }),
new object[] { command.Tooltip }
);
typeBuilder.SetCustomAttribute(attrBuilder);
}

// Emit a default constructor
typeBuilder.DefineDefaultConstructor(MethodAttributes.Public);

// Create the type (works in .NET Standard 2.0 via CreateTypeInfo)
_ = typeBuilder.CreateTypeInfo();
}
}
}
Loading