diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
new file mode 100644
index 0000000..dd84ea7
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -0,0 +1,38 @@
+---
+name: Bug report
+about: Create a report to help us improve
+title: ''
+labels: ''
+assignees: ''
+
+---
+
+**Describe the bug**
+A clear and concise description of what the bug is.
+
+**To Reproduce**
+Steps to reproduce the behavior:
+1. Go to '...'
+2. Click on '....'
+3. Scroll down to '....'
+4. See error
+
+**Expected behavior**
+A clear and concise description of what you expected to happen.
+
+**Screenshots**
+If applicable, add screenshots to help explain your problem.
+
+**Desktop (please complete the following information):**
+ - OS: [e.g. iOS]
+ - Browser [e.g. chrome, safari]
+ - Version [e.g. 22]
+
+**Smartphone (please complete the following information):**
+ - Device: [e.g. iPhone6]
+ - OS: [e.g. iOS8.1]
+ - Browser [e.g. stock browser, safari]
+ - Version [e.g. 22]
+
+**Additional context**
+Add any other context about the problem here.
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
new file mode 100644
index 0000000..bbcbbe7
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -0,0 +1,20 @@
+---
+name: Feature request
+about: Suggest an idea for this project
+title: ''
+labels: ''
+assignees: ''
+
+---
+
+**Is your feature request related to a problem? Please describe.**
+A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
+
+**Describe the solution you'd like**
+A clear and concise description of what you want to happen.
+
+**Describe alternatives you've considered**
+A clear and concise description of any alternative solutions or features you've considered.
+
+**Additional context**
+Add any other context or screenshots about the feature request here.
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
new file mode 100644
index 0000000..820aa67
--- /dev/null
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -0,0 +1,30 @@
+### Purpose
+
+(FILL ME IN) This section describes why this PR is here. Usually it would include a reference
+to the tracking task that it is part or all of the solution for.
+
+### Description
+
+(FILL ME IN) Brief description of the fix / enhancement. **Mandatory section**
+
+### Declarations
+
+Check these if you believe they are true
+
+- [ ] This PR fix bug
+- [ ] This PR for new feature
+- [ ] The codebase is in a better state after this PR
+- [ ] The level of testing this PR includes is appropriate
+- [ ] User facing strings, if any, are extracted into `*.resx` files
+- [ ] Snapshot of UI changes, if any.
+- [ ] This PR modifies some build requirements and the readme is updated
+
+### Reviewers
+
+(FILL ME IN) Reviewer 1 (If possible, assign the Reviewer for the PR)
+
+(FILL ME IN, optional) Any additional notes to reviewers or testers.
+
+### FYIs
+
+(FILL ME IN, Optional) Names of anyone else you wish to be notified of
diff --git a/.github/workflows/Workflow.yml b/.github/workflows/Workflow.yml
new file mode 100644
index 0000000..d95c820
--- /dev/null
+++ b/.github/workflows/Workflow.yml
@@ -0,0 +1,19 @@
+name: Workflow
+
+on:
+ push:
+ branches:
+ - '**'
+ pull_request:
+ branches:
+ - '!master'
+
+jobs:
+ windows:
+ name: windows-2022
+ runs-on: windows-2022
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v1
+ - name: Run Nuke Build
+ run: ./.nuke/build.cmd --GitHubToken ${{ secrets.GITHUB_TOKEN }}
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index afef6a5..2fa0e9e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,9 +1,61 @@
+#Ignore thumbnails created by Windows
+Thumbs.db
+
+#Ignore files built by Visual Studio
+*.obj
+*.exe
+*.pdb
+*.user
+*.aps
+*.pch
+*.vspscc
+*_i.c
+*_p.c
+*.ncb
+*.suo
+*.tlb
+*.tlh
+*.bak
+*.cache
+*.ilk
+*.log
+*.iref
+*.db
+*.ide
+*.opendb
+*.lock
+*.ide-shm
+*.ide-wal
+*.dll
+*.suo
+[Bb]in
+[Dd]ebug*/
+*.lib
+*.sbr
+obj/
+[Rr]elease*/
+_ReSharper*/
+[Tt]est[Rr]esult*
+.vs/
+
+#Rider
+.idea
+
+#Installer
+output
+
+#Nuget packages folder
+packages/
+*.html
+*.htm
+
# Project specific files and folders to ignore
PythonConsoleControl/obj/
RevitPythonShell/obj/
RpsRuntime/obj/
+
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
@@ -15,7 +67,6 @@ __pycache__/
.Python
env/
bin/
-build/
develop-eggs/
dist/
eggs/
@@ -60,12 +111,5 @@ docs/_build/
*.swp
-# project specific stuff
-.DS_Store
-RevitPythonShell/Examples/Output
-RevitPythonShell/Examples/Output_HelloWorld
-*.suo
-
-
# Visual Studio 2015 cache/options directory
-.vs/
\ No newline at end of file
+.vs/
diff --git a/.idea/.idea.RevitPythonShell/.idea/.gitignore b/.idea/.idea.RevitPythonShell/.idea/.gitignore
new file mode 100644
index 0000000..1c7f2c6
--- /dev/null
+++ b/.idea/.idea.RevitPythonShell/.idea/.gitignore
@@ -0,0 +1,13 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Rider ignored files
+/modules.xml
+/.idea.RevitPythonShell.iml
+/contentModel.xml
+/projectSettingsUpdater.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/.idea/.idea.RevitPythonShell/.idea/.name b/.idea/.idea.RevitPythonShell/.idea/.name
new file mode 100644
index 0000000..8229d03
--- /dev/null
+++ b/.idea/.idea.RevitPythonShell/.idea/.name
@@ -0,0 +1 @@
+RevitPythonShell
\ No newline at end of file
diff --git a/.idea/.idea.RevitPythonShell/.idea/encodings.xml b/.idea/.idea.RevitPythonShell/.idea/encodings.xml
new file mode 100644
index 0000000..df87cf9
--- /dev/null
+++ b/.idea/.idea.RevitPythonShell/.idea/encodings.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.RevitPythonShell/.idea/indexLayout.xml b/.idea/.idea.RevitPythonShell/.idea/indexLayout.xml
new file mode 100644
index 0000000..7b08163
--- /dev/null
+++ b/.idea/.idea.RevitPythonShell/.idea/indexLayout.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.RevitPythonShell/.idea/vcs.xml b/.idea/.idea.RevitPythonShell/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/.idea.RevitPythonShell/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.nuke/build.cmd b/.nuke/build.cmd
new file mode 100644
index 0000000..0dbf838
--- /dev/null
+++ b/.nuke/build.cmd
@@ -0,0 +1 @@
+powershell -ExecutionPolicy ByPass -NoProfile -File "%~dp0Build.ps1" %*
\ No newline at end of file
diff --git a/.nuke/build.ps1 b/.nuke/build.ps1
new file mode 100644
index 0000000..927e2a3
--- /dev/null
+++ b/.nuke/build.ps1
@@ -0,0 +1,69 @@
+[CmdletBinding()]
+Param(
+ [Parameter(Position=0,Mandatory=$false,ValueFromRemainingArguments=$true)]
+ [string[]]$BuildArguments
+)
+
+Write-Output "PowerShell $($PSVersionTable.PSEdition) version $($PSVersionTable.PSVersion)"
+
+Set-StrictMode -Version 2.0; $ErrorActionPreference = "Stop"; $ConfirmPreference = "None"; trap { Write-Error $_ -ErrorAction Continue; exit 1 }
+
+###########################################################################
+# CONFIGURATION
+###########################################################################
+
+$SolutionDirectory = Split-Path $PSScriptRoot -Parent
+$BuildProjectFile = "$SolutionDirectory\Build\Build.csproj"
+$TempDirectory = "$SolutionDirectory\.nuke\temp"
+
+$DotNetGlobalFile = "$SolutionDirectory\global.json"
+$DotNetInstallUrl = "https://dot.net/v1/dotnet-install.ps1"
+$DotNetChannel = "Current"
+
+$env:DOTNET_SKIP_FIRST_TIME_EXPERIENCE = 1
+$env:DOTNET_CLI_TELEMETRY_OPTOUT = 1
+$env:DOTNET_MULTILEVEL_LOOKUP = 0
+
+###########################################################################
+# EXECUTION
+###########################################################################
+
+function ExecSafe([scriptblock] $cmd) {
+ & $cmd
+ if ($LASTEXITCODE) { exit $LASTEXITCODE }
+}
+
+# If dotnet CLI is installed globally and it matches requested version, use for execution
+if ($null -ne (Get-Command "dotnet" -ErrorAction SilentlyContinue) -and `
+ $(dotnet --version) -and $LASTEXITCODE -eq 0) {
+ $env:DOTNET_EXE = (Get-Command "dotnet").Path
+}
+else {
+ # Download install script
+ $DotNetInstallFile = "$TempDirectory\dotnet-install.ps1"
+ New-Item -ItemType Directory -Path $TempDirectory -Force | Out-Null
+ [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
+ (New-Object System.Net.WebClient).DownloadFile($DotNetInstallUrl, $DotNetInstallFile)
+
+ # If global.json exists, load expected version
+ if (Test-Path $DotNetGlobalFile) {
+ $DotNetGlobal = $(Get-Content $DotNetGlobalFile | Out-String | ConvertFrom-Json)
+ if ($DotNetGlobal.PSObject.Properties["sdk"] -and $DotNetGlobal.sdk.PSObject.Properties["version"]) {
+ $DotNetVersion = $DotNetGlobal.sdk.version
+ }
+ }
+
+ # Install by channel or version
+ $DotNetDirectory = "$TempDirectory\dotnet-win"
+ if (!(Test-Path variable:DotNetVersion)) {
+ ExecSafe { & powershell $DotNetInstallFile -InstallDir $DotNetDirectory -Channel $DotNetChannel -NoPath }
+ } else {
+ ExecSafe { & powershell $DotNetInstallFile -InstallDir $DotNetDirectory -Version $DotNetVersion -NoPath }
+ }
+ $env:DOTNET_EXE = "$DotNetDirectory\dotnet.exe"
+}
+
+Write-Output "Microsoft (R) .NET Core SDK version $(& $env:DOTNET_EXE --version)"
+
+ExecSafe { & $env:DOTNET_EXE build $BuildProjectFile /nodeReuse:false /p:UseSharedCompilation=false -nologo -clp:NoSummary --verbosity quiet }
+ExecSafe { & $env:DOTNET_EXE run --project $BuildProjectFile --no-build -- $BuildArguments }
\ No newline at end of file
diff --git a/.nuke/build.schema.json b/.nuke/build.schema.json
new file mode 100644
index 0000000..d471241
--- /dev/null
+++ b/.nuke/build.schema.json
@@ -0,0 +1,106 @@
+{
+ "$schema": "http://json-schema.org/draft-04/schema#",
+ "title": "Build Schema",
+ "$ref": "#/definitions/build",
+ "definitions": {
+ "build": {
+ "type": "object",
+ "properties": {
+ "Continue": {
+ "type": "boolean",
+ "description": "Indicates to continue a previously failed build attempt"
+ },
+ "GitHubToken": {
+ "type": "string"
+ },
+ "Help": {
+ "type": "boolean",
+ "description": "Shows the help text for this build assembly"
+ },
+ "Host": {
+ "type": "string",
+ "description": "Host for execution. Default is 'automatic'",
+ "enum": [
+ "AppVeyor",
+ "AzurePipelines",
+ "Bamboo",
+ "Bitrise",
+ "GitHubActions",
+ "GitLab",
+ "Jenkins",
+ "Rider",
+ "SpaceAutomation",
+ "TeamCity",
+ "Terminal",
+ "TravisCI",
+ "VisualStudio",
+ "VSCode"
+ ]
+ },
+ "NoLogo": {
+ "type": "boolean",
+ "description": "Disables displaying the NUKE logo"
+ },
+ "Partition": {
+ "type": "string",
+ "description": "Partition to use on CI"
+ },
+ "Plan": {
+ "type": "boolean",
+ "description": "Shows the execution plan (HTML)"
+ },
+ "Profile": {
+ "type": "array",
+ "description": "Defines the profiles to load",
+ "items": {
+ "type": "string"
+ }
+ },
+ "Root": {
+ "type": "string",
+ "description": "Root directory during build execution"
+ },
+ "Skip": {
+ "type": "array",
+ "description": "List of targets to be skipped. Empty list skips all dependencies",
+ "items": {
+ "type": "string",
+ "enum": [
+ "Cleaning",
+ "Compile",
+ "CreateInstaller",
+ "PublishGitHubRelease"
+ ]
+ }
+ },
+ "Solution": {
+ "type": "string",
+ "description": "Path to a solution file that is automatically loaded"
+ },
+ "Target": {
+ "type": "array",
+ "description": "List of targets to be invoked. Default is '{default_target}'",
+ "items": {
+ "type": "string",
+ "enum": [
+ "Cleaning",
+ "Compile",
+ "CreateInstaller",
+ "PublishGitHubRelease"
+ ]
+ }
+ },
+ "Verbosity": {
+ "type": "string",
+ "description": "Logging verbosity during build execution. Default is 'Normal'",
+ "enum": [
+ "Minimal",
+ "Normal",
+ "Quiet",
+ "Verbose"
+ ]
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/.nuke/parameters.json b/.nuke/parameters.json
new file mode 100644
index 0000000..9af8c82
--- /dev/null
+++ b/.nuke/parameters.json
@@ -0,0 +1,5 @@
+{
+ "$schema": "./build.schema.json",
+ "Solution": "RevitPythonShell.sln",
+ "Verbosity": "Normal"
+}
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..6d304ef
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,10 @@
+# Changelog
+- 2022-06-27 **1.0.1**
+ - Add Process CI/CD Automatic.
+ - Fix Problem show owner window.
+ - Upgrade process use SDK Style .NET6.
+ - Improve Codebase build button.
+ - Fix minimize form window.
+ - Support installation in one file msi from Revit 2018 to Revit 2023.
+ - Version numbers changed because we use one file msi installer for all versions.(e.g 2023.0.0 to 1.0.0)
+
diff --git a/Installer/Installer.cs b/Installer/Installer.cs
new file mode 100644
index 0000000..035a794
--- /dev/null
+++ b/Installer/Installer.cs
@@ -0,0 +1,70 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Text.RegularExpressions;
+using WixSharp;
+using WixSharp.CommonTasks;
+using WixSharp.Controls;
+
+const string installationDir = @"%AppDataFolder%\Autodesk\Revit\Addins\";
+const string projectName = "RevitPythonShell";
+const string outputName = "RevitPythonShell";
+const string outputDir = "output";
+const string version = "1.0.1";
+
+var fileName = new StringBuilder().Append(outputName).Append("-").Append(version);
+var project = new Project
+{
+ Name = projectName,
+ OutDir = outputDir,
+ Platform = Platform.x64,
+ Description = "The RevitPythonShell adds an IronPython interpreter to Autodesk Revit and Vasari.",
+ UI = WUI.WixUI_InstallDir,
+ Version = new Version(version),
+ OutFileName = fileName.ToString(),
+ InstallScope = InstallScope.perUser,
+ MajorUpgrade = MajorUpgrade.Default,
+ GUID = new Guid("8A43E94C-B89C-4135-8D7C-B8E51DCE70D5"),
+ BackgroundImage = @"Installer\Resources\Icons\BackgroundImage.png",
+ BannerImage = @"Installer\Resources\Icons\BannerImage.png",
+ ControlPanelInfo =
+ {
+ Manufacturer = "architecture-building-systems",
+ HelpLink = "https://github.com/architecture-building-systems/revitpythonshell",
+ Comments = "The RevitPythonShell adds an IronPython interpreter to Autodesk Revit and Vasari.",
+ ProductIcon = @"Installer\Resources\Icons\ShellIcon.ico",
+ },
+ Dirs = new Dir[]
+ {
+ new InstallDir(installationDir, GenerateWixEntities())
+ }
+};
+
+MajorUpgrade.Default.AllowSameVersionUpgrades = true;
+project.RemoveDialogsBetween(NativeDialogs.WelcomeDlg, NativeDialogs.InstallDirDlg);
+project.BuildMsi();
+
+WixEntity[] GenerateWixEntities()
+{
+ var versionRegex = new Regex(@"\d+");
+ var versionStorages = new Dictionary>();
+
+ foreach (var directory in args)
+ {
+ var directoryInfo = new DirectoryInfo(directory);
+ var fileVersion = versionRegex.Match(directoryInfo.Name).Value;
+ var files = new Files($@"{directory}\*.*");
+ if (versionStorages.ContainsKey(fileVersion))
+ versionStorages[fileVersion].Add(files);
+ else
+ versionStorages.Add(fileVersion, new List { files });
+
+ var assemblies = Directory.GetFiles(directory, "*", SearchOption.AllDirectories);
+ Console.WriteLine($"Added '{fileVersion}' version files: ");
+ foreach (var assembly in assemblies) Console.WriteLine($"'{assembly}'");
+ }
+
+ return versionStorages.Select(storage => new Dir(storage.Key, storage.Value.ToArray())).Cast().ToArray();
+}
\ No newline at end of file
diff --git a/Installer/Installer.csproj b/Installer/Installer.csproj
new file mode 100644
index 0000000..73fc313
--- /dev/null
+++ b/Installer/Installer.csproj
@@ -0,0 +1,21 @@
+
+
+ Exe
+ latest
+ x64
+ net48
+ false
+
+
+ true
+ none
+
+
+
+ 1.19.*
+
+
+ 3.11.*
+
+
+
diff --git a/Installer/Resources/Icons/BackgroundImage.png b/Installer/Resources/Icons/BackgroundImage.png
new file mode 100644
index 0000000..549faa1
Binary files /dev/null and b/Installer/Resources/Icons/BackgroundImage.png differ
diff --git a/Installer/Resources/Icons/BannerImage.png b/Installer/Resources/Icons/BannerImage.png
new file mode 100644
index 0000000..366db7c
Binary files /dev/null and b/Installer/Resources/Icons/BannerImage.png differ
diff --git a/Installer/Resources/Icons/ShellIcon.ico b/Installer/Resources/Icons/ShellIcon.ico
new file mode 100644
index 0000000..940e075
Binary files /dev/null and b/Installer/Resources/Icons/ShellIcon.ico differ
diff --git a/Output/2015.03.20_Setup_RevitPythonShell_2014.exe b/Output/2015.03.20_Setup_RevitPythonShell_2014.exe
deleted file mode 100644
index cea3203..0000000
Binary files a/Output/2015.03.20_Setup_RevitPythonShell_2014.exe and /dev/null differ
diff --git a/Output/2015.03.20_Setup_RevitPythonShell_2015.exe b/Output/2015.03.20_Setup_RevitPythonShell_2015.exe
deleted file mode 100644
index b0014c3..0000000
Binary files a/Output/2015.03.20_Setup_RevitPythonShell_2015.exe and /dev/null differ
diff --git a/Output/2015.03.20_Setup_RevitPythonShell_Vasari_Beta3.exe b/Output/2015.03.20_Setup_RevitPythonShell_Vasari_Beta3.exe
deleted file mode 100644
index 051b299..0000000
Binary files a/Output/2015.03.20_Setup_RevitPythonShell_Vasari_Beta3.exe and /dev/null differ
diff --git a/Output/2015.04.18_Setup_RevitPythonShell_2014.exe b/Output/2015.04.18_Setup_RevitPythonShell_2014.exe
deleted file mode 100644
index 305087a..0000000
Binary files a/Output/2015.04.18_Setup_RevitPythonShell_2014.exe and /dev/null differ
diff --git a/Output/2015.04.29_Setup_RevitPythonShell_2015.exe b/Output/2015.04.29_Setup_RevitPythonShell_2015.exe
deleted file mode 100644
index c121e33..0000000
Binary files a/Output/2015.04.29_Setup_RevitPythonShell_2015.exe and /dev/null differ
diff --git a/Output/2015.04.29_Setup_RevitPythonShell_2016.exe b/Output/2015.04.29_Setup_RevitPythonShell_2016.exe
deleted file mode 100644
index 156ae83..0000000
Binary files a/Output/2015.04.29_Setup_RevitPythonShell_2016.exe and /dev/null differ
diff --git a/Output/2015.05.18_Setup_RevitPythonShell_2015.exe b/Output/2015.05.18_Setup_RevitPythonShell_2015.exe
deleted file mode 100644
index ee3dae8..0000000
Binary files a/Output/2015.05.18_Setup_RevitPythonShell_2015.exe and /dev/null differ
diff --git a/Output/2015.05.18_Setup_RevitPythonShell_2016.exe b/Output/2015.05.18_Setup_RevitPythonShell_2016.exe
deleted file mode 100644
index 8e5745f..0000000
Binary files a/Output/2015.05.18_Setup_RevitPythonShell_2016.exe and /dev/null differ
diff --git a/Output/2015.05.21_Setup_RevitPythonShell_2014.exe b/Output/2015.05.21_Setup_RevitPythonShell_2014.exe
deleted file mode 100644
index 1c15fbd..0000000
Binary files a/Output/2015.05.21_Setup_RevitPythonShell_2014.exe and /dev/null differ
diff --git a/Output/2015.05.21_Setup_RevitPythonShell_2015.exe b/Output/2015.05.21_Setup_RevitPythonShell_2015.exe
deleted file mode 100644
index 439a1a8..0000000
Binary files a/Output/2015.05.21_Setup_RevitPythonShell_2015.exe and /dev/null differ
diff --git a/Output/2015.05.21_Setup_RevitPythonShell_2016.exe b/Output/2015.05.21_Setup_RevitPythonShell_2016.exe
deleted file mode 100644
index eced67d..0000000
Binary files a/Output/2015.05.21_Setup_RevitPythonShell_2016.exe and /dev/null differ
diff --git a/Output/2015.06.17_Setup_RevitPythonShell_2014.exe b/Output/2015.06.17_Setup_RevitPythonShell_2014.exe
deleted file mode 100644
index 1c15fbd..0000000
Binary files a/Output/2015.06.17_Setup_RevitPythonShell_2014.exe and /dev/null differ
diff --git a/Output/2016.06.22_Setup_RevitPythonShell_2017.exe b/Output/2016.06.22_Setup_RevitPythonShell_2017.exe
deleted file mode 100644
index 2eaad9e..0000000
Binary files a/Output/2016.06.22_Setup_RevitPythonShell_2017.exe and /dev/null differ
diff --git a/Output/2016.06.23_Setup_RevitPythonShell_2017.exe b/Output/2016.06.23_Setup_RevitPythonShell_2017.exe
deleted file mode 100644
index 1d4b9c4..0000000
Binary files a/Output/2016.06.23_Setup_RevitPythonShell_2017.exe and /dev/null differ
diff --git a/Output/2016.06.29_Setup_RevitPythonShell_2017.exe b/Output/2016.06.29_Setup_RevitPythonShell_2017.exe
deleted file mode 100644
index 64d3ddc..0000000
Binary files a/Output/2016.06.29_Setup_RevitPythonShell_2017.exe and /dev/null differ
diff --git a/Output/2016.10.24_Setup_RevitPythonShell_2017.exe b/Output/2016.10.24_Setup_RevitPythonShell_2017.exe
deleted file mode 100644
index da0345e..0000000
Binary files a/Output/2016.10.24_Setup_RevitPythonShell_2017.exe and /dev/null differ
diff --git a/Output/2017.03.07_Setup_RevitPythonShell_2015.exe b/Output/2017.03.07_Setup_RevitPythonShell_2015.exe
deleted file mode 100644
index 0ac985f..0000000
Binary files a/Output/2017.03.07_Setup_RevitPythonShell_2015.exe and /dev/null differ
diff --git a/Output/2017.03.07_Setup_RevitPythonShell_2016.exe b/Output/2017.03.07_Setup_RevitPythonShell_2016.exe
deleted file mode 100644
index c1d93b2..0000000
Binary files a/Output/2017.03.07_Setup_RevitPythonShell_2016.exe and /dev/null differ
diff --git a/Output/2017.03.07_Setup_RevitPythonShell_2017.exe b/Output/2017.03.07_Setup_RevitPythonShell_2017.exe
deleted file mode 100644
index a732ecb..0000000
Binary files a/Output/2017.03.07_Setup_RevitPythonShell_2017.exe and /dev/null differ
diff --git a/Output/2017.04.05_Setup_RevitPythonShell_2017.exe b/Output/2017.04.05_Setup_RevitPythonShell_2017.exe
deleted file mode 100644
index 5a367e7..0000000
Binary files a/Output/2017.04.05_Setup_RevitPythonShell_2017.exe and /dev/null differ
diff --git a/Output/2017.04.06_Setup_RevitPythonShell_2017.exe b/Output/2017.04.06_Setup_RevitPythonShell_2017.exe
deleted file mode 100644
index b8029ba..0000000
Binary files a/Output/2017.04.06_Setup_RevitPythonShell_2017.exe and /dev/null differ
diff --git a/Output/2017.07.24_Setup_RevitPythonShell_2018.exe b/Output/2017.07.24_Setup_RevitPythonShell_2018.exe
deleted file mode 100644
index e6573cb..0000000
Binary files a/Output/2017.07.24_Setup_RevitPythonShell_2018.exe and /dev/null differ
diff --git a/Output/2017.09.12_Setup_RevitPythonShell_2018.exe b/Output/2017.09.12_Setup_RevitPythonShell_2018.exe
deleted file mode 100644
index 3af970e..0000000
Binary files a/Output/2017.09.12_Setup_RevitPythonShell_2018.exe and /dev/null differ
diff --git a/Output/2018.01.04_Setup_RevitPythonShell_2018.exe b/Output/2018.01.04_Setup_RevitPythonShell_2018.exe
deleted file mode 100644
index a5f41f3..0000000
Binary files a/Output/2018.01.04_Setup_RevitPythonShell_2018.exe and /dev/null differ
diff --git a/Output/2018.03.19_Setup_RevitPythonShell_2018.exe b/Output/2018.03.19_Setup_RevitPythonShell_2018.exe
deleted file mode 100644
index 636b6c4..0000000
Binary files a/Output/2018.03.19_Setup_RevitPythonShell_2018.exe and /dev/null differ
diff --git a/Output/2018.09.19_Setup_RevitPythonShell_2019.exe b/Output/2018.09.19_Setup_RevitPythonShell_2019.exe
deleted file mode 100644
index 8ff2243..0000000
Binary files a/Output/2018.09.19_Setup_RevitPythonShell_2019.exe and /dev/null differ
diff --git a/Output/2020.01.19_Setup_RevitPythonShell_2020.exe b/Output/2020.01.19_Setup_RevitPythonShell_2020.exe
deleted file mode 100644
index 7de2384..0000000
Binary files a/Output/2020.01.19_Setup_RevitPythonShell_2020.exe and /dev/null differ
diff --git a/Output/2021.03.22_Setup_RevitPythonShell_2021.exe b/Output/2021.03.22_Setup_RevitPythonShell_2021.exe
deleted file mode 100755
index 58020e1..0000000
Binary files a/Output/2021.03.22_Setup_RevitPythonShell_2021.exe and /dev/null differ
diff --git a/Output/2021.06.20_Setup_RevitPythonShell_2022.exe b/Output/2021.06.20_Setup_RevitPythonShell_2022.exe
deleted file mode 100755
index 016db18..0000000
Binary files a/Output/2021.06.20_Setup_RevitPythonShell_2022.exe and /dev/null differ
diff --git a/PythonConsoleControl/CommandLineHistory.cs b/PythonConsoleControl/CommandLineHistory.cs
index d2d0f93..5c689dd 100644
--- a/PythonConsoleControl/CommandLineHistory.cs
+++ b/PythonConsoleControl/CommandLineHistory.cs
@@ -2,8 +2,6 @@
using System;
using System.Collections.Generic;
-using System.Linq;
-using System.Text;
namespace PythonConsoleControl
{
diff --git a/PythonConsoleControl/PythonConsole.cs b/PythonConsoleControl/PythonConsole.cs
index 8028850..339ca70 100644
--- a/PythonConsoleControl/PythonConsole.cs
+++ b/PythonConsoleControl/PythonConsole.cs
@@ -2,27 +2,17 @@
using System;
using System.Collections.Generic;
-using System.Linq;
-using System.Text;
using System.IO;
using System.Threading;
using Microsoft.Scripting.Hosting.Shell;
using System.Windows.Input;
using Microsoft.Scripting;
-using IronPython.Hosting;
-using IronPython.Runtime;
using Microsoft.Scripting.Hosting;
-using Microsoft.Scripting.Hosting.Providers;
using System.Diagnostics;
-using System.Globalization;
-using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Threading;
-using System.Windows.Documents;
using ICSharpCode.AvalonEdit.Editing;
using ICSharpCode.AvalonEdit.Document;
-using ICSharpCode.AvalonEdit.Highlighting;
-using ICSharpCode.AvalonEdit.Utils;
using Style = Microsoft.Scripting.Hosting.Shell.Style;
using System.Runtime.Remoting;
diff --git a/PythonConsoleControl/PythonConsoleCompletionDataProvider.cs b/PythonConsoleControl/PythonConsoleCompletionDataProvider.cs
index 5ab1553..e6c6262 100644
--- a/PythonConsoleControl/PythonConsoleCompletionDataProvider.cs
+++ b/PythonConsoleControl/PythonConsoleCompletionDataProvider.cs
@@ -5,11 +5,7 @@
using System.Linq;
using System.Text;
using ICSharpCode.AvalonEdit.CodeCompletion;
-using ICSharpCode.AvalonEdit;
-using ICSharpCode.AvalonEdit.Editing;
-using ICSharpCode.AvalonEdit.Document;
using Microsoft.Scripting.Hosting.Shell;
-using Microsoft.Scripting.Hosting;
using Microsoft.Scripting;
using System.Threading;
using System.Reflection;
diff --git a/PythonConsoleControl/PythonConsoleCompletionWindow.cs b/PythonConsoleControl/PythonConsoleCompletionWindow.cs
index 596f3fb..523f385 100644
--- a/PythonConsoleControl/PythonConsoleCompletionWindow.cs
+++ b/PythonConsoleControl/PythonConsoleCompletionWindow.cs
@@ -1,14 +1,9 @@
// Copyright (c) 2010 Joe Moorhouse
using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
-using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Threading;
using ICSharpCode.AvalonEdit.Document;
@@ -16,7 +11,6 @@
using ICSharpCode.AvalonEdit.Rendering;
using ICSharpCode.AvalonEdit.CodeCompletion;
using System.Reflection;
-using System.ComponentModel;
namespace PythonConsoleControl
{
diff --git a/PythonConsoleControl/PythonConsoleControl.csproj b/PythonConsoleControl/PythonConsoleControl.csproj
index 1dd65a3..6fefb45 100644
--- a/PythonConsoleControl/PythonConsoleControl.csproj
+++ b/PythonConsoleControl/PythonConsoleControl.csproj
@@ -1,125 +1,20 @@
-
- Debug;Debug One;Release
-
-
-
-
- net40;net45;net451;net452;net46;net47;net471;net48
- win
+ Debug;Release
true
-
-
-
-
- net48
-
-
-
- 2014
-
-
- 2015
-
-
- 2016
-
-
- 2017
-
-
- 2018
-
-
- 2019
-
-
- 2020
-
-
- 2021
-
-
- 2022
-
-
-
-
+ net48
x64
- x64
- None
-
-
- {351668CC-8477-4fbf-BFE3-5F1006E4DB1F}
-
-
- false
- false
-
-
- REVIT$(RevitVersion);WINFORMS
- $(DefineConstants)
-
-
- false
-
-
+ latest
false
- ..\bin\$(Configuration)\$(RevitVersion)
+ false
-
$(DefineConstants);DEBUG
full
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
..\RequiredLibraries\IronPython.dll
@@ -137,8 +32,6 @@
..\RequiredLibraries\Microsoft.Scripting.Metadata.dll
-
-
@@ -179,18 +72,4 @@
-
-
-
\ No newline at end of file
diff --git a/PythonConsoleControl/PythonConsoleControl.xaml.cs b/PythonConsoleControl/PythonConsoleControl.xaml.cs
index 6e3453e..6615483 100644
--- a/PythonConsoleControl/PythonConsoleControl.xaml.cs
+++ b/PythonConsoleControl/PythonConsoleControl.xaml.cs
@@ -1,24 +1,10 @@
using System;
using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Windows;
using System.Windows.Controls;
-using System.Windows.Data;
-using System.Windows.Documents;
-using System.Windows.Input;
-using System.Windows.Media;
-using System.Windows.Media.Imaging;
-using System.Windows.Navigation;
-using System.Windows.Shapes;
using System.IO;
-using System.Windows.Threading;
using System.Xml;
-using ICSharpCode.AvalonEdit.CodeCompletion;
-using ICSharpCode.AvalonEdit.Folding;
using ICSharpCode.AvalonEdit.Highlighting;
using ICSharpCode.AvalonEdit.Rendering;
-using Microsoft.Win32;
namespace PythonConsoleControl
diff --git a/PythonConsoleControl/PythonConsoleHighlightingColorizer.cs b/PythonConsoleControl/PythonConsoleHighlightingColorizer.cs
index b4ef7c5..576979a 100644
--- a/PythonConsoleControl/PythonConsoleHighlightingColorizer.cs
+++ b/PythonConsoleControl/PythonConsoleHighlightingColorizer.cs
@@ -1,17 +1,7 @@
// Copyright (c) 2010 Joe Moorhouse
using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Diagnostics;
-using System.Windows;
-using System.Windows.Media;
-using System.Windows.Threading;
-
-using ICSharpCode.AvalonEdit;
using ICSharpCode.AvalonEdit.Document;
-using ICSharpCode.AvalonEdit.Rendering;
using ICSharpCode.AvalonEdit.Highlighting;
namespace PythonConsoleControl
diff --git a/PythonConsoleControl/PythonConsoleHost.cs b/PythonConsoleControl/PythonConsoleHost.cs
index 49ba31c..a0eba92 100644
--- a/PythonConsoleControl/PythonConsoleHost.cs
+++ b/PythonConsoleControl/PythonConsoleHost.cs
@@ -1,10 +1,7 @@
// Copyright (c) 2010 Joe Moorhouse
using System;
-using System.Collections.Generic;
-using System.Linq;
using System.Text;
-using System.Windows;
using System.Threading;
using IronPython.Hosting;
using IronPython.Runtime;
diff --git a/PythonConsoleControl/PythonConsolePad.cs b/PythonConsoleControl/PythonConsolePad.cs
index 16f51a3..d0e2ace 100644
--- a/PythonConsoleControl/PythonConsolePad.cs
+++ b/PythonConsoleControl/PythonConsolePad.cs
@@ -1,9 +1,5 @@
// Copyright (c) 2010 Joe Moorhouse
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
using ICSharpCode.AvalonEdit;
using System.Windows.Media;
diff --git a/PythonConsoleControl/PythonEditingCommandHandler.cs b/PythonConsoleControl/PythonEditingCommandHandler.cs
index 2f425b9..b68d67f 100644
--- a/PythonConsoleControl/PythonEditingCommandHandler.cs
+++ b/PythonConsoleControl/PythonEditingCommandHandler.cs
@@ -1,22 +1,15 @@
// Copyright (c) 2010 Joe Moorhouse
using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Diagnostics;
-using System.Globalization;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows;
-using System.Windows.Documents;
using System.Windows.Input;
using System.Reflection;
using ICSharpCode.AvalonEdit;
using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.AvalonEdit.Highlighting;
-using ICSharpCode.AvalonEdit.Utils;
using ICSharpCode.AvalonEdit.Editing;
namespace PythonConsoleControl
diff --git a/PythonConsoleControl/PythonOutputStream.cs b/PythonConsoleControl/PythonOutputStream.cs
index dba34f3..62bf20c 100644
--- a/PythonConsoleControl/PythonOutputStream.cs
+++ b/PythonConsoleControl/PythonOutputStream.cs
@@ -1,6 +1,5 @@
// Copyright (c) 2010 Joe Moorhouse
-using System;
using System.IO;
using System.Text;
diff --git a/PythonConsoleControl/PythonTextEditor.cs b/PythonConsoleControl/PythonTextEditor.cs
index a405e6a..4f5e95e 100644
--- a/PythonConsoleControl/PythonTextEditor.cs
+++ b/PythonConsoleControl/PythonTextEditor.cs
@@ -2,14 +2,12 @@
using System;
using System.Collections.Generic;
-using System.Linq;
using System.Text;
using ICSharpCode.AvalonEdit;
using ICSharpCode.AvalonEdit.Editing;
using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.AvalonEdit.CodeCompletion;
using System.Windows;
-using System.Windows.Media;
using System.Windows.Threading;
using System.Windows.Input;
using System.Threading;
diff --git a/README.md b/README.md
index 83e8381..d2c1c53 100644
--- a/README.md
+++ b/README.md
@@ -1,35 +1,47 @@
# RevitPythonShell
+  [](https://opensource.org/licenses/MIT)
-The RevitPythonShell adds an IronPython interpreter to Autodesk Revit and Vasari.
+   
-The RevitPythonShell (RPS) lets you to write plugins for Revit in Python, my favourite scripting language! But even better, it provides you with an
-interactive shell that lets you see the results of your code *as you type it*. This is great for exploring the Revit API while
-writing your Revit Addins - use this in combination with the [RevitLookup](https://github.com/jeremytammik/RevitLookup) database exploration tool to become a Revit API Ninja :)
+[](../../actions)
+[]()
+[](http://hits.dwyl.com/architecture-building-systems/revitpythonshell)
+
+The RevitPythonShell adds an IronPython interpreter to Autodesk Revit and Vasari.
+
+The RevitPythonShell (RPS) lets you to write plugins for Revit in Python, my favourite scripting language! But even
+better, it provides you with an
+interactive shell that lets you see the results of your code *as you type it*. This is great for exploring the Revit API
+while
+writing your Revit Addins - use this in combination with the [RevitLookup](https://github.com/jeremytammik/RevitLookup)
+database exploration tool to become a Revit API Ninja :)
## Features
- interactive IronPython interpreter for exploring the API
- - with syntax highlighting
- - autocompletion (press CTRL+SPACE after a period)
- - based on the [IronLab](http://code.google.com/p/ironlab/) project
+ - with syntax highlighting
+ - autocompletion (press CTRL+SPACE after a period)
+ - based on the [IronLab](http://code.google.com/p/ironlab/) project
- batteries included! (Python standard library is bundled as a resource in the `RpsRuntime.dll`)
- full access to the .NET framework and the Revit API
- configurable "environment" variables that can be used in your scripts
- save "external scripts" for reuse and start collecting your awesome hacks!
- run scripts at Revit startup
- deploy scripts as standalone Revit Addins
-- `lookup()` function for snooping `Element`, `ElementSet` and `ElementId` objects in [RevitLookup](https://github.com/jeremytammik/RevitLookup)
+- `lookup()` function for snooping `Element`, `ElementSet` and `ElementId` objects
+ in [RevitLookup](https://github.com/jeremytammik/RevitLookup)
## Installation
+
+Please follow last release at section [Release](https://github.com/architecture-building-systems/revitpythonshell/releases/latest) support version Support From Revit 2018-2023.
+
+Older versions:
- [Installer for Autodesk Revit 2022](https://github.com/architecture-building-systems/revitpythonshell/releases/download/2021.06.20/2021.06.20_Setup_RevitPythonShell_2022.exe)
- [Installer for Autodesk Revit 2021](https://github.com/architecture-building-systems/revitpythonshell/releases/download/2021.03.22/2021.03.22_Setup_RevitPythonShell_2021.exe)
- [Installer for Autodesk Revit 2020](https://github.com/architecture-building-systems/revitpythonshell/releases/download/2019.01.27/2020.01.19_Setup_RevitPythonShell_2020.exe)
- [Installer for Autodesk Revit 2019](https://github.com/architecture-building-systems/revitpythonshell/releases/download/2018.09.19/2018.09.19_Setup_RevitPythonShell_2019.exe)
- [Installer for Autodesk Revit 2018 (and 2018.1)](https://github.com/architecture-building-systems/revitpythonshell/releases/download/2017.07.24/2017.07.24_Setup_RevitPythonShell_2018.exe)
- [Installer for Autodesk Revit 2017](https://github.com/architecture-building-systems/revitpythonshell/releases/download/2017.04.06/2017.04.06_Setup_RevitPythonShell_2017.exe)
-
-
-Older versions:
- [Installer for Autodesk Revit 2016](https://github.com/architecture-building-systems/revitpythonshell/releases/download/2017.03.07/2017.03.07_Setup_RevitPythonShell_2016.exe)
- [Installer for Autodesk Revit 2015](https://github.com/architecture-building-systems/revitpythonshell/releases/download/2017.03.07/2017.03.07_Setup_RevitPythonShell_2015.exe)
- [Installer for Autodesk Revit 2015](http://sustain.arch.ethz.ch/DPV/Setup_RevitPythonShell_2015.exe)
@@ -52,28 +64,30 @@ Older versions:
Learn some python:
- * [The Python Tutorial](https://docs.python.org/2/tutorial/)
- * [Dive Into Python](http://www.diveintopython.net/)
+* [The Python Tutorial](https://docs.python.org/2/tutorial/)
+* [Dive Into Python](http://www.diveintopython.net/)
Learn about the Revit API:
- * [Autodesk Developer Network](T)
- * [Jeremy Tammiks blog "The Building Coder"](http://thebuildingcoder.typepad.com/)
-
+* [Autodesk Developer Network](T)
+* [Jeremy Tammiks blog "The Building Coder"](http://thebuildingcoder.typepad.com/)
+
Tutorials recommended by the community:
- * [Mono IronPython Winforms Tutorial](http://zetcode.com/tutorials/ironpythontutorial/) - recommended by Callum
+* [Mono IronPython Winforms Tutorial](http://zetcode.com/tutorials/ironpythontutorial/) - recommended by Callum
You can find sample scripts here:
- * [Sample RPS Scripts on GitHub](https://github.com/daren-thomas/rps-sample-scripts)
+* [Sample RPS Scripts on GitHub](https://github.com/daren-thomas/rps-sample-scripts)
* feel free to send me your own scripts for inclusion!
- * [Nathan's Revit API Notebook using the RevitPythonShell](http://wiki.theprovingground.org/revit-api)
- * Nathan Miller even has a [Mobius Surface for Vasari](http://wiki.theprovingground.org/revit-api-py-parametric) sample
- * [dp stuff (Python Scripts Archives)](http://dp-stuff.org/category/python-scripts)
+* [Nathan's Revit API Notebook using the RevitPythonShell](http://wiki.theprovingground.org/revit-api)
+ * Nathan Miller even has a [Mobius Surface for Vasari](http://wiki.theprovingground.org/revit-api-py-parametric)
+ sample
+* [dp stuff (Python Scripts Archives)](http://dp-stuff.org/category/python-scripts)
* lots of scripts
- * [my own blog](http://darenatwork.blogspot.com/) contains the odd sample script
- * [Check out pyRevit](http://eirannejad.github.io/pyRevit/whatspyrevit/) by Ehsan Iran-Nejad - it includes a library of interesting scripts and some additions to make writing your own easier!
+* [my own blog](http://darenatwork.blogspot.com/) contains the odd sample script
+* [Check out pyRevit](http://eirannejad.github.io/pyRevit/whatspyrevit/) by Ehsan Iran-Nejad - it includes a library of
+ interesting scripts and some additions to make writing your own easier!
## License
@@ -81,17 +95,22 @@ This project is licensed under the terms of the [MIT License](http://opensource.
## Credits
- * Daren Thomas (original version, maintainer)
- * Zachary Kron (original port to Vasari)
- * Akimitsu Hogge (original port to Vasari)
- * Joe Moorhouse (interactive shell was taken from his project [IronLab](http://ironlab.net/))
- * Jason Schaeffer (port to Revit 2011)
- * [Ehsan Iran-Nejad (@eirannejad)](https://github.com/eirannejad) countless improvements, the awesome [pyRevit](https://github.com/eirannejad/pyRevit) tool and a special thanks for helping maintain RPS!
- * [@DanRumery](https://github.com/danrumery) improved autocompletion with PR #59
- * [Petr Mitev (@mitevpi)](https://github.com/mitevpi) ported to Revit 2019 with RP #86
- * [Alvaro Ortega Pickmans (@alvpickmans)](https://github.com/alvpickmans) refactor to sdk csproject and release for Revit 2020 PR #101
- * [@hdm-dt-fb](https://github.com/hdm-dt-fb) added `set_font_sizes` function for presenting RPS ([PR #77](https://github.com/architecture-building-systems/revitpythonshell/pull/77))
- * many, many users with questions, bug reports etc!
+* Daren Thomas (original version, maintainer)
+* Zachary Kron (original port to Vasari)
+* Akimitsu Hogge (original port to Vasari)
+* Joe Moorhouse (interactive shell was taken from his project [IronLab](http://ironlab.net/))
+* Jason Schaeffer (port to Revit 2011)
+* [Ehsan Iran-Nejad (@eirannejad)](https://github.com/eirannejad) countless improvements, the
+ awesome [pyRevit](https://github.com/eirannejad/pyRevit) tool and a special thanks for helping maintain RPS!
+* [@DanRumery](https://github.com/danrumery) improved autocompletion with PR #59
+* [Petr Mitev (@mitevpi)](https://github.com/mitevpi) ported to Revit 2019 with RP #86
+* [Alvaro Ortega Pickmans (@alvpickmans)](https://github.com/alvpickmans) refactor to sdk csproject and release for
+ Revit 2020 PR #101
+* [@hdm-dt-fb](https://github.com/hdm-dt-fb) added `set_font_sizes` function for presenting
+ RPS ([PR #77](https://github.com/architecture-building-systems/revitpythonshell/pull/77))
+* [Nice3Point](https://github.com/Nice3point) for process CI/CD
+* [Chuong Mep](https://github.com/chuongmep/) a people like maintain for project open source.
+* many, many users with questions, bug reports etc!
Also, many thanks to the
[Chair for Architecture & Building Systems](http://systems.arch.ethz.ch) for making this project possible.
diff --git a/RevitPythonShell.sln b/RevitPythonShell.sln
index 7335ffe..c6f2876 100644
--- a/RevitPythonShell.sln
+++ b/RevitPythonShell.sln
@@ -13,52 +13,113 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PythonConsoleControl", "Pyt
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RpsRuntime", "RpsRuntime\RpsRuntime.csproj", "{C8446636-C663-409F-82D0-72C0D55BBA1C}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Installer", "Installer\Installer.csproj", "{B0FECFED-4451-4C7D-ACB7-59CC6F12FBAF}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Build", "build\Build.csproj", "{0DF5F952-C36B-4C97-B0CD-678C61093311}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionItems", "SolutionItems", "{7D7FB600-5CB5-46B8-9CBB-2F42E3EF19EF}"
+ ProjectSection(SolutionItems) = preProject
+ .gitignore = .gitignore
+ CHANGELOG.md = CHANGELOG.md
+ README.md = README.md
+ EndProjectSection
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug One|Any CPU = Debug One|Any CPU
- Debug One|x64 = Debug One|x64
Debug|Any CPU = Debug|Any CPU
- Debug|x64 = Debug|x64
- Release|Any CPU = Release|Any CPU
- Release|x64 = Release|x64
+ Installer|Any CPU = Installer|Any CPU
+ Debug R22|Any CPU = Debug R22|Any CPU
+ Debug R23|Any CPU = Debug R23|Any CPU
+ Release R18|Any CPU = Release R18|Any CPU
+ Release R19|Any CPU = Release R19|Any CPU
+ Release R20|Any CPU = Release R20|Any CPU
+ Release R21|Any CPU = Release R21|Any CPU
+ Release R22|Any CPU = Release R22|Any CPU
+ Release R23|Any CPU = Release R23|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {7E37F14E-D840-42F8-8CA6-90FFC5497972}.Debug One|Any CPU.ActiveCfg = Debug One|x64
- {7E37F14E-D840-42F8-8CA6-90FFC5497972}.Debug One|Any CPU.Build.0 = Debug One|x64
- {7E37F14E-D840-42F8-8CA6-90FFC5497972}.Debug One|x64.ActiveCfg = Debug One|x64
- {7E37F14E-D840-42F8-8CA6-90FFC5497972}.Debug One|x64.Build.0 = Debug One|x64
- {7E37F14E-D840-42F8-8CA6-90FFC5497972}.Debug|Any CPU.ActiveCfg = Debug|x64
- {7E37F14E-D840-42F8-8CA6-90FFC5497972}.Debug|Any CPU.Build.0 = Debug|x64
- {7E37F14E-D840-42F8-8CA6-90FFC5497972}.Debug|x64.ActiveCfg = Debug|x64
- {7E37F14E-D840-42F8-8CA6-90FFC5497972}.Debug|x64.Build.0 = Debug|x64
- {7E37F14E-D840-42F8-8CA6-90FFC5497972}.Release|Any CPU.ActiveCfg = Release|x64
- {7E37F14E-D840-42F8-8CA6-90FFC5497972}.Release|Any CPU.Build.0 = Release|x64
- {7E37F14E-D840-42F8-8CA6-90FFC5497972}.Release|x64.ActiveCfg = Release|x64
- {7E37F14E-D840-42F8-8CA6-90FFC5497972}.Release|x64.Build.0 = Release|x64
- {F1152D68-346B-4F48-8DB7-BE67B5CB1F49}.Debug One|Any CPU.ActiveCfg = Debug One|x64
- {F1152D68-346B-4F48-8DB7-BE67B5CB1F49}.Debug One|Any CPU.Build.0 = Debug One|x64
- {F1152D68-346B-4F48-8DB7-BE67B5CB1F49}.Debug One|x64.ActiveCfg = Debug One|x64
- {F1152D68-346B-4F48-8DB7-BE67B5CB1F49}.Debug One|x64.Build.0 = Debug One|x64
- {F1152D68-346B-4F48-8DB7-BE67B5CB1F49}.Debug|Any CPU.ActiveCfg = Debug|x64
- {F1152D68-346B-4F48-8DB7-BE67B5CB1F49}.Debug|Any CPU.Build.0 = Debug|x64
- {F1152D68-346B-4F48-8DB7-BE67B5CB1F49}.Debug|x64.ActiveCfg = Debug|x64
- {F1152D68-346B-4F48-8DB7-BE67B5CB1F49}.Debug|x64.Build.0 = Debug|x64
- {F1152D68-346B-4F48-8DB7-BE67B5CB1F49}.Release|Any CPU.ActiveCfg = Release|x64
- {F1152D68-346B-4F48-8DB7-BE67B5CB1F49}.Release|Any CPU.Build.0 = Release|x64
- {F1152D68-346B-4F48-8DB7-BE67B5CB1F49}.Release|x64.ActiveCfg = Release|x64
- {F1152D68-346B-4F48-8DB7-BE67B5CB1F49}.Release|x64.Build.0 = Release|x64
- {C8446636-C663-409F-82D0-72C0D55BBA1C}.Debug One|Any CPU.ActiveCfg = Debug One|x64
- {C8446636-C663-409F-82D0-72C0D55BBA1C}.Debug One|Any CPU.Build.0 = Debug One|x64
- {C8446636-C663-409F-82D0-72C0D55BBA1C}.Debug One|x64.ActiveCfg = Debug One|x64
- {C8446636-C663-409F-82D0-72C0D55BBA1C}.Debug One|x64.Build.0 = Debug One|x64
- {C8446636-C663-409F-82D0-72C0D55BBA1C}.Debug|Any CPU.ActiveCfg = Debug|x64
- {C8446636-C663-409F-82D0-72C0D55BBA1C}.Debug|Any CPU.Build.0 = Debug|x64
- {C8446636-C663-409F-82D0-72C0D55BBA1C}.Debug|x64.ActiveCfg = Debug|x64
- {C8446636-C663-409F-82D0-72C0D55BBA1C}.Debug|x64.Build.0 = Debug|x64
- {C8446636-C663-409F-82D0-72C0D55BBA1C}.Release|Any CPU.ActiveCfg = Release|x64
- {C8446636-C663-409F-82D0-72C0D55BBA1C}.Release|Any CPU.Build.0 = Release|x64
- {C8446636-C663-409F-82D0-72C0D55BBA1C}.Release|x64.ActiveCfg = Release|x64
- {C8446636-C663-409F-82D0-72C0D55BBA1C}.Release|x64.Build.0 = Release|x64
+ {B0FECFED-4451-4C7D-ACB7-59CC6F12FBAF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B0FECFED-4451-4C7D-ACB7-59CC6F12FBAF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B0FECFED-4451-4C7D-ACB7-59CC6F12FBAF}.Debug R22|Any CPU.ActiveCfg = Debug|Any CPU
+ {B0FECFED-4451-4C7D-ACB7-59CC6F12FBAF}.Debug R22|Any CPU.Build.0 = Debug|Any CPU
+ {B0FECFED-4451-4C7D-ACB7-59CC6F12FBAF}.Debug R23|Any CPU.ActiveCfg = Debug|Any CPU
+ {B0FECFED-4451-4C7D-ACB7-59CC6F12FBAF}.Release R18|Any CPU.ActiveCfg = Release|Any CPU
+ {B0FECFED-4451-4C7D-ACB7-59CC6F12FBAF}.Release R19|Any CPU.ActiveCfg = Release|Any CPU
+ {B0FECFED-4451-4C7D-ACB7-59CC6F12FBAF}.Release R20|Any CPU.ActiveCfg = Release|Any CPU
+ {B0FECFED-4451-4C7D-ACB7-59CC6F12FBAF}.Release R21|Any CPU.ActiveCfg = Release|Any CPU
+ {B0FECFED-4451-4C7D-ACB7-59CC6F12FBAF}.Release R22|Any CPU.ActiveCfg = Release|Any CPU
+ {B0FECFED-4451-4C7D-ACB7-59CC6F12FBAF}.Release R23|Any CPU.ActiveCfg = Release|Any CPU
+ {B0FECFED-4451-4C7D-ACB7-59CC6F12FBAF}.Installer|Any CPU.ActiveCfg = Release|Any CPU
+ {B0FECFED-4451-4C7D-ACB7-59CC6F12FBAF}.Installer|Any CPU.Build.0 = Release|Any CPU
+ {0DF5F952-C36B-4C97-B0CD-678C61093311}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0DF5F952-C36B-4C97-B0CD-678C61093311}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0DF5F952-C36B-4C97-B0CD-678C61093311}.Debug R22|Any CPU.ActiveCfg = Debug|Any CPU
+ {0DF5F952-C36B-4C97-B0CD-678C61093311}.Debug R22|Any CPU.Build.0 = Debug|Any CPU
+ {0DF5F952-C36B-4C97-B0CD-678C61093311}.Debug R23|Any CPU.ActiveCfg = Debug|Any CPU
+ {0DF5F952-C36B-4C97-B0CD-678C61093311}.Release R18|Any CPU.ActiveCfg = Release|Any CPU
+ {0DF5F952-C36B-4C97-B0CD-678C61093311}.Release R19|Any CPU.ActiveCfg = Release|Any CPU
+ {0DF5F952-C36B-4C97-B0CD-678C61093311}.Release R20|Any CPU.ActiveCfg = Release|Any CPU
+ {0DF5F952-C36B-4C97-B0CD-678C61093311}.Release R21|Any CPU.ActiveCfg = Release|Any CPU
+ {0DF5F952-C36B-4C97-B0CD-678C61093311}.Release R22|Any CPU.ActiveCfg = Release|Any CPU
+ {0DF5F952-C36B-4C97-B0CD-678C61093311}.Release R23|Any CPU.ActiveCfg = Release|Any CPU
+ {0DF5F952-C36B-4C97-B0CD-678C61093311}.Installer|Any CPU.ActiveCfg = Release|Any CPU
+ {F1152D68-346B-4F48-8DB7-BE67B5CB1F49}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F1152D68-346B-4F48-8DB7-BE67B5CB1F49}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F1152D68-346B-4F48-8DB7-BE67B5CB1F49}.Debug R22|Any CPU.ActiveCfg = Debug|Any CPU
+ {F1152D68-346B-4F48-8DB7-BE67B5CB1F49}.Debug R22|Any CPU.Build.0 = Debug|Any CPU
+ {F1152D68-346B-4F48-8DB7-BE67B5CB1F49}.Debug R23|Any CPU.ActiveCfg = Debug|Any CPU
+ {F1152D68-346B-4F48-8DB7-BE67B5CB1F49}.Release R18|Any CPU.ActiveCfg = Release|Any CPU
+ {F1152D68-346B-4F48-8DB7-BE67B5CB1F49}.Release R18|Any CPU.Build.0 = Release|Any CPU
+ {F1152D68-346B-4F48-8DB7-BE67B5CB1F49}.Release R19|Any CPU.ActiveCfg = Release|Any CPU
+ {F1152D68-346B-4F48-8DB7-BE67B5CB1F49}.Release R19|Any CPU.Build.0 = Release|Any CPU
+ {F1152D68-346B-4F48-8DB7-BE67B5CB1F49}.Release R20|Any CPU.ActiveCfg = Release|Any CPU
+ {F1152D68-346B-4F48-8DB7-BE67B5CB1F49}.Release R20|Any CPU.Build.0 = Release|Any CPU
+ {F1152D68-346B-4F48-8DB7-BE67B5CB1F49}.Release R21|Any CPU.ActiveCfg = Release|Any CPU
+ {F1152D68-346B-4F48-8DB7-BE67B5CB1F49}.Release R21|Any CPU.Build.0 = Release|Any CPU
+ {F1152D68-346B-4F48-8DB7-BE67B5CB1F49}.Release R22|Any CPU.ActiveCfg = Release|Any CPU
+ {F1152D68-346B-4F48-8DB7-BE67B5CB1F49}.Release R22|Any CPU.Build.0 = Release|Any CPU
+ {F1152D68-346B-4F48-8DB7-BE67B5CB1F49}.Release R23|Any CPU.ActiveCfg = Release|Any CPU
+ {F1152D68-346B-4F48-8DB7-BE67B5CB1F49}.Release R23|Any CPU.Build.0 = Release|Any CPU
+ {F1152D68-346B-4F48-8DB7-BE67B5CB1F49}.Debug R23|Any CPU.Build.0 = Debug|Any CPU
+ {F1152D68-346B-4F48-8DB7-BE67B5CB1F49}.Installer|Any CPU.ActiveCfg = Release|Any CPU
+ {7E37F14E-D840-42F8-8CA6-90FFC5497972}.Debug|Any CPU.ActiveCfg = Debug R22|Any CPU
+ {7E37F14E-D840-42F8-8CA6-90FFC5497972}.Debug|Any CPU.Build.0 = Debug R22|Any CPU
+ {7E37F14E-D840-42F8-8CA6-90FFC5497972}.Debug R22|Any CPU.ActiveCfg = Debug R22|Any CPU
+ {7E37F14E-D840-42F8-8CA6-90FFC5497972}.Debug R22|Any CPU.Build.0 = Debug R22|Any CPU
+ {7E37F14E-D840-42F8-8CA6-90FFC5497972}.Debug R23|Any CPU.ActiveCfg = Debug R23|Any CPU
+ {7E37F14E-D840-42F8-8CA6-90FFC5497972}.Release R18|Any CPU.ActiveCfg = Release R18|Any CPU
+ {7E37F14E-D840-42F8-8CA6-90FFC5497972}.Release R18|Any CPU.Build.0 = Release R18|Any CPU
+ {7E37F14E-D840-42F8-8CA6-90FFC5497972}.Release R19|Any CPU.ActiveCfg = Release R19|Any CPU
+ {7E37F14E-D840-42F8-8CA6-90FFC5497972}.Release R19|Any CPU.Build.0 = Release R19|Any CPU
+ {7E37F14E-D840-42F8-8CA6-90FFC5497972}.Release R20|Any CPU.ActiveCfg = Release R20|Any CPU
+ {7E37F14E-D840-42F8-8CA6-90FFC5497972}.Release R20|Any CPU.Build.0 = Release R20|Any CPU
+ {7E37F14E-D840-42F8-8CA6-90FFC5497972}.Release R21|Any CPU.ActiveCfg = Release R21|Any CPU
+ {7E37F14E-D840-42F8-8CA6-90FFC5497972}.Release R21|Any CPU.Build.0 = Release R21|Any CPU
+ {7E37F14E-D840-42F8-8CA6-90FFC5497972}.Release R23|Any CPU.ActiveCfg = Release R23|Any CPU
+ {7E37F14E-D840-42F8-8CA6-90FFC5497972}.Release R23|Any CPU.Build.0 = Release R23|Any CPU
+ {7E37F14E-D840-42F8-8CA6-90FFC5497972}.Debug R23|Any CPU.Build.0 = Debug R23|Any CPU
+ {7E37F14E-D840-42F8-8CA6-90FFC5497972}.Installer|Any CPU.ActiveCfg = Release R23|Any CPU
+ {7E37F14E-D840-42F8-8CA6-90FFC5497972}.Release R22|Any CPU.ActiveCfg = Release R22|Any CPU
+ {7E37F14E-D840-42F8-8CA6-90FFC5497972}.Release R22|Any CPU.Build.0 = Release R22|Any CPU
+ {C8446636-C663-409F-82D0-72C0D55BBA1C}.Debug|Any CPU.ActiveCfg = Debug R22|Any CPU
+ {C8446636-C663-409F-82D0-72C0D55BBA1C}.Debug|Any CPU.Build.0 = Debug R22|Any CPU
+ {C8446636-C663-409F-82D0-72C0D55BBA1C}.Debug R22|Any CPU.ActiveCfg = Debug R22|Any CPU
+ {C8446636-C663-409F-82D0-72C0D55BBA1C}.Debug R22|Any CPU.Build.0 = Debug R22|Any CPU
+ {C8446636-C663-409F-82D0-72C0D55BBA1C}.Debug R23|Any CPU.ActiveCfg = Debug R23|Any CPU
+ {C8446636-C663-409F-82D0-72C0D55BBA1C}.Release R18|Any CPU.ActiveCfg = Release R18|Any CPU
+ {C8446636-C663-409F-82D0-72C0D55BBA1C}.Release R18|Any CPU.Build.0 = Release R18|Any CPU
+ {C8446636-C663-409F-82D0-72C0D55BBA1C}.Release R19|Any CPU.ActiveCfg = Release R19|Any CPU
+ {C8446636-C663-409F-82D0-72C0D55BBA1C}.Release R19|Any CPU.Build.0 = Release R19|Any CPU
+ {C8446636-C663-409F-82D0-72C0D55BBA1C}.Release R20|Any CPU.ActiveCfg = Release R20|Any CPU
+ {C8446636-C663-409F-82D0-72C0D55BBA1C}.Release R20|Any CPU.Build.0 = Release R20|Any CPU
+ {C8446636-C663-409F-82D0-72C0D55BBA1C}.Release R21|Any CPU.ActiveCfg = Release R21|Any CPU
+ {C8446636-C663-409F-82D0-72C0D55BBA1C}.Release R21|Any CPU.Build.0 = Release R21|Any CPU
+ {C8446636-C663-409F-82D0-72C0D55BBA1C}.Release R22|Any CPU.ActiveCfg = Release R22|Any CPU
+ {C8446636-C663-409F-82D0-72C0D55BBA1C}.Release R22|Any CPU.Build.0 = Release R22|Any CPU
+ {C8446636-C663-409F-82D0-72C0D55BBA1C}.Release R23|Any CPU.ActiveCfg = Release R23|Any CPU
+ {C8446636-C663-409F-82D0-72C0D55BBA1C}.Release R23|Any CPU.Build.0 = Release R23|Any CPU
+ {C8446636-C663-409F-82D0-72C0D55BBA1C}.Debug R23|Any CPU.Build.0 = Debug R23|Any CPU
+ {C8446636-C663-409F-82D0-72C0D55BBA1C}.Installer|Any CPU.ActiveCfg = Release R23|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/RevitPythonShell/RevitPythonShellApplication.cs b/RevitPythonShell/App.cs
similarity index 93%
rename from RevitPythonShell/RevitPythonShellApplication.cs
rename to RevitPythonShell/App.cs
index 9fd17bc..83b79a3 100644
--- a/RevitPythonShell/RevitPythonShellApplication.cs
+++ b/RevitPythonShell/App.cs
@@ -1,618 +1,614 @@
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.IO;
-using System.Linq;
-using System.Reflection;
-using System.Reflection.Emit;
-using System.Xml.Linq;
-using Autodesk.Revit;
-using Autodesk.Revit.UI;
-using Autodesk.Revit.ApplicationServices;
-using Autodesk.Revit.Attributes;
-using System.Windows.Media;
-using System.Windows.Media.Imaging;
-using RevitPythonShell.RpsRuntime;
-
-namespace RevitPythonShell
-{
- [Regeneration(RegenerationOption.Manual)]
- [Transaction(TransactionMode.Manual)]
- class RevitPythonShellApplication : IExternalApplication
- {
- private const string APP_NAME = "RevitPythonShell";
- private static string versionNumber;
- private static string dllfolder;
-
- ///
- /// Hook into Revit to allow starting a command.
- ///
- Result IExternalApplication.OnStartup(UIControlledApplication application)
- {
-
- try
- {
- versionNumber = application.ControlledApplication.VersionNumber;
- if (application.ControlledApplication.VersionName.ToLower().Contains("vasari"))
- {
- versionNumber = "_Vasari";
- }
-
-#if DEBUG
- dllfolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
-#else
- dllfolder = Path.Combine(
- Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
- $"{APP_NAME}/{versionNumber}");
-#endif
- var assemblyName = "CommandLoaderAssembly";
- var dllfullpath = Path.Combine(dllfolder, assemblyName + ".dll");
-
- var settings = GetSettings();
-
- CreateCommandLoaderAssembly(settings, dllfolder, assemblyName);
- BuildRibbonPanel(application, dllfullpath);
-
- ExecuteStartupScript(application);
-
- return Result.Succeeded;
- }
- catch (Exception ex)
- {
- var td = new TaskDialog("Error setting up RevitPythonShell");
- td.MainInstruction = ex.Message;
- td.ExpandedContent = ex.ToString();
- td.Show();
- return Result.Failed;
- }
- }
-
- private static void ExecuteStartupScript(UIControlledApplication uiControlledApplication)
- {
- // we need a UIApplication object to assign as `__revit__` in python...
- 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);
- // execute StartupScript
- var startupScript = GetStartupScript();
- if (startupScript != null)
- {
- var executor = new ScriptExecutor(GetConfig(), uiApplication, uiControlledApplication);
- var result = executor.ExecuteScript(startupScript, GetStartupScriptPath());
- if (result == (int)Result.Failed)
- {
- TaskDialog.Show("RevitPythonShell - StartupScript", executor.Message);
- }
- }
- }
-
- private static void BuildRibbonPanel(UIControlledApplication application, string dllfullpath)
- {
- var assembly = typeof(RevitPythonShellApplication).Assembly;
- var smallImage = GetEmbeddedPng(assembly, "RevitPythonShell.Resources.Python-16.png");
- var largeImage = GetEmbeddedPng(assembly, "RevitPythonShell.Resources.Python-32.png");
-
-
- RibbonPanel ribbonPanel = application.CreateRibbonPanel(APP_NAME);
- var splitButton = ribbonPanel.AddItem(new SplitButtonData("splitButtonRevitPythonShell", APP_NAME)) as SplitButton;
-
- PushButtonData pbdOpenPythonShell = new PushButtonData(
- APP_NAME,
- "Interactive\nPython Shell",
- assembly.Location,
- "RevitPythonShell.IronPythonConsoleCommand");
- pbdOpenPythonShell.Image = smallImage;
- pbdOpenPythonShell.LargeImage = largeImage;
- pbdOpenPythonShell.AvailabilityClassName = "RevitPythonShell.IronPythonConsoleCommandAvail";
- splitButton.AddPushButton(pbdOpenPythonShell);
-
- PushButtonData pbdOpenNonModalShell = new PushButtonData(
- "NonModalRevitPythonShell",
- "Non-modal\nShell",
- assembly.Location,
- "RevitPythonShell.NonModalConsoleCommand");
- pbdOpenNonModalShell.Image = smallImage;
- pbdOpenNonModalShell.LargeImage = largeImage;
- pbdOpenNonModalShell.AvailabilityClassName = "RevitPythonShell.IronPythonConsoleCommandAvail";
- splitButton.AddPushButton(pbdOpenNonModalShell);
-
- PushButtonData pbdConfigure = new PushButtonData(
- "Configure",
- "Configure...",
- assembly.Location,
- "RevitPythonShell.ConfigureCommand");
- pbdConfigure.Image = GetEmbeddedPng(assembly, "RevitPythonShell.Resources.Settings-16.png");
- pbdConfigure.LargeImage = GetEmbeddedPng(assembly, "RevitPythonShell.Resources.Settings-32.png");
- pbdConfigure.AvailabilityClassName = "RevitPythonShell.IronPythonConsoleCommandAvail";
- splitButton.AddPushButton(pbdConfigure);
-
- PushButtonData pbdDeployRpsAddin = new PushButtonData(
- "DeployRpsAddin",
- "Deploy RpsAddin",
- assembly.Location,
- "RevitPythonShell.DeployRpsAddinCommand");
- pbdDeployRpsAddin.Image = GetEmbeddedPng(assembly, "RevitPythonShell.Resources.Deployment-16.png");
- pbdDeployRpsAddin.LargeImage = GetEmbeddedPng(assembly, "RevitPythonShell.Resources.Deployment-32.png");
- pbdDeployRpsAddin.AvailabilityClassName = "RevitPythonShell.IronPythonConsoleCommandAvail";
- splitButton.AddPushButton(pbdDeployRpsAddin);
-
- var commands = GetCommands(GetSettings()).ToList();
- AddGroupedCommands(dllfullpath, ribbonPanel, commands.Where(c => !string.IsNullOrEmpty(c.Group)).GroupBy(c => c.Group));
- AddUngroupedCommands(dllfullpath, ribbonPanel, commands.Where(c => string.IsNullOrEmpty(c.Group)).ToList());
- }
-
-
-
- private static ImageSource GetEmbeddedBmp(System.Reflection.Assembly app, string imageName)
- {
- var file = app.GetManifestResourceStream(imageName);
- var source = BmpBitmapDecoder.Create(file, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
- return source.Frames[0];
- }
-
- private static ImageSource GetEmbeddedPng(System.Reflection.Assembly app, string imageName)
- {
- var file = app.GetManifestResourceStream(imageName);
- var source = PngBitmapDecoder.Create(file, BitmapCreateOptions.None, BitmapCacheOption.None);
- return source.Frames[0];
- }
-
- private static void AddGroupedCommands(string dllfullpath, RibbonPanel ribbonPanel, IEnumerable> groupedCommands)
- {
- foreach (var group in groupedCommands)
- {
- SplitButtonData splitButtonData = new SplitButtonData(group.Key, group.Key);
- var splitButton = ribbonPanel.AddItem(splitButtonData) as SplitButton;
- foreach (var command in group)
- {
- var pbd = new PushButtonData(command.Name, command.Name, dllfullpath, "Command" + command.Index);
- pbd.Image = command.SmallImage;
- pbd.LargeImage = command.LargeImage;
- splitButton.AddPushButton(pbd);
- }
- }
- }
-
-
- private static void AddUngroupedCommands(string dllfullpath, RibbonPanel ribbonPanel, List commands)
- {
- // add canned commands as stacked pushbuttons (try to pack 3 commands per pushbutton, then 2)
- while (commands.Count > 4 || commands.Count == 3)
- {
- // remove first three commands from the list
- var command0 = commands[0];
- var command1 = commands[1];
- var command2 = commands[2];
- commands.RemoveAt(0);
- commands.RemoveAt(0);
- commands.RemoveAt(0);
-
- PushButtonData pbdA = new PushButtonData(command0.Name, command0.Name, dllfullpath, "Command" + command0.Index);
- pbdA.Image = command0.SmallImage;
- pbdA.LargeImage = command0.LargeImage;
-
- PushButtonData pbdB = new PushButtonData(command1.Name, command1.Name, dllfullpath, "Command" + command1.Index);
- pbdB.Image = command1.SmallImage;
- pbdB.LargeImage = command1.LargeImage;
-
- PushButtonData pbdC = new PushButtonData(command2.Name, command2.Name, dllfullpath, "Command" + command2.Index);
- pbdC.Image = command2.SmallImage;
- pbdC.LargeImage = command2.LargeImage;
-
- ribbonPanel.AddStackedItems(pbdA, pbdB, pbdC);
- }
- if (commands.Count == 4)
- {
- // remove first two commands from the list
- var command0 = commands[0];
- var command1 = commands[1];
- commands.RemoveAt(0);
- commands.RemoveAt(0);
-
- PushButtonData pbdA = new PushButtonData(command0.Name, command0.Name, dllfullpath, "Command" + command0.Index);
- pbdA.Image = command0.SmallImage;
- pbdA.LargeImage = command0.LargeImage;
-
- PushButtonData pbdB = new PushButtonData(command1.Name, command1.Name, dllfullpath, "Command" + command1.Index);
- pbdB.Image = command0.SmallImage;
- pbdB.LargeImage = command0.LargeImage;
-
- ribbonPanel.AddStackedItems(pbdA, pbdB);
- }
- if (commands.Count == 2)
- {
- // remove first two commands from the list
- var command0 = commands[0];
- var command1 = commands[1];
- commands.RemoveAt(0);
- commands.RemoveAt(0);
- PushButtonData pbdA = new PushButtonData(command0.Name, command0.Name, dllfullpath, "Command" + command0.Index);
- pbdA.Image = command0.SmallImage;
- pbdA.LargeImage = command0.LargeImage;
-
- PushButtonData pbdB = new PushButtonData(command1.Name, command1.Name, dllfullpath, "Command" + command1.Index);
- pbdB.Image = command1.SmallImage;
- pbdB.LargeImage = command1.LargeImage;
-
- ribbonPanel.AddStackedItems(pbdA, pbdB);
- }
- if (commands.Count == 1)
- {
- // only one command defined, show as a big button...
- var command = commands[0];
- PushButtonData pbd = new PushButtonData(command.Name, command.Name, dllfullpath, "Command" + command.Index);
- pbd.Image = command.SmallImage;
- pbd.LargeImage = command.LargeImage;
- ribbonPanel.AddItem(pbd);
- }
- }
-
- ///
- /// Creates a dynamic assembly that contains types for starting the canned commands.
- ///
- private static void CreateCommandLoaderAssembly(XDocument repository, string dllfolder, string dllname)
- {
- var assemblyName = new AssemblyName { Name = dllname + ".dll", Version = new Version(1, 0, 0, 0) };
- var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave, dllfolder);
- var moduleBuilder = assemblyBuilder.DefineDynamicModule("CommandLoaderModule", dllname + ".dll");
-
- foreach (var command in GetCommands(repository))
- {
- var typebuilder = moduleBuilder.DefineType("Command" + command.Index,
- TypeAttributes.Class | TypeAttributes.Public,
- typeof(CommandLoaderBase));
-
- // add RegenerationAttribute to type
- var regenerationConstrutorInfo = typeof(RegenerationAttribute).GetConstructor(new Type[] { typeof(RegenerationOption) });
- var regenerationAttributeBuilder = new CustomAttributeBuilder(regenerationConstrutorInfo, new object[] {RegenerationOption.Manual});
- typebuilder.SetCustomAttribute(regenerationAttributeBuilder);
-
- // add TransactionAttribute to type
- var transactionConstructorInfo = typeof(TransactionAttribute).GetConstructor(new Type[] { typeof(TransactionMode) });
- var transactionAttributeBuilder = new CustomAttributeBuilder(transactionConstructorInfo, new object[] { TransactionMode.Manual });
- typebuilder.SetCustomAttribute(transactionAttributeBuilder);
-
- // call base constructor with script path
- var ci = typeof(CommandLoaderBase).GetConstructor(new[] { typeof(string) });
-
- var constructorBuilder = typebuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, new Type[0]);
- var gen = constructorBuilder.GetILGenerator();
- gen.Emit(OpCodes.Ldarg_0); // Load "this" onto eval stack
- gen.Emit(OpCodes.Ldstr, command.Source); // Load the path to the command as a string onto stack
- gen.Emit(OpCodes.Call, ci); // call base constructor (consumes "this" and the string)
- gen.Emit(OpCodes.Nop); // Fill some space - this is how it is generated for equivalent C# code
- gen.Emit(OpCodes.Nop);
- gen.Emit(OpCodes.Nop);
- gen.Emit(OpCodes.Ret); // return from constructor
- typebuilder.CreateType();
- }
- assemblyBuilder.Save(dllname + ".dll");
- }
-
- Result IExternalApplication.OnShutdown(UIControlledApplication application)
- {
- // FIXME: deallocate the python shell...
- return Result.Succeeded;
- }
-
- public static IRpsConfig GetConfig()
- {
- return new RpsConfig(GetSettingsFile());
- }
-
- ///
- /// Returns a handle to the settings file.
- ///
- ///
- public static XDocument GetSettings()
- {
- string settingsFile = GetSettingsFile();
- return XDocument.Load(settingsFile);
- }
-
- private static string GetSettingsFile()
- {
- string folder = GetSettingsFolder();
- return Path.Combine(folder, "RevitPythonShell.xml");
- }
-
- ///
- /// Returns the name of the folder with the settings file. This folder
- /// is also the default folder for relative paths in StartupScript and InitScript tags.
- ///
- private static string GetSettingsFolder()
- {
-#if DEBUG
- return Path.Combine(dllfolder, "DefaultConfig");
-#else
- return dllfolder;
-#endif
- }
-
- ///
- /// Returns a list of commands as defined in the repository file.
- ///
- ///
- public static IEnumerable GetCommands(XDocument repository)
- {
- int i = 0;
- foreach (var commandNode in repository.Root.Descendants("Command") ?? new List())
- {
- var addinAssembly = typeof(RpsExternalApplicationBase).Assembly;
- var commandName = commandNode.Attribute("name").Value;
- var commandSrc = commandNode.Attribute("src").Value;
- var group = commandNode.Attribute("group") == null ? "" : commandNode.Attribute("group").Value;
-
- ImageSource largeImage = null;
- if (IsValidPath(commandNode.Attribute("largeImage")))
- {
- var largeImagePath = GetAbsolutePath(commandNode.Attribute("largeImage").Value);
- largeImage = BitmapDecoder.Create(File.OpenRead(largeImagePath), BitmapCreateOptions.None, BitmapCacheOption.None).Frames[0];
- }
- else
- {
- largeImage = GetEmbeddedPng(addinAssembly, "RpsRuntime.Resources.PythonScript32x32.png");
- }
-
- ImageSource smallImage = null;
- if (IsValidPath(commandNode.Attribute("smallImage")))
- {
- var smallImagePath = GetAbsolutePath(commandNode.Attribute("smallImage").Value);
- smallImage = BitmapDecoder.Create(File.OpenRead(smallImagePath), BitmapCreateOptions.None, BitmapCacheOption.None).Frames[0];
- }
- else
- {
- smallImage = GetEmbeddedPng(addinAssembly, "RpsRuntime.Resources.PythonScript16x16.png");
- }
-
- yield return new Command {
- Name = commandName,
- Source = commandSrc,
- Group = group,
- LargeImage = largeImage,
- SmallImage = smallImage,
- Index = i++
- };
- }
- }
-
- ///
- /// True, if the contents of the attribute is a valid absolute path (or relative path to the assembly) is
- /// an existing path.
- ///
- private static bool IsValidPath(XAttribute pathAttribute)
- {
- if (pathAttribute != null && !string.IsNullOrEmpty(pathAttribute.Value))
- {
- return File.Exists(GetAbsolutePath(pathAttribute.Value));
- }
- return false;
- }
-
- ///
- /// Return an absolute path for input path, with relative paths seen as
- /// relative to the assembly location. No guarantees are made as to
- /// wether the path exists or not.
- ///
- private static string GetAbsolutePath(string path)
- {
- if (Path.IsPathRooted(path))
- {
- return path;
- }
- else
- {
- var assembly = typeof(RevitPythonShellApplication).Assembly;
- return Path.Combine(Path.GetDirectoryName(assembly.Location), path);
- }
- }
-
- ///
- /// Returns a string to be executed, whenever the interactive shell is started.
- /// If this is not specified in the XML file (under /RevitPythonShell/InitScript),
- /// then null is returned.
- ///
- public static string GetInitScript()
- {
- var path = GetInitScriptPath();
- if (File.Exists(path))
- {
- using (var reader = File.OpenText(path))
- {
- var source = reader.ReadToEnd();
- return source;
- }
- }
-
- // backwards compatibility: InitScript used to have a CDATA section directly
- // embedded in the settings xml file
- var initScriptTags = GetSettings().Root.Descendants("InitScript") ?? new List();
- if (initScriptTags.Count() == 0)
- {
- return null;
- }
- var firstScript = initScriptTags.First();
- // backwards compatibility: InitScript used to be included as CDATA in the config file
- return firstScript.Value.Trim();
- }
-
- ///
- /// Returns the path to the InitScript as configured in the settings file or "" if not
- /// configured. This is used in the ConfigureCommandsForm.
- ///
- public static string GetInitScriptPath()
- {
- return GetScriptPath("InitScript");
- }
-
-
- ///
- /// Returns the path to the StartupScript as configured in the settings file or "" if not
- /// configured. This is used in the ConfigureCommandsForm.
- ///
- public static string GetStartupScriptPath()
- {
- return GetScriptPath("StartupScript");
- }
-
- ///
- /// Returns the value of the "src" attribute for the tag "tagName" in the settings file
- /// or "" if not configured.
- ///
- private static string GetScriptPath(string tagName)
- {
- var tags = GetSettings().Root.Descendants(tagName) ?? new List();
- if (tags.Count() == 0)
- {
- return "";
- }
- var firstScript = tags.First();
- if (firstScript.Attribute("src") != null)
- {
- var path = firstScript.Attribute("src").Value;
- if (Path.IsPathRooted(path))
- {
- return path;
- }
- else
- {
- return Path.Combine(GetSettingsFolder(), path);
- }
- }
- else
- {
- return "";
- }
- }
-
- ///
- /// Returns a string to be executed, whenever the revit is started.
- /// If this is not specified as a path to an existing file in the XML file (under /RevitPythonShell/StartupScript/@src),
- /// then null is returned.
- ///
- public static string GetStartupScript()
- {
- var path = GetStartupScriptPath();
- if (File.Exists(path))
- {
- using (var reader = File.OpenText(path))
- {
- var source = reader.ReadToEnd();
- return source;
- }
- }
- // no startup script found
- return null;
- }
-
- ///
- /// Writes settings to the settings file, replacing the old commands.
- ///
- public static void WriteSettings(
- IEnumerable commands,
- IEnumerable searchPaths,
- IEnumerable> variables,
- string initScript,
- string startupScript)
- {
- var doc = GetSettings();
- var settingsFolder = GetSettingsFolder();
-
- // clean out current stuff
- foreach (var xmlExistingCommands in (doc.Root.Descendants("Commands") ?? new List()).ToList())
- {
- xmlExistingCommands.Remove();
- }
- foreach (var xmlExistingSearchPaths in doc.Root.Descendants("SearchPaths").ToList())
- {
- xmlExistingSearchPaths.Remove();
- }
- foreach (var xmlExistingVariables in doc.Root.Descendants("Variables").ToList())
- {
- xmlExistingVariables.Remove();
- }
- foreach (var xmlExistingInitScript in doc.Root.Descendants("InitScript").ToList())
- {
- xmlExistingInitScript.Remove();
- }
- foreach (var xmlExistingStartupScript in doc.Root.Descendants("StartupScript").ToList())
- {
- xmlExistingStartupScript.Remove();
- }
-
- // add commnads
- var xmlCommands = new XElement("Commands");
- foreach (var command in commands)
- {
- xmlCommands.Add(new XElement(
- "Command",
- new XAttribute("name", command.Name),
- new XAttribute("src", command.Source),
- new XAttribute("group", command.Group)));
-
- }
- doc.Root.Add(xmlCommands);
-
- // add search paths
- var xmlSearchPaths = new XElement("SearchPaths");
- foreach (var path in searchPaths)
- {
- xmlSearchPaths.Add(new XElement(
- "SearchPath",
- new XAttribute("name", path)));
-
- }
- // ensure settings directory is added to the search paths
- if (!searchPaths.Contains(settingsFolder)) {
- xmlSearchPaths.Add(new XElement(
- "SearchPath",
- new XAttribute("name", settingsFolder)));
-
- }
- doc.Root.Add(xmlSearchPaths);
-
- // add variables
- var xmlVariables = new XElement("Variables");
- foreach (var variable in variables)
- {
- xmlVariables.Add(new XElement(
- "StringVariable",
- new XAttribute("name", variable.Key),
- new XAttribute("value", variable.Value)));
-
- }
- doc.Root.Add(xmlVariables);
-
- // add init script
- var xmlInitScript = new XElement("InitScript");
- xmlInitScript.Add(new XAttribute("src", initScript));
- doc.Root.Add(xmlInitScript);
-
- // add startup script
- var xmlStartupScript = new XElement("StartupScript");
- xmlStartupScript.Add(new XAttribute("src", startupScript));
- doc.Root.Add(xmlStartupScript);
-
- doc.Save(GetSettingsFile());
- }
- }
-
- ///
- /// A simple structure to hold information about canned commands.
- ///
- internal class Command
- {
- public string Name;
- public string Group;
- public string Source;
- public int Index;
- public ImageSource LargeImage;
- public ImageSource SmallImage;
-
- public override string ToString()
- {
- return Name;
- }
- }
-}
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Reflection.Emit;
+using System.Xml.Linq;
+using Autodesk.Revit;
+using Autodesk.Revit.UI;
+using Autodesk.Revit.ApplicationServices;
+using Autodesk.Revit.Attributes;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using RevitPythonShell.RevitCommands;
+using RpsRuntime;
+
+namespace RevitPythonShell
+{
+ [Regeneration(RegenerationOption.Manual)]
+ [Transaction(TransactionMode.Manual)]
+ class App : IExternalApplication
+ {
+ private const string APP_NAME = "RevitPythonShell";
+ private static string versionNumber;
+ private static string dllfolder;
+
+ ///
+ /// Hook into Revit to allow starting a command.
+ ///
+ Result IExternalApplication.OnStartup(UIControlledApplication application)
+ {
+
+ try
+ {
+ versionNumber = application.ControlledApplication.VersionNumber;
+ if (application.ControlledApplication.VersionName.ToLower().Contains("vasari"))
+ {
+ versionNumber = "_Vasari";
+ }
+
+ dllfolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
+
+ // dllfolder = Path.Combine(
+ // Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
+ // $"{APP_NAME}/{versionNumber}");
+ var assemblyName = "CommandLoaderAssembly";
+ var dllfullpath = Path.Combine(dllfolder, assemblyName + ".dll");
+
+ var settings = GetSettings();
+
+ CreateCommandLoaderAssembly(settings, dllfolder, assemblyName);
+ BuildRibbonPanel(application, dllfullpath);
+
+ ExecuteStartupScript(application);
+
+ return Result.Succeeded;
+ }
+ catch (Exception ex)
+ {
+ var td = new TaskDialog("Error setting up RevitPythonShell");
+ td.MainInstruction = ex.Message;
+ td.ExpandedContent = ex.ToString();
+ td.Show();
+ return Result.Failed;
+ }
+ }
+
+ private static void ExecuteStartupScript(UIControlledApplication uiControlledApplication)
+ {
+ // we need a UIApplication object to assign as `__revit__` in python...
+ 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);
+ // execute StartupScript
+ var startupScript = GetStartupScript();
+ if (startupScript != null)
+ {
+ var executor = new ScriptExecutor(GetConfig(), uiApplication, uiControlledApplication);
+ var result = executor.ExecuteScript(startupScript, GetStartupScriptPath());
+ if (result == (int)Result.Failed)
+ {
+ TaskDialog.Show("RevitPythonShell - StartupScript", executor.Message);
+ }
+ }
+ }
+
+ private static void BuildRibbonPanel(UIControlledApplication application, string dllfullpath)
+ {
+ var assembly = typeof(App).Assembly;
+ var smallImage = GetEmbeddedPng(assembly, "RevitPythonShell.Resources.Python-16.png");
+ var largeImage = GetEmbeddedPng(assembly, "RevitPythonShell.Resources.Python-32.png");
+
+
+ RibbonPanel ribbonPanel = application.CreateRibbonPanel(APP_NAME);
+ var splitButton = ribbonPanel.AddItem(new SplitButtonData("splitButtonRevitPythonShell", APP_NAME)) as SplitButton;
+
+ PushButtonData pbdOpenPythonShell = new PushButtonData(
+ APP_NAME,
+ "Interactive\nPython Shell",
+ assembly.Location,
+ typeof(IronPythonConsoleCommand).FullName);
+ pbdOpenPythonShell.Image = smallImage;
+ pbdOpenPythonShell.LargeImage = largeImage;
+ pbdOpenPythonShell.AvailabilityClassName = typeof(IronPythonConsoleCommandAvail).FullName;
+ splitButton.AddPushButton(pbdOpenPythonShell);
+
+ PushButtonData pbdOpenNonModalShell = new PushButtonData(
+ "NonModalRevitPythonShell",
+ "Non-modal\nShell",
+ assembly.Location,
+ typeof(NonModalConsoleCommand).FullName);
+ pbdOpenNonModalShell.Image = smallImage;
+ pbdOpenNonModalShell.LargeImage = largeImage;
+ pbdOpenNonModalShell.AvailabilityClassName = typeof(IronPythonConsoleCommandAvail).FullName;
+ splitButton.AddPushButton(pbdOpenNonModalShell);
+
+ PushButtonData pbdConfigure = new PushButtonData(
+ "Configure",
+ "Configure...",
+ assembly.Location,
+ typeof(ConfigureCommand).FullName);
+ pbdConfigure.Image = GetEmbeddedPng(assembly, "RevitPythonShell.Resources.Settings-16.png");
+ pbdConfigure.LargeImage = GetEmbeddedPng(assembly, "RevitPythonShell.Resources.Settings-32.png");
+ pbdConfigure.AvailabilityClassName = typeof(IronPythonConsoleCommandAvail).FullName;
+ splitButton.AddPushButton(pbdConfigure);
+
+ PushButtonData pbdDeployRpsAddin = new PushButtonData(
+ "DeployRpsAddin",
+ "Deploy RpsAddin",
+ assembly.Location,
+ typeof(DeployRpsAddinCommand).FullName);
+ pbdDeployRpsAddin.Image = GetEmbeddedPng(assembly, "RevitPythonShell.Resources.Deployment-16.png");
+ pbdDeployRpsAddin.LargeImage = GetEmbeddedPng(assembly, "RevitPythonShell.Resources.Deployment-32.png");
+ pbdDeployRpsAddin.AvailabilityClassName = typeof(IronPythonConsoleCommandAvail).FullName;
+ splitButton.AddPushButton(pbdDeployRpsAddin);
+
+ var commands = GetCommands(GetSettings()).ToList();
+ AddGroupedCommands(dllfullpath, ribbonPanel, commands.Where(c => !string.IsNullOrEmpty(c.Group)).GroupBy(c => c.Group));
+ AddUngroupedCommands(dllfullpath, ribbonPanel, commands.Where(c => string.IsNullOrEmpty(c.Group)).ToList());
+ }
+
+
+
+ private static ImageSource GetEmbeddedBmp(System.Reflection.Assembly app, string imageName)
+ {
+ var file = app.GetManifestResourceStream(imageName);
+ var source = BmpBitmapDecoder.Create(file, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
+ return source.Frames[0];
+ }
+
+ private static ImageSource GetEmbeddedPng(System.Reflection.Assembly app, string imageName)
+ {
+ var file = app.GetManifestResourceStream(imageName);
+ var source = PngBitmapDecoder.Create(file, BitmapCreateOptions.None, BitmapCacheOption.None);
+ return source.Frames[0];
+ }
+
+ private static void AddGroupedCommands(string dllfullpath, RibbonPanel ribbonPanel, IEnumerable> groupedCommands)
+ {
+ foreach (var group in groupedCommands)
+ {
+ SplitButtonData splitButtonData = new SplitButtonData(group.Key, group.Key);
+ var splitButton = ribbonPanel.AddItem(splitButtonData) as SplitButton;
+ foreach (var command in group)
+ {
+ var pbd = new PushButtonData(command.Name, command.Name, dllfullpath, "Command" + command.Index);
+ pbd.Image = command.SmallImage;
+ pbd.LargeImage = command.LargeImage;
+ splitButton.AddPushButton(pbd);
+ }
+ }
+ }
+
+
+ private static void AddUngroupedCommands(string dllfullpath, RibbonPanel ribbonPanel, List commands)
+ {
+ // add canned commands as stacked pushbuttons (try to pack 3 commands per pushbutton, then 2)
+ while (commands.Count > 4 || commands.Count == 3)
+ {
+ // remove first three commands from the list
+ var command0 = commands[0];
+ var command1 = commands[1];
+ var command2 = commands[2];
+ commands.RemoveAt(0);
+ commands.RemoveAt(0);
+ commands.RemoveAt(0);
+
+ PushButtonData pbdA = new PushButtonData(command0.Name, command0.Name, dllfullpath, "Command" + command0.Index);
+ pbdA.Image = command0.SmallImage;
+ pbdA.LargeImage = command0.LargeImage;
+
+ PushButtonData pbdB = new PushButtonData(command1.Name, command1.Name, dllfullpath, "Command" + command1.Index);
+ pbdB.Image = command1.SmallImage;
+ pbdB.LargeImage = command1.LargeImage;
+
+ PushButtonData pbdC = new PushButtonData(command2.Name, command2.Name, dllfullpath, "Command" + command2.Index);
+ pbdC.Image = command2.SmallImage;
+ pbdC.LargeImage = command2.LargeImage;
+
+ ribbonPanel.AddStackedItems(pbdA, pbdB, pbdC);
+ }
+ if (commands.Count == 4)
+ {
+ // remove first two commands from the list
+ var command0 = commands[0];
+ var command1 = commands[1];
+ commands.RemoveAt(0);
+ commands.RemoveAt(0);
+
+ PushButtonData pbdA = new PushButtonData(command0.Name, command0.Name, dllfullpath, "Command" + command0.Index);
+ pbdA.Image = command0.SmallImage;
+ pbdA.LargeImage = command0.LargeImage;
+
+ PushButtonData pbdB = new PushButtonData(command1.Name, command1.Name, dllfullpath, "Command" + command1.Index);
+ pbdB.Image = command0.SmallImage;
+ pbdB.LargeImage = command0.LargeImage;
+
+ ribbonPanel.AddStackedItems(pbdA, pbdB);
+ }
+ if (commands.Count == 2)
+ {
+ // remove first two commands from the list
+ var command0 = commands[0];
+ var command1 = commands[1];
+ commands.RemoveAt(0);
+ commands.RemoveAt(0);
+ PushButtonData pbdA = new PushButtonData(command0.Name, command0.Name, dllfullpath, "Command" + command0.Index);
+ pbdA.Image = command0.SmallImage;
+ pbdA.LargeImage = command0.LargeImage;
+
+ PushButtonData pbdB = new PushButtonData(command1.Name, command1.Name, dllfullpath, "Command" + command1.Index);
+ pbdB.Image = command1.SmallImage;
+ pbdB.LargeImage = command1.LargeImage;
+
+ ribbonPanel.AddStackedItems(pbdA, pbdB);
+ }
+ if (commands.Count == 1)
+ {
+ // only one command defined, show as a big button...
+ var command = commands[0];
+ PushButtonData pbd = new PushButtonData(command.Name, command.Name, dllfullpath, "Command" + command.Index);
+ pbd.Image = command.SmallImage;
+ pbd.LargeImage = command.LargeImage;
+ ribbonPanel.AddItem(pbd);
+ }
+ }
+
+ ///
+ /// Creates a dynamic assembly that contains types for starting the canned commands.
+ ///
+ private static void CreateCommandLoaderAssembly(XDocument repository, string dllfolder, string dllname)
+ {
+ var assemblyName = new AssemblyName { Name = dllname + ".dll", Version = new Version(1, 0, 0, 0) };
+ var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave, dllfolder);
+ var moduleBuilder = assemblyBuilder.DefineDynamicModule("CommandLoaderModule", dllname + ".dll");
+
+ foreach (var command in GetCommands(repository))
+ {
+ var typebuilder = moduleBuilder.DefineType("Command" + command.Index,
+ TypeAttributes.Class | TypeAttributes.Public,
+ typeof(CommandLoaderBase));
+
+ // add RegenerationAttribute to type
+ var regenerationConstrutorInfo = typeof(RegenerationAttribute).GetConstructor(new Type[] { typeof(RegenerationOption) });
+ var regenerationAttributeBuilder = new CustomAttributeBuilder(regenerationConstrutorInfo, new object[] {RegenerationOption.Manual});
+ typebuilder.SetCustomAttribute(regenerationAttributeBuilder);
+
+ // add TransactionAttribute to type
+ var transactionConstructorInfo = typeof(TransactionAttribute).GetConstructor(new Type[] { typeof(TransactionMode) });
+ var transactionAttributeBuilder = new CustomAttributeBuilder(transactionConstructorInfo, new object[] { TransactionMode.Manual });
+ typebuilder.SetCustomAttribute(transactionAttributeBuilder);
+
+ // call base constructor with script path
+ var ci = typeof(CommandLoaderBase).GetConstructor(new[] { typeof(string) });
+
+ var constructorBuilder = typebuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, new Type[0]);
+ var gen = constructorBuilder.GetILGenerator();
+ gen.Emit(OpCodes.Ldarg_0); // Load "this" onto eval stack
+ gen.Emit(OpCodes.Ldstr, command.Source); // Load the path to the command as a string onto stack
+ gen.Emit(OpCodes.Call, ci); // call base constructor (consumes "this" and the string)
+ gen.Emit(OpCodes.Nop); // Fill some space - this is how it is generated for equivalent C# code
+ gen.Emit(OpCodes.Nop);
+ gen.Emit(OpCodes.Nop);
+ gen.Emit(OpCodes.Ret); // return from constructor
+ typebuilder.CreateType();
+ }
+ assemblyBuilder.Save(dllname + ".dll");
+ }
+
+ Result IExternalApplication.OnShutdown(UIControlledApplication application)
+ {
+ // FIXME: deallocate the python shell...
+ return Result.Succeeded;
+ }
+
+ public static IRpsConfig GetConfig()
+ {
+ return new RpsConfig(GetSettingsFile());
+ }
+
+ ///
+ /// Returns a handle to the settings file.
+ ///
+ ///
+ public static XDocument GetSettings()
+ {
+ string settingsFile = GetSettingsFile();
+ return XDocument.Load(settingsFile);
+ }
+
+ private static string GetSettingsFile()
+ {
+ string folder = GetSettingsFolder();
+ return Path.Combine(folder, "RevitPythonShell.xml");
+ }
+
+ ///
+ /// Returns the name of the folder with the settings file. This folder
+ /// is also the default folder for relative paths in StartupScript and InitScript tags.
+ ///
+ private static string GetSettingsFolder()
+ {
+
+ return dllfolder;
+ }
+
+ ///
+ /// Returns a list of commands as defined in the repository file.
+ ///
+ ///
+ public static IEnumerable GetCommands(XDocument repository)
+ {
+ int i = 0;
+ foreach (var commandNode in repository.Root.Descendants("Command") ?? new List())
+ {
+ var addinAssembly = typeof(RpsExternalApplicationBase).Assembly;
+ var commandName = commandNode.Attribute("name").Value;
+ var commandSrc = commandNode.Attribute("src").Value;
+ var group = commandNode.Attribute("group") == null ? "" : commandNode.Attribute("group").Value;
+
+ ImageSource largeImage = null;
+ if (IsValidPath(commandNode.Attribute("largeImage")))
+ {
+ var largeImagePath = GetAbsolutePath(commandNode.Attribute("largeImage").Value);
+ largeImage = BitmapDecoder.Create(File.OpenRead(largeImagePath), BitmapCreateOptions.None, BitmapCacheOption.None).Frames[0];
+ }
+ else
+ {
+ largeImage = GetEmbeddedPng(addinAssembly, "RpsRuntime.Resources.PythonScript32x32.png");
+ }
+
+ ImageSource smallImage = null;
+ if (IsValidPath(commandNode.Attribute("smallImage")))
+ {
+ var smallImagePath = GetAbsolutePath(commandNode.Attribute("smallImage").Value);
+ smallImage = BitmapDecoder.Create(File.OpenRead(smallImagePath), BitmapCreateOptions.None, BitmapCacheOption.None).Frames[0];
+ }
+ else
+ {
+ smallImage = GetEmbeddedPng(addinAssembly, "RpsRuntime.Resources.PythonScript16x16.png");
+ }
+
+ yield return new Command {
+ Name = commandName,
+ Source = commandSrc,
+ Group = group,
+ LargeImage = largeImage,
+ SmallImage = smallImage,
+ Index = i++
+ };
+ }
+ }
+
+ ///
+ /// True, if the contents of the attribute is a valid absolute path (or relative path to the assembly) is
+ /// an existing path.
+ ///
+ private static bool IsValidPath(XAttribute pathAttribute)
+ {
+ if (pathAttribute != null && !string.IsNullOrEmpty(pathAttribute.Value))
+ {
+ return File.Exists(GetAbsolutePath(pathAttribute.Value));
+ }
+ return false;
+ }
+
+ ///
+ /// Return an absolute path for input path, with relative paths seen as
+ /// relative to the assembly location. No guarantees are made as to
+ /// wether the path exists or not.
+ ///
+ private static string GetAbsolutePath(string path)
+ {
+ if (Path.IsPathRooted(path))
+ {
+ return path;
+ }
+ else
+ {
+ var assembly = typeof(App).Assembly;
+ return Path.Combine(Path.GetDirectoryName(assembly.Location), path);
+ }
+ }
+
+ ///
+ /// Returns a string to be executed, whenever the interactive shell is started.
+ /// If this is not specified in the XML file (under /RevitPythonShell/InitScript),
+ /// then null is returned.
+ ///
+ public static string GetInitScript()
+ {
+ var path = GetInitScriptPath();
+ if (File.Exists(path))
+ {
+ using (var reader = File.OpenText(path))
+ {
+ var source = reader.ReadToEnd();
+ return source;
+ }
+ }
+
+ // backwards compatibility: InitScript used to have a CDATA section directly
+ // embedded in the settings xml file
+ var initScriptTags = GetSettings().Root.Descendants("InitScript") ?? new List();
+ if (initScriptTags.Count() == 0)
+ {
+ return null;
+ }
+ var firstScript = initScriptTags.First();
+ // backwards compatibility: InitScript used to be included as CDATA in the config file
+ return firstScript.Value.Trim();
+ }
+
+ ///
+ /// Returns the path to the InitScript as configured in the settings file or "" if not
+ /// configured. This is used in the ConfigureCommandsForm.
+ ///
+ public static string GetInitScriptPath()
+ {
+ return GetScriptPath("InitScript");
+ }
+
+
+ ///
+ /// Returns the path to the StartupScript as configured in the settings file or "" if not
+ /// configured. This is used in the ConfigureCommandsForm.
+ ///
+ public static string GetStartupScriptPath()
+ {
+ return GetScriptPath("StartupScript");
+ }
+
+ ///
+ /// Returns the value of the "src" attribute for the tag "tagName" in the settings file
+ /// or "" if not configured.
+ ///
+ private static string GetScriptPath(string tagName)
+ {
+ var tags = GetSettings().Root.Descendants(tagName) ?? new List();
+ if (tags.Count() == 0)
+ {
+ return "";
+ }
+ var firstScript = tags.First();
+ if (firstScript.Attribute("src") != null)
+ {
+ var path = firstScript.Attribute("src").Value;
+ if (Path.IsPathRooted(path))
+ {
+ return path;
+ }
+ else
+ {
+ return Path.Combine(GetSettingsFolder(), path);
+ }
+ }
+ else
+ {
+ return "";
+ }
+ }
+
+ ///
+ /// Returns a string to be executed, whenever the revit is started.
+ /// If this is not specified as a path to an existing file in the XML file (under /RevitPythonShell/StartupScript/@src),
+ /// then null is returned.
+ ///
+ public static string GetStartupScript()
+ {
+ var path = GetStartupScriptPath();
+ if (File.Exists(path))
+ {
+ using (var reader = File.OpenText(path))
+ {
+ var source = reader.ReadToEnd();
+ return source;
+ }
+ }
+ // no startup script found
+ return null;
+ }
+
+ ///
+ /// Writes settings to the settings file, replacing the old commands.
+ ///
+ public static void WriteSettings(
+ IEnumerable commands,
+ IEnumerable searchPaths,
+ IEnumerable> variables,
+ string initScript,
+ string startupScript)
+ {
+ var doc = GetSettings();
+ var settingsFolder = GetSettingsFolder();
+
+ // clean out current stuff
+ foreach (var xmlExistingCommands in (doc.Root.Descendants("Commands") ?? new List()).ToList())
+ {
+ xmlExistingCommands.Remove();
+ }
+ foreach (var xmlExistingSearchPaths in doc.Root.Descendants("SearchPaths").ToList())
+ {
+ xmlExistingSearchPaths.Remove();
+ }
+ foreach (var xmlExistingVariables in doc.Root.Descendants("Variables").ToList())
+ {
+ xmlExistingVariables.Remove();
+ }
+ foreach (var xmlExistingInitScript in doc.Root.Descendants("InitScript").ToList())
+ {
+ xmlExistingInitScript.Remove();
+ }
+ foreach (var xmlExistingStartupScript in doc.Root.Descendants("StartupScript").ToList())
+ {
+ xmlExistingStartupScript.Remove();
+ }
+
+ // add commnads
+ var xmlCommands = new XElement("Commands");
+ foreach (var command in commands)
+ {
+ xmlCommands.Add(new XElement(
+ "Command",
+ new XAttribute("name", command.Name),
+ new XAttribute("src", command.Source),
+ new XAttribute("group", command.Group)));
+
+ }
+ doc.Root.Add(xmlCommands);
+
+ // add search paths
+ var xmlSearchPaths = new XElement("SearchPaths");
+ foreach (var path in searchPaths)
+ {
+ xmlSearchPaths.Add(new XElement(
+ "SearchPath",
+ new XAttribute("name", path)));
+
+ }
+ // ensure settings directory is added to the search paths
+ if (!searchPaths.Contains(settingsFolder)) {
+ xmlSearchPaths.Add(new XElement(
+ "SearchPath",
+ new XAttribute("name", settingsFolder)));
+
+ }
+ doc.Root.Add(xmlSearchPaths);
+
+ // add variables
+ var xmlVariables = new XElement("Variables");
+ foreach (var variable in variables)
+ {
+ xmlVariables.Add(new XElement(
+ "StringVariable",
+ new XAttribute("name", variable.Key),
+ new XAttribute("value", variable.Value)));
+
+ }
+ doc.Root.Add(xmlVariables);
+
+ // add init script
+ var xmlInitScript = new XElement("InitScript");
+ xmlInitScript.Add(new XAttribute("src", initScript));
+ doc.Root.Add(xmlInitScript);
+
+ // add startup script
+ var xmlStartupScript = new XElement("StartupScript");
+ xmlStartupScript.Add(new XAttribute("src", startupScript));
+ doc.Root.Add(xmlStartupScript);
+
+ doc.Save(GetSettingsFile());
+ }
+ }
+
+ ///
+ /// A simple structure to hold information about canned commands.
+ ///
+ internal class Command
+ {
+ public string Name;
+ public string Group;
+ public string Source;
+ public int Index;
+ public ImageSource LargeImage;
+ public ImageSource SmallImage;
+
+ public override string ToString()
+ {
+ return Name;
+ }
+ }
+}
diff --git a/RevitPythonShell/Helpers/ProcessManager.cs b/RevitPythonShell/Helpers/ProcessManager.cs
new file mode 100644
index 0000000..350db19
--- /dev/null
+++ b/RevitPythonShell/Helpers/ProcessManager.cs
@@ -0,0 +1,53 @@
+using System;
+using System.ComponentModel;
+using System.Diagnostics;
+using System.Runtime.InteropServices;
+using System.Windows;
+using System.Windows.Interop;
+
+namespace RevitPythonShell.Helpers
+{
+ public static class ProcessManager
+ {
+
+ [DllImport("user32.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ private static extern bool SetForegroundWindow(IntPtr hWnd);
+
+ public static void SetRevitAsWindowOwner(this Window window)
+ {
+ if (null == window) { return; }
+ window.WindowStartupLocation = WindowStartupLocation.CenterScreen;
+ WindowInteropHelper helper = new WindowInteropHelper(window);
+ helper.Owner = GetActivateWindow();
+ window.Closing += SetActivateWindow;
+ }
+
+ private static void SetActivateWindow(object sender, CancelEventArgs e)
+ {
+ SetActivateWindow();
+ }
+
+ ///
+ /// Set process revert use revit
+ ///
+ ///
+ public static void SetActivateWindow()
+ {
+ IntPtr ptr = GetActivateWindow();
+ if (ptr != IntPtr.Zero)
+ {
+ SetForegroundWindow(ptr);
+ }
+ }
+
+ ///
+ /// return active windows is active
+ ///
+ ///
+ public static IntPtr GetActivateWindow()
+ {
+ return Process.GetCurrentProcess().MainWindowHandle;
+ }
+ }
+}
\ No newline at end of file
diff --git a/RevitPythonShell/Properties/launchSettings.json b/RevitPythonShell/Properties/launchSettings.json
index 977df04..1325e5c 100644
--- a/RevitPythonShell/Properties/launchSettings.json
+++ b/RevitPythonShell/Properties/launchSettings.json
@@ -43,6 +43,14 @@
"Revit 2021": {
"commandName": "Executable",
"executablePath": "%ProgramW6432%\\Autodesk\\Revit 2021\\Revit.exe"
+ } ,
+ "Revit 2022": {
+ "commandName": "Executable",
+ "executablePath": "%ProgramW6432%\\Autodesk\\Revit 2022\\Revit.exe"
+ } ,
+ "Revit 2023": {
+ "commandName": "Executable",
+ "executablePath": "%ProgramW6432%\\Autodesk\\Revit 2023\\Revit.exe"
}
}
}
\ No newline at end of file
diff --git a/RevitPythonShell/CommandLoaderBase.cs b/RevitPythonShell/RevitCommands/CommandLoaderBase.cs
similarity index 89%
rename from RevitPythonShell/CommandLoaderBase.cs
rename to RevitPythonShell/RevitCommands/CommandLoaderBase.cs
index fd993ab..1efc199 100644
--- a/RevitPythonShell/CommandLoaderBase.cs
+++ b/RevitPythonShell/RevitCommands/CommandLoaderBase.cs
@@ -1,65 +1,63 @@
-using System;
-using System.IO;
-using Autodesk.Revit;
-using Autodesk.Revit.UI;
-using Autodesk.Revit.DB;
-using Autodesk.Revit.Attributes;
-using RevitPythonShell.RpsRuntime;
-
-namespace RevitPythonShell
-{
- ///
- /// Starts up a ScriptOutput window for a given canned command.
- ///
- /// It is expected that this will be inherited by dynamic types that have the field
- /// _scriptSource set to point to a python file that will be executed in the constructor.
- ///
- [Regeneration(RegenerationOption.Manual)]
- [Transaction(TransactionMode.Manual)]
- public abstract class CommandLoaderBase : IExternalCommand
- {
- protected string _scriptSource = "";
-
- public CommandLoaderBase(string scriptSource)
- {
- _scriptSource = scriptSource;
- }
-
- ///
- /// Overload this method to implement an external command within Revit.
- ///
- ///
- /// The result indicates if the execution fails, succeeds, or was canceled by user. If it does not
- /// succeed, Revit will undo any changes made by the external command.
- ///
- /// An ExternalCommandData object which contains reference to Application and View
- /// needed by external command.Error message can be returned by external command. This will be displayed only if the command status
- /// was "Failed". There is a limit of 1023 characters for this message; strings longer than this will be truncated.Element set indicating problem elements to display in the failure dialog. This will be used
- /// only if the command status was "Failed".
- public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
- {
- // FIXME: somehow fetch back message after script execution...
- var executor = new ScriptExecutor(RevitPythonShellApplication.GetConfig(), commandData, message, elements);
-
- string source;
- using (var reader = File.OpenText(_scriptSource))
- {
- source = reader.ReadToEnd();
- }
-
- var result = executor.ExecuteScript(source, _scriptSource);
- message = executor.Message;
- switch (result)
- {
- case (int)Result.Succeeded:
- return Result.Succeeded;
- case (int)Result.Cancelled:
- return Result.Cancelled;
- case (int)Result.Failed:
- return Result.Failed;
- default:
- return Result.Succeeded;
- }
- }
- }
-}
+using System.IO;
+using Autodesk.Revit.Attributes;
+using Autodesk.Revit.DB;
+using Autodesk.Revit.UI;
+using RpsRuntime;
+
+namespace RevitPythonShell.RevitCommands
+{
+ ///
+ /// Starts up a ScriptOutput window for a given canned command.
+ ///
+ /// It is expected that this will be inherited by dynamic types that have the field
+ /// _scriptSource set to point to a python file that will be executed in the constructor.
+ ///
+ [Regeneration(RegenerationOption.Manual)]
+ [Transaction(TransactionMode.Manual)]
+ public abstract class CommandLoaderBase : IExternalCommand
+ {
+ protected string _scriptSource = "";
+
+ public CommandLoaderBase(string scriptSource)
+ {
+ _scriptSource = scriptSource;
+ }
+
+ ///
+ /// Overload this method to implement an external command within Revit.
+ ///
+ ///
+ /// The result indicates if the execution fails, succeeds, or was canceled by user. If it does not
+ /// succeed, Revit will undo any changes made by the external command.
+ ///
+ /// An ExternalCommandData object which contains reference to Application and View
+ /// needed by external command.Error message can be returned by external command. This will be displayed only if the command status
+ /// was "Failed". There is a limit of 1023 characters for this message; strings longer than this will be truncated.Element set indicating problem elements to display in the failure dialog. This will be used
+ /// only if the command status was "Failed".
+ public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
+ {
+ // FIXME: somehow fetch back message after script execution...
+ var executor = new ScriptExecutor(App.GetConfig(), commandData, message, elements);
+
+ string source;
+ using (var reader = File.OpenText(_scriptSource))
+ {
+ source = reader.ReadToEnd();
+ }
+
+ var result = executor.ExecuteScript(source, _scriptSource);
+ message = executor.Message;
+ switch (result)
+ {
+ case (int)Result.Succeeded:
+ return Result.Succeeded;
+ case (int)Result.Cancelled:
+ return Result.Cancelled;
+ case (int)Result.Failed:
+ return Result.Failed;
+ default:
+ return Result.Succeeded;
+ }
+ }
+ }
+}
diff --git a/RevitPythonShell/RevitCommands/ConfigureCommand.cs b/RevitPythonShell/RevitCommands/ConfigureCommand.cs
index 15eb015..5ebb07b 100644
--- a/RevitPythonShell/RevitCommands/ConfigureCommand.cs
+++ b/RevitPythonShell/RevitCommands/ConfigureCommand.cs
@@ -1,14 +1,10 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using Autodesk.Revit;
-using Autodesk.Revit.UI;
-using Autodesk.Revit.DB;
+using System.Windows.Forms;
using Autodesk.Revit.Attributes;
-using System.Windows.Forms;
+using Autodesk.Revit.DB;
+using Autodesk.Revit.UI;
+using RevitPythonShell.Views;
-namespace RevitPythonShell
+namespace RevitPythonShell.RevitCommands
{
///
/// Open the configuration dialog.
@@ -20,6 +16,7 @@ class ConfigureCommand: IExternalCommand
public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
{
var dialog = new ConfigureCommandsForm();
+ dialog.StartPosition = FormStartPosition.CenterScreen;
dialog.ShowDialog();
MessageBox.Show("Restart Revit to see changes to the commands in the Ribbon", "Configure RevitPythonShell", MessageBoxButtons.OK, MessageBoxIcon.Information);
diff --git a/RevitPythonShell/RevitCommands/DeployRpsAddinCommand.cs b/RevitPythonShell/RevitCommands/DeployRpsAddinCommand.cs
index 35afa71..77d7c27 100644
--- a/RevitPythonShell/RevitCommands/DeployRpsAddinCommand.cs
+++ b/RevitPythonShell/RevitCommands/DeployRpsAddinCommand.cs
@@ -1,18 +1,16 @@
using System;
using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using Autodesk.Revit.UI;
using System.IO;
+using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
+using System.Windows.Forms;
using System.Xml.Linq;
using Autodesk.Revit.Attributes;
-using System.Windows.Forms;
-using RevitPythonShell.RpsRuntime;
-using System.Security.AccessControl;
+using Autodesk.Revit.UI;
+using RpsRuntime;
-namespace RevitPythonShell
+namespace RevitPythonShell.RevitCommands
{
///
/// Ask the user for an RpsAddin xml file. Create a subfolder
diff --git a/RevitPythonShell/RevitCommands/IronPythonConsoleCommand.cs b/RevitPythonShell/RevitCommands/IronPythonConsoleCommand.cs
index 6995f9a..4a2fff0 100644
--- a/RevitPythonShell/RevitCommands/IronPythonConsoleCommand.cs
+++ b/RevitPythonShell/RevitCommands/IronPythonConsoleCommand.cs
@@ -1,17 +1,16 @@
using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
+using System.Threading;
+using System.Windows;
+using System.Windows.Threading;
using Autodesk.Revit.Attributes;
-using Autodesk.Revit.UI;
using Autodesk.Revit.DB;
-using System.Diagnostics;
+using Autodesk.Revit.UI;
using Microsoft.Scripting;
-using System.Threading;
-using System.Windows.Threading;
-using RevitPythonShell.RpsRuntime;
+using RevitPythonShell.Helpers;
+using RevitPythonShell.Views;
+using RpsRuntime;
-namespace RevitPythonShell
+namespace RevitPythonShell.RevitCommands
{
///
/// Start an interactive shell in a modal window.
@@ -32,13 +31,13 @@ public Result Execute(ExternalCommandData commandData, ref string message, Eleme
{
// now that the console is created and initialized, the script scope should
// be accessible...
- new ScriptExecutor(RevitPythonShellApplication.GetConfig(), commandData, messageCopy, elements)
+ new ScriptExecutor(App.GetConfig(), commandData, messageCopy, elements)
.SetupEnvironment(host.Engine, host.Console.ScriptScope);
host.Console.ScriptScope.SetVariable("__window__", gui);
// run the initscript
- var initScript = RevitPythonShellApplication.GetInitScript();
+ var initScript = App.GetInitScript();
if (initScript != null)
{
var scriptSource = host.Engine.CreateScriptSourceFromString(initScript, SourceCodeKind.Statements);
@@ -78,6 +77,8 @@ public Result Execute(ExternalCommandData commandData, ref string message, Eleme
}
});
});
+ gui.WindowStartupLocation = WindowStartupLocation.CenterScreen;
+ gui.SetRevitAsWindowOwner();
gui.ShowDialog();
return Result.Succeeded;
}
diff --git a/RevitPythonShell/RevitCommands/NonModalConsoleCommand.cs b/RevitPythonShell/RevitCommands/NonModalConsoleCommand.cs
index 6f8b3ea..26e682c 100644
--- a/RevitPythonShell/RevitCommands/NonModalConsoleCommand.cs
+++ b/RevitPythonShell/RevitCommands/NonModalConsoleCommand.cs
@@ -1,20 +1,18 @@
using System;
using System.Collections.Generic;
-using System.Linq;
-using System.Text;
+using System.Diagnostics;
+using System.Threading;
+using System.Windows;
using Autodesk.Revit.Attributes;
-using Autodesk.Revit.UI;
using Autodesk.Revit.DB;
-using System.Diagnostics;
+using Autodesk.Revit.UI;
using Microsoft.Scripting;
-using System.Threading;
-using System.Windows.Threading;
-using RevitPythonShell.RpsRuntime;
-using System.Threading.Tasks;
-using IronPython.Runtime;
using Microsoft.Scripting.Hosting;
+using RevitPythonShell.Helpers;
+using RevitPythonShell.Views;
+using RpsRuntime;
-namespace RevitPythonShell
+namespace RevitPythonShell.RevitCommands
{
///
/// An object of this class is instantiated every time the user clicks on the
@@ -37,13 +35,13 @@ public Result Execute(ExternalCommandData commandData, ref string message, Eleme
{
// now that the console is created and initialized, the script scope should
// be accessible...
- new ScriptExecutor(RevitPythonShellApplication.GetConfig(), commandData, messageCopy, elements)
+ new ScriptExecutor(App.GetConfig(), commandData, messageCopy, elements)
.SetupEnvironment(host.Engine, host.Console.ScriptScope);
host.Console.ScriptScope.SetVariable("__window__", gui);
// run the initscript
- var initScript = RevitPythonShellApplication.GetInitScript();
+ var initScript = App.GetInitScript();
if (initScript != null)
{
var scriptSource = host.Engine.CreateScriptSourceFromString(initScript, SourceCodeKind.Statements);
@@ -71,8 +69,9 @@ public Result Execute(ExternalCommandData commandData, ref string message, Eleme
commandCompletedEvent.WaitOne();
});
});
- gui.Topmost = true;
gui.Title = gui.Title.Replace("RevitPythonShell", "RevitPythonShell (non-modal)");
+ gui.WindowStartupLocation = WindowStartupLocation.CenterScreen;
+ gui.SetRevitAsWindowOwner();
gui.Show();
return Result.Succeeded;
}
diff --git a/RevitPythonShell/RevitPythonShell.addin b/RevitPythonShell/RevitPythonShell.addin
new file mode 100644
index 0000000..30e196d
--- /dev/null
+++ b/RevitPythonShell/RevitPythonShell.addin
@@ -0,0 +1,11 @@
+
+
+
+ RevitPythonShell.App
+ 3a7a1d24-51ed-462b-949f-1ddcca12008d
+ RevitPythonShell
+ RevitPythonShell/RevitPythonShell.dll
+ 3a7a1d24-51ed-462b-949f-1ddcca12008d
+ RIPS, RIPS,
+
+
diff --git a/RevitPythonShell/RevitPythonShell.csproj b/RevitPythonShell/RevitPythonShell.csproj
index 9e23b1d..9773421 100644
--- a/RevitPythonShell/RevitPythonShell.csproj
+++ b/RevitPythonShell/RevitPythonShell.csproj
@@ -1,132 +1,65 @@
-
- Debug;Debug One;Release
-
-
-
-
- net40;net45;net451;net452;net46;net47;net471;net48
+ Debug;Release
win
true
true
+ net48
+ latest
+ x64
+ 3a7a1d24-51ed-462b-949f-1ddcca12008d
+ RevitPythonShell
+ RIPS
+ Revit Python Shell addin for Revit
+ false
+ Debug R22;Debug R23
+ $(Configurations);Release R18;Release R19;Release R20;Release R21;Release R22;Release R23
-
-
-
- net48
-
-
-
- 2014
-
-
- 2015
-
-
- 2016
+
+ true
+ full
+ $(DefineConstants);DEBUG
-
- 2017
+
+ true
+ none
+ $(DefineConstants);RELEASE
-
+
2018
+ $(DefineConstants);R18
-
+
2019
+ $(DefineConstants);R19
-
+
2020
+ $(DefineConstants);R20
-
+
2021
+ $(DefineConstants);R21
-
+
2022
+ $(DefineConstants);R22
+
+
+ 2023
+ $(DefineConstants);R23
-
- x64
- x64
- None
-
-
- {351668CC-8477-4fbf-BFE3-5F1006E4DB1F}
-
-
- false
- false
-
-
- REVIT$(RevitVersion);WINFORMS
- $(DefineConstants)
-
-
- false
-
-
+ $(RevitVersion)
+ true
false
- .\bin\$(Configuration)\$(RevitVersion)
- 3a7a1d24-51ed-462b-949f-1ddcca12008d
- RevitPythonShell
- RIPS
- Revit Python Shell addin for Revit
-
-
-
- TRACE;REVIT2020;WINFORMS;DEBUG
- full
- .\bin\$(Configuration)\$(RevitVersion)
-
-
-
- false
+ The RevitPythonShell adds an IronPython interpreter to Autodesk Revit and Vasari.
+ true
+ true
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
..\RequiredLibraries\IronPython.dll
@@ -144,7 +77,6 @@
..\RequiredLibraries\Microsoft.Scripting.Metadata.dll
-
@@ -163,7 +95,8 @@
-
+
+
@@ -184,7 +117,7 @@
True
Resources.resx
-
+
@@ -196,6 +129,7 @@
+
MSDataSetGenerator
AddinTemplate.Designer.cs
@@ -215,14 +149,10 @@
-
- PreserveNewest
-
+
-
- PreserveNewest
-
+
@@ -235,10 +165,9 @@
-
+
Designer
- PreserveNewest
-
+
@@ -259,32 +188,6 @@
all
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- $(SolutionName)\bin\$(Configuration)\$(RevitVersion)\
-
-
-
-
-
-
-
-
-
-
@@ -297,14 +200,11 @@
-
-
-
+ ]]>
-
@@ -316,28 +216,29 @@
-
-
-
+ ]]>
-
-
-
-
+
+
-
+
+
+
-
-
+
+ bin\AddIn $(RevitVersion) $(Configuration)\
+ $(RootDir)$(AssemblyName)\
+
-
-
-
-
-
-
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/RevitPythonShell/Views/CompletionToolTip.cs b/RevitPythonShell/Views/CompletionToolTip.cs
index d62ddee..acdd31c 100644
--- a/RevitPythonShell/Views/CompletionToolTip.cs
+++ b/RevitPythonShell/Views/CompletionToolTip.cs
@@ -1,11 +1,10 @@
using System;
using System.Collections.Generic;
+using System.Drawing;
using System.Linq;
-using System.Text;
using System.Windows.Forms;
-using System.Drawing;
-namespace RevitPythonShell
+namespace RevitPythonShell.Views
{
///
/// Display a listbox with a list of completions for a given string.
diff --git a/RevitPythonShell/Views/ConfigureCommandsForm.Designer.cs b/RevitPythonShell/Views/ConfigureCommandsForm.Designer.cs
index ba70253..01865e2 100644
--- a/RevitPythonShell/Views/ConfigureCommandsForm.Designer.cs
+++ b/RevitPythonShell/Views/ConfigureCommandsForm.Designer.cs
@@ -1,4 +1,4 @@
-namespace RevitPythonShell
+namespace RevitPythonShell.Views
{
partial class ConfigureCommandsForm
{
diff --git a/RevitPythonShell/Views/ConfigureCommandsForm.cs b/RevitPythonShell/Views/ConfigureCommandsForm.cs
index 65f0319..97188ec 100644
--- a/RevitPythonShell/Views/ConfigureCommandsForm.cs
+++ b/RevitPythonShell/Views/ConfigureCommandsForm.cs
@@ -1,14 +1,10 @@
using System;
using System.Collections.Generic;
-using System.ComponentModel;
-using System.Data;
-using System.Drawing;
+using System.IO;
using System.Linq;
-using System.Text;
using System.Windows.Forms;
-using System.IO;
-namespace RevitPythonShell
+namespace RevitPythonShell.Views
{
public partial class ConfigureCommandsForm : Form
{
@@ -35,21 +31,21 @@ private void btnCancel_Click(object sender, EventArgs e)
///
private void ConfigureCommandsForm_Load(object sender, EventArgs e)
{
- _commands = RevitPythonShellApplication.GetCommands(
- RevitPythonShellApplication.GetSettings()).ToList();
+ _commands = App.GetCommands(
+ App.GetSettings()).ToList();
lstCommands.DataSource = _commands;
- _searchPaths = RevitPythonShellApplication.GetConfig().GetSearchPaths().ToList();
+ _searchPaths = App.GetConfig().GetSearchPaths().ToList();
lstSearchPaths.DataSource = _searchPaths;
- _variables = RevitPythonShellApplication.GetConfig().GetVariables().AsEnumerable().ToList();
+ _variables = App.GetConfig().GetVariables().AsEnumerable().ToList();
lstVariables.DataSource = _variables;
lstVariables.DisplayMember = "Key";
- string initScriptPath = RevitPythonShellApplication.GetInitScriptPath();
+ string initScriptPath = App.GetInitScriptPath();
txtInitScript.Text = initScriptPath;
- string startupScriptPath = RevitPythonShellApplication.GetStartupScriptPath();
+ string startupScriptPath = App.GetStartupScriptPath();
txtStartupScript.Text = startupScriptPath;
}
@@ -219,7 +215,7 @@ private void btnCommandMoveDown_Click(object sender, EventArgs e)
///
private void btnCommandSave_Click(object sender, EventArgs e)
{
- RevitPythonShellApplication.WriteSettings(_commands, _searchPaths, _variables, txtInitScript.Text, txtStartupScript.Text);
+ App.WriteSettings(_commands, _searchPaths, _variables, txtInitScript.Text, txtStartupScript.Text);
Close();
}
diff --git a/RevitPythonShell/Views/ConsoleOptions.cs b/RevitPythonShell/Views/ConsoleOptions.cs
index 52f7741..425fdeb 100644
--- a/RevitPythonShell/Views/ConsoleOptions.cs
+++ b/RevitPythonShell/Views/ConsoleOptions.cs
@@ -1,15 +1,11 @@
// Copyright (c) 2010 Joe Moorhouse
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
using System.ComponentModel;
-using ICSharpCode.AvalonEdit;
using System.Windows.Media;
+using ICSharpCode.AvalonEdit;
using PythonConsoleControl;
-namespace RevitPythonShell
+namespace RevitPythonShell.Views
{
public class ConsoleOptions
{
diff --git a/RevitPythonShell/Views/IronPythonConsole.xaml b/RevitPythonShell/Views/IronPythonConsole.xaml
index fdbecfc..4cbf120 100644
--- a/RevitPythonShell/Views/IronPythonConsole.xaml
+++ b/RevitPythonShell/Views/IronPythonConsole.xaml
@@ -1,29 +1,36 @@
-
-
-
-
-
+
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
+
-
+
-
-
-
+
+
+
-
-
+
+
-
-
+
+
-
+
# IronPython Pad. Write code snippets here and F5 to run.
+ FontFamily="Consolas"
+ FontSize="10pt"
+ GotFocus="textEditor_GotFocus"
+ Name="textEditor">
+ # IronPython Pad. Write code snippets here and F5 to run.
-
+
diff --git a/RevitPythonShell/Views/IronPythonConsole.xaml.cs b/RevitPythonShell/Views/IronPythonConsole.xaml.cs
index f9023b7..c20b276 100644
--- a/RevitPythonShell/Views/IronPythonConsole.xaml.cs
+++ b/RevitPythonShell/Views/IronPythonConsole.xaml.cs
@@ -1,14 +1,14 @@
-using ICSharpCode.AvalonEdit;
-using ICSharpCode.AvalonEdit.Highlighting;
-using Microsoft.Win32;
-using System;
+using System;
using System.IO;
using System.Reflection;
using System.Windows;
using System.Windows.Input;
using System.Xml;
+using ICSharpCode.AvalonEdit;
+using ICSharpCode.AvalonEdit.Highlighting;
+using Microsoft.Win32;
-namespace RevitPythonShell
+namespace RevitPythonShell.Views
{
///
/// Interaction logic for IronPythonConsole.xaml
diff --git a/RpsRuntime/ExternalCommandAssemblyBuilder.cs b/RpsRuntime/ExternalCommandAssemblyBuilder.cs
index 8a0e852..45689b2 100644
--- a/RpsRuntime/ExternalCommandAssemblyBuilder.cs
+++ b/RpsRuntime/ExternalCommandAssemblyBuilder.cs
@@ -1,14 +1,11 @@
-using Autodesk.Revit.Attributes;
-using System;
+using System;
using System.Collections.Generic;
using System.IO;
-using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
-using System.Text;
-using System.Xml.Linq;
+using Autodesk.Revit.Attributes;
-namespace RevitPythonShell.RpsRuntime
+namespace RpsRuntime
{
///
/// The ExternalCommandAssemblyBuilder creates an assembly (.net dll) for
diff --git a/RpsRuntime/IRpsConfig.cs b/RpsRuntime/IRpsConfig.cs
index 4d5fb4c..9a2f385 100644
--- a/RpsRuntime/IRpsConfig.cs
+++ b/RpsRuntime/IRpsConfig.cs
@@ -1,9 +1,6 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
+using System.Collections.Generic;
-namespace RevitPythonShell.RpsRuntime
+namespace RpsRuntime
{
public interface IRpsConfig
{
diff --git a/RpsRuntime/RpsConfig.cs b/RpsRuntime/RpsConfig.cs
index fa58f82..eb4076a 100644
--- a/RpsRuntime/RpsConfig.cs
+++ b/RpsRuntime/RpsConfig.cs
@@ -1,10 +1,7 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
+using System.Collections.Generic;
using System.Xml.Linq;
-namespace RevitPythonShell.RpsRuntime
+namespace RpsRuntime
{
///
/// Provides access functions to those parts of the RevitPythonShell.xml file
diff --git a/RpsRuntime/RpsExternalApplicationBase.cs b/RpsRuntime/RpsExternalApplicationBase.cs
index 54aaf9c..25aa72b 100644
--- a/RpsRuntime/RpsExternalApplicationBase.cs
+++ b/RpsRuntime/RpsExternalApplicationBase.cs
@@ -1,15 +1,14 @@
using System;
using System.Collections.Generic;
+using System.IO;
using System.Linq;
-using System.Text;
-using Autodesk.Revit.UI;
using System.Reflection;
-using System.IO;
-using System.Xml.Linq;
-using System.Windows.Media.Imaging;
using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Xml.Linq;
+using Autodesk.Revit.UI;
-namespace RevitPythonShell.RpsRuntime
+namespace RpsRuntime
{
///
/// A base class for RpsAddins to inherit from.
diff --git a/RpsRuntime/RpsExternalCommandBase.cs b/RpsRuntime/RpsExternalCommandBase.cs
index 40d7c8d..5578797 100644
--- a/RpsRuntime/RpsExternalCommandBase.cs
+++ b/RpsRuntime/RpsExternalCommandBase.cs
@@ -1,12 +1,9 @@
using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using Autodesk.Revit.UI;
using System.IO;
using System.Xml.Linq;
+using Autodesk.Revit.UI;
-namespace RevitPythonShell.RpsRuntime
+namespace RpsRuntime
{
///
/// An abstract base class for ExternalCommand instances created by the DeployRpsAddin projects.
diff --git a/RpsRuntime/RpsExternalCommandScriptBase.cs b/RpsRuntime/RpsExternalCommandScriptBase.cs
index 90507eb..88c9ea5 100644
--- a/RpsRuntime/RpsExternalCommandScriptBase.cs
+++ b/RpsRuntime/RpsExternalCommandScriptBase.cs
@@ -1,14 +1,11 @@
-using Autodesk.Revit.Attributes;
-using Autodesk.Revit.DB;
-using Autodesk.Revit.UI;
-using System;
-using System.Collections.Generic;
+using System;
using System.IO;
-using System.Linq;
using System.Xml.Linq;
-using System.Text;
+using Autodesk.Revit.Attributes;
+using Autodesk.Revit.DB;
+using Autodesk.Revit.UI;
-namespace RevitPythonShell.RpsRuntime
+namespace RpsRuntime
{
///
/// This class is very much like the RpsExternalCommandBase, but instead of looking for the
diff --git a/RpsRuntime/RpsRuntime.csproj b/RpsRuntime/RpsRuntime.csproj
index 119b850..40ea59f 100644
--- a/RpsRuntime/RpsRuntime.csproj
+++ b/RpsRuntime/RpsRuntime.csproj
@@ -1,203 +1,132 @@
-
-
- Debug;Debug One;Release
-
-
-
-
- net40;net45;net451;net452;net46;net47;net471;net48
- win
-
-
-
-
- net48
-
-
-
- 2014
-
-
- 2015
-
-
- 2016
-
-
- 2017
-
-
- 2018
-
-
- 2019
-
-
- 2020
-
-
- 2021
-
-
- 2022
-
-
-
-
- x64
- x64
- None
-
-
- {351668CC-8477-4fbf-BFE3-5F1006E4DB1F}
-
-
- false
- false
-
-
- REVIT$(RevitVersion);WINFORMS
- $(DefineConstants)
-
-
- false
-
-
- false
- ..\bin\$(Configuration)\$(RevitVersion)
-
-
-
- $(DefineConstants);DEBUG
- full
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+ Debug;Release
+ net48
+ latest
+ false
+ false
+ x64
+ Debug R22;Debug R23
+ $(Configurations);Release R18;Release R19;Release R20;Release R21;Release R22;Release R23
+
+
+ true
+ full
+ $(DefineConstants);DEBUG
+
+
+ true
+ none
+ $(DefineConstants);RELEASE
+
+
+ 2018
+ $(DefineConstants);R18
+
+
+ 2019
+ $(DefineConstants);R19
+
+
+ 2020
+ $(DefineConstants);R20
+
+
+ 2021
+ $(DefineConstants);R21
+
+
+ 2022
+ $(DefineConstants);R22
+
+
+ 2023
+ $(DefineConstants);R23
+
+
+ $(RevitVersion)
+ true
+ false
+ A Project Support for developer in revit
+ true
+ true
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+ ..\RequiredLibraries\IronPython.dll
+
+
+ ..\RequiredLibraries\IronPython.Modules.dll
+
+
+ ..\RequiredLibraries\Microsoft.Dynamic.dll
+
+
+ ..\RequiredLibraries\Microsoft.Scripting.dll
+
+
+ ..\RequiredLibraries\Microsoft.Scripting.Metadata.dll
+
+
+ ..\RequiredLibraries\Microsoft.CSharp.dll
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Form
+
+
+ ScriptOutput.cs
+
+
+
+
+
+
+ ScriptOutput.cs
+ Designer
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
- ..\RequiredLibraries\IronPython.dll
-
-
- ..\RequiredLibraries\IronPython.Modules.dll
-
-
- ..\RequiredLibraries\Microsoft.Dynamic.dll
-
-
- ..\RequiredLibraries\Microsoft.Scripting.dll
-
-
- ..\RequiredLibraries\Microsoft.Scripting.Metadata.dll
-
-
- ..\RequiredLibraries\Microsoft.CSharp.dll
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Form
-
-
- ScriptOutput.cs
-
-
-
-
-
-
- ScriptOutput.cs
- Designer
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/RpsRuntime/ScriptExecutor.cs b/RpsRuntime/ScriptExecutor.cs
index ca6b766..d39a76c 100644
--- a/RpsRuntime/ScriptExecutor.cs
+++ b/RpsRuntime/ScriptExecutor.cs
@@ -1,15 +1,14 @@
using System;
+using System.Collections.Generic;
using System.Linq;
using System.Text;
-using Autodesk.Revit;
+using Autodesk.Revit.DB;
+using Autodesk.Revit.UI;
using IronPython.Runtime.Exceptions;
using Microsoft.Scripting;
using Microsoft.Scripting.Hosting;
-using Autodesk.Revit.UI;
-using Autodesk.Revit.DB;
-using System.Collections.Generic;
-namespace RevitPythonShell.RpsRuntime
+namespace RpsRuntime
{
///
/// Executes a script scripts
@@ -181,7 +180,7 @@ public void SetupEnvironment(ScriptEngine engine, ScriptScope scope)
engine.Runtime.LoadAssembly(typeof(Autodesk.Revit.UI.TaskDialog).Assembly);
// also, allow access to the RPS internals
- engine.Runtime.LoadAssembly(typeof(RevitPythonShell.RpsRuntime.ScriptExecutor).Assembly);
+ engine.Runtime.LoadAssembly(typeof(ScriptExecutor).Assembly);
}
///
diff --git a/RpsRuntime/ScriptOutput.Designer.cs b/RpsRuntime/ScriptOutput.Designer.cs
index 7dab383..01195cf 100644
--- a/RpsRuntime/ScriptOutput.Designer.cs
+++ b/RpsRuntime/ScriptOutput.Designer.cs
@@ -1,4 +1,4 @@
-namespace RevitPythonShell.RpsRuntime
+namespace RpsRuntime
{
partial class ScriptOutput
{
diff --git a/RpsRuntime/ScriptOutput.cs b/RpsRuntime/ScriptOutput.cs
index 777362e..08f1a7a 100644
--- a/RpsRuntime/ScriptOutput.cs
+++ b/RpsRuntime/ScriptOutput.cs
@@ -1,7 +1,6 @@
-using System;
-using System.Windows.Forms;
+using System.Windows.Forms;
-namespace RevitPythonShell.RpsRuntime
+namespace RpsRuntime
{
public partial class ScriptOutput : Form
{
diff --git a/RpsRuntime/ScriptOutputStream.cs b/RpsRuntime/ScriptOutputStream.cs
index 6cb5d83..7705723 100644
--- a/RpsRuntime/ScriptOutputStream.cs
+++ b/RpsRuntime/ScriptOutputStream.cs
@@ -5,10 +5,9 @@
using System.Text;
using System.Threading;
using System.Windows.Forms;
-using IronPython.Runtime.Exceptions;
using Microsoft.Scripting.Hosting;
-namespace RevitPythonShell.RpsRuntime
+namespace RpsRuntime
{
///
/// A stream to write output to...
diff --git a/RpsRuntime/SettingsDictionary.cs b/RpsRuntime/SettingsDictionary.cs
index 6d5b6ac..40deca8 100644
--- a/RpsRuntime/SettingsDictionary.cs
+++ b/RpsRuntime/SettingsDictionary.cs
@@ -1,10 +1,8 @@
-using System;
-using System.Collections.Generic;
+using System.Collections.Generic;
using System.Linq;
-using System.Text;
using System.Xml.Linq;
-namespace RevitPythonShell.RpsRuntime
+namespace RpsRuntime
{
///
/// A subclass of Dictionary, that writes changes back to a settings xml file.
diff --git a/build/.editorconfig b/build/.editorconfig
new file mode 100644
index 0000000..133dbc8
--- /dev/null
+++ b/build/.editorconfig
@@ -0,0 +1,15 @@
+# noinspection EditorConfigKeyCorrectness
+[*.cs]
+dotnet_style_qualification_for_field = false:warning
+dotnet_style_qualification_for_property = false:warning
+dotnet_style_qualification_for_method = false:warning
+dotnet_style_qualification_for_event = false:warning
+dotnet_style_require_accessibility_modifiers = never:warning
+
+csharp_style_expression_bodied_methods = true:silent
+csharp_style_expression_bodied_properties = true:warning
+csharp_style_expression_bodied_indexers = true:warning
+csharp_style_expression_bodied_accessors = true:warning
+
+resharper_check_namespace_highlighting = none
+resharper_class_never_instantiated_global_highlighting = none
diff --git a/build/Build.Clean.cs b/build/Build.Clean.cs
new file mode 100644
index 0000000..cc881ae
--- /dev/null
+++ b/build/Build.Clean.cs
@@ -0,0 +1,21 @@
+using Nuke.Common;
+using Nuke.Common.IO;
+using Nuke.Common.Utilities.Collections;
+using static Nuke.Common.IO.FileSystemTasks;
+
+internal partial class Build
+{
+ private Target Cleaning => _ => _
+ .Executes(() =>
+ {
+ EnsureCleanDirectory(ArtifactsDirectory);
+
+ if (IsServerBuild) return;
+ foreach (var projectName in Projects)
+ {
+ var project = BuilderExtensions.GetProject(Solution, projectName);
+ var binDirectory = (AbsolutePath)new DirectoryInfo(project.GetBinDirectory()).FullName;
+ binDirectory.GlobDirectories($"{AddInBinPrefix}*", "Release*").ForEach(DeleteDirectory);
+ }
+ });
+}
\ No newline at end of file
diff --git a/build/Build.Compile.cs b/build/Build.Compile.cs
new file mode 100644
index 0000000..38b297e
--- /dev/null
+++ b/build/Build.Compile.cs
@@ -0,0 +1,24 @@
+using Nuke.Common;
+using Nuke.Common.Tooling;
+using Nuke.Common.Tools.MSBuild;
+using static Nuke.Common.Tools.MSBuild.MSBuildTasks;
+
+internal partial class Build
+{
+ private Target Compile => _ => _
+ .TriggeredBy(Cleaning)
+ .Executes(() =>
+ {
+ var configurations = GetConfigurations(BuildConfiguration, InstallerConfiguration);
+ configurations.ForEach(configuration =>
+ {
+ MSBuild(s => s
+ .SetTargets("Rebuild")
+ .SetProcessToolPath(MsBuildPath.Value)
+ .SetConfiguration(configuration)
+ .SetVerbosity(MSBuildVerbosity.Minimal)
+ .DisableNodeReuse()
+ .EnableRestore());
+ });
+ });
+}
\ No newline at end of file
diff --git a/build/Build.GitHubRelease.cs b/build/Build.GitHubRelease.cs
new file mode 100644
index 0000000..34a13c0
--- /dev/null
+++ b/build/Build.GitHubRelease.cs
@@ -0,0 +1,141 @@
+using Nuke.Common;
+using Nuke.Common.Git;
+using Nuke.Common.Tools.GitHub;
+using Nuke.Common.Tools.GitVersion;
+using Octokit;
+using Serilog;
+using System.Text;
+using System.Text.RegularExpressions;
+
+internal partial class Build
+{
+ [GitVersion(NoFetch = true)] private readonly GitVersion GitVersion;
+ [Parameter] private string GitHubToken { get; set; }
+ private readonly Regex VersionRegex = new(@"(\d+\.)+\d+", RegexOptions.Compiled);
+
+ private Target PublishGitHubRelease => _ => _
+ .TriggeredBy(CreateInstaller)
+ .Requires(() => GitHubToken)
+ .Requires(() => GitRepository)
+ .Requires(() => GitVersion)
+ .OnlyWhenStatic(() => GitRepository.IsOnMainOrMasterBranch())
+ .OnlyWhenStatic(() => IsServerBuild)
+ .Executes(() =>
+ {
+ GitHubTasks.GitHubClient = new GitHubClient(new ProductHeaderValue(Solution.Name))
+ {
+ Credentials = new Credentials(GitHubToken)
+ };
+
+ var gitHubName = GitRepository.GetGitHubName();
+ var gitHubOwner = GitRepository.GetGitHubOwner();
+ var artifacts = Directory.GetFiles(ArtifactsDirectory, "*");
+ var version = GetProductVersion(artifacts);
+
+ CheckTags(gitHubOwner, gitHubName, version);
+ Log.Information("Detected Tag: {Version}", version);
+
+ var newRelease = new NewRelease(version)
+ {
+ Name = version,
+ Body = CreateChangelog(version),
+ Draft = true,
+ TargetCommitish = GitVersion.Sha
+ };
+
+ var draft = CreatedDraft(gitHubOwner, gitHubName, newRelease);
+ UploadArtifacts(draft, artifacts);
+ ReleaseDraft(gitHubOwner, gitHubName, draft);
+ });
+
+ private string CreateChangelog(string version)
+ {
+ if (!File.Exists(ChangeLogPath))
+ {
+ Log.Warning("Can't find changelog file: {Log}", ChangeLogPath);
+ return string.Empty;
+ }
+
+ Log.Information("Detected Changelog: {Path}", ChangeLogPath);
+
+ var logBuilder = new StringBuilder();
+ var changelogLineRegex = new Regex($@"^.*({version})\S*\s?");
+ const string nextRecordSymbol = "- ";
+
+ foreach (var line in File.ReadLines(ChangeLogPath))
+ {
+ if (logBuilder.Length > 0)
+ {
+ if (line.StartsWith(nextRecordSymbol)) break;
+ logBuilder.AppendLine(line);
+ continue;
+ }
+
+ if (!changelogLineRegex.Match(line).Success) continue;
+ var truncatedLine = changelogLineRegex.Replace(line, string.Empty);
+ logBuilder.AppendLine(truncatedLine);
+ }
+
+ if (logBuilder.Length == 0) Log.Warning("There is no version entry in the changelog: {Version}", version);
+ return logBuilder.ToString();
+ }
+
+ private static void CheckTags(string gitHubOwner, string gitHubName, string version)
+ {
+ var gitHubTags = GitHubTasks.GitHubClient.Repository
+ .GetAllTags(gitHubOwner, gitHubName)
+ .Result;
+
+ if (gitHubTags.Select(tag => tag.Name).Contains(version)) throw new ArgumentException($"The repository already contains a Release with the tag: {version}");
+ }
+
+ private string GetProductVersion(IEnumerable artifacts)
+ {
+ var stringVersion = string.Empty;
+ var doubleVersion = 0d;
+ foreach (var file in artifacts)
+ {
+ var fileInfo = new FileInfo(file);
+ var match = VersionRegex.Match(fileInfo.Name);
+ if (!match.Success) continue;
+ var version = match.Value;
+ var parsedValue = double.Parse(version.Replace(".", ""));
+ if (parsedValue > doubleVersion)
+ {
+ doubleVersion = parsedValue;
+ stringVersion = version;
+ }
+ }
+
+ if (stringVersion.Equals(string.Empty)) throw new ArgumentException("Could not determine product version from artifacts.");
+
+ return stringVersion;
+ }
+
+ private static void UploadArtifacts(Release createdRelease, IEnumerable artifacts)
+ {
+ foreach (var file in artifacts)
+ {
+ var releaseAssetUpload = new ReleaseAssetUpload
+ {
+ ContentType = "application/x-binary",
+ FileName = Path.GetFileName(file),
+ RawData = File.OpenRead(file)
+ };
+ var _ = GitHubTasks.GitHubClient.Repository.Release.UploadAsset(createdRelease, releaseAssetUpload).Result;
+ Log.Information("Added artifact: {Path}", file);
+ }
+ }
+
+ private static Release CreatedDraft(string gitHubOwner, string gitHubName, NewRelease newRelease) =>
+ GitHubTasks.GitHubClient.Repository.Release
+ .Create(gitHubOwner, gitHubName, newRelease)
+ .Result;
+
+ private static void ReleaseDraft(string gitHubOwner, string gitHubName, Release draft)
+ {
+ var _ = GitHubTasks.GitHubClient.Repository.Release
+ .Edit(gitHubOwner, gitHubName, draft.Id, new ReleaseUpdate { Draft = false })
+ .Result;
+ }
+}
\ No newline at end of file
diff --git a/build/Build.Installer.cs b/build/Build.Installer.cs
new file mode 100644
index 0000000..6afadb5
--- /dev/null
+++ b/build/Build.Installer.cs
@@ -0,0 +1,75 @@
+using JetBrains.Annotations;
+using Nuke.Common;
+using Nuke.Common.Git;
+using Serilog;
+using System.Diagnostics;
+using System.Text;
+using System.Text.RegularExpressions;
+
+internal partial class Build
+{
+ private readonly Regex StreamRegex = new("'(.+?)'", RegexOptions.Compiled);
+
+ private Target CreateInstaller => _ => _
+ .TriggeredBy(Compile)
+ .OnlyWhenStatic(() => IsLocalBuild || GitRepository.IsOnMainOrMasterBranch())
+ .Executes(() =>
+ {
+ var installerProject = BuilderExtensions.GetProject(Solution, InstallerProject);
+ var buildDirectories = GetBuildDirectories();
+ var configurations = GetConfigurations(InstallerConfiguration);
+ foreach (var directoryGroup in buildDirectories)
+ {
+ var directories = directoryGroup.ToList();
+ var exeArguments = BuildExeArguments(directories.Select(info => info.FullName).ToList());
+ var exeFile = installerProject.GetExecutableFile(configurations, directories);
+ if (string.IsNullOrEmpty(exeFile))
+ {
+ Log.Warning("No installer executable was found for these packages:\n {Directories}", string.Join("\n", directories));
+ continue;
+ }
+
+ var proc = new Process();
+ proc.StartInfo.FileName = exeFile;
+ proc.StartInfo.Arguments = exeArguments;
+ proc.StartInfo.RedirectStandardOutput = true;
+ proc.Start();
+ while (!proc.StandardOutput.EndOfStream) ParseProcessOutput(proc.StandardOutput.ReadLine());
+ proc.WaitForExit();
+ if (proc.ExitCode != 0) throw new Exception("The installer creation failed.");
+ }
+ });
+
+ private void ParseProcessOutput([CanBeNull] string value)
+ {
+ if (value is null) return;
+ var matches = StreamRegex.Matches(value);
+ if (matches.Count > 0)
+ {
+ var parameters = matches.Select(match => match.Value
+ .Substring(1, match.Value.Length - 2))
+ .Cast