/// <summary> /// Handles autocomplete action. /// </summary> /// <param name="macro">Macro expression</param> /// <param name="position">Caret position</param> /// <param name="isShowContext">If true, method context should be returned, otherwise hints are returned</param> /// <param name="previousLines">Text of previous lines</param> private string AutoComplete(string macro, int position, bool isShowContext, string previousLines) { // Do lexical analysis, supress errors List <MacroElement> tokens = MacroElement.ParseExpression(macro, true); // Variables declared on actual line; List <string> inlineVariables = new List <string>(); // Locate current element, find all created variables MacroElement currentElement = null; int currentElementIndex = -1; for (int i = 0; i < tokens.Count; i++) { MacroElement el = tokens[i]; MacroElement elNext = (i < tokens.Count - 1 ? tokens[i + 1] : null); if (elNext == null || ((el.StartIndex <= position) && (elNext.StartIndex > position))) { currentElement = el; currentElementIndex = i; break; } if ((el.Type == ElementType.Operator) && (el.Expression == "=") && (i > 0)) { // Add variable declaration to special fields MacroElement elPrev = tokens[i - 1]; if (elPrev.Type == ElementType.Identifier) { inlineVariables.Add(elPrev.Expression); } } } if (isShowContext) { return(GetContext(tokens, currentElement, currentElementIndex)); } else { // If we are in the middle of the comment or a constant, do not show any help if ((currentElement != null) && ((currentElement.Type == ElementType.Boolean) || (currentElement.Type == ElementType.Double) || (currentElement.Type == ElementType.Integer) || (currentElement.Type == ElementType.String))) { return(""); } else { return(GetHints(tokens, currentElement, currentElementIndex, previousLines, inlineVariables)); } } }
/// <summary> /// Returns list of possible hints. /// </summary> /// <param name="tokens">Lexems from lexical analysis</param> /// <param name="currentElement">Current lexem</param> /// <param name="currentElementIndex">Index of the current lexem</param> /// <param name="previousLines">Previous lines to get previous variable declarations</param> private string GetHints(List <MacroElement> tokens, MacroElement currentElement, int currentElementIndex, string previousLines, List <string> inlineVariables) { // Get lists with methods and properties List <string> members = new List <string>(); string dataMemeberContext = ""; object obj = null; List <string> dataProperties = new List <string>(); if (currentElement == null) { GetPropertiesFromContext(members, null, ""); } else { // Properties autocomplete bool showAllProperties = false; if ((currentElement.Type == ElementType.LeftBracket) || (currentElement.Type == ElementType.LeftIndexer) || (currentElement.Type == ElementType.BlockStart) || (currentElement.Type == ElementType.BlockEnd) || (currentElement.Type == ElementType.Comma)) { showAllProperties = true; } if (!showAllProperties) { // We need to find current datamember context int brackets = 0; for (int i = currentElementIndex - 1; i >= 0; i--) { ElementType type = tokens[i].Type; if (brackets == 0) { // We need to take context to the left side of current lexem // It needs to preserve the structure (deepnes withing the brackets) if ((type == ElementType.Comma) || (type == ElementType.Operator) || (type == ElementType.LeftBracket) || (type == ElementType.LeftIndexer)) { break; } } // Append this part dataMemeberContext = tokens[i].Expression + dataMemeberContext; // Ensure correct deepnes within the brackets if ((type == ElementType.RightBracket) || (type == ElementType.RightIndexer)) { brackets++; } else if ((type == ElementType.LeftBracket) || (type == ElementType.LeftIndexer)) { brackets--; } } dataMemeberContext = dataMemeberContext.TrimEnd('.'); } // Analyze code before current line to find variable declarations (makes sense only for root hints - i.e. datamember context is empty) if (string.IsNullOrEmpty(dataMemeberContext)) { List <MacroElement> vartokens = MacroElement.ParseExpression(previousLines, true); List <string> variables = new List <string>(); for (int i = 0; i < vartokens.Count; i++) { MacroElement el = vartokens[i]; if ((el.Type == ElementType.Operator) && (el.Expression == "=") && (i > 0)) { // Add variable declaration to special fields MacroElement elPrev = vartokens[i - 1]; if (elPrev.Type == ElementType.Identifier) { variables.Add(elPrev.Expression); } } } // Add variables members.AddRange(variables); members.AddRange(inlineVariables); } obj = GetPropertiesFromContext(members, dataProperties, dataMemeberContext); } // Add proper methods if (string.IsNullOrEmpty(dataMemeberContext)) { // Add commands only for empty contexts members.AddRange(CommandsList); // Add namespaces objects members.Add("Math"); members.Add("Transformation"); members.Add("Countries"); // List of methods for any type FillFromMethodList(members, MacroMethods.GetMethodsForObject(null)); } else { if (obj == null) { // If the object is null we will offer string methods because these are the most common methods obj = ""; } // Get the list of suitable methods for resulting type FillFromMethodList(members, MacroMethods.GetMethodsForObject(obj)); } // Add methods which belongs to permanently registered namespaces members.AddRange(UsingList); // Sort everything members.Sort(); // Add data properties at the end if (dataProperties.Count > 0) { members.Add("----"); members.AddRange(dataProperties); } // Remove duplicities List <string> finalList = new List <string>(); foreach (string member in members) { if (!finalList.Contains(member)) { finalList.Add(member); } } StringBuilder sb = new StringBuilder(); foreach (string member in finalList) { sb.Append("$" + member); } return(sb.ToString().TrimStart('$')); }
/// <summary> /// Returns list of possible hints. /// </summary> /// <param name="tokens">Lexems from lexical analysis</param> /// <param name="currentElement">Current lexem</param> /// <param name="currentElementIndex">Index of the current lexem</param> /// <param name="previousLines">Previous lines to get previous variable declarations</param> private string GetHints(List <MacroElement> tokens, MacroElement currentElement, int currentElementIndex, string previousLines, IEnumerable <string> inlineVariables) { // Get lists with methods and properties List <string> members = new List <string>(); string dataMemeberContext = ""; object obj = null; List <string> dataProperties = new List <string>(); if (currentElement == null) { GetPropertiesFromContext(members, null, ""); } else { // Properties autocomplete bool showAllProperties = (currentElement.Type == ElementType.LeftBracket) || (currentElement.Type == ElementType.LeftIndexer) || (currentElement.Type == ElementType.BlockStart) || (currentElement.Type == ElementType.BlockEnd) || (currentElement.Type == ElementType.Comma) || MacroElement.IsValidOperator(currentElement.Expression); if (!showAllProperties) { // We need to find current datamember context int brackets = 0; for (int i = currentElementIndex - 1; i >= 0; i--) { ElementType type = tokens[i].Type; if (brackets == 0) { // We need to take context to the left side of current lexem // It needs to preserve the structure (deepnes withing the brackets) if ((type == ElementType.Comma) || (type == ElementType.Operator) || (type == ElementType.LeftBracket) || (type == ElementType.LeftIndexer)) { break; } } // Append this part dataMemeberContext = tokens[i].Expression + dataMemeberContext; // Ensure correct deepnes within the brackets if ((type == ElementType.RightBracket) || (type == ElementType.RightIndexer)) { brackets++; } else if ((type == ElementType.LeftBracket) || (type == ElementType.LeftIndexer)) { brackets--; } } dataMemeberContext = dataMemeberContext.TrimEnd('.'); } // Analyze code before current line to find variable declarations (makes sense only for root hints - i.e. datamember context is empty) if (string.IsNullOrEmpty(dataMemeberContext)) { List <MacroElement> vartokens = MacroElement.ParseExpression(previousLines, true); List <string> variables = new List <string>(); for (int i = 0; i < vartokens.Count; i++) { MacroElement el = vartokens[i]; if ((el.Type == ElementType.Operator) && (el.Expression == "=") && (i > 0)) { // Add variable declaration to special fields MacroElement elPrev = vartokens[i - 1]; if (elPrev.Type == ElementType.Identifier) { variables.Add(elPrev.Expression); } } } // Add variables members.AddRange(variables); members.AddRange(inlineVariables); } obj = GetPropertiesFromContext(members, dataProperties, dataMemeberContext); } // Do not process further if only prioritized properties should be handled if (string.IsNullOrEmpty(dataMemeberContext) && Resolver.ShowOnlyPrioritized) { members.AddRange(Resolver.NamedSourceDataPriority); members.Sort(); return(MakeFinalList(members)); } // Add proper methods if (string.IsNullOrEmpty(dataMemeberContext)) { // Add commands only for empty contexts members.AddRange(CommandsList); members.Add("Math"); // Add namespaces objects if (!ShowOnlyInnerSources) { members.Add("Transformation"); members.Add("Countries"); members.Add("Visitor"); } // List of methods for any type FillFromMethodList(members, MacroMethods.GetMethodsForObject(null)); } else { if (obj == null) { // If the object is null we will offer string methods because these are the most common methods obj = ""; } // Get the list of suitable methods for resulting type FillFromMethodList(members, MacroMethods.GetMethodsForObject(obj)); } // Add methods which belongs to permanently registered namespaces members.AddRange(UsingList); // Remove items which should not be displayed if (Resolver.Context.DisablePageContextMacros) { if (members.Contains("CurrentDocument")) { members.Remove("CurrentDocument"); } if (members.Contains("CurrentPageInfo")) { members.Remove("CurrentPageInfo"); } } // Remove context objects if not needed if (Resolver.Context.DisableContextObjectMacros) { for (int i = members.Count - 1; i >= 0; i--) { if (members[i].EndsWithCSafe("context", true)) { members.RemoveAt(i); } } } // Sort everything members.Sort(); // Insert prioritized items at the beginning if (string.IsNullOrEmpty(dataMemeberContext) && (Resolver.NamedSourceDataPriority.Count > 0)) { List <string> priorities = Resolver.NamedSourceDataPriority; priorities.Sort(); members.Insert(0, "----"); members.InsertRange(0, priorities); } // Add data properties at the end if (dataProperties.Count > 0) { members.Add("----"); members.AddRange(dataProperties); } // Remove duplicities return(MakeFinalList(members)); }