Skip to content

Commit 5001228

Browse files
Feature: Add support for launching multiple .cs hotswappable scripts.
Improve error message propagation, for now only to output panel. Add mechanism to develop C# script execution error reporting from C# script itself
1 parent ae790fd commit 5001228

5 files changed

Lines changed: 175 additions & 45 deletions

File tree

ScriptEngineStarter/CsScript.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ static public void RunScript( String scriptPath, Object mainArg)
4444

4545
String path = Path.GetFullPath(scriptPath);
4646
if( !File.Exists( path ) )
47-
throw new Exception("Error: Could not load file '" + Path.GetFileName(path) + "': File does not exists.");
47+
throw new Exception("Error: Could not load file '" + path + "': File does not exists.");
4848

4949
String dllBaseName = Path.GetFileNameWithoutExtension(path) + "_" + loadCounter.ToString();
5050
String basePath = Path.Combine(tempDir, dllBaseName);
@@ -113,9 +113,9 @@ static public void RunScript( String scriptPath, Object mainArg)
113113
// script filename, and first line position. (Not exactly right, but something at least).
114114

115115
if (error.FileName == "")
116-
sb.Append(Path.GetFileName(filesToCompile[0]));
116+
sb.Append(filesToCompile[0]);
117117
else
118-
sb.Append(Path.GetFileName(error.FileName));
118+
sb.Append(error.FileName);
119119

120120
if (error.Line == 0)
121121
// error CS0006: Metadata file 'MystiqueDll.dll' could not be found
@@ -152,10 +152,10 @@ static public void RunScript( String scriptPath, Object mainArg)
152152
}
153153

154154
if (entry == null)
155-
throw new Exception(String.Format("{0}(1,1): error: Code does not have 'Main' function\r\n", Path.GetFileName(path)));
155+
throw new Exception(String.Format("{0}(1,1): error: Code does not have 'Main' function\r\n", path));
156156

157157
if (entry.GetParameters().Length != 1)
158-
throw new Exception(String.Format("{0}(1,1): error: Function '{1}' is not expected to have one input parameter\r\n", Path.GetFileName(path), funcName));
158+
throw new Exception(String.Format("{0}(1,1): error: Function '{1}' is not expected to have one input parameter\r\n", path, funcName));
159159

160160
String oldDir = Environment.CurrentDirectory;
161161
//

ScriptEngineStarter/ScriptHost.cs

Lines changed: 67 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,55 @@ public enum CodeType
2525
};
2626

2727

28+
/// <summary>
29+
/// Depending on application itself exception from compilation and execution errors can be handled differently (log, print, display in output panel, etc)
30+
/// Here is specified base class with initial implementation for console application, override it if necessary
31+
/// </summary>
32+
public class ScriptExceptionHandler
33+
{
34+
/// <summary>
35+
/// Reports either successful script compilation & execution or reports an exception happening in either compilation or execution of script
36+
/// </summary>
37+
/// <param name="path">Path to .cs script</param>
38+
/// <param name="ex">Exception occurred, null if everything was ok</param>
39+
virtual public async void ReportScriptResult(String path, Exception ex)
40+
{
41+
if (ex == null)
42+
return;
43+
44+
Console.WriteLine(ex.Message);
45+
Debug.WriteLine(ex.Message);
46+
}
47+
}
48+
2849

