diff options
29 files changed, 853 insertions, 220 deletions
diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/ITestContext.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/ITestContext.cs index 671b2174a..41b13f2d2 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/ITestContext.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/ITestContext.cs @@ -1,6 +1,7 @@ using Google.Protobuf; using System; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -11,6 +12,11 @@ namespace Tango.FSE.Stubs { public interface ITestContext : IContext { + ReadOnlyCollection<Result> Results { get; } + Result AddResult(ResultType type, String name, object value); + Result AddResult(Result result); + void RemoveResult(Result result); + void ClearResults(); IMessage Run(String stubName, params Object[] args); IMessage Run(IMessage stub); void RunContinuous<T>(T stub, Action<T> callback) where T : class, IMessage; diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/ITestLogger.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/ITestLogger.cs new file mode 100644 index 000000000..286bc07ea --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/ITestLogger.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.FSE.Stubs +{ + public interface ITestLogger + { + void WriteLine(String text); + void Write(String text); + void Clear(); + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/ProjectRunner.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/ProjectRunner.cs index 00ab0caca..de93305d8 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/ProjectRunner.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/ProjectRunner.cs @@ -10,63 +10,104 @@ namespace Tango.FSE.Stubs { public class ProjectRunner : ExtendedObject { - private ProjectSession _currentSession; + private ProjectSession<ITestContext> _currentSession; private ProjectRunnerState _state; public ProjectRunnerState State { get { return _state; } - private set { _state = value; RaisePropertyChangedAuto(); RaisePropertyChanged(nameof(IsRunning)); } + private set + { + _state = value; + RaisePropertyChangedAuto(); + RaisePropertyChanged(nameof(IsRunning)); + RaisePropertyChanged(nameof(IsCompiling)); + RaisePropertyChanged(nameof(CanRun)); + RaisePropertyChanged(nameof(CanCompile)); + } } public bool IsRunning { - get { return State == ProjectRunnerState.Compiling || State == ProjectRunnerState.Running; } + get { return State == ProjectRunnerState.Running; } + } + + public bool IsCompiling + { + get { return State == ProjectRunnerState.Compiling; } } - public Project Project { get; private set; } + public bool CanCompile + { + get { return State != ProjectRunnerState.Running && State != ProjectRunnerState.Compiling; } + } - public ProjectRunner(Project project) + public bool CanRun + { + get { return State != ProjectRunnerState.Running && State != ProjectRunnerState.Compiling; } + } + + public Project<ITestContext> Project { get; private set; } + + public ProjectRunner(Project<ITestContext> project) { Project = project; } - public async Task<Object> Run() + public async Task<CompilationResult> Compile() { - if (State != ProjectRunnerState.Compiling && State != ProjectRunnerState.Running) + try + { + State = ProjectRunnerState.Compiling; + var result = await Project.Compile(); + State = ProjectRunnerState.None; + return result; + } + catch (Exception) + { + throw; + } + finally { - try - { - State = ProjectRunnerState.Compiling; - _currentSession = await Project.Run(null); - } - catch (Exception ex) - { - State = ProjectRunnerState.None; - throw ex; - } + State = ProjectRunnerState.None; + } + } - State = ProjectRunnerState.Running; + public async Task Run(TestContext context) + { + if (!CanRun) + { + throw new InvalidOperationException("Project is already running."); + } - try - { - var result = await _currentSession.WaitForCompletion(); - State = ProjectRunnerState.Completed; - return result; - } - catch (OperationCanceledException) - { - State = ProjectRunnerState.Aborted; - throw; - } - catch (Exception) - { - State = ProjectRunnerState.Failed; - throw; - } + try + { + State = ProjectRunnerState.Compiling; + _currentSession = await Project.Run(context); + } + catch (Exception ex) + { + State = ProjectRunnerState.None; + throw ex; } - throw new InvalidOperationException("Project is already running."); + State = ProjectRunnerState.Running; + + try + { + var result = await _currentSession.WaitForCompletion(); + State = ProjectRunnerState.Completed; + } + catch (OperationCanceledException) + { + State = ProjectRunnerState.Aborted; + throw; + } + catch (Exception) + { + State = ProjectRunnerState.Failed; + throw; + } } public void Stop() diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Resources/main_template.csx b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Resources/main_template.csx index 34604c6d3..c50f70c5f 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Resources/main_template.csx +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Resources/main_template.csx @@ -1,19 +1,18 @@ using System; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.Linq; using System.Text; +using System.Threading; using System.Threading.Tasks; using Tango.FSE.Stubs; public class Program { - public Object OnExecute(ITestContext context) + public void OnExecute(ITestContext context) { - return new - { - Item1 = "Item 1", - Item2 = "Item 2" - }; + context.AddResult(ResultType.Passed, "My Value Name", "Test for this value has passed."); + } }
\ No newline at end of file diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Result.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Result.cs new file mode 100644 index 000000000..74f95a437 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Result.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Core.ExtensionMethods; + +namespace Tango.FSE.Stubs +{ + public class Result + { + public ResultType Type { get; set; } + public String Name { get; set; } + public Object Value { get; set; } + + public Result() + { + + } + + public Result(ResultType type, String name, Object value) : this() + { + Type = type; + Name = name; + Value = value; + } + + public override string ToString() + { + return this.ToJsonString(); + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/ResultType.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/ResultType.cs new file mode 100644 index 000000000..e19f58b4f --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/ResultType.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.FSE.Stubs +{ + public enum ResultType + { + Passed, + Failed, + Warning, + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Tango.FSE.Stubs.csproj b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Tango.FSE.Stubs.csproj index 9058bf074..faf3615be 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Tango.FSE.Stubs.csproj +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Tango.FSE.Stubs.csproj @@ -61,6 +61,7 @@ <Reference Include="System" /> <Reference Include="System.ComponentModel.DataAnnotations" /> <Reference Include="System.Data" /> + <Reference Include="System.Drawing" /> <Reference Include="System.Reactive.Core, Version=3.0.3000.0, Culture=neutral, PublicKeyToken=94bc3704cddfc263, processorArchitecture=MSIL"> <HintPath>..\..\..\packages\System.Reactive.Core.3.1.1\lib\net46\System.Reactive.Core.dll</HintPath> </Reference> @@ -97,8 +98,11 @@ <Compile Include="Designer\ProjectModel.cs" /> <Compile Include="Designer\ScriptTabModel.cs" /> <Compile Include="ITestContext.cs" /> + <Compile Include="ITestLogger.cs" /> <Compile Include="ProjectRunner.cs" /> <Compile Include="ProjectRunnerState.cs" /> + <Compile Include="Result.cs" /> + <Compile Include="ResultType.cs" /> <Compile Include="TestContext.cs" /> <Compile Include="ViewModelLocator.cs" /> <Compile Include="StubsModule.cs" /> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/TestContext.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/TestContext.cs index e40ccebfc..83823a27c 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/TestContext.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/TestContext.cs @@ -1,5 +1,7 @@ using System; using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.IO; using System.Linq; using System.Reflection; using System.Text; @@ -7,6 +9,7 @@ using System.Threading; using System.Threading.Tasks; using Google.Protobuf; using Tango.Core.DI; +using Tango.FSE.Common.Connection; using Tango.FSE.Common.Notifications; using Tango.FSE.Common.Threading; using Tango.Integration.Operation; @@ -17,15 +20,23 @@ namespace Tango.FSE.Stubs { public class TestContext : ITestContext { - private IMachineOperator _machineOperator; - private INotificationProvider _notificationProvider; - private IDispatcherProvider _dispatcherProvider; + private ITestLogger _logger; - public TestContext(IMachineOperator machineOperator, INotificationProvider notificationProvider, IDispatcherProvider dispatcherProvider) + [TangoInject] + private IMachineProvider MachineProvider; + + [TangoInject] + private INotificationProvider NotificationProvider { get; set; } + + [TangoInject] + private IDispatcherProvider DispatcherProvider { get; set; } + + public ReadOnlyCollection<Result> Results { get; private set; } + + public TestContext(ITestLogger logger) { - _machineOperator = machineOperator; - _notificationProvider = notificationProvider; - _dispatcherProvider = dispatcherProvider; + _logger = logger; + Results = new ReadOnlyCollection<Result>(new List<Result>()); } public IMessage Run(string stubName, params object[] args) @@ -74,14 +85,14 @@ namespace Tango.FSE.Stubs public IMessage Run(IMessage stub) { - return _machineOperator.SendRequest(stub, new Transport.TransportRequestConfig()).Result; + return MachineProvider.MachineOperator.SendRequest(stub, new Transport.TransportRequestConfig()).Result; } public void RunContinuous<T>(T stub, Action<T> callback) where T : class, IMessage { Type stubType = stub.GetType(); - _machineOperator.SendContinuousRequest(stub, new Transport.TransportContinuousRequestConfig()).Subscribe((msg) => + MachineProvider.MachineOperator.SendContinuousRequest(stub, new Transport.TransportContinuousRequestConfig()).Subscribe((msg) => { callback?.Invoke(msg as T); @@ -143,37 +154,63 @@ namespace Tango.FSE.Stubs public void WriteLine(object obj) { - throw new NotImplementedException(); + _logger?.WriteLine(obj != null ? obj.ToString() : "null"); } public void Write(object obj) { - throw new NotImplementedException(); + _logger?.Write(obj != null ? obj.ToString() : "null"); } public void WriteLineHex(object number, int digits) { - throw new NotImplementedException(); + _logger?.WriteLine("#" + Convert.ToInt32(number).ToString("X" + digits.ToString())); } public void WriteHex(object number, int digits) { - throw new NotImplementedException(); + _logger?.Write("#" + Convert.ToInt32(number).ToString("X" + digits.ToString())); } public void Clear() { - throw new NotImplementedException(); + _logger?.Clear(); } public void WriteToFile(string filePath, string content) { - throw new NotImplementedException(); + File.WriteAllText(filePath, content); } public void AppendToFile(string filePath, string content) { - throw new NotImplementedException(); + File.AppendAllText(filePath, content); + } + + public Result AddResult(ResultType type, string name, object value) + { + var result = new Result(type, name, value); + return AddResult(result); + } + + public Result AddResult(Result result) + { + List<Result> results = new List<Result>(Results); + results.Add(result); + Results = new ReadOnlyCollection<Result>(results); + return result; + } + + public void RemoveResult(Result result) + { + List<Result> results = new List<Result>(Results); + results.Remove(result); + Results = new ReadOnlyCollection<Result>(results); + } + + public void ClearResults() + { + Results = new ReadOnlyCollection<Result>(new List<Result>()); } } } diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/ViewModels/TestDesignerViewVM.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/ViewModels/TestDesignerViewVM.cs index 6e6873c9a..d87fe0ff3 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/ViewModels/TestDesignerViewVM.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/ViewModels/TestDesignerViewVM.cs @@ -5,18 +5,38 @@ using System.Collections.ObjectModel; using System.Linq; using System.Text; using System.Threading.Tasks; +using System.Windows.Input; +using Tango.Core; using Tango.Core.Commands; +using Tango.Core.ExtensionMethods; using Tango.FSE.Common; using Tango.Integration.Operation; using Tango.Scripting.Basic; +using Tango.Scripting.Editors; +using Tango.SharedUI.Components; +using Tango.SharedUI.Helpers; using Tango.Transport; namespace Tango.FSE.Stubs.ViewModels { - public class TestDesignerViewVM : FSEViewModel + public class TestDesignerViewVM : FSEViewModel, ITestLogger { - private Project _project; - public Project Project + public enum ToolWindows + { + Output, + Errors, + Results + } + + private ToolWindows _selectedToolWindow; + public ToolWindows SelectedToolWindow + { + get { return _selectedToolWindow; } + set { _selectedToolWindow = value; RaisePropertyChangedAuto(); } + } + + private Project<ITestContext> _project; + public Project<ITestContext> Project { get { return _project; } set { _project = value; RaisePropertyChangedAuto(); OnProjectChanged(); } @@ -29,6 +49,13 @@ namespace Tango.FSE.Stubs.ViewModels set { _projectRunner = value; RaisePropertyChangedAuto(); } } + private List<CompilationError> _compilationErrors; + public List<CompilationError> CompilationErrors + { + get { return _compilationErrors; } + set { _compilationErrors = value; RaisePropertyChangedAuto(); } + } + public ObservableCollection<Script> OpenScripts { get; set; } private Script _selectedScript; @@ -38,41 +65,144 @@ namespace Tango.FSE.Stubs.ViewModels set { _selectedScript = value; RaisePropertyChangedAuto(); } } + public TextController Logger { get; set; } + + private String _status; + public String Status + { + get { return _status; } + set { _status = value; RaisePropertyChangedAuto(); } + } + + private TangoProgress<int> _cacheProgress; + public TangoProgress<int> SymbolsLoadingProgress + { + get { return _cacheProgress; } + set { _cacheProgress = value; RaisePropertyChangedAuto(); } + } + + private bool _isCaching; + public bool IsLoadingSymbols + { + get { return _isCaching; } + set { _isCaching = value; RaisePropertyChangedAuto(); } + } + public RelayCommand<Script> OpenScriptCommand { get; set; } public RelayCommand<Script> CloseScriptCommand { get; set; } public RelayCommand RunProjectCommand { get; set; } public RelayCommand StopProjectCommand { get; set; } + public RelayCommand CompileProjectCommand { get; set; } public TestDesignerViewVM() { + Status = "Ready"; + + CompilationErrors = new List<CompilationError>(); + Logger = new TextController(); + ScriptEditor.LoadingSymbolsProgress += ScriptEditor_LoadingSymbolsProgress; + ScriptEditor.LoadingSymbolsStarted += ScriptEditor_LoadingSymbolsStarted; + ScriptEditor.LoadingSymbolsCompleted += ScriptEditor_LoadingSymbolsCompleted; + ScriptEditor.BlockedUsingsCache.Add("Tango.FSE.Stubs"); + OpenScripts = new ObservableCollection<Script>(); OpenScriptCommand = new RelayCommand<Script>(OpenScript); CloseScriptCommand = new RelayCommand<Script>(CloseScript); RunProjectCommand = new RelayCommand(RunProject); StopProjectCommand = new RelayCommand(StopProject); + CompileProjectCommand = new RelayCommand(async () => await CompileProject()); CreateNewProject(); } + private void ScriptEditor_LoadingSymbolsCompleted(object sender, EventArgs e) + { + IsLoadingSymbols = false; + } + + private void ScriptEditor_LoadingSymbolsStarted(object sender, EventArgs e) + { + IsLoadingSymbols = true; + } + + private void ScriptEditor_LoadingSymbolsProgress(object sender, Core.TangoProgressChangedEventArgs<int> e) + { + SymbolsLoadingProgress = e.Progress; + } + private void StopProject() { ProjectRunner.Stop(); } + private async Task<bool> CompileProject() + { + try + { + Mouse.OverrideCursor = Cursors.AppStarting; + IsFree = false; + Logger.Clear(); + SelectedToolWindow = ToolWindows.Output; + Logger.WriteLine("Compiling project..."); + Status = "Compiling project..."; + UIHelper.DoEvents(); + + var result = await ProjectRunner.Compile(); + CompilationErrors = result.Errors; + + if (CompilationErrors.Count > 0) + { + Logger.WriteLine("Project compiled with errors."); + Status = "Project compiled with errors."; + SelectedToolWindow = ToolWindows.Errors; + return false; + } + else + { + SelectedToolWindow = ToolWindows.Output; + Status = "Project compiled successfully."; + Logger.WriteLine("Project compiled successfully."); + return true; + } + } + catch (Exception ex) + { + Logger.WriteLine($"Error compiling the project.\n{ex.FlattenMessage()}"); + await NotificationProvider.ShowError($"Error compiling the project.\n{ex.FlattenMessage()}"); + return false; + } + finally + { + Mouse.OverrideCursor = null; + Status = "Ready"; + IsFree = true; + } + } + private async void RunProject() { try { - var obj = await ProjectRunner.Run(); - await NotificationProvider.ShowSuccess(obj.ToString()); + if (await CompileProject()) + { + SelectedToolWindow = ToolWindows.Output; + Logger.Clear(); + Logger.WriteLine("Running project..."); + var context = new TestContext(this); + await ProjectRunner.Run(context); + Logger.WriteLine("Project ran to completion with test result:"); + Logger.WriteLine(context.Results.ToJsonString()); + } } catch (OperationCanceledException) { - //Do nothing. + Logger.WriteLine("Project terminated by user."); } catch (Exception ex) { - await NotificationProvider.ShowError(ex.FlattenMessage()); + SelectedToolWindow = ToolWindows.Output; + Logger.WriteLine("Project terminated with error:"); + Logger.WriteLine(ex.FlattenException()); } } @@ -95,7 +225,7 @@ namespace Tango.FSE.Stubs.ViewModels private void CreateNewProject() { - var project = Project.New("test1"); + var project = Project<ITestContext>.New("test1"); project.Scripts.Add(Script.New("Program.csx", Encoding.UTF8.GetString(Properties.Resources.main_template), true)); project.Scripts.Add(Script.New("lib.csx", Encoding.UTF8.GetString(Properties.Resources.lib_template))); project.ReferenceAssemblies.Add(new ReferenceAssembly() { FromType = this.GetType() }); @@ -103,6 +233,7 @@ namespace Tango.FSE.Stubs.ViewModels project.ReferenceAssemblies.Add(new ReferenceAssembly() { FromType = typeof(ITransporter) }); project.ReferenceAssemblies.Add(new ReferenceAssembly() { FromType = typeof(IMachineOperator) }); project.ReferenceAssemblies.Add(new ReferenceAssembly() { FromType = typeof(IMessage) }); + project.ReferenceAssemblies.Add(new ReferenceAssembly() { FromType = typeof(System.Drawing.Point) }); Project = project; } @@ -118,5 +249,20 @@ namespace Tango.FSE.Stubs.ViewModels ProjectRunner = null; } } + + public void WriteLine(string text) + { + Logger.WriteLine(text); + } + + public void Write(string text) + { + Logger.Write(text); + } + + public void Clear() + { + Logger.Clear(); + } } } diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Views/TestDesignerView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Views/TestDesignerView.xaml index 1b5e52db7..467d106f7 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Views/TestDesignerView.xaml +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Views/TestDesignerView.xaml @@ -5,6 +5,7 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:global="clr-namespace:Tango.FSE.Stubs" xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" + xmlns:components="clr-namespace:Tango.SharedUI.Components;assembly=Tango.SharedUI" xmlns:vm="clr-namespace:Tango.FSE.Stubs.ViewModels" xmlns:material="http://materialdesigninxaml.net/winfx/xaml/themes" xmlns:editors="clr-namespace:Tango.Scripting.Editors;assembly=Tango.Scripting.Editors" @@ -56,7 +57,23 @@ </MenuItem.Icon> </MenuItem> </MenuItem> - <MenuItem Header="Debug"></MenuItem> + <MenuItem Header="Debug"> + <MenuItem Header="_Build" Command="{Binding CompileProjectCommand}" InputGestureText="Shift+F6" IsEnabled="{Binding ProjectRunner.CanCompile}"> + <MenuItem.Icon> + <material:PackIcon Kind="PackageDown" /> + </MenuItem.Icon> + </MenuItem> + <MenuItem Header="_Start" Command="{Binding RunProjectCommand}" InputGestureText="F5" Visibility="{Binding ProjectRunner.CanRun,Converter={StaticResource BooleanToVisibilityConverter}}"> + <MenuItem.Icon> + <material:PackIcon Kind="Play" Foreground="{StaticResource FSE_GreenBrush}" /> + </MenuItem.Icon> + </MenuItem> + <MenuItem Header="_Stop" Command="{Binding StopProjectCommand}" Visibility="{Binding ProjectRunner.IsRunning,Converter={StaticResource BooleanToVisibilityConverter}}"> + <MenuItem.Icon> + <material:PackIcon Kind="Stop" Foreground="{StaticResource FSE_RedBrush}" /> + </MenuItem.Icon> + </MenuItem> + </MenuItem> <MenuItem Header="Publish"></MenuItem> </Menu> @@ -85,13 +102,13 @@ <material:PackIcon Kind="ContentPaste" /> </Button> <Separator/> - <Button ToolTip="Run (F5)" ToolBar.OverflowMode="AsNeeded" Command="{Binding RunProjectCommand}" Visibility="{Binding ProjectRunner.IsRunning,Converter={StaticResource BooleanToVisibilityInverseConverter}}"> + <Button Width="120" ToolTip="Run (F5)" ToolBar.OverflowMode="AsNeeded" Command="{Binding RunProjectCommand}" Visibility="{Binding ProjectRunner.IsRunning,Converter={StaticResource BooleanToVisibilityInverseConverter}}" IsEnabled="{Binding ProjectRunner.CanRun}"> <DockPanel> <material:PackIcon Kind="Play" Foreground="{StaticResource FSE_GreenBrush}" /> <TextBlock Margin="5 0 0 0" VerticalAlignment="Center">Start</TextBlock> </DockPanel> </Button> - <Button ToolTip="Stop" ToolBar.OverflowMode="AsNeeded" Command="{Binding StopProjectCommand}" Visibility="{Binding ProjectRunner.IsRunning,Converter={StaticResource BooleanToVisibilityConverter}}"> + <Button Width="120" ToolTip="Stop" ToolBar.OverflowMode="AsNeeded" Command="{Binding StopProjectCommand}" Visibility="{Binding ProjectRunner.IsRunning,Converter={StaticResource BooleanToVisibilityConverter}}"> <DockPanel> <material:PackIcon Kind="Stop" Foreground="{StaticResource FSE_RedBrush}" /> <TextBlock Margin="5 0 0 0" VerticalAlignment="Center">Stop</TextBlock> @@ -100,8 +117,21 @@ </ToolBar> </Grid> - <Grid DockPanel.Dock="Bottom" Height="25" Background="{StaticResource FSE_PrimaryAccentDarkBrush}"> + <Grid DockPanel.Dock="Bottom" Height="25" Background="#007BA5" TextElement.FontSize="{StaticResource FSE_SmallFontSize}"> <!--Status Bar--> + <Grid> + <StackPanel HorizontalAlignment="Left" Orientation="Horizontal" Margin="5 0 0 0"> + <TextBlock VerticalAlignment="Center" Text="{Binding Status}"></TextBlock> + </StackPanel> + + <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="0 0 5 0"> + <StackPanel Orientation="Horizontal" Visibility="{Binding IsLoadingSymbols,Converter={StaticResource BooleanToVisibilityConverter}}"> + <Separator Margin="10 0" /> + <TextBlock VerticalAlignment="Center" Text="{Binding SymbolsLoadingProgress.Message,Mode=OneWay}"></TextBlock> + <ProgressBar Margin="10 0 0 0" Foreground="{StaticResource FSE_PrimaryBackgroundBrush}" Width="200" Height="15" VerticalAlignment="Center" Maximum="{Binding SymbolsLoadingProgress.Maximum}" Value="{Binding SymbolsLoadingProgress.Value}" IsIndeterminate="{Binding SymbolsLoadingProgress.IsIndeterminate}" /> + </StackPanel> + </StackPanel> + </Grid> </Grid> <Grid> @@ -239,9 +269,41 @@ <Grid Grid.Row="2"> <!--Output & Error Tabs--> - <TabControl ItemContainerStyle="{StaticResource FSE_TabItem_VisualStudio_Output}" TabStripPlacement="Bottom" Margin="0" Background="{StaticResource FSE_PrimaryBackgroundDarkBrush}" BorderThickness="0"> - <TabItem Header="OUTPUT"></TabItem> - <TabItem Header="ERRORS"></TabItem> + <TabControl SelectedIndex="{Binding SelectedToolWindow,Mode=TwoWay,Converter={StaticResource EnumToIntConverter}}" ItemContainerStyle="{StaticResource FSE_TabItem_VisualStudio_Output}" TabStripPlacement="Bottom" Margin="0" Background="{StaticResource FSE_PrimaryBackgroundDarkBrush}" BorderThickness="0"> + <TabItem Header="OUTPUT"> + <TextBox HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto" Padding="5" Style="{x:Null}" Foreground="{StaticResource FSE_PrimaryForegroundBrush}" FontFamily="Consolas" components:TextController.Controller="{Binding Logger}" FontSize="{StaticResource FSE_SmallFontSize}" Background="{StaticResource FSE_PrimaryBackgroundDarkBrush}" BorderThickness="0" AcceptsReturn="True" IsReadOnly="True"> + + </TextBox> + </TabItem> + <TabItem> + <TabItem.Header> + <TextBlock> + <Run>ERRORS</Run> + <Run>(</Run><Run Text="{Binding CompilationErrors.Count,Mode=OneWay}"></Run><Run>)</Run> + </TextBlock> + </TabItem.Header> + <DataGrid ItemsSource="{Binding CompilationErrors}" Style="{StaticResource FSE_LogsGridStyle}" CellStyle="{StaticResource FSE_LogsGridCellStyle}" HorizontalGridLinesBrush="{StaticResource FSE_PrimaryBackgroundBrush}" AutoGenerateColumns="False"> + <DataGrid.Columns> + <DataGridTemplateColumn Width="40"> + <DataGridTemplateColumn.CellTemplate> + <DataTemplate> + <material:PackIcon HorizontalAlignment="Center" VerticalAlignment="Center" Kind="Alert" Foreground="{StaticResource FSE_ErrorBrush}" /> + </DataTemplate> + </DataGridTemplateColumn.CellTemplate> + </DataGridTemplateColumn> + <DataGridTextColumn Header="DESCRIPTION" Binding="{Binding Message}" Width="1*" /> + <DataGridTextColumn Header="FILE" Binding="{Binding File}" /> + <DataGridTextColumn Header="LINE" Binding="{Binding Line}" /> + <DataGridTextColumn Header="COL" Binding="{Binding Column}" /> + </DataGrid.Columns> + </DataGrid> + </TabItem> + <TabItem Header="RESULT"> + + </TabItem> + <TabItem Header="PUBLISH"> + + </TabItem> </TabControl> </Grid> </Grid> @@ -249,15 +311,13 @@ <GridSplitter Grid.Column="1" Width="5" HorizontalAlignment="Center" VerticalAlignment="Stretch" Margin="0 30" /> <Grid Grid.Column="2"> - <Grid Margin="0 32 0 29"> - <Grid.RowDefinitions> - <RowDefinition Height="451*"/> - <RowDefinition Height="5"/> - <RowDefinition Height="300*"/> - </Grid.RowDefinitions> + <Grid Margin="0 33 0 29"> <!--Project Explorer--> - <GroupBox material:ColorZoneAssist.Mode="PrimaryDark" Header="PROJECT EXPLORER" Background="{StaticResource FSE_PrimaryBackgroundDarkBrush}"> - <ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"> + <DockPanel Background="{StaticResource FSE_PrimaryBackgroundDarkBrush}"> + <Border DockPanel.Dock="Top" Padding="5" Background="{StaticResource FSE_PrimaryBackgroundLightBrush}" BorderThickness="0 2 0 0" BorderBrush="{StaticResource FSE_PrimaryAccentBrush}"> + <TextBlock>PROJECT EXPLORER</TextBlock> + </Border> + <ScrollViewer Padding="10" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"> <StackPanel> <DockPanel> <material:PackIcon Kind="ClockFast" /> @@ -265,7 +325,7 @@ </DockPanel> <DockPanel Margin="5 10 0 0"> - <controls:ToggleIconButton Width="20" Height="20" x:Name="chkReference" UncheckedIcon="ChevronRight" CheckedIcon="ChevronDown" Cursor="Hand"/> + <controls:ToggleIconButton Width="20" Height="20" x:Name="chkReference" UncheckedIcon="ChevronRight" CheckedIcon="ChevronDown" Cursor="Hand" IsChecked="True" /> <TextBlock Margin="5 0 0 0" VerticalAlignment="Center">Reference Assemblies</TextBlock> </DockPanel> @@ -297,24 +357,7 @@ </ListBox> </StackPanel> </ScrollViewer> - </GroupBox> - - <GridSplitter Grid.Row="1" Height="5" VerticalAlignment="Center" HorizontalAlignment="Stretch" /> - - <Grid Grid.Row="2"> - <GroupBox material:ColorZoneAssist.Mode="PrimaryDark" Header="PROPERTIES" Background="{StaticResource FSE_PrimaryBackgroundDarkBrush}"> - <DockPanel> - <StackPanel DockPanel.Dock="Top" Margin="10"> - <TextBlock>Project Name</TextBlock> - <TextBox Margin="0 2 0 0" Text="{Binding Project.Name,UpdateSourceTrigger=PropertyChanged}" Style="{StaticResource FSE_Rounded_Corners_TextBox}"></TextBox> - </StackPanel> - <DockPanel Margin="10 0 10 5"> - <TextBlock DockPanel.Dock="Top">Project Description</TextBlock> - <TextBox Margin="0 2 0 0" Text="{Binding Project.Description,UpdateSourceTrigger=PropertyChanged}" Style="{StaticResource FSE_Rounded_Corners_TextBox_Multiline}" Background="Transparent" ></TextBox> - </DockPanel> - </DockPanel> - </GroupBox> - </Grid> + </DockPanel> </Grid> </Grid> </Grid> diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/FSEViewModel.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/FSEViewModel.cs index 719fc36d1..1af8801db 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.Common/FSEViewModel.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/FSEViewModel.cs @@ -37,6 +37,7 @@ using Tango.FSE.Common.RemoteUpgrade; using Tango.FSE.Common.AutoComplete; using Tango.BL.Entities; using Tango.FSE.Common.Firmware; +using Tango.FSE.Common.Threading; namespace Tango.FSE.Common { @@ -163,6 +164,12 @@ namespace Tango.FSE.Common public IFirmwareStorageProvider FirmwareStorageProvider { get; set; } /// <summary> + /// Gets or sets the UI dispatcher provider. + /// </summary> + [TangoInject] + public IDispatcherProvider DispatcherProvider { get; set; } + + /// <summary> /// Gets or sets the FSE service. /// </summary> [TangoInject] diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Resources/Converters.xaml b/Software/Visual_Studio/FSE/Tango.FSE.Common/Resources/Converters.xaml index 8c36100c1..04d8dc416 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.Common/Resources/Converters.xaml +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Resources/Converters.xaml @@ -35,4 +35,5 @@ <converters:StringToTitleCaseConverter x:Key="StringToTitleCaseConverter" /> <converters:StringToOneLineConverter x:Key="StringToOneLineConverter" /> <converters:FilePathToFileNameConverter x:Key="FilePathToFileNameConverter" /> + <converters:EnumToIntConverter x:Key="EnumToIntConverter" /> </ResourceDictionary>
\ No newline at end of file diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/GlobalObject.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/GlobalObject.cs index fc48bb2a2..c76fba8e2 100644 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/GlobalObject.cs +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/GlobalObject.cs @@ -6,8 +6,8 @@ using System.Threading.Tasks; namespace Tango.Scripting.Basic { - public class GlobalObject + public class GlobalObject<T> where T : IContext { - public IContext GlobalContext { get; set; } + public T GlobalContext { get; set; } } } diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/Project.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/Project.cs index 31be3a714..85caf4706 100644 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/Project.cs +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/Project.cs @@ -18,7 +18,7 @@ using System.IO; namespace Tango.Scripting.Basic { - public class Project : ExtendedObject + public class Project<T> : ExtendedObject where T : IContext { private String _name; public String Name @@ -43,6 +43,7 @@ namespace Tango.Scripting.Basic public ObservableCollection<Script> Scripts { get; set; } + [JsonIgnore] public ObservableCollection<IScriptSource> AdditionalScripts { get @@ -78,16 +79,16 @@ namespace Tango.Scripting.Basic } } - public static Project New(String name) + public static Project<T> New(String name) { - Project p = new Project(); + Project<T> p = new Project<T>(); p.Name = name; p.ReferenceAssemblies.Add(new ReferenceAssembly() { FromType = typeof(String) }); p.ReferenceAssemblies.Add(new ReferenceAssembly() { FromType = typeof(Enumerable) }); p.ReferenceAssemblies.Add(new ReferenceAssembly() { FromType = typeof(Form) }); - p.ReferenceAssemblies.Add(new ReferenceAssembly() { FromType = typeof(Project) }); + p.ReferenceAssemblies.Add(new ReferenceAssembly() { FromType = typeof(Project<T>) }); return p; } @@ -140,14 +141,14 @@ namespace Tango.Scripting.Basic } else { - code += Environment.NewLine + Environment.NewLine + "return new Program().OnExecute(GlobalContext);"; + code += Environment.NewLine + Environment.NewLine + "new Program().OnExecute(GlobalContext);"; mainScriptCode = code; } } var scriptOptions = ScriptOptions.Default.WithReferences(ReferenceAssembliesLoaded); - var s = CSharpScript.Create<object>(mainScriptCode, scriptOptions, typeof(GlobalObject)); + var s = CSharpScript.Create<object>(mainScriptCode, scriptOptions, typeof(GlobalObject<T>)); result.Script = s; var compileResults = s.Compile(); @@ -164,7 +165,7 @@ namespace Tango.Scripting.Basic cError.Message = error.GetMessage(); cError.Severity = error.Severity; var line = error.Location.GetMappedLineSpan(); - cError.Line = line.StartLinePosition.Line + 1 + (errorScript != null ? errorScript.LoadCount : 0); + cError.Line = line.StartLinePosition.Line + 1 - (errorScript != null ? errorScript.LoadCount : 0); cError.Column = line.StartLinePosition.Character + 1; cError.Length = line.EndLinePosition.Character - line.StartLinePosition.Character; result.Errors.Add(cError); @@ -174,7 +175,7 @@ namespace Tango.Scripting.Basic }); } - public async Task<ProjectSession> Run(IContext context) + public async Task<ProjectSession<T>> Run(T context) { var result = await Compile(); @@ -184,9 +185,9 @@ namespace Tango.Scripting.Basic } Thread scriptThread = null; - ProjectSession session = null; + ProjectSession<T> session = null; - session = new ProjectSession(this, () => + session = new ProjectSession<T>(this, () => { scriptThread.Abort(); }); @@ -195,7 +196,7 @@ namespace Tango.Scripting.Basic { try { - var runResult = result.Script.RunAsync(globals: new GlobalObject() { GlobalContext = context }).Result; + var runResult = result.Script.RunAsync(globals: new GlobalObject<T>() { GlobalContext = context }).Result; session.Completed(runResult.ReturnValue); } catch (ThreadAbortException) diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/ProjectManager.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/ProjectManager.cs deleted file mode 100644 index 3af7530bc..000000000 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/ProjectManager.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Tango.Scripting.Basic -{ - public class ProjectManager - { - public Project Project { get; set; } - - public ProjectManager(Project project) - { - Project = project; - } - } -} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/ProjectSession.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/ProjectSession.cs index 565949402..6bd3d44b9 100644 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/ProjectSession.cs +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/ProjectSession.cs @@ -6,7 +6,7 @@ using System.Threading.Tasks; namespace Tango.Scripting.Basic { - public class ProjectSession + public class ProjectSession<T> where T : IContext { private Action _abortAction; private TaskCompletionSource<object> _completion; @@ -15,9 +15,9 @@ namespace Tango.Scripting.Basic public ProjectSessionState State { get; set; } - public Project Project { get; set; } + public Project<T> Project { get; set; } - public ProjectSession(Project project, Action abortAction) + public ProjectSession(Project<T> project, Action abortAction) { _completion = new TaskCompletionSource<object>(); Project = project; diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/Tango.Scripting.Basic.csproj b/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/Tango.Scripting.Basic.csproj index 8af52748a..be52ca57a 100644 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/Tango.Scripting.Basic.csproj +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/Tango.Scripting.Basic.csproj @@ -136,7 +136,6 @@ <Compile Include="CompilationResult.cs" /> <Compile Include="GlobalObject.cs" /> <Compile Include="Project.cs" /> - <Compile Include="ProjectManager.cs" /> <Compile Include="ReferenceAssembly.cs" /> <Compile Include="Properties\AssemblyInfo.cs"> <SubType>Code</SubType> diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/CachedUsing.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/CachedUsing.cs new file mode 100644 index 000000000..4a663bee9 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/CachedUsing.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Scripting.Editors.Intellisense; + +namespace Tango.Scripting.Editors +{ + public class CachedUsing + { + public String Namespace { get; set; } + public List<KnownType> KnownTypes { get; set; } + + public CachedUsing() + { + KnownTypes = new List<KnownType>(); + } + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Images/event.png b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Images/event.png Binary files differnew file mode 100644 index 000000000..4566835c0 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Images/event.png diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Intellisense/EventCompletionItem.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Intellisense/EventCompletionItem.cs new file mode 100644 index 000000000..5c510c39f --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Intellisense/EventCompletionItem.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Media.Imaging; + +namespace Tango.Scripting.Editors.Intellisense +{ + public class EventCompletionItem : CompletionItem + { + private static BitmapSource image = GetImage("event.png"); + + public override string Text => Name; + public override CompletionItemPopupControl PopupControl => new FieldCompletionItemPopup(); + public override BitmapSource Image => image; + + public String Name { get; set; } + public String Class { get; set; } + public String Type { get; set; } + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Intellisense/KnownType.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Intellisense/KnownType.cs index 6675eb582..3dc465541 100644 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Intellisense/KnownType.cs +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Intellisense/KnownType.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; +using System.Windows.Forms; using System.Xml; using Tango.Core; @@ -15,15 +16,17 @@ namespace Tango.Scripting.Editors.Intellisense { private bool _initialized; + public String Alias { get; set; } public bool DocumentationLoaded { get; set; } public Type Type { get; private set; } - public String Name { get; private set; } + public String Name { get; set; } public String TypeDefinition { get; private set; } public String FriendlyName { get; private set; } public String Summary { get; set; } public List<KnownTypeConstructor> Constructors { get; set; } public List<KnownTypeMethod> Methods { get; set; } public List<KnownTypeProperty> Properties { get; set; } + public List<KnownTypeEvent> Events { get; set; } public List<KnownTypeMember> Members { get @@ -32,6 +35,7 @@ namespace Tango.Scripting.Editors.Intellisense members.AddRange(Properties); members.AddRange(Methods); + members.AddRange(Events); return members.OrderBy(x => x.Name).ToList(); } @@ -45,6 +49,7 @@ namespace Tango.Scripting.Editors.Intellisense Methods = new List<KnownTypeMethod>(); Properties = new List<KnownTypeProperty>(); Fields = new List<KnownTypeField>(); + Events = new List<KnownTypeEvent>(); Type = type; Name = type.Name; @@ -177,7 +182,7 @@ namespace Tango.Scripting.Editors.Intellisense //Load Properties { - var properties = Type.GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(x => x.PropertyType.IsPublic).ToList(); + var properties = Type.GetProperties(BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.Instance).ToList(); for (int i = 0; i < properties.Count; i++) { @@ -192,6 +197,21 @@ namespace Tango.Scripting.Editors.Intellisense } } + //Load Events + { + var events = Type.GetRuntimeEvents().ToList(); + + for (int i = 0; i < events.Count; i++) + { + var ev = events[i]; + + KnownTypeEvent p = new KnownTypeEvent(this); + p.Name = ev.Name; + + Events.Add(p); + } + } + //Load Enum Values { if (Type.IsEnum) diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Intellisense/KnownTypeEvent.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Intellisense/KnownTypeEvent.cs new file mode 100644 index 000000000..7403d2cbd --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Intellisense/KnownTypeEvent.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.Scripting.Editors.Intellisense +{ + public class KnownTypeEvent : KnownTypeMember + { + public KnownTypeEvent() + { + Summary = "Loading documentation..."; + } + + public KnownTypeEvent(KnownType knownType) : this() + { + Type = knownType; + } + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/ScriptEditor.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/ScriptEditor.cs index a4493d2c4..29af14ddc 100644 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/ScriptEditor.cs +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/ScriptEditor.cs @@ -59,10 +59,14 @@ namespace Tango.Scripting.Editors private static Dictionary<Type, KnownType> _knownTypesCache; private static String KNOWN_TYPES_CACHE_FOLDER; private static List<CachedAssembly> _cachedAssemblies; + private static List<CachedUsing> _cachedUsings; private static bool _isLoadingCachedAssemblies; private static bool _isCacheAssembliesLoaded; + private static object _loadUsingsLock = new object(); - public static event EventHandler<TangoProgressChangedEventArgs<int>> AssemblyCacheProgress; + public static event EventHandler<TangoProgressChangedEventArgs<int>> LoadingSymbolsProgress; + public static event EventHandler LoadingSymbolsStarted; + public static event EventHandler LoadingSymbolsCompleted; #region Mini Classes @@ -96,6 +100,8 @@ namespace Tango.Scripting.Editors #region Properties + public static List<String> BlockedUsingsCache { get; set; } + /// <summary> /// Gets or sets a value indicating whether to enable folding. /// </summary> @@ -164,6 +170,8 @@ namespace Tango.Scripting.Editors { DefaultStyleKeyProperty.OverrideMetadata(typeof(ScriptEditor), new FrameworkPropertyMetadata(typeof(ScriptEditor))); + BlockedUsingsCache = new List<string>(); + if (KNOWN_TYPES_CACHE_FOLDER == null) { KNOWN_TYPES_CACHE_FOLDER = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Twine", "Tango", "Scripting", "Cache"); @@ -178,6 +186,7 @@ namespace Tango.Scripting.Editors _knownTypesCache = new Dictionary<Type, KnownType>(); _cachedAssemblies = new List<CachedAssembly>(); + _cachedUsings = new List<CachedUsing>(); } /// <summary> @@ -458,7 +467,17 @@ namespace Tango.Scripting.Editors }); } - foreach (var methodGroup in typeMembers.Where(x => x.GetType() != typeof(KnownTypeMethod)).GroupBy(x => x.Name)) + foreach (var ev in typeMembers.OfType<KnownTypeEvent>()) + { + data.Add(new EventCompletionItem() + { + Class = knownType.FriendlyName, + Name = ev.Name, + Description = ev.Summary, + }); + } + + foreach (var methodGroup in typeMembers.Where(x => x.GetType() != typeof(KnownTypeMethod) && x.GetType() != typeof(KnownTypeEvent)).GroupBy(x => x.Name)) { var member = methodGroup.First(); @@ -469,7 +488,6 @@ namespace Tango.Scripting.Editors Type = member.ReturnTypeFriendlyName, Description = member.Summary, }); - } } else @@ -558,7 +576,7 @@ namespace Tango.Scripting.Editors { //Maybe static ... var typeText = GetPreviousWord(); - knownType = _knownTypes.FirstOrDefault(x => x.FriendlyName == typeText); + knownType = _knownTypes.FirstOrDefault(x => x.FriendlyName == typeText || x.Alias == typeText); if (knownType != null) { @@ -902,7 +920,7 @@ namespace Tango.Scripting.Editors IList<ICompletionData> data = completionWindow.CompletionList.CompletionData; data.Clear(); - foreach (var item in suggestions) + foreach (var item in suggestions.DistinctBy(x => x.Text)) { data.Add(item); } @@ -984,6 +1002,13 @@ namespace Tango.Scripting.Editors { if (expression != null) { + var insideMethodExp = expression.Split('(').LastOrDefault(); + + if (insideMethodExp != null) + { + expression = insideMethodExp; + } + var tree = expression.Split('.').Select(x => x.Remove(@"\n|\t|\r|\(.*\)|\[.*\]|\s")).ToList(); var variableName = tree.FirstOrDefault(); @@ -1003,7 +1028,8 @@ namespace Tango.Scripting.Editors if (variable != null) { - var knownType = _knownTypes.FirstOrDefault(x => x.FriendlyName == Regex.Replace(variable.Type, "<.+>", "<T>")); + var name = Regex.Replace(variable.Type, "<.+>", "<T>"); + var knownType = _knownTypes.FirstOrDefault(x => name == x.FriendlyName || name == x.Alias); if (knownType != null) { @@ -1036,6 +1062,13 @@ namespace Tango.Scripting.Editors if (expression != null) { + var insideMethodExp = expression.Split('(').LastOrDefault(); + + if (insideMethodExp != null) + { + expression = insideMethodExp; + } + var tree = expression.Split('.').Select(x => x.Remove(@"\n|\t|\r|\(.*\)|\[.*\]|\s")).ToList(); var variableName = tree.FirstOrDefault(); @@ -1250,83 +1283,223 @@ namespace Tango.Scripting.Editors return popup; } - public static void LoadCachedAssemblies(List<Assembly> assemblies) + public static void LoadUsingsSymbols(List<Assembly> assemblies, List<String> usings) { - if (_isLoadingCachedAssemblies) return; + lock (_loadUsingsLock) + { + LoadingSymbolsStarted?.Invoke(null, new EventArgs()); - _isLoadingCachedAssemblies = true; + var allTypes = assemblies.SelectMany(x => x.GetTypes()); - if (!_isCacheAssembliesLoaded) - { - foreach (var file in System.IO.Directory.GetFiles(KNOWN_TYPES_CACHE_FOLDER)) + foreach (var use in usings) { - try + if (!_cachedUsings.Exists(x => x.Namespace == use)) { - AssemblyCacheProgress?.Invoke(null, new TangoProgressChangedEventArgs<int>() + var useFileName = System.IO.Path.Combine(KNOWN_TYPES_CACHE_FOLDER, use + ".json"); + + if (File.Exists(useFileName)) { - Progress = new TangoProgress<int>() + LoadingSymbolsProgress?.Invoke(null, new TangoProgressChangedEventArgs<int>() + { + Progress = new TangoProgress<int>() + { + IsIndeterminate = true, + Maximum = 100, + Message = $"Loading symbols for '{use}'..." + } + }); + + CachedUsing cached = JsonConvert.DeserializeObject<CachedUsing>(File.ReadAllText(useFileName), _jsonSettings); + _cachedUsings.Add(cached); + foreach (var knownType in cached.KnownTypes) { - IsIndeterminate = true, - Maximum = 100, - Message = $"Loading metadata cache for '{System.IO.Path.GetFileName(file)}'..." + _knownTypesCache.Add(knownType.Type, knownType); } - }); - var cachedAssembly = JsonConvert.DeserializeObject<CachedAssembly>(System.IO.File.ReadAllText(file), _jsonSettings); + continue; + } + + var useTypes = allTypes.Where(x => x.IsVisible && x.IsPublic && x.Namespace == use).ToList(); - foreach (var knownType in cachedAssembly.KnownTypes) + CachedUsing cachedUsing = new CachedUsing(); + cachedUsing.Namespace = use; + _cachedUsings.Add(cachedUsing); + + int i = 1; + + foreach (var type in useTypes) { - _knownTypesCache.Add(knownType.Type, knownType); + LoadingSymbolsProgress?.Invoke(null, new TangoProgressChangedEventArgs<int>() + { + Progress = new TangoProgress<int>() + { + IsIndeterminate = false, + Maximum = useTypes.Count, + Value = i++, + Message = $"Loading symbols for '{use}'..." + } + }); + + KnownType knownType = new KnownType(type); + + if (type.IsPrimitive) + { + if (type == typeof(Int32)) + { + knownType.Alias = "int"; + } + else if (type == typeof(float)) + { + knownType.Alias = "float"; + } + else if (type == typeof(Double)) + { + knownType.Alias = "double"; + } + else if (type == typeof(long)) + { + knownType.Alias = "long"; + } + else if (type == typeof(bool)) + { + knownType.Alias = "bool"; + } + else if (type == typeof(uint)) + { + knownType.Alias = "uint"; + } + } + + _knownTypesCache.Add(type, knownType); + cachedUsing.KnownTypes.Add(knownType); + knownType.LoadDocumentation(); } - _cachedAssemblies.Add(cachedAssembly); + if (!BlockedUsingsCache.Exists(x => x == use)) + { + Task.Factory.StartNew(() => + { + var json = JsonConvert.SerializeObject(cachedUsing, _jsonSettings); + File.WriteAllText(useFileName, json); + }); + } } - catch { } } - _isCacheAssembliesLoaded = true; + LoadingSymbolsCompleted?.Invoke(null, new EventArgs()); } + } - foreach (var asm in assemblies) - { - if (!_cachedAssemblies.Exists(x => x.Name == asm.FullName)) - { - String asmFileName = System.IO.Path.GetFileName(asm.Location); + //public static void LoadCachedAssemblies(List<Assembly> assemblies, List<String> usings = null) + //{ + // if (_isLoadingCachedAssemblies) return; - CachedAssembly cachedAssembly = new CachedAssembly(); - cachedAssembly.Name = asm.FullName; - _cachedAssemblies.Add(cachedAssembly); + // _isLoadingCachedAssemblies = true; - var types = asm.GetTypes().Where(x => x.IsVisible && x.IsPublic && !x.IsPrimitive).ToList(); + // LoadingSymbolsStarted?.Invoke(null, new EventArgs()); - int i = 0; + // if (!_isCacheAssembliesLoaded) + // { + // foreach (var file in System.IO.Directory.GetFiles(KNOWN_TYPES_CACHE_FOLDER)) + // { + // try + // { + // LoadingSymbolsProgress?.Invoke(null, new TangoProgressChangedEventArgs<int>() + // { + // Progress = new TangoProgress<int>() + // { + // IsIndeterminate = true, + // Maximum = 100, + // Message = $"Loading metadata cache for '{System.IO.Path.GetFileName(file)}'..." + // } + // }); - foreach (var type in types) - { - AssemblyCacheProgress?.Invoke(null, new TangoProgressChangedEventArgs<int>() - { - Progress = new TangoProgress<int>() - { - IsIndeterminate = false, - Maximum = types.Count, - Value = i++, - Message = $"Caching metadata for '{asmFileName}'..." - } - }); + // var cachedAssembly = JsonConvert.DeserializeObject<CachedAssembly>(System.IO.File.ReadAllText(file), _jsonSettings); - KnownType knownType = new KnownType(type); - _knownTypesCache.Add(type, knownType); - cachedAssembly.KnownTypes.Add(knownType); - knownType.LoadDocumentation(); - } + // foreach (var knownType in cachedAssembly.KnownTypes) + // { + // _knownTypesCache.Add(knownType.Type, knownType); + // } - String cachedAssemblyFile = System.IO.Path.Combine(KNOWN_TYPES_CACHE_FOLDER, asmFileName); - File.WriteAllText(cachedAssemblyFile, JsonConvert.SerializeObject(cachedAssembly, _jsonSettings)); - } - } + // _cachedAssemblies.Add(cachedAssembly); + // } + // catch { } + // } - _isLoadingCachedAssemblies = false; - } + // _isCacheAssembliesLoaded = true; + // } + + // foreach (var asm in assemblies) + // { + // if (!_cachedAssemblies.Exists(x => x.Name == asm.FullName)) + // { + // String asmFileName = System.IO.Path.GetFileName(asm.Location); + + // CachedAssembly cachedAssembly = new CachedAssembly(); + // cachedAssembly.Name = asm.FullName; + // _cachedAssemblies.Add(cachedAssembly); + + // var types = asm.GetTypes().Where(x => x.IsVisible && x.IsPublic).ToList(); + + // int i = 0; + + // foreach (var type in types) + // { + // LoadingSymbolsProgress?.Invoke(null, new TangoProgressChangedEventArgs<int>() + // { + // Progress = new TangoProgress<int>() + // { + // IsIndeterminate = false, + // Maximum = types.Count, + // Value = i++, + // Message = $"Caching metadata for '{asmFileName}'..." + // } + // }); + + // KnownType knownType = new KnownType(type); + + // if (type.IsPrimitive) + // { + // if (type == typeof(Int32)) + // { + // knownType.Alias = "int"; + // } + // else if (type == typeof(float)) + // { + // knownType.Alias = "float"; + // } + // else if (type == typeof(Double)) + // { + // knownType.Alias = "double"; + // } + // else if (type == typeof(long)) + // { + // knownType.Alias = "long"; + // } + // else if (type == typeof(bool)) + // { + // knownType.Alias = "bool"; + // } + // else if (type == typeof(uint)) + // { + // knownType.Alias = "uint"; + // } + // } + + // _knownTypesCache.Add(type, knownType); + // cachedAssembly.KnownTypes.Add(knownType); + // //knownType.LoadDocumentation(); + // } + + // String cachedAssemblyFile = System.IO.Path.Combine(KNOWN_TYPES_CACHE_FOLDER, asmFileName); + // File.WriteAllText(cachedAssemblyFile, JsonConvert.SerializeObject(cachedAssembly, _jsonSettings)); + // } + // } + + // LoadingSymbolsCompleted?.Invoke(null, new EventArgs()); + + // _isLoadingCachedAssemblies = false; + //} private void InvalidateHighlighting(bool loadKnownTypes = true) { @@ -1339,22 +1512,19 @@ namespace Tango.Scripting.Editors Thread t = new Thread(() => { - LoadCachedAssemblies(assemblies); + LoadUsingsSymbols(assemblies, usings); if (loadKnownTypes) { _knownTypes.Clear(); - foreach (var asm in assemblies) + foreach (var knownType in _knownTypesCache.ToList().Select(x => x.Value).ToList()) { - foreach (var knownType in _knownTypesCache.ToList().Select(x => x.Value).ToList()) + if (usings.Exists(x => knownType.Type.Namespace == x)) { - if (usings.Exists(x => knownType.Type.Namespace == x)) + lock (_knownTypes) { - lock (_knownTypes) - { - _knownTypes.Add(knownType); - } + _knownTypes.Add(knownType); } } } @@ -1589,7 +1759,11 @@ namespace Tango.Scripting.Editors private ConstructionSession GetConstructionSession() { - var expression = _parser.GetCurrentConstructionExpression(GetCurrentLineText()); + var currentLine = GetCurrentLineText(); + + //if (currentLine.Count(x => x == '(') > 1) return null; + + var expression = _parser.GetCurrentConstructionExpression(currentLine); if (expression != null) { @@ -1693,7 +1867,14 @@ namespace Tango.Scripting.Editors private MethodSession GetMethodSession() { - var words = GetCurrentLineText().Split(' '); + var currentLine = GetCurrentLineText(); + + if (currentLine.Count(x => x == '(') > 1) + { + currentLine = currentLine.Split('(')[currentLine.Split('(').Length - 2]; + } + + var words = currentLine.Split(' '); if (words.Count() > 0 && (words.First() == "private" || words.First() == "public" || words.First() == "void")) { @@ -1811,14 +1992,21 @@ namespace Tango.Scripting.Editors private DeclaredMethodSession GetDeclaredMethodSession() { - var words = GetCurrentLineText().Split(' '); + var currentLine = GetCurrentLineText(); + + if (currentLine.Count(x => x == '(') > 1) + { + currentLine = currentLine.Split('(')[currentLine.Split('(').Length - 2]; + } + + var words = currentLine.Split(' '); if (words.Count() > 0 && (words.First() == "private" || words.First() == "public" || words.First() == "void")) { return null; } - var expression = GetPreviousWords().LastOrDefault(); + var expression = currentLine; if (expression != null) { @@ -1833,7 +2021,7 @@ namespace Tango.Scripting.Editors if (variable != null) { - var declaredType = _declaredTypes.FirstOrDefault(x => x.Name == Regex.Replace(variable.Class, "<.+>", "<T>")); + var declaredType = _declaredTypes.FirstOrDefault(x => x.Name == Regex.Replace(variable.Type, "<.+>", "<T>")); if (declaredType != null) { diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Tango.Scripting.Editors.csproj b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Tango.Scripting.Editors.csproj index d6c89f0a4..cabacbc28 100644 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Tango.Scripting.Editors.csproj +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Tango.Scripting.Editors.csproj @@ -181,6 +181,7 @@ </Compile> <Compile Include="AvalonEditCommands.cs" /> <Compile Include="CachedAssembly.cs" /> + <Compile Include="CachedUsing.cs" /> <Compile Include="CodeCompletion\CompletionListBox.cs" /> <Compile Include="CodeCompletion\CompletionListBoxItem.cs" /> <Compile Include="CodeCompletion\CompletionWindowBase.cs" /> @@ -201,6 +202,7 @@ <Compile Include="Intellisense\CompletionItemPopupControl.cs" /> <Compile Include="Intellisense\EnumCompletionItem.cs" /> <Compile Include="Intellisense\EnumCompletionItemPopup.cs" /> + <Compile Include="Intellisense\EventCompletionItem.cs" /> <Compile Include="Intellisense\FieldCompletionItem.cs" /> <Compile Include="Intellisense\FieldCompletionItemPopup.cs" /> <Compile Include="Intellisense\ICompletionItem.cs" /> @@ -340,6 +342,7 @@ <Compile Include="Indentation\DefaultIndentationStrategy.cs" /> <Compile Include="Indentation\IIndentationStrategy.cs" /> <Compile Include="Intellisense\KnownTypeConstructor.cs" /> + <Compile Include="Intellisense\KnownTypeEvent.cs" /> <Compile Include="Intellisense\KnownTypeField.cs" /> <Compile Include="Intellisense\KnownTypeMember.cs" /> <Compile Include="Intellisense\KnownTypeMethodParameter.cs" /> @@ -634,9 +637,12 @@ <Analyzer Include="..\..\packages\Microsoft.CodeAnalysis.Analyzers.1.1.0\analyzers\dotnet\cs\Microsoft.CodeAnalysis.Analyzers.dll" /> <Analyzer Include="..\..\packages\Microsoft.CodeAnalysis.Analyzers.1.1.0\analyzers\dotnet\cs\Microsoft.CodeAnalysis.CSharp.Analyzers.dll" /> </ItemGroup> + <ItemGroup> + <Resource Include="Images\event.png" /> + </ItemGroup> <ProjectExtensions> <VisualStudio> - <UserProperties BuildVersion_StartDate="2000/1/1" BuildVersion_BuildVersioningStyle="None.None.Increment.TimeStamp" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_AssemblyInfoFilename="Properties\AssemblyInfo.cs" BuildVersion_UseGlobalSettings="True" /> + <UserProperties BuildVersion_UseGlobalSettings="True" BuildVersion_AssemblyInfoFilename="Properties\AssemblyInfo.cs" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_BuildVersioningStyle="None.None.Increment.TimeStamp" BuildVersion_StartDate="2000/1/1" /> </VisualStudio> </ProjectExtensions> </Project>
\ No newline at end of file diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Themes/Generic.xaml b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Themes/Generic.xaml index ce5cb39e1..6455b8fcb 100644 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Themes/Generic.xaml +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Themes/Generic.xaml @@ -47,6 +47,7 @@ <BitmapImage x:Key="namespace" UriSource="pack://application:,,,/Tango.Scripting.Editors;component/Images/namespace.png" /> <BitmapImage x:Key="method" UriSource="pack://application:,,,/Tango.Scripting.Editors;component/Images/method.png" /> <BitmapImage x:Key="property" UriSource="pack://application:,,,/Tango.Scripting.Editors;component/Images/property.png" /> + <BitmapImage x:Key="event" UriSource="pack://application:,,,/Tango.Scripting.Editors;component/Images/event.png" /> <!--Converters--> <converters:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" /> @@ -567,4 +568,6 @@ </Setter.Value> </Setter> </Style> + + </ResourceDictionary> diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Test/MainWindow.xaml.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Test/MainWindow.xaml.cs index 07958493d..58a695c10 100644 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Test/MainWindow.xaml.cs +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Test/MainWindow.xaml.cs @@ -25,14 +25,7 @@ namespace Tango.Scripting.Test { public MainWindow() { - ScriptEditor.AssemblyCacheProgress += ScriptEditor_AssemblyCacheProgress; - ScriptEditor.LoadCachedAssemblies(new List<System.Reflection.Assembly>() - { - typeof(String).Assembly, - typeof(Enumerable).Assembly, - typeof(Form).Assembly, - typeof(System.Drawing.Point).Assembly - }); + ScriptEditor.LoadingSymbolsProgress += ScriptEditor_AssemblyCacheProgress; InitializeComponent(); DataContext = new MainWindowVM(); diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Test/MainWindowVM.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Test/MainWindowVM.cs index 203196fda..f57de886f 100644 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Test/MainWindowVM.cs +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Test/MainWindowVM.cs @@ -12,13 +12,19 @@ using Tango.SharedUI; namespace Tango.Scripting.Test { + public class TestContext : IContext + { + + } + public class MainWindowVM : ViewModel { + public RelayCommand AddScriptCommand { get; set; } public RelayCommand RunCommand { get; set; } - private Project _project; - public Project Project + private Project<TestContext> _project; + public Project<TestContext> Project { get { return _project; } set { _project = value; RaisePropertyChangedAuto(); } @@ -26,7 +32,8 @@ namespace Tango.Scripting.Test public MainWindowVM() { - Project = Project.New("untitled", Encoding.Default.GetString(Properties.Resources.template)); + Project = Project<TestContext>.New("untitled"); + Project.Scripts.Add(Script.New("main.csx", Encoding.Default.GetString(Properties.Resources.template), true)); AddScriptCommand = new RelayCommand(AddScriptFile); RunCommand = new RelayCommand(RunProject); } diff --git a/Software/Visual_Studio/Tango.SharedUI/Converters/EnumToIntConverter.cs b/Software/Visual_Studio/Tango.SharedUI/Converters/EnumToIntConverter.cs new file mode 100644 index 000000000..43caff16c --- /dev/null +++ b/Software/Visual_Studio/Tango.SharedUI/Converters/EnumToIntConverter.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Data; + +namespace Tango.SharedUI.Converters +{ + public class EnumToIntConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + return (int)value; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + return Enum.ToObject(targetType, value); + } + } +} diff --git a/Software/Visual_Studio/Tango.SharedUI/Tango.SharedUI.csproj b/Software/Visual_Studio/Tango.SharedUI/Tango.SharedUI.csproj index 546dbf3bb..885e7c9b0 100644 --- a/Software/Visual_Studio/Tango.SharedUI/Tango.SharedUI.csproj +++ b/Software/Visual_Studio/Tango.SharedUI/Tango.SharedUI.csproj @@ -107,6 +107,7 @@ <Compile Include="Converters\EmptyStringToNullConverter.cs" /> <Compile Include="Converters\EnumToBooleanConverter.cs" /> <Compile Include="Converters\EnumToDescriptionConverter.cs" /> + <Compile Include="Converters\EnumToIntConverter.cs" /> <Compile Include="Converters\EnumToItemsSourceConverter.cs" /> <Compile Include="Converters\EnumToVisibilityConverter.cs" /> <Compile Include="Converters\EnumToXamlVectorConverter.cs" /> @@ -250,7 +251,7 @@ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <ProjectExtensions> <VisualStudio> - <UserProperties BuildVersion_AssemblyInfoFilename="Properties\AssemblyInfo.cs" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_BuildVersioningStyle="None.None.Increment.TimeStamp" BuildVersion_UseGlobalSettings="False" BuildVersion_StartDate="2000/1/1" /> + <UserProperties BuildVersion_StartDate="2000/1/1" BuildVersion_UseGlobalSettings="False" BuildVersion_BuildVersioningStyle="None.None.Increment.TimeStamp" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_AssemblyInfoFilename="Properties\AssemblyInfo.cs" /> </VisualStudio> </ProjectExtensions> </Project>
\ No newline at end of file |
