public void TestCodeCompletionParserForFunctions() { string code = @"x[y[z.foo()].goo("; string functionName; string functionPrefix; CodeCompletionParser.GetFunctionToComplete(code, out functionName, out functionPrefix); Assert.AreEqual("goo", functionName); Assert.AreEqual("y[z.foo()]", functionPrefix); code = @"abc.X[xyz.foo("; CodeCompletionParser.GetFunctionToComplete(code, out functionName, out functionPrefix); Assert.AreEqual("foo", functionName); Assert.AreEqual("xyz", functionPrefix); code = @"pnt[9][0] = abc.X[{xyz.b.foo("; CodeCompletionParser.GetFunctionToComplete(code, out functionName, out functionPrefix); Assert.AreEqual("foo", functionName); Assert.AreEqual("xyz.b", functionPrefix); code = @"foo("; CodeCompletionParser.GetFunctionToComplete(code, out functionName, out functionPrefix); Assert.AreEqual("foo", functionName); Assert.AreEqual("", functionPrefix); }
/// <summary> /// Determines if the completion string is a valid type and /// enumerates the list of completion members on the type /// </summary> /// <param name="code"> code typed in the code block </param> /// <param name="stringToComplete"> Class name or declared variable </param> /// <returns> list of method and property members of the type </returns> internal IEnumerable <CompletionData> GetCompletionsOnType(string code, string stringToComplete) { IEnumerable <StaticMirror> members = null; // Determine if the string to be completed is a class var type = GetClassType(stringToComplete); if (type != null) { members = type.GetMembers(); } // If not of class type else { // Check if the string to be completed is a declared variable string typeName = CodeCompletionParser.GetVariableType(code, stringToComplete); if (typeName != null) { type = GetClassType(typeName); } if (type != null) { members = type.GetInstanceMembers(); } } return(members.Select(x => CompletionData.ConvertMirrorToCompletionData(x))); }
public void TestCodeCompletionParser() { string code = @"x[y[z.foo()].goo()].bar"; string actual = CodeCompletionParser.GetStringToComplete(code); string expected = "x[y[z.foo()].goo()].bar"; Assert.AreEqual(expected, actual); code = @"abc.X[xyz.foo().Y"; actual = CodeCompletionParser.GetStringToComplete(code); expected = "xyz.foo().Y"; Assert.AreEqual(expected, actual); code = @"pnt[9][0] = abc.X[{xyz.b.foo((abc"; actual = CodeCompletionParser.GetStringToComplete(code); expected = "abc"; Assert.AreEqual(expected, actual); code = @"pnt[9][0] = abc.X[{xyz.b.foo((abc*x"; actual = CodeCompletionParser.GetStringToComplete(code); expected = "x"; Assert.AreEqual(expected, actual); code = @"w = abc; w = xyz; w = xyz.b; w = xyz.b.foo; w = xyz.b.foo.Y"; actual = CodeCompletionParser.GetStringToComplete(code); expected = "xyz.b.foo.Y"; Assert.AreEqual(expected, actual); }
private void OnTextAreaTextEntered(object sender, TextCompositionEventArgs e) { try { var code = this.InnerTextEditor.Text.Substring(0, this.InnerTextEditor.CaretOffset); if (e.Text == ".") { string stringToComplete = CodeCompletionParser.GetStringToComplete(code).Trim('.'); var completions = this.GetCompletionData(code, stringToComplete); if (!completions.Any()) { return; } ShowCompletionWindow(completions); } // Complete function signatures else if (e.Text == "(") { string functionName; string functionPrefix; CodeCompletionParser.GetFunctionToComplete(code, out functionName, out functionPrefix); var insightItems = this.GetFunctionSignatures(code, functionName, functionPrefix); ShowInsightWindow(insightItems); } else if (e.Text == ")") { if (insightWindow != null) { insightWindow.Close(); } } else if (completionWindow == null && (char.IsLetterOrDigit(e.Text[0]) || char.Equals(e.Text[0], '_'))) { // Autocomplete as you type // complete global methods (builtins), all classes, symbols local to codeblock node string stringToComplete = CodeCompletionParser.GetStringToComplete(code); var completions = this.SearchCompletions(stringToComplete, nodeModel.GUID); if (!completions.Any()) { return; } ShowCompletionWindow(completions, completeWhenTyping: true); } } catch (System.Exception ex) { this.dynamoViewModel.Model.Logger.Log("Failed to perform code block autocomplete with exception:"); this.dynamoViewModel.Model.Logger.Log(ex.Message); this.dynamoViewModel.Model.Logger.Log(ex.StackTrace); } }
public void TestCodeCompletionParserForVariableType() { string code = "a : Point;"; string variableName = "a"; Assert.AreEqual("Point", CodeCompletionParser.GetVariableType(code, variableName)); code = @"a : Point = Point.ByCoordinates();"; Assert.AreEqual("Point", CodeCompletionParser.GetVariableType(code, variableName)); }
/// <summary> /// Returns the list of function signatures of all overloads of a given method /// </summary> /// <param name="code"> code being typed in code block </param> /// <param name="functionName"> given method name for which signature is queried </param> /// <param name="functionPrefix"> class name in case of constructor or static method, OR /// declared instance variable on which method is invoked </param> /// <param name="resolver"></param> /// <returns> list of method overload signatures </returns> internal IEnumerable <CompletionData> GetFunctionSignatures(string code, string functionName, string functionPrefix, ElementResolver resolver = null) { IEnumerable <MethodMirror> candidates = null; // if function is global, search for function in Built-ins if (string.IsNullOrEmpty(functionPrefix)) { return(StaticMirror.GetOverloadsOnBuiltIns(core, functionName). Select(x => { return new CompletionData(x.MethodName, CompletionData.CompletionType.Method) { Stub = x.ToString() }; })); } // Determine if the function prefix is a class name if (resolver != null) { functionPrefix = resolver.LookupResolvedName(functionPrefix) ?? functionPrefix; } var type = GetClassType(functionPrefix); if (type != null) { candidates = type.GetOverloadsOnType(functionName); } // If not of class type else { // Check if the function prefix is a typed identifier string typeName = CodeCompletionParser.GetVariableType(code, functionPrefix); if (typeName != null) { type = GetClassType(typeName); } if (type != null) { candidates = type.GetOverloadsOnInstance(functionName); } } return(candidates.Select(x => CompletionData.ConvertMirrorToCompletionData(x))); }
private void OnTextAreaTextEntered(object sender, TextCompositionEventArgs e) { try { int startPos = this.InnerTextEditor.CaretOffset; var code = this.InnerTextEditor.Text.Substring(0, startPos); if (e.Text == ".") { if (CodeCompletionParser.IsInsideCommentOrString(code, startPos)) { return; } string stringToComplete = CodeCompletionParser.GetStringToComplete(code).Trim('.'); var completions = this.GetCompletionData(code, stringToComplete); if (completions == null || !completions.Any()) { return; } ShowCompletionWindow(completions); } // Complete function signatures else if (e.Text == "(") { if (CodeCompletionParser.IsInsideCommentOrString(code, startPos)) { return; } string functionName; string functionPrefix; CodeCompletionParser.GetFunctionToComplete(code, out functionName, out functionPrefix); var insightItems = this.GetFunctionSignatures(code, functionName, functionPrefix); ShowInsightWindow(insightItems); } else if (e.Text == ")") { if (insightWindow != null) { insightWindow.Close(); } } else if (completionWindow == null && (char.IsLetterOrDigit(e.Text[0]) || e.Text[0] == '_')) { // Begin completion while typing only if the previous character already typed in // is a white space or non-alphanumeric character if (startPos > 1 && char.IsLetterOrDigit(InnerTextEditor.Document.GetCharAt(startPos - 2))) { return; } if (CodeCompletionParser.IsInsideCommentOrString(code, startPos)) { return; } // Autocomplete as you type // complete global methods (builtins), all classes, symbols local to codeblock node string stringToComplete = CodeCompletionParser.GetStringToComplete(code); var completions = this.SearchCompletions(stringToComplete, nodeViewModel.NodeModel.GUID); if (!completions.Any()) { return; } ShowCompletionWindow(completions, completeWhenTyping: true); } } catch (Exception) { } }
/// <summary> /// Parse text to determine if string being typed at caretPos is in /// the context of a comment or string or character /// </summary> /// <param name="text"> input block of code </param> /// <param name="caretPos"> caret position in text at which to determine context </param> /// <returns> True if any of above context is true </returns> public static bool IsInsideCommentOrString(string text, int caretPos) { var lexer = new CodeCompletionParser(text); lexer.ParseContext(caretPos); return lexer.isInSingleComment || lexer.isInString || lexer.isInChar || lexer.isInMultiLineComment; }
/// <summary> /// Given a block of code that's currently being typed /// this returns the method name and the type name on which it is invoked /// e.g. "Point.ByCoordinates" returns 'ByCoordinates' as the functionName and 'Point' as functionPrefix /// "abc.X[{xyz.b.foo" returns 'foo' as the functionName and 'xyz.b' as the "functionPrefix" on which it is invoked /// </summary> /// <param name="code"> input code block </param> /// <param name="functionName"> output function name </param> /// <param name="functionPrefix"> output type or variable on which fn is invoked </param> public static void GetFunctionToComplete(string code, out string functionName, out string functionPrefix) { var codeParser = new CodeCompletionParser(code); // TODO: Discard complete code statements terminated by ';' // and extract only the current line being typed for (int i = 0; i < code.Length; ++i) { codeParser.ParseStringToComplete(code[i]); } functionName = codeParser.functionName; functionPrefix = codeParser.functionPrefix; }
/// <summary> /// Given the code that's currently being typed in a CBN, /// this function extracts the expression that needs to be code-completed /// e.g. given "abc.X[{xyz.b.foo((abc" it returns "abc" /// which is the "thing" that needs to be queried for completions /// </summary> /// <param name="code"></param> public static string GetStringToComplete(string code) { var codeParser = new CodeCompletionParser(code); // TODO: Discard complete code statements terminated by ';' // and extract only the current line being typed for (int i = 0; i < code.Length; ++i) { codeParser.ParseStringToComplete(code[i]); } return codeParser.strPrefix; }