From c1c1e12fd3f0d89752b42d890ac43678bf9e7d69 Mon Sep 17 00:00:00 2001 From: Roy Ben Shabat Date: Sat, 16 Mar 2019 11:53:31 +0200 Subject: More work on script editor. --- .../Tango.Scripting.Editors/Intellisense/Utils.cs | 4 +- .../Tango.Scripting.Editors/ScriptEditor.cs | 2002 ++++++++++---------- .../Tango.Scripting/Parsing/ScriptParser.cs | 2 + 3 files changed, 1012 insertions(+), 996 deletions(-) (limited to 'Software/Visual_Studio/TEMP') diff --git a/Software/Visual_Studio/TEMP/Tango.Scripting/Tango.Scripting.Editors/Intellisense/Utils.cs b/Software/Visual_Studio/TEMP/Tango.Scripting/Tango.Scripting.Editors/Intellisense/Utils.cs index e30d0e37e..f8cc7072d 100644 --- a/Software/Visual_Studio/TEMP/Tango.Scripting/Tango.Scripting.Editors/Intellisense/Utils.cs +++ b/Software/Visual_Studio/TEMP/Tango.Scripting/Tango.Scripting.Editors/Intellisense/Utils.cs @@ -116,7 +116,7 @@ namespace Tango.Scripting.Editors.Intellisense XmlNode mDoc = null; mDoc = docNodes.FirstOrDefault(x => x.Attributes["name"].InnerText.Contains(knownType.Type.Name + "." + method.Name)); - method.Summary = mDoc != null ? mDoc.SelectSingleNode("summary").InnerXml : "No documentation"; + method.Summary = mDoc != null ? mDoc.SelectSingleNode("summary").InnerXml.Remove("()") : "No documentation"; var parameters = method.Parameters.ToList(); var parametersNodes = mDoc != null ? mDoc.SelectNodes("param").OfType().ToList() : new List(); @@ -134,7 +134,7 @@ namespace Tango.Scripting.Editors.Intellisense pNode = parametersNodes[j]; } - parameter.Description = pNode != null ? pNode.InnerText : null; + parameter.Description = pNode != null ? pNode.InnerText.Remove("()") : null; } } } diff --git a/Software/Visual_Studio/TEMP/Tango.Scripting/Tango.Scripting.Editors/ScriptEditor.cs b/Software/Visual_Studio/TEMP/Tango.Scripting/Tango.Scripting.Editors/ScriptEditor.cs index 71b836f36..efa1b087a 100644 --- a/Software/Visual_Studio/TEMP/Tango.Scripting/Tango.Scripting.Editors/ScriptEditor.cs +++ b/Software/Visual_Studio/TEMP/Tango.Scripting/Tango.Scripting.Editors/ScriptEditor.cs @@ -72,6 +72,7 @@ namespace Tango.Scripting.Editors { public KnownType Type { get; set; } public String MethodName { get; set; } + public int ParameterIndex { get; set; } } private class DeclaredMethodSession @@ -210,1115 +211,1265 @@ namespace Tango.Scripting.Editors #endregion - #region Public Methods + #region Override Methods /// - /// Invalidates all using statements in the script. + /// Invoked when an unhandled  attached event reaches an element in its route that is derived from this class. Implement this method to add class handling for this event. /// - public void InvalidateUsings() + /// The that contains the event data. + protected override void OnPreviewKeyDown(KeyEventArgs e) { - 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))) + if (CurrentPopupContent is MethodPopup && (e.Key == Key.Down || e.Key == Key.Up)) { - InvalidateHighlighting(); - } - } + e.Handled = true; - /// - /// Invalidates the script folding if enabled. - /// - public void InvalidateFolding() - { - if (EnableFolding) - { - if (foldingManager == null) + if (e.Key == Key.Down) { - foldingManager = FoldingManager.Install(TextArea); + (CurrentPopupContent as MethodPopup).IncrementMethod(); + } + else if (e.Key == Key.Up) + { + (CurrentPopupContent as MethodPopup).DecrementMethod(); } - foldingStrategy.UpdateFoldings(foldingManager, Document); + return; } - } - /// - /// Indents the code. - /// - public void IndentCode() - { - Text = Indentation.CSharp.CSharpIndentationHelper.IndentCSharpCode(Text); - //Text = _parser.IndentCSharpCode(Text); + base.OnPreviewKeyDown(e); + HidePopup(); + HandleKeyCombinations(e); } - /// - /// Gets the current line. - /// - /// - public DocumentLine GetCurrentLine() - { - int offset = CaretOffset; - var line = Document.GetLineByOffset(offset); - return line; - } + #endregion - /// - /// Gets the current line text. - /// - /// - public String GetCurrentLineText() - { - var text = Document.GetText(GetCurrentLine()); - return text; - } + #region Apply Template - /// - /// Gets the current word. - /// - /// - public String GetCurrentWord() + public override void OnApplyTemplate() { - return GetWordByEndIndex(CaretOffset); + base.OnApplyTemplate(); + + _popup = GetTemplateChild("PART_popup") as Popup; } - public String GetWordByEndIndex(int index) - { - String word = String.Empty; - var line = GetCurrentLine(); + #endregion - int position = index; + #region Key Combination Handling - for (int i = position - 1; i >= line.Offset; i--) + /// + /// Handles the key combinations. + /// + /// The instance containing the event data. + private void HandleKeyCombinations(KeyEventArgs e) + { + if (Keyboard.IsKeyDown(Key.LeftCtrl) && Keyboard.IsKeyDown(Key.K) && Keyboard.IsKeyDown(Key.D)) { - char c = Document.GetText(i, 1).First(); - - if (word_separators.Contains(c)) + try { - break; + int index = CaretOffset; + Document.BeginUpdate(); + IndentCode(); + Document.EndUpdate(); + e.Handled = true; + CaretOffset = index; + } + catch + { + Debug.WriteLine("Error indenting code."); } - - word += c; } + else if (e.Key == Key.Oem2) + { + int offset = CaretOffset; + var line = Document.GetLineByOffset(offset); - word = new string(word.Reverse().ToArray()); - - if (word.Length > 0) + String text = GetCurrentLineText(); + if (text.TrimStart('\t', ' ').StartsWith("//")) + { + Document.BeginUpdate(); + Document.Replace(line, "/// \n/// \n/// "); + Document.EndUpdate(); + e.Handled = true; + CaretOffset = Document.GetLineByNumber(line.LineNumber + 1).EndOffset; + } + } + else if (e.Key == Key.End || e.Key == Key.Home) { - word = word.Replace(".", ""); + HideCompletionWindow(); } - - return word; } - public int GetCurrentWordStartIndex() + #endregion + + #region Text Entered + + private void TextArea_TextEntered(object sender, TextCompositionEventArgs e) { - var line = GetCurrentLine(); + List items = new List(); - int position = CaretOffset; + HidePopup(); - for (int i = position - 1; i >= line.Offset; i--) + 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] == "=") { - char c = Document.GetText(i, 1).First(); + var expression = previousWords.First(); + var knownType = GetKnownTypeFromExpression(expression + "."); - if (word_separators.Contains(c)) + if (knownType != null && knownType.Type.IsEnum) { - return i + 1; + completionWindow.HideCompletion(); + IList data = new List(); + + foreach (var field in knownType.Fields) + { + data.Add(new FieldCompletionItem() + { + Class = knownType.FriendlyName, + Name = knownType.FriendlyName + "." + field.Name, + Type = field.ReturnTypeFriendlyName, + Description = field.Summary, + }); + } + + ShowCompletionWindow(data.OrderBy(x => x.Text).ToList(), GetCurrentWord()); } + } + else if (e.Text == " " && GetPreviousWord() == "new") + { + var s = _parser.GetExpressionFirst(GetCurrentLineText()); - return line.Offset; - } + if (s != null) + { + String type = s.Declaration.Type.ToString(); - public String GetPreviousWord() - { - int index = GetCurrentWordStartIndex() - 1; - return GetWordByEndIndex(index); - } + IList data = new List(); - private ConstructionSession GetConstructionSession() - { - var expression = _parser.GetCurrentConstructionExpression(GetCurrentLineText()); + data.Add(new ClassCompletionItem() + { + Name = type, + Description = "Auto generate assignment...", + }); - if (expression != null) + ShowCompletionWindow(data, type); + } + } + else if (e.Text == ";" || e.Text == " ") { - ConstructionSession session = new ConstructionSession(); + HideCompletionWindow(); + } + else if (e.Text == ".") + { + var knownType = GetCurrentKnownType(); - var line = GetCurrentLine(); - int parameterIndex = 0; - for (int i = CaretOffset; i > line.Offset; i--) + if (knownType != null) { - String c = Document.GetText(i, 1); + completionWindow.HideCompletion(); + IList data = new List(); - if (c == "(") + if (!knownType.Type.IsEnum) { - var typeDeclaration = expression.Type as GenericNameSyntax; - - KnownType type = null; + var typeMembers = knownType.Members.ToList(); - if (typeDeclaration != null) + foreach (var methodGroup in typeMembers.OfType().GroupBy(x => x.NameWithTypeArguments)) { - var typeName = typeDeclaration.Identifier.ToString(); - var argumentsCount = typeDeclaration.TypeArgumentList.Arguments.Count; - session.TypeArguments = typeDeclaration.TypeArgumentList.Arguments.Select(x => x.ToString()).ToList(); + var method = methodGroup.First(); - if (argumentsCount == 0) - { - type = _knownTypes.FirstOrDefault(x => x.Type.Name == expression.Type.ToString()); - } - else + data.Add(new MethodCompletionItem() { - type = _knownTypes.FirstOrDefault(x => x.Type.Name == typeName + "`" + argumentsCount); - } - } - else - { - type = _knownTypes.FirstOrDefault(x => x.Name == expression.Type.ToString()); + Class = knownType.FriendlyName, + Name = method.NameWithTypeArguments, + ReturnType = method.ReturnTypeFriendlyName, + Description = method.Summary, + Parameters = method.Parameters, + Overloads = methodGroup.Count() - 1, + }); } - if (type != null) - { - session.Type = type; - session.ParameterIndex = parameterIndex; - return session; - } - else + foreach (var methodGroup in typeMembers.Where(x => x.GetType() != typeof(KnownTypeMethod)).GroupBy(x => x.Name)) { - return null; + var member = methodGroup.First(); + + data.Add(new PropertyCompletionItem() + { + Class = knownType.FriendlyName, + Name = member.Name, + Type = member.ReturnTypeFriendlyName, + Description = member.Summary, + }); + } } - else if (c == ",") + else { - parameterIndex++; + foreach (var field in knownType.Fields) + { + data.Add(new FieldCompletionItem() + { + Class = knownType.FriendlyName, + Name = field.Name, + Type = field.ReturnTypeFriendlyName, + Description = field.Summary, + }); + + } } + ShowCompletionWindow(data.OrderBy(x => x.Text).ToList(), GetCurrentWord()); } - } - - return null; - } - - private MethodSession GetMethodSession() - { - var expression = GetPreviousWords().LastOrDefault(); - - if (expression != null) - { - var tree = expression.Split('.').Select(x => x.Remove(@"\n|\r|\s|\t|\(|\)|\[|\]|<.*>")).ToList(); - var variableName = tree.FirstOrDefault(); - - if (variableName != null && tree.Count > 1) + else { - tree.RemoveAt(0); - var variables = _parser.GetContextSymbols(Document.Text, CaretOffset); - var variable = variables.FirstOrDefault(x => x.Name == variableName); + var declaredType = GetCurrentDeclaredType(); - if (variable != null) + if (declaredType != null) { - var knownType = _knownTypes.FirstOrDefault(x => x.FriendlyName == Regex.Replace(variable.Type, "<.+>", "")); + completionWindow.HideCompletion(); + IList data = new List(); - if (knownType != null) + var typeMembers = declaredType.Symbols.ToList(); + + foreach (var methodGroup in typeMembers.GroupBy(x => x.Name)) { - while (tree.Count > 1) + var member = methodGroup.First(); + + if (member.Kind == SymbolKind.Method) { - var memberName = tree.First(); - tree.RemoveAt(0); - var member = knownType.Members.FirstOrDefault(x => x.Name == memberName); + var methodCompletion = new MethodCompletionItem() + { + Class = declaredType.Name, + Name = member.Name, + ReturnType = member.Type, + Description = member.Summary, + Overloads = methodGroup.Count() - 1, + }; - if (member == null) + + for (int i = 0; i < member.Parameters.Count; i++) { - return null; + var pair = member.Parameters[i]; + + methodCompletion.Parameters.Add(new KnownTypeMethodParameter() + { + Type = pair.Key, + Name = pair.Value, + IsLast = (i == member.Parameters.Count - 1) + }); } - knownType = _knownTypes.FirstOrDefault(x => x.Type.Namespace + "." + x.Type.Name == member.ReturnType.Namespace + "." + member.ReturnType.Name); - } + data.Add(methodCompletion); - return new MethodSession() + } + else if (member.Kind == SymbolKind.Property) { - Type = knownType, - MethodName = tree.Last(), - }; + 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()); } } } - - return null; - } - - private DeclaredMethodSession GetDeclaredMethodSession() - { - var expression = GetPreviousWords().LastOrDefault(); - - if (expression != null) + else if (e.Text == "(" || e.Text == ",") { - var tree = expression.Split('.').Select(x => x.Replace("\n", "").Replace("\r", "").Replace(" ", "").Replace("\t", "").Replace("(", "").Replace(")", "").Replace("[", "").Replace("]", "")).ToList(); - var variableName = tree.FirstOrDefault(); + completionWindow.HideCompletion(); - if (variableName != null && tree.Count > 0) + try { - tree.RemoveAt(0); - var variables = _parser.GetContextSymbols(Document.Text, CaretOffset); - var variable = variables.FirstOrDefault(x => x.Name == variableName); + var session = GetConstructionSession(); - if (variable != null) + if (session != null) { - var declaredType = _declaredTypes.FirstOrDefault(x => x.Name == Regex.Replace(variable.Class, "<.+>", "")); - - if (declaredType != null) + var content = CreateConstructionSessionPopupContent(session); + if (content.Methods.Count > 0) { - 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; - } + ShowPopup(content); + return; + } + } - declaredType = _declaredTypes.FirstOrDefault(x => x.ContainingNamespace + "." + x.Name == member.ContainingNamespace + "." + member.Type); - } + var methodSession = GetMethodSession(); - var methodName = tree.Count > 0 ? tree.Last() : variableName; + if (methodSession != null) + { + var content = CreateMethodSessionPopupContent(methodSession); + if (content.Methods.Count > 0) + { + ShowPopup(content); + return; + } + } - var method = declaredType.Symbols.FirstOrDefault(x => x.Kind == SymbolKind.Method && x.Name == methodName); + var declaredMethodSession = GetDeclaredMethodSession(); - if (method != null) - { - return new DeclaredMethodSession() - { - Type = declaredType, - Method = method, - }; - } - } - else if (tree.Count == 0) + if (declaredMethodSession != null) + { + var content = CreateDeclaredMethodSessionPopupContent(declaredMethodSession); + if (content.Methods.Count > 0) { - var method = variable; - - if (method != null) - { - return new DeclaredMethodSession() - { - Type = declaredType, - Method = method, - }; - } + ShowPopup(content); + return; } } } + catch (Exception ex) + { + Debug.WriteLine(ex); + } } + else if (lineText.StartsWith("using")) + { + if (completionWindow.IsVisible) + { + completionWindow.UpdatePositionFix(); + return; + } - return null; - } + IList data = new List(); - public List GetPreviousWords() - { - var currentLine = GetCurrentLine(); - var currentText = Document.GetText(currentLine.Offset, CaretOffset - currentLine.Offset); - return currentText.Split(' ',',').ToList(); - } + foreach (var asm in ReferenceAssemblies) + { + foreach (var ns in asm.Assembly.GetTypes().Select(x => x.Namespace).Distinct().Where(x => x != null)) + { + data.Add(new NamespaceCompletionItem() + { + Name = ns, + Assembly = asm.Assembly.GetName().Name, + }); + } + } - #endregion + data = data.DistinctBy(x => x.Text).ToList(); - #region Highlighting + ShowCompletionWindow(data, GetCurrentWord()); + } + else if (e.Text == "{") + { + int parentesisCount = lineText.TakeWhile(x => x != '{').Count(x => x == '\"'); - private void InvalidateHighlighting() - { - if (!_isLoadingTypes) + if (parentesisCount % 2 == 0) + { + Document.Insert(CaretOffset, "}"); + CaretOffset--; + } + } + else if (e.Text == "}") { - _isLoadingTypes = true; - _knownTypes.Clear(); + 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 assemblies = ReferenceAssemblies.ToList(); - var usings = _current_usings.ToList(); + var previous_word = GetPreviousWord(); + var word = GetCurrentWord(); - Thread t = new Thread(() => + if (word.Contains("<")) { - foreach (var asm in assemblies.Select(x => x.Assembly)) + word = word.Last(x => x != '<').ToString(); + } + + if (previous_word != word) + { + if (_knownTypes.Exists(x => x.Name == previous_word)) { - Parallel.ForEach(asm.GetTypes().Where(x => x.IsVisible && x.IsPublic && !x.IsPrimitive), (type) => - { - if (usings.Exists(x => type.Namespace == x)) - { - lock (_knownTypes) - { - if (!_knownTypes.Exists(x => x.Type.FullName == type.FullName)) - { - _knownTypes.Add(new KnownType(type)); - } - } - } - }); + return; } - if (_knownTypes.Count > 0 || _declaredTypes.Count > 0) + if (_blocking_type_words.Contains(previous_word)) { - String text = String.Empty; + return; + } + } - Stream xshd_stream = typeof(ScriptEditor).Assembly.GetManifestResourceStream("Tango.Scripting.Editors.Highlighting.Resources.CSharp-Mode.xshd"); + if (!String.IsNullOrWhiteSpace(word)) + { + IList data = new List(); - using (StreamReader reader = new StreamReader(xshd_stream)) + foreach (var type in _declaredTypes.Where(x => x.Name.StartsWith(word))) + { + if (type.Kind == TypeKind.Struct) { - text = reader.ReadToEnd(); + data.Add(new StructCompletionItem() + { + Name = type.Name, + Description = type.Summary, + Namespace = type.ContainingNamespace, + Priority = 1, + }); } - - List referenceTypes = new List(); - List interfaceTypes = new List(); - - lock (_knownTypes) + else if (type.Kind == TypeKind.Enum) { - foreach (var type in _knownTypes.ToList().Where(x => x != null)) + data.Add(new EnumCompletionItem() { - 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("{0}", name)); - } - else if (type.Type.IsClass || (type.Type.IsValueType)) - { - referenceTypes.Add(String.Format("{0}", name)); - } - } + Name = type.Name, + Description = type.Summary, + Namespace = type.ContainingNamespace, + Priority = 1, + }); } - - foreach (var type in _declaredTypes) + else if (type.Kind == TypeKind.Interface) { - if (type.Kind == TypeKind.Interface || type.Kind == TypeKind.Enum) + data.Add(new InterfaceCompletionItem() { - interfaceTypes.Add(String.Format("{0}", type.Name)); - } - else if (type.Kind == TypeKind.Class) + Name = type.Name, + Description = type.Summary, + Namespace = type.ContainingNamespace, + Priority = 1, + }); + } + else if (type.Kind == TypeKind.Class) + { + data.Add(new ClassCompletionItem() { - referenceTypes.Add(String.Format("{0}", type.Name)); - } + Name = type.Name, + Description = type.Summary, + Namespace = type.ContainingNamespace, + Priority = 1, + }); } - - if (referenceTypes.Count > 0) + else { - text = text.Replace("@ReferenceTypes@", String.Join(Environment.NewLine, referenceTypes.Distinct())); + throw new NotImplementedException("Implement generic item here!"); } + } - if (interfaceTypes.Count > 0) + foreach (var type in _knownTypes.ToList().Where(x => x.Name.StartsWith(word))) + { + if (type.Type.IsEnum) { - text = text.Replace("@InterfaceTypes@", String.Join(Environment.NewLine, interfaceTypes.Distinct())); + data.Add(new EnumCompletionItem() + { + Namespace = type.Type.Namespace, + Description = type.Summary, + Name = type.FriendlyName, + Priority = 0, + }); } - - MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(text)); - - XmlTextReader xshd_reader = new XmlTextReader(ms); - - Dispatcher.BeginInvoke(new Action(() => + else if (type.Type.IsInterface) { - SyntaxHighlighting = HighlightingLoader.Load(xshd_reader, HighlightingManager.Instance); - xshd_reader.Close(); - ms.Dispose(); - })); - - - foreach (var knownType in _knownTypes) + data.Add(new InterfaceCompletionItem() + { + Name = type.FriendlyName, + Description = type.Summary, + Namespace = type.Type.Namespace, + Priority = 0, + }); + } + else if (type.Type.IsValueType) { - knownType.LoadDocumentation(); + 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."); } } - _isLoadingTypes = false; - }); - t.IsBackground = true; - t.Start(); - } - } - - private void InvalidateScriptTypesHighlightings() - { - var declaredTypes = _parser.GetDeclaredTypes(Text); + 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, + }; - if (declaredTypes.Exists(x => !_declaredTypes.Exists(y => y.Name == x.Name)) || _declaredTypes.Exists(x => !declaredTypes.Exists(y => y.Name == x.Name))) - { - _declaredTypes = declaredTypes; - InvalidateHighlighting(); - } + for (int i = 0; i < symbol.Parameters.Count; i++) + { + var pair = symbol.Parameters[i]; - _declaredTypes = declaredTypes; + methodCompletion.Parameters.Add(new KnownTypeMethodParameter() + { + Type = pair.Key, + Name = pair.Value, + IsLast = (i == symbol.Parameters.Count - 1) + }); + } - //for (int i = 0; i < TextArea.TextView.LineTransformers.Count; i++) - //{ - // if (TextArea.TextView.LineTransformers[i] is OffsetColorizer) - // { - // TextArea.TextView.LineTransformers.RemoveAt(i); - // } - //} + data.Add(methodCompletion); + } + } - //foreach (var cls in scriptClasses) - //{ - // Document.BeginUpdate(); + ShowCompletionWindow(data, word); + } + } + } - // var line = Document.GetLineByOffset(cls.Index); + #endregion - // OffsetColorizer colorizer = new OffsetColorizer(line, cls.Index, cls.Index + cls.Name.Length, Brushes.Red); - // TextArea.TextView.LineTransformers.Add(colorizer); + #region Completion Window Insertion - // Document.EndUpdate(); - //} + private void CompletionWindow_InsertionRequest(ICompletionData item) + { + item.Complete(this); } #endregion - #region Override Methods + #region Private/Internal Methods - /// - /// Invoked when an unhandled  attached event reaches an element in its route that is derived from this class. Implement this method to add class handling for this event. - /// - /// The that contains the event data. - protected override void OnPreviewKeyDown(KeyEventArgs e) + private void ShowCompletionWindow(IList suggestions, String filter) { - if (CurrentPopupContent is MethodPopup && (e.Key == Key.Down || e.Key == Key.Up)) + IList data = completionWindow.CompletionList.CompletionData; + data.Clear(); + + foreach (var item in suggestions) { - e.Handled = true; + data.Add(item); + } - if (e.Key == Key.Down) - { - (CurrentPopupContent as MethodPopup).IncrementMethod(); - } - else if (e.Key == Key.Up) + if (data.Count > 0) + { + completionWindow.ShowCompletion(); + + if (completionWindow.CompletionList.ListBox != null) { - (CurrentPopupContent as MethodPopup).DecrementMethod(); + completionWindow.CompletionList.SelectItemFiltering(filter); } - - return; } - - base.OnPreviewKeyDown(e); - HidePopup(); - HandleKeyCombinations(e); + else + { + completionWindow.HideCompletion(); + } } - #endregion - - #region Apply Template - - public override void OnApplyTemplate() + private void HideCompletionWindow() { - base.OnApplyTemplate(); - - _popup = GetTemplateChild("PART_popup") as Popup; + completionWindow.HideCompletion(); } - #endregion + private List GetScriptClassNames() + { + List list = new List(); - #region Key Combination Handling + Regex r = new Regex(@"(class\s+)(\w+)"); + var matches = r.Matches(Text); - /// - /// Handles the key combinations. - /// - /// The instance containing the event data. - private void HandleKeyCombinations(KeyEventArgs e) - { - if (Keyboard.IsKeyDown(Key.LeftCtrl) && Keyboard.IsKeyDown(Key.K) && Keyboard.IsKeyDown(Key.D)) + foreach (var m in matches.OfType()) { - try - { - int index = CaretOffset; - Document.BeginUpdate(); - IndentCode(); - Document.EndUpdate(); - e.Handled = true; - CaretOffset = index; - } - catch - { - Debug.WriteLine("Error indenting code."); - } + var g = m.Groups.OfType().Last(); + list.Add(g.Value); } - 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, "/// \n/// \n/// "); - Document.EndUpdate(); - e.Handled = true; - CaretOffset = Document.GetLineByNumber(line.LineNumber + 1).EndOffset; - } - } - else if (e.Key == Key.End || e.Key == Key.Home) + return list.Distinct().ToList(); + } + + private List GetScriptInterfaceOfEnumNames() + { + List list = new List(); + + Regex r = new Regex(@"((enum|interface)\s+)(\w+)"); + var matches = r.Matches(Text); + + foreach (var m in matches.OfType()) { - HideCompletionWindow(); + var g = m.Groups.OfType().Last(); + list.Add(g.Value); } + + return list.Distinct().ToList(); } - #endregion + private List GetScriptEnumsAndInterfaces() + { + List list = new List(); - #region Intellisense + Regex r = new Regex(@"((public|private|internal)\s+(enum|interface)\s+\w+)"); + var matches = r.Matches(Text); - /// - /// Handles the TextEntered event of the TextArea control. - /// - /// The source of the event. - /// The instance containing the event data. - private void TextArea_TextEntered(object sender, TextCompositionEventArgs e) - { - List items = new List(); + foreach (var m in matches) + { - 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(); + return list; + } - if (previousWords.Count > 0 && previousWords.First().Trim().StartsWith("//")) return; + private KnownType GetCurrentKnownType() + { + var expression = GetPreviousWords().LastOrDefault(); + return GetKnownTypeFromExpression(expression); + } - if (e.Text == " " && previousWords.Count > 2 && previousWords[previousWords.Count - 2] == "=") + private KnownType GetKnownTypeFromExpression(String expression) + { + if (expression != null) { - var expression = previousWords.First(); - var knownType = GetKnownTypeFromExpression(expression + "."); + var tree = expression.Split('.').Select(x => x.Remove(@"\n|\t|\r|\(.*\)|\[.*\]|\s")).ToList(); + var variableName = tree.FirstOrDefault(); - if (knownType != null && knownType.Type.IsEnum) + if (variableName != null) { - completionWindow.HideCompletion(); - IList data = new List(); + //Search for enum type first + var enumType = _knownTypes.FirstOrDefault(x => x.Name == variableName && x.Type.IsEnum); - foreach (var field in knownType.Fields) + if (enumType != null) { - data.Add(new FieldCompletionItem() - { - Class = knownType.FriendlyName, - Name = knownType.FriendlyName + "." + field.Name, - Type = field.ReturnTypeFriendlyName, - Description = field.Summary, - }); + return enumType; } - ShowCompletionWindow(data.OrderBy(x => x.Text).ToList(), GetCurrentWord()); - } + tree.RemoveAt(0); + var variables = _parser.GetContextSymbols(Document.Text, CaretOffset); + var variable = variables.FirstOrDefault(x => x.Name == variableName); - } - else if (e.Text == " " && GetPreviousWord() == "new") - { - var s = _parser.GetExpressionFirst(GetCurrentLineText()); + if (variable != null) + { + var knownType = _knownTypes.FirstOrDefault(x => x.FriendlyName == Regex.Replace(variable.Type, "<.+>", "")); - if (s != null) - { - String type = s.Declaration.Type.ToString(); + if (knownType != null) + { + while (tree.Count > 1) + { + var memberName = tree.First(); + tree.RemoveAt(0); + var member = knownType.Members.FirstOrDefault(x => x.Name == memberName); - IList data = new List(); + if (member == null) + { + return null; + } - data.Add(new ClassCompletionItem() - { - Name = type, - Description = "Auto generate assignment...", - }); + knownType = _knownTypes.FirstOrDefault(x => x.Type.Namespace + "." + x.Type.Name == member.ReturnType.Namespace + "." + member.ReturnType.Name); + } - ShowCompletionWindow(data, type); + return knownType; + } + } } } - else if (e.Text == ";" || e.Text == " ") - { - HideCompletionWindow(); - } - else if (e.Text == ".") + + return null; + } + + private ScriptType GetCurrentDeclaredType() + { + var expression = GetPreviousWords().LastOrDefault(); + + if (expression != null) { - var knownType = GetCurrentKnownType(); + var tree = expression.Split('.').Select(x => x.Remove(@"\n|\t|\r|\(.*\)|\[.*\]|\s")).ToList(); + var variableName = tree.FirstOrDefault(); - if (knownType != null) + if (variableName != null) { - completionWindow.HideCompletion(); - IList data = new List(); + tree.RemoveAt(0); + var variables = _parser.GetContextSymbols(Document.Text, CaretOffset); + var variable = variables.FirstOrDefault(x => x.Name == variableName); - if (!knownType.Type.IsEnum) + if (variable != null) { - var typeMembers = knownType.Members.ToList(); + var declaredType = _declaredTypes.FirstOrDefault(x => x.Name == Regex.Replace(variable.Type, "<.+>", "")); - foreach (var methodGroup in typeMembers.OfType().GroupBy(x => x.NameWithTypeArguments)) + if (declaredType != null) { - var method = methodGroup.First(); - - data.Add(new MethodCompletionItem() + while (tree.Count > 1) { - Class = knownType.FriendlyName, - Name = method.NameWithTypeArguments, - ReturnType = method.ReturnTypeFriendlyName, - Description = method.Summary, - Parameters = method.Parameters, - Overloads = methodGroup.Count() - 1, - }); - } - - foreach (var methodGroup in typeMembers.Where(x => x.GetType() != typeof(KnownTypeMethod)).GroupBy(x => x.Name)) - { - var member = methodGroup.First(); + var memberName = tree.First(); + tree.RemoveAt(0); + var member = declaredType.Symbols.FirstOrDefault(x => x.Name == memberName); - data.Add(new PropertyCompletionItem() - { - Class = knownType.FriendlyName, - Name = member.Name, - Type = member.ReturnTypeFriendlyName, - Description = member.Summary, - }); + if (member == null) + { + return null; + } - } - } - else - { - foreach (var field in knownType.Fields) - { - data.Add(new FieldCompletionItem() - { - Class = knownType.FriendlyName, - Name = field.Name, - Type = field.ReturnTypeFriendlyName, - Description = field.Summary, - }); + declaredType = _declaredTypes.FirstOrDefault(x => x.ContainingNamespace + "." + x.Name == member.ContainingNamespace + "." + member.Type); + } + return declaredType; } } - - ShowCompletionWindow(data.OrderBy(x => x.Text).ToList(), GetCurrentWord()); } - else - { - var declaredType = GetCurrentDeclaredType(); + } - if (declaredType != null) - { - completionWindow.HideCompletion(); - IList data = new List(); + return null; + } - var typeMembers = declaredType.Symbols.ToList(); + private void ShowPopup(Object content) + { + var position = TextArea.Caret.Position; + var textView = TextArea.TextView; - foreach (var methodGroup in typeMembers.GroupBy(x => x.Name)) - { - var member = methodGroup.First(); + var visualLocation = textView.GetVisualPosition(position, VisualYPosition.LineBottom); + var visualLocationTop = textView.GetVisualPosition(position, VisualYPosition.LineTop); - 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, - }; + 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)); - for (int i = 0; i < member.Parameters.Count; i++) - { - var pair = member.Parameters[i]; + CurrentPopupContent = content; - methodCompletion.Parameters.Add(new KnownTypeMethodParameter() - { - Type = pair.Key, - Name = pair.Value, - IsLast = (i == member.Parameters.Count - 1) - }); - } + _popup.IsOpen = true; + } - data.Add(methodCompletion); + private void HidePopup() + { + _popup.IsOpen = false; + CurrentPopupContent = null; + } - } - 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, - }); - } - } + private MethodPopup CreateConstructionSessionPopupContent(ConstructionSession session) + { + MethodPopup popup = new MethodPopup(); - ShowCompletionWindow(data, GetCurrentWord()); - } - } - } - else if (e.Text == "(" || e.Text == ",") + foreach (var c in session.Type.Constructors) { - completionWindow.HideCompletion(); + MethodDescription method = new MethodDescription(); + method.ReturnType = session.Type.Name; + method.Description = c.Summary; - try + if (session.Type.Type.IsGenericType && session.TypeArguments != null) { - var session = GetConstructionSession(); + method.ReturnType = new String(session.Type.Name.TakeWhile(x => x != '`').ToArray()) + $"<{String.Join(",", session.TypeArguments)}>"; + } - if (session != null) - { - var content = CreateConstructionSessionPopupContent(session); - if (content.Methods.Count > 0) - { - ShowPopup(content); - return; - } - } + var parameters = c.Parameters; - var methodSession = GetMethodSession(); + 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); + } - if (methodSession != null) - { - var content = CreateMethodSessionPopupContent(methodSession); - if (content.Methods.Count > 0) - { - ShowPopup(content); - return; - } - } + popup.Methods.Add(method); + } - var declaredMethodSession = GetDeclaredMethodSession(); + if (session.ParameterIndex > 0) + { + popup.CurrentMethod = popup.Methods.FirstOrDefault(x => x.Parameters.Count == session.ParameterIndex + 1); - if (declaredMethodSession != null) - { - var content = CreateDeclaredMethodSessionPopupContent(declaredMethodSession); - if (content.Methods.Count > 0) - { - ShowPopup(content); - return; - } - } - } - catch (Exception ex) + if (popup.CurrentMethod == null) { - Debug.WriteLine(ex); + popup.CurrentMethod = popup.Methods.FirstOrDefault(); } } - else if (lineText.StartsWith("using")) + else { - if (completionWindow.IsVisible) - { - completionWindow.UpdatePositionFix(); - return; - } + popup.CurrentMethod = popup.Methods.FirstOrDefault(); + } - IList data = new List(); + if (popup.CurrentMethod != null) + { + popup.CurrentMethodIndex = popup.Methods.IndexOf(popup.CurrentMethod) + 1; + } - foreach (var asm in ReferenceAssemblies) - { - foreach (var ns in asm.Assembly.GetTypes().Select(x => x.Namespace).Distinct().Where(x => x != null)) - { - data.Add(new NamespaceCompletionItem() - { - Name = ns, - Assembly = asm.Assembly.GetName().Name, - }); - } - } + return popup; + } - data = data.DistinctBy(x => x.Text).ToList(); + private MethodPopup CreateMethodSessionPopupContent(MethodSession session) + { + MethodPopup popup = new MethodPopup(); - ShowCompletionWindow(data, GetCurrentWord()); - } - else if (!currentWordIncludingParenthesis.Contains(".") || currentWord[currentWord.Length - 2] == '<') + foreach (var m in session.Type.Methods.Where(x => x.Name == session.MethodName)) { - if (completionWindow.IsVisible) + MethodDescription method = new MethodDescription(); + method.ReturnType = session.Type.Name; + method.Description = m.Summary; + method.Name = m.NameWithTypeArguments; + method.Class = session.Type.FriendlyName; + + //if (session.Type.Type.IsGenericType && session.TypeArguments != null) + //{ + // method.ReturnType = new String(session.Type.Name.TakeWhile(x => x != '`').ToArray()) + $"<{String.Join(",", session.TypeArguments)}>"; + //} + + var parameters = m.Parameters; + + foreach (var p in parameters) { - completionWindow.UpdatePositionFix(); - return; + ParameterDescription pDescription = new ParameterDescription(method); + pDescription.Name = p.Name; + pDescription.Type = p.Type; + pDescription.Description = p.Description; + method.Parameters.Add(pDescription); } - var previous_word = GetPreviousWord(); - var word = GetCurrentWord(); + popup.Methods.Add(method); + } - if (word.Contains("<")) + if (session.ParameterIndex > 0) + { + popup.CurrentMethod = popup.Methods.FirstOrDefault(x => x.Parameters.Count == session.ParameterIndex + 1); + + if (popup.CurrentMethod == null) { - word = word.Last(x => x != '<').ToString(); + popup.CurrentMethod = popup.Methods.FirstOrDefault(); } + } + else + { + popup.CurrentMethod = popup.Methods.FirstOrDefault(); + } - if (previous_word != word) - { - if (_knownTypes.Exists(x => x.Name == previous_word)) - { - return; - } + if (popup.CurrentMethod != null) + { + popup.CurrentMethodIndex = popup.Methods.IndexOf(popup.CurrentMethod) + 1; + } - if (_blocking_type_words.Contains(previous_word)) - { - return; - } - } + return popup; + } - if (!String.IsNullOrWhiteSpace(word)) - { - IList data = new List(); + private MethodPopup CreateDeclaredMethodSessionPopupContent(DeclaredMethodSession session) + { + MethodPopup popup = new MethodPopup(); - foreach (var type in _declaredTypes.Where(x => x.Name.StartsWith(word))) + MethodDescription method = new MethodDescription(); + method.ReturnType = session.Method.Type; + method.Description = session.Method.Summary; + method.Name = session.Method.Name; + method.Class = session.Method.Class; + + //if (session.Type.Type.IsGenericType && session.TypeArguments != null) + //{ + // method.ReturnType = new String(session.Type.Name.TakeWhile(x => x != '`').ToArray()) + $"<{String.Join(",", session.TypeArguments)}>"; + //} + + foreach (var p in session.Method.Parameters) + { + ParameterDescription pDescription = new ParameterDescription(method); + pDescription.Type = p.Key; + pDescription.Name = p.Value; + method.Parameters.Add(pDescription); + } + + popup.Methods.Add(method); + + //if (false) + //{ + // popup.CurrentMethod = popup.Methods.FirstOrDefault(x => x.Parameters.Count == session.ParameterIndex + 1); + + // if (popup.CurrentMethod == null) + // { + // popup.CurrentMethod = popup.Methods.FirstOrDefault(); + // } + //} + //else + //{ + popup.CurrentMethod = popup.Methods.FirstOrDefault(); + //} + + if (popup.CurrentMethod != null) + { + popup.CurrentMethodIndex = popup.Methods.IndexOf(popup.CurrentMethod) + 1; + } + + return popup; + } + + private void InvalidateHighlighting() + { + if (!_isLoadingTypes) + { + _isLoadingTypes = true; + _knownTypes.Clear(); + + var assemblies = ReferenceAssemblies.ToList(); + var usings = _current_usings.ToList(); + + Thread t = new Thread(() => + { + foreach (var asm in assemblies.Select(x => x.Assembly)) { - 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) + Parallel.ForEach(asm.GetTypes().Where(x => x.IsVisible && x.IsPublic && !x.IsPrimitive), (type) => { - data.Add(new ClassCompletionItem() + if (usings.Exists(x => type.Namespace == x)) { - Name = type.Name, - Description = type.Summary, - Namespace = type.ContainingNamespace, - Priority = 1, - }); - } - else - { - throw new NotImplementedException("Implement generic item here!"); - } + lock (_knownTypes) + { + if (!_knownTypes.Exists(x => x.Type.FullName == type.FullName)) + { + _knownTypes.Add(new KnownType(type)); + } + } + } + }); } - foreach (var type in _knownTypes.ToList().Where(x => x.Name.StartsWith(word))) + if (_knownTypes.Count > 0 || _declaredTypes.Count > 0) { - 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) + 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)) { - data.Add(new StructCompletionItem() - { - Name = type.FriendlyName, - Description = type.Summary, - Namespace = type.Type.Namespace, - Priority = 0, - }); + text = reader.ReadToEnd(); } - else if (type.Type.IsClass) + + List referenceTypes = new List(); + List interfaceTypes = new List(); + + lock (_knownTypes) { - data.Add(new ClassCompletionItem() + foreach (var type in _knownTypes.ToList().Where(x => x != null)) { - Name = type.FriendlyName, - Description = type.Summary, - Namespace = type.Type.Namespace, - Priority = 0, - }); - } - else - { - throw new NotImplementedException("Implement generic item here."); - } - } + String name = type.Name; - foreach (var symbol in _parser.GetContextSymbols(Document.Text, CaretOffset).Where(x => x.Name.StartsWith(GetCurrentWord()))) - { - if (symbol.Kind == SymbolKind.Property) + if (type.Type.ContainsGenericParameters) + { + name = new String(name.TakeWhile(x => x != '`').ToArray()); + } + + if (type.Type.IsInterface || type.Type.IsEnum) + { + interfaceTypes.Add(String.Format("{0}", name)); + } + else if (type.Type.IsClass || (type.Type.IsValueType)) + { + referenceTypes.Add(String.Format("{0}", name)); + } + } + } + + foreach (var type in _declaredTypes) { - data.Add(new PropertyCompletionItem() + if (type.Kind == TypeKind.Interface || type.Kind == TypeKind.Enum) { - Class = symbol.Class, - Description = symbol.Summary, - Name = symbol.Name, - Type = symbol.Type, - Priority = 2, - }); + interfaceTypes.Add(String.Format("{0}", type.Name)); + } + else if (type.Kind == TypeKind.Class) + { + referenceTypes.Add(String.Format("{0}", type.Name)); + } } - else if (symbol.Kind == SymbolKind.Field || symbol.Kind == SymbolKind.Local || symbol.Kind == SymbolKind.Parameter) + + if (referenceTypes.Count > 0) { - data.Add(new FieldCompletionItem() - { - Class = symbol.Class, - Description = symbol.Summary, - Name = symbol.Name, - Type = symbol.Type, - Priority = 2, - }); + text = text.Replace("@ReferenceTypes@", String.Join(Environment.NewLine, referenceTypes.Distinct())); } - else if (symbol.Kind == SymbolKind.Method) + + if (interfaceTypes.Count > 0) { - var methodCompletion = new MethodCompletionItem() - { - Class = symbol.Class, - Description = symbol.Summary, - Name = symbol.Name, - ReturnType = symbol.Type, - Priority = 2, - }; + text = text.Replace("@InterfaceTypes@", String.Join(Environment.NewLine, interfaceTypes.Distinct())); + } - for (int i = 0; i < symbol.Parameters.Count; i++) - { - var pair = symbol.Parameters[i]; + MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(text)); - methodCompletion.Parameters.Add(new KnownTypeMethodParameter() - { - Type = pair.Key, - Name = pair.Value, - IsLast = (i == symbol.Parameters.Count - 1) - }); - } + XmlTextReader xshd_reader = new XmlTextReader(ms); - data.Add(methodCompletion); + Dispatcher.BeginInvoke(new Action(() => + { + SyntaxHighlighting = HighlightingLoader.Load(xshd_reader, HighlightingManager.Instance); + xshd_reader.Close(); + ms.Dispose(); + })); + + + foreach (var knownType in _knownTypes) + { + knownType.LoadDocumentation(); } } - ShowCompletionWindow(data, word); - } + _isLoadingTypes = false; + }); + t.IsBackground = true; + t.Start(); } } - private void CompletionWindow_InsertionRequest(ICompletionData item) + private void InvalidateScriptTypesHighlightings() { - item.Complete(this); + var declaredTypes = _parser.GetDeclaredTypes(Text); + + if (declaredTypes.Exists(x => !_declaredTypes.Exists(y => y.Name == x.Name)) || _declaredTypes.Exists(x => !declaredTypes.Exists(y => y.Name == x.Name))) + { + _declaredTypes = declaredTypes; + InvalidateHighlighting(); + } + + _declaredTypes = declaredTypes; + + //for (int i = 0; i < TextArea.TextView.LineTransformers.Count; i++) + //{ + // if (TextArea.TextView.LineTransformers[i] is OffsetColorizer) + // { + // TextArea.TextView.LineTransformers.RemoveAt(i); + // } + //} + + //foreach (var cls in scriptClasses) + //{ + // Document.BeginUpdate(); + + // var line = Document.GetLineByOffset(cls.Index); + + // OffsetColorizer colorizer = new OffsetColorizer(line, cls.Index, cls.Index + cls.Name.Length, Brushes.Red); + // TextArea.TextView.LineTransformers.Add(colorizer); + + // Document.EndUpdate(); + //} } - private void ShowCompletionWindow(IList suggestions, String filter) + private void InvalidateUsings() { - IList data = completionWindow.CompletionList.CompletionData; - data.Clear(); + var oldUsings = _current_usings.ToList(); + _current_usings = _parser.GetUsings(Text); - foreach (var item in suggestions) + if (_current_usings.Exists(x => !oldUsings.Exists(y => y == x)) || oldUsings.Exists(x => !_current_usings.Exists(y => y == x))) { - data.Add(item); + InvalidateHighlighting(); } + } - if (data.Count > 0) + private void InvalidateFolding() + { + if (EnableFolding) { - completionWindow.ShowCompletion(); + if (foldingManager == null) + { + foldingManager = FoldingManager.Install(TextArea); + } - if (completionWindow.CompletionList.ListBox != null) + foldingStrategy.UpdateFoldings(foldingManager, Document); + } + } + + private void IndentCode() + { + Text = Indentation.CSharp.CSharpIndentationHelper.IndentCSharpCode(Text); + //Text = _parser.IndentCSharpCode(Text); + } + + internal DocumentLine GetCurrentLine() + { + int offset = CaretOffset; + var line = Document.GetLineByOffset(offset); + return line; + } + + private String GetCurrentLineText() + { + var text = Document.GetText(GetCurrentLine()); + return text; + } + + internal String GetCurrentWord() + { + return GetWordByEndIndex(CaretOffset); + } + + private String GetWordByEndIndex(int index) + { + String word = String.Empty; + var line = GetCurrentLine(); + + int position = index; + + for (int i = position - 1; i >= line.Offset; i--) + { + char c = Document.GetText(i, 1).First(); + + if (word_separators.Contains(c)) { - completionWindow.CompletionList.SelectItemFiltering(filter); + break; } + + word += c; } - else + + word = new string(word.Reverse().ToArray()); + + if (word.Length > 0) { - completionWindow.HideCompletion(); + word = word.Replace(".", ""); } - } - private void HideCompletionWindow() - { - completionWindow.HideCompletion(); + return word; } - private List GetScriptClassNames() + internal int GetCurrentWordStartIndex() { - List list = new List(); + var line = GetCurrentLine(); - Regex r = new Regex(@"(class\s+)(\w+)"); - var matches = r.Matches(Text); + int position = CaretOffset; - foreach (var m in matches.OfType()) + for (int i = position - 1; i >= line.Offset; i--) { - var g = m.Groups.OfType().Last(); - list.Add(g.Value); + char c = Document.GetText(i, 1).First(); + + if (word_separators.Contains(c)) + { + return i + 1; + } } - return list.Distinct().ToList(); + return line.Offset; } - private List GetScriptInterfaceOfEnumNames() + private String GetPreviousWord() { - List list = new List(); + int index = GetCurrentWordStartIndex() - 1; + return GetWordByEndIndex(index); + } - Regex r = new Regex(@"((enum|interface)\s+)(\w+)"); - var matches = r.Matches(Text); + private ConstructionSession GetConstructionSession() + { + var expression = _parser.GetCurrentConstructionExpression(GetCurrentLineText()); - foreach (var m in matches.OfType()) + if (expression != null) { - var g = m.Groups.OfType().Last(); - list.Add(g.Value); + ConstructionSession session = new ConstructionSession(); + + var line = GetCurrentLine(); + int parameterIndex = 0; + for (int i = CaretOffset; i > line.Offset; i--) + { + String c = Document.GetText(i, 1); + + if (c == "(") + { + var typeDeclaration = expression.Type as GenericNameSyntax; + + KnownType type = null; + + if (typeDeclaration != null) + { + var typeName = typeDeclaration.Identifier.ToString(); + var argumentsCount = typeDeclaration.TypeArgumentList.Arguments.Count; + session.TypeArguments = typeDeclaration.TypeArgumentList.Arguments.Select(x => x.ToString()).ToList(); + + if (argumentsCount == 0) + { + type = _knownTypes.FirstOrDefault(x => x.Type.Name == expression.Type.ToString()); + } + else + { + type = _knownTypes.FirstOrDefault(x => x.Type.Name == typeName + "`" + argumentsCount); + } + } + else + { + type = _knownTypes.FirstOrDefault(x => x.Name == expression.Type.ToString()); + } + + if (type != null) + { + session.Type = type; + session.ParameterIndex = parameterIndex; + return session; + } + else + { + return null; + } + } + else if (c == ",") + { + parameterIndex++; + } + + } } - return list.Distinct().ToList(); + return null; } - private List GetScriptEnumsAndInterfaces() + private MethodSession GetMethodSession() { - List list = new List(); - - Regex r = new Regex(@"((public|private|internal)\s+(enum|interface)\s+\w+)"); - var matches = r.Matches(Text); + var words = GetCurrentLineText().Split(' '); - foreach (var m in matches) + if (words.Count() > 0 && (words.First() == "private" || words.First() == "public" || words.First() == "void")) { - + return null; } - return list; - } - - private KnownType GetCurrentKnownType() - { - var expression = GetPreviousWords().LastOrDefault(); - return GetKnownTypeFromExpression(expression); - } + var expression = words.LastOrDefault(); - private KnownType GetKnownTypeFromExpression(String expression) - { if (expression != null) { - var tree = expression.Split('.').Select(x => x.Remove(@"\n|\t|\r|\(.*\)|\[.*\]|\s")).ToList(); + 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) + if (variableName != null && tree.Count > 1) { - //Search for enum type first - var enumType = _knownTypes.FirstOrDefault(x => x.Name == variableName && x.Type.IsEnum); - - if (enumType != null) - { - return enumType; - } - tree.RemoveAt(0); var variables = _parser.GetContextSymbols(Document.Text, CaretOffset); var variable = variables.FirstOrDefault(x => x.Name == variableName); @@ -1343,7 +1494,12 @@ namespace Tango.Scripting.Editors knownType = _knownTypes.FirstOrDefault(x => x.Type.Namespace + "." + x.Type.Name == member.ReturnType.Namespace + "." + member.ReturnType.Name); } - return knownType; + return new MethodSession() + { + Type = knownType, + MethodName = tree.Last(), + ParameterIndex = parameterIndex, + }; } } } @@ -1352,16 +1508,23 @@ namespace Tango.Scripting.Editors return null; } - private ScriptType GetCurrentDeclaredType() + private DeclaredMethodSession GetDeclaredMethodSession() { + var words = GetCurrentLineText().Split(' '); + + if (words.Count() > 0 && (words.First() == "private" || words.First() == "public" || words.First() == "void")) + { + return null; + } + var expression = GetPreviousWords().LastOrDefault(); if (expression != null) { - var tree = expression.Split('.').Select(x => x.Remove(@"\n|\t|\r|\(.*\)|\[.*\]|\s")).ToList(); + 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) + if (variableName != null && tree.Count > 0) { tree.RemoveAt(0); var variables = _parser.GetContextSymbols(Document.Text, CaretOffset); @@ -1369,7 +1532,7 @@ namespace Tango.Scripting.Editors if (variable != null) { - var declaredType = _declaredTypes.FirstOrDefault(x => x.Name == Regex.Replace(variable.Type, "<.+>", "")); + var declaredType = _declaredTypes.FirstOrDefault(x => x.Name == Regex.Replace(variable.Class, "<.+>", "")); if (declaredType != null) { @@ -1387,193 +1550,44 @@ namespace Tango.Scripting.Editors declaredType = _declaredTypes.FirstOrDefault(x => x.ContainingNamespace + "." + x.Name == member.ContainingNamespace + "." + member.Type); } - return declaredType; - } - } - } - } - - return null; - } - - #endregion - - #region Popup - - private void ShowPopup(Object content) - { - var position = TextArea.Caret.Position; - var textView = TextArea.TextView; - - var visualLocation = textView.GetVisualPosition(position, VisualYPosition.LineBottom); - var visualLocationTop = textView.GetVisualPosition(position, VisualYPosition.LineTop); - - Point location = textView.PointToScreen(visualLocation - textView.ScrollOffset); - Point locationTop = textView.PointToScreen(visualLocationTop - textView.ScrollOffset); - - _popup.Placement = PlacementMode.Absolute; - _popup.PlacementRectangle = new Rect(location, new Size(200, 100)); - - CurrentPopupContent = content; - - _popup.IsOpen = true; - } - - private void HidePopup() - { - _popup.IsOpen = false; - CurrentPopupContent = null; - } - - private MethodPopup CreateConstructionSessionPopupContent(ConstructionSession session) - { - MethodPopup popup = new MethodPopup(); - - foreach (var c in session.Type.Constructors) - { - MethodDescription method = new MethodDescription(); - method.ReturnType = session.Type.Name; - method.Description = c.Summary; - - if (session.Type.Type.IsGenericType && session.TypeArguments != null) - { - method.ReturnType = new String(session.Type.Name.TakeWhile(x => x != '`').ToArray()) + $"<{String.Join(",", session.TypeArguments)}>"; - } - - var parameters = c.Parameters; - - foreach (var p in parameters) - { - ParameterDescription pDescription = new ParameterDescription(method); - pDescription.Name = p.Name; - pDescription.Type = p.Type; - pDescription.Description = p.Description; - method.Parameters.Add(pDescription); - } - - popup.Methods.Add(method); - } - - if (session.ParameterIndex > 0) - { - popup.CurrentMethod = popup.Methods.FirstOrDefault(x => x.Parameters.Count == session.ParameterIndex + 1); - - if (popup.CurrentMethod == null) - { - popup.CurrentMethod = popup.Methods.FirstOrDefault(); - } - } - else - { - popup.CurrentMethod = popup.Methods.FirstOrDefault(); - } - - if (popup.CurrentMethod != null) - { - popup.CurrentMethodIndex = popup.Methods.IndexOf(popup.CurrentMethod) + 1; - } - - return popup; - } - - private MethodPopup CreateMethodSessionPopupContent(MethodSession session) - { - MethodPopup popup = new MethodPopup(); - - foreach (var m in session.Type.Methods.Where(x => x.Name == session.MethodName)) - { - MethodDescription method = new MethodDescription(); - method.ReturnType = session.Type.Name; - method.Description = m.Summary; - method.Name = m.NameWithTypeArguments; - method.Class = session.Type.FriendlyName; + var methodName = tree.Count > 0 ? tree.Last() : variableName; - //if (session.Type.Type.IsGenericType && session.TypeArguments != null) - //{ - // method.ReturnType = new String(session.Type.Name.TakeWhile(x => x != '`').ToArray()) + $"<{String.Join(",", session.TypeArguments)}>"; - //} + var method = declaredType.Symbols.FirstOrDefault(x => x.Kind == SymbolKind.Method && x.Name == methodName); - var parameters = m.Parameters; + if (method != null) + { + return new DeclaredMethodSession() + { + Type = declaredType, + Method = method, + }; + } + } + else if (tree.Count == 0) + { + var method = variable; - 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); + if (method != null) + { + return new DeclaredMethodSession() + { + Type = declaredType, + Method = method, + }; + } + } + } } - - 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; + return null; } - private MethodPopup CreateDeclaredMethodSessionPopupContent(DeclaredMethodSession session) + private List GetPreviousWords() { - 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; + var currentLine = GetCurrentLine(); + var currentText = Document.GetText(currentLine.Offset, CaretOffset - currentLine.Offset); + return currentText.Split(' ', ',').ToList(); } #endregion diff --git a/Software/Visual_Studio/TEMP/Tango.Scripting/Tango.Scripting/Parsing/ScriptParser.cs b/Software/Visual_Studio/TEMP/Tango.Scripting/Tango.Scripting/Parsing/ScriptParser.cs index f022f7999..15760c950 100644 --- a/Software/Visual_Studio/TEMP/Tango.Scripting/Tango.Scripting/Parsing/ScriptParser.cs +++ b/Software/Visual_Studio/TEMP/Tango.Scripting/Tango.Scripting/Parsing/ScriptParser.cs @@ -48,6 +48,8 @@ namespace Tango.Scripting.Parsing { var currentNode = GetCaretOffsetNode(code, caretOffset); + if (currentNode == null) return new List(); + if (currentNode.Ancestors().OfType().Count() == 0) { var usings = GetUsingsFull(code); -- cgit v1.3.1