2950
public class ScriptHost
30-
{
51+
{
52+
public static ScriptExceptionHandler exceptionHandler = new ScriptExceptionHandler();
3153
static String serverSwitch = "/rootsuffix";
3254

3355
/// <summary>
3456
/// User-defined object just to use a global variable storage between scripts runs
3557
/// </summary>
36-
static public List<Object> userObj = new List<object>();
58+
static public List<Object> userObj = new List<object>();
59+
60+
/// <summary>
61+
/// Gets user defined objects from script host.
62+
/// </summary>
63+
/// <typeparam name="T">Type of specific object</typeparam>
64+
/// <param name="args">Additional parameters to constructor in case if object will be created.</param>
65+
/// <returns></returns>
66+
public static T GetUserObject<T>(params object[] args) where T: class
67+
{
68+
T t = userObj.Where(x => x is T).FirstOrDefault() as T;
69+
if (t == null)
70+
{
71+
t = Activator.CreateInstance(typeof(T), args) as T;
72+
userObj.Add(t);
73+
}
74+
75+
return t;
76+
}
3777

3878

3979
// Must be here when using EnvDTE
@@ -44,16 +84,10 @@ static void Main(string[] args)
4484

4585
String hostExePath = @"C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\Common7\IDE\devenv.exe";
4686
String cmdArgs = "Exp"; // "/rootsuffix Exp" - launch experimental version of visual studio.
47-
String csScript = null;
87+
List<String> csScripts = new List<string>();
4888

4989
for (int i = 0; i < args.Length; i++)
5090
{
51-
if (csScript == null)
52-
{
53-
csScript = args[i];
54-
continue;
55-
}
56-
5791
if (args[i] == "/exe")
5892
{
5993
hostExePath = args[++i];
@@ -63,10 +97,10 @@ static void Main(string[] args)
6397
continue;
6498
}
6599

66-
cmdArgs += " " + args[i];
100+
csScripts.Add(args[i]);
67101
}
68102

69-
ScriptServer_ConnectDebugger(null, CodeType.Managed, csScript, hostExePath, cmdArgs);
103+
ScriptServer_ConnectDebugger(null, CodeType.Managed, csScripts, hostExePath, cmdArgs);
70104
}
71105

72106
/// <summary>
@@ -82,9 +116,10 @@ public static void ConnectDebugger(
82116
{
83117
string[] args = Environment.GetCommandLineArgs();
84118
if (args.Contains(serverSwitch))
85-
return;
86-
87-
ScriptServer_ConnectDebugger(null, codetype, csScript, hostExePath, additionCommandLineArguments);
119+
return;
120+
121+
String[] scripts = new string[] { csScript };
122+
ScriptServer_ConnectDebugger(null, codetype, scripts, hostExePath, additionCommandLineArguments);
88123
}
89124

90125
public static object mainArg = null;
@@ -95,7 +130,7 @@ public static void ConnectDebugger(
95130
/// </summary>
96131
/// <param name="csScript">C# script</param>
97132
public static void ScriptServer_ConnectDebugger(
98-
Object _mainArg = null, CodeType codetype = CodeType.Managed, String csScript = null,
133+
Object _mainArg = null, CodeType codetype = CodeType.Managed, IEnumerable<String> csScripts = null,
99134
String hostExePath = null, String additionCommandLineArguments = "")
100135
{
101136
mainArg = _mainArg;
@@ -198,9 +233,12 @@ public static void ScriptServer_ConnectDebugger(
198233

199234
// No need to attach if debugging multiple processes
200235
if (dte != null && dte.Debugger.DebuggedProcesses.Count <= 1)
201-
process.Attach2(engines);
202-
203-
new IpcChannel(process.ProcessID).Send(csScript);
236+
process.Attach2(engines);
237+
238+
foreach (String csScript in csScripts)
239+
{
240+
new IpcChannel(process.ProcessID).Send(csScript);
241+
}
204242
bAttached = true;
205243
break;
206244
}
@@ -446,6 +484,7 @@ static void FileReloadUIThread( String file )
446484
//}
447485

448486
CsScript.RunScript(file, mainArg);
487+
exceptionHandler.ReportScriptResult(file, null);
449488
break;
450489
}
451490
catch (IOException ex)
@@ -467,8 +506,16 @@ static void FileReloadUIThread( String file )
467506
}
468507

469508
if (lastException != null)
470-
Console.WriteLine(lastException.Message);
471-
509+
{
510+
try
511+
{
512+
exceptionHandler.ReportScriptResult(file, lastException);
513+
}
514+
catch (Exception ex)
515+
{
516+
Debug.WriteLine("Exception handler throwed exception by itself: " + ex.Message);
517+
}
518+
}
472519
}
473520

474521
[DllImport("ole32.dll")]

Tools/vsDev/vsDev.cs

Lines changed: 69 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -51,33 +51,82 @@ public static async void Main( object arg )
5151
//pane.Activate();
5252
//dte.ToolWindows.OutputWindow.Parent.Activate();
5353

54-
ErrorListProvider errorListProvider;
54+
//ErrorListProvider errorListProvider;
5555

56-
if (ScriptHost.userObj.Count == 0)
56+
//if (ScriptHost.userObj.Count == 0)
57+
//{
58+
// errorListProvider = new ErrorListProvider(sepkg);
59+
// ScriptHost.userObj.Add(errorListProvider);
60+
//}
61+
//else
62+
//{
63+
// errorListProvider = ScriptHost.userObj[0] as ErrorListProvider;
64+
//}
65+
66+
//errorListProvider.Tasks.Clear();
67+
//var task = new ErrorTask
68+
//{
69+
// Document = @"C:\Prototyping\cppscriptcore\Tools\vsDev\vsDev.cs",
70+
// Line = 59,
71+
// Column = 22,
72+
// ErrorCategory = TaskErrorCategory.Error,
73+
// Category = TaskCategory.BuildCompile,
74+
// Text = "Hello error panel 3"
75+
//};
76+
//task.Navigate += Task_Navigate;
77+
//errorListProvider.Tasks.Add(task);
78+
//errorListProvider.Show();
79+
//errorListProvider.BringToFront();
80+
81+
Debug.WriteLine("New compilation: " + Assembly.GetExecutingAssembly().FullName);
82+
ScriptHost.exceptionHandler = new VsScriptExceptionHandler();
83+
}
84+
85+
private static void Task_Navigate(object sender, EventArgs e)
86+
{
87+
Debug.WriteLine(Assembly.GetExecutingAssembly().FullName);
88+
}
89+
}
90+
91+
92+
class VsScriptExceptionHandler: ScriptExceptionHandler
93+
{
94+
public override async void ReportScriptResult(String file, Exception ex)
95+
{
96+
Debug.WriteLine("Started from: " + Assembly.GetExecutingAssembly().FullName);
97+
ErrorListProvider errList = ScriptHost.GetUserObject<ErrorListProvider>(ScriptHost.mainArg);
98+
99+
ScriptEnginePackage sepkg = (ScriptEnginePackage)ScriptHost.mainArg;
100+
DTE2 dte = await sepkg.GetServiceAsync(typeof(DTE)) as DTE2;
101+
102+
OutputWindowPanes panes = dte.ToolWindows.OutputWindow.OutputWindowPanes;
103+
OutputWindowPane pane;
104+
String cppScript = "Script Engine";
105+
try
57106
{
58-
errorListProvider = new ErrorListProvider(sepkg);
59-
ScriptHost.userObj.Add(errorListProvider);
107+
pane = panes.Item(cppScript);
60108
}
61-
else
109+
catch (ArgumentException)
62110
{
63-
errorListProvider = ScriptHost.userObj[0] as ErrorListProvider;
111+
pane = panes.Add(cppScript);
64112
}
65113

66-
errorListProvider.Tasks.Clear();
67-
var task = new ErrorTask
114+
pane.Clear();
115+
116+
String msg;
117+
if (ex != null)
68118
{
69-
Document = @"C:\Prototyping\cppscriptcore\Tools\vsDev\vsDev.cs",
70-
Line = 59,
71-
Column = 22,
72-
ErrorCategory = TaskErrorCategory.Error,
73-
Category = TaskCategory.BuildCompile,
74-
Text = "Hello error panel 3"
75-
};
76-
//task.Navigate += Task_Navigate;
77-
errorListProvider.Tasks.Add(task);
78-
errorListProvider.Show();
79-
errorListProvider.BringToFront();
119+
msg = ex.Message.ToString();
120+
121+
// Just in case if developer is intrested to fix this.
122+
Debug.WriteLine(msg);
123+
}
124+
else {
125+
msg = file + "(1): info: compiled / executed successfully\r\n";
126+
}
127+
128+
pane.OutputString(msg);
129+
pane.Activate();
80130
}
81131
}
82132

