diff options
| author | Roy Ben Shabat <Roy@twine-s.com> | 2020-12-30 15:11:34 +0000 |
|---|---|---|
| committer | Roy Ben Shabat <Roy@twine-s.com> | 2020-12-30 15:11:34 +0000 |
| commit | d33c19b3ac6803de4b5c8d475832efef131c1a45 (patch) | |
| tree | ea725abc39def99a755b041c13cba1fe0d594ddc /Software/Visual_Studio/Scripting | |
| parent | 1bdcaa9f51303bbff682507f31fb3b4414692ca4 (diff) | |
| download | Tango-d33c19b3ac6803de4b5c8d475832efef131c1a45.tar.gz Tango-d33c19b3ac6803de4b5c8d475832efef131c1a45.zip | |
Revert "Hope it is fine"
Diffstat (limited to 'Software/Visual_Studio/Scripting')
80 files changed, 7966 insertions, 2479 deletions
diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/CompilationError.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/CompilationError.cs new file mode 100644 index 000000000..eda72fa6e --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/CompilationError.cs @@ -0,0 +1,20 @@ +using Microsoft.CodeAnalysis; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.Scripting.Basic +{ + public class CompilationError + { + public String File { get; set; } + public String Message { get; set; } + public DiagnosticSeverity Severity { get; set; } + public int Position { get; set; } + public int Line { get; set; } + public int Column { get; set; } + public int Length { get; set; } + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/CompilationResult.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/CompilationResult.cs new file mode 100644 index 000000000..d3676acc0 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/CompilationResult.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Core.IO; + +namespace Tango.Scripting.Basic +{ + public class CompilationResult + { + public List<CompilationError> Errors { get; set; } + public TemporaryFolder TemporaryProjectPath { get; set; } + public Microsoft.CodeAnalysis.Scripting.Script Script { get; set; } + + public CompilationResult() + { + Errors = new List<CompilationError>(); + } + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/GlobalObject.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/GlobalObject.cs new file mode 100644 index 000000000..c76fba8e2 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/GlobalObject.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.Scripting.Basic +{ + public class GlobalObject<T> where T : IContext + { + public T GlobalContext { get; set; } + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/IContext.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/IContext.cs new file mode 100644 index 000000000..d817c5d46 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/IContext.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.Scripting.Basic +{ + public interface IContext + { + + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/Project.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/Project.cs new file mode 100644 index 000000000..7500e404f --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/Project.cs @@ -0,0 +1,259 @@ +using Microsoft.CodeAnalysis.CSharp.Scripting; +using Microsoft.CodeAnalysis.Scripting; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Forms; +using Tango.Core; +using Tango.Core.IO; +using Tango.Scripting.Core; +using System.IO; +using Tango.Core.Helpers; + +namespace Tango.Scripting.Basic +{ + public class Project<T> : ExtendedObject where T : IContext + { + private object _compileLock = new object(); + + public String ID { get; set; } + + private String _name; + public String Name + { + get { return _name; } + set { _name = value; RaisePropertyChangedAuto(); } + } + + private String _description; + public String Description + { + get { return _description; } + set { _description = value; RaisePropertyChangedAuto(); } + } + + private bool _isRunning; + [JsonIgnore] + public bool IsRunning + { + get { return _isRunning; } + set { _isRunning = value; RaisePropertyChangedAuto(); } + } + + private bool _isCompiling; + [JsonIgnore] + public bool IsCompiling + { + get { return _isCompiling; } + set { _isCompiling = value; RaisePropertyChangedAuto(); } + } + + public ApartmentState ApartmentState { get; set; } + + public ObservableCollection<ReferenceAssembly> ReferenceAssemblies { get; set; } + + public ObservableCollection<Script> Scripts { get; set; } + + [JsonIgnore] + public ObservableCollection<IScriptSource> AdditionalScripts + { + get + { + return Scripts.Where(x => !x.IsEntryPoint).Cast<IScriptSource>().ToObservableCollection(); + } + } + + [JsonIgnore] + public List<ScriptBreakPoint> BreakPoints { get; set; } + + public Project() + { + ID = Guid.NewGuid().ToString(); + + ApartmentState = ApartmentState.MTA; + + ReferenceAssemblies = new ObservableCollection<ReferenceAssembly>(); + + Scripts = new ObservableCollection<Script>(); + Scripts.CollectionChanged += (x, e) => { RaisePropertyChanged(nameof(AdditionalScripts)); }; + + BreakPoints = new List<ScriptBreakPoint>(); + } + + public Task<CompilationResult> Compile() + { + return Task.Factory.StartNew<CompilationResult>(() => + { + lock (_compileLock) + { + try + { + IsCompiling = true; + var result = new CompilationResult(); + var tempFolder = TemporaryManager.CreateFolder(Name + "_" + ID); + result.TemporaryProjectPath = tempFolder; + + String mainScriptCode = String.Empty; + + foreach (var script in Scripts) + { + script.LoadCount = 0; + script.LoadCharCount = 0; + String code = script.Code; + String codeFile = Path.Combine(tempFolder, script.Name); + + String loadingString = String.Empty; + + foreach (var file in Scripts.Where(x => !x.IsEntryPoint && script != x).Select(x => Path.Combine(tempFolder, x.Name))) + { + loadingString += $"#load \"{file}\"\n"; + script.LoadCount++; + } + + script.LoadCharCount += loadingString.Length; + + code = loadingString + code; + + int debugLinesLength = 0; + + foreach (var breakPoint in BreakPoints.Where(x => x.Script == script).OrderBy(x => x.LineNumber)) + { + var debugLine = $"context.BreakPoint(\"{script.Name}\",{breakPoint.LineNumber}"; + + foreach (var symbol in breakPoint.ContextSymbols) + { + debugLine += $",\"{symbol.Name}\",{symbol.Offset},{symbol.Length},{symbol.Name}"; + } + + debugLine += ");"; + + StringBuilder builder = new StringBuilder(code); + builder.Insert(breakPoint.LineStartOffset + loadingString.Length + debugLinesLength, debugLine); + code = builder.ToString(); + + debugLinesLength += debugLine.Length; + } + + if (!script.IsEntryPoint) + { + File.WriteAllText(codeFile, code); + } + else + { + code += Environment.NewLine + Environment.NewLine + "new Program().OnExecute(GlobalContext);"; + mainScriptCode = code; + } + } + + var scriptOptions = ScriptOptions.Default.WithReferences(LoadReferenceAssemblies()).WithEmitDebugInformation(true); + + var s = CSharpScript.Create<object>(mainScriptCode, scriptOptions, typeof(GlobalObject<T>)); + + result.Script = s; + + var compileResults = s.Compile(); + + GC.Collect(); + + foreach (var error in compileResults.Where(x => x.Severity == Microsoft.CodeAnalysis.DiagnosticSeverity.Error)) + { + CompilationError cError = new CompilationError(); + cError.File = System.IO.Path.GetFileName(error.Location.SourceTree.FilePath); + if (cError.File == String.Empty) + { + cError.File = Scripts.Single(x => x.IsEntryPoint).Name; + } + Script errorScript = Scripts.Single(x => x.Name == cError.File); + cError.Message = error.GetMessage(); + cError.Severity = error.Severity; + cError.Position = error.Location.SourceSpan.Start - (errorScript != null ? errorScript.LoadCharCount : 0); + var line = error.Location.GetMappedLineSpan(); + 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); + } + + return result; + } + catch (Exception) + { + throw; + } + finally + { + IsCompiling = false; + } + } + }); + } + + public async Task<ProjectSession<T>> Run(T context) + { + IsRunning = true; + var result = await Compile(); + + if (result.Errors.Count > 0) + { + throw new InvalidOperationException($"Cannot run project with the following compilation errors:\n{String.Join(Environment.NewLine, result.Errors.Select(x => x.Message))}"); + } + + Thread scriptThread = null; + ProjectSession<T> session = null; + + session = new ProjectSession<T>(this, () => + { + scriptThread.Abort(); + }); + + scriptThread = new Thread(() => + { + try + { + var runResult = result.Script.RunAsync(globals: new GlobalObject<T>() { GlobalContext = context }).Result; + IsRunning = false; + session.Completed(runResult.ReturnValue); + } + catch (ThreadAbortException) + { + + } + catch (Exception ex) + { + session.Failed(ex.InnerException); + } + finally + { + BreakPoints.Clear(); + GC.Collect(); + IsRunning = false; + } + }); + + scriptThread.SetApartmentState(ApartmentState); + scriptThread.IsBackground = true; + scriptThread.Start(); + + return session; + } + + public List<Assembly> LoadReferenceAssemblies() + { + List<Assembly> loadedAssemblies = new List<Assembly>(); + + foreach (var asm in ReferenceAssemblies) + { + loadedAssemblies.Add(asm.Load()); + } + + return loadedAssemblies; + } + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/ProjectSession.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/ProjectSession.cs new file mode 100644 index 000000000..6bd3d44b9 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/ProjectSession.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.Scripting.Basic +{ + public class ProjectSession<T> where T : IContext + { + private Action _abortAction; + private TaskCompletionSource<object> _completion; + + public event EventHandler<ProjectSessionStateChangedEventArgs> StateChanged; + + public ProjectSessionState State { get; set; } + + public Project<T> Project { get; set; } + + public ProjectSession(Project<T> project, Action abortAction) + { + _completion = new TaskCompletionSource<object>(); + Project = project; + _abortAction = abortAction; + } + + public void Abort() + { + _abortAction(); + State = ProjectSessionState.Aborted; + _completion.SetException(new OperationCanceledException("Project execution aborted.")); + RaiseStateChanged(); + } + + internal void Failed(Exception ex) + { + State = ProjectSessionState.Failed; + _completion.SetException(ex); + RaiseStateChanged(null, ex); + } + + internal void Completed(object returnValue) + { + State = ProjectSessionState.Completed; + _completion.SetResult(returnValue); + RaiseStateChanged(returnValue, null); + } + + private void RaiseStateChanged(object returnValue = null, Exception ex = null) + { + StateChanged?.Invoke(this, + new ProjectSessionStateChangedEventArgs() + { + ReturnValue = returnValue, + State = State, + Exception = ex + }); + } + + public Task<Object> WaitForCompletion() + { + return _completion.Task; + } + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/ProjectSessionState.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/ProjectSessionState.cs new file mode 100644 index 000000000..e47eecb8c --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/ProjectSessionState.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.Scripting.Basic +{ + public enum ProjectSessionState + { + Running, + Completed, + Aborted, + Failed, + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/ProjectSessionStateChangedEventArgs.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/ProjectSessionStateChangedEventArgs.cs new file mode 100644 index 000000000..53ea96cd6 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/ProjectSessionStateChangedEventArgs.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.Scripting.Basic +{ + public class ProjectSessionStateChangedEventArgs : EventArgs + { + public Object ReturnValue { get; set; } + + public ProjectSessionState State { get; set; } + + public Exception Exception { get; set; } + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/Properties/AssemblyInfo.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..20a020e63 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/Properties/AssemblyInfo.cs @@ -0,0 +1,55 @@ +using System.Reflection; +using System.Resources; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Windows; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Tango.Scripting.Basic")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Tango.Scripting.Basic")] +[assembly: AssemblyCopyright("Copyright © 2020")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +//In order to begin building localizable applications, set +//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file +//inside a <PropertyGroup>. For example, if you are using US english +//in your source files, set the <UICulture> to en-US. Then uncomment +//the NeutralResourceLanguage attribute below. Update the "en-US" in +//the line below to match the UICulture setting in the project file. + +//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] + + +[assembly:ThemeInfo( + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + //(used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) +)] + + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/Properties/Resources.Designer.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/Properties/Resources.Designer.cs new file mode 100644 index 000000000..97b6a82b6 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/Properties/Resources.Designer.cs @@ -0,0 +1,73 @@ +//------------------------------------------------------------------------------ +// <auto-generated> +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// </auto-generated> +//------------------------------------------------------------------------------ + +namespace Tango.Scripting.Basic.Properties { + using System; + + + /// <summary> + /// A strongly-typed resource class, for looking up localized strings, etc. + /// </summary> + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// <summary> + /// Returns the cached ResourceManager instance used by this class. + /// </summary> + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Tango.Scripting.Basic.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// <summary> + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// </summary> + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// <summary> + /// Looks up a localized resource of type System.Byte[]. + /// </summary> + internal static byte[] template { + get { + object obj = ResourceManager.GetObject("template", resourceCulture); + return ((byte[])(obj)); + } + } + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/Properties/Resources.resx b/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/Properties/Resources.resx new file mode 100644 index 000000000..37de48988 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/Properties/Resources.resx @@ -0,0 +1,124 @@ +<?xml version="1.0" encoding="utf-8"?> +<root> + <!-- + Microsoft ResX Schema + + Version 2.0 + + The primary goals of this format is to allow a simple XML format + that is mostly human readable. The generation and parsing of the + various data types are done through the TypeConverter classes + associated with the data types. + + Example: + + ... ado.net/XML headers & schema ... + <resheader name="resmimetype">text/microsoft-resx</resheader> + <resheader name="version">2.0</resheader> + <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader> + <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader> + <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data> + <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data> + <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64"> + <value>[base64 mime encoded serialized .NET Framework object]</value> + </data> + <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> + <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value> + <comment>This is a comment</comment> + </data> + + There are any number of "resheader" rows that contain simple + name/value pairs. + + Each data row contains a name, and value. The row also contains a + type or mimetype. Type corresponds to a .NET class that support + text/value conversion through the TypeConverter architecture. + Classes that don't support this are serialized and stored with the + mimetype set. + + The mimetype is used for serialized objects, and tells the + ResXResourceReader how to depersist the object. This is currently not + extensible. For a given mimetype the value must be set accordingly: + + Note - application/x-microsoft.net.object.binary.base64 is the format + that the ResXResourceWriter will generate, however the reader can + read any of the formats listed below. + + mimetype: application/x-microsoft.net.object.binary.base64 + value : The object must be serialized with + : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter + : and then encoded with base64 encoding. + + mimetype: application/x-microsoft.net.object.soap.base64 + value : The object must be serialized with + : System.Runtime.Serialization.Formatters.Soap.SoapFormatter + : and then encoded with base64 encoding. + + mimetype: application/x-microsoft.net.object.bytearray.base64 + value : The object must be serialized into a byte array + : using a System.ComponentModel.TypeConverter + : and then encoded with base64 encoding. + --> + <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> + <xsd:import namespace="http://www.w3.org/XML/1998/namespace" /> + <xsd:element name="root" msdata:IsDataSet="true"> + <xsd:complexType> + <xsd:choice maxOccurs="unbounded"> + <xsd:element name="metadata"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" /> + </xsd:sequence> + <xsd:attribute name="name" use="required" type="xsd:string" /> + <xsd:attribute name="type" type="xsd:string" /> + <xsd:attribute name="mimetype" type="xsd:string" /> + <xsd:attribute ref="xml:space" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="assembly"> + <xsd:complexType> + <xsd:attribute name="alias" type="xsd:string" /> + <xsd:attribute name="name" type="xsd:string" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="data"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> + <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" /> + <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /> + <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /> + <xsd:attribute ref="xml:space" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="resheader"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" use="required" /> + </xsd:complexType> + </xsd:element> + </xsd:choice> + </xsd:complexType> + </xsd:element> + </xsd:schema> + <resheader name="resmimetype"> + <value>text/microsoft-resx</value> + </resheader> + <resheader name="version"> + <value>2.0</value> + </resheader> + <resheader name="reader"> + <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </resheader> + <resheader name="writer"> + <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </resheader> + <assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> + <data name="template" type="System.Resources.ResXFileRef, System.Windows.Forms"> + <value>..\Resources\template.csx;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> +</root>
\ No newline at end of file diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/Properties/Settings.Designer.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/Properties/Settings.Designer.cs new file mode 100644 index 000000000..cb477c7a2 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/Properties/Settings.Designer.cs @@ -0,0 +1,30 @@ +//------------------------------------------------------------------------------ +// <auto-generated> +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// </auto-generated> +//------------------------------------------------------------------------------ + +namespace Tango.Scripting.Basic.Properties +{ + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase + { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default + { + get + { + return defaultInstance; + } + } + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/Properties/Settings.settings b/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/Properties/Settings.settings new file mode 100644 index 000000000..033d7a5e9 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/Properties/Settings.settings @@ -0,0 +1,7 @@ +<?xml version='1.0' encoding='utf-8'?> +<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)"> + <Profiles> + <Profile Name="(Default)" /> + </Profiles> + <Settings /> +</SettingsFile>
\ No newline at end of file diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/ReferenceAssembly.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/ReferenceAssembly.cs new file mode 100644 index 000000000..665bd7ab1 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/ReferenceAssembly.cs @@ -0,0 +1,88 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using Tango.Core.Helpers; + +namespace Tango.Scripting.Basic +{ + public class ReferenceAssembly + { + private static Dictionary<String, Assembly> _assembliesCache; + + static ReferenceAssembly() + { + _assembliesCache = new Dictionary<string, Assembly>(); + } + + public String File { get; set; } + + public Type HintType { get; set; } + + [JsonIgnore] + public String Name + { + get { return Path.GetFileNameWithoutExtension(File); } + } + + public static ReferenceAssembly FromType(Type type) + { + ReferenceAssembly reference = new ReferenceAssembly(); + reference.HintType = type; + var assembly = type.Assembly; + reference.File = assembly.Location; + return reference; + } + + public static ReferenceAssembly FromFile(String file) + { + return new ReferenceAssembly() { File = file }; + } + + public Assembly Load() + { + Assembly loaded = null; + if (!_assembliesCache.TryGetValue(Name, out loaded)) + { + try + { + if (HintType != null) + { + loaded = HintType.Assembly; + } + else + { + loaded = Assembly.LoadFrom(File); + } + + _assembliesCache.Add(Name, loaded); + } + catch + { + try + { + String dotNetPath = AssemblyHelper.GetAssemblyTargetFrameworkFolder(Assembly.GetExecutingAssembly()); + String dotNetAsm = Path.Combine(dotNetPath, Name + ".dll"); + loaded = Assembly.LoadFrom(dotNetAsm); + _assembliesCache.Add(Name, loaded); + } + catch (Exception ex) + { + throw new FileNotFoundException($"Could not load assembly '{Name}'. File not found.", ex); + } + } + } + + return loaded; + } + + public override string ToString() + { + return Name; + } + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/Resources/template.csx b/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/Resources/template.csx new file mode 100644 index 000000000..307e1e483 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/Resources/template.csx @@ -0,0 +1,16 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Tango.Scripting.Basic; + +public class MainScript +{ + public object OnExecute(IContext context) + { + return new + { + Item1 = "1", + Item2 = "2" + }; + } +}
\ No newline at end of file diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/Script.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/Script.cs new file mode 100644 index 000000000..c465292cb --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/Script.cs @@ -0,0 +1,80 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Core; +using Tango.Scripting.Core; + +namespace Tango.Scripting.Basic +{ + public class Script : ExtendedObject, IScriptSource + { + private String _name; + public String Name + { + get { return _name; } + set { _name = value; RaisePropertyChangedAuto(); } + } + + public bool IsEntryPoint { get; set; } + + private String _code; + public String Code + { + get { return _code; } + set + { + if (_code != null && _code != value) + { + IsChanged = true; + } + + _code = value; + RaisePropertyChangedAuto(); + } + } + + private bool _isChanged; + [JsonIgnore] + public bool IsChanged + { + get { return _isChanged; } + set { _isChanged = value; RaisePropertyChangedAuto(); } + } + + private bool _isSelected; + [JsonIgnore] + public bool IsSelected + { + get { return _isSelected; } + set { _isSelected = value; RaisePropertyChangedAuto(); } + } + + [JsonIgnore] + public int LoadCount { get; internal set; } + [JsonIgnore] + public int LoadCharCount { get; set; } + + public static Script New(String file) + { + return new Script() + { + Name = Path.GetFileName(file), + Code = System.IO.File.ReadAllText(file), + }; + } + + public static Script New(String name, String code, bool isEntryPoint = false) + { + return new Script() + { + Name = name, + Code = code, + IsEntryPoint = isEntryPoint, + }; + } + } +} 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 new file mode 100644 index 000000000..be52ca57a --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/Tango.Scripting.Basic.csproj @@ -0,0 +1,185 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <ProjectGuid>{2B29A699-1D65-463A-8250-A2CE81D019C9}</ProjectGuid> + <OutputType>library</OutputType> + <RootNamespace>Tango.Scripting.Basic</RootNamespace> + <AssemblyName>Tango.Scripting.Basic</AssemblyName> + <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion> + <FileAlignment>512</FileAlignment> + <ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> + <WarningLevel>4</WarningLevel> + <Deterministic>true</Deterministic> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\Debug\</OutputPath> + <DefineConstants>DEBUG;TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\Release\</OutputPath> + <DefineConstants>TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <ItemGroup> + <Reference Include="Microsoft.CodeAnalysis, Version=2.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"> + <HintPath>..\..\packages\Microsoft.CodeAnalysis.Common.2.4.0\lib\netstandard1.3\Microsoft.CodeAnalysis.dll</HintPath> + </Reference> + <Reference Include="Microsoft.CodeAnalysis.CSharp, Version=2.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"> + <HintPath>..\..\packages\Microsoft.CodeAnalysis.CSharp.2.4.0\lib\netstandard1.3\Microsoft.CodeAnalysis.CSharp.dll</HintPath> + </Reference> + <Reference Include="Microsoft.CodeAnalysis.CSharp.Scripting, Version=2.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"> + <HintPath>..\..\packages\Microsoft.CodeAnalysis.CSharp.Scripting.2.4.0\lib\netstandard1.3\Microsoft.CodeAnalysis.CSharp.Scripting.dll</HintPath> + </Reference> + <Reference Include="Microsoft.CodeAnalysis.Scripting, Version=2.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"> + <HintPath>..\..\packages\Microsoft.CodeAnalysis.Scripting.Common.2.4.0\lib\netstandard1.3\Microsoft.CodeAnalysis.Scripting.dll</HintPath> + </Reference> + <Reference Include="Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL"> + <HintPath>..\..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll</HintPath> + </Reference> + <Reference Include="System" /> + <Reference Include="System.AppContext, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> + <HintPath>..\..\packages\System.AppContext.4.3.0\lib\net46\System.AppContext.dll</HintPath> + </Reference> + <Reference Include="System.Collections.Immutable, Version=1.2.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> + <HintPath>..\..\packages\System.Collections.Immutable.1.3.1\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath> + </Reference> + <Reference Include="System.ComponentModel.Composition" /> + <Reference Include="System.Console, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> + <HintPath>..\..\packages\System.Console.4.3.0\lib\net46\System.Console.dll</HintPath> + </Reference> + <Reference Include="System.Data" /> + <Reference Include="System.Diagnostics.FileVersionInfo, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> + <HintPath>..\..\packages\System.Diagnostics.FileVersionInfo.4.3.0\lib\net46\System.Diagnostics.FileVersionInfo.dll</HintPath> + </Reference> + <Reference Include="System.Diagnostics.StackTrace, Version=4.0.3.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> + <HintPath>..\..\packages\System.Diagnostics.StackTrace.4.3.0\lib\net46\System.Diagnostics.StackTrace.dll</HintPath> + </Reference> + <Reference Include="System.IO.Compression, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL"> + <HintPath>..\..\packages\System.IO.Compression.4.3.0\lib\net46\System.IO.Compression.dll</HintPath> + </Reference> + <Reference Include="System.IO.FileSystem, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> + <HintPath>..\..\packages\System.IO.FileSystem.4.3.0\lib\net46\System.IO.FileSystem.dll</HintPath> + </Reference> + <Reference Include="System.IO.FileSystem.Primitives, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> + <HintPath>..\..\packages\System.IO.FileSystem.Primitives.4.3.0\lib\net46\System.IO.FileSystem.Primitives.dll</HintPath> + </Reference> + <Reference Include="System.Numerics" /> + <Reference Include="System.Reflection.Metadata, Version=1.4.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> + <HintPath>..\..\packages\System.Reflection.Metadata.1.4.2\lib\portable-net45+win8\System.Reflection.Metadata.dll</HintPath> + </Reference> + <Reference Include="System.Security.Cryptography.Algorithms, Version=4.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> + <HintPath>..\..\packages\System.Security.Cryptography.Algorithms.4.3.0\lib\net461\System.Security.Cryptography.Algorithms.dll</HintPath> + </Reference> + <Reference Include="System.Security.Cryptography.Encoding, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> + <HintPath>..\..\packages\System.Security.Cryptography.Encoding.4.3.0\lib\net46\System.Security.Cryptography.Encoding.dll</HintPath> + </Reference> + <Reference Include="System.Security.Cryptography.Primitives, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> + <HintPath>..\..\packages\System.Security.Cryptography.Primitives.4.3.0\lib\net46\System.Security.Cryptography.Primitives.dll</HintPath> + </Reference> + <Reference Include="System.Security.Cryptography.X509Certificates, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> + <HintPath>..\..\packages\System.Security.Cryptography.X509Certificates.4.3.0\lib\net461\System.Security.Cryptography.X509Certificates.dll</HintPath> + </Reference> + <Reference Include="System.Text.Encoding.CodePages, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> + <HintPath>..\..\packages\System.Text.Encoding.CodePages.4.3.0\lib\net46\System.Text.Encoding.CodePages.dll</HintPath> + </Reference> + <Reference Include="System.Threading.Thread, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> + <HintPath>..\..\packages\System.Threading.Thread.4.3.0\lib\net46\System.Threading.Thread.dll</HintPath> + </Reference> + <Reference Include="System.ValueTuple, Version=4.0.1.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL"> + <HintPath>..\..\packages\System.ValueTuple.4.3.0\lib\netstandard1.0\System.ValueTuple.dll</HintPath> + </Reference> + <Reference Include="System.Windows.Forms" /> + <Reference Include="System.Xml" /> + <Reference Include="Microsoft.CSharp" /> + <Reference Include="System.Core" /> + <Reference Include="System.Xml.Linq" /> + <Reference Include="System.Data.DataSetExtensions" /> + <Reference Include="System.Net.Http" /> + <Reference Include="System.Xaml"> + <RequiredTargetFramework>4.0</RequiredTargetFramework> + </Reference> + <Reference Include="System.Xml.ReaderWriter, Version=4.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> + <HintPath>..\..\packages\System.Xml.ReaderWriter.4.3.0\lib\net46\System.Xml.ReaderWriter.dll</HintPath> + </Reference> + <Reference Include="System.Xml.XmlDocument, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> + <HintPath>..\..\packages\System.Xml.XmlDocument.4.3.0\lib\net46\System.Xml.XmlDocument.dll</HintPath> + </Reference> + <Reference Include="System.Xml.XPath, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> + <HintPath>..\..\packages\System.Xml.XPath.4.3.0\lib\net46\System.Xml.XPath.dll</HintPath> + </Reference> + <Reference Include="System.Xml.XPath.XDocument, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> + <HintPath>..\..\packages\System.Xml.XPath.XDocument.4.3.0\lib\net46\System.Xml.XPath.XDocument.dll</HintPath> + </Reference> + <Reference Include="WindowsBase" /> + <Reference Include="PresentationCore" /> + <Reference Include="PresentationFramework" /> + </ItemGroup> + <ItemGroup> + <Page Include="Themes\Generic.xaml"> + <Generator>MSBuild:Compile</Generator> + <SubType>Designer</SubType> + </Page> + </ItemGroup> + <ItemGroup> + <Compile Include="CompilationError.cs" /> + <Compile Include="CompilationResult.cs" /> + <Compile Include="GlobalObject.cs" /> + <Compile Include="Project.cs" /> + <Compile Include="ReferenceAssembly.cs" /> + <Compile Include="Properties\AssemblyInfo.cs"> + <SubType>Code</SubType> + </Compile> + <Compile Include="Properties\Resources.Designer.cs"> + <AutoGen>True</AutoGen> + <DesignTime>True</DesignTime> + <DependentUpon>Resources.resx</DependentUpon> + </Compile> + <Compile Include="Properties\Settings.Designer.cs"> + <AutoGen>True</AutoGen> + <DependentUpon>Settings.settings</DependentUpon> + <DesignTimeSharedInput>True</DesignTimeSharedInput> + </Compile> + <Compile Include="Script.cs" /> + <Compile Include="IContext.cs" /> + <Compile Include="ProjectSession.cs" /> + <Compile Include="ProjectSessionState.cs" /> + <Compile Include="ProjectSessionStateChangedEventArgs.cs" /> + <EmbeddedResource Include="Properties\Resources.resx"> + <Generator>ResXFileCodeGenerator</Generator> + <LastGenOutput>Resources.Designer.cs</LastGenOutput> + </EmbeddedResource> + <None Include="app.config" /> + <None Include="packages.config" /> + <None Include="Properties\Settings.settings"> + <Generator>SettingsSingleFileGenerator</Generator> + <LastGenOutput>Settings.Designer.cs</LastGenOutput> + </None> + <None Include="Resources\template.csx" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="..\..\Tango.Core\Tango.Core.csproj"> + <Project>{a34ee0f0-649d-41c8-8489-b6f1cc6924ee}</Project> + <Name>Tango.Core</Name> + </ProjectReference> + <ProjectReference Include="..\Tango.Scripting.Core\Tango.Scripting.Core.csproj"> + <Project>{5812E1C6-ABAA-4066-94AC-971C27B4F46A}</Project> + <Name>Tango.Scripting.Core</Name> + </ProjectReference> + </ItemGroup> + <ItemGroup> + <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> + <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> +</Project>
\ No newline at end of file diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/Themes/Generic.xaml b/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/Themes/Generic.xaml new file mode 100644 index 000000000..a6b1f858a --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/Themes/Generic.xaml @@ -0,0 +1,6 @@ +<ResourceDictionary + xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:local="clr-namespace:Tango.Scripting.Basic"> + +</ResourceDictionary> diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/app.config b/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/app.config new file mode 100644 index 000000000..451526a2c --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/app.config @@ -0,0 +1,47 @@ +<?xml version="1.0" encoding="utf-8"?> +<configuration> + <runtime> + <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> + <dependentAssembly> + <assemblyIdentity name="System.Collections.Immutable" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-1.2.1.0" newVersion="1.2.1.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="System.IO.Compression" publicKeyToken="b77a5c561934e089" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-4.1.2.0" newVersion="4.1.2.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="System.Security.Cryptography.Algorithms" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-4.1.0.0" newVersion="4.1.0.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="System.IO.FileSystem" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="System.IO.FileSystem.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="System.Security.Cryptography.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="System.Xml.XPath.XDocument" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="System.Console" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="System.Diagnostics.StackTrace" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="Microsoft.IdentityModel.Clients.ActiveDirectory" publicKeyToken="31bf3856ad364e35" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-5.0.5.0" newVersion="5.0.5.0" /> + </dependentAssembly> + </assemblyBinding> + </runtime> +</configuration>
\ No newline at end of file diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/packages.config b/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/packages.config new file mode 100644 index 000000000..fd135245d --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/packages.config @@ -0,0 +1,52 @@ +<?xml version="1.0" encoding="utf-8"?> +<packages> + <package id="Microsoft.CodeAnalysis.Analyzers" version="1.1.0" targetFramework="net461" /> + <package id="Microsoft.CodeAnalysis.Common" version="2.4.0" targetFramework="net461" /> + <package id="Microsoft.CodeAnalysis.CSharp" version="2.4.0" targetFramework="net461" /> + <package id="Microsoft.CodeAnalysis.CSharp.Scripting" version="2.4.0" targetFramework="net461" /> + <package id="Microsoft.CodeAnalysis.Scripting" version="2.4.0" targetFramework="net461" /> + <package id="Microsoft.CodeAnalysis.Scripting.Common" version="2.4.0" targetFramework="net461" /> + <package id="Newtonsoft.Json" version="9.0.1" targetFramework="net461" /> + <package id="System.AppContext" version="4.3.0" targetFramework="net461" /> + <package id="System.Collections" version="4.3.0" targetFramework="net461" /> + <package id="System.Collections.Concurrent" version="4.3.0" targetFramework="net461" /> + <package id="System.Collections.Immutable" version="1.3.1" targetFramework="net461" /> + <package id="System.Console" version="4.3.0" targetFramework="net461" /> + <package id="System.Diagnostics.Debug" version="4.3.0" targetFramework="net461" /> + <package id="System.Diagnostics.FileVersionInfo" version="4.3.0" targetFramework="net461" /> + <package id="System.Diagnostics.StackTrace" version="4.3.0" targetFramework="net461" /> + <package id="System.Diagnostics.Tools" version="4.3.0" targetFramework="net461" /> + <package id="System.Dynamic.Runtime" version="4.3.0" targetFramework="net461" /> + <package id="System.Globalization" version="4.3.0" targetFramework="net461" /> + <package id="System.IO" version="4.3.0" targetFramework="net461" /> + <package id="System.IO.Compression" version="4.3.0" targetFramework="net461" /> + <package id="System.IO.FileSystem" version="4.3.0" targetFramework="net461" /> + <package id="System.IO.FileSystem.Primitives" version="4.3.0" targetFramework="net461" /> + <package id="System.Linq" version="4.3.0" targetFramework="net461" /> + <package id="System.Linq.Expressions" version="4.3.0" targetFramework="net461" /> + <package id="System.Reflection" version="4.3.0" targetFramework="net461" /> + <package id="System.Reflection.Extensions" version="4.3.0" targetFramework="net461" /> + <package id="System.Reflection.Metadata" version="1.4.2" targetFramework="net461" /> + <package id="System.Resources.ResourceManager" version="4.3.0" targetFramework="net461" /> + <package id="System.Runtime" version="4.3.0" targetFramework="net461" /> + <package id="System.Runtime.Extensions" version="4.3.0" targetFramework="net461" /> + <package id="System.Runtime.InteropServices" version="4.3.0" targetFramework="net461" /> + <package id="System.Runtime.Numerics" version="4.3.0" targetFramework="net461" /> + <package id="System.Security.Cryptography.Algorithms" version="4.3.0" targetFramework="net461" /> + <package id="System.Security.Cryptography.Encoding" version="4.3.0" targetFramework="net461" /> + <package id="System.Security.Cryptography.Primitives" version="4.3.0" targetFramework="net461" /> + <package id="System.Security.Cryptography.X509Certificates" version="4.3.0" targetFramework="net461" /> + <package id="System.Text.Encoding" version="4.3.0" targetFramework="net461" /> + <package id="System.Text.Encoding.CodePages" version="4.3.0" targetFramework="net461" /> + <package id="System.Text.Encoding.Extensions" version="4.3.0" targetFramework="net461" /> + <package id="System.Threading" version="4.3.0" targetFramework="net461" /> + <package id="System.Threading.Tasks" version="4.3.0" targetFramework="net461" /> + <package id="System.Threading.Tasks.Parallel" version="4.3.0" targetFramework="net461" /> + <package id="System.Threading.Thread" version="4.3.0" targetFramework="net461" /> + <package id="System.ValueTuple" version="4.3.0" targetFramework="net461" /> + <package id="System.Xml.ReaderWriter" version="4.3.0" targetFramework="net461" /> + <package id="System.Xml.XDocument" version="4.3.0" targetFramework="net461" /> + <package id="System.Xml.XmlDocument" version="4.3.0" targetFramework="net461" /> + <package id="System.Xml.XPath" version="4.3.0" targetFramework="net461" /> + <package id="System.Xml.XPath.XDocument" version="4.3.0" targetFramework="net461" /> +</packages>
\ No newline at end of file diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Core/BreakPoint.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Core/BreakPoint.cs new file mode 100644 index 000000000..e847ea03e --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Core/BreakPoint.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.Scripting.Core +{ + public class BreakPoint + { + public int LineNumber { get; set; } + public bool IsActive { get; set; } + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Core/IScriptSource.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Core/IScriptSource.cs new file mode 100644 index 000000000..831d65935 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Core/IScriptSource.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.Scripting.Core +{ + public interface IScriptSource + { + String Code { get; set; } + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Core/Properties/AssemblyInfo.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Core/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..8b788d4cf --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Core/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Tango.Scripting.Core")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Tango.Scripting.Core")] +[assembly: AssemblyCopyright("Copyright © 2020")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("5812e1c6-abaa-4066-94ac-971c27b4f46a")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Core/ScriptBreakPoint.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Core/ScriptBreakPoint.cs new file mode 100644 index 000000000..626c1abc6 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Core/ScriptBreakPoint.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Scripting.Core; + +namespace Tango.Scripting.Core +{ + public class ScriptBreakPoint + { + public IScriptSource Script { get; set; } + public int LineNumber { get; set; } + public int LineStartOffset { get; set; } + public int LineEndOffset { get; set; } + public List<ScriptBreakPointSymbol> ContextSymbols { get; set; } + + public ScriptBreakPoint() + { + ContextSymbols = new List<ScriptBreakPointSymbol>(); + } + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Core/ScriptBreakPointSymbol.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Core/ScriptBreakPointSymbol.cs new file mode 100644 index 000000000..8da35fe55 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Core/ScriptBreakPointSymbol.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.Scripting.Core +{ + public class ScriptBreakPointSymbol + { + public String Name { get; set; } + public int Offset { get; set; } + public int Length { get; set; } + public Object SymbolObject { get; set; } + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Core/Tango.Scripting.Core.csproj b/Software/Visual_Studio/Scripting/Tango.Scripting.Core/Tango.Scripting.Core.csproj new file mode 100644 index 000000000..bb623a4fe --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Core/Tango.Scripting.Core.csproj @@ -0,0 +1,51 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <ProjectGuid>{5812E1C6-ABAA-4066-94AC-971C27B4F46A}</ProjectGuid> + <OutputType>Library</OutputType> + <AppDesignerFolder>Properties</AppDesignerFolder> + <RootNamespace>Tango.Scripting.Core</RootNamespace> + <AssemblyName>Tango.Scripting.Core</AssemblyName> + <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion> + <FileAlignment>512</FileAlignment> + <Deterministic>true</Deterministic> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\Debug\</OutputPath> + <DefineConstants>DEBUG;TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\Release\</OutputPath> + <DefineConstants>TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <ItemGroup> + <Reference Include="System" /> + <Reference Include="System.Core" /> + <Reference Include="System.Xml.Linq" /> + <Reference Include="System.Data.DataSetExtensions" /> + <Reference Include="Microsoft.CSharp" /> + <Reference Include="System.Data" /> + <Reference Include="System.Net.Http" /> + <Reference Include="System.Xml" /> + </ItemGroup> + <ItemGroup> + <Compile Include="BreakPoint.cs" /> + <Compile Include="IScriptSource.cs" /> + <Compile Include="Properties\AssemblyInfo.cs" /> + <Compile Include="ScriptBreakPoint.cs" /> + <Compile Include="ScriptBreakPointSymbol.cs" /> + </ItemGroup> + <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> +</Project>
\ No newline at end of file diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/BreakPointSymbolPressedEventArgs.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/BreakPointSymbolPressedEventArgs.cs new file mode 100644 index 000000000..1728bb565 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/BreakPointSymbolPressedEventArgs.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using Tango.Scripting.Core; + +namespace Tango.Scripting.Editors +{ + public class BreakPointSymbolPressedEventArgs : EventArgs + { + public ScriptBreakPointSymbol BreakPointSymbol { get; set; } + public Point Position { get; set; } + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/CachedAssembly.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/CachedAssembly.cs new file mode 100644 index 000000000..b0178e63e --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/CachedAssembly.cs @@ -0,0 +1,21 @@ +using Newtonsoft.Json; +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 CachedAssembly + { + public String Name { get; set; } + public List<KnownType> KnownTypes { get; set; } + + public CachedAssembly() + { + KnownTypes = new List<KnownType>(); + } + } +} 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/Document/TextDocument.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Document/TextDocument.cs index 84fc86f44..a95d07fcf 100644 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Document/TextDocument.cs +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Document/TextDocument.cs @@ -14,823 +14,884 @@ using Tango.Scripting.Editors.Utils; namespace Tango.Scripting.Editors.Document { - /// <summary> - /// This class is the main class of the text model. Basically, it is a <see cref="System.Text.StringBuilder"/> with events. - /// </summary> - /// <remarks> - /// <b>Thread safety:</b> - /// <inheritdoc cref="VerifyAccess"/> - /// <para>However, there is a single method that is thread-safe: <see cref="CreateSnapshot()"/> (and its overloads).</para> - /// </remarks> - public sealed class TextDocument : ITextSource, INotifyPropertyChanged - { - #region Thread ownership - readonly object lockObject = new object(); - Thread owner = Thread.CurrentThread; - - /// <summary> - /// Verifies that the current thread is the documents owner thread. - /// Throws an <see cref="InvalidOperationException"/> if the wrong thread accesses the TextDocument. - /// </summary> - /// <remarks> - /// <para>The TextDocument class is not thread-safe. A document instance expects to have a single owner thread - /// and will throw an <see cref="InvalidOperationException"/> when accessed from another thread. - /// It is possible to change the owner thread using the <see cref="SetOwnerThread"/> method.</para> - /// </remarks> - public void VerifyAccess() - { - if (Thread.CurrentThread != owner) - throw new InvalidOperationException("TextDocument can be accessed only from the thread that owns it."); - } - - /// <summary> - /// Transfers ownership of the document to another thread. This method can be used to load - /// a file into a TextDocument on a background thread and then transfer ownership to the UI thread - /// for displaying the document. - /// </summary> - /// <remarks> - /// <inheritdoc cref="VerifyAccess"/> - /// <para> - /// The owner can be set to null, which means that no thread can access the document. But, if the document - /// has no owner thread, any thread may take ownership by calling <see cref="SetOwnerThread"/>. - /// </para> - /// </remarks> - public void SetOwnerThread(Thread newOwner) - { - // We need to lock here to ensure that in the null owner case, - // only one thread succeeds in taking ownership. - lock (lockObject) { - if (owner != null) { - VerifyAccess(); - } - owner = newOwner; - } - } - #endregion - - #region Fields + Constructor - readonly Rope<char> rope; - readonly DocumentLineTree lineTree; - readonly LineManager lineManager; - readonly TextAnchorTree anchorTree; - ChangeTrackingCheckpoint currentCheckpoint; - - /// <summary> - /// Create an empty text document. - /// </summary> - public TextDocument() - : this(string.Empty) - { - } - - /// <summary> - /// Create a new text document with the specified initial text. - /// </summary> - public TextDocument(IEnumerable<char> initialText) - { - if (initialText == null) - throw new ArgumentNullException("initialText"); - rope = new Rope<char>(initialText); - lineTree = new DocumentLineTree(this); - lineManager = new LineManager(lineTree, this); - lineTrackers.CollectionChanged += delegate { - lineManager.UpdateListOfLineTrackers(); - }; - - anchorTree = new TextAnchorTree(this); - undoStack = new UndoStack(); - FireChangeEvents(); - } - - /// <summary> - /// Create a new text document with the specified initial text. - /// </summary> - public TextDocument(ITextSource initialText) - : this(GetTextFromTextSource(initialText)) - { - } - - // gets the text from a text source, directly retrieving the underlying rope where possible - static IEnumerable<char> GetTextFromTextSource(ITextSource textSource) - { - if (textSource == null) - throw new ArgumentNullException("textSource"); - - RopeTextSource rts = textSource as RopeTextSource; - if (rts != null) - return rts.GetRope(); - - TextDocument doc = textSource as TextDocument; - if (doc != null) - return doc.rope; - - return textSource.Text; - } - #endregion - - #region Text - void ThrowIfRangeInvalid(int offset, int length) - { - if (offset < 0 || offset > rope.Length) { - throw new ArgumentOutOfRangeException("offset", offset, "0 <= offset <= " + rope.Length.ToString(CultureInfo.InvariantCulture)); - } - if (length < 0 || offset + length > rope.Length) { - throw new ArgumentOutOfRangeException("length", length, "0 <= length, offset(" + offset + ")+length <= " + rope.Length.ToString(CultureInfo.InvariantCulture)); - } - } - - /// <inheritdoc/> - public string GetText(int offset, int length) - { - VerifyAccess(); - return rope.ToString(offset, length); - } - - /// <summary> - /// Retrieves the text for a portion of the document. - /// </summary> - public string GetText(ISegment segment) - { - if (segment == null) - throw new ArgumentNullException("segment"); - return GetText(segment.Offset, segment.Length); - } - - int ITextSource.IndexOfAny(char[] anyOf, int startIndex, int count) - { - DebugVerifyAccess(); // frequently called (NewLineFinder), so must be fast in release builds - return rope.IndexOfAny(anyOf, startIndex, count); - } - - /// <inheritdoc/> - public char GetCharAt(int offset) - { - DebugVerifyAccess(); // frequently called, so must be fast in release builds - return rope[offset]; - } - - WeakReference cachedText; - - /// <summary> - /// Gets/Sets the text of the whole document. - /// </summary> - public string Text { - get { - VerifyAccess(); - string completeText = cachedText != null ? (cachedText.Target as string) : null; - if (completeText == null) { - completeText = rope.ToString(); - cachedText = new WeakReference(completeText); - } - return completeText; - } - set { - VerifyAccess(); - if (value == null) - throw new ArgumentNullException("value"); - Replace(0, rope.Length, value); - } - } - - /// <inheritdoc/> - /// <remarks><inheritdoc cref="Changing"/></remarks> - public event EventHandler TextChanged; - - /// <inheritdoc/> - public int TextLength { - get { - VerifyAccess(); - return rope.Length; - } - } - - /// <summary> - /// Is raised when the TextLength property changes. - /// </summary> - /// <remarks><inheritdoc cref="Changing"/></remarks> - [Obsolete("This event will be removed in a future version; use the PropertyChanged event instead")] - public event EventHandler TextLengthChanged; - - /// <summary> - /// Is raised when one of the properties <see cref="Text"/>, <see cref="TextLength"/>, <see cref="LineCount"/>, - /// <see cref="UndoStack"/> changes. - /// </summary> - /// <remarks><inheritdoc cref="Changing"/></remarks> - public event PropertyChangedEventHandler PropertyChanged; - - /// <summary> - /// Is raised before the document changes. - /// </summary> - /// <remarks> - /// <para>Here is the order in which events are raised during a document update:</para> - /// <list type="bullet"> - /// <item><description><b><see cref="BeginUpdate">BeginUpdate()</see></b></description> - /// <list type="bullet"> - /// <item><description>Start of change group (on undo stack)</description></item> - /// <item><description><see cref="UpdateStarted"/> event is raised</description></item> - /// </list></item> - /// <item><description><b><see cref="Insert(int,string)">Insert()</see> / <see cref="Remove(int,int)">Remove()</see> / <see cref="Replace(int,int,string)">Replace()</see></b></description> - /// <list type="bullet"> - /// <item><description><see cref="Changing"/> event is raised</description></item> - /// <item><description>The document is changed</description></item> - /// <item><description><see cref="TextAnchor.Deleted">TextAnchor.Deleted</see> event is raised if anchors were - /// in the deleted text portion</description></item> - /// <item><description><see cref="Changed"/> event is raised</description></item> - /// </list></item> - /// <item><description><b><see cref="EndUpdate">EndUpdate()</see></b></description> - /// <list type="bullet"> - /// <item><description><see cref="TextChanged"/> event is raised</description></item> - /// <item><description><see cref="PropertyChanged"/> event is raised (for the Text, TextLength, LineCount properties, in that order)</description></item> - /// <item><description>End of change group (on undo stack)</description></item> - /// <item><description><see cref="UpdateFinished"/> event is raised</description></item> - /// </list></item> - /// </list> - /// <para> - /// If the insert/remove/replace methods are called without a call to <c>BeginUpdate()</c>, - /// they will call <c>BeginUpdate()</c> and <c>EndUpdate()</c> to ensure no change happens outside of <c>UpdateStarted</c>/<c>UpdateFinished</c>. - /// </para><para> - /// There can be multiple document changes between the <c>BeginUpdate()</c> and <c>EndUpdate()</c> calls. - /// In this case, the events associated with EndUpdate will be raised only once after the whole document update is done. - /// </para><para> - /// The <see cref="UndoStack"/> listens to the <c>UpdateStarted</c> and <c>UpdateFinished</c> events to group all changes into a single undo step. - /// </para> - /// </remarks> - public event EventHandler<DocumentChangeEventArgs> Changing; - - /// <summary> - /// Is raised after the document has changed. - /// </summary> - /// <remarks><inheritdoc cref="Changing"/></remarks> - public event EventHandler<DocumentChangeEventArgs> Changed; - - /// <summary> - /// Creates a snapshot of the current text. - /// </summary> - /// <remarks> - /// <para>This method returns an immutable snapshot of the document, and may be safely called even when - /// the document's owner thread is concurrently modifying the document. - /// </para><para> - /// This special thread-safety guarantee is valid only for TextDocument.CreateSnapshot(), not necessarily for other - /// classes implementing ITextSource.CreateSnapshot(). - /// </para><para> - /// </para> - /// </remarks> - public ITextSource CreateSnapshot() - { - lock (lockObject) { - return new RopeTextSource(rope.Clone()); - } - } - - /// <summary> - /// Creates a snapshot of the current text. - /// Additionally, creates a checkpoint that allows tracking document changes. - /// </summary> - /// <remarks><inheritdoc cref="CreateSnapshot()"/><inheritdoc cref="ChangeTrackingCheckpoint"/></remarks> - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", Justification = "Need to return snapshot and checkpoint together to ensure thread-safety")] - public ITextSource CreateSnapshot(out ChangeTrackingCheckpoint checkpoint) - { - lock (lockObject) { - if (currentCheckpoint == null) - currentCheckpoint = new ChangeTrackingCheckpoint(lockObject); - checkpoint = currentCheckpoint; - return new RopeTextSource(rope.Clone()); - } - } - - internal ChangeTrackingCheckpoint CreateChangeTrackingCheckpoint() - { - lock (lockObject) { - if (currentCheckpoint == null) - currentCheckpoint = new ChangeTrackingCheckpoint(lockObject); - return currentCheckpoint; - } - } - - /// <summary> - /// Creates a snapshot of a part of the current text. - /// </summary> - /// <remarks><inheritdoc cref="CreateSnapshot()"/></remarks> - public ITextSource CreateSnapshot(int offset, int length) - { - lock (lockObject) { - return new RopeTextSource(rope.GetRange(offset, length)); - } - } - - /// <inheritdoc/> - public System.IO.TextReader CreateReader() - { - lock (lockObject) { - return new RopeTextReader(rope); - } - } - #endregion - - #region BeginUpdate / EndUpdate - int beginUpdateCount; - - /// <summary> - /// Gets if an update is running. - /// </summary> - /// <remarks><inheritdoc cref="BeginUpdate"/></remarks> - public bool IsInUpdate { - get { - VerifyAccess(); - return beginUpdateCount > 0; - } - } - - /// <summary> - /// Immediately calls <see cref="BeginUpdate()"/>, - /// and returns an IDisposable that calls <see cref="EndUpdate()"/>. - /// </summary> - /// <remarks><inheritdoc cref="BeginUpdate"/></remarks> - public IDisposable RunUpdate() - { - BeginUpdate(); - return new CallbackOnDispose(EndUpdate); - } - - /// <summary> - /// <para>Begins a group of document changes.</para> - /// <para>Some events are suspended until EndUpdate is called, and the <see cref="UndoStack"/> will - /// group all changes into a single action.</para> - /// <para>Calling BeginUpdate several times increments a counter, only after the appropriate number - /// of EndUpdate calls the events resume their work.</para> - /// </summary> - /// <remarks><inheritdoc cref="Changing"/></remarks> - public void BeginUpdate() - { - VerifyAccess(); - if (inDocumentChanging) - throw new InvalidOperationException("Cannot change document within another document change."); - beginUpdateCount++; - if (beginUpdateCount == 1) { - undoStack.StartUndoGroup(); - if (UpdateStarted != null) - UpdateStarted(this, EventArgs.Empty); - } - } - - /// <summary> - /// Ends a group of document changes. - /// </summary> - /// <remarks><inheritdoc cref="Changing"/></remarks> - public void EndUpdate() - { - VerifyAccess(); - if (inDocumentChanging) - throw new InvalidOperationException("Cannot end update within document change."); - if (beginUpdateCount == 0) - throw new InvalidOperationException("No update is active."); - if (beginUpdateCount == 1) { - // fire change events inside the change group - event handlers might add additional - // document changes to the change group - FireChangeEvents(); - undoStack.EndUndoGroup(); - beginUpdateCount = 0; - if (UpdateFinished != null) - UpdateFinished(this, EventArgs.Empty); - } else { - beginUpdateCount -= 1; - } - } - - /// <summary> - /// Occurs when a document change starts. - /// </summary> - /// <remarks><inheritdoc cref="Changing"/></remarks> - public event EventHandler UpdateStarted; - - /// <summary> - /// Occurs when a document change is finished. - /// </summary> - /// <remarks><inheritdoc cref="Changing"/></remarks> - public event EventHandler UpdateFinished; - #endregion - - #region Fire events after update - int oldTextLength; - int oldLineCount; - bool fireTextChanged; - - /// <summary> - /// Fires TextChanged, TextLengthChanged, LineCountChanged if required. - /// </summary> - internal void FireChangeEvents() - { - // it may be necessary to fire the event multiple times if the document is changed - // from inside the event handlers - while (fireTextChanged) { - fireTextChanged = false; - if (TextChanged != null) - TextChanged(this, EventArgs.Empty); - OnPropertyChanged("Text"); - - int textLength = rope.Length; - if (textLength != oldTextLength) { - oldTextLength = textLength; - if (TextLengthChanged != null) - TextLengthChanged(this, EventArgs.Empty); - OnPropertyChanged("TextLength"); - } - int lineCount = lineTree.LineCount; - if (lineCount != oldLineCount) { - oldLineCount = lineCount; - if (LineCountChanged != null) - LineCountChanged(this, EventArgs.Empty); - OnPropertyChanged("LineCount"); - } - } - } - - void OnPropertyChanged(string propertyName) - { - if (PropertyChanged != null) - PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); - } - #endregion - - #region Insert / Remove / Replace - /// <summary> - /// Inserts text. - /// </summary> - public void Insert(int offset, string text) - { - Replace(offset, 0, text); - } - - /// <summary> - /// Removes text. - /// </summary> - public void Remove(ISegment segment) - { - Replace(segment, string.Empty); - } - - /// <summary> - /// Removes text. - /// </summary> - public void Remove(int offset, int length) - { - Replace(offset, length, string.Empty); - } - - internal bool inDocumentChanging; - - /// <summary> - /// Replaces text. - /// </summary> - public void Replace(ISegment segment, string text) - { - if (segment == null) - throw new ArgumentNullException("segment"); - Replace(segment.Offset, segment.Length, text, null); - } - - /// <summary> - /// Replaces text. - /// </summary> - public void Replace(int offset, int length, string text) - { - Replace(offset, length, text, null); - } - - /// <summary> - /// Replaces text. - /// </summary> - /// <param name="offset">The starting offset of the text to be replaced.</param> - /// <param name="length">The length of the text to be replaced.</param> - /// <param name="text">The new text.</param> - /// <param name="offsetChangeMappingType">The offsetChangeMappingType determines how offsets inside the old text are mapped to the new text. - /// This affects how the anchors and segments inside the replaced region behave.</param> - public void Replace(int offset, int length, string text, OffsetChangeMappingType offsetChangeMappingType) - { - if (text == null) - throw new ArgumentNullException("text"); - // Please see OffsetChangeMappingType XML comments for details on how these modes work. - switch (offsetChangeMappingType) { - case OffsetChangeMappingType.Normal: - Replace(offset, length, text, null); - break; - case OffsetChangeMappingType.KeepAnchorBeforeInsertion: - Replace(offset, length, text, OffsetChangeMap.FromSingleElement( - new OffsetChangeMapEntry(offset, length, text.Length, false, true))); - break; - case OffsetChangeMappingType.RemoveAndInsert: - if (length == 0 || text.Length == 0) { - // only insertion or only removal? - // OffsetChangeMappingType doesn't matter, just use Normal. - Replace(offset, length, text, null); - } else { - OffsetChangeMap map = new OffsetChangeMap(2); - map.Add(new OffsetChangeMapEntry(offset, length, 0)); - map.Add(new OffsetChangeMapEntry(offset, 0, text.Length)); - map.Freeze(); - Replace(offset, length, text, map); - } - break; - case OffsetChangeMappingType.CharacterReplace: - if (length == 0 || text.Length == 0) { - // only insertion or only removal? - // OffsetChangeMappingType doesn't matter, just use Normal. - Replace(offset, length, text, null); - } else if (text.Length > length) { - // look at OffsetChangeMappingType.CharacterReplace XML comments on why we need to replace - // the last character - OffsetChangeMapEntry entry = new OffsetChangeMapEntry(offset + length - 1, 1, 1 + text.Length - length); - Replace(offset, length, text, OffsetChangeMap.FromSingleElement(entry)); - } else if (text.Length < length) { - OffsetChangeMapEntry entry = new OffsetChangeMapEntry(offset + text.Length, length - text.Length, 0, true, false); - Replace(offset, length, text, OffsetChangeMap.FromSingleElement(entry)); - } else { - Replace(offset, length, text, OffsetChangeMap.Empty); - } - break; - default: - throw new ArgumentOutOfRangeException("offsetChangeMappingType", offsetChangeMappingType, "Invalid enum value"); - } - } - - /// <summary> - /// Replaces text. - /// </summary> - /// <param name="offset">The starting offset of the text to be replaced.</param> - /// <param name="length">The length of the text to be replaced.</param> - /// <param name="text">The new text.</param> - /// <param name="offsetChangeMap">The offsetChangeMap determines how offsets inside the old text are mapped to the new text. - /// This affects how the anchors and segments inside the replaced region behave. - /// If you pass null (the default when using one of the other overloads), the offsets are changed as - /// in OffsetChangeMappingType.Normal mode. - /// If you pass OffsetChangeMap.Empty, then everything will stay in its old place (OffsetChangeMappingType.CharacterReplace mode). - /// The offsetChangeMap must be a valid 'explanation' for the document change. See <see cref="OffsetChangeMap.IsValidForDocumentChange"/>. - /// Passing an OffsetChangeMap to the Replace method will automatically freeze it to ensure the thread safety of the resulting - /// DocumentChangeEventArgs instance. - /// </param> - public void Replace(int offset, int length, string text, OffsetChangeMap offsetChangeMap) - { - if (text == null) - throw new ArgumentNullException("text"); - - if (offsetChangeMap != null) - offsetChangeMap.Freeze(); - - // Ensure that all changes take place inside an update group. - // Will also take care of throwing an exception if inDocumentChanging is set. - BeginUpdate(); - try { - // protect document change against corruption by other changes inside the event handlers - inDocumentChanging = true; - try { - // The range verification must wait until after the BeginUpdate() call because the document - // might be modified inside the UpdateStarted event. - ThrowIfRangeInvalid(offset, length); - - DoReplace(offset, length, text, offsetChangeMap); - } finally { - inDocumentChanging = false; - } - } finally { - EndUpdate(); - } - } - - void DoReplace(int offset, int length, string newText, OffsetChangeMap offsetChangeMap) - { - if (length == 0 && newText.Length == 0) - return; - - // trying to replace a single character in 'Normal' mode? - // for single characters, 'CharacterReplace' mode is equivalent, but more performant - // (we don't have to touch the anchorTree at all in 'CharacterReplace' mode) - if (length == 1 && newText.Length == 1 && offsetChangeMap == null) - offsetChangeMap = OffsetChangeMap.Empty; - - string removedText = rope.ToString(offset, length); - DocumentChangeEventArgs args = new DocumentChangeEventArgs(offset, removedText, newText, offsetChangeMap); - - // fire DocumentChanging event - if (Changing != null) - Changing(this, args); - - undoStack.Push(this, args); - - cachedText = null; // reset cache of complete document text - fireTextChanged = true; - DelayedEvents delayedEvents = new DelayedEvents(); - - lock (lockObject) { - // create linked list of checkpoints, if required - if (currentCheckpoint != null) { - currentCheckpoint = currentCheckpoint.Append(args); - } - - // now update the textBuffer and lineTree - if (offset == 0 && length == rope.Length) { - // optimize replacing the whole document - rope.Clear(); - rope.InsertText(0, newText); - lineManager.Rebuild(); - } else { - rope.RemoveRange(offset, length); - lineManager.Remove(offset, length); - #if DEBUG - lineTree.CheckProperties(); - #endif - rope.InsertText(offset, newText); - lineManager.Insert(offset, newText); - #if DEBUG - lineTree.CheckProperties(); - #endif - } - } - - // update text anchors - if (offsetChangeMap == null) { - anchorTree.HandleTextChange(args.CreateSingleChangeMapEntry(), delayedEvents); - } else { - foreach (OffsetChangeMapEntry entry in offsetChangeMap) { - anchorTree.HandleTextChange(entry, delayedEvents); - } - } - - // raise delayed events after our data structures are consistent again - delayedEvents.RaiseEvents(); - - // fire DocumentChanged event - if (Changed != null) - Changed(this, args); - } - #endregion - - #region GetLineBy... - /// <summary> - /// Gets a read-only list of lines. - /// </summary> - /// <remarks><inheritdoc cref="DocumentLine"/></remarks> - public IList<DocumentLine> Lines { - get { return lineTree; } - } - - /// <summary> - /// Gets a line by the line number: O(log n) - /// </summary> - public DocumentLine GetLineByNumber(int number) - { - VerifyAccess(); - if (number < 1 || number > lineTree.LineCount) - throw new ArgumentOutOfRangeException("number", number, "Value must be between 1 and " + lineTree.LineCount); - return lineTree.GetByNumber(number); - } - - /// <summary> - /// Gets a document lines by offset. - /// Runtime: O(log n) - /// </summary> - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "System.Int32.ToString")] - public DocumentLine GetLineByOffset(int offset) - { - VerifyAccess(); - if (offset < 0 || offset > rope.Length) { - throw new ArgumentOutOfRangeException("offset", offset, "0 <= offset <= " + rope.Length.ToString()); - } - return lineTree.GetByOffset(offset); - } - #endregion - - /// <summary> - /// Gets the offset from a text location. - /// </summary> - /// <seealso cref="GetLocation"/> - public int GetOffset(TextLocation location) - { - return GetOffset(location.Line, location.Column); - } - - /// <summary> - /// Gets the offset from a text location. - /// </summary> - /// <seealso cref="GetLocation"/> - public int GetOffset(int line, int column) - { - DocumentLine docLine = GetLineByNumber(line); - if (column <= 0) - return docLine.Offset; - if (column > docLine.Length) - return docLine.EndOffset; - return docLine.Offset + column - 1; - } - - /// <summary> - /// Gets the location from an offset. - /// </summary> - /// <seealso cref="GetOffset(TextLocation)"/> - public TextLocation GetLocation(int offset) - { - DocumentLine line = GetLineByOffset(offset); - return new TextLocation(line.LineNumber, offset - line.Offset + 1); - } - - readonly ObservableCollection<ILineTracker> lineTrackers = new ObservableCollection<ILineTracker>(); - - /// <summary> - /// Gets the list of <see cref="ILineTracker"/>s attached to this document. - /// You can add custom line trackers to this list. - /// </summary> - public IList<ILineTracker> LineTrackers { - get { - VerifyAccess(); - return lineTrackers; - } - } - - UndoStack undoStack; - - /// <summary> - /// Gets the <see cref="UndoStack"/> of the document. - /// </summary> - /// <remarks>This property can also be used to set the undo stack, e.g. for sharing a common undo stack between multiple documents.</remarks> - public UndoStack UndoStack { - get { return undoStack; } - set { - if (value == null) - throw new ArgumentNullException(); - if (value != undoStack) { - undoStack.ClearAll(); // first clear old undo stack, so that it can't be used to perform unexpected changes on this document - // ClearAll() will also throw an exception when it's not safe to replace the undo stack (e.g. update is currently in progress) - undoStack = value; - OnPropertyChanged("UndoStack"); - } - } - } - - /// <summary> - /// Creates a new <see cref="TextAnchor"/> at the specified offset. - /// </summary> - /// <inheritdoc cref="TextAnchor" select="remarks|example"/> - public TextAnchor CreateAnchor(int offset) - { - VerifyAccess(); - if (offset < 0 || offset > rope.Length) { - throw new ArgumentOutOfRangeException("offset", offset, "0 <= offset <= " + rope.Length.ToString(CultureInfo.InvariantCulture)); - } - return anchorTree.CreateAnchor(offset); - } - - #region LineCount - /// <summary> - /// Gets the total number of lines in the document. - /// Runtime: O(1). - /// </summary> - public int LineCount { - get { - VerifyAccess(); - return lineTree.LineCount; - } - } - - /// <summary> - /// Is raised when the LineCount property changes. - /// </summary> - [Obsolete("This event will be removed in a future version; use the PropertyChanged event instead")] - public event EventHandler LineCountChanged; - #endregion - - #region Debugging - [Conditional("DEBUG")] - internal void DebugVerifyAccess() - { - VerifyAccess(); - } - - /// <summary> - /// Gets the document lines tree in string form. - /// </summary> - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] - internal string GetLineTreeAsString() - { - #if DEBUG - return lineTree.GetTreeAsString(); - #else + /// <summary> + /// This class is the main class of the text model. Basically, it is a <see cref="System.Text.StringBuilder"/> with events. + /// </summary> + /// <remarks> + /// <b>Thread safety:</b> + /// <inheritdoc cref="VerifyAccess"/> + /// <para>However, there is a single method that is thread-safe: <see cref="CreateSnapshot()"/> (and its overloads).</para> + /// </remarks> + public sealed class TextDocument : ITextSource, INotifyPropertyChanged + { + #region Thread ownership + readonly object lockObject = new object(); + Thread owner = Thread.CurrentThread; + + /// <summary> + /// Verifies that the current thread is the documents owner thread. + /// Throws an <see cref="InvalidOperationException"/> if the wrong thread accesses the TextDocument. + /// </summary> + /// <remarks> + /// <para>The TextDocument class is not thread-safe. A document instance expects to have a single owner thread + /// and will throw an <see cref="InvalidOperationException"/> when accessed from another thread. + /// It is possible to change the owner thread using the <see cref="SetOwnerThread"/> method.</para> + /// </remarks> + public void VerifyAccess() + { + if (Thread.CurrentThread != owner) + throw new InvalidOperationException("TextDocument can be accessed only from the thread that owns it."); + } + + /// <summary> + /// Transfers ownership of the document to another thread. This method can be used to load + /// a file into a TextDocument on a background thread and then transfer ownership to the UI thread + /// for displaying the document. + /// </summary> + /// <remarks> + /// <inheritdoc cref="VerifyAccess"/> + /// <para> + /// The owner can be set to null, which means that no thread can access the document. But, if the document + /// has no owner thread, any thread may take ownership by calling <see cref="SetOwnerThread"/>. + /// </para> + /// </remarks> + public void SetOwnerThread(Thread newOwner) + { + // We need to lock here to ensure that in the null owner case, + // only one thread succeeds in taking ownership. + lock (lockObject) + { + if (owner != null) + { + VerifyAccess(); + } + owner = newOwner; + } + } + #endregion + + #region Fields + Constructor + readonly Rope<char> rope; + readonly DocumentLineTree lineTree; + readonly LineManager lineManager; + readonly TextAnchorTree anchorTree; + ChangeTrackingCheckpoint currentCheckpoint; + + /// <summary> + /// Create an empty text document. + /// </summary> + public TextDocument() + : this(string.Empty) + { + } + + /// <summary> + /// Create a new text document with the specified initial text. + /// </summary> + public TextDocument(IEnumerable<char> initialText) + { + if (initialText == null) + throw new ArgumentNullException("initialText"); + rope = new Rope<char>(initialText); + lineTree = new DocumentLineTree(this); + lineManager = new LineManager(lineTree, this); + lineTrackers.CollectionChanged += delegate + { + lineManager.UpdateListOfLineTrackers(); + }; + + anchorTree = new TextAnchorTree(this); + undoStack = new UndoStack(); + FireChangeEvents(); + } + + /// <summary> + /// Create a new text document with the specified initial text. + /// </summary> + public TextDocument(ITextSource initialText) + : this(GetTextFromTextSource(initialText)) + { + } + + // gets the text from a text source, directly retrieving the underlying rope where possible + static IEnumerable<char> GetTextFromTextSource(ITextSource textSource) + { + if (textSource == null) + throw new ArgumentNullException("textSource"); + + RopeTextSource rts = textSource as RopeTextSource; + if (rts != null) + return rts.GetRope(); + + TextDocument doc = textSource as TextDocument; + if (doc != null) + return doc.rope; + + return textSource.Text; + } + #endregion + + #region Text + void ThrowIfRangeInvalid(int offset, int length) + { + if (offset < 0 || offset > rope.Length) + { + throw new ArgumentOutOfRangeException("offset", offset, "0 <= offset <= " + rope.Length.ToString(CultureInfo.InvariantCulture)); + } + if (length < 0 || offset + length > rope.Length) + { + throw new ArgumentOutOfRangeException("length", length, "0 <= length, offset(" + offset + ")+length <= " + rope.Length.ToString(CultureInfo.InvariantCulture)); + } + } + + /// <inheritdoc/> + public string GetText(int offset, int length) + { + VerifyAccess(); + return rope.ToString(Math.Max(offset, 0), length); + } + + /// <summary> + /// Retrieves the text for a portion of the document. + /// </summary> + public string GetText(ISegment segment) + { + if (segment == null) + throw new ArgumentNullException("segment"); + return GetText(segment.Offset, segment.Length); + } + + int ITextSource.IndexOfAny(char[] anyOf, int startIndex, int count) + { + DebugVerifyAccess(); // frequently called (NewLineFinder), so must be fast in release builds + return rope.IndexOfAny(anyOf, startIndex, count); + } + + /// <inheritdoc/> + public char GetCharAt(int offset) + { + DebugVerifyAccess(); // frequently called, so must be fast in release builds + return rope[offset]; + } + + WeakReference cachedText; + + /// <summary> + /// Gets/Sets the text of the whole document. + /// </summary> + public string Text + { + get + { + VerifyAccess(); + string completeText = cachedText != null ? (cachedText.Target as string) : null; + if (completeText == null) + { + completeText = rope.ToString(); + cachedText = new WeakReference(completeText); + } + return completeText; + } + set + { + VerifyAccess(); + if (value == null) + throw new ArgumentNullException("value"); + Replace(0, rope.Length, value); + } + } + + /// <inheritdoc/> + /// <remarks><inheritdoc cref="Changing"/></remarks> + public event EventHandler TextChanged; + + /// <inheritdoc/> + public int TextLength + { + get + { + VerifyAccess(); + return rope.Length; + } + } + + /// <summary> + /// Is raised when the TextLength property changes. + /// </summary> + /// <remarks><inheritdoc cref="Changing"/></remarks> + [Obsolete("This event will be removed in a future version; use the PropertyChanged event instead")] + public event EventHandler TextLengthChanged; + + /// <summary> + /// Is raised when one of the properties <see cref="Text"/>, <see cref="TextLength"/>, <see cref="LineCount"/>, + /// <see cref="UndoStack"/> changes. + /// </summary> + /// <remarks><inheritdoc cref="Changing"/></remarks> + public event PropertyChangedEventHandler PropertyChanged; + + /// <summary> + /// Is raised before the document changes. + /// </summary> + /// <remarks> + /// <para>Here is the order in which events are raised during a document update:</para> + /// <list type="bullet"> + /// <item><description><b><see cref="BeginUpdate">BeginUpdate()</see></b></description> + /// <list type="bullet"> + /// <item><description>Start of change group (on undo stack)</description></item> + /// <item><description><see cref="UpdateStarted"/> event is raised</description></item> + /// </list></item> + /// <item><description><b><see cref="Insert(int,string)">Insert()</see> / <see cref="Remove(int,int)">Remove()</see> / <see cref="Replace(int,int,string)">Replace()</see></b></description> + /// <list type="bullet"> + /// <item><description><see cref="Changing"/> event is raised</description></item> + /// <item><description>The document is changed</description></item> + /// <item><description><see cref="TextAnchor.Deleted">TextAnchor.Deleted</see> event is raised if anchors were + /// in the deleted text portion</description></item> + /// <item><description><see cref="Changed"/> event is raised</description></item> + /// </list></item> + /// <item><description><b><see cref="EndUpdate">EndUpdate()</see></b></description> + /// <list type="bullet"> + /// <item><description><see cref="TextChanged"/> event is raised</description></item> + /// <item><description><see cref="PropertyChanged"/> event is raised (for the Text, TextLength, LineCount properties, in that order)</description></item> + /// <item><description>End of change group (on undo stack)</description></item> + /// <item><description><see cref="UpdateFinished"/> event is raised</description></item> + /// </list></item> + /// </list> + /// <para> + /// If the insert/remove/replace methods are called without a call to <c>BeginUpdate()</c>, + /// they will call <c>BeginUpdate()</c> and <c>EndUpdate()</c> to ensure no change happens outside of <c>UpdateStarted</c>/<c>UpdateFinished</c>. + /// </para><para> + /// There can be multiple document changes between the <c>BeginUpdate()</c> and <c>EndUpdate()</c> calls. + /// In this case, the events associated with EndUpdate will be raised only once after the whole document update is done. + /// </para><para> + /// The <see cref="UndoStack"/> listens to the <c>UpdateStarted</c> and <c>UpdateFinished</c> events to group all changes into a single undo step. + /// </para> + /// </remarks> + public event EventHandler<DocumentChangeEventArgs> Changing; + + /// <summary> + /// Is raised after the document has changed. + /// </summary> + /// <remarks><inheritdoc cref="Changing"/></remarks> + public event EventHandler<DocumentChangeEventArgs> Changed; + + /// <summary> + /// Creates a snapshot of the current text. + /// </summary> + /// <remarks> + /// <para>This method returns an immutable snapshot of the document, and may be safely called even when + /// the document's owner thread is concurrently modifying the document. + /// </para><para> + /// This special thread-safety guarantee is valid only for TextDocument.CreateSnapshot(), not necessarily for other + /// classes implementing ITextSource.CreateSnapshot(). + /// </para><para> + /// </para> + /// </remarks> + public ITextSource CreateSnapshot() + { + lock (lockObject) + { + return new RopeTextSource(rope.Clone()); + } + } + + /// <summary> + /// Creates a snapshot of the current text. + /// Additionally, creates a checkpoint that allows tracking document changes. + /// </summary> + /// <remarks><inheritdoc cref="CreateSnapshot()"/><inheritdoc cref="ChangeTrackingCheckpoint"/></remarks> + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", Justification = "Need to return snapshot and checkpoint together to ensure thread-safety")] + public ITextSource CreateSnapshot(out ChangeTrackingCheckpoint checkpoint) + { + lock (lockObject) + { + if (currentCheckpoint == null) + currentCheckpoint = new ChangeTrackingCheckpoint(lockObject); + checkpoint = currentCheckpoint; + return new RopeTextSource(rope.Clone()); + } + } + + internal ChangeTrackingCheckpoint CreateChangeTrackingCheckpoint() + { + lock (lockObject) + { + if (currentCheckpoint == null) + currentCheckpoint = new ChangeTrackingCheckpoint(lockObject); + return currentCheckpoint; + } + } + + /// <summary> + /// Creates a snapshot of a part of the current text. + /// </summary> + /// <remarks><inheritdoc cref="CreateSnapshot()"/></remarks> + public ITextSource CreateSnapshot(int offset, int length) + { + lock (lockObject) + { + return new RopeTextSource(rope.GetRange(offset, length)); + } + } + + /// <inheritdoc/> + public System.IO.TextReader CreateReader() + { + lock (lockObject) + { + return new RopeTextReader(rope); + } + } + #endregion + + #region BeginUpdate / EndUpdate + int beginUpdateCount; + + /// <summary> + /// Gets if an update is running. + /// </summary> + /// <remarks><inheritdoc cref="BeginUpdate"/></remarks> + public bool IsInUpdate + { + get + { + VerifyAccess(); + return beginUpdateCount > 0; + } + } + + /// <summary> + /// Immediately calls <see cref="BeginUpdate()"/>, + /// and returns an IDisposable that calls <see cref="EndUpdate()"/>. + /// </summary> + /// <remarks><inheritdoc cref="BeginUpdate"/></remarks> + public IDisposable RunUpdate() + { + BeginUpdate(); + return new CallbackOnDispose(EndUpdate); + } + + /// <summary> + /// <para>Begins a group of document changes.</para> + /// <para>Some events are suspended until EndUpdate is called, and the <see cref="UndoStack"/> will + /// group all changes into a single action.</para> + /// <para>Calling BeginUpdate several times increments a counter, only after the appropriate number + /// of EndUpdate calls the events resume their work.</para> + /// </summary> + /// <remarks><inheritdoc cref="Changing"/></remarks> + public void BeginUpdate() + { + VerifyAccess(); + if (inDocumentChanging) + throw new InvalidOperationException("Cannot change document within another document change."); + beginUpdateCount++; + if (beginUpdateCount == 1) + { + undoStack.StartUndoGroup(); + if (UpdateStarted != null) + UpdateStarted(this, EventArgs.Empty); + } + } + + /// <summary> + /// Ends a group of document changes. + /// </summary> + /// <remarks><inheritdoc cref="Changing"/></remarks> + public void EndUpdate() + { + VerifyAccess(); + if (inDocumentChanging) + throw new InvalidOperationException("Cannot end update within document change."); + if (beginUpdateCount == 0) + throw new InvalidOperationException("No update is active."); + if (beginUpdateCount == 1) + { + // fire change events inside the change group - event handlers might add additional + // document changes to the change group + FireChangeEvents(); + undoStack.EndUndoGroup(); + beginUpdateCount = 0; + if (UpdateFinished != null) + UpdateFinished(this, EventArgs.Empty); + } + else + { + beginUpdateCount -= 1; + } + } + + /// <summary> + /// Occurs when a document change starts. + /// </summary> + /// <remarks><inheritdoc cref="Changing"/></remarks> + public event EventHandler UpdateStarted; + + /// <summary> + /// Occurs when a document change is finished. + /// </summary> + /// <remarks><inheritdoc cref="Changing"/></remarks> + public event EventHandler UpdateFinished; + #endregion + + #region Fire events after update + int oldTextLength; + int oldLineCount; + bool fireTextChanged; + + /// <summary> + /// Fires TextChanged, TextLengthChanged, LineCountChanged if required. + /// </summary> + internal void FireChangeEvents() + { + // it may be necessary to fire the event multiple times if the document is changed + // from inside the event handlers + while (fireTextChanged) + { + fireTextChanged = false; + if (TextChanged != null) + TextChanged(this, EventArgs.Empty); + OnPropertyChanged("Text"); + + int textLength = rope.Length; + if (textLength != oldTextLength) + { + oldTextLength = textLength; + if (TextLengthChanged != null) + TextLengthChanged(this, EventArgs.Empty); + OnPropertyChanged("TextLength"); + } + int lineCount = lineTree.LineCount; + if (lineCount != oldLineCount) + { + oldLineCount = lineCount; + if (LineCountChanged != null) + LineCountChanged(this, EventArgs.Empty); + OnPropertyChanged("LineCount"); + } + } + } + + void OnPropertyChanged(string propertyName) + { + if (PropertyChanged != null) + PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); + } + #endregion + + #region Insert / Remove / Replace + /// <summary> + /// Inserts text. + /// </summary> + public void Insert(int offset, string text) + { + Replace(offset, 0, text); + } + + /// <summary> + /// Removes text. + /// </summary> + public void Remove(ISegment segment) + { + Replace(segment, string.Empty); + } + + /// <summary> + /// Removes text. + /// </summary> + public void Remove(int offset, int length) + { + Replace(offset, length, string.Empty); + } + + internal bool inDocumentChanging; + + /// <summary> + /// Replaces text. + /// </summary> + public void Replace(ISegment segment, string text) + { + if (segment == null) + throw new ArgumentNullException("segment"); + Replace(segment.Offset, segment.Length, text, null); + } + + /// <summary> + /// Replaces text. + /// </summary> + public void Replace(int offset, int length, string text) + { + Replace(offset, length, text, null); + } + + /// <summary> + /// Replaces text. + /// </summary> + /// <param name="offset">The starting offset of the text to be replaced.</param> + /// <param name="length">The length of the text to be replaced.</param> + /// <param name="text">The new text.</param> + /// <param name="offsetChangeMappingType">The offsetChangeMappingType determines how offsets inside the old text are mapped to the new text. + /// This affects how the anchors and segments inside the replaced region behave.</param> + public void Replace(int offset, int length, string text, OffsetChangeMappingType offsetChangeMappingType) + { + if (text == null) + throw new ArgumentNullException("text"); + // Please see OffsetChangeMappingType XML comments for details on how these modes work. + switch (offsetChangeMappingType) + { + case OffsetChangeMappingType.Normal: + Replace(offset, length, text, null); + break; + case OffsetChangeMappingType.KeepAnchorBeforeInsertion: + Replace(offset, length, text, OffsetChangeMap.FromSingleElement( + new OffsetChangeMapEntry(offset, length, text.Length, false, true))); + break; + case OffsetChangeMappingType.RemoveAndInsert: + if (length == 0 || text.Length == 0) + { + // only insertion or only removal? + // OffsetChangeMappingType doesn't matter, just use Normal. + Replace(offset, length, text, null); + } + else + { + OffsetChangeMap map = new OffsetChangeMap(2); + map.Add(new OffsetChangeMapEntry(offset, length, 0)); + map.Add(new OffsetChangeMapEntry(offset, 0, text.Length)); + map.Freeze(); + Replace(offset, length, text, map); + } + break; + case OffsetChangeMappingType.CharacterReplace: + if (length == 0 || text.Length == 0) + { + // only insertion or only removal? + // OffsetChangeMappingType doesn't matter, just use Normal. + Replace(offset, length, text, null); + } + else if (text.Length > length) + { + // look at OffsetChangeMappingType.CharacterReplace XML comments on why we need to replace + // the last character + OffsetChangeMapEntry entry = new OffsetChangeMapEntry(offset + length - 1, 1, 1 + text.Length - length); + Replace(offset, length, text, OffsetChangeMap.FromSingleElement(entry)); + } + else if (text.Length < length) + { + OffsetChangeMapEntry entry = new OffsetChangeMapEntry(offset + text.Length, length - text.Length, 0, true, false); + Replace(offset, length, text, OffsetChangeMap.FromSingleElement(entry)); + } + else + { + Replace(offset, length, text, OffsetChangeMap.Empty); + } + break; + default: + throw new ArgumentOutOfRangeException("offsetChangeMappingType", offsetChangeMappingType, "Invalid enum value"); + } + } + + /// <summary> + /// Replaces text. + /// </summary> + /// <param name="offset">The starting offset of the text to be replaced.</param> + /// <param name="length">The length of the text to be replaced.</param> + /// <param name="text">The new text.</param> + /// <param name="offsetChangeMap">The offsetChangeMap determines how offsets inside the old text are mapped to the new text. + /// This affects how the anchors and segments inside the replaced region behave. + /// If you pass null (the default when using one of the other overloads), the offsets are changed as + /// in OffsetChangeMappingType.Normal mode. + /// If you pass OffsetChangeMap.Empty, then everything will stay in its old place (OffsetChangeMappingType.CharacterReplace mode). + /// The offsetChangeMap must be a valid 'explanation' for the document change. See <see cref="OffsetChangeMap.IsValidForDocumentChange"/>. + /// Passing an OffsetChangeMap to the Replace method will automatically freeze it to ensure the thread safety of the resulting + /// DocumentChangeEventArgs instance. + /// </param> + public void Replace(int offset, int length, string text, OffsetChangeMap offsetChangeMap) + { + if (text == null) + throw new ArgumentNullException("text"); + + if (offsetChangeMap != null) + offsetChangeMap.Freeze(); + + // Ensure that all changes take place inside an update group. + // Will also take care of throwing an exception if inDocumentChanging is set. + BeginUpdate(); + try + { + // protect document change against corruption by other changes inside the event handlers + inDocumentChanging = true; + try + { + // The range verification must wait until after the BeginUpdate() call because the document + // might be modified inside the UpdateStarted event. + ThrowIfRangeInvalid(offset, length); + + DoReplace(offset, length, text, offsetChangeMap); + } + finally + { + inDocumentChanging = false; + } + } + finally + { + EndUpdate(); + } + } + + void DoReplace(int offset, int length, string newText, OffsetChangeMap offsetChangeMap) + { + if (length == 0 && newText.Length == 0) + return; + + // trying to replace a single character in 'Normal' mode? + // for single characters, 'CharacterReplace' mode is equivalent, but more performant + // (we don't have to touch the anchorTree at all in 'CharacterReplace' mode) + if (length == 1 && newText.Length == 1 && offsetChangeMap == null) + offsetChangeMap = OffsetChangeMap.Empty; + + string removedText = rope.ToString(offset, length); + DocumentChangeEventArgs args = new DocumentChangeEventArgs(offset, removedText, newText, offsetChangeMap); + + // fire DocumentChanging event + if (Changing != null) + Changing(this, args); + + undoStack.Push(this, args); + + cachedText = null; // reset cache of complete document text + fireTextChanged = true; + DelayedEvents delayedEvents = new DelayedEvents(); + + lock (lockObject) + { + // create linked list of checkpoints, if required + if (currentCheckpoint != null) + { + currentCheckpoint = currentCheckpoint.Append(args); + } + + // now update the textBuffer and lineTree + if (offset == 0 && length == rope.Length) + { + // optimize replacing the whole document + rope.Clear(); + rope.InsertText(0, newText); + lineManager.Rebuild(); + } + else + { + rope.RemoveRange(offset, length); + lineManager.Remove(offset, length); +#if DEBUG + lineTree.CheckProperties(); +#endif + rope.InsertText(offset, newText); + lineManager.Insert(offset, newText); +#if DEBUG + lineTree.CheckProperties(); +#endif + } + } + + // update text anchors + if (offsetChangeMap == null) + { + anchorTree.HandleTextChange(args.CreateSingleChangeMapEntry(), delayedEvents); + } + else + { + foreach (OffsetChangeMapEntry entry in offsetChangeMap) + { + anchorTree.HandleTextChange(entry, delayedEvents); + } + } + + // raise delayed events after our data structures are consistent again + delayedEvents.RaiseEvents(); + + // fire DocumentChanged event + if (Changed != null) + Changed(this, args); + } + #endregion + + #region GetLineBy... + /// <summary> + /// Gets a read-only list of lines. + /// </summary> + /// <remarks><inheritdoc cref="DocumentLine"/></remarks> + public IList<DocumentLine> Lines + { + get { return lineTree; } + } + + /// <summary> + /// Gets a line by the line number: O(log n) + /// </summary> + public DocumentLine GetLineByNumber(int number) + { + VerifyAccess(); + if (number < 1 || number > lineTree.LineCount) + throw new ArgumentOutOfRangeException("number", number, "Value must be between 1 and " + lineTree.LineCount); + return lineTree.GetByNumber(number); + } + + /// <summary> + /// Gets a document lines by offset. + /// Runtime: O(log n) + /// </summary> + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "System.Int32.ToString")] + public DocumentLine GetLineByOffset(int offset) + { + VerifyAccess(); + if (offset < 0 || offset > rope.Length) + { + throw new ArgumentOutOfRangeException("offset", offset, "0 <= offset <= " + rope.Length.ToString()); + } + return lineTree.GetByOffset(offset); + } + #endregion + + /// <summary> + /// Gets the offset from a text location. + /// </summary> + /// <seealso cref="GetLocation"/> + public int GetOffset(TextLocation location) + { + return GetOffset(location.Line, location.Column); + } + + /// <summary> + /// Gets the offset from a text location. + /// </summary> + /// <seealso cref="GetLocation"/> + public int GetOffset(int line, int column) + { + DocumentLine docLine = GetLineByNumber(line); + if (column <= 0) + return docLine.Offset; + if (column > docLine.Length) + return docLine.EndOffset; + return docLine.Offset + column - 1; + } + + /// <summary> + /// Gets the location from an offset. + /// </summary> + /// <seealso cref="GetOffset(TextLocation)"/> + public TextLocation GetLocation(int offset) + { + DocumentLine line = GetLineByOffset(offset); + return new TextLocation(line.LineNumber, offset - line.Offset + 1); + } + + readonly ObservableCollection<ILineTracker> lineTrackers = new ObservableCollection<ILineTracker>(); + + /// <summary> + /// Gets the list of <see cref="ILineTracker"/>s attached to this document. + /// You can add custom line trackers to this list. + /// </summary> + public IList<ILineTracker> LineTrackers + { + get + { + VerifyAccess(); + return lineTrackers; + } + } + + UndoStack undoStack; + + /// <summary> + /// Gets the <see cref="UndoStack"/> of the document. + /// </summary> + /// <remarks>This property can also be used to set the undo stack, e.g. for sharing a common undo stack between multiple documents.</remarks> + public UndoStack UndoStack + { + get { return undoStack; } + set + { + if (value == null) + throw new ArgumentNullException(); + if (value != undoStack) + { + undoStack.ClearAll(); // first clear old undo stack, so that it can't be used to perform unexpected changes on this document + // ClearAll() will also throw an exception when it's not safe to replace the undo stack (e.g. update is currently in progress) + undoStack = value; + OnPropertyChanged("UndoStack"); + } + } + } + + /// <summary> + /// Creates a new <see cref="TextAnchor"/> at the specified offset. + /// </summary> + /// <inheritdoc cref="TextAnchor" select="remarks|example"/> + public TextAnchor CreateAnchor(int offset) + { + VerifyAccess(); + if (offset < 0 || offset > rope.Length) + { + throw new ArgumentOutOfRangeException("offset", offset, "0 <= offset <= " + rope.Length.ToString(CultureInfo.InvariantCulture)); + } + return anchorTree.CreateAnchor(offset); + } + + #region LineCount + /// <summary> + /// Gets the total number of lines in the document. + /// Runtime: O(1). + /// </summary> + public int LineCount + { + get + { + VerifyAccess(); + return lineTree.LineCount; + } + } + + /// <summary> + /// Is raised when the LineCount property changes. + /// </summary> + [Obsolete("This event will be removed in a future version; use the PropertyChanged event instead")] + public event EventHandler LineCountChanged; + #endregion + + #region Debugging + [Conditional("DEBUG")] + internal void DebugVerifyAccess() + { + VerifyAccess(); + } + + /// <summary> + /// Gets the document lines tree in string form. + /// </summary> + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] + internal string GetLineTreeAsString() + { +#if DEBUG + return lineTree.GetTreeAsString(); +#else return "Not available in release build."; - #endif - } - - /// <summary> - /// Gets the text anchor tree in string form. - /// </summary> - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] - internal string GetTextAnchorTreeAsString() - { - #if DEBUG - return anchorTree.GetTreeAsString(); - #else +#endif + } + + /// <summary> + /// Gets the text anchor tree in string form. + /// </summary> + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] + internal string GetTextAnchorTreeAsString() + { +#if DEBUG + return anchorTree.GetTreeAsString(); +#else return "Not available in release build."; - #endif - } - #endregion - } +#endif + } + #endregion + } } diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Document/UndoStack.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Document/UndoStack.cs index f0a759b23..86e1fa33e 100644 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Document/UndoStack.cs +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Document/UndoStack.cs @@ -414,7 +414,7 @@ namespace Tango.Scripting.Editors.Document /// </summary> public void ClearAll() { - ThrowIfUndoGroupOpen(); + //ThrowIfUndoGroupOpen(); actionCountInUndoGroup = 0; optionalActionCount = 0; if (undostack.Count != 0) { diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Editing/BreakPointMargin.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Editing/BreakPointMargin.cs new file mode 100644 index 000000000..e566e6aa9 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Editing/BreakPointMargin.cs @@ -0,0 +1,285 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.Diagnostics; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Media.TextFormatting; +using Tango.Scripting.Core; +using Tango.Scripting.Editors.Document; +using Tango.Scripting.Editors.Rendering; +using Tango.Scripting.Editors.Utils; + +namespace Tango.Scripting.Editors.Editing +{ + public class BreakPointMargin : AbstractMargin, IWeakEventListener + { + private TextArea textArea; + private int maxLineNumberLength = 1; + private BitmapSource _arrowBitmap; + private ScriptEditor _editor; + + public ObservableCollection<BreakPoint> BreakPoints { get; set; } + + public Brush Background + { + get { return (Brush)GetValue(BackgroundProperty); } + set { SetValue(BackgroundProperty, value); } + } + public static readonly DependencyProperty BackgroundProperty = + DependencyProperty.Register("Background", typeof(Brush), typeof(BreakPointMargin), new PropertyMetadata(new SolidColorBrush(Color.FromRgb(50, 50, 50)))); + + public Brush Foreground + { + get { return (Brush)GetValue(ForegroundProperty); } + set { SetValue(ForegroundProperty, value); } + } + public static readonly DependencyProperty ForegroundProperty = + DependencyProperty.Register("Foreground", typeof(Brush), typeof(BreakPointMargin), new PropertyMetadata(Brushes.Red)); + + static BreakPointMargin() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(BreakPointMargin), + new FrameworkPropertyMetadata(typeof(BreakPointMargin))); + } + + public BreakPointMargin(ScriptEditor editor) + { + _editor = editor; + BreakPoints = new ObservableCollection<BreakPoint>(); + BreakPoints.CollectionChanged += BreakPoints_CollectionChanged; + RenderOptions.SetEdgeMode(this, EdgeMode.Unspecified); + + _arrowBitmap = new BitmapImage(new Uri($"pack://application:,,,/Tango.Scripting.Editors;component/Images/break_point_arrow.png", UriKind.Absolute)); + } + + private void BreakPoints_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) + { + InvalidateVisual(); + } + + protected override Size MeasureOverride(Size availableSize) + { + return new Size(20, 0); + } + + protected override void OnRender(DrawingContext drawingContext) + { + TextView textView = this.TextView; + Size renderSize = this.RenderSize; + if (textView != null && textView.VisualLinesValid) + { + drawingContext.DrawRectangle(Background, new Pen(Background, 1), new Rect(0, 0, ActualWidth, ActualHeight)); + + var foreground = Foreground; + foreach (VisualLine line in textView.VisualLines) + { + int lineNumber = line.FirstDocumentLine.LineNumber; + + BreakPoint b = BreakPoints.FirstOrDefault(x => x.LineNumber == lineNumber); + + if (b != null) + { + double y = line.GetTextLineVisualYPosition(line.TextLines[0], VisualYPosition.TextTop); + drawingContext.DrawEllipse(Foreground, new Pen(Brushes.Gainsboro, 1), new Point(10, y - textView.VerticalOffset + 8), 6, 6); + + if (b.IsActive) + { + drawingContext.DrawImage(_arrowBitmap, new Rect(6, y - textView.VerticalOffset + 2.5, 8.5, 10)); + } + } + } + } + } + + protected override void OnTextViewChanged(TextView oldTextView, TextView newTextView) + { + if (oldTextView != null) + { + oldTextView.VisualLinesChanged -= TextViewVisualLinesChanged; + } + base.OnTextViewChanged(oldTextView, newTextView); + if (newTextView != null) + { + newTextView.VisualLinesChanged += TextViewVisualLinesChanged; + + // find the text area belonging to the new text view + textArea = newTextView.Services.GetService(typeof(TextArea)) as TextArea; + } + else + { + textArea = null; + } + InvalidateVisual(); + } + + protected override void OnDocumentChanged(TextDocument oldDocument, TextDocument newDocument) + { + if (oldDocument != null) + { + PropertyChangedEventManager.RemoveListener(oldDocument, this, "LineCount"); + } + base.OnDocumentChanged(oldDocument, newDocument); + if (newDocument != null) + { + PropertyChangedEventManager.AddListener(newDocument, this, "LineCount"); + } + OnDocumentLineCountChanged(); + } + + protected virtual bool ReceiveWeakEvent(Type managerType, object sender, EventArgs e) + { + if (managerType == typeof(PropertyChangedEventManager)) + { + OnDocumentLineCountChanged(); + return true; + } + return false; + } + + bool IWeakEventListener.ReceiveWeakEvent(Type managerType, object sender, EventArgs e) + { + return ReceiveWeakEvent(managerType, sender, e); + } + + private void OnDocumentLineCountChanged() + { + int documentLineCount = Document != null ? Document.LineCount : 1; + int newLength = documentLineCount.ToString(CultureInfo.CurrentCulture).Length; + + foreach (var breakPoint in BreakPoints.ToList()) + { + if (breakPoint.LineNumber > documentLineCount) + { + BreakPoints.Remove(breakPoint); + } + else + { + try + { + var line = Document.GetLineByNumber(breakPoint.LineNumber); + if (line != null) + { + String lineText = Document.GetText(line.Offset, line.Length); + if (!IsBreakPointValid(lineText)) + { + BreakPoints.Remove(breakPoint); + } + } + } + catch { } + } + } + + // The margin looks too small when there is only one digit, so always reserve space for + // at least two digits + if (newLength < 2) + newLength = 2; + + if (newLength != maxLineNumberLength) + { + maxLineNumberLength = newLength; + InvalidateMeasure(); + } + } + + private void TextViewVisualLinesChanged(object sender, EventArgs e) + { + InvalidateVisual(); + } + + protected override HitTestResult HitTestCore(PointHitTestParameters hitTestParameters) + { + // accept clicks even when clicking on the background + return new PointHitTestResult(this, hitTestParameters.HitPoint); + } + + private VisualLine GetLineNumberByMousePosition(MouseEventArgs e) + { + Point pos = e.GetPosition(TextView); + pos.X = 0; + pos.Y += TextView.VerticalOffset; + VisualLine vl = TextView.GetVisualLineFromVisualTop(pos.Y); + return vl; + } + + private bool IsBreakPointValid(String lineText) + { + if (lineText.EndsWith(";") && !lineText.StartsWith("using")) + { + return true; + } + + return false; + } + + protected override void OnPreviewMouseMove(MouseEventArgs e) + { + base.OnPreviewMouseMove(e); + + if (_editor.DisableBreakPoints) + { + Cursor = Cursors.No; + } + else + { + Cursor = Cursors.Arrow; + } + } + + protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e) + { + base.OnMouseLeftButtonDown(e); + + if (_editor.DisableBreakPoints) + { + return; + } + + try + { + if (!e.Handled && TextView != null && textArea != null) + { + e.Handled = true; + textArea.Focus(); + + var visualLine = GetLineNumberByMousePosition(e); + + int? lineNumber = visualLine != null ? (int?)visualLine.FirstDocumentLine.LineNumber : null; + + if (lineNumber != null) + { + var breakPoint = BreakPoints.FirstOrDefault(x => x.LineNumber == lineNumber.Value); + if (breakPoint != null) + { + BreakPoints.Remove(breakPoint); + } + else + { + var lineText = Document.GetText(visualLine.FirstDocumentLine.Offset, visualLine.FirstDocumentLine.Length).Trim(); + + if (IsBreakPointValid(lineText)) + { + BreakPoint newBreakPoint = new BreakPoint(); + newBreakPoint.LineNumber = lineNumber.Value; + BreakPoints.Add(newBreakPoint); + } + } + } + } + } + catch (Exception ex) + { + Debug.WriteLine(ex); + } + } + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Errors/ITextMarker.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Errors/ITextMarker.cs new file mode 100644 index 000000000..dcbf8388a --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Errors/ITextMarker.cs @@ -0,0 +1,169 @@ +// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.Collections.Generic; +using System.Windows; +using System.Windows.Media; + +namespace Tango.Scripting.Editors +{ + /// <summary> + /// Represents a text marker. + /// </summary> + public interface ITextMarker + { + /// <summary> + /// Gets the start offset of the marked text region. + /// </summary> + int StartOffset { get; } + + /// <summary> + /// Gets the end offset of the marked text region. + /// </summary> + int EndOffset { get; } + + /// <summary> + /// Gets the length of the marked region. + /// </summary> + int Length { get; } + + /// <summary> + /// Deletes the text marker. + /// </summary> + void Delete(); + + /// <summary> + /// Gets whether the text marker was deleted. + /// </summary> + bool IsDeleted { get; } + + /// <summary> + /// Event that occurs when the text marker is deleted. + /// </summary> + event EventHandler Deleted; + + /// <summary> + /// Gets/Sets the background color. + /// </summary> + Color? BackgroundColor { get; set; } + + /// <summary> + /// Gets/Sets the foreground color. + /// </summary> + Color? ForegroundColor { get; set; } + + /// <summary> + /// Gets/Sets the font weight. + /// </summary> + FontWeight? FontWeight { get; set; } + + /// <summary> + /// Gets/Sets the font style. + /// </summary> + FontStyle? FontStyle { get; set; } + + /// <summary> + /// Gets/Sets the type of the marker. Use TextMarkerType.None for normal markers. + /// </summary> + TextMarkerTypes MarkerTypes { get; set; } + + /// <summary> + /// Gets/Sets the color of the marker. + /// </summary> + Color MarkerColor { get; set; } + + /// <summary> + /// Gets/Sets an object with additional data for this text marker. + /// </summary> + object Tag { get; set; } + + /// <summary> + /// Gets/Sets an object that will be displayed as tooltip in the text editor. + /// </summary> + /// <remarks>Not supported in this sample!</remarks> + object ToolTip { get; set; } + } + + [Flags] + public enum TextMarkerTypes + { + /// <summary> + /// Use no marker + /// </summary> + None = 0x0000, + /// <summary> + /// Use squiggly underline marker + /// </summary> + SquigglyUnderline = 0x001, + /// <summary> + /// Normal underline. + /// </summary> + NormalUnderline = 0x002, + /// <summary> + /// Dotted underline. + /// </summary> + DottedUnderline = 0x004, + + /// <summary> + /// Horizontal line in the scroll bar. + /// </summary> + LineInScrollBar = 0x0100, + /// <summary> + /// Small triangle in the scroll bar, pointing to the right. + /// </summary> + ScrollBarRightTriangle = 0x0400, + /// <summary> + /// Small triangle in the scroll bar, pointing to the left. + /// </summary> + ScrollBarLeftTriangle = 0x0800, + /// <summary> + /// Small circle in the scroll bar. + /// </summary> + CircleInScrollBar = 0x1000 + } + + public interface ITextMarkerService + { + /// <summary> + /// Creates a new text marker. The text marker will be invisible at first, + /// you need to set one of the Color properties to make it visible. + /// </summary> + ITextMarker Create(int startOffset, int length); + + /// <summary> + /// Gets the list of text markers. + /// </summary> + IEnumerable<ITextMarker> TextMarkers { get; } + + /// <summary> + /// Removes the specified text marker. + /// </summary> + void Remove(ITextMarker marker); + + /// <summary> + /// Removes all text markers that match the condition. + /// </summary> + void RemoveAll(Predicate<ITextMarker> predicate); + + /// <summary> + /// Finds all text markers at the specified offset. + /// </summary> + IEnumerable<ITextMarker> GetMarkersAtOffset(int offset); + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Errors/TextMarkerService.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Errors/TextMarkerService.cs new file mode 100644 index 000000000..2bb3d8e03 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Errors/TextMarkerService.cs @@ -0,0 +1,365 @@ +// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Windows; +using System.Windows.Media; +using System.Windows.Threading; +using Tango.Scripting.Editors.Document; +using Tango.Scripting.Editors.Rendering; + +namespace Tango.Scripting.Editors +{ + /// <summary> + /// Handles the text markers for a code editor. + /// </summary> + public sealed class TextMarkerService : DocumentColorizingTransformer, IBackgroundRenderer, ITextMarkerService, ITextViewConnect + { + TextSegmentCollection<TextMarker> markers; + TextDocument document; + + public TextMarkerService(TextDocument document) + { + if (document == null) + throw new ArgumentNullException("document"); + this.document = document; + this.markers = new TextSegmentCollection<TextMarker>(document); + } + + #region ITextMarkerService + public ITextMarker Create(int startOffset, int length) + { + if (markers == null) + throw new InvalidOperationException("Cannot create a marker when not attached to a document"); + + int textLength = document.TextLength; + if (startOffset < 0 || startOffset > textLength) + throw new ArgumentOutOfRangeException("startOffset", startOffset, "Value must be between 0 and " + textLength); + if (length < 0 || startOffset + length > textLength) + throw new ArgumentOutOfRangeException("length", length, "length must not be negative and startOffset+length must not be after the end of the document"); + + TextMarker m = new TextMarker(this, startOffset, length); + markers.Add(m); + // no need to mark segment for redraw: the text marker is invisible until a property is set + return m; + } + + public IEnumerable<ITextMarker> GetMarkersAtOffset(int offset) + { + if (markers == null) + return Enumerable.Empty<ITextMarker>(); + else + return markers.FindSegmentsContaining(offset); + } + + public IEnumerable<ITextMarker> TextMarkers { + get { return markers ?? Enumerable.Empty<ITextMarker>(); } + } + + public void RemoveAll(Predicate<ITextMarker> predicate) + { + if (predicate == null) + throw new ArgumentNullException("predicate"); + if (markers != null) { + foreach (TextMarker m in markers.ToArray()) { + if (predicate(m)) + Remove(m); + } + } + } + + public void Remove(ITextMarker marker) + { + if (marker == null) + throw new ArgumentNullException("marker"); + TextMarker m = marker as TextMarker; + if (markers != null && markers.Remove(m)) { + Redraw(m); + m.OnDeleted(); + } + } + + /// <summary> + /// Redraws the specified text segment. + /// </summary> + internal void Redraw(ISegment segment) + { + foreach (var view in textViews) { + view.Redraw(segment, DispatcherPriority.Normal); + } + if (RedrawRequested != null) + RedrawRequested(this, EventArgs.Empty); + } + + public event EventHandler RedrawRequested; + #endregion + + #region DocumentColorizingTransformer + protected override void ColorizeLine(DocumentLine line) + { + if (markers == null) + return; + int lineStart = line.Offset; + int lineEnd = lineStart + line.Length; + foreach (TextMarker marker in markers.FindOverlappingSegments(lineStart, line.Length)) { + Brush foregroundBrush = null; + if (marker.ForegroundColor != null) { + foregroundBrush = new SolidColorBrush(marker.ForegroundColor.Value); + foregroundBrush.Freeze(); + } + ChangeLinePart( + Math.Max(marker.StartOffset, lineStart), + Math.Min(marker.EndOffset, lineEnd), + element => { + if (foregroundBrush != null) { + element.TextRunProperties.SetForegroundBrush(foregroundBrush); + } + Typeface tf = element.TextRunProperties.Typeface; + element.TextRunProperties.SetTypeface(new Typeface( + tf.FontFamily, + marker.FontStyle ?? tf.Style, + marker.FontWeight ?? tf.Weight, + tf.Stretch + )); + } + ); + } + } + #endregion + + #region IBackgroundRenderer + public KnownLayer Layer { + get { + // draw behind selection + return KnownLayer.Selection; + } + } + + public void Draw(TextView textView, DrawingContext drawingContext) + { + if (textView == null) + throw new ArgumentNullException("textView"); + if (drawingContext == null) + throw new ArgumentNullException("drawingContext"); + if (markers == null || !textView.VisualLinesValid) + return; + var visualLines = textView.VisualLines; + if (visualLines.Count == 0) + return; + int viewStart = visualLines.First().FirstDocumentLine.Offset; + int viewEnd = visualLines.Last().LastDocumentLine.EndOffset; + foreach (TextMarker marker in markers.FindOverlappingSegments(viewStart, viewEnd - viewStart)) { + if (marker.BackgroundColor != null) { + BackgroundGeometryBuilder geoBuilder = new BackgroundGeometryBuilder(); + geoBuilder.AlignToWholePixels = true; + geoBuilder.CornerRadius = 3; + geoBuilder.AddSegment(textView, marker); + Geometry geometry = geoBuilder.CreateGeometry(); + if (geometry != null) { + Color color = marker.BackgroundColor.Value; + SolidColorBrush brush = new SolidColorBrush(color); + brush.Freeze(); + drawingContext.DrawGeometry(brush, null, geometry); + } + } + var underlineMarkerTypes = TextMarkerTypes.SquigglyUnderline | TextMarkerTypes.NormalUnderline | TextMarkerTypes.DottedUnderline; + if ((marker.MarkerTypes & underlineMarkerTypes) != 0) { + foreach (Rect r in BackgroundGeometryBuilder.GetRectsForSegment(textView, marker)) { + Point startPoint = r.BottomLeft; + Point endPoint = r.BottomRight; + + Brush usedBrush = new SolidColorBrush(marker.MarkerColor); + usedBrush.Freeze(); + if ((marker.MarkerTypes & TextMarkerTypes.SquigglyUnderline) != 0) { + double offset = 2.5; + + int count = Math.Max((int)((endPoint.X - startPoint.X) / offset) + 1, 4); + + StreamGeometry geometry = new StreamGeometry(); + + using (StreamGeometryContext ctx = geometry.Open()) { + ctx.BeginFigure(startPoint, false, false); + ctx.PolyLineTo(CreatePoints(startPoint, endPoint, offset, count).ToArray(), true, false); + } + + geometry.Freeze(); + + Pen usedPen = new Pen(usedBrush, 1); + usedPen.Freeze(); + drawingContext.DrawGeometry(Brushes.Transparent, usedPen, geometry); + } + if ((marker.MarkerTypes & TextMarkerTypes.NormalUnderline) != 0) { + Pen usedPen = new Pen(usedBrush, 1); + usedPen.Freeze(); + drawingContext.DrawLine(usedPen, startPoint, endPoint); + } + if ((marker.MarkerTypes & TextMarkerTypes.DottedUnderline) != 0) { + Pen usedPen = new Pen(usedBrush, 1); + usedPen.DashStyle = DashStyles.Dot; + usedPen.Freeze(); + drawingContext.DrawLine(usedPen, startPoint, endPoint); + } + } + } + } + } + + IEnumerable<Point> CreatePoints(Point start, Point end, double offset, int count) + { + for (int i = 0; i < count; i++) + yield return new Point(start.X + i * offset, start.Y - ((i + 1) % 2 == 0 ? offset : 0)); + } + #endregion + + #region ITextViewConnect + readonly List<TextView> textViews = new List<TextView>(); + + void ITextViewConnect.AddToTextView(TextView textView) + { + if (textView != null && !textViews.Contains(textView)) { + Debug.Assert(textView.Document == document); + textViews.Add(textView); + } + } + + void ITextViewConnect.RemoveFromTextView(TextView textView) + { + if (textView != null) { + Debug.Assert(textView.Document == document); + textViews.Remove(textView); + } + } + #endregion + } + + public sealed class TextMarker : TextSegment, ITextMarker + { + readonly TextMarkerService service; + + public TextMarker(TextMarkerService service, int startOffset, int length) + { + if (service == null) + throw new ArgumentNullException("service"); + this.service = service; + this.StartOffset = startOffset; + this.Length = length; + this.markerTypes = TextMarkerTypes.None; + } + + public event EventHandler Deleted; + + public bool IsDeleted { + get { return !this.IsConnectedToCollection; } + } + + public void Delete() + { + service.Remove(this); + } + + internal void OnDeleted() + { + if (Deleted != null) + Deleted(this, EventArgs.Empty); + } + + void Redraw() + { + service.Redraw(this); + } + + Color? backgroundColor; + + public Color? BackgroundColor { + get { return backgroundColor; } + set { + if (backgroundColor != value) { + backgroundColor = value; + Redraw(); + } + } + } + + Color? foregroundColor; + + public Color? ForegroundColor { + get { return foregroundColor; } + set { + if (foregroundColor != value) { + foregroundColor = value; + Redraw(); + } + } + } + + FontWeight? fontWeight; + + public FontWeight? FontWeight { + get { return fontWeight; } + set { + if (fontWeight != value) { + fontWeight = value; + Redraw(); + } + } + } + + FontStyle? fontStyle; + + public FontStyle? FontStyle { + get { return fontStyle; } + set { + if (fontStyle != value) { + fontStyle = value; + Redraw(); + } + } + } + + public object Tag { get; set; } + + TextMarkerTypes markerTypes; + + public TextMarkerTypes MarkerTypes { + get { return markerTypes; } + set { + if (markerTypes != value) { + markerTypes = value; + Redraw(); + } + } + } + + Color markerColor; + + public Color MarkerColor { + get { return markerColor; } + set { + if (markerColor != value) { + markerColor = value; + Redraw(); + } + } + } + + public object ToolTip { get; set; } + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/ExtensionMethods.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/ExtensionMethods.cs index 1605ff281..d112c6141 100644 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/ExtensionMethods.cs +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/ExtensionMethods.cs @@ -22,7 +22,7 @@ namespace Tango.Scripting.Editors { List<String> args = new List<string>(); - foreach (var lGenericArgument in type.GetGenericTypeDefinition().GetGenericArguments()) + foreach (var lGenericArgument in type.GetGenericArguments()) { args.Add(lGenericArgument.Name); } diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/OffsetColorizer.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/OffsetColorizer.cs index a05d1fc75..72c27f9a9 100644 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/OffsetColorizer.cs +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/OffsetColorizer.cs @@ -30,7 +30,7 @@ namespace Tango.Scripting.Editors.Highlighting { try { - ChangeLinePart(StartOffset, EndOffset, element => element.TextRunProperties.SetForegroundBrush(Brush)); + ChangeLinePart(StartOffset, EndOffset, element => element.TextRunProperties.SetBackgroundBrush(Brush)); } catch { } } diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/CSharp-Mode.xshd b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/CSharp-Mode.xshd index 40f362e08..1f6139ff6 100644 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/CSharp-Mode.xshd +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/CSharp-Mode.xshd @@ -11,7 +11,7 @@ <Color name="InterfaceTypes" foreground="#B5CE8A" exampleText="object o;" /> <Color name="MethodCall" foreground="Gainsboro" exampleText="o.ToString();"/> <Color name="NumberLiteral" foreground="#B5CE8A" exampleText="3.1415f"/> - <Color name="ThisOrBaseReference" exampleText="this.Do(); base.Do();"/> + <Color name="ThisOrBaseReference" foreground="#3F8FD6" exampleText="this.Do(); base.Do();"/> <Color name="NullOrValueKeywords" exampleText="if (value == null)"/> <Color name="Keywords" foreground="#3F8FD6" exampleText="if (a) {} else {}"/> <Color name="GotoKeywords" foreground="#3F8FD6" exampleText="continue; return null;"/> @@ -22,7 +22,7 @@ <Color name="OperatorKeywords" foreground="Pink" exampleText="public static implicit operator..."/> <Color name="ParameterModifiers" foreground="DeepPink" exampleText="(ref int a, params int[] b)"/> <Color name="Modifiers" foreground="#3F8FD6" exampleText="static readonly int a;"/> - <Color name="CustomKeywords" foreground="#FAFF00" /> + <Color name="CustomKeywords" foreground="DarkGray" /> <Color name="Visibility" foreground="#3F8FD6" exampleText="public override void ToString();"/> <Color name="NamespaceKeywords" foreground="#569CD6" exampleText="namespace A.B { using System; }"/> <Color name="GetSetAddRemove" foreground="#3F8FD6" exampleText="int Prop { get; set; }"/> @@ -47,26 +47,7 @@ <!-- This is the main ruleset. --> <RuleSet> - <Span color="Preprocessor"> - <Begin>\#</Begin> - <RuleSet name="PreprocessorSet"> - <Span> <!-- preprocessor directives that allows comments --> - <Begin > - (define|undef|if|elif|else|endif|line)\b - </Begin> - <RuleSet> - <Span color="Comment" ruleSet="CommentMarkerSet"> - <Begin>//</Begin> - </Span> - </RuleSet> - </Span> - <Span> <!-- preprocessor directives that don't allow comments --> - <Begin > - (region|endregion|error|warning|pragma)\b - </Begin> - </Span> - </RuleSet> - </Span> + <!--<Span color="Comment"> <Begin color="XmlDoc/DocComment">///</Begin> @@ -118,8 +99,7 @@ </Rule> <Keywords color="CustomKeywords"> - <Word>include</Word> - <Word>import</Word> + <Word>#load</Word> </Keywords> <Keywords color="ThisOrBaseReference"> @@ -214,6 +194,7 @@ <Word>enum</Word> <Word>float</Word> <Word>int</Word> + <Word>object</Word> <Word>string</Word> <Word>long</Word> <Word>sbyte</Word> diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/MarkDown-Mode.xshd b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/MarkDown-Mode.xshd index ead5045ab..8e02db898 100644 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/MarkDown-Mode.xshd +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/MarkDown-Mode.xshd @@ -5,7 +5,6 @@ <Color name="StrongEmphasis" fontWeight="bold" exampleText="**this** is more important!" /> <Color name="Code" exampleText="this is `int.GetHashCode()`" /> <Color name="BlockQuote" foreground="DarkBlue" exampleText="> This is a\r\n> quote." /> - <Color name="Link" foreground="Blue" exampleText="[text](http://example.com)" /> <Color name="Image" foreground="Green" exampleText="[text][http://example.com/test.png]" /> <Color name="LineBreak" background="LightGray" exampleText="end of line \r\n2nd line " /> @@ -43,12 +42,6 @@ <Rule color="Image"> \!\[.*\]\[.*\] </Rule> - <Rule color="Link"> - \[.*\]\(.*\) - </Rule> - <Rule color="Link"> - \[.*\]\[.*\] - </Rule> <Rule color="LineBreak"> [ ]{2}$ </Rule> diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/XML-Mode.xshd b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/XML-Mode.xshd index 8f0bdef76..50fdc0e2c 100644 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/XML-Mode.xshd +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/XML-Mode.xshd @@ -1,13 +1,13 @@ <SyntaxDefinition name="XML" extensions=".xml;.xsl;.xslt;.xsd;.manifest;.config;.addin;.xshd;.wxs;.wxi;.wxl;.proj;.csproj;.vbproj;.ilproj;.booproj;.build;.xfrm;.targets;.xaml;.xpt;.xft;.map;.wsdl;.disco;.ps1xml;.nuspec" xmlns="http://icsharpcode.net/sharpdevelop/syntaxdefinition/2008"> <Color foreground="Green" name="Comment" exampleText="<!-- comment -->" /> - <Color foreground="Blue" name="CData" exampleText="<![CDATA[data]]>" /> - <Color foreground="Blue" name="DocType" exampleText="<!DOCTYPE rootElement>" /> - <Color foreground="Blue" name="XmlDeclaration" exampleText='<?xml version="1.0"?>' /> - <Color foreground="DarkMagenta" name="XmlTag" exampleText='<tag attribute="value" />' /> - <Color foreground="Red" name="AttributeName" exampleText='<tag attribute="value" />' /> - <Color foreground="Blue" name="AttributeValue" exampleText='<tag attribute="value" />' /> + <Color foreground="#3F92D6" name="CData" exampleText="<![CDATA[data]]>" /> + <Color foreground="#C8C8C7" name="DocType" exampleText="<!DOCTYPE rootElement>" /> + <Color foreground="#3F92D6" name="XmlDeclaration" exampleText='<?xml version="1.0"?>' /> + <Color foreground="#3F92D6" name="XmlTag" exampleText='<tag attribute="value" />' /> + <Color foreground="#92CAF4" name="AttributeName" exampleText='<tag attribute="value" />' /> + <Color foreground="#C8C8C7" name="AttributeValue" exampleText='<tag attribute="value" />' /> <Color foreground="Teal" name="Entity" exampleText="index.aspx?a=1&amp;b=2" /> - <Color foreground="Olive" name="BrokenEntity" exampleText="index.aspx?a=1&b=2" /> + <Color foreground="Red" name="BrokenEntity" exampleText="index.aspx?a=1&b=2" /> <RuleSet> <Span color="Comment" multiline="true"> diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Images/break_point_arrow.png b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Images/break_point_arrow.png Binary files differnew file mode 100644 index 000000000..e8d367028 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Images/break_point_arrow.png 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/Images/snippet.png b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Images/snippet.png Binary files differnew file mode 100644 index 000000000..fe4d71eb4 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Images/snippet.png diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Intellisense/CompletionItem.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Intellisense/CompletionItem.cs index c8beebd28..191f99b6c 100644 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Intellisense/CompletionItem.cs +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Intellisense/CompletionItem.cs @@ -31,7 +31,7 @@ namespace Tango.Scripting.Editors.Intellisense int index = editor.GetCurrentWordStartIndex(); int max = editor.GetCurrentLine().EndOffset; - editor.Document.Replace(index, word.Length,Text); + editor.Document.Replace(index, word.Length, GetCode()); } public abstract BitmapSource Image { get; } @@ -41,6 +41,11 @@ namespace Tango.Scripting.Editors.Intellisense return new BitmapImage(new Uri($"pack://application:,,,/Tango.Scripting.Editors;component/Images/{name}", UriKind.Absolute)); } + protected virtual String GetCode() + { + return Text; + } + public override string ToString() { return Text; 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/HideIntellisenseAttribute.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Intellisense/HideIntellisenseAttribute.cs new file mode 100644 index 000000000..548bd909e --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Intellisense/HideIntellisenseAttribute.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.Scripting.Editors.Intellisense +{ + public class HideIntellisenseAttribute : Attribute + { + } +} 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 28f9ccb9a..8010dc689 100644 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Intellisense/KnownType.cs +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Intellisense/KnownType.cs @@ -1,11 +1,14 @@ -using System; +using Newtonsoft.Json; +using System; using System.Collections; using System.Collections.Generic; +using System.Drawing; using System.IO; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; +using System.Windows.Forms; using System.Xml; using Tango.Core; @@ -14,16 +17,18 @@ namespace Tango.Scripting.Editors.Intellisense public class KnownType { private bool _initialized; - private bool _documentationLoaded; + 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,12 +37,20 @@ namespace Tango.Scripting.Editors.Intellisense members.AddRange(Properties); members.AddRange(Methods); + members.AddRange(Events); return members.OrderBy(x => x.Name).ToList(); } } public List<KnownTypeField> Fields { get; set; } + public static List<Assembly> ExtensionMethodsAssemblies { get; set; } + + static KnownType() + { + ExtensionMethodsAssemblies = new List<Assembly>(); + } + public KnownType(Type type) { Summary = "Loading documentation..."; @@ -45,6 +58,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; @@ -118,9 +132,31 @@ namespace Tango.Scripting.Editors.Intellisense { var methods = Type.GetRuntimeMethods().Where(x => x.IsPublic && !x.IsSpecialName).ToList(); + if (Type.IsInterface) + { + foreach (var inter in Type.GetInterfaces()) + { + methods.AddRange(inter.GetRuntimeMethods().Where(x => x.IsPublic && !x.IsSpecialName).ToList()); + } + methods = methods.Distinct().ToList(); + + if (!methods.Exists(x => x.Name == "ToString")) + { + methods.Add(typeof(Object).GetMethod("ToString")); + } + } + //TODO: Separate extension methods! methods.AddRange(Type.GetExtensionMethods(Type.Assembly).ToList()); + if (Type.Namespace.StartsWith("Tango")) + { + foreach (var asm in ExtensionMethodsAssemblies.Where(x => x != Type.Assembly)) + { + methods.AddRange(Type.GetExtensionMethods(asm).ToList()); + } + } + if (typeof(IEnumerable).IsAssignableFrom(Type)) { var linqMethods = typeof(System.Linq.Enumerable).GetMethods(BindingFlags.Static | BindingFlags.Public).ToList(); @@ -131,10 +167,13 @@ namespace Tango.Scripting.Editors.Intellisense { var method = methods[i]; + if (method.GetCustomAttribute<HideIntellisenseAttribute>() != null) continue; + KnownTypeMethod m = new KnownTypeMethod(this); m.Name = method.Name; m.ReturnType = method.ReturnType; m.ReturnTypeFriendlyName = method.ReturnType.GetFriendlyName(); + m.IsStatic = method.IsStatic && !method.IsDefined(typeof(System.Runtime.CompilerServices.ExtensionAttribute), false); if (method.IsGenericMethod) { @@ -148,6 +187,11 @@ namespace Tango.Scripting.Editors.Intellisense bool isLinq = method.DeclaringType == typeof(Enumerable); + if (isLinq) + { + m.IsStatic = false; + } + for (int j = 0; j < parameters.Count; j++) { var parameter = parameters[j]; @@ -171,12 +215,14 @@ 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 | BindingFlags.Static).ToList(); for (int i = 0; i < properties.Count; i++) { var property = properties[i]; + if (property.GetCustomAttribute<HideIntellisenseAttribute>() != null) continue; + KnownTypeProperty p = new KnownTypeProperty(this); p.Name = property.Name; p.ReturnType = property.PropertyType; @@ -186,6 +232,23 @@ namespace Tango.Scripting.Editors.Intellisense } } + //Load Events + { + var events = Type.GetRuntimeEvents().ToList(); + + for (int i = 0; i < events.Count; i++) + { + var ev = events[i]; + + if (ev.GetCustomAttribute<HideIntellisenseAttribute>() != null) continue; + + KnownTypeEvent p = new KnownTypeEvent(this); + p.Name = ev.Name; + + Events.Add(p); + } + } + //Load Enum Values { if (Type.IsEnum) @@ -211,9 +274,9 @@ namespace Tango.Scripting.Editors.Intellisense public void LoadDocumentation() { - if (!_documentationLoaded) + if (!DocumentationLoaded) { - _documentationLoaded = true; + DocumentationLoaded = true; Utils.LoadKnownTypeDocs(this); } 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/Intellisense/KnownTypeMethod.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Intellisense/KnownTypeMethod.cs index f84e26fe5..4cedad377 100644 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Intellisense/KnownTypeMethod.cs +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Intellisense/KnownTypeMethod.cs @@ -8,6 +8,8 @@ namespace Tango.Scripting.Editors.Intellisense { public class KnownTypeMethod : KnownTypeMember { + public bool IsStatic { get; set; } + public List<KnownTypeMethodParameter> Parameters { get; set; } public List<String> TypeArguments { get; set; } diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Intellisense/SnippetCompletionItem.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Intellisense/SnippetCompletionItem.cs new file mode 100644 index 000000000..97807ed19 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Intellisense/SnippetCompletionItem.cs @@ -0,0 +1,26 @@ +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 SnippetCompletionItem : CompletionItem + { + private static BitmapSource image = GetImage("snippet.png"); + + public override string Text => Name; + public override CompletionItemPopupControl PopupControl => new FieldCompletionItemPopup(); + public override BitmapSource Image => image; + + public String Name { get; set; } + public String Code { get; set; } + + protected override string GetCode() + { + return Code; + } + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Intellisense/Utils.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Intellisense/Utils.cs index f8cc7072d..2ead15d0d 100644 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Intellisense/Utils.cs +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Intellisense/Utils.cs @@ -150,7 +150,12 @@ namespace Tango.Scripting.Editors.Intellisense var property = knownType.Properties[i]; var pDoc = docNodes.FirstOrDefault(x => x.Attributes["name"].InnerText.Contains(knownType.Type.Name + "." + property.Name)); - property.Summary = pDoc != null ? pDoc.SelectSingleNode("summary").InnerXml : "No documentation"; + + if (pDoc != null) + { + var summaryNode = pDoc.SelectSingleNode("summary"); + property.Summary = summaryNode != null ? summaryNode.InnerXml : "No documentation"; + } } } @@ -162,7 +167,12 @@ namespace Tango.Scripting.Editors.Intellisense { var field = knownType.Fields[i]; var pDoc = xmlDoc.SelectSingleNode("//member[starts-with(@name, '" + $"F:{knownType.Type.FullName}.{field.Name}" + "')]"); - field.Summary = pDoc != null ? pDoc.SelectSingleNode("summary").InnerXml : "No documentation"; + + if (pDoc != null) + { + var summaryNode = pDoc.SelectSingleNode("summary"); + field.Summary = summaryNode != null ? summaryNode.InnerXml : "No documentation"; + } } } } diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Rendering/TextView.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Rendering/TextView.cs index 3dabb6b7a..1b1f12ff3 100644 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Rendering/TextView.cs +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Rendering/TextView.cs @@ -554,7 +554,7 @@ namespace Tango.Scripting.Editors.Rendering /// </summary> public static readonly DependencyProperty LinkTextForegroundBrushProperty = DependencyProperty.Register("LinkTextForegroundBrush", typeof(Brush), typeof(TextView), - new FrameworkPropertyMetadata(Brushes.Blue)); + new FrameworkPropertyMetadata(Brushes.Gray)); /// <summary> /// Gets/sets the Brush used for displaying link texts. diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/ScriptEditor.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/ScriptEditor.cs index efa1b087a..e65ff671d 100644 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/ScriptEditor.cs +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/ScriptEditor.cs @@ -1,8 +1,10 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; +using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.ComponentModel.Design; using System.Diagnostics; using System.IO; using System.Linq; @@ -23,7 +25,9 @@ using System.Windows.Navigation; using System.Windows.Shapes; using System.Windows.Threading; using System.Xml; +using Tango.Core; using Tango.Core.Commands; +using Tango.Scripting.Core; using Tango.Scripting.Editors.CodeCompletion; using Tango.Scripting.Editors.Document; using Tango.Scripting.Editors.Editing; @@ -33,6 +37,7 @@ using Tango.Scripting.Editors.Highlighting.Xshd; using Tango.Scripting.Editors.Intellisense; using Tango.Scripting.Editors.Popups; using Tango.Scripting.Editors.Rendering; +using Tango.Scripting.Formatting; using Tango.Scripting.Parsing; namespace Tango.Scripting.Editors @@ -42,7 +47,10 @@ namespace Tango.Scripting.Editors private char[] word_separators = { ' ', '\t', '\n', '.', '(', ',', '-', '*', '/', '+', '$', '=', '<', '>' }; private string[] _blocking_type_words = { "class", "void" }; + public event EventHandler<BreakPointSymbolPressedEventArgs> BreakPointSymbolPressed; + private DispatcherTimer _update_timer; + private BreakPointMargin breakPointMargin; private Popup _popup; private FoldingManager foldingManager; private BraceFoldingStrategy foldingStrategy; @@ -52,9 +60,48 @@ namespace Tango.Scripting.Editors private List<KnownType> _knownTypes; private List<ScriptType> _declaredTypes; private bool _isLoadingTypes; + private TextMarkerService errorMarkerService; + private List<ScriptBreakPointSymbol> _breakPointSymbols; + private int _breakPointLineNumber; + private ScriptBreakPointSymbol _currentBreakPointSymbol; + private Point _currentBreakPointSymbolPosition; + + private static JsonSerializerSettings _jsonSettings; + 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 bool _isUsingsLoadingStarted; + private static object _loadUsingsLock = new object(); + private static List<SnippetCompletionItem> snippets; + + public static event EventHandler<TangoProgressChangedEventArgs<int>> LoadingSymbolsProgress; + public static event EventHandler LoadingSymbolsStarted; + public static event EventHandler LoadingSymbolsCompleted; + private static event EventHandler KnownTypesAvailable; + public static event EventHandler UsingsLoadingStarted; + public static event EventHandler UsingsLoadingCompleted; #region Mini Classes + private class KnownTypeResult + { + public KnownType KnownType { get; set; } + public bool IsStatic { get; set; } + + public KnownTypeResult() + { + + } + + public KnownTypeResult(KnownType knownType) + { + KnownType = knownType; + } + } + private class ScriptClass { public String Name { get; set; } @@ -85,6 +132,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> @@ -110,13 +159,13 @@ namespace Tango.Scripting.Editors /// <summary> /// Gets or sets the reference assemblies. /// </summary> - public ObservableCollection<ReferenceAssembly> ReferenceAssemblies + public ObservableCollection<Assembly> ReferenceAssemblies { - get { return (ObservableCollection<ReferenceAssembly>)GetValue(ReferenceAssembliesProperty); } + get { return (ObservableCollection<Assembly>)GetValue(ReferenceAssembliesProperty); } set { SetValue(ReferenceAssembliesProperty, value); } } public static readonly DependencyProperty ReferenceAssembliesProperty = - DependencyProperty.Register("ReferenceAssemblies", typeof(ObservableCollection<ReferenceAssembly>), typeof(ScriptEditor), new PropertyMetadata(null)); + DependencyProperty.Register("ReferenceAssemblies", typeof(ObservableCollection<Assembly>), typeof(ScriptEditor), new PropertyMetadata(null, (d, e) => (d as ScriptEditor).OnReferenceAssembliesChanged())); public Object CurrentPopupContent { @@ -126,6 +175,70 @@ namespace Tango.Scripting.Editors public static readonly DependencyProperty CurrentPopupContentProperty = DependencyProperty.Register("CurrentPopupContent", typeof(Object), typeof(ScriptEditor), new PropertyMetadata(null)); + public String Code + { + get { return (String)GetValue(CodeProperty); } + set { SetValue(CodeProperty, value); } + } + public static readonly DependencyProperty CodeProperty = + DependencyProperty.Register("Code", typeof(String), typeof(ScriptEditor), new PropertyMetadata(null, (d, e) => (d as ScriptEditor).OnCodeChanged())); + + public ObservableCollection<IScriptSource> AdditionalScripts + { + get { return (ObservableCollection<IScriptSource>)GetValue(AdditionalScriptsProperty); } + set { SetValue(AdditionalScriptsProperty, value); } + } + public static readonly DependencyProperty AdditionalScriptsProperty = + DependencyProperty.Register("AdditionalScripts", typeof(ObservableCollection<IScriptSource>), typeof(ScriptEditor), new PropertyMetadata(null)); + + public Brush ColorizeBrush + { + get { return (Brush)GetValue(ColorizeBrushProperty); } + set { SetValue(ColorizeBrushProperty, value); } + } + 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 })); + + public Brush DebugLineBrush + { + get { return (Brush)GetValue(DebugLineBrushProperty); } + set { SetValue(DebugLineBrushProperty, value); } + } + public static readonly DependencyProperty DebugLineBrushProperty = + DependencyProperty.Register("DebugLineBrush", typeof(Brush), typeof(ScriptEditor), new PropertyMetadata(new SolidColorBrush(Colors.Gray) { Opacity = 0.5 })); + + public Brush BreakPointLineBrush + { + get { return (Brush)GetValue(BreakPointLineBrushProperty); } + set { SetValue(BreakPointLineBrushProperty, value); } + } + public static readonly DependencyProperty BreakPointLineBrushProperty = + DependencyProperty.Register("BreakPointLineBrush", typeof(Brush), typeof(ScriptEditor), new PropertyMetadata(new SolidColorBrush(Colors.Yellow) { Opacity = 0.5 })); + + public IScriptSource ScriptSource + { + get { return (IScriptSource)GetValue(ScriptSourceProperty); } + set { SetValue(ScriptSourceProperty, value); } + } + public static readonly DependencyProperty ScriptSourceProperty = + DependencyProperty.Register("ScriptSource", typeof(IScriptSource), typeof(ScriptEditor), new PropertyMetadata(null)); + + public bool DisableBreakPoints + { + get { return (bool)GetValue(DisableBreakPointsProperty); } + set { SetValue(DisableBreakPointsProperty, value); } + } + public static readonly DependencyProperty DisableBreakPointsProperty = + DependencyProperty.Register("DisableBreakPoints", typeof(bool), typeof(ScriptEditor), new PropertyMetadata(false)); + #endregion @@ -137,6 +250,87 @@ namespace Tango.Scripting.Editors static ScriptEditor() { DefaultStyleKeyProperty.OverrideMetadata(typeof(ScriptEditor), new FrameworkPropertyMetadata(typeof(ScriptEditor))); + + snippets = new List<SnippetCompletionItem>(); + + 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"); + Directory.CreateDirectory(KNOWN_TYPES_CACHE_FOLDER); + } + + _jsonSettings = new JsonSerializerSettings() + { + TypeNameHandling = TypeNameHandling.Auto, + PreserveReferencesHandling = PreserveReferencesHandling.All + }; + + _knownTypesCache = new Dictionary<Type, KnownType>(); + _cachedAssemblies = new List<CachedAssembly>(); + _cachedUsings = new List<CachedUsing>(); + + snippets.Add(new SnippetCompletionItem() + { + Name = "for", + Code = @"for (int i = 0; i < 10; i++) + { + + }" + }); + + snippets.Add(new SnippetCompletionItem() + { + Name = "while", + Code = @"while (true) + { + + }" + }); + + snippets.Add(new SnippetCompletionItem() + { + Name = "foreach", + Code = @"foreach (var item in items) + { + + }" + }); + + snippets.Add(new SnippetCompletionItem() + { + Name = "prop", + Code = @"public int MyProperty { get; set; }" + }); + + snippets.Add(new SnippetCompletionItem() + { + Name = "do", + Code = @"do + { + + } while (true)" + }); + + snippets.Add(new SnippetCompletionItem() + { + Name = "try", + Code = @"try + { + + } + catch (Exception ex) + { + + }" + }); + + snippets.Add(new SnippetCompletionItem() + { + Name = "cw", + Code = "context.WriteLine(\"\");" + }); } /// <summary> @@ -148,16 +342,17 @@ namespace Tango.Scripting.Editors _current_usings = new List<string>(); - ReferenceAssemblies = new ObservableCollection<ReferenceAssembly>(); + //ReferenceAssemblies = new ObservableCollection<ReferenceAssembly>(); - //Add basic assemblies... - ReferenceAssemblies.Add(new ReferenceAssembly(typeof(String))); //mscorelib - ReferenceAssemblies.Add(new ReferenceAssembly(typeof(Enumerable))); //System.Core - ReferenceAssemblies.Add(new ReferenceAssembly(typeof(Tango.Core.CoreSettings))); //System.Core + ////Add basic assemblies... + //ReferenceAssemblies.Add(new ReferenceAssembly(typeof(String))); //mscorelib + //ReferenceAssemblies.Add(new ReferenceAssembly(typeof(Enumerable))); //System.Core _knownTypes = new List<KnownType>(); _parser = new ScriptParser(); + KnownTypesAvailable += ScriptEditor_KnownTypesAvailable; + TextArea.IndentationStrategy = new Indentation.CSharp.CSharpIndentationStrategy(Options); foldingStrategy = new BraceFoldingStrategy(); @@ -175,6 +370,59 @@ namespace Tango.Scripting.Editors completionWindow.AllowsTransparency = true; completionWindow.ResizeMode = ResizeMode.NoResize; completionWindow.InsertionRequest += CompletionWindow_InsertionRequest; + + TextChanged += ScriptEditor_TextChanged; + + errorMarkerService = new TextMarkerService(Document); + TextArea.TextView.BackgroundRenderers.Add(errorMarkerService); + TextArea.TextView.LineTransformers.Add(errorMarkerService); + + Unloaded += ScriptEditor_Unloaded; + + breakPointMargin = new BreakPointMargin(this); + _breakPointSymbols = new List<ScriptBreakPointSymbol>(); + Loaded += ScriptEditor_Loaded; + + MouseMove += ScriptEditor_MouseMove; + } + + private void ScriptEditor_Loaded(object sender, RoutedEventArgs e) + { + TextArea.LeftMargins.Insert(0, breakPointMargin); + } + + private void ScriptEditor_Unloaded(object sender, RoutedEventArgs e) + { + _update_timer.Stop(); + } + + private void ScriptEditor_KnownTypesAvailable(object sender, EventArgs e) + { + if (sender != this) + { + InvalidateHighlightingPartial(); + } + } + + private bool preventCodeUpdate; + private void ScriptEditor_TextChanged(object sender, EventArgs e) + { + if (!preventCodeUpdate) + { + preventCodeUpdate = true; + Code = Text; + preventCodeUpdate = false; + } + } + + private void OnCodeChanged() + { + if (!preventCodeUpdate) + { + preventCodeUpdate = true; + Text = Code; + preventCodeUpdate = false; + } } #endregion @@ -279,18 +527,18 @@ namespace Tango.Scripting.Editors } else if (e.Key == Key.Oem2) { - int offset = CaretOffset; - var line = Document.GetLineByOffset(offset); + //int offset = CaretOffset; + //var line = Document.GetLineByOffset(offset); - String text = GetCurrentLineText(); - if (text.TrimStart('\t', ' ').StartsWith("//")) - { - Document.BeginUpdate(); - Document.Replace(line, "/// <summary>\n/// \n/// </summary>"); - Document.EndUpdate(); - e.Handled = true; - CaretOffset = Document.GetLineByNumber(line.LineNumber + 1).EndOffset; - } + //String text = GetCurrentLineText(); + //if (text.TrimStart('\t', ' ').StartsWith("//")) + //{ + // Document.BeginUpdate(); + // Document.Replace(line, "/// <summary>\n/// \n/// </summary>"); + // Document.EndUpdate(); + // e.Handled = true; + // CaretOffset = Document.GetLineByNumber(line.LineNumber + 1).EndOffset; + //} } else if (e.Key == Key.End || e.Key == Key.Home) { @@ -304,474 +552,509 @@ namespace Tango.Scripting.Editors private void TextArea_TextEntered(object sender, TextCompositionEventArgs e) { - List<Object> items = new List<object>(); + if (IsReadOnly) return; - HidePopup(); + try + { + List<Object> items = new List<object>(); - var lineText = GetCurrentLineText(); - var previousWords = GetPreviousWords(); - var previousWordsLast = previousWords.LastOrDefault(); - String currentWord = previousWordsLast != null ? previousWordsLast.Replace("\t", "") : String.Empty; - String currentWordIncludingParenthesis = currentWord.Split('(').LastOrDefault(); + HidePopup(); - if (previousWords.Count > 0 && previousWords.First().Trim().StartsWith("//")) return; + var lineText = GetCurrentLineText(); + var previousWords = GetPreviousWords(); + var previousWordsLast = previousWords.LastOrDefault(); + String currentWord = previousWordsLast != null ? previousWordsLast.Replace("\t", "") : String.Empty; + String currentWordIncludingParenthesis = currentWord.Split('(').LastOrDefault(); - if (e.Text == " " && previousWords.Count > 2 && previousWords[previousWords.Count - 2] == "=") - { - var expression = previousWords.First(); - var knownType = GetKnownTypeFromExpression(expression + "."); + if (previousWords.Count > 0 && previousWords.First().Trim().StartsWith("//")) return; - if (knownType != null && knownType.Type.IsEnum) + if (e.Text == " " && previousWords.Count > 2 && previousWords[previousWords.Count - 2] == "=") { - completionWindow.HideCompletion(); - IList<ICompletionData> data = new List<ICompletionData>(); + var expression = previousWords.First(); + var knownTypeResult = GetKnownTypeFromExpression(expression + "."); - foreach (var field in knownType.Fields) + if (knownTypeResult != null && knownTypeResult.KnownType.Type.IsEnum) { - data.Add(new FieldCompletionItem() + completionWindow.HideCompletion(); + IList<ICompletionData> data = new List<ICompletionData>(); + + foreach (var field in knownTypeResult.KnownType.Fields) { - Class = knownType.FriendlyName, - Name = knownType.FriendlyName + "." + field.Name, - Type = field.ReturnTypeFriendlyName, - Description = field.Summary, - }); + data.Add(new FieldCompletionItem() + { + Class = knownTypeResult.KnownType.FriendlyName, + Name = knownTypeResult.KnownType.FriendlyName + "." + field.Name, + Type = field.ReturnTypeFriendlyName, + Description = field.Summary, + }); + } + + ShowCompletionWindow(data.OrderBy(x => x.Text).ToList(), GetCurrentWord()); } - ShowCompletionWindow(data.OrderBy(x => x.Text).ToList(), GetCurrentWord()); } - - } - else if (e.Text == " " && GetPreviousWord() == "new") - { - var s = _parser.GetExpressionFirst<FieldDeclarationSyntax>(GetCurrentLineText()); - - if (s != null) + else if (e.Text == " " && GetPreviousWord() == "new") { - String type = s.Declaration.Type.ToString(); - - IList<ICompletionData> data = new List<ICompletionData>(); + var s = _parser.GetExpressionFirst<FieldDeclarationSyntax>(GetCurrentLineText()); - data.Add(new ClassCompletionItem() + if (s != null) { - Name = type, - Description = "Auto generate assignment...", - }); + String type = s.Declaration.Type.ToString(); - ShowCompletionWindow(data, type); - } - } - else if (e.Text == ";" || e.Text == " ") - { - HideCompletionWindow(); - } - else if (e.Text == ".") - { - var knownType = GetCurrentKnownType(); + IList<ICompletionData> data = new List<ICompletionData>(); - if (knownType != null) + data.Add(new ClassCompletionItem() + { + Name = type, + Description = "Auto generate assignment...", + }); + + ShowCompletionWindow(data, type); + } + } + else if (e.Text == ";" || e.Text == " ") { - completionWindow.HideCompletion(); + HideCompletionWindow(); + } + else if (e.Text == ".") + { + var knownTypeResult = GetCurrentKnownType(); + IList<ICompletionData> data = new List<ICompletionData>(); - if (!knownType.Type.IsEnum) + if (knownTypeResult != null) { - var typeMembers = knownType.Members.ToList(); + completionWindow.HideCompletion(); - foreach (var methodGroup in typeMembers.OfType<KnownTypeMethod>().GroupBy(x => x.NameWithTypeArguments)) + if (!knownTypeResult.KnownType.Type.IsEnum) { - var method = methodGroup.First(); + var typeMembers = knownTypeResult.KnownType.Members.ToList(); - data.Add(new MethodCompletionItem() + foreach (var methodGroup in typeMembers.OfType<KnownTypeMethod>().Where(x => (!knownTypeResult.IsStatic && !x.IsStatic) || (knownTypeResult.IsStatic && x.IsStatic)).GroupBy(x => x.NameWithTypeArguments)) { - Class = knownType.FriendlyName, - Name = method.NameWithTypeArguments, - ReturnType = method.ReturnTypeFriendlyName, - Description = method.Summary, - Parameters = method.Parameters, - Overloads = methodGroup.Count() - 1, - }); - } + var method = methodGroup.First(); - foreach (var methodGroup in typeMembers.Where(x => x.GetType() != typeof(KnownTypeMethod)).GroupBy(x => x.Name)) - { - var member = methodGroup.First(); + data.Add(new MethodCompletionItem() + { + Class = knownTypeResult.KnownType.FriendlyName, + Name = method.NameWithTypeArguments, + ReturnType = method.ReturnTypeFriendlyName, + Description = method.Summary, + Parameters = method.Parameters, + Overloads = methodGroup.Count() - 1, + }); + } - data.Add(new PropertyCompletionItem() + foreach (var ev in typeMembers.OfType<KnownTypeEvent>()) { - Class = knownType.FriendlyName, - Name = member.Name, - Type = member.ReturnTypeFriendlyName, - Description = member.Summary, - }); + data.Add(new EventCompletionItem() + { + Class = knownTypeResult.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(); + + data.Add(new PropertyCompletionItem() + { + Class = knownTypeResult.KnownType.FriendlyName, + Name = member.Name, + Type = member.ReturnTypeFriendlyName, + Description = member.Summary, + }); + } } - } - else - { - foreach (var field in knownType.Fields) + else { - data.Add(new FieldCompletionItem() + foreach (var field in knownTypeResult.KnownType.Fields) { - Class = knownType.FriendlyName, - Name = field.Name, - Type = field.ReturnTypeFriendlyName, - Description = field.Summary, - }); + data.Add(new FieldCompletionItem() + { + Class = knownTypeResult.KnownType.FriendlyName, + Name = field.Name, + Type = field.ReturnTypeFriendlyName, + Description = field.Summary, + }); + } } - } - ShowCompletionWindow(data.OrderBy(x => x.Text).ToList(), GetCurrentWord()); - } - else - { - var declaredType = GetCurrentDeclaredType(); - - if (declaredType != null) + ShowCompletionWindow(data.OrderBy(x => x.Text).ToList(), GetCurrentWord()); + } + else { - completionWindow.HideCompletion(); - IList<ICompletionData> data = new List<ICompletionData>(); + var declaredType = GetCurrentDeclaredType(); - var typeMembers = declaredType.Symbols.ToList(); - - foreach (var methodGroup in typeMembers.GroupBy(x => x.Name)) + if (declaredType != null) { - var member = methodGroup.First(); + completionWindow.HideCompletion(); - if (member.Kind == SymbolKind.Method) - { - var methodCompletion = new MethodCompletionItem() - { - Class = declaredType.Name, - Name = member.Name, - ReturnType = member.Type, - Description = member.Summary, - Overloads = methodGroup.Count() - 1, - }; + var typeMembers = declaredType.Symbols.ToList(); + foreach (var methodGroup in typeMembers.GroupBy(x => x.Name)) + { + var member = methodGroup.First(); - for (int i = 0; i < member.Parameters.Count; i++) + if (member.Kind == SymbolKind.Method) { - var pair = member.Parameters[i]; + var methodCompletion = new MethodCompletionItem() + { + Class = declaredType.Name, + Name = member.Name, + ReturnType = member.Type, + Description = member.Summary, + Overloads = methodGroup.Count() - 1, + }; - methodCompletion.Parameters.Add(new KnownTypeMethodParameter() + + for (int i = 0; i < member.Parameters.Count; i++) { - Type = pair.Key, - Name = pair.Value, - IsLast = (i == member.Parameters.Count - 1) - }); - } + var pair = member.Parameters[i]; - data.Add(methodCompletion); + methodCompletion.Parameters.Add(new KnownTypeMethodParameter() + { + Type = pair.Key, + Name = pair.Value, + IsLast = (i == member.Parameters.Count - 1) + }); + } - } - else if (member.Kind == SymbolKind.Property) - { - data.Add(new PropertyCompletionItem() + data.Add(methodCompletion); + + } + else if (member.Kind == SymbolKind.Property) { - Class = declaredType.Name, - Name = member.Name, - Type = member.Type, - Description = member.Summary, - }); - } - else if (member.Kind == SymbolKind.Field) - { - data.Add(new FieldCompletionItem() + data.Add(new PropertyCompletionItem() + { + Class = declaredType.Name, + Name = member.Name, + Type = member.Type, + Description = member.Summary, + }); + } + else if (member.Kind == SymbolKind.Field) { - Class = declaredType.Name, - Name = member.Name, - Type = member.Type, - Description = member.Summary, - }); + data.Add(new FieldCompletionItem() + { + Class = declaredType.Name, + Name = member.Name, + Type = member.Type, + Description = member.Summary, + }); + } } - } - ShowCompletionWindow(data, GetCurrentWord()); + ShowCompletionWindow(data, GetCurrentWord()); + } } } - } - else if (e.Text == "(" || e.Text == ",") - { - completionWindow.HideCompletion(); - - try + else if (e.Text == "(" || e.Text == ",") { - var session = GetConstructionSession(); + completionWindow.HideCompletion(); - if (session != null) + try { - var content = CreateConstructionSessionPopupContent(session); - if (content.Methods.Count > 0) + var session = GetConstructionSession(); + + if (session != null) { - ShowPopup(content); - return; + var content = CreateConstructionSessionPopupContent(session); + if (content.Methods.Count > 0) + { + ShowPopup(content); + return; + } } - } - var methodSession = GetMethodSession(); + var methodSession = GetMethodSession(); - if (methodSession != null) - { - var content = CreateMethodSessionPopupContent(methodSession); - if (content.Methods.Count > 0) + if (methodSession != null) { - ShowPopup(content); - return; + var content = CreateMethodSessionPopupContent(methodSession); + if (content.Methods.Count > 0) + { + ShowPopup(content); + return; + } } - } - var declaredMethodSession = GetDeclaredMethodSession(); + var declaredMethodSession = GetDeclaredMethodSession(); - if (declaredMethodSession != null) - { - var content = CreateDeclaredMethodSessionPopupContent(declaredMethodSession); - if (content.Methods.Count > 0) + if (declaredMethodSession != null) { - ShowPopup(content); - return; + var content = CreateDeclaredMethodSessionPopupContent(declaredMethodSession); + if (content.Methods.Count > 0) + { + ShowPopup(content); + return; + } + } + + var staticMethodSession = GetStaticMethodSession(); + + if (staticMethodSession != null) + { + var content = CreateMethodSessionPopupContent(staticMethodSession); + if (content.Methods.Count > 0) + { + ShowPopup(content); + return; + } } } + catch (Exception ex) + { + Debug.WriteLine(ex); + } } - catch (Exception ex) - { - Debug.WriteLine(ex); - } - } - else if (lineText.StartsWith("using")) - { - if (completionWindow.IsVisible) + else if (lineText.StartsWith("using") && e.Text != "\n") { - completionWindow.UpdatePositionFix(); - return; - } + if (completionWindow.IsVisible) + { + completionWindow.UpdatePositionFix(); + return; + } - IList<ICompletionData> data = new List<ICompletionData>(); + IList<ICompletionData> data = new List<ICompletionData>(); - foreach (var asm in ReferenceAssemblies) - { - foreach (var ns in asm.Assembly.GetTypes().Select(x => x.Namespace).Distinct().Where(x => x != null)) + foreach (var asm in ReferenceAssemblies) { - data.Add(new NamespaceCompletionItem() + foreach (var ns in asm.GetTypes().Select(x => x.Namespace).Distinct().Where(x => x != null)) { - Name = ns, - Assembly = asm.Assembly.GetName().Name, - }); + data.Add(new NamespaceCompletionItem() + { + Name = ns, + Assembly = asm.GetName().Name, + }); + } } - } - data = data.DistinctBy(x => x.Text).ToList(); + data = data.DistinctBy(x => x.Text).ToList(); - ShowCompletionWindow(data, GetCurrentWord()); - } - else if (e.Text == "{") - { - int parentesisCount = lineText.TakeWhile(x => x != '{').Count(x => x == '\"'); - - if (parentesisCount % 2 == 0) - { - Document.Insert(CaretOffset, "}"); - CaretOffset--; + ShowCompletionWindow(data, GetCurrentWord()); } - } - else if (e.Text == "}") - { - if (Document.GetText(CaretOffset - 2, 1) == "{" && Document.GetText(CaretOffset, 1) == "}") + else if (e.Text == "{") { - Document.Replace(CaretOffset, 1, ""); - } - } - else if (e.Text == "\n") - { - if (Document.GetText(CaretOffset - 3, 1) == "{" && Document.GetText(CaretOffset, 1) == "}") - { - CaretOffset--; - Document.Insert(CaretOffset, "\n\t"); + int parentesisCount = lineText.TakeWhile(x => x != '{').Count(x => x == '\"'); + + if (parentesisCount % 2 == 0) + { + Document.Insert(CaretOffset, "}"); + CaretOffset--; + } } - } - else if (!currentWordIncludingParenthesis.Contains(".") || currentWord[currentWord.Length - 2] == '<') - { - if (completionWindow.IsVisible) + else if (e.Text == "}") { - completionWindow.UpdatePositionFix(); - return; + if (Document.GetText(CaretOffset - 2, 1) == "{" && Document.GetText(CaretOffset, 1) == "}") + { + Document.Replace(CaretOffset, 1, ""); + } } - - var previous_word = GetPreviousWord(); - var word = GetCurrentWord(); - - if (word.Contains("<")) + else if (e.Text == "\n") { - word = word.Last(x => x != '<').ToString(); + if (Document.GetText(CaretOffset - 3, 1) == "{" && Document.GetText(CaretOffset, 1) == "}") + { + CaretOffset--; + Document.Insert(CaretOffset, "\n\t"); + } } - - if (previous_word != word) + else if (!currentWordIncludingParenthesis.Contains(".") || currentWord[currentWord.Length - 2] == '<') { - if (_knownTypes.Exists(x => x.Name == previous_word)) + if (completionWindow.IsVisible) { + completionWindow.UpdatePositionFix(); return; } - if (_blocking_type_words.Contains(previous_word)) + var previous_word = GetPreviousWord(); + var word = GetCurrentWord(); + + if (word.Contains("<")) { - return; + word = word.Last(x => x != '<').ToString(); } - } - if (!String.IsNullOrWhiteSpace(word)) - { - IList<ICompletionData> data = new List<ICompletionData>(); - - foreach (var type in _declaredTypes.Where(x => x.Name.StartsWith(word))) + if (previous_word != word) { - if (type.Kind == TypeKind.Struct) - { - data.Add(new StructCompletionItem() - { - Name = type.Name, - Description = type.Summary, - Namespace = type.ContainingNamespace, - Priority = 1, - }); - } - else if (type.Kind == TypeKind.Enum) - { - data.Add(new EnumCompletionItem() - { - Name = type.Name, - Description = type.Summary, - Namespace = type.ContainingNamespace, - Priority = 1, - }); - } - else if (type.Kind == TypeKind.Interface) + if (_knownTypes.Exists(x => x.Name == previous_word)) { - data.Add(new InterfaceCompletionItem() - { - Name = type.Name, - Description = type.Summary, - Namespace = type.ContainingNamespace, - Priority = 1, - }); - } - else if (type.Kind == TypeKind.Class) - { - data.Add(new ClassCompletionItem() - { - Name = type.Name, - Description = type.Summary, - Namespace = type.ContainingNamespace, - Priority = 1, - }); + return; } - else + + if (_blocking_type_words.Contains(previous_word)) { - throw new NotImplementedException("Implement generic item here!"); + return; } } - foreach (var type in _knownTypes.ToList().Where(x => x.Name.StartsWith(word))) + if (!String.IsNullOrWhiteSpace(word)) { - if (type.Type.IsEnum) + IList<ICompletionData> data = new List<ICompletionData>(); + + foreach (var snippet in snippets) { - data.Add(new EnumCompletionItem() - { - Namespace = type.Type.Namespace, - Description = type.Summary, - Name = type.FriendlyName, - Priority = 0, - }); + data.Add(snippet); } - else if (type.Type.IsInterface) + + foreach (var type in _declaredTypes.Where(x => x.Name.StartsWith(word))) { - data.Add(new InterfaceCompletionItem() + if (type.Kind == TypeKind.Struct) { - Name = type.FriendlyName, - Description = type.Summary, - Namespace = type.Type.Namespace, - Priority = 0, - }); - } - else if (type.Type.IsValueType) - { - data.Add(new StructCompletionItem() + data.Add(new StructCompletionItem() + { + Name = type.Name, + Description = type.Summary, + Namespace = type.ContainingNamespace, + Priority = 1, + }); + } + else if (type.Kind == TypeKind.Enum) { - Name = type.FriendlyName, - Description = type.Summary, - Namespace = type.Type.Namespace, - Priority = 0, - }); - } - else if (type.Type.IsClass) - { - data.Add(new ClassCompletionItem() + data.Add(new EnumCompletionItem() + { + Name = type.Name, + Description = type.Summary, + Namespace = type.ContainingNamespace, + Priority = 1, + }); + } + else if (type.Kind == TypeKind.Interface) { - Name = type.FriendlyName, - Description = type.Summary, - Namespace = type.Type.Namespace, - Priority = 0, - }); - } - else - { - throw new NotImplementedException("Implement generic item here."); + data.Add(new InterfaceCompletionItem() + { + Name = type.Name, + Description = type.Summary, + Namespace = type.ContainingNamespace, + Priority = 1, + }); + } + else if (type.Kind == TypeKind.Class) + { + data.Add(new ClassCompletionItem() + { + Name = type.Name, + Description = type.Summary, + Namespace = type.ContainingNamespace, + Priority = 1, + }); + } + else + { + throw new NotImplementedException("Implement generic item here!"); + } } - } - foreach (var symbol in _parser.GetContextSymbols(Document.Text, CaretOffset).Where(x => x.Name.StartsWith(GetCurrentWord()))) - { - if (symbol.Kind == SymbolKind.Property) + foreach (var type in _knownTypes.ToList().Where(x => x.Name.StartsWith(word))) { - data.Add(new PropertyCompletionItem() + if (type.Type.IsEnum) { - Class = symbol.Class, - Description = symbol.Summary, - Name = symbol.Name, - Type = symbol.Type, - Priority = 2, - }); - } - else if (symbol.Kind == SymbolKind.Field || symbol.Kind == SymbolKind.Local || symbol.Kind == SymbolKind.Parameter) - { - data.Add(new FieldCompletionItem() + data.Add(new EnumCompletionItem() + { + Namespace = type.Type.Namespace, + Description = type.Summary, + Name = type.FriendlyName, + Priority = 0, + }); + } + else if (type.Type.IsInterface) { - Class = symbol.Class, - Description = symbol.Summary, - Name = symbol.Name, - Type = symbol.Type, - Priority = 2, - }); + data.Add(new InterfaceCompletionItem() + { + Name = type.FriendlyName, + Description = type.Summary, + Namespace = type.Type.Namespace, + Priority = 0, + }); + } + else if (type.Type.IsValueType) + { + data.Add(new StructCompletionItem() + { + Name = type.FriendlyName, + Description = type.Summary, + Namespace = type.Type.Namespace, + Priority = 0, + }); + } + else if (type.Type.IsClass) + { + data.Add(new ClassCompletionItem() + { + Name = type.FriendlyName, + Description = type.Summary, + Namespace = type.Type.Namespace, + Priority = 0, + }); + } + else + { + throw new NotImplementedException("Implement generic item here."); + } } - else if (symbol.Kind == SymbolKind.Method) + + foreach (var symbol in _parser.GetContextSymbols(Document.Text, CaretOffset).Where(x => x.Name.StartsWith(GetCurrentWord()))) { - var methodCompletion = new MethodCompletionItem() + if (symbol.Kind == SymbolKind.Property) { - Class = symbol.Class, - Description = symbol.Summary, - Name = symbol.Name, - ReturnType = symbol.Type, - Priority = 2, - }; - - for (int i = 0; i < symbol.Parameters.Count; i++) + data.Add(new PropertyCompletionItem() + { + Class = symbol.Class, + Description = symbol.Summary, + Name = symbol.Name, + Type = symbol.Type, + Priority = 2, + }); + } + else if (symbol.Kind == SymbolKind.Field || symbol.Kind == SymbolKind.Local || symbol.Kind == SymbolKind.Parameter) { - var pair = symbol.Parameters[i]; - - methodCompletion.Parameters.Add(new KnownTypeMethodParameter() + data.Add(new FieldCompletionItem() { - Type = pair.Key, - Name = pair.Value, - IsLast = (i == symbol.Parameters.Count - 1) + Class = symbol.Class, + Description = symbol.Summary, + Name = symbol.Name, + Type = symbol.Type, + Priority = 2, }); } + else if (symbol.Kind == SymbolKind.Method) + { + var methodCompletion = new MethodCompletionItem() + { + Class = symbol.Class, + Description = symbol.Summary, + Name = symbol.Name, + ReturnType = symbol.Type, + Priority = 2, + }; + + for (int i = 0; i < symbol.Parameters.Count; i++) + { + var pair = symbol.Parameters[i]; - data.Add(methodCompletion); + methodCompletion.Parameters.Add(new KnownTypeMethodParameter() + { + Type = pair.Key, + Name = pair.Value, + IsLast = (i == symbol.Parameters.Count - 1) + }); + } + + data.Add(methodCompletion); + } } - } - ShowCompletionWindow(data, word); + ShowCompletionWindow(data, word); + } } } + catch (Exception ex) + { + Debug.WriteLine(ex.ToString()); + } } #endregion @@ -792,7 +1075,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); } @@ -864,16 +1147,23 @@ namespace Tango.Scripting.Editors return list; } - private KnownType GetCurrentKnownType() + private KnownTypeResult GetCurrentKnownType() { var expression = GetPreviousWords().LastOrDefault(); return GetKnownTypeFromExpression(expression); } - private KnownType GetKnownTypeFromExpression(String expression) + private KnownTypeResult GetKnownTypeFromExpression(String expression) { 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(); @@ -884,7 +1174,7 @@ namespace Tango.Scripting.Editors if (enumType != null) { - return enumType; + return new KnownTypeResult(enumType); } tree.RemoveAt(0); @@ -893,7 +1183,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) { @@ -911,9 +1202,37 @@ namespace Tango.Scripting.Editors knownType = _knownTypes.FirstOrDefault(x => x.Type.Namespace + "." + x.Type.Name == member.ReturnType.Namespace + "." + member.ReturnType.Name); } - return knownType; + return new KnownTypeResult(knownType); + } + else //Maybe a variable of a declared type... + { + if (tree.Count > 0) + { + var memberName = tree[0]; + var declaredType = _declaredTypes.SingleOrDefault(x => x.Name == name); + + if (declaredType != null) + { + var member = declaredType.Symbols.FirstOrDefault(x => x.Name == memberName); + if (member != null) + { + knownType = _knownTypes.SingleOrDefault(x => x.Name.ToLower() == member.Type.ToLower()); + + if (knownType != null) + { + return new KnownTypeResult(knownType); + } + } + } + } } } + else + { + //Maybe static... + var type = _knownTypes.FirstOrDefault(x => x.Name == variableName || x.Alias == variableName); + return type != null ? new KnownTypeResult(type) { IsStatic = true } : null; + } } } @@ -926,6 +1245,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(); @@ -958,6 +1284,11 @@ namespace Tango.Scripting.Editors return declaredType; } } + else + { + //Maybe static... + return _declaredTypes.FirstOrDefault(x => x.Name == variableName); + } } } @@ -1047,7 +1378,7 @@ namespace Tango.Scripting.Editors foreach (var m in session.Type.Methods.Where(x => x.Name == session.MethodName)) { MethodDescription method = new MethodDescription(); - method.ReturnType = session.Type.Name; + method.ReturnType = m.ReturnTypeFriendlyName; method.Description = m.Summary; method.Name = m.NameWithTypeArguments; method.Class = session.Type.FriendlyName; @@ -1140,33 +1471,364 @@ namespace Tango.Scripting.Editors return popup; } - private void InvalidateHighlighting() + public void LoadUsingsSymbols(List<Assembly> assemblies, List<String> usings) + { + lock (_loadUsingsLock) + { + LoadingSymbolsStarted?.Invoke(null, new EventArgs()); + + var allTypes = assemblies.SelectMany(x => x.GetTypes()); + + foreach (var use in usings) + { + if (!_cachedUsings.Exists(x => x.Namespace == use)) + { + if (!_isUsingsLoadingStarted) + { + _isUsingsLoadingStarted = true; + UsingsLoadingStarted?.Invoke(this, new EventArgs()); + } + + var useFileName = System.IO.Path.Combine(KNOWN_TYPES_CACHE_FOLDER, use + ".json"); + + if (File.Exists(useFileName)) + { + 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) + { + _knownTypesCache.Add(knownType.Type, knownType); + } + + KnownTypesAvailable?.Invoke(this, new EventArgs()); + InvalidateHighlightingPartial(); + + continue; + } + + var useTypes = allTypes.Where(x => x.IsVisible && x.IsPublic && x.Namespace == use).ToList(); + + CachedUsing cachedUsing = new CachedUsing(); + cachedUsing.Namespace = use; + _cachedUsings.Add(cachedUsing); + + int i = 1; + + foreach (var type in useTypes) + { + 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"; + } + } + else if (type == typeof(String)) + { + knownType.Alias = "string"; + } + + _knownTypesCache.Add(type, knownType); + cachedUsing.KnownTypes.Add(knownType); + knownType.LoadDocumentation(); + } + + if (!BlockedUsingsCache.Exists(x => use.StartsWith(x))) + { + Task.Factory.StartNew(() => + { + var json = JsonConvert.SerializeObject(cachedUsing, _jsonSettings); + File.WriteAllText(useFileName, json); + }); + } + } + } + + if (_isUsingsLoadingStarted) + { + UsingsLoadingCompleted?.Invoke(this, new EventArgs()); + } + + LoadingSymbolsCompleted?.Invoke(null, new EventArgs()); + } + } + + //public static void LoadCachedAssemblies(List<Assembly> assemblies, List<String> usings = null) + //{ + // if (_isLoadingCachedAssemblies) return; + + // _isLoadingCachedAssemblies = true; + + // LoadingSymbolsStarted?.Invoke(null, new EventArgs()); + + // 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)}'..." + // } + // }); + + // var cachedAssembly = JsonConvert.DeserializeObject<CachedAssembly>(System.IO.File.ReadAllText(file), _jsonSettings); + + // foreach (var knownType in cachedAssembly.KnownTypes) + // { + // _knownTypesCache.Add(knownType.Type, knownType); + // } + + // _cachedAssemblies.Add(cachedAssembly); + // } + // catch { } + // } + + // _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 InvalidateHighlightingPartial() + { + List<Assembly> assemblies = new List<Assembly>(); + Dispatcher.Invoke(() => + { + assemblies = ReferenceAssemblies.ToList(); + }); + + var usings = _current_usings.ToList(); + + _knownTypes.Clear(); + + foreach (var knownType in _knownTypesCache.ToList().Select(x => x.Value).ToList()) + { + if (usings.Exists(x => knownType.Type.Namespace == x) && assemblies.Exists(x => x == knownType.Type.Assembly)) + { + lock (_knownTypes) + { + _knownTypes.Add(knownType); + } + } + } + + if (_knownTypes.Count > 0 || _declaredTypes.Count > 0) + { + String text = String.Empty; + + Stream xshd_stream = typeof(ScriptEditor).Assembly.GetManifestResourceStream("Tango.Scripting.Editors.Highlighting.Resources.CSharp-Mode.xshd"); + + using (StreamReader reader = new StreamReader(xshd_stream)) + { + text = reader.ReadToEnd(); + } + + List<String> referenceTypes = new List<string>(); + List<String> interfaceTypes = new List<string>(); + + lock (_knownTypes) + { + foreach (var type in _knownTypes.ToList().Where(x => x != null)) + { + String name = type.Name; + + if (type.Type.ContainsGenericParameters) + { + name = new String(name.TakeWhile(x => x != '`').ToArray()); + } + + if (type.Type.IsInterface || type.Type.IsEnum) + { + interfaceTypes.Add(String.Format("<Word>{0}</Word>", name)); + } + else if (type.Type.IsClass || (type.Type.IsValueType)) + { + referenceTypes.Add(String.Format("<Word>{0}</Word>", name)); + } + } + } + + foreach (var type in _declaredTypes) + { + if (type.Kind == TypeKind.Interface || type.Kind == TypeKind.Enum) + { + interfaceTypes.Add(String.Format("<Word>{0}</Word>", type.Name)); + } + else if (type.Kind == TypeKind.Class) + { + referenceTypes.Add(String.Format("<Word>{0}</Word>", type.Name)); + } + } + + if (referenceTypes.Count > 0) + { + text = text.Replace("<Word>@ReferenceTypes@</Word>", String.Join(Environment.NewLine, referenceTypes.Distinct())); + } + + if (interfaceTypes.Count > 0) + { + text = text.Replace("<Word>@InterfaceTypes@</Word>", String.Join(Environment.NewLine, interfaceTypes.Distinct())); + } + + MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(text)); + + XmlTextReader xshd_reader = new XmlTextReader(ms); + + Dispatcher.Invoke(new Action(() => + { + SyntaxHighlighting = HighlightingLoader.Load(xshd_reader, HighlightingManager.Instance); + xshd_reader.Close(); + ms.Dispose(); + })); + } + } + + public void InvalidateHighlighting(bool loadKnownTypes = true) { if (!_isLoadingTypes) { _isLoadingTypes = true; - _knownTypes.Clear(); var assemblies = ReferenceAssemblies.ToList(); + KnownType.ExtensionMethodsAssemblies = assemblies.ToList(); var usings = _current_usings.ToList(); Thread t = new Thread(() => { - foreach (var asm in assemblies.Select(x => x.Assembly)) + LoadUsingsSymbols(assemblies, usings); + + if (loadKnownTypes) { - Parallel.ForEach(asm.GetTypes().Where(x => x.IsVisible && x.IsPublic && !x.IsPrimitive), (type) => + _knownTypes.Clear(); + + foreach (var knownType in _knownTypesCache.ToList().Select(x => x.Value).ToList()) { - if (usings.Exists(x => type.Namespace == x)) + if (usings.Exists(x => knownType.Type.Namespace == x) && assemblies.Exists(x => x == knownType.Type.Assembly)) { lock (_knownTypes) { - if (!_knownTypes.Exists(x => x.Type.FullName == type.FullName)) - { - _knownTypes.Add(new KnownType(type)); - } + _knownTypes.Add(knownType); } } - }); + } } if (_knownTypes.Count > 0 || _declaredTypes.Count > 0) @@ -1239,10 +1901,10 @@ namespace Tango.Scripting.Editors })); - foreach (var knownType in _knownTypes) - { - knownType.LoadDocumentation(); - } + //foreach (var knownType in _knownTypes) + //{ + // knownType.LoadDocumentation(); + //} } _isLoadingTypes = false; @@ -1256,10 +1918,19 @@ namespace Tango.Scripting.Editors { var declaredTypes = _parser.GetDeclaredTypes(Text); + if (AdditionalScripts != null) + { + foreach (var script in AdditionalScripts) + { + declaredTypes.AddRange(_parser.GetDeclaredTypes(script.Code)); + } + } + + if (declaredTypes.Exists(x => !_declaredTypes.Exists(y => y.Name == x.Name)) || _declaredTypes.Exists(x => !declaredTypes.Exists(y => y.Name == x.Name))) { _declaredTypes = declaredTypes; - InvalidateHighlighting(); + InvalidateHighlighting(false); } _declaredTypes = declaredTypes; @@ -1311,7 +1982,8 @@ namespace Tango.Scripting.Editors private void IndentCode() { - Text = Indentation.CSharp.CSharpIndentationHelper.IndentCSharpCode(Text); + Text = CodeFormatter.Format(Text); + //Text = Indentation.CSharp.CSharpIndentationHelper.IndentCSharpCode(Text); //Text = _parser.IndentCSharpCode(Text); } @@ -1389,7 +2061,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) { @@ -1445,13 +2121,64 @@ namespace Tango.Scripting.Editors } } + else + { + var expression2 = _parser.GetCurrentConstructionExpressionAlt(GetCurrentLineText()); + + if (expression2 != null && expression2.Identifier != null) + { + ConstructionSession session = new ConstructionSession(); + + var line = GetCurrentLine(); + int parameterIndex = 0; + for (int i = CaretOffset; i > line.Offset; i--) + { + String c = Document.GetText(i, 1); + + if (c == "(") + { + KnownType type = null; + + if (expression2.Identifier != null) + { + var typeName = expression2.Identifier.ToString(); + type = _knownTypes.FirstOrDefault(x => x.Type.Name == typeName); + + if (type != null) + { + session.Type = type; + session.ParameterIndex = parameterIndex; + return session; + } + else + { + return null; + } + } + } + else if (c == ",") + { + parameterIndex++; + } + } + } + } return null; } private MethodSession GetMethodSession() { - var words = GetCurrentLineText().Split(' '); + var currentLine = GetCurrentLineText(); + + if (currentLine.Count(x => x == '(') > 1) + { + currentLine = currentLine.Split('(')[currentLine.Split('(').Length - 2]; + } + + currentLine = Regex.Replace(currentLine, "(?<=\")(.*?)(?=\")", string.Empty); + + var words = currentLine.Split(' '); if (words.Count() > 0 && (words.First() == "private" || words.First() == "public" || words.First() == "void")) { @@ -1463,6 +2190,8 @@ namespace Tango.Scripting.Editors if (expression != null) { int parameterIndex = expression.Count(x => x == ','); + + expression = new string(expression.TakeWhile(x => x != '(').ToArray()); var tree = expression.Split('.').Select(x => x.Remove(@"\n|\r|\s|\t|\(|\)|\[|\]|<.*>")).ToList(); @@ -1508,7 +2237,7 @@ namespace Tango.Scripting.Editors return null; } - private DeclaredMethodSession GetDeclaredMethodSession() + private MethodSession GetStaticMethodSession() { var words = GetCurrentLineText().Split(' '); @@ -1517,7 +2246,73 @@ namespace Tango.Scripting.Editors return null; } - var expression = GetPreviousWords().LastOrDefault(); + var expression = words.LastOrDefault(); + + if (expression != null) + { + int parameterIndex = expression.Count(x => x == ','); + expression = new string(expression.TakeWhile(x => x != '(').ToArray()); + + var tree = expression.Split('.').Select(x => x.Remove(@"\n|\r|\s|\t|\(|\)|\[|\]|<.*>")).ToList(); + var variableName = tree.FirstOrDefault(); + + if (variableName != null && tree.Count > 1) + { + tree.RemoveAt(0); + var variables = _parser.GetContextSymbols(Document.Text, CaretOffset); + var variable = variableName; + + if (variable != null) + { + var knownType = _knownTypes.FirstOrDefault(x => x.FriendlyName == Regex.Replace(variable, "<.+>", "<T>")); + + if (knownType != null) + { + while (tree.Count > 1) + { + var memberName = tree.First(); + tree.RemoveAt(0); + var member = knownType.Members.FirstOrDefault(x => x.Name == memberName); + + if (member == null) + { + return null; + } + + knownType = _knownTypes.FirstOrDefault(x => x.Type.Namespace + "." + x.Type.Name == member.ReturnType.Namespace + "." + member.ReturnType.Name); + } + + return new MethodSession() + { + Type = knownType, + MethodName = tree.Last(), + ParameterIndex = parameterIndex, + }; + } + } + } + } + + return null; + } + + private DeclaredMethodSession GetDeclaredMethodSession() + { + 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 = currentLine; if (expression != null) { @@ -1532,7 +2327,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) { @@ -1591,5 +2386,413 @@ namespace Tango.Scripting.Editors } #endregion + + #region Reference Assemblies Changed + + private void OnReferenceAssembliesChanged() + { + if (ReferenceAssemblies != null) + { + ReferenceAssemblies.CollectionChanged -= ReferenceAssemblies_CollectionChanged; + ReferenceAssemblies.CollectionChanged += ReferenceAssemblies_CollectionChanged; + + InvalidateHighlighting(); + } + } + + private void ReferenceAssemblies_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) + { + InvalidateHighlighting(); + } + + #endregion + + #region Public Methods + + public void FormatCode() + { + try + { + int index = CaretOffset; + Document.BeginUpdate(); + IndentCode(); + Document.EndUpdate(); + CaretOffset = index; + } + catch + { + Debug.WriteLine("Error formatting code."); + } + } + + public void Highlight(int position, int length, int line) + { + Select(position, Math.Max(length, 1)); + ScrollToLine(line); + } + + public void InsertCode(String code) + { + Document.Insert(TextArea.Caret.Offset, code); + } + + public int Find(String text) + { + if (String.IsNullOrEmpty(text)) return -1; + + string txt = Document.Text; + int index = txt.IndexOf(text, TextArea.Caret.Offset); + + if (index > -1) + { + Select(index, text.Length); + ScrollToLine(TextArea.Selection.StartPosition.Line); + } + else + { + index = txt.IndexOf(text, 0); + + if (index > -1) + { + Select(index, text.Length); + ScrollToLine(TextArea.Selection.StartPosition.Line); + } + else + { + Select(0, 0); + System.Media.SystemSounds.Beep.Play(); + } + } + + return index; + } + + public int ReplaceNext(String text, String replace) + { + if (String.IsNullOrEmpty(text)) return -1; + + String selectedText = TextArea.Selection.GetText(); + + if (selectedText == text) + { + TextArea.Selection.ReplaceSelectionWithText(replace); + } + + return Find(text); + } + + public int ReplaceAll(String text, String replace) + { + int counter = 0; + + Select(0, 0); + + while (ReplaceNext(text, replace) > -1) + { + counter++; + }; + + return counter; + } + + public void ColorizeByKeyword(String text) + { + ResetColorizationByKeyword(); + + if (String.IsNullOrEmpty(text)) return; + + var txt = Document.Text; + + var indexes = txt.AllIndexesOf(text).ToList(); + + foreach (var index in indexes) + { + Document.BeginUpdate(); + + var line = Document.GetLineByOffset(index); + + OffsetColorizer colorizer = new OffsetColorizer(line, index, index + text.Length, ColorizeBrush); + TextArea.TextView.LineTransformers.Add(colorizer); + + Document.EndUpdate(); + } + } + + public void ResetColorizationByKeyword() + { + Document.BeginUpdate(); + + for (int i = 0; i < TextArea.TextView.LineTransformers.Count; i++) + { + if (TextArea.TextView.LineTransformers[i] is OffsetColorizer) + { + TextArea.TextView.LineTransformers.RemoveAt(i); + i--; + } + } + + Document.EndUpdate(); + } + + public void HighlighError(int position, int length) + { + try + { + ITextMarker marker = errorMarkerService.Create(position, length); + marker.MarkerTypes = TextMarkerTypes.SquigglyUnderline; + marker.MarkerColor = Colors.Red; + } + catch (Exception ex) + { + Debug.WriteLine($"Error highlighting script error.\n{ex.ToString()}"); + } + } + + public void ClearErrors() + { + 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 void HighlightDebugLine(int lineNumber) + { + Document.BeginUpdate(); + + var line = Document.GetLineByNumber(lineNumber); + OffsetColorizer errorLineColrizer = new OffsetColorizer(line, line.Offset, line.EndOffset, DebugLineBrush); + TextArea.TextView.LineTransformers.Add(errorLineColrizer); + + Document.EndUpdate(); + } + + public void HighlightBreakPoint(int lineNumber, List<ScriptBreakPointSymbol> symbols) + { + _breakPointLineNumber = lineNumber; + _breakPointSymbols = symbols.ToList(); + _currentBreakPointSymbol = null; + + Document.BeginUpdate(); + + var line = Document.GetLineByNumber(lineNumber); + OffsetColorizer errorLineColrizer = new OffsetColorizer(line, line.Offset, line.EndOffset, BreakPointLineBrush); + TextArea.TextView.LineTransformers.Add(errorLineColrizer); + + var breakPoint = breakPointMargin.BreakPoints.FirstOrDefault(x => x.LineNumber == lineNumber); + breakPoint.IsActive = true; + breakPointMargin.InvalidateVisual(); + + Document.EndUpdate(); + } + + public void ResetBreakPointLine() + { + _breakPointSymbols = new List<ScriptBreakPointSymbol>(); + _currentBreakPointSymbol = null; + ResetColorizationByKeyword(); + breakPointMargin.BreakPoints.ToList().ForEach(x => x.IsActive = false); + Mouse.OverrideCursor = null; + ClearErrors(); + breakPointMargin.InvalidateVisual(); + } + + 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; + } + + public List<ScriptBreakPoint> GetBreakPoints() + { + List<ScriptBreakPoint> breakPoints = new List<ScriptBreakPoint>(); + + foreach (var b in breakPointMargin.BreakPoints) + { + ScriptBreakPoint breakPoint = new ScriptBreakPoint(); + breakPoint.Script = ScriptSource; + breakPoint.LineNumber = b.LineNumber; + + var line = Document.GetLineByNumber(b.LineNumber); + breakPoint.LineStartOffset = line.Offset; + breakPoint.LineEndOffset = line.EndOffset; + + var symbols = _parser.GetContextSymbols(Document.Text, line.Offset); + + foreach (var symbol in symbols.Where(x => (x.Kind == SymbolKind.Property || x.Kind == SymbolKind.Field || x.Kind == SymbolKind.Local || x.Kind == SymbolKind.Parameter) && !x.IsUnassigned)) + { + if (symbol.Offset < line.Offset) + { + breakPoint.ContextSymbols.Add(new ScriptBreakPointSymbol() + { + Name = symbol.Name, + Offset = symbol.Offset, + Length = symbol.Length, + }); + } + } + + breakPoints.Add(breakPoint); + } + + return breakPoints; + } + + #endregion + + #region BreakPoint Symbols Search + + private void ScriptEditor_MouseMove(object sender, MouseEventArgs e) + { + if (IsReadOnly && _breakPointSymbols.Count > 0) + { + try + { + var word_separators_plus = word_separators.ToList(); + word_separators_plus.Add(')'); + word_separators_plus.Add(';'); + + var textView = TextArea.TextView; + Point position = e.GetPosition(textView); + position.Y += textView.VerticalOffset; + VisualLine visualLine = textView.GetVisualLineFromVisualTop(position.Y); + int columnIndex = visualLine.GetVisualColumnFloor(position, false); + String line = Document.GetText(visualLine.FirstDocumentLine.Offset, visualLine.FirstDocumentLine.Length); + if (columnIndex < line.Length) + { + int wordStartIndex = columnIndex; + int wordEndIndex = columnIndex; + + while (wordStartIndex > 0) + { + if (word_separators_plus.Contains(line[wordStartIndex])) break; + wordStartIndex--; + } + + while (wordEndIndex < line.Length) + { + if (word_separators_plus.Contains(line[wordEndIndex])) break; + wordEndIndex++; + } + + if (wordStartIndex > 0) + { + wordStartIndex++; + } + + String word = line.Substring(wordStartIndex, wordEndIndex - wordStartIndex); + + var breakPointSymbol = _breakPointSymbols.FirstOrDefault(x => x.Name == word); + + if (breakPointSymbol != null) + { + int wordStartOffset = visualLine.FirstDocumentLine.Offset + wordStartIndex; + + ClearErrors(); + ITextMarker marker = errorMarkerService.Create(wordStartOffset, word.Length); + marker.MarkerTypes = TextMarkerTypes.NormalUnderline; + marker.MarkerColor = Colors.Yellow; + Mouse.OverrideCursor = Cursors.Hand; + + _currentBreakPointSymbol = breakPointSymbol; + _currentBreakPointSymbolPosition = visualLine.GetVisualPosition(wordEndIndex, VisualYPosition.LineTop); + } + else + { + _currentBreakPointSymbol = null; + Mouse.OverrideCursor = null; + ClearErrors(); + } + } + else + { + _currentBreakPointSymbol = null; + Mouse.OverrideCursor = null; + ClearErrors(); + } + } + catch (Exception ex) + { + _currentBreakPointSymbol = null; + Mouse.OverrideCursor = null; + ClearErrors(); + Debug.WriteLine(ex.Message); + } + } + } + + protected override void OnPreviewMouseLeftButtonUp(MouseButtonEventArgs e) + { + base.OnPreviewMouseLeftButtonUp(e); + + if (_currentBreakPointSymbol != null) + { + Mouse.OverrideCursor = null; + Debug.WriteLine($"Pressed on break point symbol: {_currentBreakPointSymbol.Name}"); + BreakPointSymbolPressed?.Invoke(this, new BreakPointSymbolPressedEventArgs() + { + BreakPointSymbol = _currentBreakPointSymbol, + Position = _currentBreakPointSymbolPosition + }); + } + } + + public String GetCaretWord() + { + try + { + var word_separators_plus = word_separators.ToList(); + word_separators_plus.Add(')'); + word_separators_plus.Add(';'); + + int wordStartOffset = CaretOffset; + int wordEndOffset = CaretOffset; + + while (wordStartOffset > 0) + { + if (word_separators_plus.Contains(Document.Text[wordStartOffset])) break; + wordStartOffset--; + } + + while (wordEndOffset < Document.Text.Length) + { + if (word_separators_plus.Contains(Document.Text[wordEndOffset])) break; + wordEndOffset++; + } + + if (wordStartOffset > 0) + { + wordStartOffset++; + } + + String word = Document.Text.Substring(wordStartOffset, wordEndOffset - wordStartOffset); + + return word; + } + catch + { + return null; + } + } + + #endregion } } 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 ce7c361e3..11e023f86 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 @@ -77,6 +77,9 @@ <Reference Include="Microsoft.CodeAnalysis.CSharp, Version=2.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"> <HintPath>..\..\packages\Microsoft.CodeAnalysis.CSharp.2.4.0\lib\netstandard1.3\Microsoft.CodeAnalysis.CSharp.dll</HintPath> </Reference> + <Reference Include="Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL"> + <HintPath>..\..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll</HintPath> + </Reference> <Reference Include="PresentationCore"> <RequiredTargetFramework>3.0</RequiredTargetFramework> </Reference> @@ -177,6 +180,9 @@ <Link>GlobalVersionInfo.cs</Link> </Compile> <Compile Include="AvalonEditCommands.cs" /> + <Compile Include="BreakPointSymbolPressedEventArgs.cs" /> + <Compile Include="CachedAssembly.cs" /> + <Compile Include="CachedUsing.cs" /> <Compile Include="CodeCompletion\CompletionListBox.cs" /> <Compile Include="CodeCompletion\CompletionListBoxItem.cs" /> <Compile Include="CodeCompletion\CompletionWindowBase.cs" /> @@ -191,14 +197,19 @@ <Compile Include="CodeCompletion\OverloadViewer.cs" /> <Compile Include="Converters\BooleanToVisibilityConverter.cs" /> <Compile Include="Converters\BooleanToVisibilityInversedConverter.cs" /> + <Compile Include="Editing\BreakPointMargin.cs" /> + <Compile Include="Errors\ITextMarker.cs" /> + <Compile Include="Errors\TextMarkerService.cs" /> <Compile Include="ExtensionMethods.cs" /> <Compile Include="Intellisense\ClassCompletionItemPopup.cs" /> <Compile Include="Intellisense\CompletionItem.cs" /> <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\HideIntellisenseAttribute.cs" /> <Compile Include="Intellisense\ICompletionItem.cs" /> <Compile Include="Intellisense\ICompletionProvider.cs" /> <Compile Include="Intellisense\InterfaceCompletionItem.cs" /> @@ -336,6 +347,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" /> @@ -348,6 +360,7 @@ <Compile Include="Intellisense\NamespaceCompletionItemPopup.cs" /> <Compile Include="Intellisense\PropertyCompletionItem.cs" /> <Compile Include="Intellisense\PropertyCompletionItemPopup.cs" /> + <Compile Include="Intellisense\SnippetCompletionItem.cs" /> <Compile Include="Intellisense\StructCompletionItem.cs" /> <Compile Include="Intellisense\StructCompletionItemPopup.cs" /> <Compile Include="Intellisense\Utils.cs" /> @@ -500,6 +513,7 @@ <Compile Include="Utils\ThrowUtil.cs" /> <Compile Include="Utils\Win32.cs" /> <CodeAnalysisDictionary Include="Properties\CodeAnalysisDictionary.xml" /> + <Compile Include="XamlEditor.cs" /> <Compile Include="Xml\AbstractAXmlVisitor.cs" /> <Compile Include="Xml\AXmlAttribute.cs" /> <Compile Include="Xml\AXmlAttributeCollection.cs" /> @@ -579,6 +593,14 @@ <Project>{a34ee0f0-649d-41c8-8489-b6f1cc6924ee}</Project> <Name>Tango.Core</Name> </ProjectReference> + <ProjectReference Include="..\Tango.Scripting.Core\Tango.Scripting.Core.csproj"> + <Project>{5812E1C6-ABAA-4066-94AC-971C27B4F46A}</Project> + <Name>Tango.Scripting.Core</Name> + </ProjectReference> + <ProjectReference Include="..\Tango.Scripting.Formatting\Tango.Scripting.Formatting.csproj"> + <Project>{8d8f06ed-7f75-4933-b0c5-829b0ff654d0}</Project> + <Name>Tango.Scripting.Formatting</Name> + </ProjectReference> <ProjectReference Include="..\Tango.Scripting\Tango.Scripting.csproj"> <Project>{1e938fd2-c669-4738-98c9-77f96ce4d451}</Project> <Name>Tango.Scripting</Name> @@ -626,9 +648,18 @@ <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> + <ItemGroup> + <Resource Include="Images\snippet.png" /> + </ItemGroup> + <ItemGroup> + <Resource Include="Images\break_point_arrow.png" /> + </ItemGroup> <ProjectExtensions> <VisualStudio> - <UserProperties BuildVersion_UseGlobalSettings="True" BuildVersion_AssemblyInfoFilename="Properties\AssemblyInfo.cs" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_BuildVersioningStyle="None.None.Increment.TimeStamp" BuildVersion_StartDate="2000/1/1" /> + <UserProperties BuildVersion_StartDate="2000/1/1" BuildVersion_BuildVersioningStyle="None.None.Increment.TimeStamp" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_AssemblyInfoFilename="Properties\AssemblyInfo.cs" BuildVersion_UseGlobalSettings="True" /> </VisualStudio> </ProjectExtensions> </Project>
\ No newline at end of file diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Tango.Scripting.Editors_di35u2uj_wpftmp.csproj b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Tango.Scripting.Editors_di35u2uj_wpftmp.csproj new file mode 100644 index 000000000..70a4840c4 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Tango.Scripting.Editors_di35u2uj_wpftmp.csproj @@ -0,0 +1,628 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup> + <ProjectGuid>{DA62FA39-668B-47A6-B0F2-D2C1DAF777B0}</ProjectGuid> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <OutputType>Library</OutputType> + <RootNamespace>Tango.Scripting.Editors</RootNamespace> + <AssemblyName>Tango.Scripting.Editors</AssemblyName> + <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion> + <AppDesignerFolder>Properties</AppDesignerFolder> + <SourceAnalysisOverrideSettingsFile>"C:\Program Files\SharpDevelop\3.0\bin\..\AddIns\AddIns\Misc\SourceAnalysis\Settings.SourceAnalysis"</SourceAnalysisOverrideSettingsFile> + <AllowUnsafeBlocks>False</AllowUnsafeBlocks> + <NoStdLib>False</NoStdLib> + <WarningLevel>4</WarningLevel> + <TreatWarningsAsErrors>false</TreatWarningsAsErrors> + <SignAssembly>false</SignAssembly> + <AssemblyOriginatorKeyFile>ICSharpCode.AvalonEdit.snk</AssemblyOriginatorKeyFile> + <DelaySign>False</DelaySign> + <AssemblyOriginatorKeyMode>File</AssemblyOriginatorKeyMode> + <RunCodeAnalysis>False</RunCodeAnalysis> + <CodeAnalysisRules>-Microsoft.Design#CA1020;-Microsoft.Design#CA1033;-Microsoft.Performance#CA1805;-Microsoft.Performance#CA1810</CodeAnalysisRules> + <OutputPath>..\bin\$(Configuration)</OutputPath> + <DocumentationFile>..\bin\$(Configuration)\ICSharpCode.AvalonEdit.xml</DocumentationFile> + <NoWarn>1607</NoWarn> + <TargetFrameworkProfile> + </TargetFrameworkProfile> + <SccProjectName>SAK</SccProjectName> + <SccLocalPath>SAK</SccLocalPath> + <SccAuxPath>SAK</SccAuxPath> + <SccProvider>SAK</SccProvider> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)' == 'Debug' "> + <DebugSymbols>true</DebugSymbols> + <DebugType>Full</DebugType> + <Optimize>False</Optimize> + <CheckForOverflowUnderflow>True</CheckForOverflowUnderflow> + <DefineConstants>DEBUG;TRACE;DOTNET4</DefineConstants> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)' == 'Release' "> + <DebugSymbols>false</DebugSymbols> + <DebugType>PdbOnly</DebugType> + <Optimize>True</Optimize> + <CheckForOverflowUnderflow>False</CheckForOverflowUnderflow> + <DefineConstants>TRACE;DOTNET4</DefineConstants> + </PropertyGroup> + <PropertyGroup Condition=" '$(Platform)' == 'AnyCPU' "> + <RegisterForComInterop>False</RegisterForComInterop> + <GenerateSerializationAssemblies>Auto</GenerateSerializationAssemblies> + <BaseAddress>4194304</BaseAddress> + <PlatformTarget>AnyCPU</PlatformTarget> + <FileAlignment>4096</FileAlignment> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'"> + <OutputPath>..\..\Build\Scripting\Debug\</OutputPath> + <DocumentationFile> + </DocumentationFile> + <Prefer32Bit>false</Prefer32Bit> + <DefineConstants>TRACE;DEBUG</DefineConstants> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|AnyCPU'"> + <Prefer32Bit>false</Prefer32Bit> + <OutputPath>..\..\Build\Scripting\Release\</OutputPath> + <DocumentationFile /> + </PropertyGroup> + <PropertyGroup> + <ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> + </PropertyGroup> + <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" /> + <ItemGroup> + </ItemGroup> + <ItemGroup> + <Compile Include="..\..\Versioning\GlobalVersionInfo.cs"> + <Link>GlobalVersionInfo.cs</Link> + </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" /> + <Compile Include="CodeCompletion\CompletionList.cs" /> + <Compile Include="CodeCompletion\CompletionWindow.cs"> + <SubType>Code</SubType> + </Compile> + <Compile Include="CodeCompletion\ICompletionData.cs" /> + <Compile Include="CodeCompletion\InsightWindow.cs" /> + <Compile Include="CodeCompletion\IOverloadProvider.cs" /> + <Compile Include="CodeCompletion\OverloadInsightWindow.cs" /> + <Compile Include="CodeCompletion\OverloadViewer.cs" /> + <Compile Include="Converters\BooleanToVisibilityConverter.cs" /> + <Compile Include="Converters\BooleanToVisibilityInversedConverter.cs" /> + <Compile Include="Editing\BreakPoint.cs" /> + <Compile Include="Editing\BreakPointMargin.cs" /> + <Compile Include="Errors\ITextMarker.cs" /> + <Compile Include="Errors\TextMarkerService.cs" /> + <Compile Include="ExtensionMethods.cs" /> + <Compile Include="Intellisense\ClassCompletionItemPopup.cs" /> + <Compile Include="Intellisense\CompletionItem.cs" /> + <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" /> + <Compile Include="Intellisense\ICompletionProvider.cs" /> + <Compile Include="Intellisense\InterfaceCompletionItem.cs" /> + <Compile Include="Intellisense\InterfaceCompletionItemPopup.cs" /> + <Compile Include="Intellisense\KnownType.cs" /> + <Compile Include="Document\ChangeTrackingCheckpoint.cs" /> + <Compile Include="Document\DocumentChangeOperation.cs"> + <DependentUpon>UndoStack.cs</DependentUpon> + </Compile> + <Compile Include="Document\ILineTracker.cs" /> + <Compile Include="Document\ISegment.cs" /> + <Compile Include="Document\ITextSource.cs" /> + <Compile Include="Document\IUndoableOperation.cs"> + <DependentUpon>UndoStack.cs</DependentUpon> + </Compile> + <Compile Include="Document\LineNode.cs"> + <DependentUpon>DocumentLine.cs</DependentUpon> + </Compile> + <Compile Include="Document\NewLineFinder.cs" /> + <Compile Include="Document\OffsetChangeMap.cs" /> + <Compile Include="Document\TextDocumentWeakEventManager.cs"> + <DependentUpon>TextDocument.cs</DependentUpon> + </Compile> + <Compile Include="Document\TextSegmentCollection.cs" /> + <Compile Include="Document\TextAnchor.cs" /> + <Compile Include="Document\TextAnchorNode.cs"> + <DependentUpon>TextAnchor.cs</DependentUpon> + </Compile> + <Compile Include="Document\TextAnchorTree.cs"> + <DependentUpon>TextAnchor.cs</DependentUpon> + </Compile> + <Compile Include="Document\TextLocation.cs" /> + <Compile Include="Document\TextSegment.cs" /> + <Compile Include="Document\TextUtilities.cs" /> + <Compile Include="Document\UndoOperationGroup.cs"> + <DependentUpon>UndoStack.cs</DependentUpon> + </Compile> + <Compile Include="Document\UndoStack.cs"> + </Compile> + <Compile Include="Document\WeakLineTracker.cs"> + <DependentUpon>ILineTracker.cs</DependentUpon> + </Compile> + <Compile Include="Editing\AbstractMargin.cs" /> + <Compile Include="Editing\Caret.cs" /> + <Compile Include="Editing\CaretLayer.cs"> + </Compile> + <Compile Include="Editing\CaretNavigationCommandHandler.cs"> + </Compile> + <Compile Include="Editing\CaretWeakEventHandler.cs" /> + <Compile Include="Editing\DottedLineMargin.cs" /> + <Compile Include="Editing\DragDropException.cs" /> + <Compile Include="Editing\EditingCommandHandler.cs" /> + <Compile Include="Editing\EmptySelection.cs"> + <DependentUpon>Selection.cs</DependentUpon> + </Compile> + <Compile Include="Editing\ImeNativeWrapper.cs" /> + <Compile Include="Editing\SelectionSegment.cs" /> + <Compile Include="Editing\ImeSupport.cs" /> + <Compile Include="Folding\AbstractFoldingStrategy.cs" /> + <Compile Include="Folding\BraceFoldingStrategy.cs" /> + <Compile Include="Folding\FoldingElementGenerator.cs" /> + <Compile Include="Folding\FoldingManager.cs" /> + <Compile Include="Folding\FoldingMargin.cs" /> + <Compile Include="Folding\FoldingMarginMarker.cs" /> + <Compile Include="Folding\FoldingSection.cs" /> + <Compile Include="Editing\IReadOnlySectionProvider.cs" /> + <Compile Include="Editing\LineNumberMargin.cs" /> + <Compile Include="Editing\NoReadOnlySections.cs"> + <DependentUpon>IReadOnlySectionProvider.cs</DependentUpon> + </Compile> + <Compile Include="Editing\RectangleSelection.cs"> + <DependentUpon>Selection.cs</DependentUpon> + </Compile> + <Compile Include="Editing\Selection.cs" /> + <Compile Include="Editing\SelectionColorizer.cs"> + <DependentUpon>Selection.cs</DependentUpon> + </Compile> + <Compile Include="Editing\SelectionLayer.cs"> + <DependentUpon>Selection.cs</DependentUpon> + </Compile> + <Compile Include="Editing\SelectionMouseHandler.cs"> + <DependentUpon>Selection.cs</DependentUpon> + </Compile> + <Compile Include="Editing\SimpleSelection.cs"> + <DependentUpon>Selection.cs</DependentUpon> + </Compile> + <Compile Include="Editing\TextArea.cs" /> + <Compile Include="Editing\TextAreaDefaultInputHandlers.cs" /> + <Compile Include="Editing\TextAreaInputHandler.cs" /> + <Compile Include="Editing\TextSegmentReadOnlySectionProvider.cs"> + <DependentUpon>IReadOnlySectionProvider.cs</DependentUpon> + </Compile> + <Compile Include="Folding\NewFolding.cs" /> + <Compile Include="Folding\XmlFoldingStrategy.cs" /> + <Compile Include="Highlighting\DocumentHighlighter.cs" /> + <Compile Include="Highlighting\HighlightedInlineBuilder.cs" /> + <Compile Include="Highlighting\HighlightedLine.cs" /> + <Compile Include="Highlighting\HighlightedSection.cs" /> + <Compile Include="Highlighting\HighlightingBrush.cs" /> + <Compile Include="Highlighting\HighlightingColor.cs" /> + <Compile Include="Highlighting\HighlightingColorizer.cs" /> + <Compile Include="Highlighting\HighlightingDefinitionInvalidException.cs" /> + <Compile Include="Highlighting\HighlightingDefinitionTypeConverter.cs" /> + <Compile Include="Highlighting\HighlightingManager.cs" /> + <Compile Include="Highlighting\HtmlClipboard.cs" /> + <Compile Include="Highlighting\IHighlighter.cs" /> + <Compile Include="Highlighting\IHighlightingDefinition.cs" /> + <Compile Include="Highlighting\HighlightingRule.cs" /> + <Compile Include="Highlighting\OffsetColorizer.cs" /> + <Compile Include="Highlighting\Resources\Resources.cs" /> + <Compile Include="Highlighting\HighlightingRuleSet.cs" /> + <Compile Include="Highlighting\HighlightingSpan.cs" /> + <Compile Include="Highlighting\IHighlightingDefinitionReferenceResolver.cs"> + </Compile> + <Compile Include="Highlighting\Xshd\HighlightingLoader.cs" /> + <Compile Include="Highlighting\Xshd\IXshdVisitor.cs" /> + <Compile Include="Highlighting\Xshd\SaveXshdVisitor.cs" /> + <Compile Include="Highlighting\Xshd\V1Loader.cs" /> + <Compile Include="Highlighting\Xshd\V2Loader.cs" /> + <Compile Include="Highlighting\Xshd\XmlHighlightingDefinition.cs" /> + <Compile Include="Highlighting\Xshd\XshdColor.cs" /> + <Compile Include="Highlighting\Xshd\XshdImport.cs" /> + <Compile Include="Highlighting\Xshd\XshdProperty.cs" /> + <Compile Include="Highlighting\Xshd\XshdReference.cs" /> + <Compile Include="Highlighting\Xshd\XshdElement.cs" /> + <Compile Include="Highlighting\Xshd\XshdKeywords.cs" /> + <Compile Include="Highlighting\Xshd\XshdRule.cs" /> + <Compile Include="Highlighting\Xshd\XshdRuleSet.cs" /> + <Compile Include="Highlighting\Xshd\XshdSpan.cs" /> + <Compile Include="Highlighting\Xshd\XshdSyntaxDefinition.cs" /> + <Compile Include="Indentation\CSharp\CSharpIndentationHelper.cs" /> + <Compile Include="Indentation\CSharp\IndentationReformatter.cs" /> + <Compile Include="Indentation\CSharp\CSharpIndentationStrategy.cs" /> + <Compile Include="Indentation\CSharp\DocumentAccessor.cs" /> + <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" /> + <Compile Include="Intellisense\KnownTypeMethod.cs" /> + <Compile Include="Intellisense\KnownTypeProperty.cs" /> + <Compile Include="Intellisense\ClassCompletionItem.cs" /> + <Compile Include="Intellisense\MethodCompletionItem.cs" /> + <Compile Include="Intellisense\MethodCompletionItemPopup.cs" /> + <Compile Include="Intellisense\NamespaceCompletionItem.cs" /> + <Compile Include="Intellisense\NamespaceCompletionItemPopup.cs" /> + <Compile Include="Intellisense\PropertyCompletionItem.cs" /> + <Compile Include="Intellisense\PropertyCompletionItemPopup.cs" /> + <Compile Include="Intellisense\SnippetCompletionItem.cs" /> + <Compile Include="Intellisense\StructCompletionItem.cs" /> + <Compile Include="Intellisense\StructCompletionItemPopup.cs" /> + <Compile Include="Intellisense\Utils.cs" /> + <Compile Include="Popups\MethodDescription.cs" /> + <Compile Include="Popups\MethodPopup.cs" /> + <Compile Include="Popups\ParameterDescription.cs" /> + <Compile Include="Rendering\BackgroundGeometryBuilder.cs"> + <DependentUpon>IBackgroundRenderer.cs</DependentUpon> + </Compile> + <Compile Include="Rendering\CollapsedLineSection.cs"> + <DependentUpon>HeightTree.cs</DependentUpon> + </Compile> + <Compile Include="Rendering\ColorizingTransformer.cs"> + <DependentUpon>IVisualLineTransformer.cs</DependentUpon> + </Compile> + <Compile Include="Rendering\ColumnRulerRenderer.cs" /> + <Compile Include="Rendering\DefaultTextRunTypographyProperties.cs" /> + <Compile Include="Rendering\DocumentColorizingTransformer.cs"> + <DependentUpon>IVisualLineTransformer.cs</DependentUpon> + </Compile> + <Compile Include="Rendering\FormattedTextElement.cs" /> + <Compile Include="Rendering\GlobalTextRunProperties.cs"> + <DependentUpon>TextView.cs</DependentUpon> + </Compile> + <Compile Include="Rendering\HeightTree.cs" /> + <Compile Include="Rendering\HeightTreeLineNode.cs"> + <DependentUpon>HeightTree.cs</DependentUpon> + </Compile> + <Compile Include="Rendering\HeightTreeNode.cs"> + <DependentUpon>HeightTree.cs</DependentUpon> + </Compile> + <Compile Include="Rendering\IBackgroundRenderer.cs" /> + <Compile Include="Rendering\InlineObjectRun.cs" /> + <Compile Include="Rendering\ITextRunConstructionContext.cs"> + <DependentUpon>VisualLineElementGenerator.cs</DependentUpon> + </Compile> + <Compile Include="Rendering\ITextViewConnect.cs"> + <DependentUpon>TextView.cs</DependentUpon> + </Compile> + <Compile Include="Rendering\IVisualLineTransformer.cs" /> + <Compile Include="Rendering\Layer.cs"> + <DependentUpon>TextView.cs</DependentUpon> + </Compile> + <Compile Include="Rendering\LayerPosition.cs"> + <DependentUpon>TextView.cs</DependentUpon> + </Compile> + <Compile Include="Rendering\LinkElementGenerator.cs" /> + <Compile Include="Rendering\MouseHoverLogic.cs" /> + <Compile Include="Rendering\SimpleTextSource.cs"> + <DependentUpon>FormattedTextElement.cs</DependentUpon> + </Compile> + <Compile Include="Rendering\SingleCharacterElementGenerator.cs" /> + <Compile Include="Rendering\TextLayer.cs"> + <DependentUpon>TextView.cs</DependentUpon> + </Compile> + <Compile Include="Rendering\TextView.cs" /> + <Compile Include="Rendering\TextViewCachedElements.cs" /> + <Compile Include="Rendering\TextViewWeakEventManager.cs"> + <DependentUpon>TextView.cs</DependentUpon> + </Compile> + <Compile Include="Rendering\VisualLine.cs" /> + <Compile Include="Rendering\VisualLineConstructionStartEventArgs.cs" /> + <Compile Include="Rendering\VisualLineElement.cs" /> + <Compile Include="Rendering\VisualLineElementGenerator.cs" /> + <Compile Include="Rendering\VisualLineElementTextRunProperties.cs"> + <DependentUpon>VisualLine.cs</DependentUpon> + </Compile> + <Compile Include="Rendering\VisualLineLinkText.cs" /> + <Compile Include="Rendering\VisualLinesInvalidException.cs" /> + <Compile Include="Rendering\VisualLineText.cs" /> + <Compile Include="Rendering\VisualLineTextParagraphProperties.cs"> + <DependentUpon>VisualLine.cs</DependentUpon> + </Compile> + <Compile Include="Rendering\VisualLineTextSource.cs"> + <DependentUpon>VisualLineElementGenerator.cs</DependentUpon> + </Compile> + <Compile Include="Rendering\VisualYPosition.cs"> + <DependentUpon>VisualLine.cs</DependentUpon> + </Compile> + <Compile Include="ScriptEditor.cs" /> + <Compile Include="Search\Localization.cs" /> + <Compile Include="Search\RegexSearchStrategy.cs" /> + <Compile Include="Search\DropDownButton.cs" /> + <Compile Include="Search\ISearchStrategy.cs" /> + <Compile Include="Search\SearchCommands.cs" /> + <Compile Include="Search\SearchResultBackgroundRenderer.cs" /> + <Compile Include="Search\SearchPanel.cs"> + <SubType>Code</SubType> + </Compile> + <Compile Include="Search\SearchStrategyFactory.cs" /> + <Compile Include="Snippets\IActiveElement.cs" /> + <Compile Include="Snippets\SnippetAnchorElement.cs" /> + <Compile Include="Snippets\SnippetEventArgs.cs" /> + <Compile Include="Snippets\SnippetInputHandler.cs" /> + <Compile Include="Snippets\Snippet.cs" /> + <Compile Include="Snippets\SnippetBoundElement.cs" /> + <Compile Include="Snippets\SnippetCaretElement.cs" /> + <Compile Include="Snippets\SnippetContainerElement.cs" /> + <Compile Include="Snippets\SnippetElement.cs" /> + <Compile Include="Snippets\InsertionContext.cs" /> + <Compile Include="Snippets\SnippetReplaceableTextElement.cs" /> + <Compile Include="Snippets\SnippetSelectionElement.cs" /> + <Compile Include="Snippets\SnippetTextElement.cs" /> + <Compile Include="TextEditor.cs" /> + <Compile Include="TextEditorAutomationPeer.cs" /> + <Compile Include="TextEditorComponent.cs"> + </Compile> + <Compile Include="Properties\AssemblyInfo.cs" /> + <Compile Include="Document\DocumentChangeEventArgs.cs" /> + <Compile Include="Document\GapTextBuffer.cs"> + <DependentUpon>TextDocument.cs</DependentUpon> + </Compile> + <Compile Include="Document\LineManager.cs"> + <DependentUpon>TextDocument.cs</DependentUpon> + </Compile> + <Compile Include="Document\DocumentLine.cs" /> + <Compile Include="Document\DocumentLineTree.cs"> + <DependentUpon>DocumentLine.cs</DependentUpon> + </Compile> + <Compile Include="Document\TextDocument.cs" /> + <Compile Include="TextEditorOptions.cs" /> + <Compile Include="TextEditorWeakEventManager.cs"> + <DependentUpon>TextEditor.cs</DependentUpon> + </Compile> + <Compile Include="TextViewPosition.cs" /> + <Compile Include="Utils\Boxes.cs" /> + <Compile Include="Utils\BusyManager.cs"> + <DependentUpon>ObserveAddRemoveCollection.cs</DependentUpon> + </Compile> + <Compile Include="Utils\CharRope.cs" /> + <Compile Include="Utils\CompressingTreeList.cs" /> + <Compile Include="Utils\Constants.cs" /> + <Compile Include="Utils\DelayedEvents.cs" /> + <Compile Include="Utils\CallbackOnDispose.cs" /> + <Compile Include="Utils\Deque.cs" /> + <Compile Include="Utils\Empty.cs" /> + <Compile Include="Utils\ExtensionMethods.cs" /> + <Compile Include="Utils\FileReader.cs" /> + <Compile Include="Utils\ImmutableStack.cs" /> + <Compile Include="Utils\NullSafeCollection.cs" /> + <Compile Include="Utils\ObserveAddRemoveCollection.cs" /> + <Compile Include="Utils\PropertyChangedWeakEventManager.cs" /> + <Compile Include="Utils\Rope.cs" /> + <Compile Include="Utils\RopeNode.cs" /> + <Compile Include="Utils\RopeTextReader.cs" /> + <Compile Include="Utils\StringSegment.cs" /> + <Compile Include="Utils\TextFormatterFactory.cs" /> + <Compile Include="Utils\WeakEventManagerBase.cs" /> + <Compile Include="Utils\PixelSnapHelpers.cs" /> + <Compile Include="Utils\ThrowUtil.cs" /> + <Compile Include="Utils\Win32.cs" /> + <CodeAnalysisDictionary Include="Properties\CodeAnalysisDictionary.xml" /> + <Compile Include="XamlEditor.cs" /> + <Compile Include="Xml\AbstractAXmlVisitor.cs" /> + <Compile Include="Xml\AXmlAttribute.cs" /> + <Compile Include="Xml\AXmlAttributeCollection.cs" /> + <Compile Include="Xml\AXmlContainer.cs" /> + <Compile Include="Xml\AXmlDocument.cs" /> + <Compile Include="Xml\AXmlElement.cs" /> + <Compile Include="Xml\AXmlObject.cs" /> + <Compile Include="Xml\AXmlObjectCollection.cs" /> + <Compile Include="Xml\AXmlObjectEventArgs.cs" /> + <Compile Include="Xml\AXmlParser.cs" /> + <Compile Include="Xml\AXmlTag.cs" /> + <Compile Include="Xml\AXmlText.cs" /> + <Compile Include="Xml\CanonicalPrintAXmlVisitor.cs" /> + <Compile Include="Xml\InternalException.cs" /> + <Compile Include="Xml\TrackedSegmentCollection.cs"> + <DependentUpon>AXmlParser.cs</DependentUpon> + </Compile> + <Compile Include="Xml\ExtensionMethods.cs" /> + <Compile Include="Xml\FilteredCollection.cs" /> + <Compile Include="Xml\IAXmlVisitor.cs" /> + <Compile Include="Xml\MergedCollection.cs" /> + <Compile Include="Xml\PrettyPrintAXmlVisitor.cs" /> + <Compile Include="Xml\SyntaxError.cs" /> + <Compile Include="Xml\TagMatchingHeuristics.cs"> + <DependentUpon>AXmlParser.cs</DependentUpon> + </Compile> + <Compile Include="Xml\TagReader.cs"> + <DependentUpon>AXmlParser.cs</DependentUpon> + </Compile> + <Compile Include="Xml\TextType.cs"> + <DependentUpon>AXmlText.cs</DependentUpon> + </Compile> + <Compile Include="Xml\TokenReader.cs"> + <DependentUpon>AXmlParser.cs</DependentUpon> + </Compile> + <EmbeddedResource Include="Highlighting\Resources\ASPX.xshd" /> + <EmbeddedResource Include="Highlighting\Resources\Boo.xshd" /> + <EmbeddedResource Include="Highlighting\Resources\Coco-Mode.xshd" /> + <EmbeddedResource Include="Highlighting\Resources\CPP-Mode.xshd" /> + <EmbeddedResource Include="Highlighting\Resources\HTML-Mode.xshd" /> + <EmbeddedResource Include="Highlighting\Resources\Java-Mode.xshd" /> + <EmbeddedResource Include="Highlighting\Resources\JavaScript-Mode.xshd" /> + <EmbeddedResource Include="Highlighting\Resources\Patch-Mode.xshd" /> + <EmbeddedResource Include="Highlighting\Resources\PHP-Mode.xshd" /> + <EmbeddedResource Include="Highlighting\Resources\Tex-Mode.xshd" /> + <EmbeddedResource Include="Highlighting\Resources\VBNET-Mode.xshd" /> + <EmbeddedResource Include="Highlighting\Resources\XML-Mode.xshd" /> + <EmbeddedResource Include="Highlighting\Resources\ModeV1.xsd" /> + <EmbeddedResource Include="Highlighting\Resources\ModeV2.xsd" /> + <EmbeddedResource Include="Highlighting\Resources\CSharp-Mode.xshd" /> + <EmbeddedResource Include="Highlighting\Resources\XmlDoc.xshd" /> + </ItemGroup> + <ItemGroup> + </ItemGroup> + <ItemGroup> + <EmbeddedResource Include="Highlighting\Resources\CSS-Mode.xshd" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="..\..\Tango.Core\Tango.Core.csproj"> + <Project>{a34ee0f0-649d-41c8-8489-b6f1cc6924ee}</Project> + <Name>Tango.Core</Name> + </ProjectReference> + <ProjectReference Include="..\Tango.Scripting.Core\Tango.Scripting.Core.csproj"> + <Project>{5812E1C6-ABAA-4066-94AC-971C27B4F46A}</Project> + <Name>Tango.Scripting.Core</Name> + </ProjectReference> + <ProjectReference Include="..\Tango.Scripting.Formatting\Tango.Scripting.Formatting.csproj"> + <Project>{8d8f06ed-7f75-4933-b0c5-829b0ff654d0}</Project> + <Name>Tango.Scripting.Formatting</Name> + </ProjectReference> + <ProjectReference Include="..\Tango.Scripting\Tango.Scripting.csproj"> + <Project>{1e938fd2-c669-4738-98c9-77f96ce4d451}</Project> + <Name>Tango.Scripting</Name> + </ProjectReference> + </ItemGroup> + <ItemGroup> + </ItemGroup> + <ItemGroup> + <EmbeddedResource Include="Highlighting\Resources\PowerShell.xshd" /> + </ItemGroup> + <ItemGroup> + <EmbeddedResource Include="Highlighting\Resources\MarkDown-Mode.xshd" /> + </ItemGroup> + <ItemGroup> + <None Include="app.config" /> + <None Include="packages.config" /> + </ItemGroup> + <ItemGroup> + </ItemGroup> + <ItemGroup> + </ItemGroup> + <ItemGroup> + </ItemGroup> + <ItemGroup> + </ItemGroup> + <ItemGroup> + </ItemGroup> + <ItemGroup> + </ItemGroup> + <ItemGroup> + </ItemGroup> + <ItemGroup> + </ItemGroup> + <ItemGroup> + <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> + </ItemGroup> + <ItemGroup> + </ItemGroup> + <ProjectExtensions> + <VisualStudio> + <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> + <ItemGroup> + <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\packages\FontAwesome.WPF.4.7.0.9\lib\net40\FontAwesome.WPF.dll" /> + <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\packages\Microsoft.CodeAnalysis.CSharp.2.4.0\lib\netstandard1.3\Microsoft.CodeAnalysis.CSharp.dll" /> + <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\packages\Microsoft.CodeAnalysis.Common.2.4.0\lib\netstandard1.3\Microsoft.CodeAnalysis.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\mscorlib.dll" /> + <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\PresentationCore.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\PresentationFramework.dll" /> + <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\packages\System.AppContext.4.3.0\lib\net46\System.AppContext.dll" /> + <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\packages\System.Collections.Immutable.1.3.1\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\System.ComponentModel.Composition.dll" /> + <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\packages\System.Console.4.3.0\lib\net46\System.Console.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\System.Core.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\System.Data.DataSetExtensions.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\System.Data.dll" /> + <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\packages\System.Diagnostics.FileVersionInfo.4.3.0\lib\net46\System.Diagnostics.FileVersionInfo.dll" /> + <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\packages\System.Diagnostics.StackTrace.4.3.0\lib\net46\System.Diagnostics.StackTrace.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\System.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\System.Drawing.dll" /> + <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\packages\System.IO.Compression.4.3.0\lib\net46\System.IO.Compression.dll" /> + <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\packages\System.IO.FileSystem.4.3.0\lib\net46\System.IO.FileSystem.dll" /> + <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\packages\System.IO.FileSystem.Primitives.4.3.0\lib\net46\System.IO.FileSystem.Primitives.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\System.Numerics.dll" /> + <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\packages\System.Reflection.Metadata.1.4.2\lib\portable-net45+win8\System.Reflection.Metadata.dll" /> + <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\packages\System.Security.Cryptography.Algorithms.4.3.0\lib\net461\System.Security.Cryptography.Algorithms.dll" /> + <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\packages\System.Security.Cryptography.Encoding.4.3.0\lib\net46\System.Security.Cryptography.Encoding.dll" /> + <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\packages\System.Security.Cryptography.Primitives.4.3.0\lib\net46\System.Security.Cryptography.Primitives.dll" /> + <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\packages\System.Security.Cryptography.X509Certificates.4.3.0\lib\net461\System.Security.Cryptography.X509Certificates.dll" /> + <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\packages\System.Text.Encoding.CodePages.4.3.0\lib\net46\System.Text.Encoding.CodePages.dll" /> + <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\packages\System.Threading.Thread.4.3.0\lib\net46\System.Threading.Thread.dll" /> + <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\packages\System.ValueTuple.4.3.0\lib\netstandard1.0\System.ValueTuple.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\System.Windows.Forms.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\System.Xaml.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\System.Xml.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\System.Xml.Linq.dll" /> + <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\packages\System.Xml.ReaderWriter.4.3.0\lib\net46\System.Xml.ReaderWriter.dll" /> + <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\packages\System.Xml.XmlDocument.4.3.0\lib\net46\System.Xml.XmlDocument.dll" /> + <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\packages\System.Xml.XPath.4.3.0\lib\net46\System.Xml.XPath.dll" /> + <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\packages\System.Xml.XPath.XDocument.4.3.0\lib\net46\System.Xml.XPath.XDocument.dll" /> + <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\Build\Core\Debug\Tango.Core.dll" /> + <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\Scripting\Tango.Scripting.Core\bin\Debug\Tango.Scripting.Core.dll" /> + <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\Build\Scripting\Debug\Tango.Scripting.dll" /> + <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\Scripting\Tango.Scripting.Formatting\bin\Debug\Tango.Scripting.Formatting.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\UIAutomationProvider.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\UIAutomationTypes.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\WindowsBase.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Collections.Concurrent.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Collections.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.ComponentModel.Annotations.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.ComponentModel.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.ComponentModel.EventBasedAsync.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Diagnostics.Contracts.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Diagnostics.Debug.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Diagnostics.Tools.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Diagnostics.Tracing.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Dynamic.Runtime.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Globalization.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.IO.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Linq.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Linq.Expressions.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Linq.Parallel.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Linq.Queryable.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Net.NetworkInformation.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Net.Primitives.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Net.Requests.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Net.WebHeaderCollection.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.ObjectModel.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Reflection.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Reflection.Emit.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Reflection.Emit.ILGeneration.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Reflection.Emit.Lightweight.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Reflection.Extensions.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Reflection.Primitives.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Resources.ResourceManager.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Runtime.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Runtime.Extensions.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Runtime.Handles.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Runtime.InteropServices.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Runtime.InteropServices.WindowsRuntime.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Runtime.Numerics.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Runtime.Serialization.Json.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Runtime.Serialization.Primitives.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Runtime.Serialization.Xml.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Security.Principal.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.ServiceModel.Duplex.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.ServiceModel.Http.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.ServiceModel.NetTcp.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.ServiceModel.Primitives.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.ServiceModel.Security.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Text.Encoding.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Text.Encoding.Extensions.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Text.RegularExpressions.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Threading.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Threading.Tasks.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Threading.Tasks.Parallel.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Threading.Timer.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Xml.XDocument.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Xml.XmlSerializer.dll" /> + </ItemGroup> + <ItemGroup> + <Compile Include="C:\DATA\Development\Tango\Software\Visual_Studio\Scripting\Tango.Scripting.Editors\obj\Debug\GeneratedInternalTypeHelper.g.cs" /> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/TextEditor.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/TextEditor.cs index d2fc9e02b..cd9977520 100644 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/TextEditor.cs +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/TextEditor.cs @@ -3,6 +3,7 @@ using System; using System.ComponentModel; +using System.Diagnostics; using System.IO; using System.Linq; using System.Text; @@ -24,1121 +25,1229 @@ using Tango.Scripting.Editors.Utils; namespace Tango.Scripting.Editors { - /// <summary> - /// The text editor control. - /// Contains a scrollable TextArea. - /// </summary> - [Localizability(LocalizationCategory.Text), ContentProperty("Text")] - public class TextEditor : Control, ITextEditorComponent, IServiceProvider, IWeakEventListener - { - #region Constructors - static TextEditor() - { - DefaultStyleKeyProperty.OverrideMetadata(typeof(TextEditor), - new FrameworkPropertyMetadata(typeof(TextEditor))); - FocusableProperty.OverrideMetadata(typeof(TextEditor), - new FrameworkPropertyMetadata(Boxes.True)); - } - - /// <summary> - /// Creates a new TextEditor instance. - /// </summary> - public TextEditor() : this(new TextArea()) - { - } - - /// <summary> - /// Creates a new TextEditor instance. - /// </summary> - protected TextEditor(TextArea textArea) - { - if (textArea == null) - throw new ArgumentNullException("textArea"); - this.textArea = textArea; - - textArea.TextView.Services.AddService(typeof(TextEditor), this); - - SetCurrentValue(OptionsProperty, textArea.Options); - SetCurrentValue(DocumentProperty, new TextDocument()); - } - - #endregion - - /// <inheritdoc/> - protected override System.Windows.Automation.Peers.AutomationPeer OnCreateAutomationPeer() - { - return new TextEditorAutomationPeer(this); - } - - /// Forward focus to TextArea. - /// <inheritdoc/> - protected override void OnGotKeyboardFocus(KeyboardFocusChangedEventArgs e) - { - base.OnGotKeyboardFocus(e); - if (e.NewFocus == this) { - Keyboard.Focus(this.TextArea); - e.Handled = true; - } - } - - #region Document property - /// <summary> - /// Document property. - /// </summary> - public static readonly DependencyProperty DocumentProperty - = TextView.DocumentProperty.AddOwner( - typeof(TextEditor), new FrameworkPropertyMetadata(OnDocumentChanged)); - - /// <summary> - /// Gets/Sets the document displayed by the text editor. - /// This is a dependency property. - /// </summary> - public TextDocument Document { - get { return (TextDocument)GetValue(DocumentProperty); } - set { SetValue(DocumentProperty, value); } - } - - /// <summary> - /// Occurs when the document property has changed. - /// </summary> - public event EventHandler DocumentChanged; - - /// <summary> - /// Raises the <see cref="DocumentChanged"/> event. - /// </summary> - protected virtual void OnDocumentChanged(EventArgs e) - { - if (DocumentChanged != null) { - DocumentChanged(this, e); - } - } - - static void OnDocumentChanged(DependencyObject dp, DependencyPropertyChangedEventArgs e) - { - ((TextEditor)dp).OnDocumentChanged((TextDocument)e.OldValue, (TextDocument)e.NewValue); - } - - void OnDocumentChanged(TextDocument oldValue, TextDocument newValue) - { - if (oldValue != null) { - TextDocumentWeakEventManager.TextChanged.RemoveListener(oldValue, this); - PropertyChangedEventManager.RemoveListener(oldValue.UndoStack, this, "IsOriginalFile"); - } - textArea.Document = newValue; - if (newValue != null) { - TextDocumentWeakEventManager.TextChanged.AddListener(newValue, this); - PropertyChangedEventManager.AddListener(newValue.UndoStack, this, "IsOriginalFile"); - } - OnDocumentChanged(EventArgs.Empty); - OnTextChanged(EventArgs.Empty); - } - #endregion - - #region Options property - /// <summary> - /// Options property. - /// </summary> - public static readonly DependencyProperty OptionsProperty - = TextView.OptionsProperty.AddOwner(typeof(TextEditor), new FrameworkPropertyMetadata(OnOptionsChanged)); - - /// <summary> - /// Gets/Sets the options currently used by the text editor. - /// </summary> - public TextEditorOptions Options { - get { return (TextEditorOptions)GetValue(OptionsProperty); } - set { SetValue(OptionsProperty, value); } - } - - /// <summary> - /// Occurs when a text editor option has changed. - /// </summary> - public event PropertyChangedEventHandler OptionChanged; - - /// <summary> - /// Raises the <see cref="OptionChanged"/> event. - /// </summary> - protected virtual void OnOptionChanged(PropertyChangedEventArgs e) - { - if (OptionChanged != null) { - OptionChanged(this, e); - } - } - - static void OnOptionsChanged(DependencyObject dp, DependencyPropertyChangedEventArgs e) - { - ((TextEditor)dp).OnOptionsChanged((TextEditorOptions)e.OldValue, (TextEditorOptions)e.NewValue); - } - - void OnOptionsChanged(TextEditorOptions oldValue, TextEditorOptions newValue) - { - if (oldValue != null) { - PropertyChangedWeakEventManager.RemoveListener(oldValue, this); - } - textArea.Options = newValue; - if (newValue != null) { - PropertyChangedWeakEventManager.AddListener(newValue, this); - } - OnOptionChanged(new PropertyChangedEventArgs(null)); - } - - /// <inheritdoc cref="IWeakEventListener.ReceiveWeakEvent"/> - protected virtual bool ReceiveWeakEvent(Type managerType, object sender, EventArgs e) - { - if (managerType == typeof(PropertyChangedWeakEventManager)) { - OnOptionChanged((PropertyChangedEventArgs)e); - return true; - } else if (managerType == typeof(TextDocumentWeakEventManager.TextChanged)) { - OnTextChanged(e); - return true; - } else if (managerType == typeof(PropertyChangedEventManager)) { - return HandleIsOriginalChanged((PropertyChangedEventArgs)e); - } - return false; - } - - bool IWeakEventListener.ReceiveWeakEvent(Type managerType, object sender, EventArgs e) - { - return ReceiveWeakEvent(managerType, sender, e); - } - #endregion - - #region Text property - /// <summary> - /// Gets/Sets the text of the current document. - /// </summary> - [Localizability(LocalizationCategory.Text), DefaultValue("")] - public string Text { - get { - TextDocument document = this.Document; - return document != null ? document.Text : string.Empty; - } - set { - TextDocument document = GetDocument(); - document.Text = value ?? string.Empty; - // after replacing the full text, the caret is positioned at the end of the document - // - reset it to the beginning. - this.CaretOffset = 0; - document.UndoStack.ClearAll(); - } - } - - TextDocument GetDocument() - { - TextDocument document = this.Document; - if (document == null) - throw ThrowUtil.NoDocumentAssigned(); - return document; - } - - /// <summary> - /// Occurs when the Text property changes. - /// </summary> - public event EventHandler TextChanged; - - /// <summary> - /// Raises the <see cref="TextChanged"/> event. - /// </summary> - protected virtual void OnTextChanged(EventArgs e) - { - if (TextChanged != null) { - TextChanged(this, e); - } - } - #endregion - - #region TextArea / ScrollViewer properties - readonly TextArea textArea; - ScrollViewer scrollViewer; - - /// <summary> - /// Is called after the template was applied. - /// </summary> - public override void OnApplyTemplate() - { - base.OnApplyTemplate(); - scrollViewer = (ScrollViewer)Template.FindName("PART_ScrollViewer", this); - } - - /// <summary> - /// Gets the text area. - /// </summary> - public TextArea TextArea { - get { - return textArea; - } - } - - /// <summary> - /// Gets the scroll viewer used by the text editor. - /// This property can return null if the template has not been applied / does not contain a scroll viewer. - /// </summary> - internal ScrollViewer ScrollViewer { - get { return scrollViewer; } - } - - bool CanExecute(RoutedUICommand command) - { - TextArea textArea = this.TextArea; - if (textArea == null) - return false; - else - return command.CanExecute(null, textArea); - } - - void Execute(RoutedUICommand command) - { - TextArea textArea = this.TextArea; - if (textArea != null) - command.Execute(null, textArea); - } - #endregion - - #region Syntax highlighting - /// <summary> - /// The <see cref="SyntaxHighlighting"/> property. - /// </summary> - public static readonly DependencyProperty SyntaxHighlightingProperty = - DependencyProperty.Register("SyntaxHighlighting", typeof(IHighlightingDefinition), typeof(TextEditor), - new FrameworkPropertyMetadata(OnSyntaxHighlightingChanged)); - - - /// <summary> - /// Gets/sets the syntax highlighting definition used to colorize the text. - /// </summary> - public IHighlightingDefinition SyntaxHighlighting { - get { return (IHighlightingDefinition)GetValue(SyntaxHighlightingProperty); } - set { SetValue(SyntaxHighlightingProperty, value); } - } - - IVisualLineTransformer colorizer; - - static void OnSyntaxHighlightingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - ((TextEditor)d).OnSyntaxHighlightingChanged(e.NewValue as IHighlightingDefinition); - } - - void OnSyntaxHighlightingChanged(IHighlightingDefinition newValue) - { - if (colorizer != null) { - this.TextArea.TextView.LineTransformers.Remove(colorizer); - colorizer = null; - } - if (newValue != null) { - colorizer = CreateColorizer(newValue); - this.TextArea.TextView.LineTransformers.Insert(0, colorizer); - } - } - - /// <summary> - /// Creates the highlighting colorizer for the specified highlighting definition. - /// Allows derived classes to provide custom colorizer implementations for special highlighting definitions. - /// </summary> - /// <returns></returns> - protected virtual IVisualLineTransformer CreateColorizer(IHighlightingDefinition highlightingDefinition) - { - if (highlightingDefinition == null) - throw new ArgumentNullException("highlightingDefinition"); - return new HighlightingColorizer(highlightingDefinition.MainRuleSet); - } - #endregion - - #region WordWrap - /// <summary> - /// Word wrap dependency property. - /// </summary> - public static readonly DependencyProperty WordWrapProperty = - DependencyProperty.Register("WordWrap", typeof(bool), typeof(TextEditor), - new FrameworkPropertyMetadata(Boxes.False)); - - /// <summary> - /// Specifies whether the text editor uses word wrapping. - /// </summary> - /// <remarks> - /// Setting WordWrap=true has the same effect as setting HorizontalScrollBarVisibility=Disabled and will override the - /// HorizontalScrollBarVisibility setting. - /// </remarks> - public bool WordWrap { - get { return (bool)GetValue(WordWrapProperty); } - set { SetValue(WordWrapProperty, Boxes.Box(value)); } - } - #endregion - - #region IsReadOnly - /// <summary> - /// IsReadOnly dependency property. - /// </summary> - public static readonly DependencyProperty IsReadOnlyProperty = - DependencyProperty.Register("IsReadOnly", typeof(bool), typeof(TextEditor), - new FrameworkPropertyMetadata(Boxes.False, OnIsReadOnlyChanged)); - - /// <summary> - /// Specifies whether the user can change the text editor content. - /// Setting this property will replace the - /// <see cref="Editing.TextArea.ReadOnlySectionProvider">TextArea.ReadOnlySectionProvider</see>. - /// </summary> - public bool IsReadOnly { - get { return (bool)GetValue(IsReadOnlyProperty); } - set { SetValue(IsReadOnlyProperty, Boxes.Box(value)); } - } - - static void OnIsReadOnlyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - TextEditor editor = d as TextEditor; - if (editor != null) { - if ((bool)e.NewValue) - editor.TextArea.ReadOnlySectionProvider = ReadOnlyDocument.Instance; - else - editor.TextArea.ReadOnlySectionProvider = NoReadOnlySections.Instance; - - TextEditorAutomationPeer peer = TextEditorAutomationPeer.FromElement(editor) as TextEditorAutomationPeer; - if (peer != null) { - peer.RaiseIsReadOnlyChanged((bool)e.OldValue, (bool)e.NewValue); - } - } - } - #endregion - - #region IsModified - /// <summary> - /// Dependency property for <see cref="IsModified"/> - /// </summary> - public static readonly DependencyProperty IsModifiedProperty = - DependencyProperty.Register("IsModified", typeof(bool), typeof(TextEditor), - new FrameworkPropertyMetadata(Boxes.False, OnIsModifiedChanged)); - - /// <summary> - /// Gets/Sets the 'modified' flag. - /// </summary> - public bool IsModified { - get { return (bool)GetValue(IsModifiedProperty); } - set { SetValue(IsModifiedProperty, Boxes.Box(value)); } - } - - static void OnIsModifiedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - TextEditor editor = d as TextEditor; - if (editor != null) { - TextDocument document = editor.Document; - if (document != null) { - UndoStack undoStack = document.UndoStack; - if ((bool)e.NewValue) { - if (undoStack.IsOriginalFile) - undoStack.DiscardOriginalFileMarker(); - } else { - undoStack.MarkAsOriginalFile(); - } - } - } - } - - bool HandleIsOriginalChanged(PropertyChangedEventArgs e) - { - if (e.PropertyName == "IsOriginalFile") { - TextDocument document = this.Document; - if (document != null) { - SetCurrentValue(IsModifiedProperty, Boxes.Box(!document.UndoStack.IsOriginalFile)); - } - return true; - } else { - return false; - } - } - #endregion - - #region ShowLineNumbers - /// <summary> - /// ShowLineNumbers dependency property. - /// </summary> - public static readonly DependencyProperty ShowLineNumbersProperty = - DependencyProperty.Register("ShowLineNumbers", typeof(bool), typeof(TextEditor), - new FrameworkPropertyMetadata(Boxes.False, OnShowLineNumbersChanged)); - - /// <summary> - /// Specifies whether line numbers are shown on the left to the text view. - /// </summary> - public bool ShowLineNumbers { - get { return (bool)GetValue(ShowLineNumbersProperty); } - set { SetValue(ShowLineNumbersProperty, Boxes.Box(value)); } - } - - static void OnShowLineNumbersChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - TextEditor editor = (TextEditor)d; - var leftMargins = editor.TextArea.LeftMargins; - if ((bool)e.NewValue) { - LineNumberMargin lineNumbers = new LineNumberMargin(); - Line line = (Line)DottedLineMargin.Create(); - leftMargins.Insert(0, lineNumbers); - leftMargins.Insert(1, line); - var lineNumbersForeground = new Binding("LineNumbersForeground") { Source = editor }; - line.SetBinding(Line.StrokeProperty, lineNumbersForeground); - lineNumbers.SetBinding(Control.ForegroundProperty, lineNumbersForeground); - } else { - for (int i = 0; i < leftMargins.Count; i++) { - if (leftMargins[i] is LineNumberMargin) { - leftMargins.RemoveAt(i); - if (i < leftMargins.Count && DottedLineMargin.IsDottedLineMargin(leftMargins[i])) { - leftMargins.RemoveAt(i); - } - break; - } - } - } - } - #endregion - - #region LineNumbersForeground - /// <summary> - /// LineNumbersForeground dependency property. - /// </summary> - public static readonly DependencyProperty LineNumbersForegroundProperty = - DependencyProperty.Register("LineNumbersForeground", typeof(Brush), typeof(TextEditor), - new FrameworkPropertyMetadata(Brushes.Gray, OnLineNumbersForegroundChanged)); - - /// <summary> - /// Gets/sets the Brush used for displaying the foreground color of line numbers. - /// </summary> - public Brush LineNumbersForeground { - get { return (Brush)GetValue(LineNumbersForegroundProperty); } - set { SetValue(LineNumbersForegroundProperty, value); } - } - - static void OnLineNumbersForegroundChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - TextEditor editor = (TextEditor)d; - var lineNumberMargin = editor.TextArea.LeftMargins.FirstOrDefault(margin => margin is LineNumberMargin) as LineNumberMargin;; - - if (lineNumberMargin != null) { - lineNumberMargin.SetValue(Control.ForegroundProperty, e.NewValue); - } - } - #endregion - - #region TextBoxBase-like methods - /// <summary> - /// Appends text to the end of the document. - /// </summary> - public void AppendText(string textData) - { - var document = GetDocument(); - document.Insert(document.TextLength, textData); - } - - /// <summary> - /// Begins a group of document changes. - /// </summary> - public void BeginChange() - { - GetDocument().BeginUpdate(); - } - - /// <summary> - /// Copies the current selection to the clipboard. - /// </summary> - public void Copy() - { - Execute(ApplicationCommands.Copy); - } - - /// <summary> - /// Removes the current selection and copies it to the clipboard. - /// </summary> - public void Cut() - { - Execute(ApplicationCommands.Cut); - } - - /// <summary> - /// Begins a group of document changes and returns an object that ends the group of document - /// changes when it is disposed. - /// </summary> - public IDisposable DeclareChangeBlock() - { - return GetDocument().RunUpdate(); - } - - /// <summary> - /// Ends the current group of document changes. - /// </summary> - public void EndChange() - { - GetDocument().EndUpdate(); - } - - /// <summary> - /// Scrolls one line down. - /// </summary> - public void LineDown() - { - if (scrollViewer != null) - scrollViewer.LineDown(); - } - - /// <summary> - /// Scrolls to the left. - /// </summary> - public void LineLeft() - { - if (scrollViewer != null) - scrollViewer.LineLeft(); - } - - /// <summary> - /// Scrolls to the right. - /// </summary> - public void LineRight() - { - if (scrollViewer != null) - scrollViewer.LineRight(); - } - - /// <summary> - /// Scrolls one line up. - /// </summary> - public void LineUp() - { - if (scrollViewer != null) - scrollViewer.LineUp(); - } - - /// <summary> - /// Scrolls one page down. - /// </summary> - public void PageDown() - { - if (scrollViewer != null) - scrollViewer.PageDown(); - } - - /// <summary> - /// Scrolls one page up. - /// </summary> - public void PageUp() - { - if (scrollViewer != null) - scrollViewer.PageUp(); - } - - /// <summary> - /// Scrolls one page left. - /// </summary> - public void PageLeft() - { - if (scrollViewer != null) - scrollViewer.PageLeft(); - } - - /// <summary> - /// Scrolls one page right. - /// </summary> - public void PageRight() - { - if (scrollViewer != null) - scrollViewer.PageRight(); - } - - /// <summary> - /// Pastes the clipboard content. - /// </summary> - public void Paste() - { - Execute(ApplicationCommands.Paste); - } - - /// <summary> - /// Redoes the most recent undone command. - /// </summary> - /// <returns>True is the redo operation was successful, false is the redo stack is empty.</returns> - public bool Redo() - { - if (CanExecute(ApplicationCommands.Redo)) { - Execute(ApplicationCommands.Redo); - return true; - } - return false; - } - - /// <summary> - /// Scrolls to the end of the document. - /// </summary> - public void ScrollToEnd() - { - ApplyTemplate(); // ensure scrollViewer is created - if (scrollViewer != null) - scrollViewer.ScrollToEnd(); - } - - /// <summary> - /// Scrolls to the start of the document. - /// </summary> - public void ScrollToHome() - { - ApplyTemplate(); // ensure scrollViewer is created - if (scrollViewer != null) - scrollViewer.ScrollToHome(); - } - - /// <summary> - /// Scrolls to the specified position in the document. - /// </summary> - public void ScrollToHorizontalOffset(double offset) - { - ApplyTemplate(); // ensure scrollViewer is created - if (scrollViewer != null) - scrollViewer.ScrollToHorizontalOffset(offset); - } - - /// <summary> - /// Scrolls to the specified position in the document. - /// </summary> - public void ScrollToVerticalOffset(double offset) - { - ApplyTemplate(); // ensure scrollViewer is created - if (scrollViewer != null) - scrollViewer.ScrollToVerticalOffset(offset); - } - - /// <summary> - /// Selects the entire text. - /// </summary> - public void SelectAll() - { - Execute(ApplicationCommands.SelectAll); - } - - /// <summary> - /// Undoes the most recent command. - /// </summary> - /// <returns>True is the undo operation was successful, false is the undo stack is empty.</returns> - public bool Undo() - { - if (CanExecute(ApplicationCommands.Undo)) { - Execute(ApplicationCommands.Undo); - return true; - } - return false; - } - - /// <summary> - /// Gets if the most recent undone command can be redone. - /// </summary> - public bool CanRedo { - get { return CanExecute(ApplicationCommands.Redo); } - } - - /// <summary> - /// Gets if the most recent command can be undone. - /// </summary> - public bool CanUndo { - get { return CanExecute(ApplicationCommands.Undo); } - } - - /// <summary> - /// Gets the vertical size of the document. - /// </summary> - public double ExtentHeight { - get { - return scrollViewer != null ? scrollViewer.ExtentHeight : 0; - } - } - - /// <summary> - /// Gets the horizontal size of the current document region. - /// </summary> - public double ExtentWidth { - get { - return scrollViewer != null ? scrollViewer.ExtentWidth : 0; - } - } - - /// <summary> - /// Gets the horizontal size of the viewport. - /// </summary> - public double ViewportHeight { - get { - return scrollViewer != null ? scrollViewer.ViewportHeight : 0; - } - } - - /// <summary> - /// Gets the horizontal size of the viewport. - /// </summary> - public double ViewportWidth { - get { - return scrollViewer != null ? scrollViewer.ViewportWidth : 0; - } - } - - /// <summary> - /// Gets the vertical scroll position. - /// </summary> - public double VerticalOffset { - get { - return scrollViewer != null ? scrollViewer.VerticalOffset : 0; - } - } - - /// <summary> - /// Gets the horizontal scroll position. - /// </summary> - public double HorizontalOffset { - get { - return scrollViewer != null ? scrollViewer.HorizontalOffset : 0; - } - } - #endregion - - #region TextBox methods - /// <summary> - /// Gets/Sets the selected text. - /// </summary> - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public string SelectedText { - get { - TextArea textArea = this.TextArea; - // We'll get the text from the whole surrounding segment. - // This is done to ensure that SelectedText.Length == SelectionLength. - if (textArea != null && textArea.Document != null && !textArea.Selection.IsEmpty) - return textArea.Document.GetText(textArea.Selection.SurroundingSegment); - else - return string.Empty; - } - set { - if (value == null) - throw new ArgumentNullException("value"); - TextArea textArea = this.TextArea; - if (textArea != null && textArea.Document != null) { - int offset = this.SelectionStart; - int length = this.SelectionLength; - textArea.Document.Replace(offset, length, value); - // keep inserted text selected - textArea.Selection = SimpleSelection.Create(textArea, offset, offset + value.Length); - } - } - } - - /// <summary> - /// Gets/sets the caret position. - /// </summary> - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public int CaretOffset { - get { - TextArea textArea = this.TextArea; - if (textArea != null) - return textArea.Caret.Offset; - else - return 0; - } - set { - TextArea textArea = this.TextArea; - if (textArea != null) - textArea.Caret.Offset = value; - } - } - - /// <summary> - /// Gets/sets the start position of the selection. - /// </summary> - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public int SelectionStart { - get { - TextArea textArea = this.TextArea; - if (textArea != null) { - if (textArea.Selection.IsEmpty) - return textArea.Caret.Offset; - else - return textArea.Selection.SurroundingSegment.Offset; - } else { - return 0; - } - } - set { - Select(value, SelectionLength); - } - } - - /// <summary> - /// Gets/sets the length of the selection. - /// </summary> - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public int SelectionLength { - get { - TextArea textArea = this.TextArea; - if (textArea != null && !textArea.Selection.IsEmpty) - return textArea.Selection.SurroundingSegment.Length; - else - return 0; - } - set { - Select(SelectionStart, value); - } - } - - /// <summary> - /// Selects the specified text section. - /// </summary> - public void Select(int start, int length) - { - int documentLength = Document != null ? Document.TextLength : 0; - if (start < 0 || start > documentLength) - throw new ArgumentOutOfRangeException("start", start, "Value must be between 0 and " + documentLength); - if (length < 0 || start + length > documentLength) - throw new ArgumentOutOfRangeException("length", length, "Value must be between 0 and " + (documentLength - length)); - textArea.Selection = SimpleSelection.Create(textArea, start, start + length); - textArea.Caret.Offset = start + length; - } - - /// <summary> - /// Gets the number of lines in the document. - /// </summary> - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public int LineCount { - get { - TextDocument document = this.Document; - if (document != null) - return document.LineCount; - else - return 1; - } - } - - /// <summary> - /// Clears the text. - /// </summary> - public void Clear() - { - this.Text = string.Empty; - } - #endregion - - #region Loading from stream - /// <summary> - /// Loads the text from the stream, auto-detecting the encoding. - /// </summary> - /// <remarks> - /// This method sets <see cref="IsModified"/> to false. - /// </remarks> - public void Load(Stream stream) - { - using (StreamReader reader = FileReader.OpenStream(stream, this.Encoding ?? Encoding.UTF8)) { - this.Text = reader.ReadToEnd(); - this.Encoding = reader.CurrentEncoding; // assign encoding after ReadToEnd() so that the StreamReader can autodetect the encoding - } - this.IsModified = false; - } - - /// <summary> - /// Loads the text from the stream, auto-detecting the encoding. - /// </summary> - public void Load(string fileName) - { - if (fileName == null) - throw new ArgumentNullException("fileName"); - using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read)) { - Load(fs); - } - } - - /// <summary> - /// Gets/sets the encoding used when the file is saved. - /// </summary> - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public Encoding Encoding { get; set; } - - /// <summary> - /// Saves the text to the stream. - /// </summary> - /// <remarks> - /// This method sets <see cref="IsModified"/> to false. - /// </remarks> - public void Save(Stream stream) - { - if (stream == null) - throw new ArgumentNullException("stream"); - StreamWriter writer = new StreamWriter(stream, this.Encoding ?? Encoding.UTF8); - writer.Write(this.Text); - writer.Flush(); - // do not close the stream - this.IsModified = false; - } - - /// <summary> - /// Saves the text to the file. - /// </summary> - public void Save(string fileName) - { - if (fileName == null) - throw new ArgumentNullException("fileName"); - using (FileStream fs = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.None)) { - Save(fs); - } - } - #endregion - - #region MouseHover events - /// <summary> - /// The PreviewMouseHover event. - /// </summary> - public static readonly RoutedEvent PreviewMouseHoverEvent = - TextView.PreviewMouseHoverEvent.AddOwner(typeof(TextEditor)); - - /// <summary> - /// The MouseHover event. - /// </summary> - public static readonly RoutedEvent MouseHoverEvent = - TextView.MouseHoverEvent.AddOwner(typeof(TextEditor)); - - - /// <summary> - /// The PreviewMouseHoverStopped event. - /// </summary> - public static readonly RoutedEvent PreviewMouseHoverStoppedEvent = - TextView.PreviewMouseHoverStoppedEvent.AddOwner(typeof(TextEditor)); - - /// <summary> - /// The MouseHoverStopped event. - /// </summary> - public static readonly RoutedEvent MouseHoverStoppedEvent = - TextView.MouseHoverStoppedEvent.AddOwner(typeof(TextEditor)); - - - /// <summary> - /// Occurs when the mouse has hovered over a fixed location for some time. - /// </summary> - public event MouseEventHandler PreviewMouseHover { - add { AddHandler(PreviewMouseHoverEvent, value); } - remove { RemoveHandler(PreviewMouseHoverEvent, value); } - } - - /// <summary> - /// Occurs when the mouse has hovered over a fixed location for some time. - /// </summary> - public event MouseEventHandler MouseHover { - add { AddHandler(MouseHoverEvent, value); } - remove { RemoveHandler(MouseHoverEvent, value); } - } - - /// <summary> - /// Occurs when the mouse had previously hovered but now started moving again. - /// </summary> - public event MouseEventHandler PreviewMouseHoverStopped { - add { AddHandler(PreviewMouseHoverStoppedEvent, value); } - remove { RemoveHandler(PreviewMouseHoverStoppedEvent, value); } - } - - /// <summary> - /// Occurs when the mouse had previously hovered but now started moving again. - /// </summary> - public event MouseEventHandler MouseHoverStopped { - add { AddHandler(MouseHoverStoppedEvent, value); } - remove { RemoveHandler(MouseHoverStoppedEvent, value); } - } - #endregion - - #region ScrollBarVisibility - /// <summary> - /// Dependency property for <see cref="HorizontalScrollBarVisibility"/> - /// </summary> - public static readonly DependencyProperty HorizontalScrollBarVisibilityProperty = ScrollViewer.HorizontalScrollBarVisibilityProperty.AddOwner(typeof(TextEditor), new FrameworkPropertyMetadata(ScrollBarVisibility.Visible)); - - /// <summary> - /// Gets/Sets the horizontal scroll bar visibility. - /// </summary> - public ScrollBarVisibility HorizontalScrollBarVisibility { - get { return (ScrollBarVisibility)GetValue(HorizontalScrollBarVisibilityProperty); } - set { SetValue(HorizontalScrollBarVisibilityProperty, value); } - } - - /// <summary> - /// Dependency property for <see cref="VerticalScrollBarVisibility"/> - /// </summary> - public static readonly DependencyProperty VerticalScrollBarVisibilityProperty = ScrollViewer.VerticalScrollBarVisibilityProperty.AddOwner(typeof(TextEditor), new FrameworkPropertyMetadata(ScrollBarVisibility.Visible)); - - /// <summary> - /// Gets/Sets the vertical scroll bar visibility. - /// </summary> - public ScrollBarVisibility VerticalScrollBarVisibility { - get { return (ScrollBarVisibility)GetValue(VerticalScrollBarVisibilityProperty); } - set { SetValue(VerticalScrollBarVisibilityProperty, value); } - } - #endregion - - object IServiceProvider.GetService(Type serviceType) - { - return textArea.GetService(serviceType); - } - - /// <summary> - /// Gets the text view position from a point inside the editor. - /// </summary> - /// <param name="point">The position, relative to top left - /// corner of TextEditor control</param> - /// <returns>The text view position, or null if the point is outside the document.</returns> - public TextViewPosition? GetPositionFromPoint(Point point) - { - if (this.Document == null) - return null; - TextView textView = this.TextArea.TextView; - return textView.GetPosition(TranslatePoint(point, textView) + textView.ScrollOffset); - } - - /// <summary> - /// Scrolls to the specified line. - /// This method requires that the TextEditor was already assigned a size (WPF layout must have run prior). - /// </summary> - public void ScrollToLine(int line) - { - ScrollTo(line, -1); - } - - /// <summary> - /// Scrolls to the specified line/column. - /// This method requires that the TextEditor was already assigned a size (WPF layout must have run prior). - /// </summary> - public void ScrollTo(int line, int column) - { - const double MinimumScrollPercentage = 0.3; - - TextView textView = textArea.TextView; - TextDocument document = textView.Document; - if (scrollViewer != null && document != null) { - if (line < 1) - line = 1; - if (line > document.LineCount) - line = document.LineCount; - - IScrollInfo scrollInfo = textView; - if (!scrollInfo.CanHorizontallyScroll) { - // Word wrap is enabled. Ensure that we have up-to-date info about line height so that we scroll - // to the correct position. - // This avoids that the user has to repeat the ScrollTo() call several times when there are very long lines. - VisualLine vl = textView.GetOrConstructVisualLine(document.GetLineByNumber(line)); - double remainingHeight = scrollViewer.ViewportHeight / 2; - while (remainingHeight > 0) { - DocumentLine prevLine = vl.FirstDocumentLine.PreviousLine; - if (prevLine == null) - break; - vl = textView.GetOrConstructVisualLine(prevLine); - remainingHeight -= vl.Height; - } - } - - Point p = textArea.TextView.GetVisualPosition(new TextViewPosition(line, Math.Max(1, column)), VisualYPosition.LineMiddle); - double verticalPos = p.Y - scrollViewer.ViewportHeight / 2; - if (Math.Abs(verticalPos - scrollViewer.VerticalOffset) > MinimumScrollPercentage * scrollViewer.ViewportHeight) { - scrollViewer.ScrollToVerticalOffset(Math.Max(0, verticalPos)); - } - if (column > 0) { - if (p.X > scrollViewer.ViewportWidth - Caret.MinimumDistanceToViewBorder * 2) { - double horizontalPos = Math.Max(0, p.X - scrollViewer.ViewportWidth / 2); - if (Math.Abs(horizontalPos - scrollViewer.HorizontalOffset) > MinimumScrollPercentage * scrollViewer.ViewportWidth) { - scrollViewer.ScrollToHorizontalOffset(horizontalPos); - } - } else { - scrollViewer.ScrollToHorizontalOffset(0); - } - } - } - } - } + /// <summary> + /// The text editor control. + /// Contains a scrollable TextArea. + /// </summary> + [Localizability(LocalizationCategory.Text), ContentProperty("Text")] + public class TextEditor : Control, ITextEditorComponent, IServiceProvider, IWeakEventListener + { + #region Constructors + static TextEditor() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(TextEditor), + new FrameworkPropertyMetadata(typeof(TextEditor))); + FocusableProperty.OverrideMetadata(typeof(TextEditor), + new FrameworkPropertyMetadata(Boxes.True)); + } + + /// <summary> + /// Creates a new TextEditor instance. + /// </summary> + public TextEditor() : this(new TextArea()) + { + } + + /// <summary> + /// Creates a new TextEditor instance. + /// </summary> + protected TextEditor(TextArea textArea) + { + if (textArea == null) + throw new ArgumentNullException("textArea"); + this.textArea = textArea; + + textArea.TextView.Services.AddService(typeof(TextEditor), this); + + SetCurrentValue(OptionsProperty, textArea.Options); + SetCurrentValue(DocumentProperty, new TextDocument()); + } + + #endregion + + /// <inheritdoc/> + protected override System.Windows.Automation.Peers.AutomationPeer OnCreateAutomationPeer() + { + return new TextEditorAutomationPeer(this); + } + + /// Forward focus to TextArea. + /// <inheritdoc/> + protected override void OnGotKeyboardFocus(KeyboardFocusChangedEventArgs e) + { + base.OnGotKeyboardFocus(e); + if (e.NewFocus == this) + { + Keyboard.Focus(this.TextArea); + e.Handled = true; + } + } + + #region Document property + /// <summary> + /// Document property. + /// </summary> + public static readonly DependencyProperty DocumentProperty + = TextView.DocumentProperty.AddOwner( + typeof(TextEditor), new FrameworkPropertyMetadata(OnDocumentChanged)); + + /// <summary> + /// Gets/Sets the document displayed by the text editor. + /// This is a dependency property. + /// </summary> + public TextDocument Document + { + get { return (TextDocument)GetValue(DocumentProperty); } + set { SetValue(DocumentProperty, value); } + } + + /// <summary> + /// Occurs when the document property has changed. + /// </summary> + public event EventHandler DocumentChanged; + + /// <summary> + /// Raises the <see cref="DocumentChanged"/> event. + /// </summary> + protected virtual void OnDocumentChanged(EventArgs e) + { + if (DocumentChanged != null) + { + DocumentChanged(this, e); + } + } + + static void OnDocumentChanged(DependencyObject dp, DependencyPropertyChangedEventArgs e) + { + ((TextEditor)dp).OnDocumentChanged((TextDocument)e.OldValue, (TextDocument)e.NewValue); + } + + void OnDocumentChanged(TextDocument oldValue, TextDocument newValue) + { + if (oldValue != null) + { + TextDocumentWeakEventManager.TextChanged.RemoveListener(oldValue, this); + PropertyChangedEventManager.RemoveListener(oldValue.UndoStack, this, "IsOriginalFile"); + } + textArea.Document = newValue; + if (newValue != null) + { + TextDocumentWeakEventManager.TextChanged.AddListener(newValue, this); + PropertyChangedEventManager.AddListener(newValue.UndoStack, this, "IsOriginalFile"); + } + OnDocumentChanged(EventArgs.Empty); + OnTextChanged(EventArgs.Empty); + } + #endregion + + #region Options property + /// <summary> + /// Options property. + /// </summary> + public static readonly DependencyProperty OptionsProperty + = TextView.OptionsProperty.AddOwner(typeof(TextEditor), new FrameworkPropertyMetadata(OnOptionsChanged)); + + /// <summary> + /// Gets/Sets the options currently used by the text editor. + /// </summary> + public TextEditorOptions Options + { + get { return (TextEditorOptions)GetValue(OptionsProperty); } + set { SetValue(OptionsProperty, value); } + } + + /// <summary> + /// Occurs when a text editor option has changed. + /// </summary> + public event PropertyChangedEventHandler OptionChanged; + + /// <summary> + /// Raises the <see cref="OptionChanged"/> event. + /// </summary> + protected virtual void OnOptionChanged(PropertyChangedEventArgs e) + { + if (OptionChanged != null) + { + OptionChanged(this, e); + } + } + + static void OnOptionsChanged(DependencyObject dp, DependencyPropertyChangedEventArgs e) + { + ((TextEditor)dp).OnOptionsChanged((TextEditorOptions)e.OldValue, (TextEditorOptions)e.NewValue); + } + + void OnOptionsChanged(TextEditorOptions oldValue, TextEditorOptions newValue) + { + if (oldValue != null) + { + PropertyChangedWeakEventManager.RemoveListener(oldValue, this); + } + textArea.Options = newValue; + if (newValue != null) + { + PropertyChangedWeakEventManager.AddListener(newValue, this); + } + OnOptionChanged(new PropertyChangedEventArgs(null)); + } + + /// <inheritdoc cref="IWeakEventListener.ReceiveWeakEvent"/> + protected virtual bool ReceiveWeakEvent(Type managerType, object sender, EventArgs e) + { + if (managerType == typeof(PropertyChangedWeakEventManager)) + { + OnOptionChanged((PropertyChangedEventArgs)e); + return true; + } + else if (managerType == typeof(TextDocumentWeakEventManager.TextChanged)) + { + OnTextChanged(e); + return true; + } + else if (managerType == typeof(PropertyChangedEventManager)) + { + return HandleIsOriginalChanged((PropertyChangedEventArgs)e); + } + return false; + } + + bool IWeakEventListener.ReceiveWeakEvent(Type managerType, object sender, EventArgs e) + { + return ReceiveWeakEvent(managerType, sender, e); + } + #endregion + + #region Text property + /// <summary> + /// Gets/Sets the text of the current document. + /// </summary> + [Localizability(LocalizationCategory.Text), DefaultValue("")] + public string Text + { + get + { + TextDocument document = this.Document; + return document != null ? document.Text : string.Empty; + } + set + { + TextDocument document = GetDocument(); + document.Text = value ?? string.Empty; + // after replacing the full text, the caret is positioned at the end of the document + // - reset it to the beginning. + this.CaretOffset = 0; + document.UndoStack.ClearAll(); + } + } + + TextDocument GetDocument() + { + TextDocument document = this.Document; + if (document == null) + throw ThrowUtil.NoDocumentAssigned(); + return document; + } + + /// <summary> + /// Occurs when the Text property changes. + /// </summary> + public event EventHandler TextChanged; + + /// <summary> + /// Raises the <see cref="TextChanged"/> event. + /// </summary> + protected virtual void OnTextChanged(EventArgs e) + { + if (TextChanged != null) + { + TextChanged(this, e); + } + } + #endregion + + #region TextArea / ScrollViewer properties + readonly TextArea textArea; + ScrollViewer scrollViewer; + + /// <summary> + /// Is called after the template was applied. + /// </summary> + public override void OnApplyTemplate() + { + base.OnApplyTemplate(); + scrollViewer = (ScrollViewer)Template.FindName("PART_ScrollViewer", this); + } + + /// <summary> + /// Gets the text area. + /// </summary> + public TextArea TextArea + { + get + { + return textArea; + } + } + + /// <summary> + /// Gets the scroll viewer used by the text editor. + /// This property can return null if the template has not been applied / does not contain a scroll viewer. + /// </summary> + internal ScrollViewer ScrollViewer + { + get { return scrollViewer; } + } + + bool CanExecute(RoutedUICommand command) + { + TextArea textArea = this.TextArea; + if (textArea == null) + return false; + else + return command.CanExecute(null, textArea); + } + + void Execute(RoutedUICommand command) + { + TextArea textArea = this.TextArea; + if (textArea != null) + command.Execute(null, textArea); + } + #endregion + + #region Syntax highlighting + /// <summary> + /// The <see cref="SyntaxHighlighting"/> property. + /// </summary> + public static readonly DependencyProperty SyntaxHighlightingProperty = + DependencyProperty.Register("SyntaxHighlighting", typeof(IHighlightingDefinition), typeof(TextEditor), + new FrameworkPropertyMetadata(OnSyntaxHighlightingChanged)); + + + /// <summary> + /// Gets/sets the syntax highlighting definition used to colorize the text. + /// </summary> + public IHighlightingDefinition SyntaxHighlighting + { + get { return (IHighlightingDefinition)GetValue(SyntaxHighlightingProperty); } + set { SetValue(SyntaxHighlightingProperty, value); } + } + + IVisualLineTransformer colorizer; + + static void OnSyntaxHighlightingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((TextEditor)d).OnSyntaxHighlightingChanged(e.NewValue as IHighlightingDefinition); + } + + void OnSyntaxHighlightingChanged(IHighlightingDefinition newValue) + { + if (colorizer != null) + { + this.TextArea.TextView.LineTransformers.Remove(colorizer); + colorizer = null; + } + if (newValue != null) + { + colorizer = CreateColorizer(newValue); + this.TextArea.TextView.LineTransformers.Insert(0, colorizer); + } + } + + /// <summary> + /// Creates the highlighting colorizer for the specified highlighting definition. + /// Allows derived classes to provide custom colorizer implementations for special highlighting definitions. + /// </summary> + /// <returns></returns> + protected virtual IVisualLineTransformer CreateColorizer(IHighlightingDefinition highlightingDefinition) + { + if (highlightingDefinition == null) + throw new ArgumentNullException("highlightingDefinition"); + return new HighlightingColorizer(highlightingDefinition.MainRuleSet); + } + #endregion + + #region WordWrap + /// <summary> + /// Word wrap dependency property. + /// </summary> + public static readonly DependencyProperty WordWrapProperty = + DependencyProperty.Register("WordWrap", typeof(bool), typeof(TextEditor), + new FrameworkPropertyMetadata(Boxes.False)); + + /// <summary> + /// Specifies whether the text editor uses word wrapping. + /// </summary> + /// <remarks> + /// Setting WordWrap=true has the same effect as setting HorizontalScrollBarVisibility=Disabled and will override the + /// HorizontalScrollBarVisibility setting. + /// </remarks> + public bool WordWrap + { + get { return (bool)GetValue(WordWrapProperty); } + set { SetValue(WordWrapProperty, Boxes.Box(value)); } + } + #endregion + + #region IsReadOnly + /// <summary> + /// IsReadOnly dependency property. + /// </summary> + public static readonly DependencyProperty IsReadOnlyProperty = + DependencyProperty.Register("IsReadOnly", typeof(bool), typeof(TextEditor), + new FrameworkPropertyMetadata(Boxes.False, OnIsReadOnlyChanged)); + + /// <summary> + /// Specifies whether the user can change the text editor content. + /// Setting this property will replace the + /// <see cref="Editing.TextArea.ReadOnlySectionProvider">TextArea.ReadOnlySectionProvider</see>. + /// </summary> + public bool IsReadOnly + { + get { return (bool)GetValue(IsReadOnlyProperty); } + set { SetValue(IsReadOnlyProperty, Boxes.Box(value)); } + } + + static void OnIsReadOnlyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + TextEditor editor = d as TextEditor; + if (editor != null) + { + if ((bool)e.NewValue) + editor.TextArea.ReadOnlySectionProvider = ReadOnlyDocument.Instance; + else + editor.TextArea.ReadOnlySectionProvider = NoReadOnlySections.Instance; + + TextEditorAutomationPeer peer = TextEditorAutomationPeer.FromElement(editor) as TextEditorAutomationPeer; + if (peer != null) + { + peer.RaiseIsReadOnlyChanged((bool)e.OldValue, (bool)e.NewValue); + } + } + } + #endregion + + #region IsModified + /// <summary> + /// Dependency property for <see cref="IsModified"/> + /// </summary> + public static readonly DependencyProperty IsModifiedProperty = + DependencyProperty.Register("IsModified", typeof(bool), typeof(TextEditor), + new FrameworkPropertyMetadata(Boxes.False, OnIsModifiedChanged)); + + /// <summary> + /// Gets/Sets the 'modified' flag. + /// </summary> + public bool IsModified + { + get { return (bool)GetValue(IsModifiedProperty); } + set { SetValue(IsModifiedProperty, Boxes.Box(value)); } + } + + static void OnIsModifiedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + TextEditor editor = d as TextEditor; + if (editor != null) + { + TextDocument document = editor.Document; + if (document != null) + { + UndoStack undoStack = document.UndoStack; + if ((bool)e.NewValue) + { + if (undoStack.IsOriginalFile) + undoStack.DiscardOriginalFileMarker(); + } + else + { + undoStack.MarkAsOriginalFile(); + } + } + } + } + + bool HandleIsOriginalChanged(PropertyChangedEventArgs e) + { + if (e.PropertyName == "IsOriginalFile") + { + TextDocument document = this.Document; + if (document != null) + { + SetCurrentValue(IsModifiedProperty, Boxes.Box(!document.UndoStack.IsOriginalFile)); + } + return true; + } + else + { + return false; + } + } + #endregion + + #region ShowLineNumbers + /// <summary> + /// ShowLineNumbers dependency property. + /// </summary> + public static readonly DependencyProperty ShowLineNumbersProperty = + DependencyProperty.Register("ShowLineNumbers", typeof(bool), typeof(TextEditor), + new FrameworkPropertyMetadata(Boxes.False, OnShowLineNumbersChanged)); + + /// <summary> + /// Specifies whether line numbers are shown on the left to the text view. + /// </summary> + public bool ShowLineNumbers + { + get { return (bool)GetValue(ShowLineNumbersProperty); } + set { SetValue(ShowLineNumbersProperty, Boxes.Box(value)); } + } + + static void OnShowLineNumbersChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + TextEditor editor = (TextEditor)d; + var leftMargins = editor.TextArea.LeftMargins; + if ((bool)e.NewValue) + { + LineNumberMargin lineNumbers = new LineNumberMargin(); + Line line = (Line)DottedLineMargin.Create(); + leftMargins.Insert(0, lineNumbers); + leftMargins.Insert(1, line); + var lineNumbersForeground = new Binding("LineNumbersForeground") { Source = editor }; + line.SetBinding(Line.StrokeProperty, lineNumbersForeground); + lineNumbers.SetBinding(Control.ForegroundProperty, lineNumbersForeground); + } + else + { + for (int i = 0; i < leftMargins.Count; i++) + { + if (leftMargins[i] is LineNumberMargin) + { + leftMargins.RemoveAt(i); + if (i < leftMargins.Count && DottedLineMargin.IsDottedLineMargin(leftMargins[i])) + { + leftMargins.RemoveAt(i); + } + break; + } + } + } + } + #endregion + + #region LineNumbersForeground + /// <summary> + /// LineNumbersForeground dependency property. + /// </summary> + public static readonly DependencyProperty LineNumbersForegroundProperty = + DependencyProperty.Register("LineNumbersForeground", typeof(Brush), typeof(TextEditor), + new FrameworkPropertyMetadata(Brushes.Gray, OnLineNumbersForegroundChanged)); + + /// <summary> + /// Gets/sets the Brush used for displaying the foreground color of line numbers. + /// </summary> + public Brush LineNumbersForeground + { + get { return (Brush)GetValue(LineNumbersForegroundProperty); } + set { SetValue(LineNumbersForegroundProperty, value); } + } + + static void OnLineNumbersForegroundChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + TextEditor editor = (TextEditor)d; + var lineNumberMargin = editor.TextArea.LeftMargins.FirstOrDefault(margin => margin is LineNumberMargin) as LineNumberMargin; ; + + if (lineNumberMargin != null) + { + lineNumberMargin.SetValue(Control.ForegroundProperty, e.NewValue); + } + } + #endregion + + #region TextBoxBase-like methods + /// <summary> + /// Appends text to the end of the document. + /// </summary> + public void AppendText(string textData) + { + var document = GetDocument(); + document.Insert(document.TextLength, textData); + } + + /// <summary> + /// Begins a group of document changes. + /// </summary> + public void BeginChange() + { + GetDocument().BeginUpdate(); + } + + /// <summary> + /// Copies the current selection to the clipboard. + /// </summary> + public void Copy() + { + Execute(ApplicationCommands.Copy); + } + + /// <summary> + /// Removes the current selection and copies it to the clipboard. + /// </summary> + public void Cut() + { + Execute(ApplicationCommands.Cut); + } + + /// <summary> + /// Begins a group of document changes and returns an object that ends the group of document + /// changes when it is disposed. + /// </summary> + public IDisposable DeclareChangeBlock() + { + return GetDocument().RunUpdate(); + } + + /// <summary> + /// Ends the current group of document changes. + /// </summary> + public void EndChange() + { + GetDocument().EndUpdate(); + } + + /// <summary> + /// Scrolls one line down. + /// </summary> + public void LineDown() + { + if (scrollViewer != null) + scrollViewer.LineDown(); + } + + /// <summary> + /// Scrolls to the left. + /// </summary> + public void LineLeft() + { + if (scrollViewer != null) + scrollViewer.LineLeft(); + } + + /// <summary> + /// Scrolls to the right. + /// </summary> + public void LineRight() + { + if (scrollViewer != null) + scrollViewer.LineRight(); + } + + /// <summary> + /// Scrolls one line up. + /// </summary> + public void LineUp() + { + if (scrollViewer != null) + scrollViewer.LineUp(); + } + + /// <summary> + /// Scrolls one page down. + /// </summary> + public void PageDown() + { + if (scrollViewer != null) + scrollViewer.PageDown(); + } + + /// <summary> + /// Scrolls one page up. + /// </summary> + public void PageUp() + { + if (scrollViewer != null) + scrollViewer.PageUp(); + } + + /// <summary> + /// Scrolls one page left. + /// </summary> + public void PageLeft() + { + if (scrollViewer != null) + scrollViewer.PageLeft(); + } + + /// <summary> + /// Scrolls one page right. + /// </summary> + public void PageRight() + { + if (scrollViewer != null) + scrollViewer.PageRight(); + } + + /// <summary> + /// Pastes the clipboard content. + /// </summary> + public void Paste() + { + Execute(ApplicationCommands.Paste); + } + + /// <summary> + /// Redoes the most recent undone command. + /// </summary> + /// <returns>True is the redo operation was successful, false is the redo stack is empty.</returns> + public bool Redo() + { + if (CanExecute(ApplicationCommands.Redo)) + { + Execute(ApplicationCommands.Redo); + return true; + } + return false; + } + + /// <summary> + /// Scrolls to the end of the document. + /// </summary> + public void ScrollToEnd() + { + ApplyTemplate(); // ensure scrollViewer is created + if (scrollViewer != null) + scrollViewer.ScrollToEnd(); + } + + /// <summary> + /// Scrolls to the start of the document. + /// </summary> + public void ScrollToHome() + { + ApplyTemplate(); // ensure scrollViewer is created + if (scrollViewer != null) + scrollViewer.ScrollToHome(); + } + + /// <summary> + /// Scrolls to the specified position in the document. + /// </summary> + public void ScrollToHorizontalOffset(double offset) + { + ApplyTemplate(); // ensure scrollViewer is created + if (scrollViewer != null) + scrollViewer.ScrollToHorizontalOffset(offset); + } + + /// <summary> + /// Scrolls to the specified position in the document. + /// </summary> + public void ScrollToVerticalOffset(double offset) + { + ApplyTemplate(); // ensure scrollViewer is created + if (scrollViewer != null) + scrollViewer.ScrollToVerticalOffset(offset); + } + + /// <summary> + /// Selects the entire text. + /// </summary> + public void SelectAll() + { + Execute(ApplicationCommands.SelectAll); + } + + /// <summary> + /// Undoes the most recent command. + /// </summary> + /// <returns>True is the undo operation was successful, false is the undo stack is empty.</returns> + public bool Undo() + { + if (CanExecute(ApplicationCommands.Undo)) + { + Execute(ApplicationCommands.Undo); + return true; + } + return false; + } + + /// <summary> + /// Gets if the most recent undone command can be redone. + /// </summary> + public bool CanRedo + { + get { return CanExecute(ApplicationCommands.Redo); } + } + + /// <summary> + /// Gets if the most recent command can be undone. + /// </summary> + public bool CanUndo + { + get { return CanExecute(ApplicationCommands.Undo); } + } + + /// <summary> + /// Gets the vertical size of the document. + /// </summary> + public double ExtentHeight + { + get + { + return scrollViewer != null ? scrollViewer.ExtentHeight : 0; + } + } + + /// <summary> + /// Gets the horizontal size of the current document region. + /// </summary> + public double ExtentWidth + { + get + { + return scrollViewer != null ? scrollViewer.ExtentWidth : 0; + } + } + + /// <summary> + /// Gets the horizontal size of the viewport. + /// </summary> + public double ViewportHeight + { + get + { + return scrollViewer != null ? scrollViewer.ViewportHeight : 0; + } + } + + /// <summary> + /// Gets the horizontal size of the viewport. + /// </summary> + public double ViewportWidth + { + get + { + return scrollViewer != null ? scrollViewer.ViewportWidth : 0; + } + } + + /// <summary> + /// Gets the vertical scroll position. + /// </summary> + public double VerticalOffset + { + get + { + return scrollViewer != null ? scrollViewer.VerticalOffset : 0; + } + } + + /// <summary> + /// Gets the horizontal scroll position. + /// </summary> + public double HorizontalOffset + { + get + { + return scrollViewer != null ? scrollViewer.HorizontalOffset : 0; + } + } + #endregion + + #region TextBox methods + /// <summary> + /// Gets/Sets the selected text. + /// </summary> + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public string SelectedText + { + get + { + TextArea textArea = this.TextArea; + // We'll get the text from the whole surrounding segment. + // This is done to ensure that SelectedText.Length == SelectionLength. + if (textArea != null && textArea.Document != null && !textArea.Selection.IsEmpty) + return textArea.Document.GetText(textArea.Selection.SurroundingSegment); + else + return string.Empty; + } + set + { + if (value == null) + throw new ArgumentNullException("value"); + TextArea textArea = this.TextArea; + if (textArea != null && textArea.Document != null) + { + int offset = this.SelectionStart; + int length = this.SelectionLength; + textArea.Document.Replace(offset, length, value); + // keep inserted text selected + textArea.Selection = SimpleSelection.Create(textArea, offset, offset + value.Length); + } + } + } + + /// <summary> + /// Gets/sets the caret position. + /// </summary> + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public int CaretOffset + { + get + { + TextArea textArea = this.TextArea; + if (textArea != null) + return textArea.Caret.Offset; + else + return 0; + } + set + { + TextArea textArea = this.TextArea; + if (textArea != null) + textArea.Caret.Offset = value; + } + } + + /// <summary> + /// Gets/sets the start position of the selection. + /// </summary> + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public int SelectionStart + { + get + { + TextArea textArea = this.TextArea; + if (textArea != null) + { + if (textArea.Selection.IsEmpty) + return textArea.Caret.Offset; + else + return textArea.Selection.SurroundingSegment.Offset; + } + else + { + return 0; + } + } + set + { + Select(value, SelectionLength); + } + } + + /// <summary> + /// Gets/sets the length of the selection. + /// </summary> + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public int SelectionLength + { + get + { + TextArea textArea = this.TextArea; + if (textArea != null && !textArea.Selection.IsEmpty) + return textArea.Selection.SurroundingSegment.Length; + else + return 0; + } + set + { + Select(SelectionStart, value); + } + } + + /// <summary> + /// Selects the specified text section. + /// </summary> + public void Select(int start, int length) + { + int documentLength = Document != null ? Document.TextLength : 0; + + if (start < 0 || start > documentLength) + { + Debug.WriteLine(new ArgumentOutOfRangeException("start", start, "Value must be between 0 and " + documentLength)); + return; + } + + if (length < 0 || start + length > documentLength) + { + Debug.WriteLine(new ArgumentOutOfRangeException("length", length, "Value must be between 0 and " + (documentLength - length))); + return; + } + + textArea.Selection = SimpleSelection.Create(textArea, start, start + length); + textArea.Caret.Offset = start + length; + } + + /// <summary> + /// Gets the number of lines in the document. + /// </summary> + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public int LineCount + { + get + { + TextDocument document = this.Document; + if (document != null) + return document.LineCount; + else + return 1; + } + } + + /// <summary> + /// Clears the text. + /// </summary> + public void Clear() + { + this.Text = string.Empty; + } + #endregion + + #region Loading from stream + /// <summary> + /// Loads the text from the stream, auto-detecting the encoding. + /// </summary> + /// <remarks> + /// This method sets <see cref="IsModified"/> to false. + /// </remarks> + public void Load(Stream stream) + { + using (StreamReader reader = FileReader.OpenStream(stream, this.Encoding ?? Encoding.UTF8)) + { + this.Text = reader.ReadToEnd(); + this.Encoding = reader.CurrentEncoding; // assign encoding after ReadToEnd() so that the StreamReader can autodetect the encoding + } + this.IsModified = false; + } + + /// <summary> + /// Loads the text from the stream, auto-detecting the encoding. + /// </summary> + public void Load(string fileName) + { + if (fileName == null) + throw new ArgumentNullException("fileName"); + using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read)) + { + Load(fs); + } + } + + /// <summary> + /// Gets/sets the encoding used when the file is saved. + /// </summary> + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public Encoding Encoding { get; set; } + + /// <summary> + /// Saves the text to the stream. + /// </summary> + /// <remarks> + /// This method sets <see cref="IsModified"/> to false. + /// </remarks> + public void Save(Stream stream) + { + if (stream == null) + throw new ArgumentNullException("stream"); + StreamWriter writer = new StreamWriter(stream, this.Encoding ?? Encoding.UTF8); + writer.Write(this.Text); + writer.Flush(); + // do not close the stream + this.IsModified = false; + } + + /// <summary> + /// Saves the text to the file. + /// </summary> + public void Save(string fileName) + { + if (fileName == null) + throw new ArgumentNullException("fileName"); + using (FileStream fs = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.None)) + { + Save(fs); + } + } + #endregion + + #region MouseHover events + /// <summary> + /// The PreviewMouseHover event. + /// </summary> + public static readonly RoutedEvent PreviewMouseHoverEvent = + TextView.PreviewMouseHoverEvent.AddOwner(typeof(TextEditor)); + + /// <summary> + /// The MouseHover event. + /// </summary> + public static readonly RoutedEvent MouseHoverEvent = + TextView.MouseHoverEvent.AddOwner(typeof(TextEditor)); + + + /// <summary> + /// The PreviewMouseHoverStopped event. + /// </summary> + public static readonly RoutedEvent PreviewMouseHoverStoppedEvent = + TextView.PreviewMouseHoverStoppedEvent.AddOwner(typeof(TextEditor)); + + /// <summary> + /// The MouseHoverStopped event. + /// </summary> + public static readonly RoutedEvent MouseHoverStoppedEvent = + TextView.MouseHoverStoppedEvent.AddOwner(typeof(TextEditor)); + + + /// <summary> + /// Occurs when the mouse has hovered over a fixed location for some time. + /// </summary> + public event MouseEventHandler PreviewMouseHover + { + add { AddHandler(PreviewMouseHoverEvent, value); } + remove { RemoveHandler(PreviewMouseHoverEvent, value); } + } + + /// <summary> + /// Occurs when the mouse has hovered over a fixed location for some time. + /// </summary> + public event MouseEventHandler MouseHover + { + add { AddHandler(MouseHoverEvent, value); } + remove { RemoveHandler(MouseHoverEvent, value); } + } + + /// <summary> + /// Occurs when the mouse had previously hovered but now started moving again. + /// </summary> + public event MouseEventHandler PreviewMouseHoverStopped + { + add { AddHandler(PreviewMouseHoverStoppedEvent, value); } + remove { RemoveHandler(PreviewMouseHoverStoppedEvent, value); } + } + + /// <summary> + /// Occurs when the mouse had previously hovered but now started moving again. + /// </summary> + public event MouseEventHandler MouseHoverStopped + { + add { AddHandler(MouseHoverStoppedEvent, value); } + remove { RemoveHandler(MouseHoverStoppedEvent, value); } + } + #endregion + + #region ScrollBarVisibility + /// <summary> + /// Dependency property for <see cref="HorizontalScrollBarVisibility"/> + /// </summary> + public static readonly DependencyProperty HorizontalScrollBarVisibilityProperty = ScrollViewer.HorizontalScrollBarVisibilityProperty.AddOwner(typeof(TextEditor), new FrameworkPropertyMetadata(ScrollBarVisibility.Visible)); + + /// <summary> + /// Gets/Sets the horizontal scroll bar visibility. + /// </summary> + public ScrollBarVisibility HorizontalScrollBarVisibility + { + get { return (ScrollBarVisibility)GetValue(HorizontalScrollBarVisibilityProperty); } + set { SetValue(HorizontalScrollBarVisibilityProperty, value); } + } + + /// <summary> + /// Dependency property for <see cref="VerticalScrollBarVisibility"/> + /// </summary> + public static readonly DependencyProperty VerticalScrollBarVisibilityProperty = ScrollViewer.VerticalScrollBarVisibilityProperty.AddOwner(typeof(TextEditor), new FrameworkPropertyMetadata(ScrollBarVisibility.Visible)); + + /// <summary> + /// Gets/Sets the vertical scroll bar visibility. + /// </summary> + public ScrollBarVisibility VerticalScrollBarVisibility + { + get { return (ScrollBarVisibility)GetValue(VerticalScrollBarVisibilityProperty); } + set { SetValue(VerticalScrollBarVisibilityProperty, value); } + } + #endregion + + object IServiceProvider.GetService(Type serviceType) + { + return textArea.GetService(serviceType); + } + + /// <summary> + /// Gets the text view position from a point inside the editor. + /// </summary> + /// <param name="point">The position, relative to top left + /// corner of TextEditor control</param> + /// <returns>The text view position, or null if the point is outside the document.</returns> + public TextViewPosition? GetPositionFromPoint(Point point) + { + if (this.Document == null) + return null; + TextView textView = this.TextArea.TextView; + return textView.GetPosition(TranslatePoint(point, textView) + textView.ScrollOffset); + } + + /// <summary> + /// Scrolls to the specified line. + /// This method requires that the TextEditor was already assigned a size (WPF layout must have run prior). + /// </summary> + public void ScrollToLine(int line) + { + ScrollTo(line, -1); + } + + /// <summary> + /// Scrolls to the specified line/column. + /// This method requires that the TextEditor was already assigned a size (WPF layout must have run prior). + /// </summary> + public void ScrollTo(int line, int column) + { + const double MinimumScrollPercentage = 0.3; + + TextView textView = textArea.TextView; + TextDocument document = textView.Document; + if (scrollViewer != null && document != null) + { + if (line < 1) + line = 1; + if (line > document.LineCount) + line = document.LineCount; + + IScrollInfo scrollInfo = textView; + if (!scrollInfo.CanHorizontallyScroll) + { + // Word wrap is enabled. Ensure that we have up-to-date info about line height so that we scroll + // to the correct position. + // This avoids that the user has to repeat the ScrollTo() call several times when there are very long lines. + VisualLine vl = textView.GetOrConstructVisualLine(document.GetLineByNumber(line)); + double remainingHeight = scrollViewer.ViewportHeight / 2; + while (remainingHeight > 0) + { + DocumentLine prevLine = vl.FirstDocumentLine.PreviousLine; + if (prevLine == null) + break; + vl = textView.GetOrConstructVisualLine(prevLine); + remainingHeight -= vl.Height; + } + } + + Point p = textArea.TextView.GetVisualPosition(new TextViewPosition(line, Math.Max(1, column)), VisualYPosition.LineMiddle); + double verticalPos = p.Y - scrollViewer.ViewportHeight / 2; + if (Math.Abs(verticalPos - scrollViewer.VerticalOffset) > MinimumScrollPercentage * scrollViewer.ViewportHeight) + { + scrollViewer.ScrollToVerticalOffset(Math.Max(0, verticalPos)); + } + if (column > 0) + { + if (p.X > scrollViewer.ViewportWidth - Caret.MinimumDistanceToViewBorder * 2) + { + double horizontalPos = Math.Max(0, p.X - scrollViewer.ViewportWidth / 2); + if (Math.Abs(horizontalPos - scrollViewer.HorizontalOffset) > MinimumScrollPercentage * scrollViewer.ViewportWidth) + { + scrollViewer.ScrollToHorizontalOffset(horizontalPos); + } + } + else + { + scrollViewer.ScrollToHorizontalOffset(0); + } + } + } + } + } }
\ 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..5de763df3 100644 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Themes/Generic.xaml +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Themes/Generic.xaml @@ -47,12 +47,19 @@ <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" /> + <BitmapImage x:Key="snippet" UriSource="pack://application:,,,/Tango.Scripting.Editors;component/Images/snippet.png" /> <!--Converters--> <converters:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" /> <converters:BooleanToVisibilityInversedConverter x:Key="BooleanToVisibilityInversedConverter" /> <Style TargetType="{x:Type completion:CompletionList}"> + <Style.Resources> + <Style TargetType="ToolTip"> + + </Style> + </Style.Resources> <Setter Property="Background" Value="{StaticResource CompletionBackgroundBrush}"></Setter> <Setter Property="BorderThickness" Value="0"></Setter> @@ -83,95 +90,6 @@ <Setter.Value> <DataTemplate> <Border Background="{StaticResource CompletionToolTipBackgroundBrush}" CornerRadius="3" BorderThickness="0.5" BorderBrush="#434343" Padding="10 5" TextElement.Foreground="{StaticResource ScriptForegroundBrush}" TextElement.FontSize="12"> - <!--<ContentControl Content="{Binding}"> - <ContentControl.Style> - <Style TargetType="ContentControl"> - <Setter Property="ContentTemplate"> - <Setter.Value> - <DataTemplate> - <ContentPresenter Content="{Binding PopupControl}" /> - </DataTemplate> - </Setter.Value> - </Setter> - <Style.Triggers> - <DataTrigger Binding="{Binding Type}" Value="method"> - <Setter Property="ContentTemplate"> - <Setter.Value> - <DataTemplate> - <StackPanel> - <StackPanel Orientation="Horizontal"> - <TextBlock Text="{Binding ReturnType}" Foreground="{StaticResource ScriptReferenceTypesBrush}"></TextBlock> - <TextBlock Margin="5 0 0 0" Text="{Binding Class}" Foreground="{StaticResource ScriptReferenceTypesBrush}"></TextBlock> - <TextBlock>.</TextBlock> - <TextBlock Text="{Binding Text}"></TextBlock> - <TextBlock>(</TextBlock> - <ItemsControl ItemsSource="{Binding Parameters}"> - <ItemsControl.ItemsPanel> - <ItemsPanelTemplate> - <StackPanel Orientation="Horizontal"></StackPanel> - </ItemsPanelTemplate> - </ItemsControl.ItemsPanel> - <ItemsControl.ItemTemplate> - <DataTemplate> - <StackPanel Orientation="Horizontal"> - <TextBlock Text="{Binding Type.Name}" Foreground="{StaticResource ScriptReferenceTypesBrush}"></TextBlock> - <TextBlock Margin="5 0 0 0" Text="{Binding Name}"></TextBlock> - <TextBlock Margin="0 0 5 0" Text="," Visibility="{Binding IsLast,Converter={StaticResource BooleanToVisibilityInversedConverter}}"></TextBlock> - </StackPanel> - </DataTemplate> - </ItemsControl.ItemTemplate> - </ItemsControl> - <TextBlock>)</TextBlock> - - <StackPanel Margin="5 0 0 0" Orientation="Horizontal" Visibility="{Binding HasOverloads,Converter={StaticResource BooleanToVisibilityConverter}}"> - <TextBlock>(+</TextBlock> - <TextBlock Margin="2 0" Text="{Binding Overloads}"></TextBlock> - <TextBlock>overloads)</TextBlock> - </StackPanel> - </StackPanel> - - <TextBlock Text="{Binding Description}"></TextBlock> - </StackPanel> - </DataTemplate> - </Setter.Value> - </Setter> - </DataTrigger> - - <DataTrigger Binding="{Binding Type}" Value="property"> - <Setter Property="ContentTemplate"> - <Setter.Value> - <DataTemplate> - <StackPanel> - <StackPanel Orientation="Horizontal"> - <TextBlock Text="{Binding ReturnType}" Foreground="{StaticResource ScriptReferenceTypesBrush}"></TextBlock> - <TextBlock Margin="5 0 0 0" Text="{Binding Class}" Foreground="{StaticResource ScriptReferenceTypesBrush}"></TextBlock> - <TextBlock>.</TextBlock> - <TextBlock Text="{Binding Text}"></TextBlock> - <TextBlock Margin="5 0 0 0"> - <Run>{</Run> - <Run Foreground="{StaticResource ScriptKeywordBrush}">get</Run><Run>;</Run> - <Run Foreground="{StaticResource ScriptKeywordBrush}">set</Run><Run>;</Run> - <Run>}</Run> - </TextBlock> - </StackPanel> - - <TextBlock Text="{Binding Description}"></TextBlock> - </StackPanel> - </DataTemplate> - </Setter.Value> - </Setter> - </DataTrigger> - </Style.Triggers> - </Style> - </ContentControl.Style> - - <ContentControl.ContentTemplate> - <DataTemplate> - <ContentPresenter Content="{Binding PopupControl}" /> - </DataTemplate> - </ContentControl.ContentTemplate> - </ContentControl>--> - <ContentPresenter DataContext="{Binding}" Content="{Binding PopupControl}" /> </Border> </DataTemplate> @@ -223,6 +141,15 @@ <Setter Property="Control.Cursor" Value="/Tango.Scripting.Editors;component/themes/RightArrow.cur"/> </Style> + <Style TargetType="{x:Type local:XamlEditor}"> + <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"></Setter> + <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"></Setter> + <Setter Property="FontFamily" Value="Consolas"></Setter> + <Setter Property="FontSize" Value="13"></Setter> + <Setter Property="SyntaxHighlighting" Value="XML"></Setter> + <Setter Property="ShowLineNumbers" Value="True"></Setter> + </Style> + <Style TargetType="{x:Type local:ScriptEditor}"> <Setter Property="Background" Value="{StaticResource ScriptBackgroundBrush}"></Setter> <Setter Property="Foreground" Value="{StaticResource ScriptForegroundBrush}"></Setter> @@ -567,4 +494,6 @@ </Setter.Value> </Setter> </Style> + + </ResourceDictionary> diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/XamlEditor.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/XamlEditor.cs new file mode 100644 index 000000000..22b425ba2 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/XamlEditor.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; + +namespace Tango.Scripting.Editors +{ + public class XamlEditor : TextEditor + { + private bool preventCodeUpdate; + + public String Xaml + { + get { return (String)GetValue(XamlProperty); } + set { SetValue(XamlProperty, value); } + } + public static readonly DependencyProperty XamlProperty = + DependencyProperty.Register("Xaml", typeof(String), typeof(XamlEditor), new PropertyMetadata(null, (d, e) => (d as XamlEditor).OnXamlChanged())); + + public XamlEditor() + { + TextChanged += XamlEditor_TextChanged; + } + + private void XamlEditor_TextChanged(object sender, EventArgs e) + { + if (!preventCodeUpdate) + { + preventCodeUpdate = true; + Xaml = Text; + preventCodeUpdate = false; + } + } + + private void OnXamlChanged() + { + if (!preventCodeUpdate) + { + preventCodeUpdate = true; + Text = Xaml; + preventCodeUpdate = false; + } + } + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/app.config b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/app.config index d3a17b4de..16d75cf59 100644 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/app.config +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/app.config @@ -77,6 +77,14 @@ </dependentAssembly> + <dependentAssembly> + + <assemblyIdentity name="Microsoft.IdentityModel.Clients.ActiveDirectory" publicKeyToken="31bf3856ad364e35" culture="neutral" /> + + <bindingRedirect oldVersion="0.0.0.0-5.0.5.0" newVersion="5.0.5.0" /> + + </dependentAssembly> + </assemblyBinding> </runtime> diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/packages.config b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/packages.config index 00eef19db..a0f62a1d4 100644 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/packages.config +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/packages.config @@ -4,6 +4,7 @@ <package id="Microsoft.CodeAnalysis.Analyzers" version="1.1.0" targetFramework="net461" /> <package id="Microsoft.CodeAnalysis.Common" version="2.4.0" targetFramework="net461" /> <package id="Microsoft.CodeAnalysis.CSharp" version="2.4.0" targetFramework="net461" /> + <package id="Newtonsoft.Json" version="9.0.1" targetFramework="net461" /> <package id="System.AppContext" version="4.3.0" targetFramework="net461" /> <package id="System.Collections" version="4.3.0" targetFramework="net461" /> <package id="System.Collections.Concurrent" version="4.3.0" targetFramework="net461" /> diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Formatting/CodeFormatter.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Formatting/CodeFormatter.cs new file mode 100644 index 000000000..c933f7e09 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Formatting/CodeFormatter.cs @@ -0,0 +1,61 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Formatting; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.Scripting.Formatting +{ + public static class CodeFormatter + { + public static String Format(String code) + { + SyntaxTree tree = CSharpSyntaxTree.ParseText(code); + CompilationUnitSyntax root = tree.GetCompilationUnitRoot(); + + //var node = ApplyBraceNewLineRule(root); + //node = ApplyCopyrightHeaderRule(node); + //node = ApplyNewLineAboveRule(node); + //node = ApplyUsingLocationRule(node); + + //Just to make VS copy the dll to output folder. + Microsoft.CodeAnalysis.CSharp.Formatting.BinaryOperatorSpacingOptions a = Microsoft.CodeAnalysis.CSharp.Formatting.BinaryOperatorSpacingOptions.Ignore; + + var node = Formatter.Format(root, new AdhocWorkspace()); + + return node.ToString(); + } + + //private static SyntaxNode ApplyUsingLocationRule(SyntaxNode node) + //{ + // UsingLocationRule rule = new UsingLocationRule(); + // return rule.Process(node, "CSharp"); + //} + + //private static SyntaxNode ApplyBraceNewLineRule(SyntaxNode node) + //{ + // BraceNewLineRule rule = new BraceNewLineRule(); + // return rule.Process(node, "CSharp"); + //} + + //private static SyntaxNode ApplyNewLineAboveRule(SyntaxNode node) + //{ + // NewLineAboveRule rule = new NewLineAboveRule(); + // return rule.Process(node, "CSharp"); + //} + + //private static SyntaxNode ApplyCopyrightHeaderRule(SyntaxNode node) + //{ + // CopyrightHeaderRule rule = new CopyrightHeaderRule(new Microsoft.DotNet.CodeFormatting.Options() + // { + + // }); + + // return rule.ProcessCSharp(node); + //} + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Formatting/Properties/AssemblyInfo.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Formatting/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..5436fc65e --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Formatting/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Tango.Scripting.Formatting")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Tango.Scripting.Formatting")] +[assembly: AssemblyCopyright("Copyright © 2020")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("8d8f06ed-7f75-4933-b0c5-829b0ff654d0")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Formatting/Tango.Scripting.Formatting.csproj b/Software/Visual_Studio/Scripting/Tango.Scripting.Formatting/Tango.Scripting.Formatting.csproj new file mode 100644 index 000000000..4e5b927b0 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Formatting/Tango.Scripting.Formatting.csproj @@ -0,0 +1,160 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <ProjectGuid>{8D8F06ED-7F75-4933-B0C5-829B0FF654D0}</ProjectGuid> + <OutputType>Library</OutputType> + <AppDesignerFolder>Properties</AppDesignerFolder> + <RootNamespace>Tango.Scripting.Formatting</RootNamespace> + <AssemblyName>Tango.Scripting.Formatting</AssemblyName> + <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion> + <FileAlignment>512</FileAlignment> + <Deterministic>true</Deterministic> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\Debug\</OutputPath> + <DefineConstants>DEBUG;TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\Release\</OutputPath> + <DefineConstants>TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <ItemGroup> + <Reference Include="Esent.Interop, Version=1.9.4.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"> + <HintPath>..\..\packages\ManagedEsent.1.9.4\lib\net40\Esent.Interop.dll</HintPath> + </Reference> + <Reference Include="Microsoft.CodeAnalysis, Version=2.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"> + <HintPath>..\..\packages\Microsoft.CodeAnalysis.Common.2.4.0\lib\netstandard1.3\Microsoft.CodeAnalysis.dll</HintPath> + </Reference> + <Reference Include="Microsoft.CodeAnalysis.CSharp, Version=2.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"> + <HintPath>..\..\packages\Microsoft.CodeAnalysis.CSharp.2.4.0\lib\netstandard1.3\Microsoft.CodeAnalysis.CSharp.dll</HintPath> + </Reference> + <Reference Include="Microsoft.CodeAnalysis.CSharp.Scripting, Version=2.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"> + <HintPath>..\..\packages\Microsoft.CodeAnalysis.CSharp.Scripting.2.4.0\lib\netstandard1.3\Microsoft.CodeAnalysis.CSharp.Scripting.dll</HintPath> + </Reference> + <Reference Include="Microsoft.CodeAnalysis.CSharp.Workspaces, Version=2.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"> + <HintPath>..\..\packages\Microsoft.CodeAnalysis.CSharp.Workspaces.2.4.0\lib\netstandard1.3\Microsoft.CodeAnalysis.CSharp.Workspaces.dll</HintPath> + </Reference> + <Reference Include="Microsoft.CodeAnalysis.Scripting, Version=2.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"> + <HintPath>..\..\packages\Microsoft.CodeAnalysis.Scripting.Common.2.4.0\lib\netstandard1.3\Microsoft.CodeAnalysis.Scripting.dll</HintPath> + </Reference> + <Reference Include="Microsoft.CodeAnalysis.Workspaces, Version=2.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"> + <HintPath>..\..\packages\Microsoft.CodeAnalysis.Workspaces.Common.2.4.0\lib\net46\Microsoft.CodeAnalysis.Workspaces.dll</HintPath> + </Reference> + <Reference Include="Microsoft.CodeAnalysis.Workspaces.Desktop, Version=2.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"> + <HintPath>..\..\packages\Microsoft.CodeAnalysis.Workspaces.Common.2.4.0\lib\net46\Microsoft.CodeAnalysis.Workspaces.Desktop.dll</HintPath> + </Reference> + <Reference Include="Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL"> + <HintPath>..\..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll</HintPath> + </Reference> + <Reference Include="System" /> + <Reference Include="System.AppContext, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> + <HintPath>..\..\packages\System.AppContext.4.3.0\lib\net46\System.AppContext.dll</HintPath> + </Reference> + <Reference Include="System.Collections.Immutable, Version=1.2.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> + <HintPath>..\..\packages\System.Collections.Immutable.1.3.1\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath> + </Reference> + <Reference Include="System.ComponentModel.Composition" /> + <Reference Include="System.Composition.AttributedModel, Version=1.0.31.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> + <HintPath>..\..\packages\System.Composition.AttributedModel.1.0.31\lib\portable-net45+win8+wp8+wpa81\System.Composition.AttributedModel.dll</HintPath> + </Reference> + <Reference Include="System.Composition.Convention, Version=1.0.31.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> + <HintPath>..\..\packages\System.Composition.Convention.1.0.31\lib\portable-net45+win8+wp8+wpa81\System.Composition.Convention.dll</HintPath> + </Reference> + <Reference Include="System.Composition.Hosting, Version=1.0.31.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> + <HintPath>..\..\packages\System.Composition.Hosting.1.0.31\lib\portable-net45+win8+wp8+wpa81\System.Composition.Hosting.dll</HintPath> + </Reference> + <Reference Include="System.Composition.Runtime, Version=1.0.31.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> + <HintPath>..\..\packages\System.Composition.Runtime.1.0.31\lib\portable-net45+win8+wp8+wpa81\System.Composition.Runtime.dll</HintPath> + </Reference> + <Reference Include="System.Composition.TypedParts, Version=1.0.31.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> + <HintPath>..\..\packages\System.Composition.TypedParts.1.0.31\lib\portable-net45+win8+wp8+wpa81\System.Composition.TypedParts.dll</HintPath> + </Reference> + <Reference Include="System.Console, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> + <HintPath>..\..\packages\System.Console.4.3.0\lib\net46\System.Console.dll</HintPath> + </Reference> + <Reference Include="System.Core" /> + <Reference Include="System.Diagnostics.FileVersionInfo, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> + <HintPath>..\..\packages\System.Diagnostics.FileVersionInfo.4.3.0\lib\net46\System.Diagnostics.FileVersionInfo.dll</HintPath> + </Reference> + <Reference Include="System.Diagnostics.StackTrace, Version=4.0.3.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> + <HintPath>..\..\packages\System.Diagnostics.StackTrace.4.3.0\lib\net46\System.Diagnostics.StackTrace.dll</HintPath> + </Reference> + <Reference Include="System.IO.Compression, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL"> + <HintPath>..\..\packages\System.IO.Compression.4.3.0\lib\net46\System.IO.Compression.dll</HintPath> + </Reference> + <Reference Include="System.IO.FileSystem, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> + <HintPath>..\..\packages\System.IO.FileSystem.4.3.0\lib\net46\System.IO.FileSystem.dll</HintPath> + </Reference> + <Reference Include="System.IO.FileSystem.Primitives, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> + <HintPath>..\..\packages\System.IO.FileSystem.Primitives.4.3.0\lib\net46\System.IO.FileSystem.Primitives.dll</HintPath> + </Reference> + <Reference Include="System.Numerics" /> + <Reference Include="System.Reflection.Metadata, Version=1.4.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> + <HintPath>..\..\packages\System.Reflection.Metadata.1.4.2\lib\portable-net45+win8\System.Reflection.Metadata.dll</HintPath> + </Reference> + <Reference Include="System.Security.Cryptography.Algorithms, Version=4.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> + <HintPath>..\..\packages\System.Security.Cryptography.Algorithms.4.3.0\lib\net461\System.Security.Cryptography.Algorithms.dll</HintPath> + </Reference> + <Reference Include="System.Security.Cryptography.Encoding, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> + <HintPath>..\..\packages\System.Security.Cryptography.Encoding.4.3.0\lib\net46\System.Security.Cryptography.Encoding.dll</HintPath> + </Reference> + <Reference Include="System.Security.Cryptography.Primitives, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> + <HintPath>..\..\packages\System.Security.Cryptography.Primitives.4.3.0\lib\net46\System.Security.Cryptography.Primitives.dll</HintPath> + </Reference> + <Reference Include="System.Security.Cryptography.X509Certificates, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> + <HintPath>..\..\packages\System.Security.Cryptography.X509Certificates.4.3.0\lib\net461\System.Security.Cryptography.X509Certificates.dll</HintPath> + </Reference> + <Reference Include="System.Text.Encoding.CodePages, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> + <HintPath>..\..\packages\System.Text.Encoding.CodePages.4.3.0\lib\net46\System.Text.Encoding.CodePages.dll</HintPath> + </Reference> + <Reference Include="System.Threading.Thread, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> + <HintPath>..\..\packages\System.Threading.Thread.4.3.0\lib\net46\System.Threading.Thread.dll</HintPath> + </Reference> + <Reference Include="System.ValueTuple, Version=4.0.1.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL"> + <HintPath>..\..\packages\System.ValueTuple.4.3.0\lib\netstandard1.0\System.ValueTuple.dll</HintPath> + </Reference> + <Reference Include="System.Xml.Linq" /> + <Reference Include="System.Data.DataSetExtensions" /> + <Reference Include="Microsoft.CSharp" /> + <Reference Include="System.Data" /> + <Reference Include="System.Net.Http" /> + <Reference Include="System.Xml" /> + <Reference Include="System.Xml.ReaderWriter, Version=4.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> + <HintPath>..\..\packages\System.Xml.ReaderWriter.4.3.0\lib\net46\System.Xml.ReaderWriter.dll</HintPath> + </Reference> + <Reference Include="System.Xml.XmlDocument, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> + <HintPath>..\..\packages\System.Xml.XmlDocument.4.3.0\lib\net46\System.Xml.XmlDocument.dll</HintPath> + </Reference> + <Reference Include="System.Xml.XPath, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> + <HintPath>..\..\packages\System.Xml.XPath.4.3.0\lib\net46\System.Xml.XPath.dll</HintPath> + </Reference> + <Reference Include="System.Xml.XPath.XDocument, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> + <HintPath>..\..\packages\System.Xml.XPath.XDocument.4.3.0\lib\net46\System.Xml.XPath.XDocument.dll</HintPath> + </Reference> + </ItemGroup> + <ItemGroup> + <Compile Include="CodeFormatter.cs" /> + <Compile Include="Properties\AssemblyInfo.cs" /> + </ItemGroup> + <ItemGroup> + <None Include="app.config" /> + <None Include="packages.config" /> + </ItemGroup> + <ItemGroup> + <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> + <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> +</Project>
\ No newline at end of file diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Formatting/app.config b/Software/Visual_Studio/Scripting/Tango.Scripting.Formatting/app.config new file mode 100644 index 000000000..9da0b3b67 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Formatting/app.config @@ -0,0 +1,47 @@ +<?xml version="1.0" encoding="utf-8"?> +<configuration> + <runtime> + <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> + <dependentAssembly> + <assemblyIdentity name="System.Collections.Immutable" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-1.2.1.0" newVersion="1.2.1.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="System.IO.Compression" publicKeyToken="b77a5c561934e089" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-4.1.2.0" newVersion="4.1.2.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="System.Security.Cryptography.Algorithms" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-4.1.0.0" newVersion="4.1.0.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="System.IO.FileSystem" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="System.IO.FileSystem.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="System.Security.Cryptography.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="System.Xml.XPath.XDocument" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="System.Console" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="System.Diagnostics.StackTrace" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="System.Threading.Thread" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" /> + </dependentAssembly> + </assemblyBinding> + </runtime> +</configuration>
\ No newline at end of file diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Formatting/packages.config b/Software/Visual_Studio/Scripting/Tango.Scripting.Formatting/packages.config new file mode 100644 index 000000000..6844de8c2 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Formatting/packages.config @@ -0,0 +1,61 @@ +<?xml version="1.0" encoding="utf-8"?> +<packages> + <package id="ManagedEsent" version="1.9.4" targetFramework="net461" /> + <package id="Microsoft.CodeAnalysis.Analyzers" version="1.1.0" targetFramework="net461" /> + <package id="Microsoft.CodeAnalysis.Common" version="2.4.0" targetFramework="net461" /> + <package id="Microsoft.CodeAnalysis.CSharp" version="2.4.0" targetFramework="net461" /> + <package id="Microsoft.CodeAnalysis.CSharp.Scripting" version="2.4.0" targetFramework="net461" /> + <package id="Microsoft.CodeAnalysis.CSharp.Workspaces" version="2.4.0" targetFramework="net461" /> + <package id="Microsoft.CodeAnalysis.Scripting" version="2.4.0" targetFramework="net461" /> + <package id="Microsoft.CodeAnalysis.Scripting.Common" version="2.4.0" targetFramework="net461" /> + <package id="Microsoft.CodeAnalysis.Workspaces.Common" version="2.4.0" targetFramework="net461" /> + <package id="Newtonsoft.Json" version="9.0.1" targetFramework="net461" /> + <package id="System.AppContext" version="4.3.0" targetFramework="net461" /> + <package id="System.Collections" version="4.3.0" targetFramework="net461" /> + <package id="System.Collections.Concurrent" version="4.3.0" targetFramework="net461" /> + <package id="System.Collections.Immutable" version="1.3.1" targetFramework="net461" /> + <package id="System.Composition" version="1.0.31" targetFramework="net461" /> + <package id="System.Composition.AttributedModel" version="1.0.31" targetFramework="net461" /> + <package id="System.Composition.Convention" version="1.0.31" targetFramework="net461" /> + <package id="System.Composition.Hosting" version="1.0.31" targetFramework="net461" /> + <package id="System.Composition.Runtime" version="1.0.31" targetFramework="net461" /> + <package id="System.Composition.TypedParts" version="1.0.31" targetFramework="net461" /> + <package id="System.Console" version="4.3.0" targetFramework="net461" /> + <package id="System.Diagnostics.Debug" version="4.3.0" targetFramework="net461" /> + <package id="System.Diagnostics.FileVersionInfo" version="4.3.0" targetFramework="net461" /> + <package id="System.Diagnostics.StackTrace" version="4.3.0" targetFramework="net461" /> + <package id="System.Diagnostics.Tools" version="4.3.0" targetFramework="net461" /> + <package id="System.Dynamic.Runtime" version="4.3.0" targetFramework="net461" /> + <package id="System.Globalization" version="4.3.0" targetFramework="net461" /> + <package id="System.IO" version="4.3.0" targetFramework="net461" /> + <package id="System.IO.Compression" version="4.3.0" targetFramework="net461" /> + <package id="System.IO.FileSystem" version="4.3.0" targetFramework="net461" /> + <package id="System.IO.FileSystem.Primitives" version="4.3.0" targetFramework="net461" /> + <package id="System.Linq" version="4.3.0" targetFramework="net461" /> + <package id="System.Linq.Expressions" version="4.3.0" targetFramework="net461" /> + <package id="System.Reflection" version="4.3.0" targetFramework="net461" /> + <package id="System.Reflection.Extensions" version="4.3.0" targetFramework="net461" /> + <package id="System.Reflection.Metadata" version="1.4.2" targetFramework="net461" /> + <package id="System.Resources.ResourceManager" version="4.3.0" targetFramework="net461" /> + <package id="System.Runtime" version="4.3.0" targetFramework="net461" /> + <package id="System.Runtime.Extensions" version="4.3.0" targetFramework="net461" /> + <package id="System.Runtime.InteropServices" version="4.3.0" targetFramework="net461" /> + <package id="System.Runtime.Numerics" version="4.3.0" targetFramework="net461" /> + <package id="System.Security.Cryptography.Algorithms" version="4.3.0" targetFramework="net461" /> + <package id="System.Security.Cryptography.Encoding" version="4.3.0" targetFramework="net461" /> + <package id="System.Security.Cryptography.Primitives" version="4.3.0" targetFramework="net461" /> + <package id="System.Security.Cryptography.X509Certificates" version="4.3.0" targetFramework="net461" /> + <package id="System.Text.Encoding" version="4.3.0" targetFramework="net461" /> + <package id="System.Text.Encoding.CodePages" version="4.3.0" targetFramework="net461" /> + <package id="System.Text.Encoding.Extensions" version="4.3.0" targetFramework="net461" /> + <package id="System.Threading" version="4.3.0" targetFramework="net461" /> + <package id="System.Threading.Tasks" version="4.3.0" targetFramework="net461" /> + <package id="System.Threading.Tasks.Parallel" version="4.3.0" targetFramework="net461" /> + <package id="System.Threading.Thread" version="4.3.0" targetFramework="net461" /> + <package id="System.ValueTuple" version="4.3.0" targetFramework="net461" /> + <package id="System.Xml.ReaderWriter" version="4.3.0" targetFramework="net461" /> + <package id="System.Xml.XDocument" version="4.3.0" targetFramework="net461" /> + <package id="System.Xml.XmlDocument" version="4.3.0" targetFramework="net461" /> + <package id="System.Xml.XPath" version="4.3.0" targetFramework="net461" /> + <package id="System.Xml.XPath.XDocument" version="4.3.0" targetFramework="net461" /> +</packages>
\ No newline at end of file diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Test/App.config b/Software/Visual_Studio/Scripting/Tango.Scripting.Test/App.config new file mode 100644 index 000000000..731f6de6c --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Test/App.config @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8" ?> +<configuration> + <startup> + <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" /> + </startup> +</configuration>
\ No newline at end of file diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Test/App.xaml b/Software/Visual_Studio/Scripting/Tango.Scripting.Test/App.xaml new file mode 100644 index 000000000..731c7f907 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Test/App.xaml @@ -0,0 +1,9 @@ +<Application x:Class="Tango.Scripting.Test.App" + xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:local="clr-namespace:Tango.Scripting.Test" + StartupUri="MainWindow.xaml"> + <Application.Resources> + + </Application.Resources> +</Application> diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Test/App.xaml.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Test/App.xaml.cs new file mode 100644 index 000000000..e1965607a --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Test/App.xaml.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Data; +using System.Linq; +using System.Threading.Tasks; +using System.Windows; + +namespace Tango.Scripting.Test +{ + /// <summary> + /// Interaction logic for App.xaml + /// </summary> + public partial class App : Application + { + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Test/MainWindow.xaml b/Software/Visual_Studio/Scripting/Tango.Scripting.Test/MainWindow.xaml new file mode 100644 index 000000000..c1d784f10 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Test/MainWindow.xaml @@ -0,0 +1,38 @@ +<Window x:Class="Tango.Scripting.Test.MainWindow" + xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:d="http://schemas.microsoft.com/expression/blend/2008" + xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + xmlns:scripting="clr-namespace:Tango.Scripting.Editors;assembly=Tango.Scripting.Editors" + xmlns:local="clr-namespace:Tango.Scripting.Test" + mc:Ignorable="d" + Title="MainWindow" Height="450" Width="800" d:DataContext="{d:DesignInstance Type={x:Type local:MainWindowVM},IsDesignTimeCreatable=False}"> + <Grid> + <DockPanel> + <Menu DockPanel.Dock="Top" IsMainMenu="True"> + <MenuItem Header="File"> + <MenuItem Header="Add Script" Command="{Binding AddScriptCommand}"></MenuItem> + </MenuItem> + <MenuItem Header="Debug"> + <MenuItem Header="Run" Command="{Binding RunCommand}"></MenuItem> + </MenuItem> + </Menu> + + <TabControl ItemsSource="{Binding Project.Scripts}" SelectedIndex="0"> + <TabControl.ItemTemplate> + <DataTemplate> + <TextBlock Text="{Binding Name}"></TextBlock> + </DataTemplate> + </TabControl.ItemTemplate> + <TabControl.ContentTemplate> + <DataTemplate> + <scripting:ScriptEditor + ReferenceAssemblies="{Binding RelativeSource={RelativeSource AncestorType=Window},Path=DataContext.Project.ReferenceAssembliesLoaded}" + AdditionalScripts="{Binding RelativeSource={RelativeSource AncestorType=Window},Path=DataContext.Project.AdditionalScripts}" + Code="{Binding Code,Mode=TwoWay}" /> + </DataTemplate> + </TabControl.ContentTemplate> + </TabControl> + </DockPanel> + </Grid> +</Window> diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Test/MainWindow.xaml.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Test/MainWindow.xaml.cs new file mode 100644 index 000000000..58a695c10 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Test/MainWindow.xaml.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +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.Forms; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; +using Tango.Scripting.Editors; + +namespace Tango.Scripting.Test +{ + /// <summary> + /// Interaction logic for MainWindow.xaml + /// </summary> + public partial class MainWindow : Window + { + public MainWindow() + { + ScriptEditor.LoadingSymbolsProgress += ScriptEditor_AssemblyCacheProgress; + + InitializeComponent(); + DataContext = new MainWindowVM(); + } + + private void ScriptEditor_AssemblyCacheProgress(object sender, Tango.Core.TangoProgressChangedEventArgs<int> e) + { + Debug.WriteLine(e.Progress.ToString()); + } + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Test/MainWindowVM.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Test/MainWindowVM.cs new file mode 100644 index 000000000..f57de886f --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Test/MainWindowVM.cs @@ -0,0 +1,69 @@ +using Microsoft.Win32; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using Tango.Core.Commands; +using Tango.Scripting.Basic; +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<TestContext> _project; + public Project<TestContext> Project + { + get { return _project; } + set { _project = value; RaisePropertyChangedAuto(); } + } + + public MainWindowVM() + { + 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); + } + + private void AddScriptFile() + { + OpenFileDialog dlg = new OpenFileDialog(); + dlg.Filter = "CSharp Script|*.csx"; + if (dlg.ShowDialog().Value) + { + AddScript(dlg.FileName); + } + } + + private void AddScript(String file) + { + Project.Scripts.Add(Script.New(file)); + } + + private async void RunProject() + { + var session = await Project.Run(null); + + session.StateChanged += (x, e) => + { + if (e.State == ProjectSessionState.Completed) + { + MessageBox.Show(e.ReturnValue.ToString()); + } + }; + } + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Test/Properties/AssemblyInfo.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Test/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..f85cc741b --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Test/Properties/AssemblyInfo.cs @@ -0,0 +1,55 @@ +using System.Reflection; +using System.Resources; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Windows; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Tango.Scripting.Test")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Tango.Scripting.Test")] +[assembly: AssemblyCopyright("Copyright © 2020")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +//In order to begin building localizable applications, set +//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file +//inside a <PropertyGroup>. For example, if you are using US english +//in your source files, set the <UICulture> to en-US. Then uncomment +//the NeutralResourceLanguage attribute below. Update the "en-US" in +//the line below to match the UICulture setting in the project file. + +//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] + + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + //(used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) +)] + + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Test/Properties/Resources.Designer.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Test/Properties/Resources.Designer.cs new file mode 100644 index 000000000..3cc3d2906 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Test/Properties/Resources.Designer.cs @@ -0,0 +1,73 @@ +//------------------------------------------------------------------------------ +// <auto-generated> +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// </auto-generated> +//------------------------------------------------------------------------------ + +namespace Tango.Scripting.Test.Properties { + using System; + + + /// <summary> + /// A strongly-typed resource class, for looking up localized strings, etc. + /// </summary> + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// <summary> + /// Returns the cached ResourceManager instance used by this class. + /// </summary> + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Tango.Scripting.Test.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// <summary> + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// </summary> + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// <summary> + /// Looks up a localized resource of type System.Byte[]. + /// </summary> + internal static byte[] template { + get { + object obj = ResourceManager.GetObject("template", resourceCulture); + return ((byte[])(obj)); + } + } + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Test/Properties/Resources.resx b/Software/Visual_Studio/Scripting/Tango.Scripting.Test/Properties/Resources.resx new file mode 100644 index 000000000..37de48988 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Test/Properties/Resources.resx @@ -0,0 +1,124 @@ +<?xml version="1.0" encoding="utf-8"?> +<root> + <!-- + Microsoft ResX Schema + + Version 2.0 + + The primary goals of this format is to allow a simple XML format + that is mostly human readable. The generation and parsing of the + various data types are done through the TypeConverter classes + associated with the data types. + + Example: + + ... ado.net/XML headers & schema ... + <resheader name="resmimetype">text/microsoft-resx</resheader> + <resheader name="version">2.0</resheader> + <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader> + <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader> + <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data> + <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data> + <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64"> + <value>[base64 mime encoded serialized .NET Framework object]</value> + </data> + <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> + <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value> + <comment>This is a comment</comment> + </data> + + There are any number of "resheader" rows that contain simple + name/value pairs. + + Each data row contains a name, and value. The row also contains a + type or mimetype. Type corresponds to a .NET class that support + text/value conversion through the TypeConverter architecture. + Classes that don't support this are serialized and stored with the + mimetype set. + + The mimetype is used for serialized objects, and tells the + ResXResourceReader how to depersist the object. This is currently not + extensible. For a given mimetype the value must be set accordingly: + + Note - application/x-microsoft.net.object.binary.base64 is the format + that the ResXResourceWriter will generate, however the reader can + read any of the formats listed below. + + mimetype: application/x-microsoft.net.object.binary.base64 + value : The object must be serialized with + : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter + : and then encoded with base64 encoding. + + mimetype: application/x-microsoft.net.object.soap.base64 + value : The object must be serialized with + : System.Runtime.Serialization.Formatters.Soap.SoapFormatter + : and then encoded with base64 encoding. + + mimetype: application/x-microsoft.net.object.bytearray.base64 + value : The object must be serialized into a byte array + : using a System.ComponentModel.TypeConverter + : and then encoded with base64 encoding. + --> + <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> + <xsd:import namespace="http://www.w3.org/XML/1998/namespace" /> + <xsd:element name="root" msdata:IsDataSet="true"> + <xsd:complexType> + <xsd:choice maxOccurs="unbounded"> + <xsd:element name="metadata"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" /> + </xsd:sequence> + <xsd:attribute name="name" use="required" type="xsd:string" /> + <xsd:attribute name="type" type="xsd:string" /> + <xsd:attribute name="mimetype" type="xsd:string" /> + <xsd:attribute ref="xml:space" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="assembly"> + <xsd:complexType> + <xsd:attribute name="alias" type="xsd:string" /> + <xsd:attribute name="name" type="xsd:string" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="data"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> + <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" /> + <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /> + <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /> + <xsd:attribute ref="xml:space" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="resheader"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" use="required" /> + </xsd:complexType> + </xsd:element> + </xsd:choice> + </xsd:complexType> + </xsd:element> + </xsd:schema> + <resheader name="resmimetype"> + <value>text/microsoft-resx</value> + </resheader> + <resheader name="version"> + <value>2.0</value> + </resheader> + <resheader name="reader"> + <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </resheader> + <resheader name="writer"> + <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </resheader> + <assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> + <data name="template" type="System.Resources.ResXFileRef, System.Windows.Forms"> + <value>..\Resources\template.csx;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> +</root>
\ No newline at end of file diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Test/Properties/Settings.Designer.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Test/Properties/Settings.Designer.cs new file mode 100644 index 000000000..05e12ac76 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Test/Properties/Settings.Designer.cs @@ -0,0 +1,30 @@ +//------------------------------------------------------------------------------ +// <auto-generated> +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// </auto-generated> +//------------------------------------------------------------------------------ + +namespace Tango.Scripting.Test.Properties +{ + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase + { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default + { + get + { + return defaultInstance; + } + } + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Test/Properties/Settings.settings b/Software/Visual_Studio/Scripting/Tango.Scripting.Test/Properties/Settings.settings new file mode 100644 index 000000000..033d7a5e9 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Test/Properties/Settings.settings @@ -0,0 +1,7 @@ +<?xml version='1.0' encoding='utf-8'?> +<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)"> + <Profiles> + <Profile Name="(Default)" /> + </Profiles> + <Settings /> +</SettingsFile>
\ No newline at end of file diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Test/Resources/template.csx b/Software/Visual_Studio/Scripting/Tango.Scripting.Test/Resources/template.csx new file mode 100644 index 000000000..524b1bb24 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Test/Resources/template.csx @@ -0,0 +1,18 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Tango.Scripting.Basic; + +public class Program +{ + public object OnExecute(IContext context) + { + + + return new + { + Item1 = "1", + Item2 = "2" + }; + } +}
\ No newline at end of file diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Test/Tango.Scripting.Test.csproj b/Software/Visual_Studio/Scripting/Tango.Scripting.Test/Tango.Scripting.Test.csproj new file mode 100644 index 000000000..46c6d6453 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Test/Tango.Scripting.Test.csproj @@ -0,0 +1,132 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <ProjectGuid>{564A30E2-E681-422A-9528-3E8CE301B837}</ProjectGuid> + <OutputType>WinExe</OutputType> + <RootNamespace>Tango.Scripting.Test</RootNamespace> + <AssemblyName>Tango.Scripting.Test</AssemblyName> + <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion> + <FileAlignment>512</FileAlignment> + <ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> + <WarningLevel>4</WarningLevel> + <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects> + <Deterministic>true</Deterministic> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> + <PlatformTarget>AnyCPU</PlatformTarget> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\Debug\</OutputPath> + <DefineConstants>DEBUG;TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + <DocumentationFile> + </DocumentationFile> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> + <PlatformTarget>AnyCPU</PlatformTarget> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\Release\</OutputPath> + <DefineConstants>TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <ItemGroup> + <Reference Include="System" /> + <Reference Include="System.Data" /> + <Reference Include="System.Drawing" /> + <Reference Include="System.Windows.Forms" /> + <Reference Include="System.Xml" /> + <Reference Include="Microsoft.CSharp" /> + <Reference Include="System.Core" /> + <Reference Include="System.Xml.Linq" /> + <Reference Include="System.Data.DataSetExtensions" /> + <Reference Include="System.Net.Http" /> + <Reference Include="System.Xaml"> + <RequiredTargetFramework>4.0</RequiredTargetFramework> + </Reference> + <Reference Include="WindowsBase" /> + <Reference Include="PresentationCore" /> + <Reference Include="PresentationFramework" /> + </ItemGroup> + <ItemGroup> + <ApplicationDefinition Include="App.xaml"> + <Generator>MSBuild:Compile</Generator> + <SubType>Designer</SubType> + </ApplicationDefinition> + <Compile Include="Properties\Resources.Designer.cs"> + <AutoGen>True</AutoGen> + <DesignTime>True</DesignTime> + <DependentUpon>Resources.resx</DependentUpon> + </Compile> + <Page Include="MainWindow.xaml"> + <Generator>MSBuild:Compile</Generator> + <SubType>Designer</SubType> + </Page> + <Compile Include="App.xaml.cs"> + <DependentUpon>App.xaml</DependentUpon> + <SubType>Code</SubType> + </Compile> + <Compile Include="MainWindow.xaml.cs"> + <DependentUpon>MainWindow.xaml</DependentUpon> + <SubType>Code</SubType> + </Compile> + </ItemGroup> + <ItemGroup> + <Compile Include="MainWindowVM.cs" /> + <Compile Include="Properties\AssemblyInfo.cs"> + <SubType>Code</SubType> + </Compile> + <Compile Include="Properties\Settings.Designer.cs"> + <AutoGen>True</AutoGen> + <DependentUpon>Settings.settings</DependentUpon> + <DesignTimeSharedInput>True</DesignTimeSharedInput> + </Compile> + <EmbeddedResource Include="Properties\Resources.resx"> + <Generator>ResXFileCodeGenerator</Generator> + <LastGenOutput>Resources.Designer.cs</LastGenOutput> + </EmbeddedResource> + <None Include="lib.csx" /> + <None Include="Properties\Settings.settings"> + <Generator>SettingsSingleFileGenerator</Generator> + <LastGenOutput>Settings.Designer.cs</LastGenOutput> + </None> + <None Include="Resources\template.csx" /> + </ItemGroup> + <ItemGroup> + <None Include="App.config" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="..\..\Tango.Core\Tango.Core.csproj"> + <Project>{a34ee0f0-649d-41c8-8489-b6f1cc6924ee}</Project> + <Name>Tango.Core</Name> + </ProjectReference> + <ProjectReference Include="..\..\Tango.SharedUI\Tango.SharedUI.csproj"> + <Project>{8491d07b-c1f6-4b62-a412-41b9fd2d6538}</Project> + <Name>Tango.SharedUI</Name> + </ProjectReference> + <ProjectReference Include="..\Tango.Scripting.Basic\Tango.Scripting.Basic.csproj"> + <Project>{2b29a699-1d65-463a-8250-a2ce81d019c9}</Project> + <Name>Tango.Scripting.Basic</Name> + </ProjectReference> + <ProjectReference Include="..\Tango.Scripting.Core\Tango.Scripting.Core.csproj"> + <Project>{5812e1c6-abaa-4066-94ac-971c27b4f46a}</Project> + <Name>Tango.Scripting.Core</Name> + </ProjectReference> + <ProjectReference Include="..\Tango.Scripting.Editors\Tango.Scripting.Editors.csproj"> + <Project>{da62fa39-668b-47a6-b0f2-d2c1daf777b0}</Project> + <Name>Tango.Scripting.Editors</Name> + </ProjectReference> + </ItemGroup> + <ItemGroup> + <PackageReference Include="FontAwesome.WPF"> + <Version>4.7.0.9</Version> + </PackageReference> + </ItemGroup> + <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> +</Project>
\ No newline at end of file diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Test/lib.csx b/Software/Visual_Studio/Scripting/Tango.Scripting.Test/lib.csx new file mode 100644 index 000000000..bada6e745 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Test/lib.csx @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +public class MyClass +{ + public String Do() + { + return "Hi From Lib"; + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting/Parsing/ScriptParser.cs b/Software/Visual_Studio/Scripting/Tango.Scripting/Parsing/ScriptParser.cs index 15760c950..63d2cca5d 100644 --- a/Software/Visual_Studio/Scripting/Tango.Scripting/Parsing/ScriptParser.cs +++ b/Software/Visual_Studio/Scripting/Tango.Scripting/Parsing/ScriptParser.cs @@ -131,16 +131,55 @@ namespace Tango.Scripting.Parsing if (prop != null) { - vars.Add(new ScriptSymbol() + var type = ReplaceFakeScript(prop.GetValue(symbol).ToString()); + + ScriptSymbol varSymbol = new ScriptSymbol(); + varSymbol.Name = symbol.Name; + varSymbol.Type = type; + varSymbol.Class = ReplaceFakeScript(symbol.ContainingType?.Name); + varSymbol.Kind = symbol.Kind; + varSymbol.RealSymbol = symbol; + varSymbol.Accessibility = symbol.DeclaredAccessibility; + varSymbol.ContainingNamespace = ReplaceFakeScript(symbol.ContainingNamespace?.Name); + varSymbol.Summary = GetSymbolDocumentation(symbol); + + try { - Name = symbol.Name, - Type = ReplaceFakeScript(prop.GetValue(symbol).ToString()), - Class = ReplaceFakeScript(symbol.ContainingType?.Name), - Kind = symbol.Kind, - Accessibility = symbol.DeclaredAccessibility, - ContainingNamespace = ReplaceFakeScript(symbol.ContainingNamespace?.Name), - Summary = GetSymbolDocumentation(symbol), - }); + if (symbol.Kind == SymbolKind.Local && symbol.DeclaringSyntaxReferences.Count() > 0) + { + var node = symbol.DeclaringSyntaxReferences.First().GetSyntax() as VariableDeclaratorSyntax; + + if (node != null) + { + varSymbol.IsUnassigned = node.Initializer == null; + } + } + } + catch { } + + try + { + varSymbol.Offset = symbol.Locations[0].SourceSpan.Start; + varSymbol.Length = symbol.Locations[0].SourceSpan.Length; + } + catch { } + + vars.Add(varSymbol); + + if (type == "?") + { + try + { + var variables = GetScriptVariables(code); + var variable = variables.FirstOrDefault(x => x.Name == symbol.Name); + + if (variable != null) + { + varSymbol.Type = variable.Type; + } + } + catch { } + } } } } @@ -258,7 +297,21 @@ namespace Tango.Scripting.Parsing { SyntaxTree tree = CSharpSyntaxTree.ParseText(code); CompilationUnitSyntax root = tree.GetCompilationUnitRoot(); - return root.DescendantNodes().OfType<ObjectCreationExpressionSyntax>().FirstOrDefault(); + var creationSyntax = root.DescendantNodes().OfType<ObjectCreationExpressionSyntax>().FirstOrDefault(); + return creationSyntax; + } + + public MethodDeclarationSyntax GetCurrentConstructionExpressionAlt(String code) + { + if (code.Contains("=") && code.Contains("new")) + { + SyntaxTree tree = CSharpSyntaxTree.ParseText(code); + CompilationUnitSyntax root = tree.GetCompilationUnitRoot(); + var creationSyntax = root.DescendantNodes().OfType<MethodDeclarationSyntax>().FirstOrDefault(); + return creationSyntax; + } + + return null; } public T GetExpressionFirst<T>(String line) where T : CSharpSyntaxNode @@ -378,5 +431,72 @@ namespace Tango.Scripting.Parsing var ret = root.ToFullString(); return ret; } + + private List<ScriptVariable> GetScriptVariables(String code) + { + List<ScriptVariable> vars = new List<ScriptVariable>(); + + SyntaxTree tree = CSharpSyntaxTree.ParseText(code); + var root = (CompilationUnitSyntax)tree.GetRoot(); + + List<VariableDeclaratorSyntax> variables = new List<VariableDeclaratorSyntax>(); + FillVariables(variables, new List<SyntaxNode>(), root.Members[0]); + variables = variables.Distinct().ToList(); + + foreach (var item in variables) + { + ScriptVariable v = new ScriptVariable(); + v.Name = item.Identifier.ToString(); + + if (item.Initializer.Value.GetType() == typeof(ObjectCreationExpressionSyntax)) + { + v.Type = (item.Initializer.Value as ObjectCreationExpressionSyntax).Type.ToString(); + } + else if (item.Initializer.Value.GetType() == typeof(InvocationExpressionSyntax)) + { + v.Type = (((item.Initializer.Value as InvocationExpressionSyntax).Expression as MemberAccessExpressionSyntax).Name as GenericNameSyntax).TypeArgumentList.Arguments[0].ToString(); + } + + vars.Add(v); + } + + return vars; + } + + private void FillVariables(List<VariableDeclaratorSyntax> variables, List<SyntaxNode> existingNodes, SyntaxNode node) + { + var nodes = node.ChildNodes().ToList(); + + nodes.RemoveAll(x => existingNodes.Contains(x)); + + foreach (var item in nodes) + { + existingNodes.Add(item); + + if (item.GetType() == typeof(VariableDeclaratorSyntax)) + { + variables.Add(item as VariableDeclaratorSyntax); + } + else if (item == node) + { + continue; + } + else + { + FillVariables(variables, existingNodes, item); + } + } + } + + private class ScriptVariable + { + public String Name { get; set; } + public String Type { get; set; } + + public override string ToString() + { + return String.Format("{0} : {1}", Type, Name); + } + } } } diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting/Parsing/ScriptSymbol.cs b/Software/Visual_Studio/Scripting/Tango.Scripting/Parsing/ScriptSymbol.cs index d6fdaeebf..4b34837af 100644 --- a/Software/Visual_Studio/Scripting/Tango.Scripting/Parsing/ScriptSymbol.cs +++ b/Software/Visual_Studio/Scripting/Tango.Scripting/Parsing/ScriptSymbol.cs @@ -17,6 +17,10 @@ namespace Tango.Scripting.Parsing public String ContainingNamespace { get; set; } public List<KeyValuePair<String,String>> Parameters { get; set; } public String Summary { get; set; } + public int Offset { get; set; } + public int Length { get; set; } + public bool IsUnassigned { get; set; } + public ISymbol RealSymbol { get; set; } public ScriptSymbol() { |
