From 255a47cf96e83e8d11befa9180dc4458f6767188 Mon Sep 17 00:00:00 2001 From: Roy Ben Shabat Date: Thu, 6 Aug 2020 04:34:38 +0300 Subject: Implemented interactive runtime error handling on procedures. --- .../Tango.Scripting.Editors/ScriptEditor.cs | 35 ++++++++++++++++++++++ 1 file changed, 35 insertions(+) (limited to 'Software/Visual_Studio/Scripting/Tango.Scripting.Editors/ScriptEditor.cs') diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/ScriptEditor.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/ScriptEditor.cs index 0802cf456..c650ad425 100644 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/ScriptEditor.cs +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/ScriptEditor.cs @@ -191,6 +191,14 @@ namespace Tango.Scripting.Editors public static readonly DependencyProperty ColorizeBrushProperty = DependencyProperty.Register("ColorizeBrush", typeof(Brush), typeof(ScriptEditor), new PropertyMetadata(new SolidColorBrush(Colors.YellowGreen) { Opacity = 0.5 })); + public Brush ErrorLineBrush + { + get { return (Brush)GetValue(ErrorLineBrushProperty); } + set { SetValue(ErrorLineBrushProperty, value); } + } + public static readonly DependencyProperty ErrorLineBrushProperty = + DependencyProperty.Register("ErrorLineBrush", typeof(Brush), typeof(ScriptEditor), new PropertyMetadata(new SolidColorBrush(Colors.Red) { Opacity = 0.5 })); + #endregion #region Constructors @@ -2486,6 +2494,33 @@ namespace Tango.Scripting.Editors errorMarkerService.RemoveAll(m => true); } + public void HighlightErrorLine(int lineNumber) + { + Document.BeginUpdate(); + + var line = Document.GetLineByNumber(lineNumber); + OffsetColorizer errorLineColrizer = new OffsetColorizer(line, line.Offset, line.EndOffset, ErrorLineBrush); + TextArea.TextView.LineTransformers.Add(errorLineColrizer); + + Document.EndUpdate(); + } + + public Point? GetLineVisualPosition(int lineNumber) + { + double top = TextArea.TextView.GetVisualTopByDocumentLine(lineNumber); + var visualLine = TextArea.TextView.GetVisualLine(lineNumber); + + if (visualLine != null) + { + var textLine = visualLine.GetTextLine(0); + var x = visualLine.GetTextLineVisualXPosition(textLine, visualLine.VisualLengthWithEndOfLineMarker); + var left = visualLine.VisualLengthWithEndOfLineMarker; + return new Point(x, top); + } + + return null; + } + #endregion } } -- cgit v1.3.1 From 92db2f2431bb58a84dc4d476b889fee1de0143e9 Mon Sep 17 00:00:00 2001 From: Roy Ben Shabat Date: Sun, 9 Aug 2020 02:26:07 +0300 Subject: Procedure runtime debugging and exceptions. --- .../BreakPointRequestEventArgs.cs | 31 + .../Contracts/IProcedureDesignerView.cs | 5 + .../Controls/ObjectInTreeView.xaml | 27 + .../Controls/ObjectInTreeView.xaml.cs | 50 ++ .../Tango.FSE.Procedures/Controls/TreeNode.cs | 98 ++++ .../FSE/Modules/Tango.FSE.Procedures/DebugNode.cs | 256 +++++++++ .../Helpers/ProcedureExceptionHelper.cs | 36 ++ .../Tango.FSE.Procedures/IProcedureContext.cs | 19 + .../Tango.FSE.Procedures/ProcedureContext.cs | 46 +- .../Tango.FSE.Procedures.csproj | 12 + .../Tango.FSE.Procedures/Themes/Generic.xaml | 219 +++++++ .../ViewModels/ProcedureDesignerViewVM.cs | 105 +++- .../Views/ProcedureDesignerView.xaml | 37 +- .../Views/ProcedureDesignerView.xaml.cs | 66 +++ .../Sandcastle/SHFBInstaller_v2020.3.6.0.zip | Bin 0 -> 48579276 bytes .../Scripting/Tango.Scripting.Basic/Project.cs | 42 +- .../Scripting/Tango.Scripting.Core/BreakPoint.cs | 14 + .../Tango.Scripting.Core/ScriptBreakPoint.cs | 23 + .../Tango.Scripting.Core/ScriptBreakPointSymbol.cs | 16 + .../Tango.Scripting.Core.csproj | 3 + .../BreakPointSymbolPressedEventArgs.cs | 16 + .../Editing/BreakPointMargin.cs | 285 ++++++++++ .../Images/break_point_arrow.png | Bin 0 -> 453 bytes .../Intellisense/HideIntellisenseAttribute.cs | 12 + .../Intellisense/KnownType.cs | 11 +- .../Tango.Scripting.Editors/ScriptEditor.cs | 229 ++++++++ .../Tango.Scripting.Editors.csproj | 6 + .../Tango.Scripting.Editors_di35u2uj_wpftmp.csproj | 628 +++++++++++++++++++++ .../Tango.Scripting/Parsing/ScriptParser.cs | 23 + .../Tango.Scripting/Parsing/ScriptSymbol.cs | 4 + 30 files changed, 2275 insertions(+), 44 deletions(-) create mode 100644 Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/BreakPointRequestEventArgs.cs create mode 100644 Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/Controls/ObjectInTreeView.xaml create mode 100644 Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/Controls/ObjectInTreeView.xaml.cs create mode 100644 Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/Controls/TreeNode.cs create mode 100644 Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/DebugNode.cs create mode 100644 Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/Helpers/ProcedureExceptionHelper.cs create mode 100644 Software/Visual_Studio/Installers/Sandcastle/SHFBInstaller_v2020.3.6.0.zip create mode 100644 Software/Visual_Studio/Scripting/Tango.Scripting.Core/BreakPoint.cs create mode 100644 Software/Visual_Studio/Scripting/Tango.Scripting.Core/ScriptBreakPoint.cs create mode 100644 Software/Visual_Studio/Scripting/Tango.Scripting.Core/ScriptBreakPointSymbol.cs create mode 100644 Software/Visual_Studio/Scripting/Tango.Scripting.Editors/BreakPointSymbolPressedEventArgs.cs create mode 100644 Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Editing/BreakPointMargin.cs create mode 100644 Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Images/break_point_arrow.png create mode 100644 Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Intellisense/HideIntellisenseAttribute.cs create mode 100644 Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Tango.Scripting.Editors_di35u2uj_wpftmp.csproj (limited to 'Software/Visual_Studio/Scripting/Tango.Scripting.Editors/ScriptEditor.cs') diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/BreakPointRequestEventArgs.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/BreakPointRequestEventArgs.cs new file mode 100644 index 000000000..768f4bb0d --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/BreakPointRequestEventArgs.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Scripting.Basic; +using Tango.Scripting.Core; + +namespace Tango.FSE.Procedures +{ + public class BreakPointRequestEventArgs : EventArgs + { + private Action _releaseAction; + + public int LineNumber { get; set; } + public Script Script { get; set; } + + public List Symbols { get; set; } + + public BreakPointRequestEventArgs(Action releaseAction) + { + Symbols = new List(); + _releaseAction = releaseAction; + } + + public void Release() + { + _releaseAction?.Invoke(); + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/Contracts/IProcedureDesignerView.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/Contracts/IProcedureDesignerView.cs index fa8a4cab6..a16345f65 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/Contracts/IProcedureDesignerView.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/Contracts/IProcedureDesignerView.cs @@ -4,6 +4,8 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using Tango.FSE.Common; +using Tango.Scripting.Basic; +using Tango.Scripting.Core; namespace Tango.FSE.Procedures.Contracts { @@ -24,5 +26,8 @@ namespace Tango.FSE.Procedures.Contracts void ScrollToLine(int lineNumber); void HighlightRuntimeError(int lineNumber); void CloseRunTimeError(); + List GetBreakPoints(); + void HighlightBreakPointRequest(int lineNumber, List symbols); + void ResetBreakPointRequest(); } } diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/Controls/ObjectInTreeView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/Controls/ObjectInTreeView.xaml new file mode 100644 index 000000000..d331935c8 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/Controls/ObjectInTreeView.xaml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/Controls/ObjectInTreeView.xaml.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/Controls/ObjectInTreeView.xaml.cs new file mode 100644 index 000000000..b1d1ee14d --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/Controls/ObjectInTreeView.xaml.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +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; + +namespace Tango.FSE.Procedures.Controls +{ + /// + /// Interaction logic for ObjectInTreeView.xaml + /// + public partial class ObjectInTreeView : UserControl + { + public ObjectInTreeView() + { + InitializeComponent(); + } + + public object ObjectToVisualize + { + get { return (object)GetValue(ObjectToVisualizeProperty); } + set { SetValue(ObjectToVisualizeProperty, value); } + } + public static readonly DependencyProperty ObjectToVisualizeProperty = + DependencyProperty.Register("ObjectToVisualize", typeof(object), typeof(ObjectInTreeView), new PropertyMetadata(null, OnObjectChanged)); + + private static void OnObjectChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + TreeNode tree = TreeNode.CreateTree(e.NewValue); + (d as ObjectInTreeView).TreeNodes = new List() { tree }; + } + + public List TreeNodes + { + get { return (List)GetValue(TreeNodesProperty); } + set { SetValue(TreeNodesProperty, value); } + } + public static readonly DependencyProperty TreeNodesProperty = + DependencyProperty.Register("TreeNodes", typeof(List), typeof(ObjectInTreeView), new PropertyMetadata(null)); + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/Controls/TreeNode.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/Controls/TreeNode.cs new file mode 100644 index 000000000..47407077f --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/Controls/TreeNode.cs @@ -0,0 +1,98 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Web.Script.Serialization; + +namespace Tango.FSE.Procedures.Controls +{ + public class TreeNode + { + public string Name { get; set; } + public string Value { get; set; } + public List Children { get; set; } = new List(); + + public static TreeNode CreateTree(object obj) + { + if (obj.GetType().IsValueTypeOrString()) + { + return new TreeNode() + { + Name = "Value", + Value = obj.ToStringSafe() + }; + } + else + { + JavaScriptSerializer jss = new JavaScriptSerializer(); + var serialized = Newtonsoft.Json.JsonConvert.SerializeObject(obj); + Dictionary dic = jss.Deserialize>(serialized); + var root = new TreeNode(); + root.Name = "Root"; + BuildTree(dic, root); + return root; + } + } + + private static void BuildTree(object item, TreeNode node) + { + if (item is KeyValuePair) + { + KeyValuePair kv = (KeyValuePair)item; + TreeNode keyValueNode = new TreeNode(); + keyValueNode.Name = kv.Key; + keyValueNode.Value = GetValueAsString(kv.Value); + node.Children.Add(keyValueNode); + BuildTree(kv.Value, keyValueNode); + } + else if (item is ArrayList) + { + ArrayList list = (ArrayList)item; + int index = 0; + foreach (object value in list) + { + TreeNode arrayItem = new TreeNode(); + arrayItem.Name = $"[{index}]"; + arrayItem.Value = ""; + node.Children.Add(arrayItem); + BuildTree(value, arrayItem); + index++; + } + } + else if (item is Dictionary) + { + Dictionary dictionary = (Dictionary)item; + foreach (KeyValuePair d in dictionary) + { + BuildTree(d, node); + } + } + } + + private static string GetValueAsString(object value) + { + if (value == null) + return "null"; + var type = value.GetType(); + if (type.IsArray) + { + return "[]"; + } + + if (value is ArrayList) + { + var arr = value as ArrayList; + return $"[{arr.Count}]"; + } + + if (type.IsGenericType) + { + return "{}"; + } + + return value.ToString(); + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/DebugNode.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/DebugNode.cs new file mode 100644 index 000000000..81f29c96c --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/DebugNode.cs @@ -0,0 +1,256 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using Tango.Core; +using Tango.Core.Commands; + +namespace Tango.FSE.Procedures +{ + public class DebugNode : ExtendedObject + { + private Object _originalValue; + + public String Name { get; set; } + public Object ParentObject { get; set; } + + private Object _value; + public Object Value + { + get { return _value; } + set + { + _value = value; + + if (_originalValue == null) + { + _originalValue = _value; + } + + DisplayValue = GetDisplayValue(_value); + RaisePropertyChangedAuto(); + } + } + + public bool IsSimpleValue { get; set; } + + public String Type { get; set; } + public PropertyInfo PropertyInfo { get; set; } + public FieldInfo FieldInfo { get; set; } + + public Type MemberType + { + get + { + if (PropertyInfo != null) + { + return PropertyInfo.PropertyType; + } + else if (FieldInfo != null) + { + return FieldInfo.FieldType; + } + else + { + return Value.GetType(); + } + } + } + + private bool _isEdited; + public bool IsEdited + { + get { return _isEdited; } + set { _isEdited = value; RaisePropertyChangedAuto(); } + } + + public RelayCommand UpdateValueCommand { get; set; } + + public bool IsEditable + { + get + { + if (IsSimpleValue) + { + return false; //Sorry can't update simple script symbols as they are passed to me by value... + } + + if (MemberType != null && MemberType.IsValueTypeOrString() && ((PropertyInfo != null && PropertyInfo.SetMethod != null) || FieldInfo != null)) + { + return true; + } + + return false; + } + } + + private Object _displayValue; + public Object DisplayValue + { + get { return _displayValue; } + set { _displayValue = value; RaisePropertyChangedAuto(); } + } + + public List Nodes + { + get + { + return GetChildNodes(); + } + } + + public DebugNode() + { + UpdateValueCommand = new RelayCommand(UpdateValue); + } + + private void UpdateValue() + { + try + { + if (IsSimpleValue && Value != null) + { + _value = Convert.ChangeType(DisplayValue, Value.GetType()); + IsEdited = _originalValue.ToStringSafe() != Value.ToStringSafe(); + } + else if (IsEditable && ((PropertyInfo != null && PropertyInfo.SetMethod != null) || FieldInfo != null)) + { + if (PropertyInfo != null) + { + _value = Convert.ChangeType(DisplayValue, PropertyInfo.PropertyType); + PropertyInfo.SetValue(ParentObject, Value); + IsEdited = _originalValue.ToStringSafe() != Value.ToStringSafe(); + } + else if (FieldInfo != null) + { + _value = Convert.ChangeType(DisplayValue, FieldInfo.FieldType); + FieldInfo.SetValue(ParentObject, Value); + IsEdited = _originalValue.ToStringSafe() != Value.ToStringSafe(); + } + } + } + catch { } + + DisplayValue = GetDisplayValue(Value); + } + + private List GetChildNodes() + { + List childNodes = new List(); + + if (Value == null) return childNodes; + + var type = Value.GetType(); + + if (type.IsValueTypeOrString()) + { + return childNodes; + } + + if (typeof(IEnumerable).IsAssignableFrom(type) && type != typeof(String)) + { + List list = (Value as IEnumerable).Cast().ToList(); + + for (int i = 0; i < list.Count; i++) + { + var item = list[i]; + + DebugNode listNode = new DebugNode(); + listNode.Name = $"[{i}]"; + listNode.Value = item; + listNode.Type = GetFriendlyName(item.GetType()); + childNodes.Add(listNode); + } + } + else + { + foreach (var prop in type.GetProperties(BindingFlags.Instance | BindingFlags.Public)) + { + DebugNode propNode = new DebugNode(); + propNode.Type = GetFriendlyName(prop.PropertyType); + propNode.Name = prop.Name; + propNode.Value = prop.GetValue(Value); + propNode.PropertyInfo = prop; + propNode.ParentObject = Value; + childNodes.Add(propNode); + } + + foreach (var field in type.GetFields(BindingFlags.Instance | BindingFlags.Public)) + { + DebugNode propNode = new DebugNode(); + propNode.Type = GetFriendlyName(field.FieldType); + propNode.Name = field.Name; + propNode.Value = field.GetValue(Value); + propNode.FieldInfo = field; + propNode.ParentObject = Value; + childNodes.Add(propNode); + } + } + + return childNodes; + } + + public static DebugNode CreateNode(String name, Object obj) + { + DebugNode node = new DebugNode(); + node.Name = name; + node.Value = obj; + node.Type = GetFriendlyName(obj.GetType()); + + if (obj.GetType().IsValueTypeOrString()) + { + node.IsSimpleValue = true; + } + + return node; + } + + private static String GetFriendlyName(Type type) + { + if (type == typeof(int)) + return "int"; + else if (type == typeof(short)) + return "short"; + else if (type == typeof(byte)) + return "byte"; + else if (type == typeof(bool)) + return "bool"; + else if (type == typeof(long)) + return "long"; + else if (type == typeof(float)) + return "float"; + else if (type == typeof(double)) + return "double"; + else if (type == typeof(decimal)) + return "decimal"; + else if (type == typeof(string)) + return "string"; + else if (type.IsGenericType) + return type.Name.Split('`')[0] + "<" + string.Join(", ", type.GetGenericArguments().Select(x => GetFriendlyName(x)).ToArray()) + ">"; + else + return type.Name; + } + + private static Object GetDisplayValue(Object value) + { + if (value == null) + { + return "null"; + } + else if (value.GetType().IsValueTypeOrString()) + { + return value; + } + else if (typeof(IEnumerable).IsAssignableFrom(value.GetType())) + { + List list = (value as IEnumerable).Cast().ToList(); + return $"Count = {list.Count}"; + } + + return value.ToStringSafe(); + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/Helpers/ProcedureExceptionHelper.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/Helpers/ProcedureExceptionHelper.cs new file mode 100644 index 000000000..7a57681e7 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/Helpers/ProcedureExceptionHelper.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace Tango.FSE.Procedures.Helpers +{ + public static class ProcedureExceptionHelper + { + public static int? GetExceptionLineNumber(Exception ex, ProcedureProject project) + { + try + { + Regex regex = new Regex(@"OnExecute\(IProcedureContext context\) in :line (\d+)"); + var matches = regex.Matches(ex.ToString()).OfType().ToList(); + + if (matches.Count > 0) + { + var match = matches.First(); + + if (match.Groups.Count > 1) + { + var line = match.Groups[1].Value; + int lineNumber = int.Parse(line) - project.Scripts.Count + 1; + return lineNumber; + } + } + } + catch { } + + return null; + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/IProcedureContext.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/IProcedureContext.cs index e93311d80..8dafe2291 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/IProcedureContext.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/IProcedureContext.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.Drawing; using System.Linq; +using System.Runtime.CompilerServices; using System.Text; using System.Threading; using System.Threading.Tasks; @@ -14,6 +15,7 @@ using Tango.FSE.Common.Connection; using Tango.FSE.Common.Diagnostics; using Tango.Integration.Operation; using Tango.Scripting.Basic; +using Tango.Scripting.Editors.Intellisense; namespace Tango.FSE.Procedures { @@ -22,11 +24,19 @@ namespace Tango.FSE.Procedures /// /// Occurs when the procedure is reporting about some progress. /// + [HideIntellisense] event EventHandler> Progress; + /// + /// Occurs when a procedure object break point request occurs through the IDE break points. + /// + [HideIntellisense] + event EventHandler BreakPointRequest; + /// /// Gets the list of current results. /// + [HideIntellisense] ReadOnlyCollection Results { get; } /// @@ -469,5 +479,14 @@ namespace Tango.FSE.Procedures /// The file path. /// The items to write. void WriteCsv(String file, List items); + + /// + /// Request a breakpoint operation from the host IDE (internal use only). + /// + /// The file. + /// The line number. + /// The symbols map. + [HideIntellisense] + void BreakPoint(String file, int lineNumber, params Object[] symbolsMap); } } diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/ProcedureContext.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/ProcedureContext.cs index 88ab8dae9..0f422c5f5 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/ProcedureContext.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/ProcedureContext.cs @@ -9,6 +9,7 @@ using System.Linq; using System.Reactive.Concurrency; using System.Reactive.Linq; using System.Reflection; +using System.Runtime.CompilerServices; using System.Text; using System.Threading; using System.Threading.Tasks; @@ -25,9 +26,11 @@ using Tango.FSE.Common.Diagnostics; using Tango.FSE.Common.Notifications; using Tango.FSE.Common.Threading; using Tango.FSE.Procedures.Dialogs; +using Tango.FSE.Procedures.Helpers; using Tango.Integration.Operation; using Tango.PMR; using Tango.Scripting.Basic; +using Tango.Scripting.Core; namespace Tango.FSE.Procedures { @@ -38,6 +41,10 @@ namespace Tango.FSE.Procedures private Dictionary _inputs; private DiagnosticsFrame _lastDiagnosticsFrame; + public event EventHandler> Progress; + + public event EventHandler BreakPointRequest; + [TangoInject] private IMachineProvider MachineProvider { get; set; } @@ -561,8 +568,6 @@ namespace Tango.FSE.Procedures }); } - public event EventHandler> Progress; - public Result AddBitmapResult(ResultType type, String name, Bitmap bitmap) { return AddResult(new Result() @@ -799,5 +804,42 @@ namespace Tango.FSE.Procedures csvFile.Dispose(); } + + public void BreakPoint(string file, int lineNumber, params object[] symbolsMap) + { + if (BreakPointRequest != null && symbolsMap.Length > 0) + { + bool released = false; + + BreakPointRequestEventArgs args = new BreakPointRequestEventArgs(() => + { + released = true; + }); + + args.LineNumber = lineNumber; + args.Script = _project.Scripts.SingleOrDefault(x => x.Name == file); + + for (int i = 0; i < symbolsMap.Length; i += 4) + { + args.Symbols.Add(new ScriptBreakPointSymbol() + { + Name = symbolsMap[i].ToString(), + Offset = (int)symbolsMap[i + 1], + Length = (int)symbolsMap[i + 2], + SymbolObject = symbolsMap[i + 3], + }); + } + + DispatcherProvider.Invoke(() => + { + BreakPointRequest?.Invoke(this, args); + }); + + while (!released) + { + Thread.Sleep(100); + } + } + } } } diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/Tango.FSE.Procedures.csproj b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/Tango.FSE.Procedures.csproj index fcd5c7603..03ae31168 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/Tango.FSE.Procedures.csproj +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/Tango.FSE.Procedures.csproj @@ -80,6 +80,7 @@ ..\..\..\packages\System.Reactive.Windows.Threading.3.1.1\lib\net45\System.Reactive.Windows.Threading.dll + @@ -100,12 +101,18 @@ + + + ObjectInTreeView.xaml + + + @@ -142,6 +149,7 @@ UserInputDialogView.xaml + @@ -300,6 +308,10 @@ MSBuild:Compile Designer + + Designer + MSBuild:Compile + Designer MSBuild:Compile diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/Themes/Generic.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/Themes/Generic.xaml index 06e60997d..661eb5405 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/Themes/Generic.xaml +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/Themes/Generic.xaml @@ -2,6 +2,8 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:realTimeGraphX="clr-namespace:RealTimeGraphX.WPF;assembly=RealTimeGraphX.WPF" xmlns:commonGraph="clr-namespace:Tango.FSE.Common.Graphs;assembly=Tango.FSE.Common" + xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" + xmlns:material="http://materialdesigninxaml.net/winfx/xaml/themes" xmlns:local="clr-namespace:Tango.FSE.Procedures.Themes"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [ + + ] + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/ViewModels/ProcedureDesignerViewVM.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/ViewModels/ProcedureDesignerViewVM.cs index bd36350c1..8b3912c32 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/ViewModels/ProcedureDesignerViewVM.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/ViewModels/ProcedureDesignerViewVM.cs @@ -59,6 +59,7 @@ namespace Tango.FSE.Procedures.ViewModels private String PROJECT_DIALOG_FILTER = $"Procedure Project Files|*.pproj"; private bool _isProjectChanged; private TaskItem _symbolsTaskItem; + private BreakPointRequestEventArgs _lastBreakPointRequestArgs; #region Properties @@ -215,6 +216,20 @@ namespace Tango.FSE.Procedures.ViewModels set { _runtimeErrorFree = value; RaisePropertyChangedAuto(); } } + private bool _isBreakPoint; + public bool IsBreakPoint + { + get { return _isBreakPoint; } + set { _isBreakPoint = value; RaisePropertyChangedAuto(); InvalidateRelayCommands(); } + } + + private bool _isReadOnly; + public bool IsReadOnly + { + get { return _isReadOnly; } + set { _isReadOnly = value; RaisePropertyChangedAuto(); } + } + #endregion #region Commands @@ -260,6 +275,7 @@ namespace Tango.FSE.Procedures.ViewModels public RelayCommand OpenResourceCommand { get; set; } public RelayCommand ExportResourceCommand { get; set; } public RelayCommand CloseRuntimeErrorCommand { get; set; } + public RelayCommand ContinueProjectCommand { get; set; } #endregion @@ -288,7 +304,7 @@ namespace Tango.FSE.Procedures.ViewModels OpenScripts = new ObservableCollection