83-

Tools/vsDev/vsDev.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@
9393
</ItemGroup>
9494
<ItemGroup>
9595
<Compile Include="vsDev.cs" />
96+
<Compile Include="vsDev2.cs" />
9697
</ItemGroup>
9798
<ItemGroup>
9899
<Folder Include="Properties\" />

Tools/vsDev/vsDev2.cs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
//css_ref \Prototyping\cppscriptcore\ScriptEngine\packages\Microsoft.VisualStudio.Shell.15.0.15.0.26228\lib\Microsoft.VisualStudio.Shell.15.0.dll
2+
//css_ref C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\Common7\IDE\PublicAssemblies\EnvDTE80.dll
3+
//css_ref \Prototyping\cppscriptcore\ScriptEngine\bin\Debug\ScriptEngine.dll
4+
//css_ref \Prototyping\cppscriptcore\ScriptEngine\packages\Microsoft.VisualStudio.Shell.Interop.7.10.6071\lib\Microsoft.VisualStudio.Shell.Interop.dll
5+
//css_ref \Prototyping\cppscriptcore\ScriptEngine\packages\Microsoft.VisualStudio.OLE.Interop.7.10.6071\lib\Microsoft.VisualStudio.OLE.Interop.dll
6+
//css_ref \Prototyping\cppscriptcore\ScriptEngine\packages\Microsoft.VisualStudio.Shell.Interop.8.0.8.0.50727\lib\Microsoft.VisualStudio.Shell.Interop.8.0.dll
7+
//css_ref \Prototyping\cppscriptcore\ScriptEngine\packages\Microsoft.VisualStudio.Shell.Interop.9.0.9.0.30729\lib\Microsoft.VisualStudio.Shell.Interop.9.0.dll
8+
//css_ref \Prototyping\cppscriptcore\ScriptEngine\packages\Microsoft.VisualStudio.Shell.Interop.10.0.10.0.30319\lib\Microsoft.VisualStudio.Shell.Interop.10.0.dll
9+
//css_ref \Prototyping\cppscriptcore\ScriptEngine\packages\Microsoft.VisualStudio.Shell.Interop.14.0.DesignTime.14.3.25407\lib\Microsoft.VisualStudio.Shell.Interop.14.0.DesignTime.dll
10+
//css_ref \Prototyping\cppscriptcore\ScriptEngine\packages\Microsoft.VisualStudio.Shell.Framework.15.0.26228\lib\net45\Microsoft.VisualStudio.Shell.Framework.dll
11+
//css_ref C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\Common7\IDE\PublicAssemblies\EnvDTE.dll
12+
//css_ref C:\Prototyping\cppscriptcore\bin\ScriptEngineStarter.exe
13+
using EnvDTE;
14+
using EnvDTE80;
15+
using Microsoft.VisualStudio.Shell;
16+
using ScriptEngine;
17+
using System;
18+
using System.Collections.Generic;
19+
using System.Diagnostics;
20+
using System.IO;
21+
using System.Linq;
22+
using System.Reflection;
23+
using System.Text;
24+
using System.Threading.Tasks;
25+
26+
public class vsDev2
27+
{
28+
public static async void Main( object arg )
29+
{
30+
Debug.WriteLine("Started ok.");
31+
}
32+
}
33+

0 commit comments

Comments
 (0)