aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.Common/Controls/RealTimeGraphMultiControl.xaml.cs
blob: 8e3b6b6e3845f72f11ea87a10c76cbb3149cdadd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
using RealTimeGraphEx;
using RealTimeGraphEx.Controllers;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace Tango.MachineStudio.Common.Controls
{
    /// <summary>
    /// Interaction logic for RealTimeGraphControl.xaml
    /// </summary>
    public partial class RealTimeGraphMultiControl : UserControl , IRealTimeGraph
    {
        private Grid headerGrid;

        #region Properties

        /// <summary>
        /// Gets or sets the name of the sensor.
        /// </summary>
        public String SensorName
        {
            get { return (String)GetValue(SensorNameProperty); }
            set { SetValue(SensorNameProperty, value); }
        }
        public static readonly DependencyProperty SensorNameProperty =
            DependencyProperty.Register("SensorName", typeof(String), typeof(RealTimeGraphMultiControl), new PropertyMetadata(null));

        /// <summary>
        /// Gets or sets the sensor units.
        /// </summary>
        public String SensorUnits
        {
            get { return (String)GetValue(SensorUnitsProperty); }
            set { SetValue(SensorUnitsProperty, value); }
        }
        public static readonly DependencyProperty SensorUnitsProperty =
            DependencyProperty.Register("SensorUnits", typeof(String), typeof(RealTimeGraphMultiControl), new PropertyMetadata(null));

        public double Minimum
        {
            get { return (double)GetValue(MinimumProperty); }
            set { SetValue(MinimumProperty, value); }
        }
        public static readonly DependencyProperty MinimumProperty =
            DependencyProperty.Register("Minimum", typeof(double), typeof(RealTimeGraphMultiControl), new PropertyMetadata(0.0));



        public double Maximum
        {
            get { return (double)GetValue(MaximumProperty); }
            set { SetValue(MaximumProperty, value); }
        }
        public static readonly DependencyProperty MaximumProperty =
            DependencyProperty.Register("Maximum", typeof(double), typeof(RealTimeGraphMultiControl), new PropertyMetadata(100.0));

        public void InvalidateGraph()
        {
            InnerGraph.Clear();
            yAxis.Render(InnerGraph);
            yAxisTicks.Render(InnerGraph);
        }

        /// <summary>
        /// Gets or sets the inner real-time graph control.
        /// </summary>
        public RealTimeGraphExBase InnerGraph { get; set; }

        /// <summary>
        /// Gets or sets the inner graph controller.
        /// </summary>
        public GraphControllerBase Controller { get; set; }

        private bool _enableToolbar;
        /// <summary>
        /// Gets or sets a value indicating whether to enable toolbar buttons.
        /// </summary>
        public bool EnableToolBar
        {
            get { return _enableToolbar; }
            set
            {
                _enableToolbar = value;

                if (!value)
                {
                    if (headerGrid != null)
                    {
                        ThicknessAnimation ani = new ThicknessAnimation();
                        ani.To = new Thickness(0, -35, 0, 0);
                        ani.Duration = TimeSpan.FromSeconds(0.2);
                        headerGrid.BeginAnimation(Grid.MarginProperty, ani);
                    }
                }
            }
        }

        #endregion

        #region Events

        public event EventHandler GraphRemoveButtonPressed;
        public event EventHandler GraphFullScreenButtonPressed;

        #endregion

        public RealTimeGraphMultiControl()
        {
            InitializeComponent();
            EnableToolBar = true;
            InnerGraph = Graph;
            Controller = new GraphMultiController();
        }

        private void OnGraphFullScreen(object sender, RoutedEventArgs e)
        {
            GraphFullScreenButtonPressed?.Invoke(this, new EventArgs());
        }

        private void Graph_MouseEnter(object sender, MouseEventArgs e)
        {
            if (EnableToolBar)
            {
                Grid mainGrid = sender as Grid;
                headerGrid = mainGrid.Children.OfType<Grid>().ToList().First();
                ThicknessAnimation ani = new ThicknessAnimation();
                ani.To = new Thickness(0, 0, 0, 0);
                ani.Duration = TimeSpan.FromSeconds(0.2);
                headerGrid.BeginAnimation(Grid.MarginProperty, ani);
            }
        }

        private void Graph_MouseLeave(object sender, MouseEventArgs e)
        {
            Grid mainGrid = sender as Grid;
            headerGrid = mainGrid.Children.OfType<Grid>().ToList().First();
            ThicknessAnimation ani = new ThicknessAnimation();
            ani.To = new Thickness(0, -35, 0, 0);
            ani.Duration = TimeSpan.FromSeconds(0.2);
            headerGrid.BeginAnimation(Grid.MarginProperty, ani);
        }

        private void OnGraphRemove(object sender, RoutedEventArgs e)
        {
            GraphRemoveButtonPressed?.Invoke(this, new EventArgs());
        }
    }
}
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel.Design;
using System.Diagnostics;
using System.IO;
using System.Linq;
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;
using Tango.Core.Commands;
using Tango.Scripting.Core;
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.Formatting;
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" };

        public event EventHandler<BreakPointSymbolPressedEventArgs> BreakPointSymbolPressed;

        private DispatcherTimer _update_timer;
        private BreakPointMargin breakPointMargin;
        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;
        private TextMarkerService errorMarkerService;
        private List<ScriptBreakPointSymbol> _breakPointSymbols;
        private int _breakPointLineNumber;
        private ScriptBreakPointSymbol _currentBreakPointSymbol;
        private Point _currentBreakPointSymbolPosition;

        private static JsonSerializerSettings _jsonSettings;
        private static Dictionary<Type, KnownType> _knownTypesCache;
        private static String KNOWN_TYPES_CACHE_FOLDER;
        private static List<CachedAssembly> _cachedAssemblies;
        private static List<CachedUsing> _cachedUsings;
        private static bool _isLoadingCachedAssemblies;
        private static bool _isCacheAssembliesLoaded;
        private static bool _isUsingsLoadingStarted;
        private static object _loadUsingsLock = new object();
        private static List<SnippetCompletionItem> snippets;

        public static event EventHandler<TangoProgressChangedEventArgs<int>> LoadingSymbolsProgress;
        public static event EventHandler LoadingSymbolsStarted;
        public static event EventHandler LoadingSymbolsCompleted;
        private static event EventHandler KnownTypesAvailable;
        public static event EventHandler UsingsLoadingStarted;
        public static event EventHandler UsingsLoadingCompleted;

        #region Mini Classes

        private class KnownTypeResult
        {
            public KnownType KnownType { get; set; }
            public bool IsStatic { get; set; }

            public KnownTypeResult()
            {

            }

            public KnownTypeResult(KnownType knownType)
            {
                KnownType = knownType;
            }
        }

        private class ScriptClass
        {
            public String Name { get; set; }
            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

        public static List<String> BlockedUsingsCache { get; set; }

        /// <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<Assembly> ReferenceAssemblies
        {
            get { return (ObservableCollection<Assembly>)GetValue(ReferenceAssembliesProperty); }
            set { SetValue(ReferenceAssembliesProperty, value); }
        }
        public static readonly DependencyProperty ReferenceAssembliesProperty =
            DependencyProperty.Register("ReferenceAssemblies", typeof(ObservableCollection<Assembly>), typeof(ScriptEditor), new PropertyMetadata(null, (d, e) => (d as ScriptEditor).OnReferenceAssembliesChanged()));

        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));

        public String Code
        {
            get { return (String)GetValue(CodeProperty); }
            set { SetValue(CodeProperty, value); }
        }
        public static readonly DependencyProperty CodeProperty =
            DependencyProperty.Register("Code", typeof(String), typeof(ScriptEditor), new PropertyMetadata(null, (d, e) => (d as ScriptEditor).OnCodeChanged()));

        public ObservableCollection<IScriptSource> AdditionalScripts
        {
            get { return (ObservableCollection<IScriptSource>)GetValue(AdditionalScriptsProperty); }
            set { SetValue(AdditionalScriptsProperty, value); }
        }
        public static readonly DependencyProperty AdditionalScriptsProperty =
            DependencyProperty.Register("AdditionalScripts", typeof(ObservableCollection<IScriptSource>), typeof(ScriptEditor), new PropertyMetadata(null));

        public Brush ColorizeBrush
        {
            get { return (Brush)GetValue(ColorizeBrushProperty); }
            set { SetValue(ColorizeBrushProperty, value); }
        }
        public static readonly DependencyProperty ColorizeBrushProperty =
            DependencyProperty.Register("ColorizeBrush", typeof(Brush), typeof(ScriptEditor), new PropertyMetadata(new SolidColorBrush(Colors.YellowGreen) { Opacity = 0.5 }));

        public Brush ErrorLineBrush
        {
            get { return (Brush)GetValue(ErrorLineBrushProperty); }
            set { SetValue(ErrorLineBrushProperty, value); }
        }
        public static readonly DependencyProperty ErrorLineBrushProperty =
            DependencyProperty.Register("ErrorLineBrush", typeof(Brush), typeof(ScriptEditor), new PropertyMetadata(new SolidColorBrush(Colors.Red) { Opacity = 0.5 }));

        public Brush DebugLineBrush
        {
            get { return (Brush)GetValue(DebugLineBrushProperty); }
            set { SetValue(DebugLineBrushProperty, value); }
        }
        public static readonly DependencyProperty DebugLineBrushProperty =
            DependencyProperty.Register("DebugLineBrush", typeof(Brush), typeof(ScriptEditor), new PropertyMetadata(new SolidColorBrush(Colors.Gray) { Opacity = 0.5 }));

        public Brush BreakPointLineBrush
        {
            get { return (Brush)GetValue(BreakPointLineBrushProperty); }
            set { SetValue(BreakPointLineBrushProperty, value); }
        }
        public static readonly DependencyProperty BreakPointLineBrushProperty =
            DependencyProperty.Register("BreakPointLineBrush", typeof(Brush), typeof(ScriptEditor), new PropertyMetadata(new SolidColorBrush(Colors.Yellow) { Opacity = 0.5 }));

        public IScriptSource ScriptSource
        {
            get { return (IScriptSource)GetValue(ScriptSourceProperty); }
            set { SetValue(ScriptSourceProperty, value); }
        }
        public static readonly DependencyProperty ScriptSourceProperty =
            DependencyProperty.Register("ScriptSource", typeof(IScriptSource), typeof(ScriptEditor), new PropertyMetadata(null));

        public bool DisableBreakPoints
        {
            get { return (bool)GetValue(DisableBreakPointsProperty); }
            set { SetValue(DisableBreakPointsProperty, value); }
        }
        public static readonly DependencyProperty DisableBreakPointsProperty =
            DependencyProperty.Register("DisableBreakPoints", typeof(bool), typeof(ScriptEditor), new PropertyMetadata(false));


        #endregion

        #region Constructors

        /// <summary>
        /// Initializes the <see cref="ScriptEditor"/> class.
        /// </summary>
        static ScriptEditor()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(ScriptEditor), new FrameworkPropertyMetadata(typeof(ScriptEditor)));

            snippets = new List<SnippetCompletionItem>();

            BlockedUsingsCache = new List<string>();

            if (KNOWN_TYPES_CACHE_FOLDER == null)
            {
                KNOWN_TYPES_CACHE_FOLDER = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Twine", "Tango", "Scripting", "Cache");
                Directory.CreateDirectory(KNOWN_TYPES_CACHE_FOLDER);
            }

            _jsonSettings = new JsonSerializerSettings()
            {
                TypeNameHandling = TypeNameHandling.Auto,
                PreserveReferencesHandling = PreserveReferencesHandling.All
            };

            _knownTypesCache = new Dictionary<Type, KnownType>();
            _cachedAssemblies = new List<CachedAssembly>();
            _cachedUsings = new List<CachedUsing>();

            snippets.Add(new SnippetCompletionItem()
            {
                Name = "for",
                Code = @"for (int i = 0; i < 10; i++)
        {
            
        }"
            });

            snippets.Add(new SnippetCompletionItem()
            {
                Name = "while",
                Code = @"while (true)
        {
            
        }"
            });

            snippets.Add(new SnippetCompletionItem()
            {
                Name = "foreach",
                Code = @"foreach (var item in items)
        {
            
        }"
            });

            snippets.Add(new SnippetCompletionItem()
            {
                Name = "prop",
                Code = @"public int MyProperty { get; set; }"
            });

            snippets.Add(new SnippetCompletionItem()
            {
                Name = "do",
                Code = @"do
        {
            
        } while (true)"
            });

            snippets.Add(new SnippetCompletionItem()
            {
                Name = "try",
                Code = @"try
        {
                
        }
        catch (Exception ex)
        {
            
        }"
            });

            snippets.Add(new SnippetCompletionItem()
            {
                Name = "cw",
                Code = "context.WriteLine(\"\");"
            });
        }

        /// <summary>
        /// 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

            _knownTypes = new List<KnownType>();
            _parser = new ScriptParser();

            KnownTypesAvailable += ScriptEditor_KnownTypesAvailable;

            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;

            TextChanged += ScriptEditor_TextChanged;

            errorMarkerService = new TextMarkerService(Document);
            TextArea.TextView.BackgroundRenderers.Add(errorMarkerService);
            TextArea.TextView.LineTransformers.Add(errorMarkerService);

            Unloaded += ScriptEditor_Unloaded;

            breakPointMargin = new BreakPointMargin(this);
            _breakPointSymbols = new List<ScriptBreakPointSymbol>();
            Loaded += ScriptEditor_Loaded;

            MouseMove += ScriptEditor_MouseMove;
        }

        private void ScriptEditor_Loaded(object sender, RoutedEventArgs e)
        {
            TextArea.LeftMargins.Insert(0, breakPointMargin);
        }

        private void ScriptEditor_Unloaded(object sender, RoutedEventArgs e)
        {
            _update_timer.Stop();
        }

        private void ScriptEditor_KnownTypesAvailable(object sender, EventArgs e)
        {
            if (sender != this)
            {
                InvalidateHighlightingPartial();
            }
        }

        private bool preventCodeUpdate;
        private void ScriptEditor_TextChanged(object sender, EventArgs e)
        {
            if (!preventCodeUpdate)
            {
                preventCodeUpdate = true;
                Code = Text;
                preventCodeUpdate = false;
            }
        }

        private void OnCodeChanged()
        {
            if (!preventCodeUpdate)
            {
                preventCodeUpdate = true;
                Text = Code;
                preventCodeUpdate = false;
            }
        }

        #endregion

        #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)
        {
            if (IsReadOnly) return;

            try
            {
                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 knownTypeResult = GetKnownTypeFromExpression(expression + ".");

                    if (knownTypeResult != null && knownTypeResult.KnownType.Type.IsEnum)
                    {
                        completionWindow.HideCompletion();
                        IList<ICompletionData> data = new List<ICompletionData>();

                        foreach (var field in knownTypeResult.KnownType.Fields)
                        {
                            data.Add(new FieldCompletionItem()
                            {
                                Class = knownTypeResult.KnownType.FriendlyName,
                                Name = knownTypeResult.KnownType.FriendlyName + "." + field.Name,
                                Type = field.ReturnTypeFriendlyName,
                                Description = field.Summary,
                            });
                        }

                        ShowCompletionWindow(data.OrderBy(x => x.Text).ToList(), GetCurrentWord());
                    }

                }
                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 knownTypeResult = GetCurrentKnownType();

                    IList<ICompletionData> data = new List<ICompletionData>();

                    if (knownTypeResult != null)
                    {
                        completionWindow.HideCompletion();

                        if (!knownTypeResult.KnownType.Type.IsEnum)
                        {
                            var typeMembers = knownTypeResult.KnownType.Members.ToList();

                            foreach (var methodGroup in typeMembers.OfType<KnownTypeMethod>().Where(x => (!knownTypeResult.IsStatic && !x.IsStatic) || (knownTypeResult.IsStatic && x.IsStatic)).GroupBy(x => x.NameWithTypeArguments))
                            {
                                var method = methodGroup.First();

                                data.Add(new MethodCompletionItem()
                                {
                                    Class = knownTypeResult.KnownType.FriendlyName,
                                    Name = method.NameWithTypeArguments,
                                    ReturnType = method.ReturnTypeFriendlyName,
                                    Description = method.Summary,
                                    Parameters = method.Parameters,
                                    Overloads = methodGroup.Count() - 1,
                                });
                            }

                            foreach (var ev in typeMembers.OfType<KnownTypeEvent>())
                            {
                                data.Add(new EventCompletionItem()
                                {
                                    Class = knownTypeResult.KnownType.FriendlyName,
                                    Name = ev.Name,
                                    Description = ev.Summary,
                                });
                            }

                            foreach (var methodGroup in typeMembers.Where(x => x.GetType() != typeof(KnownTypeMethod) && x.GetType() != typeof(KnownTypeEvent)).GroupBy(x => x.Name))
                            {
                                var member = methodGroup.First();

                                data.Add(new PropertyCompletionItem()
                                {
                                    Class = knownTypeResult.KnownType.FriendlyName,
                                    Name = member.Name,
                                    Type = member.ReturnTypeFriendlyName,
                                    Description = member.Summary,
                                });
                            }
                        }
                        else
                        {
                            foreach (var field in knownTypeResult.KnownType.Fields)
                            {
                                data.Add(new FieldCompletionItem()
                                {
                                    Class = knownTypeResult.KnownType.FriendlyName,
                                    Name = field.Name,
                                    Type = field.ReturnTypeFriendlyName,
                                    Description = field.Summary,
                                });

                            }
                        }

                        ShowCompletionWindow(data.OrderBy(x => x.Text).ToList(), GetCurrentWord());
                    }
                    else
                    {
                        var declaredType = GetCurrentDeclaredType();

                        if (declaredType != null)
                        {
                            completionWindow.HideCompletion();

                            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;
                            }
                        }

                        var staticMethodSession = GetStaticMethodSession();

                        if (staticMethodSession != null)
                        {
                            var content = CreateMethodSessionPopupContent(staticMethodSession);
                            if (content.Methods.Count > 0)
                            {
                                ShowPopup(content);
                                return;
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        Debug.WriteLine(ex);
                    }
                }
                else if (lineText.StartsWith("using") && e.Text != "\n")
                {
                    if (completionWindow.IsVisible)
                    {
                        completionWindow.UpdatePositionFix();
                        return;
                    }

                    IList<ICompletionData> data = new List<ICompletionData>();

                    foreach (var asm in ReferenceAssemblies)
                    {
                        foreach (var ns in asm.GetTypes().Select(x => x.Namespace).Distinct().Where(x => x != null))
                        {
                            data.Add(new NamespaceCompletionItem()
                            {
                                Name = ns,
                                Assembly = asm.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 snippet in snippets)
                        {
                            data.Add(snippet);
                        }

                        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);
                    }
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.ToString());
            }
        }

        #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.DistinctBy(x => x.Text))
            {
                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 KnownTypeResult GetCurrentKnownType()
        {
            var expression = GetPreviousWords().LastOrDefault();
            return GetKnownTypeFromExpression(expression);
        }

        private KnownTypeResult GetKnownTypeFromExpression(String expression)
        {
            if (expression != null)
            {
                var insideMethodExp = expression.Split('(').LastOrDefault();

                if (insideMethodExp != null)
                {
                    expression = insideMethodExp;
                }

                var tree = expression.Split('.').Select(x => x.Remove(@"\n|\t|\r|\(.*\)|\[.*\]|\s")).ToList();
                var variableName = tree.FirstOrDefault();

                if (variableName != null)
                {
                    //Search for enum type first
                    var enumType = _knownTypes.FirstOrDefault(x => x.Name == variableName && x.Type.IsEnum);

                    if (enumType != null)
                    {
                        return new KnownTypeResult(enumType);
                    }

                    tree.RemoveAt(0);
                    var variables = _parser.GetContextSymbols(Document.Text, CaretOffset);
                    var variable = variables.FirstOrDefault(x => x.Name == variableName);

                    if (variable != null)
                    {
                        var name = Regex.Replace(variable.Type, "<.+>", "<T>");
                        var knownType = _knownTypes.FirstOrDefault(x => name == x.FriendlyName || name == x.Alias);

                        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 KnownTypeResult(knownType);
                        }
                        else //Maybe a variable of a declared type...
                        {
                            if (tree.Count > 0)
                            {
                                var memberName = tree[0];
                                var declaredType = _declaredTypes.SingleOrDefault(x => x.Name == name);

                                if (declaredType != null)
                                {
                                    var member = declaredType.Symbols.FirstOrDefault(x => x.Name == memberName);
                                    if (member != null)
                                    {
                                        knownType = _knownTypes.SingleOrDefault(x => x.Name.ToLower() == member.Type.ToLower());

                                        if (knownType != null)
                                        {
                                            return new KnownTypeResult(knownType);
                                        }
                                    }
                                }
                            }
                        }
                    }
                    else
                    {
                        //Maybe static...
                        var type = _knownTypes.FirstOrDefault(x => x.Name == variableName || x.Alias == variableName);
                        return type != null ? new KnownTypeResult(type) { IsStatic = true } : null;
                    }
                }
            }

            return null;
        }

        private ScriptType GetCurrentDeclaredType()
        {
            var expression = GetPreviousWords().LastOrDefault();

            if (expression != null)
            {
                var insideMethodExp = expression.Split('(').LastOrDefault();

                if (insideMethodExp != null)
                {
                    expression = insideMethodExp;
                }

                var tree = expression.Split('.').Select(x => x.Remove(@"\n|\t|\r|\(.*\)|\[.*\]|\s")).ToList();
                var variableName = tree.FirstOrDefault();

                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;
                        }
                    }
                    else
                    {
                        //Maybe static...
                        return _declaredTypes.FirstOrDefault(x => x.Name == variableName);
                    }
                }
            }

            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 = m.ReturnTypeFriendlyName;
                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;
        }

        public void LoadUsingsSymbols(List<Assembly> assemblies, List<String> usings)
        {
            lock (_loadUsingsLock)
            {
                LoadingSymbolsStarted?.Invoke(null, new EventArgs());

                var allTypes = assemblies.SelectMany(x => x.GetTypes());

                foreach (var use in usings)
                {
                    if (!_cachedUsings.Exists(x => x.Namespace == use))
                    {
                        if (!_isUsingsLoadingStarted)
                        {
                            _isUsingsLoadingStarted = true;
                            UsingsLoadingStarted?.Invoke(this, new EventArgs());
                        }

                        var useFileName = System.IO.Path.Combine(KNOWN_TYPES_CACHE_FOLDER, use + ".json");

                        if (File.Exists(useFileName))
                        {
                            LoadingSymbolsProgress?.Invoke(null, new TangoProgressChangedEventArgs<int>()
                            {
                                Progress = new TangoProgress<int>()
                                {
                                    IsIndeterminate = true,
                                    Maximum = 100,
                                    Message = $"Loading symbols for '{use}'..."
                                }
                            });

                            CachedUsing cached = JsonConvert.DeserializeObject<CachedUsing>(File.ReadAllText(useFileName), _jsonSettings);
                            _cachedUsings.Add(cached);
                            foreach (var knownType in cached.KnownTypes)
                            {
                                _knownTypesCache.Add(knownType.Type, knownType);
                            }

                            KnownTypesAvailable?.Invoke(this, new EventArgs());
                            InvalidateHighlightingPartial();

                            continue;
                        }

                        var useTypes = allTypes.Where(x => x.IsVisible && x.IsPublic && x.Namespace == use).ToList();

                        CachedUsing cachedUsing = new CachedUsing();
                        cachedUsing.Namespace = use;
                        _cachedUsings.Add(cachedUsing);

                        int i = 1;

                        foreach (var type in useTypes)
                        {
                            LoadingSymbolsProgress?.Invoke(null, new TangoProgressChangedEventArgs<int>()
                            {
                                Progress = new TangoProgress<int>()
                                {
                                    IsIndeterminate = false,
                                    Maximum = useTypes.Count,
                                    Value = i++,
                                    Message = $"Loading symbols for '{use}'..."
                                }
                            });

                            KnownType knownType = new KnownType(type);

                            if (type.IsPrimitive)
                            {
                                if (type == typeof(Int32))
                                {
                                    knownType.Alias = "int";
                                }
                                else if (type == typeof(float))
                                {
                                    knownType.Alias = "float";
                                }
                                else if (type == typeof(Double))
                                {
                                    knownType.Alias = "double";
                                }
                                else if (type == typeof(long))
                                {
                                    knownType.Alias = "long";
                                }
                                else if (type == typeof(bool))
                                {
                                    knownType.Alias = "bool";
                                }
                                else if (type == typeof(uint))
                                {
                                    knownType.Alias = "uint";
                                }
                            }
                            else if (type == typeof(String))
                            {
                                knownType.Alias = "string";
                            }

                            _knownTypesCache.Add(type, knownType);
                            cachedUsing.KnownTypes.Add(knownType);
                            knownType.LoadDocumentation();
                        }

                        if (!BlockedUsingsCache.Exists(x => use.StartsWith(x)))
                        {
                            Task.Factory.StartNew(() =>
                            {
                                var json = JsonConvert.SerializeObject(cachedUsing, _jsonSettings);
                                File.WriteAllText(useFileName, json);
                            });
                        }
                    }
                }

                if (_isUsingsLoadingStarted)
                {
                    UsingsLoadingCompleted?.Invoke(this, new EventArgs());
                }

                LoadingSymbolsCompleted?.Invoke(null, new EventArgs());
            }
        }

        //public static void LoadCachedAssemblies(List<Assembly> assemblies, List<String> usings = null)
        //{
        //    if (_isLoadingCachedAssemblies) return;

        //    _isLoadingCachedAssemblies = true;

        //    LoadingSymbolsStarted?.Invoke(null, new EventArgs());

        //    if (!_isCacheAssembliesLoaded)
        //    {
        //        foreach (var file in System.IO.Directory.GetFiles(KNOWN_TYPES_CACHE_FOLDER))
        //        {
        //            try
        //            {
        //                LoadingSymbolsProgress?.Invoke(null, new TangoProgressChangedEventArgs<int>()
        //                {
        //                    Progress = new TangoProgress<int>()
        //                    {
        //                        IsIndeterminate = true,
        //                        Maximum = 100,
        //                        Message = $"Loading metadata cache for '{System.IO.Path.GetFileName(file)}'..."
        //                    }
        //                });

        //                var cachedAssembly = JsonConvert.DeserializeObject<CachedAssembly>(System.IO.File.ReadAllText(file), _jsonSettings);

        //                foreach (var knownType in cachedAssembly.KnownTypes)
        //                {
        //                    _knownTypesCache.Add(knownType.Type, knownType);
        //                }

        //                _cachedAssemblies.Add(cachedAssembly);
        //            }
        //            catch { }
        //        }

        //        _isCacheAssembliesLoaded = true;
        //    }

        //    foreach (var asm in assemblies)
        //    {
        //        if (!_cachedAssemblies.Exists(x => x.Name == asm.FullName))
        //        {
        //            String asmFileName = System.IO.Path.GetFileName(asm.Location);

        //            CachedAssembly cachedAssembly = new CachedAssembly();
        //            cachedAssembly.Name = asm.FullName;
        //            _cachedAssemblies.Add(cachedAssembly);

        //            var types = asm.GetTypes().Where(x => x.IsVisible && x.IsPublic).ToList();

        //            int i = 0;

        //            foreach (var type in types)
        //            {
        //                LoadingSymbolsProgress?.Invoke(null, new TangoProgressChangedEventArgs<int>()
        //                {
        //                    Progress = new TangoProgress<int>()
        //                    {
        //                        IsIndeterminate = false,
        //                        Maximum = types.Count,
        //                        Value = i++,
        //                        Message = $"Caching metadata for '{asmFileName}'..."
        //                    }
        //                });

        //                KnownType knownType = new KnownType(type);

        //                if (type.IsPrimitive)
        //                {
        //                    if (type == typeof(Int32))
        //                    {
        //                        knownType.Alias = "int";
        //                    }
        //                    else if (type == typeof(float))
        //                    {
        //                        knownType.Alias = "float";
        //                    }
        //                    else if (type == typeof(Double))
        //                    {
        //                        knownType.Alias = "double";
        //                    }
        //                    else if (type == typeof(long))
        //                    {
        //                        knownType.Alias = "long";
        //                    }
        //                    else if (type == typeof(bool))
        //                    {
        //                        knownType.Alias = "bool";
        //                    }
        //                    else if (type == typeof(uint))
        //                    {
        //                        knownType.Alias = "uint";
        //                    }
        //                }

        //                _knownTypesCache.Add(type, knownType);
        //                cachedAssembly.KnownTypes.Add(knownType);
        //                //knownType.LoadDocumentation();
        //            }

        //            String cachedAssemblyFile = System.IO.Path.Combine(KNOWN_TYPES_CACHE_FOLDER, asmFileName);
        //            File.WriteAllText(cachedAssemblyFile, JsonConvert.SerializeObject(cachedAssembly, _jsonSettings));
        //        }
        //    }

        //    LoadingSymbolsCompleted?.Invoke(null, new EventArgs());

        //    _isLoadingCachedAssemblies = false;
        //}

        private void InvalidateHighlightingPartial()
        {
            List<Assembly> assemblies = new List<Assembly>();
            Dispatcher.Invoke(() =>
            {
                assemblies = ReferenceAssemblies.ToList();
            });

            var usings = _current_usings.ToList();

            _knownTypes.Clear();

            foreach (var knownType in _knownTypesCache.ToList().Select(x => x.Value).ToList())
            {
                if (usings.Exists(x => knownType.Type.Namespace == x) && assemblies.Exists(x => x == knownType.Type.Assembly))
                {
                    lock (_knownTypes)
                    {
                        _knownTypes.Add(knownType);
                    }
                }
            }

            if (_knownTypes.Count > 0 || _declaredTypes.Count > 0)
            {
                String text = String.Empty;

                Stream xshd_stream = typeof(ScriptEditor).Assembly.GetManifestResourceStream("Tango.Scripting.Editors.Highlighting.Resources.CSharp-Mode.xshd");

                using (StreamReader reader = new StreamReader(xshd_stream))
                {
                    text = reader.ReadToEnd();
                }

                List<String> referenceTypes = new List<string>();
                List<String> interfaceTypes = new List<string>();

                lock (_knownTypes)
                {
                    foreach (var type in _knownTypes.ToList().Where(x => x != null))
                    {
                        String name = type.Name;

                        if (type.Type.ContainsGenericParameters)
                        {
                            name = new String(name.TakeWhile(x => x != '`').ToArray());
                        }

                        if (type.Type.IsInterface || type.Type.IsEnum)
                        {
                            interfaceTypes.Add(String.Format("<Word>{0}</Word>", name));
                        }
                        else if (type.Type.IsClass || (type.Type.IsValueType))
                        {
                            referenceTypes.Add(String.Format("<Word>{0}</Word>", name));
                        }
                    }
                }

                foreach (var type in _declaredTypes)
                {
                    if (type.Kind == TypeKind.Interface || type.Kind == TypeKind.Enum)
                    {
                        interfaceTypes.Add(String.Format("<Word>{0}</Word>", type.Name));
                    }
                    else if (type.Kind == TypeKind.Class)
                    {
                        referenceTypes.Add(String.Format("<Word>{0}</Word>", type.Name));
                    }
                }

                if (referenceTypes.Count > 0)
                {
                    text = text.Replace("<Word>@ReferenceTypes@</Word>", String.Join(Environment.NewLine, referenceTypes.Distinct()));
                }

                if (interfaceTypes.Count > 0)
                {
                    text = text.Replace("<Word>@InterfaceTypes@</Word>", String.Join(Environment.NewLine, interfaceTypes.Distinct()));
                }

                MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(text));

                XmlTextReader xshd_reader = new XmlTextReader(ms);

                Dispatcher.Invoke(new Action(() =>
                {
                    SyntaxHighlighting = HighlightingLoader.Load(xshd_reader, HighlightingManager.Instance);
                    xshd_reader.Close();
                    ms.Dispose();
                }));
            }
        }

        public void InvalidateHighlighting(bool loadKnownTypes = true)
        {
            if (!_isLoadingTypes)
            {
                _isLoadingTypes = true;

                var assemblies = ReferenceAssemblies.ToList();
                KnownType.ExtensionMethodsAssemblies = assemblies.ToList();
                var usings = _current_usings.ToList();

                Thread t = new Thread(() =>
                {
                    LoadUsingsSymbols(assemblies, usings);

                    if (loadKnownTypes)
                    {
                        _knownTypes.Clear();

                        foreach (var knownType in _knownTypesCache.ToList().Select(x => x.Value).ToList())
                        {
                            if (usings.Exists(x => knownType.Type.Namespace == x) && assemblies.Exists(x => x == knownType.Type.Assembly))
                            {
                                lock (_knownTypes)
                                {
                                    _knownTypes.Add(knownType);
                                }
                            }
                        }
                    }

                    if (_knownTypes.Count > 0 || _declaredTypes.Count > 0)
                    {
                        String text = String.Empty;

                        Stream xshd_stream = typeof(ScriptEditor).Assembly.GetManifestResourceStream("Tango.Scripting.Editors.Highlighting.Resources.CSharp-Mode.xshd");

                        using (StreamReader reader = new StreamReader(xshd_stream))
                        {
                            text = reader.ReadToEnd();
                        }

                        List<String> referenceTypes = new List<string>();
                        List<String> interfaceTypes = new List<string>();

                        lock (_knownTypes)
                        {
                            foreach (var type in _knownTypes.ToList().Where(x => x != null))
                            {
                                String name = type.Name;

                                if (type.Type.ContainsGenericParameters)
                                {
                                    name = new String(name.TakeWhile(x => x != '`').ToArray());
                                }

                                if (type.Type.IsInterface || type.Type.IsEnum)
                                {
                                    interfaceTypes.Add(String.Format("<Word>{0}</Word>", name));
                                }
                                else if (type.Type.IsClass || (type.Type.IsValueType))
                                {
                                    referenceTypes.Add(String.Format("<Word>{0}</Word>", name));
                                }
                            }
                        }

                        foreach (var type in _declaredTypes)
                        {
                            if (type.Kind == TypeKind.Interface || type.Kind == TypeKind.Enum)
                            {
                                interfaceTypes.Add(String.Format("<Word>{0}</Word>", type.Name));
                            }
                            else if (type.Kind == TypeKind.Class)
                            {
                                referenceTypes.Add(String.Format("<Word>{0}</Word>", type.Name));
                            }
                        }

                        if (referenceTypes.Count > 0)
                        {
                            text = text.Replace("<Word>@ReferenceTypes@</Word>", String.Join(Environment.NewLine, referenceTypes.Distinct()));
                        }

                        if (interfaceTypes.Count > 0)
                        {
                            text = text.Replace("<Word>@InterfaceTypes@</Word>", String.Join(Environment.NewLine, interfaceTypes.Distinct()));
                        }

                        MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(text));

                        XmlTextReader xshd_reader = new XmlTextReader(ms);

                        Dispatcher.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 (AdditionalScripts != null)
            {
                foreach (var script in AdditionalScripts)
                {
                    declaredTypes.AddRange(_parser.GetDeclaredTypes(script.Code));
                }
            }


            if (declaredTypes.Exists(x => !_declaredTypes.Exists(y => y.Name == x.Name)) || _declaredTypes.Exists(x => !declaredTypes.Exists(y => y.Name == x.Name)))
            {
                _declaredTypes = declaredTypes;
                InvalidateHighlighting(false);
            }

            _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 = CodeFormatter.Format(Text);
            //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 currentLine = GetCurrentLineText();

            //if (currentLine.Count(x => x == '(') > 1) return null;

            var expression = _parser.GetCurrentConstructionExpression(currentLine);

            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++;
                    }

                }
            }
            else
            {
                var expression2 = _parser.GetCurrentConstructionExpressionAlt(GetCurrentLineText());

                if (expression2 != null && expression2.Identifier != null)
                {
                    ConstructionSession session = new ConstructionSession();

                    var line = GetCurrentLine();
                    int parameterIndex = 0;
                    for (int i = CaretOffset; i > line.Offset; i--)
                    {
                        String c = Document.GetText(i, 1);

                        if (c == "(")
                        {
                            KnownType type = null;

                            if (expression2.Identifier != null)
                            {
                                var typeName = expression2.Identifier.ToString();
                                type = _knownTypes.FirstOrDefault(x => x.Type.Name == typeName);

                                if (type != null)
                                {
                                    session.Type = type;
                                    session.ParameterIndex = parameterIndex;
                                    return session;
                                }
                                else
                                {
                                    return null;
                                }
                            }
                        }
                        else if (c == ",")
                        {
                            parameterIndex++;
                        }
                    }
                }
            }

            return null;
        }

        private MethodSession GetMethodSession()
        {
            var currentLine = GetCurrentLineText();

            if (currentLine.Count(x => x == '(') > 1)
            {
                currentLine = currentLine.Split('(')[currentLine.Split('(').Length - 2];
            }

            currentLine = Regex.Replace(currentLine, "(?<=\")(.*?)(?=\")", string.Empty);

            var words = currentLine.Split(' ');

            if (words.Count() > 0 && (words.First() == "private" || words.First() == "public" || words.First() == "void"))
            {
                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 MethodSession GetStaticMethodSession()
        {
            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 = variableName;

                    if (variable != null)
                    {
                        var knownType = _knownTypes.FirstOrDefault(x => x.FriendlyName == Regex.Replace(variable, "<.+>", "<T>"));

                        if (knownType != null)
                        {
                            while (tree.Count > 1)
                            {
                                var memberName = tree.First();
                                tree.RemoveAt(0);
                                var member = knownType.Members.FirstOrDefault(x => x.Name == memberName);

                                if (member == null)
                                {
                                    return null;
                                }

                                knownType = _knownTypes.FirstOrDefault(x => x.Type.Namespace + "." + x.Type.Name == member.ReturnType.Namespace + "." + member.ReturnType.Name);
                            }

                            return new MethodSession()
                            {
                                Type = knownType,
                                MethodName = tree.Last(),
                                ParameterIndex = parameterIndex,
                            };
                        }
                    }
                }
            }

            return null;
        }

        private DeclaredMethodSession GetDeclaredMethodSession()
        {
            var currentLine = GetCurrentLineText();

            if (currentLine.Count(x => x == '(') > 1)
            {
                currentLine = currentLine.Split('(')[currentLine.Split('(').Length - 2];
            }

            var words = currentLine.Split(' ');

            if (words.Count() > 0 && (words.First() == "private" || words.First() == "public" || words.First() == "void"))
            {
                return null;
            }

            var expression = currentLine;

            if (expression != null)
            {
                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.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);
                            }

                            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

        #region Reference Assemblies Changed

        private void OnReferenceAssembliesChanged()
        {
            if (ReferenceAssemblies != null)
            {
                ReferenceAssemblies.CollectionChanged -= ReferenceAssemblies_CollectionChanged;
                ReferenceAssemblies.CollectionChanged += ReferenceAssemblies_CollectionChanged;

                InvalidateHighlighting();
            }
        }

        private void ReferenceAssemblies_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            InvalidateHighlighting();
        }

        #endregion

        #region Public Methods

        public void FormatCode()
        {
            try
            {
                int index = CaretOffset;
                Document.BeginUpdate();
                IndentCode();
                Document.EndUpdate();
                CaretOffset = index;
            }
            catch
            {
                Debug.WriteLine("Error formatting code.");
            }
        }

        public void Highlight(int position, int length, int line)
        {
            Select(position, Math.Max(length, 1));
            ScrollToLine(line);
        }

        public void InsertCode(String code)
        {
            Document.Insert(TextArea.Caret.Offset, code);
        }

        public int Find(String text)
        {
            if (String.IsNullOrEmpty(text)) return -1;

            string txt = Document.Text;
            int index = txt.IndexOf(text, TextArea.Caret.Offset);

            if (index > -1)
            {
                Select(index, text.Length);
                ScrollToLine(TextArea.Selection.StartPosition.Line);
            }
            else
            {
                index = txt.IndexOf(text, 0);

                if (index > -1)
                {
                    Select(index, text.Length);
                    ScrollToLine(TextArea.Selection.StartPosition.Line);
                }
                else
                {
                    Select(0, 0);
                    System.Media.SystemSounds.Beep.Play();
                }
            }

            return index;
        }

        public int ReplaceNext(String text, String replace)
        {
            if (String.IsNullOrEmpty(text)) return -1;

            String selectedText = TextArea.Selection.GetText();

            if (selectedText == text)
            {
                TextArea.Selection.ReplaceSelectionWithText(replace);
            }

            return Find(text);
        }

        public int ReplaceAll(String text, String replace)
        {
            int counter = 0;

            Select(0, 0);

            while (ReplaceNext(text, replace) > -1)
            {
                counter++;
            };

            return counter;
        }

        public void ColorizeByKeyword(String text)
        {
            ResetColorizationByKeyword();

            if (String.IsNullOrEmpty(text)) return;

            var txt = Document.Text;

            var indexes = txt.AllIndexesOf(text).ToList();

            foreach (var index in indexes)
            {
                Document.BeginUpdate();

                var line = Document.GetLineByOffset(index);

                OffsetColorizer colorizer = new OffsetColorizer(line, index, index + text.Length, ColorizeBrush);
                TextArea.TextView.LineTransformers.Add(colorizer);

                Document.EndUpdate();
            }
        }

        public void ResetColorizationByKeyword()
        {
            Document.BeginUpdate();

            for (int i = 0; i < TextArea.TextView.LineTransformers.Count; i++)
            {
                if (TextArea.TextView.LineTransformers[i] is OffsetColorizer)
                {
                    TextArea.TextView.LineTransformers.RemoveAt(i);
                    i--;
                }
            }

            Document.EndUpdate();
        }

        public void HighlighError(int position, int length)
        {
            try
            {
                ITextMarker marker = errorMarkerService.Create(position, length);
                marker.MarkerTypes = TextMarkerTypes.SquigglyUnderline;
                marker.MarkerColor = Colors.Red;
            }
            catch (Exception ex)
            {
                Debug.WriteLine($"Error highlighting script error.\n{ex.ToString()}");
            }
        }

        public void ClearErrors()
        {
            errorMarkerService.RemoveAll(m => true);
        }

        public void HighlightErrorLine(int lineNumber)
        {
            Document.BeginUpdate();

            var line = Document.GetLineByNumber(lineNumber);
            OffsetColorizer errorLineColrizer = new OffsetColorizer(line, line.Offset, line.EndOffset, ErrorLineBrush);
            TextArea.TextView.LineTransformers.Add(errorLineColrizer);

            Document.EndUpdate();
        }

        public void HighlightDebugLine(int lineNumber)
        {
            Document.BeginUpdate();

            var line = Document.GetLineByNumber(lineNumber);
            OffsetColorizer errorLineColrizer = new OffsetColorizer(line, line.Offset, line.EndOffset, DebugLineBrush);
            TextArea.TextView.LineTransformers.Add(errorLineColrizer);

            Document.EndUpdate();
        }

        public void HighlightBreakPoint(int lineNumber, List<ScriptBreakPointSymbol> symbols)
        {
            _breakPointLineNumber = lineNumber;
            _breakPointSymbols = symbols.ToList();
            _currentBreakPointSymbol = null;

            Document.BeginUpdate();

            var line = Document.GetLineByNumber(lineNumber);
            OffsetColorizer errorLineColrizer = new OffsetColorizer(line, line.Offset, line.EndOffset, BreakPointLineBrush);
            TextArea.TextView.LineTransformers.Add(errorLineColrizer);

            var breakPoint = breakPointMargin.BreakPoints.FirstOrDefault(x => x.LineNumber == lineNumber);
            breakPoint.IsActive = true;
            breakPointMargin.InvalidateVisual();

            Document.EndUpdate();
        }

        public void ResetBreakPointLine()
        {
            _breakPointSymbols = new List<ScriptBreakPointSymbol>();
            _currentBreakPointSymbol = null;
            ResetColorizationByKeyword();
            breakPointMargin.BreakPoints.ToList().ForEach(x => x.IsActive = false);
            Mouse.OverrideCursor = null;
            ClearErrors();
            breakPointMargin.InvalidateVisual();
        }

        public Point? GetLineVisualPosition(int lineNumber)
        {
            double top = TextArea.TextView.GetVisualTopByDocumentLine(lineNumber);
            var visualLine = TextArea.TextView.GetVisualLine(lineNumber);

            if (visualLine != null)
            {
                var textLine = visualLine.GetTextLine(0);
                var x = visualLine.GetTextLineVisualXPosition(textLine, visualLine.VisualLengthWithEndOfLineMarker);
                var left = visualLine.VisualLengthWithEndOfLineMarker;
                return new Point(x, top);
            }

            return null;
        }

        public List<ScriptBreakPoint> GetBreakPoints()
        {
            List<ScriptBreakPoint> breakPoints = new List<ScriptBreakPoint>();

            foreach (var b in breakPointMargin.BreakPoints)
            {
                ScriptBreakPoint breakPoint = new ScriptBreakPoint();
                breakPoint.Script = ScriptSource;
                breakPoint.LineNumber = b.LineNumber;

                var line = Document.GetLineByNumber(b.LineNumber);
                breakPoint.LineStartOffset = line.Offset;
                breakPoint.LineEndOffset = line.EndOffset;

                var symbols = _parser.GetContextSymbols(Document.Text, line.Offset);

                foreach (var symbol in symbols.Where(x => (x.Kind == SymbolKind.Property || x.Kind == SymbolKind.Field || x.Kind == SymbolKind.Local || x.Kind == SymbolKind.Parameter) && !x.IsUnassigned))
                {
                    if (symbol.Offset < line.Offset)
                    {
                        breakPoint.ContextSymbols.Add(new ScriptBreakPointSymbol()
                        {
                            Name = symbol.Name,
                            Offset = symbol.Offset,
                            Length = symbol.Length,
                        });
                    }
                }

                breakPoints.Add(breakPoint);
            }

            return breakPoints;
        }

        #endregion

        #region BreakPoint Symbols Search

        private void ScriptEditor_MouseMove(object sender, MouseEventArgs e)
        {
            if (IsReadOnly && _breakPointSymbols.Count > 0)
            {
                try
                {
                    var word_separators_plus = word_separators.ToList();
                    word_separators_plus.Add(')');
                    word_separators_plus.Add(';');

                    var textView = TextArea.TextView;
                    Point position = e.GetPosition(textView);
                    position.Y += textView.VerticalOffset;
                    VisualLine visualLine = textView.GetVisualLineFromVisualTop(position.Y);
                    int columnIndex = visualLine.GetVisualColumnFloor(position, false);
                    String line = Document.GetText(visualLine.FirstDocumentLine.Offset, visualLine.FirstDocumentLine.Length);
                    if (columnIndex < line.Length)
                    {
                        int wordStartIndex = columnIndex;
                        int wordEndIndex = columnIndex;

                        while (wordStartIndex > 0)
                        {
                            if (word_separators_plus.Contains(line[wordStartIndex])) break;
                            wordStartIndex--;
                        }

                        while (wordEndIndex < line.Length)
                        {
                            if (word_separators_plus.Contains(line[wordEndIndex])) break;
                            wordEndIndex++;
                        }

                        if (wordStartIndex > 0)
                        {
                            wordStartIndex++;
                        }

                        String word = line.Substring(wordStartIndex, wordEndIndex - wordStartIndex);

                        var breakPointSymbol = _breakPointSymbols.FirstOrDefault(x => x.Name == word);

                        if (breakPointSymbol != null)
                        {
                            int wordStartOffset = visualLine.FirstDocumentLine.Offset + wordStartIndex;

                            ClearErrors();
                            ITextMarker marker = errorMarkerService.Create(wordStartOffset, word.Length);
                            marker.MarkerTypes = TextMarkerTypes.NormalUnderline;
                            marker.MarkerColor = Colors.Yellow;
                            Mouse.OverrideCursor = Cursors.Hand;

                            _currentBreakPointSymbol = breakPointSymbol;
                            _currentBreakPointSymbolPosition = visualLine.GetVisualPosition(wordEndIndex, VisualYPosition.LineTop);
                        }
                        else
                        {
                            _currentBreakPointSymbol = null;
                            Mouse.OverrideCursor = null;
                            ClearErrors();
                        }
                    }
                    else
                    {
                        _currentBreakPointSymbol = null;
                        Mouse.OverrideCursor = null;
                        ClearErrors();
                    }
                }
                catch (Exception ex)
                {
                    _currentBreakPointSymbol = null;
                    Mouse.OverrideCursor = null;
                    ClearErrors();
                    Debug.WriteLine(ex.Message);
                }
            }
        }

        protected override void OnPreviewMouseLeftButtonUp(MouseButtonEventArgs e)
        {
            base.OnPreviewMouseLeftButtonUp(e);

            if (_currentBreakPointSymbol != null)
            {
                Mouse.OverrideCursor = null;
                Debug.WriteLine($"Pressed on break point symbol: {_currentBreakPointSymbol.Name}");
                BreakPointSymbolPressed?.Invoke(this, new BreakPointSymbolPressedEventArgs()
                {
                    BreakPointSymbol = _currentBreakPointSymbol,
                    Position = _currentBreakPointSymbolPosition
                });
            }
        }

        public String GetCaretWord()
        {
            try
            {
                var word_separators_plus = word_separators.ToList();
                word_separators_plus.Add(')');
                word_separators_plus.Add(';');

                int wordStartOffset = CaretOffset;
                int wordEndOffset = CaretOffset;

                while (wordStartOffset > 0)
                {
                    if (word_separators_plus.Contains(Document.Text[wordStartOffset])) break;
                    wordStartOffset--;
                }

                while (wordEndOffset < Document.Text.Length)
                {
                    if (word_separators_plus.Contains(Document.Text[wordEndOffset])) break;
                    wordEndOffset++;
                }

                if (wordStartOffset > 0)
                {
                    wordStartOffset++;
                }

                String word = Document.Text.Substring(wordStartOffset, wordEndOffset - wordStartOffset);

                return word;
            }
            catch
            {
                return null;
            }
        }

        #endregion
    }
}