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