/// <summary> /// Merge selected items from the SORTED lists without duplicate values /// /// </summary> /// <param name="list">Items to merge</param> /// <param name="mask">Filter by mask</param> /// <param name="filterStatic">Ignore static members (inheritance)</param> public void Merge(ASMemberList list, FlagType mask, bool filterStatic) { int index = 0; bool added; foreach (ASMember m in list) { if ((m.Flags & mask) == mask && (!filterStatic || (m.Flags & FlagType.Static) == 0)) { added = false; while (index < items.Count) { if (m.CompareTo(items[index]) <= 0) { if (!m.Equals(items[index])) { items.Insert(index, m); } added = true; break; } index++; } if (!added) { items.Add(m); } } } }
/// <summary> /// Merge one item into the list /// </summary> /// <param name="item">Item to merge</param> public void Merge(ASMember item) { ASMemberList list = new ASMemberList(); list.Add(item); Merge(list, 0); }
public ASClass() { ClassName = null; Imports = new ASMemberList(); Methods = new ASMemberList(); Vars = new ASMemberList(); Properties = new ASMemberList(); }
public ASMemberList MultipleSearch(string name, FlagType mask) { ASMemberList result = new ASMemberList(); foreach (ASMember m in items) { if ((m.Name.Equals(name)) && ((m.Flags & mask) == mask)) { result.Add(m); } } return(result); }
/// <summary> /// Parse a class from source /// </summary> /// <param name="aClass">Class object</param> /// <param name="src">Class source</param> static public void ParseClass(ASClass aClass, string src) { // remove comments StringCollection comments = new StringCollection(); src = CleanClassSource(src, comments); // check class definition Match mClass = re_class.Match(src); if (!mClass.Success) { aClass.ClassName = null; return; } // classname string prevCName = aClass.ClassName; aClass.ClassName = mClass.Groups["cname"].Value; // HACK AS3 package support string preClassSrc = src.Substring(0, mClass.Groups["ctype"].Index); string AS3package = null; Match mPackage = re_AS3package.Match(preClassSrc); if (mPackage.Success) { aClass.IsAS3 = true; AS3package = mPackage.Groups["name"].Value; if (AS3package != null && AS3package.Length > 0) { aClass.ClassName = AS3package + "." + aClass.ClassName; } } else { aClass.IsAS3 = false; } // check classname int p = aClass.ClassName.LastIndexOf("."); string constructor = (p >= 0) ? aClass.ClassName.Substring(p + 1) : aClass.ClassName; string classType = mClass.Groups["ctype"].Value; if (src.Substring(0, mClass.Groups["cname"].Index).IndexOf(" comment0 ") >= 0) { aClass.Comments = comments[0]; } // class base path bool validClassFile = true; int basepos = aClass.FileName.LastIndexOf(aClass.ClassName.Replace('.', Path.DirectorySeparatorChar) + ".as"); if (basepos < 0) { // this class name & file don't match, it can lead to dangerous errors validClassFile = false; // warm about the misspelled class name if (!aClass.FileName.EndsWith("/" + constructor + ".as") || !aClass.FileName.ToUpper().EndsWith("\\" + aClass.ClassName.ToUpper().Replace('.', '\\') + ".AS")) { if (prevCName != aClass.ClassName) { string msg = String.Format("The {0} '{1}' does not match the file name:\n{2}", classType, aClass.ClassName, aClass.FileName); context.DisplayError(msg); } } aClass.BasePath = System.IO.Path.GetDirectoryName(aClass.FileName) + "\\"; } else { aClass.BasePath = aClass.FileName.Substring(0, basepos); } // add to classpath context.SetTemporaryBasePath(aClass.FileName, aClass.BasePath); // class flag aClass.Flags = FlagType.Class; if (classType == "interface") { aClass.Flags |= FlagType.Interface; } if (mClass.Groups["keys"].Value.IndexOf("intrinsic") >= 0) { aClass.Flags |= FlagType.Intrinsic; } if (mClass.Groups["keys"].Value.IndexOf("dynamic") >= 0) { aClass.Flags |= FlagType.Dynamic; } // import statements ParseImports(preClassSrc, aClass); preClassSrc = null; // inheritance string herit = mClass.Groups["herit"].Value; Match mExtends = re_extends.Match(herit); string extends = (validClassFile && mExtends.Success) ? mExtends.Groups["cname"].ToString() : "Object"; if ((extends != aClass.ClassName) && (aClass.ClassName != "TopLevel")) { aClass.Extends = null; // resolve extended class ASClass extendsClass = context.GetClassByName(extends, aClass); // detect infinite extension loop ASClass tmpClass = extendsClass; while (tmpClass != null) { if (tmpClass == aClass) { string msg = String.Format("The {0} '{1}' extends itself.", classType, aClass.ClassName); context.DisplayError(msg); extendsClass = null; break; } tmpClass = tmpClass.Extends; } if (extendsClass != null) { aClass.Extends = extendsClass; } else { aClass.Extends = new ASClass(); } } Match mImplements = re_implements.Match(herit); if (mImplements.Success) { string implements; if (!mExtends.Success || mImplements.Index > mExtends.Index) { implements = herit.Substring(mImplements.Index + mImplements.Length).Trim(); } else { implements = herit.Substring(mImplements.Index + mImplements.Length, mExtends.Index - mImplements.Index - mImplements.Length).Trim(); } aClass.Implements = re_parametersSeparator.Replace(implements, ", "); } else { aClass.Implements = null; } // clean class body src = "; " + src.Substring(mClass.Groups["herit"].Index + mClass.Groups["herit"].Value.Length + 1); src = re_balancedBraces.Replace(src, ";"); // if updating, clear aClass.Methods.Clear(); aClass.Properties.Clear(); aClass.Vars.Clear(); // parse functions string keys; bool isStatic; MatchCollection mcFunc = re_functions.Matches(src); Match mFunc; Match mType; Match mComments; ASMember member; foreach (Match m in mcFunc) { mFunc = re_splitFunction.Match(m.Value); if (!mFunc.Success) { continue; } // keywords keys = mFunc.Groups["keys"].Value; member = new ASMember(); member.Flags = FlagType.Function; if (keys.IndexOf("private") >= 0) { member.Flags |= FlagType.Private; } else { member.Flags |= FlagType.Public; } isStatic = (keys.IndexOf("static") >= 0); if (isStatic) { member.Flags |= FlagType.Static; } else { member.Flags |= FlagType.Dynamic; } // comments if (comments.Count > 0) { mComments = re_commentIndex.Match(keys); if (mComments.Success) { member.Comments = comments[Convert.ToInt16(mComments.Groups["index"].Value)]; } } // method member.Name = mFunc.Groups["fname"].Value.Trim(); if (member.Name.Length == 0) { continue; } // parameters member.Parameters = re_colonParams.Replace(re_parametersSeparator.Replace(mFunc.Groups["params"].Value.Trim(), ", "), ":"); // return type mType = re_variableType.Match(mFunc.Groups["type"].Value); if (mType.Success) { member.Type = mType.Groups["type"].Value; } else { member.Type = ""; } // constructor type if (member.Name == constructor) { member.Flags |= FlagType.Constructor; member.Type = constructor; } // getter/setter if ((member.Name.Length > 4) && ((int)member.Name[3] < 33)) { Match mProp = re_isGetterSetter.Match(member.Name); if (mProp.Success) { string pname = mProp.Groups["pname"].Value; ASMember prop = aClass.Properties.Search(pname, 0); if (prop == null) { prop = member; prop.Name = pname; prop.Flags -= FlagType.Function; aClass.Properties.Add(prop); } if (mProp.Groups["type"].Value == "g") { prop.Flags |= FlagType.Getter; prop.Type = member.Type; if (!mType.Success) { prop.Type = "Object"; } } else { prop.Flags |= FlagType.Setter; prop.Parameters = member.Parameters; } if ((member.Comments != null) && ((prop.Comments == null) || (prop.Comments.Length < member.Comments.Length))) { prop.Comments = member.Comments; } } // store method else { aClass.Methods.Add(member); } } // store method else { aClass.Methods.Add(member); } } // parse variables MatchCollection mcVars = re_variable.Matches(src); Match mVar; foreach (Match m in mcVars) { mVar = re_splitVariable.Match(m.Value); if (!mVar.Success) { continue; } // parse method definition keys = mVar.Groups["keys"].Value; member = new ASMember(); member.Flags = FlagType.Variable; // keywords if (keys.IndexOf("private") >= 0) { member.Flags |= FlagType.Private; } else { member.Flags |= FlagType.Public; } isStatic = (keys.IndexOf("static") >= 0); if (isStatic) { member.Flags |= FlagType.Static; } else { member.Flags |= FlagType.Dynamic; } // comments mComments = re_commentIndex.Match(keys); if (mComments.Success) { member.Comments = comments[Convert.ToInt16(mComments.Groups["index"].Value)]; } // name member.Name = mVar.Groups["pname"].Value; // type mType = re_variableType.Match(mVar.Groups["type"].Value); if (mType.Success) { member.Type = mType.Groups["type"].Value; } else { member.Type = "Object"; } // store aClass.Vars.Add(member); } // HACK AS3 'const' declarations if (AS3package != null) { mcVars = re_constant.Matches(src); foreach (Match m in mcVars) { mVar = re_splitConstant.Match(m.Value); if (!mVar.Success) { continue; } // parse method definition keys = mVar.Groups["keys"].Value; member = new ASMember(); member.Flags = FlagType.Variable; // keywords if (keys.IndexOf("private") >= 0) { member.Flags |= FlagType.Private; } else { member.Flags |= FlagType.Public; } isStatic = (keys.IndexOf("static") >= 0); if (isStatic) { member.Flags |= FlagType.Static; } else { member.Flags |= FlagType.Dynamic; } // comments mComments = re_commentIndex.Match(keys); if (mComments.Success) { member.Comments = comments[Convert.ToInt16(mComments.Groups["index"].Value)]; } // name member.Name = mVar.Groups["pname"].Value; // type mType = re_variableType.Match(mVar.Groups["type"].Value); if (mType.Success) { member.Type = mType.Groups["type"].Value; } else { member.Type = "Object"; } // store aClass.Vars.Add(member); } } // is also a package? //DebugConsole.Trace("check folder "+aClass.FileName.Substring(0, aClass.FileName.Length-3)); if (System.IO.Directory.Exists(aClass.FileName.Substring(0, aClass.FileName.Length - 3))) { string package = aClass.FileName.Substring(aClass.BasePath.Length); package = package.Substring(0, package.IndexOf('.')); ASMemberList pList = context.GetSubClasses(package); if ((pList != null) && (pList.Count > 0)) { //DebugConsole.Trace("Sub classes/packages "+package+" "+pList.Count); aClass.Flags |= FlagType.Package; aClass.Package = pList; // if intrinsic class, inherit flag if ((aClass.Flags & FlagType.Intrinsic) == FlagType.Intrinsic) { foreach (ASMember import in pList) { import.Flags |= FlagType.Intrinsic; } } } } // done }
public void UpdateView(ASClass aClass) { bool updateToken = false; try { DebugConsole.Trace("UI: update "+aClass.ClassName); if (aClass.IsVoid()) return; // compute class data "checksum" to know if it changed string fileName = aClass.FileName; string prevDataCheck = (string)checkEntries[fileName]; StringBuilder sb = new StringBuilder().Append(aClass.Extends.ClassName); foreach(ASMember import in aClass.Imports) sb.Append(import.Name); foreach(ASMember method in aClass.Methods) sb.Append(method.Flags.ToString()).Append(method.ToString()); foreach(ASMember prop in aClass.Properties) sb.Append(prop.Flags.ToString()).Append(prop.ToString()); foreach(ASMember var in aClass.Vars) sb.Append(var.Flags.ToString()).Append(var.ToString()); string classDataCheck = sb.ToString(); // for tree exploration TreeNodeCollection nodes = classTree.Nodes; TreeNode node = null; TreeNode insertBefore = null; // re-sort imports by package aClass.Sort(); ASMemberList import2 = new ASMemberList(); ASMember newImport; foreach(ASMember import in aClass.Imports) { newImport = new ASMember(); newImport.Name = import.Type; import2.Add(newImport); } import2.Sort(); // search item insertion/update position string cname = aClass.ClassName; bool entryExists = false; foreach(TreeNode sub in nodes) { if (sub.Text == cname) { node = sub; entryExists = true; break; } else if (sub.Text.CompareTo(cname) > 0) { insertBefore = sub; break; } } // New class if (node == null) { updateToken = true; classTree.BeginStatefulUpdate(); // create class node node = new TreeNode(cname); node.Tag = aClass.FileName; if (insertBefore != null) nodes.Insert(insertBefore.Index, node); else nodes.Add(node); // class details nodes if (showExtend) node.Nodes.Add(new TreeNode("Extends",1,1)); if (showImports) node.Nodes.Add(new TreeNode("Imports",1,1)); // class members nodes if (memberGroups == 1) { node.Nodes.Add(new TreeNode("Members",1,1)); } else { if (memberGroups > 1) { node.Nodes.Add(new TreeNode("Methods",1,1)); node.Nodes.Add(new TreeNode("Properties",1,1)); } if (memberGroups > 2) node.Nodes.Add(new TreeNode("Variables",1,1)); } } // Check class infos else { if (classDataCheck == prevDataCheck) return; updateToken = true; classTree.BeginStatefulUpdate(); } // // UPDATE CLASS INFO // checkEntries[fileName] = classDataCheck; int index = 0; TreeNode sub2; // entends if (showExtend) { nodes = node.Nodes[index++].Nodes; nodes.Clear(); if (!aClass.Extends.IsVoid()) { if ((aClass.Extends.Flags & FlagType.Intrinsic) > 0) sub2 = new TreeNode(aClass.Extends.ClassName, 7,7); else sub2 = new TreeNode(aClass.Extends.ClassName, 0,0); sub2.Tag = aClass.Extends.FileName; nodes.Add(sub2); } } // imports if (showImports) { nodes = node.Nodes[index++].Nodes; nodes.Clear(); foreach(ASMember import in import2) { if ((import.Flags & FlagType.Intrinsic) > 0) nodes.Add(new TreeNode(import.Name, 7,7)); else nodes.Add(new TreeNode(import.Name, 0,0)); } } // methods int img; if (memberGroups > 0) { nodes = node.Nodes[index++].Nodes; nodes.Clear(); foreach(ASMember method in aClass.Methods) { img = ((method.Flags & FlagType.Private) > 0) ? 12 : 3; sub2 = new TreeNode(method.ToString(), img,img); sub2.Tag = method.Name; nodes.Add(sub2); } // properties if (memberGroups > 1) { nodes = node.Nodes[index++].Nodes; nodes.Clear(); } foreach(ASMember prop in aClass.Properties) { img = ((prop.Flags & FlagType.Private) > 0) ? 13 : 4; sub2 = new TreeNode(prop.ToString(), img,img); sub2.Tag = prop.Name; nodes.Add(sub2); } // variables if (memberGroups > 2) { nodes = node.Nodes[index++].Nodes; nodes.Clear(); } foreach(ASMember var in aClass.Vars) { img = ((var.Flags & FlagType.Private) > 0) ? 14 : 5; sub2 = new TreeNode(var.ToString(),img,img); sub2.Tag = var.Name; nodes.Add(sub2); } } // expand index = 0; if (showExtend) index++; if (showImports) index++; for (int i=0; i<memberGroups; i++) node.Nodes[index++].Expand(); node.Expand(); if (!entryExists) node.EnsureVisible(); } finally { if (updateToken) classTree.EndStatefulUpdate(); } }
/// <summary> /// Complete object member /// </summary> /// <param name="Sci">Scintilla control</param> /// <param name="autoHide">Don't keep the list open if the word does not match</param> /// <returns>Auto-completion has been handled</returns> static private bool HandleDotCompletion(ScintillaNet.ScintillaControl Sci, bool autoHide) { // get expression at cursor position int position = Sci.CurrentPos; ASExpr expr = GetExpression(Sci, position); if (expr.Value == null) return true; int dotIndex = expr.Value.LastIndexOf('.'); if (dotIndex == 0) return true; string tail = (dotIndex >= 0) ? expr.Value.Substring(dotIndex+1) : expr.Value; DebugConsole.Trace("? "+dotIndex+" '"+expr.separator+"' "+expr.Keyword+" ."+tail); // complete keyword if (dotIndex < 0) { if (expr.Keyword == "new") return HandleNewCompletion(Sci, expr.Value, autoHide); else if (expr.separator == ':') { if (HandleColonCompletion(Sci, expr.Value, autoHide)) return true; } else if (expr.Keyword == "import") return HandleImportCompletion(Sci, expr.Value, autoHide); else if ((expr.Keyword == "extends") || (expr.Keyword == "implements")) return HandleNewCompletion(Sci, expr.Value, autoHide); } else if ((expr.ContextBody == null) && (expr.separator != ':') && (expr.separator != '=') && (expr.Keyword != "import") && (expr.Keyword != "extends") && (expr.Keyword != "implements") ) return true; // complete declaration if ((expr.ContextBody == null) && ((expr.separator == ';') || (expr.separator == ' ') || (expr.separator == '}') || (expr.separator == '{'))) { if (expr.Value.IndexOf('#') >= 0) return true; else { string text = " "+ASClassParser.CleanClassSource(Sci.GetText(Sci.CurrentPos), null)+" "; if (Regex.IsMatch(text, "[\\s](class|interface)[\\s]")) { DebugConsole.Trace("Match class"); Match m = Regex.Match(text, "[\\s](class|interface)[\\s]+"+ASContext.CurrentClass.ClassName+"[\\s{]"); if (m.Success) { if (text.Substring(m.Index).IndexOf('{') > 0) return HandleDeclarationCompletion(Sci, "function private public static var", tail, autoHide); else if ((expr.Keyword != "extends") && (expr.Keyword != "implements")) return HandleDeclarationCompletion(Sci, "extends implements", tail, autoHide); } else return true; } else if (expr.Keyword == "class") return true; else if (dotIndex < 0) return HandleDeclarationCompletion(Sci, "import", tail, autoHide); } } DebugConsole.Trace("** Complete expression '"+expr.separator+"' "+expr.Value.Length); DebugConsole.Trace(expr.Value); // Context expr.LocalVars = ParseLocalVars(expr); ASClass cClass = ASContext.CurrentClass; ASResult result; ASClass tmpClass; if (dotIndex > 0) { // Expression before cursor result = EvalExpression(expr.Value, expr, cClass, false); if (result.IsNull()) return true; tmpClass = result.Class; } else { result = new ASResult(); tmpClass = cClass; } ASMemberList mix = new ASMemberList(); // local vars are the first thing to try if ((result.IsNull() || (dotIndex < 0)) && (expr.ContextFunction != null)) mix.Merge(expr.LocalVars); // packages if (tmpClass.Package != null) mix.Merge(tmpClass.Package); // get all members FlagType mask = 0; if ((expr.ContextFunction != null) || (expr.separator != ':')) { // user setting may ask to hide some members bool limitMembers = ASContext.HideIntrinsicMembers || (autoHide && !ASContext.AlwaysShowIntrinsicMembers); // static or dynamic members? if (!result.IsNull()) mask = (result.IsStatic) ? FlagType.Static : FlagType.Dynamic; // show private member of current class only only if (!FriendClasses(cClass, tmpClass)) mask |= FlagType.Public; DebugConsole.Trace("Filter members by: "+mask); // explore members bool classExtend = false; if (!limitMembers || (tmpClass.ClassName != "Object")) while ((tmpClass != null) && (!tmpClass.IsVoid())) { tmpClass.Sort(); // add members mix.Merge(tmpClass.Methods, mask, classExtend); // remove constructor methods foreach(ASMember meth in tmpClass.Methods) if ((meth.Flags & FlagType.Constructor) > 0) { mix.Remove(meth); break; } mix.Merge(tmpClass.Properties, mask, classExtend); mix.Merge(tmpClass.Vars, mask, classExtend); if (result.IsStatic && (tmpClass.Package != null)) { DebugConsole.Trace("Class is package "+tmpClass.ClassName); mix.Merge(tmpClass.Package, 0); } tmpClass = tmpClass.Extends; if (tmpClass != null) { // static members not inherited in AS3 classExtend = tmpClass.IsAS3; if (((tmpClass.Flags & FlagType.Intrinsic) == FlagType.Intrinsic) && (tmpClass.FileName.StartsWith(ASContext.TopLevelClassPath))) { if (limitMembers) tmpClass = null; } } } } // known classes / toplevel vars/methods if (result.IsNull() || (dotIndex < 0)) { mix.Merge(cClass.ToASMember()); mix.Merge(cClass.Imports); mix.Merge(ASContext.TopLevel.Imports); mix.Merge(ASContext.TopLevel.Methods); mix.Merge(ASContext.TopLevel.Vars); mix.Merge(ASContext.GetBasePackages()); } // show ArrayList list = new ArrayList(); foreach(ASMember member in mix) list.Add(new MemberItem(member)); CompletionList.Show(list, autoHide, tail); return true; }
static private void CompleteTemplate(string Context) { // get indentation ScintillaNet.ScintillaControl Sci = ASContext.MainForm.CurSciControl; if (Sci == null) { return; } int position = Sci.CurrentPos; int line = Sci.LineFromPosition(position); int indent = Sci.LineIndentPosition(line) - Sci.PositionFromLine(line); string tab = Sci.GetLine(line).Substring(0, indent); // get EOL int eolMode = Sci.EOLMode; string newline; if (eolMode == 0) { newline = "\r\n"; } else if (eolMode == 1) { newline = "\r"; } else { newline = "\n"; } // empty box if (Context == null) { Sci.ReplaceSel(newline + tab + "* " + newline + tab + "*/"); position += newline.Length + tab.Length + 2; Sci.SetSel(position, position); } // method details else { string box = newline + tab + "* "; Match mFun = ASClassParser.re_splitFunction.Match(Context); if (mFun.Success) { // parameters ASMemberList list = ASComplete.ParseMethodParameters(mFun.Groups["params"].Value); foreach (ASMember param in list) { box += newline + tab + "* @param\t" + param.Name; } // return type Match mType = ASClassParser.re_variableType.Match(mFun.Groups["type"].Value); if (mType.Success && (mType.Groups["type"].Value.ToLower() != "void")) { box += newline + tab + "* @return"; //+mType.Groups["type"].Value; } } box += newline + tab + "*/"; Sci.ReplaceSel(box); position += newline.Length + tab.Length + 2; Sci.SetSel(position, position); } }
/// <summary> /// Returns parameters string as member list /// </summary> /// <param name="parameters">Method parameters</param> /// <returns>Member list</returns> static public ASMemberList ParseMethodParameters(string parameters) { ASMemberList list = new ASMemberList(); if (parameters == null) return list; int p = parameters.IndexOf('('); if (p >= 0) parameters = parameters.Substring(p+1, parameters.IndexOf(')')-p-1); parameters = parameters.Trim(); if (parameters.Length == 0) return list; string[] sparam = parameters.Split(','); string[] parType; ASMember param; foreach(string pt in sparam) { parType = pt.Split(':'); param = new ASMember(); param.Name = parType[0].Trim(); if (param.Name.Length == 0) continue; if (parType.Length == 2) param.Type = parType[1].Trim(); else param.Type = "Object"; param.Flags = FlagType.Variable | FlagType.Dynamic; list.Add(param); } return list; }
public ASMemberList MultipleSearch(string name, FlagType mask) { ASMemberList result = new ASMemberList(); foreach (ASMember m in items) if ((m.Name.Equals(name)) && ((m.Flags & mask) == mask)) result.Add(m); return result; }
static private bool HandleNewCompletion(ScintillaNet.ScintillaControl Sci, string tail, bool autoHide) { DebugConsole.Trace("** Complete: new <class>"); // Context ASClass cClass = ASContext.CurrentClass; // Consolidate known classes ASMemberList known = new ASMemberList(); known.Merge(cClass.ToASMember()); known.Merge(cClass.Imports); known.Merge(ASContext.TopLevel.Imports); known.Merge(ASContext.GetBasePackages()); // show ArrayList list = new ArrayList(); foreach(ASMember member in known) list.Add(new MemberItem(member)); CompletionList.Show(list, autoHide, tail); return true; }
static private bool HandleColonCompletion(ScintillaNet.ScintillaControl Sci, string tail, bool autoHide) { DebugConsole.Trace("** Complete: ':'<class>"); // Context ASClass cClass = ASContext.CurrentClass; // Valid statement int position = Sci.CurrentPos-1; string keyword = null; int stylemask = (1 << Sci.StyleBits) -1; char c; while (position > 0) { position--; c = (char)Sci.CharAt(position); if ((c == '{') || (c == '=')) return false; else if ((Sci.StyleAt(position) & stylemask) == 19) { keyword = GetWordLeft(Sci, ref position); DebugConsole.Trace("'"+keyword+"'"); break; } } if (keyword != "var" && keyword != "function" && keyword != "get" && keyword != "set" && keyword != "const") return false; // Consolidate known classes ASMemberList known = new ASMemberList(); known.Merge(cClass.ToASMember()); known.Merge(cClass.Imports); known.Merge(ASContext.TopLevel.Imports); known.Merge(ASContext.GetBasePackages()); // show ArrayList list = new ArrayList(); foreach(ASMember member in known) list.Add(new MemberItem(member)); CompletionList.Show(list, autoHide, tail); return true; }
public void UpdateView(ASClass aClass) { bool updateToken = false; try { DebugConsole.Trace("UI: update " + aClass.ClassName); if (aClass.IsVoid()) { return; } // compute class data "checksum" to know if it changed string fileName = aClass.FileName; string prevDataCheck = (string)checkEntries[fileName]; StringBuilder sb = new StringBuilder().Append(aClass.Extends.ClassName); foreach (ASMember import in aClass.Imports) { sb.Append(import.Name); } foreach (ASMember method in aClass.Methods) { sb.Append(method.Flags.ToString()).Append(method.ToString()); } foreach (ASMember prop in aClass.Properties) { sb.Append(prop.Flags.ToString()).Append(prop.ToString()); } foreach (ASMember var in aClass.Vars) { sb.Append(var.Flags.ToString()).Append(var.ToString()); } string classDataCheck = sb.ToString(); // for tree exploration TreeNodeCollection nodes = classTree.Nodes; TreeNode node = null; TreeNode insertBefore = null; // re-sort imports by package aClass.Sort(); ASMemberList import2 = new ASMemberList(); ASMember newImport; foreach (ASMember import in aClass.Imports) { newImport = new ASMember(); newImport.Name = import.Type; import2.Add(newImport); } import2.Sort(); // search item insertion/update position string cname = aClass.ClassName; bool entryExists = false; foreach (TreeNode sub in nodes) { if (sub.Text == cname) { node = sub; entryExists = true; break; } else if (sub.Text.CompareTo(cname) > 0) { insertBefore = sub; break; } } // New class if (node == null) { updateToken = true; classTree.BeginStatefulUpdate(); // create class node node = new TreeNode(cname); node.Tag = aClass.FileName; if (insertBefore != null) { nodes.Insert(insertBefore.Index, node); } else { nodes.Add(node); } // class details nodes if (showExtend) { node.Nodes.Add(new TreeNode("Extends", 1, 1)); } if (showImports) { node.Nodes.Add(new TreeNode("Imports", 1, 1)); } // class members nodes if (memberGroups == 1) { node.Nodes.Add(new TreeNode("Members", 1, 1)); } else { if (memberGroups > 1) { node.Nodes.Add(new TreeNode("Methods", 1, 1)); node.Nodes.Add(new TreeNode("Properties", 1, 1)); } if (memberGroups > 2) { node.Nodes.Add(new TreeNode("Variables", 1, 1)); } } } // Check class infos else { if (classDataCheck == prevDataCheck) { return; } updateToken = true; classTree.BeginStatefulUpdate(); } // // UPDATE CLASS INFO // checkEntries[fileName] = classDataCheck; int index = 0; TreeNode sub2; // entends if (showExtend) { nodes = node.Nodes[index++].Nodes; nodes.Clear(); if (!aClass.Extends.IsVoid()) { if ((aClass.Extends.Flags & FlagType.Intrinsic) > 0) { sub2 = new TreeNode(aClass.Extends.ClassName, 7, 7); } else { sub2 = new TreeNode(aClass.Extends.ClassName, 0, 0); } sub2.Tag = aClass.Extends.FileName; nodes.Add(sub2); } } // imports if (showImports) { nodes = node.Nodes[index++].Nodes; nodes.Clear(); foreach (ASMember import in import2) { if ((import.Flags & FlagType.Intrinsic) > 0) { nodes.Add(new TreeNode(import.Name, 7, 7)); } else { nodes.Add(new TreeNode(import.Name, 0, 0)); } } } // methods int img; if (memberGroups > 0) { nodes = node.Nodes[index++].Nodes; nodes.Clear(); foreach (ASMember method in aClass.Methods) { img = ((method.Flags & FlagType.Private) > 0) ? 12 : 3; sub2 = new TreeNode(method.ToString(), img, img); sub2.Tag = method.Name; nodes.Add(sub2); } // properties if (memberGroups > 1) { nodes = node.Nodes[index++].Nodes; nodes.Clear(); } foreach (ASMember prop in aClass.Properties) { img = ((prop.Flags & FlagType.Private) > 0) ? 13 : 4; sub2 = new TreeNode(prop.ToString(), img, img); sub2.Tag = prop.Name; nodes.Add(sub2); } // variables if (memberGroups > 2) { nodes = node.Nodes[index++].Nodes; nodes.Clear(); } foreach (ASMember var in aClass.Vars) { img = ((var.Flags & FlagType.Private) > 0) ? 14 : 5; sub2 = new TreeNode(var.ToString(), img, img); sub2.Tag = var.Name; nodes.Add(sub2); } } // expand index = 0; if (showExtend) { index++; } if (showImports) { index++; } for (int i = 0; i < memberGroups; i++) { node.Nodes[index++].Expand(); } node.Expand(); if (!entryExists) { node.EnsureVisible(); } } finally { if (updateToken) { classTree.EndStatefulUpdate(); } } }
/// <summary> /// Search all base packages (com, net, org,...) in classpath /// </summary> /// <returns>Base packages list as members</returns> static public ASMemberList GetBasePackages() { ASMemberList packages = new ASMemberList(); ASMember package; string[] dirEntries; string[] fileEntries; string cname; string upPath; string mmCP = MMClassPath.ToUpper(); string mtascCP = mtascRootFolder.ToUpper(); bool notMacromedia; bool notMTASC; foreach(string path in classPath) try { upPath = path.ToUpper(); notMacromedia = (mmCP.Length == 0) || !upPath.StartsWith(mmCP); notMTASC = (mtascCP.Length == 0) || !upPath.StartsWith(mtascCP); // base classes if (notMacromedia && notMTASC) { try { fileEntries = System.IO.Directory.GetFiles(path, "*.as"); } catch { // fail silently fileEntries = null; } if (fileEntries != null) foreach(string entry in fileEntries) { cname = GetLastStringToken(entry, dirSeparator); int p = cname.LastIndexOf('.'); cname = cname.Substring(0,p); if (!cname.StartsWith("_") && (cname.IndexOf('.') < 0) && (cname.IndexOf(' ') < 0) && (packages.Search(cname, 0) == null)) { //DebugConsole.Trace("Base class "+cname); package = new ASMember(); package.Flags = 0; package.Type = package.Name = cname; packages.Add(package); } } } // base packages if (notMacromedia) { try { dirEntries = System.IO.Directory.GetDirectories(path); } catch { // fail silently dirEntries = null; } if (dirEntries != null) foreach(string entry in dirEntries) { cname = GetLastStringToken(entry, dirSeparator); if (!cname.StartsWith("_") && (cname.IndexOf(' ') < 0) && (cname.IndexOf('.') < 0) && (packages.Search(cname, 0) == null)) { //DebugConsole.Trace("Base package "+cname); package = new ASMember(); package.Flags = FlagType.Package; package.Type = package.Name = cname; packages.Add(package); } } } else if (packages.Search("mx", 0) == null) { package = new ASMember(); package.Flags = FlagType.Package; package.Type = package.Name = "mx"; packages.Add(package); } } catch(Exception ex) { ErrorHandler.ShowError(ex.Message+"\n"+path, ex); } packages.Sort(); return packages; }
/// <summary> /// Find folder and classes in classpath /// </summary> /// <param name="folder">Path to eval</param> /// <returns>Package folders and classes</returns> static public ASMemberList FindPackage(string folder, bool completeContent) { if ((folder == null) || (folder.Length == 0)) return null; ASMemberList package = new ASMemberList(); ASMember pathMember; string[] dirEntries; string cname; foreach(string path in classPath) try { if (System.IO.Directory.Exists(path+folder)) { // continue parsing? if (!completeContent) return package; // add sub packages try { dirEntries = System.IO.Directory.GetDirectories(path+folder); } catch { // fail silently dirEntries = null; } if (dirEntries != null) foreach(string entry in dirEntries) { cname = GetLastStringToken(entry, dirSeparator); if ((cname.Length > 0) && !cname.StartsWith("_") && (cname.IndexOf(' ') < 0) && (cname.IndexOf('.') < 0) && (package.Search(cname, 0) == null)) { pathMember = new ASMember(); pathMember.Flags = FlagType.Package; pathMember.Type = folder.Replace(dirSeparatorChar, '.')+"."+cname; pathMember.Name = cname; package.Add(pathMember); } } // add sub classes try { dirEntries = System.IO.Directory.GetFiles(path+folder); } catch { // fail silently dirEntries = null; } if (dirEntries != null) foreach(string entry in dirEntries) if (entry.EndsWith(".as")) { cname = GetLastStringToken(entry, dirSeparator); cname = cname.Substring(0, cname.LastIndexOf(".")); pathMember = package.Search(cname, 0); if ((pathMember == null) && (cname.Length > 0) && (cname.IndexOf(' ') < 0) && (cname.IndexOf('.') < 0)) { pathMember = new ASMember(); pathMember.Flags = 0; pathMember.Type = folder.Replace(dirSeparatorChar,'.')+"."+cname; pathMember.Name = cname; package.Add(pathMember); } } } } catch(Exception ex) { ErrorHandler.ShowError(ex.Message+"\n"+path+folder, ex); } // result if (package.Count > 0) { package.Sort(); return package; } else return null; }
/// <summary> /// Merge SORTED lists without duplicate values /// </summary> /// <param name="list">Items to merge</param> public void Merge(ASMemberList list) { Merge(list, 0); }
/// <summary> /// Merge selected items from the SORTED lists without duplicate values /// /// </summary> /// <param name="list">Items to merge</param> /// <param name="mask">Filter by mask</param> /// <param name="filterStatic">Ignore static members (inheritance)</param> public void Merge(ASMemberList list, FlagType mask, bool filterStatic) { int index = 0; bool added; foreach (ASMember m in list) if ((m.Flags & mask) == mask && (!filterStatic || (m.Flags & FlagType.Static) == 0)) { added = false; while (index < items.Count) { if (m.CompareTo(items[index]) <= 0) { if (!m.Equals(items[index])) items.Insert(index, m); added = true; break; } index++; } if (!added) items.Add(m); } }
/// <summary> /// Parse function body for local var definitions /// TODO ASComplete: parse coma separated local vars definitions /// </summary> /// <param name="expression">Expression source</param> /// <returns>Local vars dictionnary (name, type)</returns> static public ASMemberList ParseLocalVars(ASExpr expression) { ASMemberList vars = new ASMemberList(); if ((expression.ContextBody == null) || (expression.ContextBody.Length == 0)) return vars; // parse MatchCollection mcVars = re_variable.Matches(";"+expression.ContextBody); Match mVar; Match mType; string type; ASMember var; foreach(Match m in mcVars) { mVar = re_splitVariable.Match(m.Value); if (!mVar.Success) continue; mType = re_variableType.Match(mVar.Groups["type"].Value); if (mType.Success) type = mType.Groups["type"].Value; else type = "Object"; var = new ASMember(); var.Flags = FlagType.Variable | FlagType.Dynamic; var.Name = mVar.Groups["pname"].Value; var.Type = type; vars.Add(var); } // method parameters vars.Merge( ParseMethodParameters(expression.ContextFunction) ); return vars; }