aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/Tango.CodeGeneration/EntityInheritedCodeFile.cs
blob: e9c8ac717d7d39b8fcf06a04b4713792d62f4919 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Tango.CodeGeneration
{
    public class EntityInheritedCodeFile : Class
    {
        public String BaseClass { get; set; }

        public EntityInheritedCodeFile(String name, String baseClass)
        {
            Name = name;
            BaseClass = baseClass;
        }
    }
}
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
    }
}