├── .gitignore
├── CodeListener.sln
├── CodeListener
├── CodeListener.csproj
├── CodeListenerCommand.cs
├── CodeListenerExecute.cs
├── CodeListenerPlugIn.cs
├── CodeListenerVersion.cs
├── EmbeddedResources
│ └── plugin-utility.ico
├── FeedbackSender.cs
├── Properties
│ └── AssemblyInfo.cs
├── ResetScriptEngine.cs
├── StopCodeListener.cs
└── packages.config
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.suo
8 | *.user
9 | *.userosscache
10 | *.sln.docstates
11 |
12 | # User-specific files (MonoDevelop/Xamarin Studio)
13 | *.userprefs
14 |
15 | # Build results
16 | [Dd]ebug/
17 | [Dd]ebugPublic/
18 | [Rr]elease/
19 | [Rr]eleases/
20 | x64/
21 | x86/
22 | bld/
23 | [Bb]in/
24 | [Oo]bj/
25 | [Ll]og/
26 |
27 | # Visual Studio 2015/2017 cache/options directory
28 | .vs/
29 | # Uncomment if you have tasks that create the project's static files in wwwroot
30 | #wwwroot/
31 |
32 | # Visual Studio 2017 auto generated files
33 | Generated\ Files/
34 |
35 | # MSTest test Results
36 | [Tt]est[Rr]esult*/
37 | [Bb]uild[Ll]og.*
38 |
39 | # NUNIT
40 | *.VisualState.xml
41 | TestResult.xml
42 |
43 | # Build Results of an ATL Project
44 | [Dd]ebugPS/
45 | [Rr]eleasePS/
46 | dlldata.c
47 |
48 | # Benchmark Results
49 | BenchmarkDotNet.Artifacts/
50 |
51 | # .NET Core
52 | project.lock.json
53 | project.fragment.lock.json
54 | artifacts/
55 | **/Properties/launchSettings.json
56 |
57 | # StyleCop
58 | StyleCopReport.xml
59 |
60 | # Files built by Visual Studio
61 | *_i.c
62 | *_p.c
63 | *_i.h
64 | *.ilk
65 | *.meta
66 | *.obj
67 | *.iobj
68 | *.pch
69 | *.pdb
70 | *.ipdb
71 | *.pgc
72 | *.pgd
73 | *.rsp
74 | *.sbr
75 | *.tlb
76 | *.tli
77 | *.tlh
78 | *.tmp
79 | *.tmp_proj
80 | *.log
81 | *.vspscc
82 | *.vssscc
83 | .builds
84 | *.pidb
85 | *.svclog
86 | *.scc
87 |
88 | # Chutzpah Test files
89 | _Chutzpah*
90 |
91 | # Visual C++ cache files
92 | ipch/
93 | *.aps
94 | *.ncb
95 | *.opendb
96 | *.opensdf
97 | *.sdf
98 | *.cachefile
99 | *.VC.db
100 | *.VC.VC.opendb
101 |
102 | # Visual Studio profiler
103 | *.psess
104 | *.vsp
105 | *.vspx
106 | *.sap
107 |
108 | # Visual Studio Trace Files
109 | *.e2e
110 |
111 | # TFS 2012 Local Workspace
112 | $tf/
113 |
114 | # Guidance Automation Toolkit
115 | *.gpState
116 |
117 | # ReSharper is a .NET coding add-in
118 | _ReSharper*/
119 | *.[Rr]e[Ss]harper
120 | *.DotSettings.user
121 |
122 | # JustCode is a .NET coding add-in
123 | .JustCode
124 |
125 | # TeamCity is a build add-in
126 | _TeamCity*
127 |
128 | # DotCover is a Code Coverage Tool
129 | *.dotCover
130 |
131 | # AxoCover is a Code Coverage Tool
132 | .axoCover/*
133 | !.axoCover/settings.json
134 |
135 | # Visual Studio code coverage results
136 | *.coverage
137 | *.coveragexml
138 |
139 | # NCrunch
140 | _NCrunch_*
141 | .*crunch*.local.xml
142 | nCrunchTemp_*
143 |
144 | # MightyMoose
145 | *.mm.*
146 | AutoTest.Net/
147 |
148 | # Web workbench (sass)
149 | .sass-cache/
150 |
151 | # Installshield output folder
152 | [Ee]xpress/
153 |
154 | # DocProject is a documentation generator add-in
155 | DocProject/buildhelp/
156 | DocProject/Help/*.HxT
157 | DocProject/Help/*.HxC
158 | DocProject/Help/*.hhc
159 | DocProject/Help/*.hhk
160 | DocProject/Help/*.hhp
161 | DocProject/Help/Html2
162 | DocProject/Help/html
163 |
164 | # Click-Once directory
165 | publish/
166 |
167 | # Publish Web Output
168 | *.[Pp]ublish.xml
169 | *.azurePubxml
170 | # Note: Comment the next line if you want to checkin your web deploy settings,
171 | # but database connection strings (with potential passwords) will be unencrypted
172 | *.pubxml
173 | *.publishproj
174 |
175 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
176 | # checkin your Azure Web App publish settings, but sensitive information contained
177 | # in these scripts will be unencrypted
178 | PublishScripts/
179 |
180 | # NuGet Packages
181 | *.nupkg
182 | # The packages folder can be ignored because of Package Restore
183 | **/[Pp]ackages/*
184 | # except build/, which is used as an MSBuild target.
185 | !**/[Pp]ackages/build/
186 | # Uncomment if necessary however generally it will be regenerated when needed
187 | #!**/[Pp]ackages/repositories.config
188 | # NuGet v3's project.json files produces more ignorable files
189 | *.nuget.props
190 | *.nuget.targets
191 |
192 | # Microsoft Azure Build Output
193 | csx/
194 | *.build.csdef
195 |
196 | # Microsoft Azure Emulator
197 | ecf/
198 | rcf/
199 |
200 | # Windows Store app package directories and files
201 | AppPackages/
202 | BundleArtifacts/
203 | Package.StoreAssociation.xml
204 | _pkginfo.txt
205 | *.appx
206 |
207 | # Visual Studio cache files
208 | # files ending in .cache can be ignored
209 | *.[Cc]ache
210 | # but keep track of directories ending in .cache
211 | !*.[Cc]ache/
212 |
213 | # Others
214 | ClientBin/
215 | ~$*
216 | *~
217 | *.dbmdl
218 | *.dbproj.schemaview
219 | *.jfm
220 | *.pfx
221 | *.publishsettings
222 | orleans.codegen.cs
223 |
224 | # Including strong name files can present a security risk
225 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
226 | #*.snk
227 |
228 | # Since there are multiple workflows, uncomment next line to ignore bower_components
229 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
230 | #bower_components/
231 |
232 | # RIA/Silverlight projects
233 | Generated_Code/
234 |
235 | # Backup & report files from converting an old project file
236 | # to a newer Visual Studio version. Backup files are not needed,
237 | # because we have git ;-)
238 | _UpgradeReport_Files/
239 | Backup*/
240 | UpgradeLog*.XML
241 | UpgradeLog*.htm
242 | ServiceFabricBackup/
243 | *.rptproj.bak
244 |
245 | # SQL Server files
246 | *.mdf
247 | *.ldf
248 | *.ndf
249 |
250 | # Business Intelligence projects
251 | *.rdl.data
252 | *.bim.layout
253 | *.bim_*.settings
254 | *.rptproj.rsuser
255 |
256 | # Microsoft Fakes
257 | FakesAssemblies/
258 |
259 | # GhostDoc plugin setting file
260 | *.GhostDoc.xml
261 |
262 | # Node.js Tools for Visual Studio
263 | .ntvs_analysis.dat
264 | node_modules/
265 |
266 | # Visual Studio 6 build log
267 | *.plg
268 |
269 | # Visual Studio 6 workspace options file
270 | *.opt
271 |
272 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
273 | *.vbw
274 |
275 | # Visual Studio LightSwitch build output
276 | **/*.HTMLClient/GeneratedArtifacts
277 | **/*.DesktopClient/GeneratedArtifacts
278 | **/*.DesktopClient/ModelManifest.xml
279 | **/*.Server/GeneratedArtifacts
280 | **/*.Server/ModelManifest.xml
281 | _Pvt_Extensions
282 |
283 | # Paket dependency manager
284 | .paket/paket.exe
285 | paket-files/
286 |
287 | # FAKE - F# Make
288 | .fake/
289 |
290 | # JetBrains Rider
291 | .idea/
292 | *.sln.iml
293 |
294 | # CodeRush
295 | .cr/
296 |
297 | # Python Tools for Visual Studio (PTVS)
298 | __pycache__/
299 | *.pyc
300 |
301 | # Cake - Uncomment if you are using it
302 | # tools/**
303 | # !tools/packages.config
304 |
305 | # Tabs Studio
306 | *.tss
307 |
308 | # Telerik's JustMock configuration file
309 | *.jmconfig
310 |
311 | # BizTalk build output
312 | *.btp.cs
313 | *.btm.cs
314 | *.odx.cs
315 | *.xsd.cs
316 |
317 | # OpenCover UI analysis results
318 | OpenCover/
319 |
320 | # Azure Stream Analytics local run output
321 | ASALocalRun/
322 |
323 | # MSBuild Binary and Structured Log
324 | *.binlog
325 |
326 | # NVidia Nsight GPU debugger configuration file
327 | *.nvuser
328 |
329 | # MFractors (Xamarin productivity tool) working folder
330 | .mfractor/
--------------------------------------------------------------------------------
/CodeListener.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 14
4 | VisualStudioVersion = 14.0.25420.1
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeListener", "CodeListener\CodeListener.csproj", "{8C4235B6-64BC-4508-9166-BEF8AA151085}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug (Rhino 5)|Any CPU = Debug (Rhino 5)|Any CPU
11 | Debug (Rhino 5)|x64 = Debug (Rhino 5)|x64
12 | Debug (Rhino 5)|x86 = Debug (Rhino 5)|x86
13 | Debug (Rhino 6)|Any CPU = Debug (Rhino 6)|Any CPU
14 | Debug (Rhino 6)|x64 = Debug (Rhino 6)|x64
15 | Debug (Rhino 6)|x86 = Debug (Rhino 6)|x86
16 | Release (Rhino 5)|Any CPU = Release (Rhino 5)|Any CPU
17 | Release (Rhino 5)|x64 = Release (Rhino 5)|x64
18 | Release (Rhino 5)|x86 = Release (Rhino 5)|x86
19 | Release (Rhino 6)|Any CPU = Release (Rhino 6)|Any CPU
20 | Release (Rhino 6)|x64 = Release (Rhino 6)|x64
21 | Release (Rhino 6)|x86 = Release (Rhino 6)|x86
22 | EndGlobalSection
23 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
24 | {8C4235B6-64BC-4508-9166-BEF8AA151085}.Debug (Rhino 5)|Any CPU.ActiveCfg = Debug (Rhino 5)|Any CPU
25 | {8C4235B6-64BC-4508-9166-BEF8AA151085}.Debug (Rhino 5)|Any CPU.Build.0 = Debug (Rhino 5)|Any CPU
26 | {8C4235B6-64BC-4508-9166-BEF8AA151085}.Debug (Rhino 5)|x64.ActiveCfg = Debug (Rhino 5)|Any CPU
27 | {8C4235B6-64BC-4508-9166-BEF8AA151085}.Debug (Rhino 5)|x64.Build.0 = Debug (Rhino 5)|Any CPU
28 | {8C4235B6-64BC-4508-9166-BEF8AA151085}.Debug (Rhino 5)|x86.ActiveCfg = Debug (Rhino 5)|Any CPU
29 | {8C4235B6-64BC-4508-9166-BEF8AA151085}.Debug (Rhino 5)|x86.Build.0 = Debug (Rhino 5)|Any CPU
30 | {8C4235B6-64BC-4508-9166-BEF8AA151085}.Debug (Rhino 6)|Any CPU.ActiveCfg = Debug (Rhino 6)|Any CPU
31 | {8C4235B6-64BC-4508-9166-BEF8AA151085}.Debug (Rhino 6)|Any CPU.Build.0 = Debug (Rhino 6)|Any CPU
32 | {8C4235B6-64BC-4508-9166-BEF8AA151085}.Debug (Rhino 6)|x64.ActiveCfg = Debug (Rhino 6)|Any CPU
33 | {8C4235B6-64BC-4508-9166-BEF8AA151085}.Debug (Rhino 6)|x64.Build.0 = Debug (Rhino 6)|Any CPU
34 | {8C4235B6-64BC-4508-9166-BEF8AA151085}.Debug (Rhino 6)|x86.ActiveCfg = Debug (Rhino 6)|Any CPU
35 | {8C4235B6-64BC-4508-9166-BEF8AA151085}.Debug (Rhino 6)|x86.Build.0 = Debug (Rhino 6)|Any CPU
36 | {8C4235B6-64BC-4508-9166-BEF8AA151085}.Release (Rhino 5)|Any CPU.ActiveCfg = Release (Rhino 5)|Any CPU
37 | {8C4235B6-64BC-4508-9166-BEF8AA151085}.Release (Rhino 5)|Any CPU.Build.0 = Release (Rhino 5)|Any CPU
38 | {8C4235B6-64BC-4508-9166-BEF8AA151085}.Release (Rhino 5)|x64.ActiveCfg = Release (Rhino 5)|Any CPU
39 | {8C4235B6-64BC-4508-9166-BEF8AA151085}.Release (Rhino 5)|x64.Build.0 = Release (Rhino 5)|Any CPU
40 | {8C4235B6-64BC-4508-9166-BEF8AA151085}.Release (Rhino 5)|x86.ActiveCfg = Release (Rhino 5)|Any CPU
41 | {8C4235B6-64BC-4508-9166-BEF8AA151085}.Release (Rhino 5)|x86.Build.0 = Release (Rhino 5)|Any CPU
42 | {8C4235B6-64BC-4508-9166-BEF8AA151085}.Release (Rhino 6)|Any CPU.ActiveCfg = Release (Rhino 6)|Any CPU
43 | {8C4235B6-64BC-4508-9166-BEF8AA151085}.Release (Rhino 6)|Any CPU.Build.0 = Release (Rhino 6)|Any CPU
44 | {8C4235B6-64BC-4508-9166-BEF8AA151085}.Release (Rhino 6)|x64.ActiveCfg = Release (Rhino 6)|Any CPU
45 | {8C4235B6-64BC-4508-9166-BEF8AA151085}.Release (Rhino 6)|x64.Build.0 = Release (Rhino 6)|Any CPU
46 | {8C4235B6-64BC-4508-9166-BEF8AA151085}.Release (Rhino 6)|x86.ActiveCfg = Release (Rhino 6)|Any CPU
47 | {8C4235B6-64BC-4508-9166-BEF8AA151085}.Release (Rhino 6)|x86.Build.0 = Release (Rhino 6)|Any CPU
48 | EndGlobalSection
49 | GlobalSection(SolutionProperties) = preSolution
50 | HideSolutionNode = FALSE
51 | EndGlobalSection
52 | GlobalSection(ExtensibilityGlobals) = postSolution
53 | SolutionGuid = {E31AE304-E446-413F-8E04-99A913698FC6}
54 | EndGlobalSection
55 | EndGlobal
56 |
--------------------------------------------------------------------------------
/CodeListener/CodeListener.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | AnyCPU
6 | 8.0.30703
7 | 2.0
8 | {8C4235B6-64BC-4508-9166-BEF8AA151085}
9 | Library
10 | Properties
11 | CodeListener
12 | CodeListener
13 | v4.8
14 | 512
15 | false
16 |
17 |
18 |
19 | true
20 | full
21 | false
22 | bin\Debug\Rhino5\
23 | TRACE;DEBUG;RHINO5
24 | prompt
25 | false
26 |
27 |
28 | pdbonly
29 | true
30 | bin\Release\Rhino5\
31 | TRACE;RHINO5
32 | prompt
33 | 4
34 |
35 |
36 | true
37 | bin\Debug\Rhino6\
38 | TRACE;DEBUG;RHINO6
39 | full
40 | AnyCPU
41 | prompt
42 | MinimumRecommendedRules.ruleset
43 | false
44 |
45 |
46 | bin\Release\Rhino6\
47 | TRACE;RHINO6
48 | true
49 | pdbonly
50 | AnyCPU
51 | prompt
52 | MinimumRecommendedRules.ruleset
53 |
54 |
55 |
56 | ..\..\..\..\..\..\..\Program Files\Rhino 7\System\Eto.dll
57 | False
58 |
59 |
60 | ..\..\..\..\..\..\..\Program Files\Rhino 7\Plug-ins\IronPython\IronPython.dll
61 | False
62 |
63 |
64 |
65 |
66 | ..\..\..\..\..\..\..\Program Files\Rhino 7\System\RhinoCommon.dll
67 | False
68 |
69 |
70 | ..\..\..\..\..\..\..\Program Files\Rhino 7\Plug-ins\IronPython\RhinoPythonHost.dll
71 | False
72 |
73 |
74 |
75 |
76 |
77 |
78 | ..\..\..\..\Program Files\Rhino6\System\RhinoCommon.dll
79 | False
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
112 |
113 | Copy "$(TargetPath)" "$(TargetDir)$(ProjectName).rhp"
114 | Erase "$(TargetPath)"
115 |
116 |
117 | en-US
118 |
119 |
120 | C:\Program Files\Rhinoceros 5 (64-bit)\System\Rhino.exe
121 |
122 |
123 | Program
124 |
125 |
--------------------------------------------------------------------------------
/CodeListener/CodeListenerCommand.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel;
4 | using System.IO;
5 | using System.Linq;
6 | using System.Net;
7 | using System.Net.Http;
8 | using System.Net.Http.Headers;
9 | using System.Net.Sockets;
10 | using System.Runtime.Serialization;
11 | using System.Text;
12 | using Rhino;
13 | using Rhino.Commands;
14 | using Rhino.Geometry;
15 | using System.Runtime.Serialization.Json;
16 | using System.Text.RegularExpressions;
17 | using System.Windows;
18 | using Rhino.Display;
19 | using Rhino.DocObjects;
20 | using Rhino.Runtime;
21 | using Command = Rhino.Commands.Command;
22 | using MessageBox = System.Windows.MessageBox;
23 | #if RHINO6
24 | using Eto.Forms;
25 | #endif
26 |
27 |
28 | namespace CodeListener
29 | {
30 | public class CodeListenerCommand : Command
31 | {
32 | internal static BackgroundWorker _tcpServerWorker;
33 | private RhinoDoc _idoc;
34 | internal static TcpListener _server;
35 |
36 | #if RHINO5
37 | private Application _app;
38 | #endif
39 |
40 |
41 | public CodeListenerCommand()
42 | {
43 | // Rhino only creates one instance of each command class defined in a
44 | // plug-in, so it is safe to store a refence in a static property.
45 |
46 | Instance = this;
47 | }
48 |
49 | ///The only instance of this command.
50 | public static CodeListenerCommand Instance
51 | {
52 | get; private set;
53 | }
54 |
55 | ///The command name as it appears on the Rhino command line.
56 | public override string EnglishName
57 | {
58 | get { return "CodeListener"; }
59 | }
60 |
61 | protected override Result RunCommand(RhinoDoc doc, RunMode mode)
62 | {
63 | _idoc = doc;
64 | CheckLatestVersion();
65 | #if RHINO5
66 | // Start WPF UI Dispatcher if not running.
67 | if (_app == null)
68 | {
69 | _app = Application.Current ?? new Application { ShutdownMode = ShutdownMode.OnExplicitShutdown };
70 | }
71 | #endif
72 | // set up the listenner
73 | if (_tcpServerWorker != null && _tcpServerWorker.IsBusy)
74 | {
75 | RhinoApp.WriteLine("VS Code Listener is running.", EnglishName);
76 | return Result.Cancel;
77 | };
78 |
79 | // Start the worker thread
80 | _tcpServerWorker = new BackgroundWorker();
81 | _tcpServerWorker.WorkerSupportsCancellation = true;
82 | _tcpServerWorker.DoWork += TcpServerWorkerListening;
83 | _tcpServerWorker.RunWorkerCompleted += TcpServerWorkerRunTcpServerWorkerCompleted;
84 | _tcpServerWorker.RunWorkerAsync();
85 |
86 |
87 | return Result.Success;
88 | }
89 |
90 | // fire this function when the background worker has stopped
91 | protected void TcpServerWorkerRunTcpServerWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
92 | {
93 | _tcpServerWorker.Dispose();
94 | _tcpServerWorker = null;
95 | RhinoApp.WriteLine("VS Code Listener stopped. Please run CodeListener again.");
96 | }
97 |
98 | // the main listener function
99 | protected void TcpServerWorkerListening(object sender, DoWorkEventArgs e)
100 | {
101 | //---listen at the specified IP and port no.---
102 | const int portNo = 614;
103 | IPAddress serverIp = IPAddress.Parse("127.0.0.1");
104 | if (_server == null) _server = new TcpListener(serverIp, portNo);
105 | try
106 | {
107 | _server.Start();
108 | RhinoApp.WriteLine("VS Code Listener Started...");
109 | }
110 | catch (Exception err)
111 | {
112 | RhinoApp.WriteLine("Error start Code Listener. Is other Rhino instance occupying?");
113 | RhinoApp.WriteLine(err.ToString());
114 | }
115 |
116 | while (true)
117 | {
118 | // incoming client connected
119 | TcpClient client;
120 | try
121 | {
122 | client = _server.AcceptTcpClient();
123 | }
124 | catch (Exception serverException)
125 | {
126 | return;
127 | }
128 |
129 | // get the incoming data through a network stream
130 | NetworkStream nwStream = client.GetStream();
131 | byte[] buffer = new byte[client.ReceiveBufferSize];
132 |
133 | // read incoming stream
134 | int bytesRead = nwStream.Read(buffer, 0, client.ReceiveBufferSize);
135 |
136 | // convert the data received into a string
137 | StringBuilder msg = new StringBuilder();
138 |
139 | // parse the buffer into msg
140 | foreach (var b in buffer)
141 | {
142 | if (b.Equals(00)) break;
143 | msg.Append(Convert.ToChar(b).ToString());
144 | }
145 |
146 | // parse the received message into C# Object
147 | string msgString = msg.ToString();
148 | msgString = Regex.Split(msgString, "}")[0] + "}";
149 | MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(msgString));
150 | DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(msgObject));
151 | msgObject msgObj;
152 | try
153 | {
154 | msgObj = ser.ReadObject(ms) as msgObject;
155 | }
156 | catch (Exception ex)
157 | {
158 | RhinoApp.WriteLine("Received invalid data, please try again.");
159 | return;
160 | }
161 |
162 | ms.Close();
163 |
164 | // invoke the main task in the main thread
165 | #if RHINO5
166 | _app.Dispatcher.Invoke(() =>
167 | #else
168 | Eto.Forms.Application.Instance.Invoke(() =>
169 | #endif
170 | {
171 | // create python script runner
172 | PythonScript myScript = PythonScript.Create();
173 | // redirect output to _output field
174 | myScript.Output = PrintToVSCode;
175 | FeedbackSender feedbackSender = new FeedbackSender(nwStream);
176 | GotCodeFeekBack += feedbackSender.OnGotCodeFeedBack;
177 |
178 | // if flagged reset, then reset the script engine.
179 | if (msgObj.reset)
180 | {
181 | ResetScriptEngine.ResetEngine();
182 | }
183 |
184 | // if it is not a temp folder, add the folder to python library path
185 | if (!msgObj.temp)
186 | {
187 | string pythonFilePath = Path.GetDirectoryName(msgObj.filename);
188 | string code = string.Format("import sys\nimport os\nif \"{0}\" not in sys.path: sys.path.append(\"{0}\")", pythonFilePath.Replace("\\", "\\\\"));
189 | try
190 | {
191 | myScript.ExecuteScript(code);
192 | }
193 | catch (Exception exception)
194 | {
195 | PrintToVSCode(exception.Message);
196 | }
197 | }
198 |
199 | // determines if run actual script
200 | if (msgObj.run)
201 | {
202 | uint sn = _idoc.BeginUndoRecord("VS Code execution");
203 | var sn_start = RhinoObject.NextRuntimeSerialNumber;
204 | try
205 | {
206 | myScript.ExecuteFile(msgObj.filename);
207 | }
208 | catch (Exception ex)
209 | {
210 | // get the exception message
211 | var error = myScript.GetStackTraceFromException(ex);
212 | string message = ex.Message + "\n" + error;
213 | // send exception msg back to VS Code
214 | PrintToVSCode(message);
215 | }
216 | finally
217 | {
218 | CloseConnection(nwStream);
219 | _idoc.EndUndoRecord(sn);
220 | // fix the rs.Prompt bug
221 | RhinoApp.SetCommandPrompt("Command");
222 |
223 | // select created objects
224 | var sn_end = RhinoObject.NextRuntimeSerialNumber;
225 | if (sn_end > sn_start)
226 | {
227 | for (var i = sn_start; i < sn_end; i++)
228 | {
229 | var obj = _idoc.Objects.Find(i);
230 | if (null != obj)
231 | {
232 | obj.Select(true);
233 | }
234 | }
235 | }
236 | // enable the view
237 | _idoc.Views.RedrawEnabled = true;
238 | }
239 | }
240 | else
241 | {
242 | CloseConnection(nwStream);
243 | }
244 | });
245 | }
246 | }
247 |
248 | public class GotCodeFeedbackEventArgs : EventArgs
249 | {
250 | public string Message { get; set; }
251 | }
252 |
253 | public delegate void CodeFeedBackEventHandler(object source, GotCodeFeedbackEventArgs e);
254 |
255 | public event CodeFeedBackEventHandler GotCodeFeekBack;
256 |
257 | protected virtual void OnGotCodeFeedBack(GotCodeFeedbackEventArgs e)
258 | {
259 | GotCodeFeekBack?.Invoke(this, e);
260 | }
261 |
262 | // add the action to redirect output to VS Code
263 | protected void PrintToVSCode(string m)
264 | {
265 | RhinoApp.Write(m);
266 | GotCodeFeedbackEventArgs arg = new GotCodeFeedbackEventArgs { Message = m };
267 | OnGotCodeFeedBack(arg);
268 | }
269 |
270 | // close connection
271 | protected void CloseConnection(NetworkStream stream)
272 | {
273 | stream.Close();
274 | }
275 |
276 | // check plugin versions
277 | protected async void CheckLatestVersion()
278 | {
279 | // hardcoded github latest releases
280 | string sURL = "https://api.github.com/repos/ccc159/CodeListener/releases/latest";
281 | string pageURL = "https://github.com/ccc159/CodeListener/releases/latest";
282 | var client = new HttpClient();
283 | ServicePointManager.SecurityProtocol =
284 | SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
285 | client.DefaultRequestHeaders.Add("User-Agent", "CodeListener");
286 | try
287 | {
288 | var uri = new Uri(sURL);
289 | Stream respStream = await client.GetStreamAsync(uri);
290 | StreamReader reader = new StreamReader(respStream);
291 | string responseFromServer = reader.ReadToEnd();
292 | var index = responseFromServer.IndexOf("tag_name", StringComparison.Ordinal);
293 | var version = (responseFromServer.Substring(index + 11, 10).Split('\"')[0]).Split('.');
294 | // version Major.Minor.Patch -> 0.1.5
295 | int major = Int32.Parse(version[0]);
296 | int minor = Int32.Parse(version[1]);
297 | int patch = Int32.Parse(version[2]);
298 | if (CodeListenerVersion.MAJOR < major || CodeListenerVersion.MINOR < minor ||
299 | CodeListenerVersion.PATCH < patch)
300 | {
301 | var msg = $"CodeListener has new a version {major}.{minor}.{patch}! Go to download page?";
302 | var result = MessageBox.Show(msg, "New Version", MessageBoxButton.OKCancel,
303 | MessageBoxImage.Information);
304 | if (result == MessageBoxResult.OK) System.Diagnostics.Process.Start(pageURL);
305 | }
306 | }
307 | catch (Exception ex)
308 | {
309 | RhinoApp.WriteLine("Check new version failed.");
310 | }
311 | }
312 | }
313 |
314 | // define the message object structure that received from VS Code
315 | [DataContract]
316 | public class msgObject
317 | {
318 | [DataMember]
319 | internal bool run;
320 | [DataMember]
321 | internal bool temp;
322 | [DataMember]
323 | internal bool reset;
324 | [DataMember]
325 | internal string filename;
326 | }
327 | }
328 |
--------------------------------------------------------------------------------
/CodeListener/CodeListenerExecute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 | using System.IO;
4 | using Rhino;
5 | using Rhino.Commands;
6 | using Rhino.Input;
7 |
8 | namespace CodeListener
9 | {
10 | [System.Runtime.InteropServices.Guid("a6dbd0d2-3ef9-44e7-8867-e0b359b57f38")]
11 | public class CodeListenerExecute : Command
12 | {
13 | static CodeListenerExecute _instance;
14 | public CodeListenerExecute()
15 | {
16 | _instance = this;
17 | }
18 |
19 | ///The only instance of the CodeListenerExecute command.
20 | public static CodeListenerExecute Instance
21 | {
22 | get { return _instance; }
23 | }
24 |
25 | public override string EnglishName
26 | {
27 | get { return "CodeListenerExecute"; }
28 | }
29 |
30 | protected override Result RunCommand(RhinoDoc doc, RunMode mode)
31 | {
32 | // get the path
33 | string path = string.Empty;
34 | RhinoGet.GetString("Absolute path of the exexutable", true, ref path);
35 | if (string.IsNullOrEmpty(path))
36 | {
37 | RhinoApp.WriteLine("Cancelled.");
38 | return Result.Cancel;
39 | }
40 | // valdiate path
41 | if (!File.Exists(path))
42 | {
43 | RhinoApp.WriteLine("File path is not valid.");
44 | return Result.Cancel;
45 | }
46 | // run the file
47 | try
48 | {
49 | Process.Start(path);
50 | }
51 | catch (Exception e)
52 | {
53 | RhinoApp.WriteLine(e.Message);
54 | }
55 |
56 | return Result.Success;
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/CodeListener/CodeListenerPlugIn.cs:
--------------------------------------------------------------------------------
1 | namespace CodeListener
2 | {
3 | ///
4 | /// Every RhinoCommon .rhp assembly must have one and only one PlugIn-derived
5 | /// class. DO NOT create instances of this class yourself. It is the
6 | /// responsibility of Rhino to create an instance of this class.
7 | /// To complete plug-in information, please also see all PlugInDescription
8 | /// attributes in AssemblyInfo.cs (you might need to click "Project" ->
9 | /// "Show All Files" to see it in the "Solution Explorer" window).
10 | ///
11 | public class CodeListenerPlugIn : Rhino.PlugIns.PlugIn
12 |
13 | {
14 | public CodeListenerPlugIn()
15 | {
16 | Instance = this;
17 | }
18 |
19 | ///Gets the only instance of the CodeListenerPlugIn plug-in.
20 | public static CodeListenerPlugIn Instance
21 | {
22 | get; private set;
23 | }
24 |
25 | // You can override methods here to change the plug-in behavior on
26 | // loading and shut down, add options pages to the Rhino _Option command
27 | // and maintain plug-in wide options in a document.
28 | }
29 | }
--------------------------------------------------------------------------------
/CodeListener/CodeListenerVersion.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Windows;
3 | using System.Windows.Forms;
4 | using Rhino;
5 | using Rhino.Commands;
6 | using MessageBox = System.Windows.MessageBox;
7 |
8 | namespace CodeListener
9 | {
10 | [System.Runtime.InteropServices.Guid("56773c6e-b5d1-462f-af01-43bed492ef53")]
11 | public class CodeListenerVersion : Command
12 | {
13 | internal static int MAJOR = 0;
14 | internal static int MINOR = 1;
15 | internal static int PATCH = 8;
16 | internal static string Version = $"{MAJOR}.{MINOR}.{PATCH}";
17 | static CodeListenerVersion _instance;
18 | public CodeListenerVersion()
19 | {
20 | _instance = this;
21 | }
22 |
23 | ///The only instance of the CodeListenerVersion command.
24 | public static CodeListenerVersion Instance
25 | {
26 | get { return _instance; }
27 | }
28 |
29 | public override string EnglishName
30 | {
31 | get { return "CodeListenerVersion"; }
32 | }
33 |
34 | protected override Result RunCommand(RhinoDoc doc, RunMode mode)
35 | {
36 | // TODO: remember to change to versions every time publish a new one!!
37 | RhinoApp.WriteLine($"CodeListener Version: {Version}");
38 | return Result.Success;
39 | }
40 |
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/CodeListener/EmbeddedResources/plugin-utility.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jingcheng-chen/CodeListener/9186157ab6f380102efceb91712b4a6ba5c74bb0/CodeListener/EmbeddedResources/plugin-utility.ico
--------------------------------------------------------------------------------
/CodeListener/FeedbackSender.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Net.Sockets;
5 | using System.Text;
6 |
7 | namespace CodeListener
8 | {
9 | class FeedbackSender
10 | {
11 | private NetworkStream stream;
12 |
13 | public FeedbackSender(NetworkStream istream)
14 | {
15 | stream = istream;
16 | }
17 |
18 | public void OnGotCodeFeedBack(object source, CodeListenerCommand.GotCodeFeedbackEventArgs e)
19 | {
20 | // Process the data sent by the client.
21 | byte[] errMsgBytes = Encoding.ASCII.GetBytes(e.Message);
22 | // Send back a response.
23 | try
24 | {
25 | stream.Write(errMsgBytes, 0, errMsgBytes.Length);
26 | }
27 | catch (Exception exception)
28 | {
29 | stream.Close();
30 | }
31 | }
32 | }
33 |
34 |
35 | }
--------------------------------------------------------------------------------
/CodeListener/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 | using CodeListener;
5 | using Rhino.PlugIns;
6 |
7 | // Plug-in Description Attributes - all of these are optional.
8 | // These will show in Rhino's option dialog, in the tab Plug-ins.
9 | [assembly: PlugInDescription(DescriptionType.Address, "Seestrasse 78, 8703 Erlenbach/Zürich")]
10 | [assembly: PlugInDescription(DescriptionType.Country, "Switzerland")]
11 | [assembly: PlugInDescription(DescriptionType.Email, "info@designtoproduction.com")]
12 | [assembly: PlugInDescription(DescriptionType.Phone, "+41 (0) 44 914 74 90")]
13 | [assembly: PlugInDescription(DescriptionType.Fax, "+41 (0) 44 914 74 99")]
14 | [assembly: PlugInDescription(DescriptionType.Organization, "Design-to-Production GmbH")]
15 | [assembly: PlugInDescription(DescriptionType.UpdateUrl, "https://github.com/ccc159/CodeListener")]
16 | [assembly: PlugInDescription(DescriptionType.WebSite, "http://designtoproduction.com/")]
17 |
18 | // Icons should be Windows .ico files and contain 32-bit images in the following sizes: 16, 24, 32, 48, and 256.
19 | // This is a Rhino 6-only description.
20 |
21 | // General Information about an assembly is controlled through the following
22 | // set of attributes. Change these attribute values to modify the information
23 | // associated with an assembly.
24 | [assembly: AssemblyTitle("CodeListener")]
25 |
26 | // This will be used also for the plug-in description.
27 | [assembly: AssemblyDescription("CodeListener utility plug-in")]
28 |
29 | [assembly: AssemblyConfiguration("")]
30 | [assembly: AssemblyCompany("Design-To-Production")]
31 | [assembly: AssemblyProduct("CodeListener")]
32 | [assembly: AssemblyCopyright("Copyright © 2018")]
33 | [assembly: AssemblyTrademark("")]
34 | [assembly: AssemblyCulture("")]
35 |
36 | // Setting ComVisible to false makes the types in this assembly not visible
37 | // to COM components. If you need to access a type in this assembly from
38 | // COM, set the ComVisible attribute to true on that type.
39 | [assembly: ComVisible(false)]
40 |
41 | // The following GUID is for the ID of the typelib if this project is exposed to COM
42 | [assembly: Guid("8c4235b6-64bc-4508-9166-bef8aa151085")] // This will also be the Guid of the Rhino plug-in
43 |
44 | // Version information for an assembly consists of the following four values:
45 | //
46 | // Major Version
47 | // Minor Version
48 | // Build Number
49 | // Revision
50 | //
51 | // You can specify all the values or you can default the Build and Revision Numbers
52 | // by using the '*' as shown below:
53 | // [assembly: AssemblyVersion("1.0.*")]
54 |
55 | [assembly: AssemblyVersion("0.1.7")]
56 | [assembly: AssemblyFileVersion("0.1.7")]
57 |
58 | // Make compatible with Rhino Installer Engine
59 | [assembly: AssemblyInformationalVersion("2")]
60 |
--------------------------------------------------------------------------------
/CodeListener/ResetScriptEngine.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Text;
4 | using Rhino;
5 | using Rhino.Commands;
6 |
7 | namespace CodeListener
8 | {
9 | [System.Runtime.InteropServices.Guid("78d32084-0d9a-41b4-99f6-83740f67fb48"),
10 | Rhino.Commands.CommandStyle(Rhino.Commands.Style.ScriptRunner)]
11 | public class ResetScriptEngine : Command
12 | {
13 | static ResetScriptEngine _instance;
14 | public ResetScriptEngine()
15 | {
16 | _instance = this;
17 | }
18 |
19 | ///The only instance of the Reset command.
20 | public static ResetScriptEngine Instance
21 | {
22 | get { return _instance; }
23 | }
24 |
25 | public override string EnglishName
26 | {
27 | get { return "ResetScriptEngine"; }
28 | }
29 |
30 | protected override Result RunCommand(RhinoDoc doc, RunMode mode)
31 | {
32 | try
33 | {
34 | ResetEngine();
35 | return Result.Success;
36 | }
37 | catch (Exception exception)
38 | {
39 | return Result.Failure;
40 | }
41 | }
42 |
43 | public static void ResetEngine()
44 | {
45 | // shut down host
46 | RhinoPython.Host.ShutDown();
47 |
48 | // create a new resetscriptengine.py python file
49 | string tempPath = Path.GetTempPath();
50 | string filepath = tempPath + "resetscriptengine.py";
51 | try
52 | {
53 | if (!File.Exists(filepath))
54 | {
55 | // Create the file.
56 | using (FileStream fs = File.Create(filepath))
57 | {
58 | Byte[] info = new UTF8Encoding(true).GetBytes("print \"Python script engine has been reset.\"");
59 | fs.Write(info, 0, info.Length);
60 | }
61 | }
62 | }
63 | catch (Exception ex)
64 | {
65 | throw ex;
66 | }
67 |
68 | // run this file through RhinoApp Command to initialize a new python script engine.
69 | var script = "-_EditPythonScript Debugging=Off \n(\n" + filepath + "\n)\n";
70 | RhinoApp.RunScript(script, true);
71 | }
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/CodeListener/StopCodeListener.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Rhino;
3 | using Rhino.Commands;
4 |
5 | namespace CodeListener
6 | {
7 | [System.Runtime.InteropServices.Guid("4e5821bd-858e-4183-9107-6c3f4be1783e")]
8 | public class StopCodeListener : Command
9 | {
10 | static StopCodeListener _instance;
11 | public StopCodeListener()
12 | {
13 | _instance = this;
14 | }
15 |
16 | ///The only instance of the ResetCodeListener command.
17 | public static StopCodeListener Instance
18 | {
19 | get { return _instance; }
20 | }
21 |
22 | public override string EnglishName
23 | {
24 | get { return "StopCodeListener"; }
25 | }
26 |
27 | protected override Result RunCommand(RhinoDoc doc, RunMode mode)
28 | {
29 | if (CodeListenerCommand._server != null)
30 | {
31 | CodeListenerCommand._server.Stop();
32 | CodeListenerCommand._server = null;
33 | return Result.Success;
34 | }
35 |
36 | return Result.Cancel;
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/CodeListener/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # CodeListener
2 |
3 | Codelistener is part of the plugin [RhinoPython](https://github.com/ccc159/PythonScript). It is the RhinoPython server that runs in Rhino that listens to VS Code editor.
4 |
5 | ## Installation & Usage
6 |
7 | For the instructions of installation and usage please refer to [RhinoPython readme](https://github.com/ccc159/PythonScript/blob/master/README.md).
8 |
9 | ## Commands
10 |
11 | - **CodeListener**: Start CodeListener in the background.
12 | - **StopCodeListener**: Stop CodeListener, to allow other rhino instances to run CodeListener. Automatically stopped if current rhino instance exits.
13 | - **CodeListenerVersion**: Check current CodeListener version.
14 | - **CodeListenerExecute**: Allow Rhino to execute a file with given path. Can be used in combination with keyboard shortcut. For instance: `F2` binds to `_-CodeListenerExecute "C:\Program Files\Rhinoceros 5 (64-bit)\Plug-ins\IronPython\RhinoIronPython.chm" _Enter`
15 | - **ResetScriptEngine**: Reset Rhino python script engine.
--------------------------------------------------------------------------------