aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/ScriptEditor.cs
diff options
context:
space:
mode:
authorVictoria Plitt <Victoria.Plitt@twine-s.com>2019-04-08 13:49:55 +0300
committerVictoria Plitt <Victoria.Plitt@twine-s.com>2019-04-08 13:49:55 +0300
commitfc8a05358a92cc3c77c5f1e30d536807ef0614fd (patch)
treec65f696ebd60f3790145721307c255e5a339923f /Software/Visual_Studio/Scripting/Tango.Scripting.Editors/ScriptEditor.cs
parentb4a71931ea52636c6b36376aa9d71697ccf73524 (diff)
downloadTango-fc8a05358a92cc3c77c5f1e30d536807ef0614fd.tar.gz
Tango-fc8a05358a92cc3c77c5f1e30d536807ef0614fd.zip
were added scripting projects
Diffstat (limited to 'Software/Visual_Studio/Scripting/Tango.Scripting.Editors/ScriptEditor.cs')
-rw-r--r--Software/Visual_Studio/Scripting/Tango.Scripting.Editors/ScriptEditor.cs1595
1 files changed, 1595 insertions, 0 deletions
diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/ScriptEditor.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/ScriptEditor.cs
new file mode 100644
index 000000000..efa1b087a
--- /dev/null
+++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/ScriptEditor.cs
@@ -0,0 +1,1595 @@
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Controls.Primitives;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+using System.Windows.Threading;
+using System.Xml;
+using Tango.Core.Commands;
+using Tango.Scripting.Editors.CodeCompletion;
+using Tango.Scripting.Editors.Document;
+using Tango.Scripting.Editors.Editing;
+using Tango.Scripting.Editors.Folding;
+using Tango.Scripting.Editors.Highlighting;
+using Tango.Scripting.Editors.Highlighting.Xshd;
+using Tango.Scripting.Editors.Intellisense;
+using Tango.Scripting.Editors.Popups;
+using Tango.Scripting.Editors.Rendering;
+using Tango.Scripting.Parsing;
+
+namespace Tango.Scripting.Editors
+{
+ public class ScriptEditor : TextEditor
+ {
+ private char[] word_separators = { ' ', '\t', '\n', '.', '(', ',', '-', '*', '/', '+', '$', '=', '<', '>' };
+ private string[] _blocking_type_words = { "class", "void" };
+
+ private DispatcherTimer _update_timer;
+ private Popup _popup;
+ private FoldingManager foldingManager;
+ private BraceFoldingStrategy foldingStrategy;
+ private CompletionWindow completionWindow;
+ private ScriptParser _parser;
+ private List<String> _current_usings;
+ private List<KnownType> _knownTypes;
+ private List<ScriptType> _declaredTypes;
+ private bool _isLoadingTypes;
+
+ #region Mini Classes
+
+ private class ScriptClass
+ {
+ public String Name { get; set; }
+ public int Index { get; set; }
+ }
+
+ private class ConstructionSession
+ {
+ public KnownType Type { get; set; }
+ public int ParameterIndex { get; set; }
+ public List<String> TypeArguments { get; set; }
+ }
+
+ private class MethodSession
+ {
+ public KnownType Type { get; set; }
+ public String MethodName { get; set; }
+ public int ParameterIndex { get; set; }
+ }
+
+ private class DeclaredMethodSession
+ {
+ public ScriptType Type { get; set; }
+ public ScriptSymbol Method { get; set; }
+ }
+
+ #endregion
+
+ #region Properties
+
+ /// <summary>
+ /// Gets or sets a value indicating whether to enable folding.
+ /// </summary>
+ public bool EnableFolding
+ {
+ get { return (bool)GetValue(EnableFoldingProperty); }
+ set { SetValue(EnableFoldingProperty, value); }
+ }
+ public static readonly DependencyProperty EnableFoldingProperty =
+ DependencyProperty.Register("EnableFolding", typeof(bool), typeof(ScriptEditor), new PropertyMetadata(true, (d, e) => (d as ScriptEditor).OnEnableFoldingChanged()));
+
+ /// <summary>
+ ///
+ /// </summary>
+ public RelayCommand IndentCommand
+ {
+ get { return (RelayCommand)GetValue(IndentCommandProperty); }
+ set { SetValue(IndentCommandProperty, value); }
+ }
+ public static readonly DependencyProperty IndentCommandProperty =
+ DependencyProperty.Register("IndentCommand", typeof(RelayCommand), typeof(ScriptEditor), new PropertyMetadata(null));
+
+ /// <summary>
+ /// Gets or sets the reference assemblies.
+ /// </summary>
+ public ObservableCollection<ReferenceAssembly> ReferenceAssemblies
+ {
+ get { return (ObservableCollection<ReferenceAssembly>)GetValue(ReferenceAssembliesProperty); }
+ set { SetValue(ReferenceAssembliesProperty, value); }
+ }
+ public static readonly DependencyProperty ReferenceAssembliesProperty =
+ DependencyProperty.Register("ReferenceAssemblies", typeof(ObservableCollection<ReferenceAssembly>), typeof(ScriptEditor), new PropertyMetadata(null));
+
+ public Object CurrentPopupContent
+ {
+ get { return (Object)GetValue(CurrentPopupContentProperty); }
+ set { SetValue(CurrentPopupContentProperty, value); }
+ }
+ public static readonly DependencyProperty CurrentPopupContentProperty =
+ DependencyProperty.Register("CurrentPopupContent", typeof(Object), typeof(ScriptEditor), new PropertyMetadata(null));
+
+
+ #endregion
+
+ #region Constructors
+
+ /// <summary>
+ /// Initializes the <see cref="ScriptEditor"/> class.
+ /// </summary>
+ static ScriptEditor()
+ {
+ DefaultStyleKeyProperty.OverrideMetadata(typeof(ScriptEditor), new FrameworkPropertyMetadata(typeof(ScriptEditor)));
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="ScriptEditor"/> class.
+ /// </summary>
+ public ScriptEditor()
+ {
+ _declaredTypes = new List<ScriptType>();
+
+ _current_usings = new List<string>();
+
+ 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
+
+ _knownTypes = new List<KnownType>();
+ _parser = new ScriptParser();
+
+ TextArea.IndentationStrategy = new Indentation.CSharp.CSharpIndentationStrategy(Options);
+ foldingStrategy = new BraceFoldingStrategy();
+
+ _update_timer = new DispatcherTimer();
+ _update_timer.Interval = TimeSpan.FromSeconds(2);
+ _update_timer.Tick += UpdateTimer_Tick;
+ _update_timer.Start();
+
+ IndentCommand = new RelayCommand(IndentCode);
+
+ TextArea.TextEntered += TextArea_TextEntered;
+
+ completionWindow = new CompletionWindow(TextArea);
+ completionWindow.WindowStyle = WindowStyle.None;
+ completionWindow.AllowsTransparency = true;
+ completionWindow.ResizeMode = ResizeMode.NoResize;
+ completionWindow.InsertionRequest += CompletionWindow_InsertionRequest;
+ }
+
+ #endregion
+
+ #region Update Time Tick
+
+ /// <summary>
+ /// Handles the Tick event of the UpdateTimer control.
+ /// </summary>
+ /// <param name="sender">The source of the event.</param>
+ /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
+ private void UpdateTimer_Tick(object sender, EventArgs e)
+ {
+ InvalidateFolding();
+ InvalidateUsings();
+ InvalidateScriptTypesHighlightings();
+ }
+
+ #endregion
+
+ #region Properties Changes
+
+ private void OnEnableFoldingChanged()
+ {
+ if (EnableFolding)
+ {
+ foldingManager = FoldingManager.Install(TextArea);
+ }
+ else
+ {
+ FoldingManager.Uninstall(foldingManager);
+ }
+ }
+
+ #endregion
+
+ #region Override Methods
+
+ /// <summary>
+ /// Invoked when an unhandled <see cref="E:System.Windows.Input.Keyboard.PreviewKeyDown" /> attached event reaches an element in its route that is derived from this class. Implement this method to add class handling for this event.
+ /// </summary>
+ /// <param name="e">The <see cref="T:System.Windows.Input.KeyEventArgs" /> that contains the event data.</param>
+ protected override void OnPreviewKeyDown(KeyEventArgs e)
+ {
+ if (CurrentPopupContent is MethodPopup && (e.Key == Key.Down || e.Key == Key.Up))
+ {
+ e.Handled = true;
+
+ if (e.Key == Key.Down)
+ {
+ (CurrentPopupContent as MethodPopup).IncrementMethod();
+ }
+ else if (e.Key == Key.Up)
+ {
+ (CurrentPopupContent as MethodPopup).DecrementMethod();
+ }
+
+ return;
+ }
+
+ base.OnPreviewKeyDown(e);
+ HidePopup();
+ HandleKeyCombinations(e);
+ }
+
+ #endregion
+
+ #region Apply Template
+
+ public override void OnApplyTemplate()
+ {
+ base.OnApplyTemplate();
+
+ _popup = GetTemplateChild("PART_popup") as Popup;
+ }
+
+ #endregion
+
+ #region Key Combination Handling
+
+ /// <summary>
+ /// Handles the key combinations.
+ /// </summary>
+ /// <param name="e">The <see cref="KeyEventArgs"/> instance containing the event data.</param>
+ private void HandleKeyCombinations(KeyEventArgs e)
+ {
+ if (Keyboard.IsKeyDown(Key.LeftCtrl) && Keyboard.IsKeyDown(Key.K) && Keyboard.IsKeyDown(Key.D))
+ {
+ try
+ {
+ int index = CaretOffset;
+ Document.BeginUpdate();
+ IndentCode();
+ Document.EndUpdate();
+ e.Handled = true;
+ CaretOffset = index;
+ }
+ catch
+ {
+ Debug.WriteLine("Error indenting code.");
+ }
+ }
+ else if (e.Key == Key.Oem2)
+ {
+ 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;
+ }
+ }
+ else if (e.Key == Key.End || e.Key == Key.Home)
+ {
+ HideCompletionWindow();
+ }
+ }
+
+ #endregion
+
+ #region Text Entered
+
+ private void TextArea_TextEntered(object sender, TextCompositionEventArgs e)
+ {
+ List<Object> items = new List<object>();
+
+ HidePopup();
+
+ 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 (previousWords.Count > 0 && previousWords.First().Trim().StartsWith("//")) return;
+
+ if (e.Text == " " && previousWords.Count > 2 && previousWords[previousWords.Count - 2] == "=")
+ {
+ var expression = previousWords.First();
+ var knownType = GetKnownTypeFromExpression(expression + ".");
+
+ if (knownType != null && knownType.Type.IsEnum)
+ {
+ completionWindow.HideCompletion();
+ IList<ICompletionData> data = new List<ICompletionData>();
+
+ foreach (var field in knownType.Fields)
+ {
+ data.Add(new FieldCompletionItem()
+ {
+ Class = knownType.FriendlyName,
+ Name = knownType.FriendlyName + "." + field.Name,
+ Type = field.ReturnTypeFriendlyName,
+ Description = field.Summary,
+ });
+ }
+
+ ShowCompletionWindow(data.OrderBy(x => x.Text).ToList(), GetCurrentWord());
+ }
+
+ }
+ else if (e.Text == " " && GetPreviousWord() == "new")
+ {
+ var s = _parser.GetExpressionFirst<FieldDeclarationSyntax>(GetCurrentLineText());
+
+ if (s != null)
+ {
+ String type = s.Declaration.Type.ToString();
+
+ IList<ICompletionData> data = new List<ICompletionData>();
+
+ data.Add(new ClassCompletionItem()
+ {
+ Name = type,
+ Description = "Auto generate assignment...",
+ });
+
+ ShowCompletionWindow(data, type);
+ }
+ }
+ else if (e.Text == ";" || e.Text == " ")
+ {
+ HideCompletionWindow();
+ }
+ else if (e.Text == ".")
+ {
+ var knownType = GetCurrentKnownType();
+
+ if (knownType != null)
+ {
+ completionWindow.HideCompletion();
+ IList<ICompletionData> data = new List<ICompletionData>();
+
+ if (!knownType.Type.IsEnum)
+ {
+ var typeMembers = knownType.Members.ToList();
+
+ foreach (var methodGroup in typeMembers.OfType<KnownTypeMethod>().GroupBy(x => x.NameWithTypeArguments))
+ {
+ var method = methodGroup.First();
+
+ data.Add(new MethodCompletionItem()
+ {
+ Class = knownType.FriendlyName,
+ Name = method.NameWithTypeArguments,
+ ReturnType = method.ReturnTypeFriendlyName,
+ Description = method.Summary,
+ Parameters = method.Parameters,
+ Overloads = methodGroup.Count() - 1,
+ });
+ }
+
+ foreach (var methodGroup in typeMembers.Where(x => x.GetType() != typeof(KnownTypeMethod)).GroupBy(x => x.Name))
+ {
+ var member = methodGroup.First();
+
+ data.Add(new PropertyCompletionItem()
+ {
+ Class = knownType.FriendlyName,
+ Name = member.Name,
+ Type = member.ReturnTypeFriendlyName,
+ Description = member.Summary,
+ });
+
+ }
+ }
+ else
+ {
+ foreach (var field in knownType.Fields)
+ {
+ data.Add(new FieldCompletionItem()
+ {
+ Class = 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)
+ {
+ completionWindow.HideCompletion();
+ IList<ICompletionData> data = new List<ICompletionData>();
+
+ var typeMembers = declaredType.Symbols.ToList();
+
+ foreach (var methodGroup in typeMembers.GroupBy(x => x.Name))
+ {
+ var member = methodGroup.First();
+
+ 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,
+ };
+
+
+ for (int i = 0; i < member.Parameters.Count; i++)
+ {
+ var pair = member.Parameters[i];
+
+ methodCompletion.Parameters.Add(new KnownTypeMethodParameter()
+ {
+ Type = pair.Key,
+ Name = pair.Value,
+ IsLast = (i == member.Parameters.Count - 1)
+ });
+ }
+
+ data.Add(methodCompletion);
+
+ }
+ else if (member.Kind == SymbolKind.Property)
+ {
+ data.Add(new PropertyCompletionItem()
+ {
+ Class = declaredType.Name,
+ Name = member.Name,
+ Type = member.Type,
+ Description = member.Summary,
+ });
+ }
+ else if (member.Kind == SymbolKind.Field)
+ {
+ data.Add(new FieldCompletionItem()
+ {
+ Class = declaredType.Name,
+ Name = member.Name,
+ Type = member.Type,
+ Description = member.Summary,
+ });
+ }
+ }
+
+ ShowCompletionWindow(data, GetCurrentWord());
+ }
+ }
+ }
+ else if (e.Text == "(" || e.Text == ",")
+ {
+ completionWindow.HideCompletion();
+
+ try
+ {
+ var session = GetConstructionSession();
+
+ if (session != null)
+ {
+ var content = CreateConstructionSessionPopupContent(session);
+ if (content.Methods.Count > 0)
+ {
+ ShowPopup(content);
+ return;
+ }
+ }
+
+ var methodSession = GetMethodSession();
+
+ if (methodSession != null)
+ {
+ var content = CreateMethodSessionPopupContent(methodSession);
+ if (content.Methods.Count > 0)
+ {
+ ShowPopup(content);
+ return;
+ }
+ }
+
+ var declaredMethodSession = GetDeclaredMethodSession();
+
+ if (declaredMethodSession != null)
+ {
+ var content = CreateDeclaredMethodSessionPopupContent(declaredMethodSession);
+ if (content.Methods.Count > 0)
+ {
+ ShowPopup(content);
+ return;
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine(ex);
+ }
+ }
+ else if (lineText.StartsWith("using"))
+ {
+ if (completionWindow.IsVisible)
+ {
+ completionWindow.UpdatePositionFix();
+ return;
+ }
+
+ 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))
+ {
+ data.Add(new NamespaceCompletionItem()
+ {
+ Name = ns,
+ Assembly = asm.Assembly.GetName().Name,
+ });
+ }
+ }
+
+ 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--;
+ }
+ }
+ else if (e.Text == "}")
+ {
+ if (Document.GetText(CaretOffset - 2, 1) == "{" && Document.GetText(CaretOffset, 1) == "}")
+ {
+ 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");
+ }
+ }
+ else if (!currentWordIncludingParenthesis.Contains(".") || currentWord[currentWord.Length - 2] == '<')
+ {
+ if (completionWindow.IsVisible)
+ {
+ completionWindow.UpdatePositionFix();
+ return;
+ }
+
+ var previous_word = GetPreviousWord();
+ var word = GetCurrentWord();
+
+ if (word.Contains("<"))
+ {
+ word = word.Last(x => x != '<').ToString();
+ }
+
+ if (previous_word != word)
+ {
+ if (_knownTypes.Exists(x => x.Name == previous_word))
+ {
+ return;
+ }
+
+ if (_blocking_type_words.Contains(previous_word))
+ {
+ return;
+ }
+ }
+
+ if (!String.IsNullOrWhiteSpace(word))
+ {
+ IList<ICompletionData> data = new List<ICompletionData>();
+
+ foreach (var type in _declaredTypes.Where(x => x.Name.StartsWith(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)
+ {
+ 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 type in _knownTypes.ToList().Where(x => x.Name.StartsWith(word)))
+ {
+ if (type.Type.IsEnum)
+ {
+ data.Add(new EnumCompletionItem()
+ {
+ Namespace = type.Type.Namespace,
+ Description = type.Summary,
+ Name = type.FriendlyName,
+ Priority = 0,
+ });
+ }
+ else if (type.Type.IsInterface)
+ {
+ 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.");
+ }
+ }
+
+ foreach (var symbol in _parser.GetContextSymbols(Document.Text, CaretOffset).Where(x => x.Name.StartsWith(GetCurrentWord())))
+ {
+ if (symbol.Kind == SymbolKind.Property)
+ {
+ 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)
+ {
+ data.Add(new FieldCompletionItem()
+ {
+ 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];
+
+ methodCompletion.Parameters.Add(new KnownTypeMethodParameter()
+ {
+ Type = pair.Key,
+ Name = pair.Value,
+ IsLast = (i == symbol.Parameters.Count - 1)
+ });
+ }
+
+ data.Add(methodCompletion);
+ }
+ }
+
+ ShowCompletionWindow(data, word);
+ }
+ }
+ }
+
+ #endregion
+
+ #region Completion Window Insertion
+
+ private void CompletionWindow_InsertionRequest(ICompletionData item)
+ {
+ item.Complete(this);
+ }
+
+ #endregion
+
+ #region Private/Internal Methods
+
+ private void ShowCompletionWindow(IList<ICompletionData> suggestions, String filter)
+ {
+ IList<ICompletionData> data = completionWindow.CompletionList.CompletionData;
+ data.Clear();
+
+ foreach (var item in suggestions)
+ {
+ data.Add(item);
+ }
+
+ if (data.Count > 0)
+ {
+ completionWindow.ShowCompletion();
+
+ if (completionWindow.CompletionList.ListBox != null)
+ {
+ completionWindow.CompletionList.SelectItemFiltering(filter);
+ }
+ }
+ else
+ {
+ completionWindow.HideCompletion();
+ }
+ }
+
+ private void HideCompletionWindow()
+ {
+ completionWindow.HideCompletion();
+ }
+
+ private List<String> GetScriptClassNames()
+ {
+ List<String> list = new List<String>();
+
+ Regex r = new Regex(@"(class\s+)(\w+)");
+ var matches = r.Matches(Text);
+
+ foreach (var m in matches.OfType<Match>())
+ {
+ var g = m.Groups.OfType<Group>().Last();
+ list.Add(g.Value);
+ }
+
+ return list.Distinct().ToList();
+ }
+
+ private List<String> GetScriptInterfaceOfEnumNames()
+ {
+ List<String> list = new List<String>();
+
+ Regex r = new Regex(@"((enum|interface)\s+)(\w+)");
+ var matches = r.Matches(Text);
+
+ foreach (var m in matches.OfType<Match>())
+ {
+ var g = m.Groups.OfType<Group>().Last();
+ list.Add(g.Value);
+ }
+
+ return list.Distinct().ToList();
+ }
+
+ private List<String> GetScriptEnumsAndInterfaces()
+ {
+ List<String> list = new List<string>();
+
+ Regex r = new Regex(@"((public|private|internal)\s+(enum|interface)\s+\w+)");
+ var matches = r.Matches(Text);
+
+ foreach (var m in matches)
+ {
+
+ }
+
+ return list;
+ }
+
+ private KnownType GetCurrentKnownType()
+ {
+ var expression = GetPreviousWords().LastOrDefault();
+ return GetKnownTypeFromExpression(expression);
+ }
+
+ private KnownType GetKnownTypeFromExpression(String expression)
+ {
+ if (expression != null)
+ {
+ var tree = expression.Split('.').Select(x => x.Remove(@"\n|\t|\r|\(.*\)|\[.*\]|\s")).ToList();
+ var variableName = tree.FirstOrDefault();
+
+ if (variableName != null)
+ {
+ //Search for enum type first
+ var enumType = _knownTypes.FirstOrDefault(x => x.Name == variableName && x.Type.IsEnum);
+
+ if (enumType != null)
+ {
+ return enumType;
+ }
+
+ tree.RemoveAt(0);
+ var variables = _parser.GetContextSymbols(Document.Text, CaretOffset);
+ var variable = variables.FirstOrDefault(x => x.Name == variableName);
+
+ if (variable != null)
+ {
+ var knownType = _knownTypes.FirstOrDefault(x => x.FriendlyName == Regex.Replace(variable.Type, "<.+>", "<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 knownType;
+ }
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private ScriptType GetCurrentDeclaredType()
+ {
+ var expression = GetPreviousWords().LastOrDefault();
+
+ if (expression != null)
+ {
+ var tree = expression.Split('.').Select(x => x.Remove(@"\n|\t|\r|\(.*\)|\[.*\]|\s")).ToList();
+ var variableName = tree.FirstOrDefault();
+
+ if (variableName != null)
+ {
+ tree.RemoveAt(0);
+ var variables = _parser.GetContextSymbols(Document.Text, CaretOffset);
+ var variable = variables.FirstOrDefault(x => x.Name == variableName);
+
+ if (variable != null)
+ {
+ var declaredType = _declaredTypes.FirstOrDefault(x => x.Name == Regex.Replace(variable.Type, "<.+>", "<T>"));
+
+ if (declaredType != null)
+ {
+ while (tree.Count > 1)
+ {
+ var memberName = tree.First();
+ tree.RemoveAt(0);
+ var member = declaredType.Symbols.FirstOrDefault(x => x.Name == memberName);
+
+ if (member == null)
+ {
+ return null;
+ }
+
+ declaredType = _declaredTypes.FirstOrDefault(x => x.ContainingNamespace + "." + x.Name == member.ContainingNamespace + "." + member.Type);
+ }
+
+ return declaredType;
+ }
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private void ShowPopup(Object content)
+ {
+ var position = TextArea.Caret.Position;
+ var textView = TextArea.TextView;
+
+ var visualLocation = textView.GetVisualPosition(position, VisualYPosition.LineBottom);
+ var visualLocationTop = textView.GetVisualPosition(position, VisualYPosition.LineTop);
+
+ Point location = textView.PointToScreen(visualLocation - textView.ScrollOffset);
+ Point locationTop = textView.PointToScreen(visualLocationTop - textView.ScrollOffset);
+
+ _popup.Placement = PlacementMode.Absolute;
+ _popup.PlacementRectangle = new Rect(location, new Size(200, 100));
+
+ CurrentPopupContent = content;
+
+ _popup.IsOpen = true;
+ }
+
+ private void HidePopup()
+ {
+ _popup.IsOpen = false;
+ CurrentPopupContent = null;
+ }
+
+ private MethodPopup CreateConstructionSessionPopupContent(ConstructionSession session)
+ {
+ MethodPopup popup = new MethodPopup();
+
+ foreach (var c in session.Type.Constructors)
+ {
+ MethodDescription method = new MethodDescription();
+ method.ReturnType = session.Type.Name;
+ method.Description = c.Summary;
+
+ if (session.Type.Type.IsGenericType && session.TypeArguments != null)
+ {
+ method.ReturnType = new String(session.Type.Name.TakeWhile(x => x != '`').ToArray()) + $"<{String.Join(",", session.TypeArguments)}>";
+ }
+
+ var parameters = c.Parameters;
+
+ foreach (var p in parameters)
+ {
+ ParameterDescription pDescription = new ParameterDescription(method);
+ pDescription.Name = p.Name;
+ pDescription.Type = p.Type;
+ pDescription.Description = p.Description;
+ method.Parameters.Add(pDescription);
+ }
+
+ popup.Methods.Add(method);
+ }
+
+ if (session.ParameterIndex > 0)
+ {
+ popup.CurrentMethod = popup.Methods.FirstOrDefault(x => x.Parameters.Count == session.ParameterIndex + 1);
+
+ if (popup.CurrentMethod == null)
+ {
+ popup.CurrentMethod = popup.Methods.FirstOrDefault();
+ }
+ }
+ else
+ {
+ popup.CurrentMethod = popup.Methods.FirstOrDefault();
+ }
+
+ if (popup.CurrentMethod != null)
+ {
+ popup.CurrentMethodIndex = popup.Methods.IndexOf(popup.CurrentMethod) + 1;
+ }
+
+ return popup;
+ }
+
+ private MethodPopup CreateMethodSessionPopupContent(MethodSession session)
+ {
+ MethodPopup popup = new MethodPopup();
+
+ foreach (var m in session.Type.Methods.Where(x => x.Name == session.MethodName))
+ {
+ MethodDescription method = new MethodDescription();
+ method.ReturnType = session.Type.Name;
+ method.Description = m.Summary;
+ method.Name = m.NameWithTypeArguments;
+ method.Class = session.Type.FriendlyName;
+
+ //if (session.Type.Type.IsGenericType && session.TypeArguments != null)
+ //{
+ // method.ReturnType = new String(session.Type.Name.TakeWhile(x => x != '`').ToArray()) + $"<{String.Join(",", session.TypeArguments)}>";
+ //}
+
+ var parameters = m.Parameters;
+
+ foreach (var p in parameters)
+ {
+ ParameterDescription pDescription = new ParameterDescription(method);
+ pDescription.Name = p.Name;
+ pDescription.Type = p.Type;
+ pDescription.Description = p.Description;
+ method.Parameters.Add(pDescription);
+ }
+
+ popup.Methods.Add(method);
+ }
+
+ if (session.ParameterIndex > 0)
+ {
+ popup.CurrentMethod = popup.Methods.FirstOrDefault(x => x.Parameters.Count == session.ParameterIndex + 1);
+
+ if (popup.CurrentMethod == null)
+ {
+ popup.CurrentMethod = popup.Methods.FirstOrDefault();
+ }
+ }
+ else
+ {
+ popup.CurrentMethod = popup.Methods.FirstOrDefault();
+ }
+
+ if (popup.CurrentMethod != null)
+ {
+ popup.CurrentMethodIndex = popup.Methods.IndexOf(popup.CurrentMethod) + 1;
+ }
+
+ return popup;
+ }
+
+ private MethodPopup CreateDeclaredMethodSessionPopupContent(DeclaredMethodSession session)
+ {
+ MethodPopup popup = new MethodPopup();
+
+ MethodDescription method = new MethodDescription();
+ method.ReturnType = session.Method.Type;
+ method.Description = session.Method.Summary;
+ method.Name = session.Method.Name;
+ method.Class = session.Method.Class;
+
+ //if (session.Type.Type.IsGenericType && session.TypeArguments != null)
+ //{
+ // method.ReturnType = new String(session.Type.Name.TakeWhile(x => x != '`').ToArray()) + $"<{String.Join(",", session.TypeArguments)}>";
+ //}
+
+ foreach (var p in session.Method.Parameters)
+ {
+ ParameterDescription pDescription = new ParameterDescription(method);
+ pDescription.Type = p.Key;
+ pDescription.Name = p.Value;
+ method.Parameters.Add(pDescription);
+ }
+
+ popup.Methods.Add(method);
+
+ //if (false)
+ //{
+ // popup.CurrentMethod = popup.Methods.FirstOrDefault(x => x.Parameters.Count == session.ParameterIndex + 1);
+
+ // if (popup.CurrentMethod == null)
+ // {
+ // popup.CurrentMethod = popup.Methods.FirstOrDefault();
+ // }
+ //}
+ //else
+ //{
+ popup.CurrentMethod = popup.Methods.FirstOrDefault();
+ //}
+
+ if (popup.CurrentMethod != null)
+ {
+ popup.CurrentMethodIndex = popup.Methods.IndexOf(popup.CurrentMethod) + 1;
+ }
+
+ return popup;
+ }
+
+ private void InvalidateHighlighting()
+ {
+ if (!_isLoadingTypes)
+ {
+ _isLoadingTypes = true;
+ _knownTypes.Clear();
+
+ var assemblies = ReferenceAssemblies.ToList();
+ var usings = _current_usings.ToList();
+
+ Thread t = new Thread(() =>
+ {
+ foreach (var asm in assemblies.Select(x => x.Assembly))
+ {
+ Parallel.ForEach(asm.GetTypes().Where(x => x.IsVisible && x.IsPublic && !x.IsPrimitive), (type) =>
+ {
+ if (usings.Exists(x => type.Namespace == x))
+ {
+ lock (_knownTypes)
+ {
+ if (!_knownTypes.Exists(x => x.Type.FullName == type.FullName))
+ {
+ _knownTypes.Add(new KnownType(type));
+ }
+ }
+ }
+ });
+ }
+
+ 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.BeginInvoke(new Action(() =>
+ {
+ SyntaxHighlighting = HighlightingLoader.Load(xshd_reader, HighlightingManager.Instance);
+ xshd_reader.Close();
+ ms.Dispose();
+ }));
+
+
+ foreach (var knownType in _knownTypes)
+ {
+ knownType.LoadDocumentation();
+ }
+ }
+
+ _isLoadingTypes = false;
+ });
+ t.IsBackground = true;
+ t.Start();
+ }
+ }
+
+ private void InvalidateScriptTypesHighlightings()
+ {
+ var declaredTypes = _parser.GetDeclaredTypes(Text);
+
+ if (declaredTypes.Exists(x => !_declaredTypes.Exists(y => y.Name == x.Name)) || _declaredTypes.Exists(x => !declaredTypes.Exists(y => y.Name == x.Name)))
+ {
+ _declaredTypes = declaredTypes;
+ InvalidateHighlighting();
+ }
+
+ _declaredTypes = declaredTypes;
+
+ //for (int i = 0; i < TextArea.TextView.LineTransformers.Count; i++)
+ //{
+ // if (TextArea.TextView.LineTransformers[i] is OffsetColorizer)
+ // {
+ // TextArea.TextView.LineTransformers.RemoveAt(i);
+ // }
+ //}
+
+ //foreach (var cls in scriptClasses)
+ //{
+ // Document.BeginUpdate();
+
+ // var line = Document.GetLineByOffset(cls.Index);
+
+ // OffsetColorizer colorizer = new OffsetColorizer(line, cls.Index, cls.Index + cls.Name.Length, Brushes.Red);
+ // TextArea.TextView.LineTransformers.Add(colorizer);
+
+ // Document.EndUpdate();
+ //}
+ }
+
+ private void InvalidateUsings()
+ {
+ var oldUsings = _current_usings.ToList();
+ _current_usings = _parser.GetUsings(Text);
+
+ if (_current_usings.Exists(x => !oldUsings.Exists(y => y == x)) || oldUsings.Exists(x => !_current_usings.Exists(y => y == x)))
+ {
+ InvalidateHighlighting();
+ }
+ }
+
+ private void InvalidateFolding()
+ {
+ if (EnableFolding)
+ {
+ if (foldingManager == null)
+ {
+ foldingManager = FoldingManager.Install(TextArea);
+ }
+
+ foldingStrategy.UpdateFoldings(foldingManager, Document);
+ }
+ }
+
+ private void IndentCode()
+ {
+ Text = Indentation.CSharp.CSharpIndentationHelper.IndentCSharpCode(Text);
+ //Text = _parser.IndentCSharpCode(Text);
+ }
+
+ internal DocumentLine GetCurrentLine()
+ {
+ int offset = CaretOffset;
+ var line = Document.GetLineByOffset(offset);
+ return line;
+ }
+
+ private String GetCurrentLineText()
+ {
+ var text = Document.GetText(GetCurrentLine());
+ return text;
+ }
+
+ internal String GetCurrentWord()
+ {
+ return GetWordByEndIndex(CaretOffset);
+ }
+
+ private String GetWordByEndIndex(int index)
+ {
+ String word = String.Empty;
+ var line = GetCurrentLine();
+
+ int position = index;
+
+ for (int i = position - 1; i >= line.Offset; i--)
+ {
+ char c = Document.GetText(i, 1).First();
+
+ if (word_separators.Contains(c))
+ {
+ break;
+ }
+
+ word += c;
+ }
+
+ word = new string(word.Reverse().ToArray());
+
+ if (word.Length > 0)
+ {
+ word = word.Replace(".", "");
+ }
+
+ return word;
+ }
+
+ internal int GetCurrentWordStartIndex()
+ {
+ var line = GetCurrentLine();
+
+ int position = CaretOffset;
+
+ for (int i = position - 1; i >= line.Offset; i--)
+ {
+ char c = Document.GetText(i, 1).First();
+
+ if (word_separators.Contains(c))
+ {
+ return i + 1;
+ }
+ }
+
+ return line.Offset;
+ }
+
+ private String GetPreviousWord()
+ {
+ int index = GetCurrentWordStartIndex() - 1;
+ return GetWordByEndIndex(index);
+ }
+
+ private ConstructionSession GetConstructionSession()
+ {
+ var expression = _parser.GetCurrentConstructionExpression(GetCurrentLineText());
+
+ if (expression != 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 == "(")
+ {
+ var typeDeclaration = expression.Type as GenericNameSyntax;
+
+ KnownType type = null;
+
+ if (typeDeclaration != null)
+ {
+ var typeName = typeDeclaration.Identifier.ToString();
+ var argumentsCount = typeDeclaration.TypeArgumentList.Arguments.Count;
+ session.TypeArguments = typeDeclaration.TypeArgumentList.Arguments.Select(x => x.ToString()).ToList();
+
+ if (argumentsCount == 0)
+ {
+ type = _knownTypes.FirstOrDefault(x => x.Type.Name == expression.Type.ToString());
+ }
+ else
+ {
+ type = _knownTypes.FirstOrDefault(x => x.Type.Name == typeName + "`" + argumentsCount);
+ }
+ }
+ else
+ {
+ type = _knownTypes.FirstOrDefault(x => x.Name == expression.Type.ToString());
+ }
+
+ 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(' ');
+
+ if (words.Count() > 0 && (words.First() == "private" || words.First() == "public" || words.First() == "void"))
+ {
+ return null;
+ }
+
+ 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 = variables.FirstOrDefault(x => x.Name == variableName);
+
+ if (variable != null)
+ {
+ var knownType = _knownTypes.FirstOrDefault(x => x.FriendlyName == Regex.Replace(variable.Type, "<.+>", "<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 words = GetCurrentLineText().Split(' ');
+
+ if (words.Count() > 0 && (words.First() == "private" || words.First() == "public" || words.First() == "void"))
+ {
+ return null;
+ }
+
+ var expression = GetPreviousWords().LastOrDefault();
+
+ if (expression != null)
+ {
+ var tree = expression.Split('.').Select(x => x.Replace("\n", "").Replace("\r", "").Replace(" ", "").Replace("\t", "").Replace("(", "").Replace(")", "").Replace("[", "").Replace("]", "")).ToList();
+ var variableName = tree.FirstOrDefault();
+
+ if (variableName != null && tree.Count > 0)
+ {
+ tree.RemoveAt(0);
+ var variables = _parser.GetContextSymbols(Document.Text, CaretOffset);
+ var variable = variables.FirstOrDefault(x => x.Name == variableName);
+
+ if (variable != null)
+ {
+ var declaredType = _declaredTypes.FirstOrDefault(x => x.Name == Regex.Replace(variable.Class, "<.+>", "<T>"));
+
+ if (declaredType != null)
+ {
+ while (tree.Count > 1)
+ {
+ var memberName = tree.First();
+ tree.RemoveAt(0);
+ var member = declaredType.Symbols.FirstOrDefault(x => x.Name == memberName);
+
+ if (member == null)
+ {
+ return null;
+ }
+
+ declaredType = _declaredTypes.FirstOrDefault(x => x.ContainingNamespace + "." + x.Name == member.ContainingNamespace + "." + member.Type);
+ }
+
+ var methodName = tree.Count > 0 ? tree.Last() : variableName;
+
+ var method = declaredType.Symbols.FirstOrDefault(x => x.Kind == SymbolKind.Method && x.Name == methodName);
+
+ if (method != null)
+ {
+ return new DeclaredMethodSession()
+ {
+ Type = declaredType,
+ Method = method,
+ };
+ }
+ }
+ else if (tree.Count == 0)
+ {
+ var method = variable;
+
+ if (method != null)
+ {
+ return new DeclaredMethodSession()
+ {
+ Type = declaredType,
+ Method = method,
+ };
+ }
+ }
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private List<String> GetPreviousWords()
+ {
+ var currentLine = GetCurrentLine();
+ var currentText = Document.GetText(currentLine.Offset, CaretOffset - currentLine.Offset);
+ return currentText.Split(' ', ',').ToList();
+ }
+
+ #endregion
+ }
+}