static public void ContextualGenerator(ScintillaNet.ScintillaControl Sci)
        {
            if (ASContext.Context is ASContext) (ASContext.Context as ASContext).UpdateCurrentFile(false); // update model
            if ((ASContext.Context.CurrentClass.Flags & (FlagType.Enum | FlagType.TypeDef)) > 0) return;

            lookupPosition = -1;
            int position = Sci.CurrentPos;
            if (Sci.BaseStyleAt(position) == 19) // on keyword
                return;
            bool isNotInterface = (ASContext.Context.CurrentClass.Flags & FlagType.Interface) == 0;
            int line = Sci.LineFromPosition(position);
            contextToken = Sci.GetWordFromPosition(position);
            contextMatch = null;

            FoundDeclaration found = GetDeclarationAtLine(Sci, line);
            string text = Sci.GetLine(line);
            bool suggestItemDeclaration = false;

            if (isNotInterface && !String.IsNullOrEmpty(contextToken) && Char.IsDigit(contextToken[0]))
            {
                ShowConvertToConst(found);
                return;
            }

            ASResult resolve = ASComplete.GetExpressionType(Sci, Sci.WordEndPosition(position, true));
            contextResolved = resolve;
            
            // ignore automatic vars (MovieClip members)
            if (isNotInterface
                && resolve.Member != null
                && (((resolve.Member.Flags & FlagType.AutomaticVar) > 0) || (resolve.InClass != null && resolve.InClass.QualifiedName == "Object")))
            {
                resolve.Member = null;
                resolve.Type = null;
            }

            if (isNotInterface && found.inClass != ClassModel.VoidClass && contextToken != null)
            {
                if (resolve.Member == null && resolve.Type != null
                    && (resolve.Type.Flags & FlagType.Interface) > 0) // implement interface
                {
                    contextParam = resolve.Type.Type;
                    ShowImplementInterface(found);
                    return;
                }

                if (resolve.Member != null && !ASContext.Context.CurrentClass.IsVoid()
                    && (resolve.Member.Flags & FlagType.LocalVar) > 0) // promote to class var
                {
                    contextMember = resolve.Member;
                    ShowPromoteLocalAndAddParameter(found);
                    return;
                }
            }
            
            if (contextToken != null && resolve.Member == null) // import declaration
            {
                if ((resolve.Type == null || resolve.Type.IsVoid() || !ASContext.Context.IsImported(resolve.Type, line)) && CheckAutoImport(found)) return;
                if (resolve.Type == null)
                {
                    int stylemask = (1 << Sci.StyleBits) - 1;
                    suggestItemDeclaration = ASComplete.IsTextStyle(Sci.StyleAt(position - 1) & stylemask);
                }
            }

            if (isNotInterface && found.member != null)
            {
                // private var -> property
                if ((found.member.Flags & FlagType.Variable) > 0 && (found.member.Flags & FlagType.LocalVar) == 0)
                {
                    // maybe we just want to import the member's non-imported type
                    Match m = Regex.Match(text, String.Format(patternVarDecl, found.member.Name, contextToken));
                    if (m.Success)
                    {
                        contextMatch = m;
                        ClassModel type = ASContext.Context.ResolveType(contextToken, ASContext.Context.CurrentModel);
                        if (type.IsVoid() && CheckAutoImport(found))
                            return;
                    }
                    ShowGetSetList(found);
                    return;
                }
                // inside a function
                else if ((found.member.Flags & (FlagType.Function | FlagType.Getter | FlagType.Setter)) > 0
                    && resolve.Member == null && resolve.Type == null)
                {
                    if (contextToken != null)
                    {
                        // "generate event handlers" suggestion
                        string re = String.Format(patternEvent, contextToken);
                        Match m = Regex.Match(text, re, RegexOptions.IgnoreCase);
                        if (m.Success)
                        {
                            contextMatch = m;
                            contextParam = CheckEventType(m.Groups["event"].Value);
                            ShowEventList(found);
                            return;
                        }
                        m = Regex.Match(text, String.Format(patternAS2Delegate, contextToken), RegexOptions.IgnoreCase);
                        if (m.Success)
                        {
                            contextMatch = m;
                            ShowDelegateList(found);
                            return;
                        }
                        // suggest delegate
                        if (ASContext.Context.Features.hasDelegates)
                        {
                            m = Regex.Match(text, @"([a-z0-9_.]+)\s*\+=\s*" + contextToken, RegexOptions.IgnoreCase);
                            if (m.Success)
                            {
                                int offset = Sci.PositionFromLine(Sci.LineFromPosition(position))
                                    + m.Groups[1].Index + m.Groups[1].Length;
                                resolve = ASComplete.GetExpressionType(Sci, offset);
                                if (resolve.Member != null)
                                    contextMember = ResolveDelegate(resolve.Member.Type, resolve.InFile);
                                contextMatch = m;
                                ShowDelegateList(found);
                                return;
                            }
                        }
                    }
                    else
                    {
                        // insert a default handler name, then "generate event handlers" suggestion
                        Match m = Regex.Match(text, String.Format(patternEvent, ""), RegexOptions.IgnoreCase);
                        if (m.Success)
                        {
                            int regexIndex = m.Index + Sci.PositionFromLine(Sci.CurrentLine);
                            GenerateDefaultHandlerName(Sci, position, regexIndex, m.Groups["event"].Value, true);
                            resolve = ASComplete.GetExpressionType(Sci, Sci.CurrentPos);
                            if (resolve.Member == null || (resolve.Member.Flags & FlagType.AutomaticVar) > 0)
                            {
                                contextMatch = m;
                                contextParam = CheckEventType(m.Groups["event"].Value);
                                ShowEventList(found);
                            }
                            return;
                        }

                        // insert default delegate name, then "generate delegate" suggestion
                        if (ASContext.Context.Features.hasDelegates)
                        {
                            m = Regex.Match(text, @"([a-z0-9_.]+)\s*\+=\s*", RegexOptions.IgnoreCase);
                            if (m.Success)
                            {
                                int offset = Sci.PositionFromLine(Sci.LineFromPosition(position))
                                        + m.Groups[1].Index + m.Groups[1].Length;
                                resolve = ASComplete.GetExpressionType(Sci, offset);
                                if (resolve.Member != null)
                                {
                                    contextMember = ResolveDelegate(resolve.Member.Type, resolve.InFile);
                                    string delegateName = resolve.Member.Name;
                                    if (delegateName.StartsWith("on")) delegateName = delegateName.Substring(2);
                                    GenerateDefaultHandlerName(Sci, position, offset, delegateName, false);
                                    resolve = ASComplete.GetExpressionType(Sci, Sci.CurrentPos);
                                    if (resolve.Member == null || (resolve.Member.Flags & FlagType.AutomaticVar) > 0)
                                    {
                                        contextMatch = m;
                                        ShowDelegateList(found);
                                    }
                                    return;
                                }
                            }
                        }
                    }
                }

                // "Generate fields from parameters" suggestion
                if (found.member != null
                    && (found.member.Flags & FlagType.Function) > 0
                    && found.member.Parameters != null && (found.member.Parameters.Count > 0)
                    && resolve.Member != null && (resolve.Member.Flags & FlagType.ParameterVar) > 0)
                {
                    contextMember = resolve.Member;
                    ShowFieldFromParameter(found);
                    return;
                }

                // "add to interface" suggestion
                if (resolve.Member != null
                    && resolve.Member.Name == found.member.Name
                    && line == found.member.LineFrom
                    && ((found.member.Flags & FlagType.Function) > 0 
                            || (found.member.Flags & FlagType.Getter) > 0
                            || (found.member.Flags & FlagType.Setter) > 0)
                    && found.inClass != ClassModel.VoidClass
                    && found.inClass.Implements != null
                    && found.inClass.Implements.Count > 0)
                {
                    string funcName = found.member.Name;
                    FlagType flags = found.member.Flags & ~FlagType.Access;
                    
                    List<string> interfaces = new List<string>();
                    foreach (string interf in found.inClass.Implements)
                    {
                        bool skip = false;
                        ClassModel cm = ASContext.Context.ResolveType(interf, ASContext.Context.CurrentModel);
                        foreach (MemberModel m in cm.Members)
                        {
                            if (m.Name.Equals(funcName) && m.Flags.Equals(flags))
                            {
                                skip = true;
                                break;
                            }
                        }
                        if (!skip)
                        {
                            interfaces.Add(interf);
                        }
                    }
                    if (interfaces.Count > 0)
                    {
                        ShowAddInterfaceDefList(found, interfaces);
                        return;
                    }
                }

                // "assign var to statement" suggestion
                int curLine = Sci.CurrentLine;
                string ln = Sci.GetLine(curLine).TrimEnd();
                if (ln.Length > 0 && ln.IndexOf("=") == -1 
                    && ln.Length <= Sci.CurrentPos - Sci.PositionFromLine(curLine)) // cursor at end of line
                {
                    ShowAssignStatementToVarList(found);
                    return;
                }
            }
            
            // suggest generate constructor / toString
            if (isNotInterface && found.member == null && found.inClass != ClassModel.VoidClass && contextToken == null)
            {
                bool hasConstructor = false;
                bool hasToString = false;
                foreach (MemberModel m in ASContext.Context.CurrentClass.Members)
                {
                    if (!hasConstructor && (m.Flags & FlagType.Constructor) > 0)
                        hasConstructor = true;

                    if (!hasToString && (m.Flags & FlagType.Function) > 0 && m.Name.Equals("toString"))
                        hasToString = true;
                }

                if (!hasConstructor || !hasToString)
                {
                    ShowConstructorAndToStringList(found, hasConstructor, hasToString);
                    return;
                }
            }

            if (isNotInterface 
                && resolve.Member != null
                && resolve.Type != null
                && resolve.Type.QualifiedName == "String"
                && found.inClass != ClassModel.VoidClass)
            {
                int lineStartPos = Sci.PositionFromLine(Sci.CurrentLine);
                string lineStart = text.Substring(0, Sci.CurrentPos - lineStartPos);
                Match m = Regex.Match(lineStart, String.Format(@"new\s+(?<event>\w+)\s*\(\s*\w+", lineStart));
                if (m.Success)
                {
                    Group g = m.Groups["event"];
                    ASResult eventResolve = ASComplete.GetExpressionType(Sci, lineStartPos + g.Index + g.Length);
                    if (eventResolve != null && eventResolve.Type != null)
                    {
                        ClassModel aType = eventResolve.Type;
                        aType.ResolveExtends();
                        while (!aType.IsVoid() && aType.QualifiedName != "Object")
                        {
                            if (aType.QualifiedName == "flash.events.Event")
                            {
                                contextParam = eventResolve.Type.QualifiedName;
                                ShowEventMetatagList(found);
                                return;
                            }
                            aType = aType.Extends;
                        }
                    }
                }
            }
            
            // suggest declaration
            if (contextToken != null)
            {
                if (suggestItemDeclaration)
                {
                    Match m = Regex.Match(text, String.Format(patternClass, contextToken));
                    if (m.Success)
                    {
                        contextMatch = m;
                        ShowNewClassList(found);
                    }
                    else if (!found.inClass.IsVoid())
                    {
                        m = Regex.Match(text, String.Format(patternMethod, contextToken));
                        if (m.Success)
                        {
                            contextMatch = m;
                            ShowNewMethodList(found);
                        }
                        else ShowNewVarList(found);
                    }
                }
                else
                {
                    if (resolve != null
                        && resolve.InClass != null
                        && resolve.InClass.InFile != null
                        && resolve.Member != null
                        && (resolve.Member.Flags & FlagType.Function) > 0
                        && File.Exists(resolve.InClass.InFile.FileName)
                        && !resolve.InClass.InFile.FileName.StartsWith(PathHelper.AppDir))
                    {
                        Match m = Regex.Match(text, String.Format(patternMethodDecl, contextToken));
                        Match m2 = Regex.Match(text, String.Format(patternMethod, contextToken));
                        if (!m.Success && m2.Success)
                        {
                            contextMatch = m;
                            ShowChangeMethodDeclList(found);
                        }
                    }
                    else if (resolve != null
                        && resolve.Type != null
                        && resolve.Type.InFile != null
                        && resolve.RelClass != null
                        && File.Exists(resolve.Type.InFile.FileName)
                        && !resolve.Type.InFile.FileName.StartsWith(PathHelper.AppDir))
                    {
                        Match m = Regex.Match(text, String.Format(patternClass, contextToken));
                        if (m.Success)
                        {
                            contextMatch = m;
                            ShowChangeConstructorDeclList(found);
                        }
                    }
                }
            }
            // TODO: Empty line, show generators list?
        }
Exemple #2
0
        static public void ContextualGenerator(ScintillaNet.ScintillaControl Sci)
        {
            if (ASContext.Context is ASContext)
                (ASContext.Context as ASContext).UpdateCurrentFile(false); // update model

            lookupPosition = -1;
            int position = Sci.CurrentPos;
            if (Sci.BaseStyleAt(position) == 19) // on keyword
                return;
            int line = Sci.LineFromPosition(position);
            contextToken = Sci.GetWordFromPosition(position);
            contextMatch = null;

            FoundDeclaration found = GetDeclarationAtLine(Sci, line);
            string text = Sci.GetLine(line);
            bool suggestItemDeclaration = false;

            if (!String.IsNullOrEmpty(contextToken) && Char.IsDigit(contextToken[0]))
            {
                ShowConvertToConst(found);
                return;
            }

            ASResult resolve = ASComplete.GetExpressionType(Sci, Sci.WordEndPosition(position, true));
            // ignore automatic vars (MovieClip members)
            if (resolve.Member != null &&
                (((resolve.Member.Flags & FlagType.AutomaticVar) > 0)
                 || (resolve.inClass != null && resolve.inClass.QualifiedName == "Object")))
            {
                resolve.Member = null;
                resolve.Type = null;
            }

            if (found.inClass != ClassModel.VoidClass && contextToken != null)
            {
                if (resolve.Member == null && resolve.Type != null
                    && (resolve.Type.Flags & FlagType.Interface) > 0) // implement interface
                {
                    contextParam = resolve.Type.Type;
                    ShowImplementInterface(found);
                    return;
                }

                if (resolve.Member != null && !ASContext.Context.CurrentClass.IsVoid()
                    && (resolve.Member.Flags & FlagType.LocalVar) > 0) // promote to class var
                {
                    contextMember = resolve.Member;
                    ShowPromoteLocalAndAddParameter(found);
                    return;
                }

                if (resolve.Member == null && resolve.Type == null) // import declaration
                {
                    if (CheckAutoImport(found))
                    {
                        return;
                    }
                    else
                    {
                        int stylemask = (1 << Sci.StyleBits) - 1;
                        if (ASComplete.IsTextStyle(Sci.StyleAt(position - 1) & stylemask))
                        {
                            suggestItemDeclaration = true;
                        }
                    }
                }
            }

            if (found.member != null)
            {
                // private var -> property
                if ((found.member.Flags & FlagType.Variable) > 0 && (found.member.Flags & FlagType.LocalVar) == 0)
                {
                    // maybe we just want to import the member's non-imported type
                    Match m = Regex.Match(text, String.Format(patternVarDecl, found.member.Name, contextToken));
                    if (m.Success)
                    {
                        contextMatch = m;
                        ClassModel type = ASContext.Context.ResolveType(contextToken, ASContext.Context.CurrentModel);
                        if (type.IsVoid() && CheckAutoImport(found))
                            return;
                    }
                    // create property
                    ShowGetSetList(found);
                    return;
                }
                // inside a function
                else if ((found.member.Flags & (FlagType.Function | FlagType.Getter | FlagType.Setter)) > 0
                    && resolve.Member == null && resolve.Type == null)
                {
                    if (contextToken != null)
                    {
                        // "generate event handlers" suggestion
                        Match m = Regex.Match(text, String.Format(patternEvent, contextToken), RegexOptions.IgnoreCase);
                        if (m.Success)
                        {
                            contextMatch = m;
                            contextParam = CheckEventType(m.Groups["event"].Value);
                            ShowEventList(found);
                            return;
                        }
                        m = Regex.Match(text, String.Format(patternDelegate, contextToken), RegexOptions.IgnoreCase);
                        if (m.Success)
                        {
                            contextMatch = m;
                            ShowDelegateList(found);
                            return;
                        }
                    }
                }

                // "Generate fields from parameters" suggestion
                if (found.member != null
                    && (found.member.Flags & FlagType.Function) > 0
                    && (found.member.Flags & FlagType.Static) == 0
                    && found.member.Parameters != null && (found.member.Parameters.Count > 0)
                    && resolve.Member != null && (resolve.Member.Flags & FlagType.ParameterVar) > 0)
                {
                    contextMember = resolve.Member;
                    ShowFieldFromParameter(found);
                    return;
                }

                // "add to interface" suggestion
                if (resolve.Member != null &&
                    resolve.Member.Name == found.member.Name &&
                    (found.member.Flags & FlagType.Function) > 0 &&
                    found.inClass != null &&
                    found.inClass.Implements != null &&
                    found.inClass.Implements.Count > 0)
                {
                    string funcName = found.member.Name;
                    int classPosStart = Sci.PositionFromLine(found.inClass.LineFrom);

                    bool skip = false;
                    foreach (string interf in found.inClass.Implements)
                    {
                        if (skip)
                        {
                            break;
                        }
                        ClassModel cm = ASContext.Context.ResolveType(interf, ASContext.Context.CurrentModel);
                        contextParam = cm.Type;
                        MemberList members = cm.Members;
                        foreach (MemberModel m in members)
                        {
                            if (m.Name.Equals(funcName))
                            {
                                skip = true;
                                break;
                            }
                        }
                    }
                    if (!skip && contextParam != null)
                    {
                        ShowAddInterfaceDefList(found);
                        return;
                    }
                }


                // "assign var to statement" siggestion
                int curLine = Sci.LineFromPosition(Sci.CurrentPos);
                string ln = Sci.GetLine(curLine);
                if (ln.Trim().Length > 0 && ln.TrimEnd().Length <= Sci.CurrentPos - Sci.PositionFromLine(curLine))
                {
                    Regex re = new Regex("=");
                    Match m = re.Match(ln);
                    if (!m.Success)
                    {
                        ShowAssignStatementToVarList(found);
                    }
                }
            }

            // suggest generate constructor / toString
            if (found.member == null && found.inClass != ClassModel.VoidClass && contextToken == null)
            {
                ClassModel cm = ASContext.Context.CurrentClass;
                MemberList members = cm.Members;

                bool hasConstructor = false;
                bool hasToString = false;
                foreach (MemberModel m in members)
                {
                    if ((m.Flags & FlagType.Constructor) > 0)
                    {
                        hasConstructor = true;
                    }
                    if ((m.Flags & FlagType.Function) > 0 && m.Name.Equals("toString"))
                    {
                        hasToString = true;
                    }
                }

                if (!hasConstructor || !hasToString)
                {
                    ShowConstructorAndToStringList(found, hasConstructor, hasToString);
                    return;
                }
            }

            if (resolve.Member != null
                && resolve.Type != null
                && resolve.Type.QualifiedName == "String"
                && found.inClass != null)
            {
                int lineStartPos = Sci.PositionFromLine(Sci.LineFromPosition(Sci.CurrentPos));
                string lineStart = text.Substring(0, Sci.CurrentPos - lineStartPos);
                Match m = Regex.Match(lineStart, String.Format(@"new\s+(?<event>\w+)\s*\(\s*\w+", lineStart));
                if (m.Success)
                {
                    Group g = m.Groups["event"];
                    ASResult eventResolve = ASComplete.GetExpressionType(Sci, lineStartPos + g.Index + g.Length);
                    if (eventResolve != null && eventResolve.Type != null)
                    {
                        ClassModel aType = eventResolve.Type;
                        aType.ResolveExtends();
                        while (!aType.IsVoid() && aType.QualifiedName != "Object")
                        {
                            if (aType.QualifiedName == "flash.events.Event")
                            {
                                contextParam = eventResolve.Type.QualifiedName;
                                ShowEventMetatagList(found);
                                return;
                            }
                            aType = aType.Extends;
                        }
                    }
                }
            }


            
            // suggest declaration
            if (contextToken != null)
            {
                if (suggestItemDeclaration)
                {
                    Match m = Regex.Match(text, String.Format(patternClass, contextToken));
                    if (m.Success)
                    {
                        contextMatch = m;
                        ShowNewClassList(found);
                    }
                    else
                    {
                        m = Regex.Match(text, String.Format(patternMethod, contextToken));
                        if (m.Success)
                        {
                            contextMatch = m;
                            ShowNewMethodList(found);
                        }
                        else ShowNewVarList(found);
                    }
                }
                else
                {
                    if (resolve != null 
                        && resolve.inClass != null 
                        && resolve.inClass.InFile != null
                        && resolve.Member != null
                        && (resolve.Member.Flags & FlagType.Function) > 0
                        && File.Exists(resolve.inClass.InFile.FileName)
                        && !resolve.inClass.InFile.FileName.StartsWith(PathHelper.AppDir))
                    {
                        Match m = Regex.Match(text, String.Format(patternMethodDecl, contextToken));
                        Match m2 = Regex.Match(text, String.Format(patternMethod, contextToken));
                        if (!m.Success && m2.Success)
                        {
                            contextMatch = m;
                            ShowChangeMethodDeclList(found);
                        }
                    }
                }
            }
            

            // TODO  Empty line, show generators list?
        }
        public static void GenerateExtractVariable(ScintillaNet.ScintillaControl Sci, string NewName)
        {
            FileModel cFile;
            IASContext context = ASContext.Context;
            Int32 pos = Sci.CurrentPos;

            string expression = Sci.SelText.Trim(new char[] { '=', ' ', '\t', '\n', '\r', ';', '.' });
            expression = expression.TrimEnd(new char[] { '(', '[', '{', '<' });
            expression = expression.TrimStart(new char[] { ')', ']', '}', '>' });

            cFile = ASContext.Context.CurrentModel;
            ASFileParser parser = new ASFileParser();
            parser.ParseSrc(cFile, Sci.Text);

            MemberModel current = cFile.Context.CurrentMember;

            string characterClass = ScintillaNet.ScintillaControl.Configuration.GetLanguage(Sci.ConfigurationLanguage).characterclass.Characters;

            int funcBodyStart = ASGenerator.GetBodyStart(current.LineFrom, current.LineTo, Sci);
            Sci.SetSel(funcBodyStart, Sci.LineEndPosition(current.LineTo));
            string currentMethodBody = Sci.SelText;

            bool isExprInSingleQuotes = (expression.StartsWith("'") && expression.EndsWith("'"));
            bool isExprInDoubleQuotes = (expression.StartsWith("\"") && expression.EndsWith("\""));
            int stylemask = (1 << Sci.StyleBits) - 1;
            int lastPos = -1;
            char prevOrNextChar;
            Sci.Colourise(0, -1);
            while (true)
            {
                lastPos = currentMethodBody.IndexOf(expression, lastPos + 1);
                if (lastPos > -1)
                {
                    if (lastPos > 0)
                    {
                        prevOrNextChar = currentMethodBody[lastPos - 1];
                        if (characterClass.IndexOf(prevOrNextChar) > -1)
                        {
                            continue;
                        }
                    }
                    if (lastPos + expression.Length < currentMethodBody.Length)
                    {
                        prevOrNextChar = currentMethodBody[lastPos + expression.Length];
                        if (characterClass.IndexOf(prevOrNextChar) > -1)
                        {
                            continue;
                        }
                    }

                    int style = Sci.StyleAt(funcBodyStart + lastPos) & stylemask;
                    if (ASComplete.IsCommentStyle(style))
                    {
                        continue;
                    }
                    else if ((isExprInDoubleQuotes && currentMethodBody[lastPos] == '"' && currentMethodBody[lastPos + expression.Length - 1] == '"')
                        || (isExprInSingleQuotes && currentMethodBody[lastPos] == '\'' && currentMethodBody[lastPos + expression.Length - 1] == '\''))
                    {

                    }
                    else if (!ASComplete.IsTextStyle(style))
                    {
                        continue;
                    }

                    Sci.SetSel(funcBodyStart + lastPos, funcBodyStart + lastPos + expression.Length);
                    Sci.ReplaceSel(NewName);
                    currentMethodBody = currentMethodBody.Substring(0, lastPos) + NewName + currentMethodBody.Substring(lastPos + expression.Length);
                    lastPos += NewName.Length;
                }
                else
                {
                    break;
                }
            }

            Sci.CurrentPos = funcBodyStart;
            Sci.SetSel(Sci.CurrentPos, Sci.CurrentPos);

            MemberModel m = new MemberModel(NewName, "", FlagType.LocalVar, 0);
            m.Value = expression;

            string snippet = TemplateUtils.GetTemplate("Variable");
            snippet = TemplateUtils.ReplaceTemplateVariable(snippet, "Modifiers", null);
            snippet = TemplateUtils.ToDeclarationString(m, snippet);
            snippet += NewLine + "$(Boundary)";
            SnippetHelper.InsertSnippetText(Sci, Sci.CurrentPos, snippet);
        }
Exemple #4
0
        /// <summary>
        /// Find Actionscript expression at cursor position
        /// </summary>
        /// <param name="sci">Scintilla Control</param>
        /// <param name="position">Cursor position</param>
        /// <param name="ignoreWhiteSpace">Skip whitespace at position</param>
        /// <returns></returns>
        private static ASExpr GetExpression(ScintillaNet.ScintillaControl Sci, int position, bool ignoreWhiteSpace)
        {
            ASExpr expression = new ASExpr();
            expression.Position = position;
            expression.Separator = ' ';

            // file's member declared at this position
            expression.ContextMember = ASContext.Context.CurrentMember;
            int minPos = 0;
            string body = null;
            if (expression.ContextMember != null)
            {
                minPos = Sci.PositionFromLine(expression.ContextMember.LineFrom);
                StringBuilder sbBody = new StringBuilder();
                for (int i = expression.ContextMember.LineFrom; i <= expression.ContextMember.LineTo; i++)
                    sbBody.Append(Sci.GetLine(i)).Append('\n');
                body = sbBody.ToString();
                //int tokPos = body.IndexOf(expression.ContextMember.Name);
                //if (tokPos >= 0) minPos += tokPos + expression.ContextMember.Name.Length;

                if ((expression.ContextMember.Flags & (FlagType.Function | FlagType.Constructor | FlagType.Getter | FlagType.Setter)) > 0)
                {
                    expression.ContextFunction = expression.ContextMember;
                    expression.FunctionOffset = expression.ContextMember.LineFrom;

                    Match mStart = Regex.Match(body, "(\\)|[a-z0-9*.,-<>])\\s*{", RegexOptions.IgnoreCase);
                    if (mStart.Success)
                    {
                        // cleanup function body & offset
                        int pos = mStart.Index + mStart.Length;
                        expression.BeforeBody = (position < Sci.PositionFromLine(expression.ContextMember.LineFrom) + pos);
                        string pre = body.Substring(0, pos);
                        for (int i = 0; i < pre.Length - 1; i++)
                            if (pre[i] == '\r') { expression.FunctionOffset++; if (pre[i + 1] == '\n') i++; }
                            else if (pre[i] == '\n') expression.FunctionOffset++;
                        body = body.Substring(pos);
                    }
                    expression.FunctionBody = body;
                }
                else
                {
                    int eqPos = body.IndexOf('=');
                    expression.BeforeBody = (eqPos < 0 || position < Sci.PositionFromLine(expression.ContextMember.LineFrom) + eqPos);
                }
            }

            // get the word characters from the syntax definition
            string characterClass = ScintillaNet.ScintillaControl.Configuration.GetLanguage(Sci.ConfigurationLanguage).characterclass.Characters;

            // get expression before cursor
            ContextFeatures features = ASContext.Context.Features;
            int stylemask = (1 << Sci.StyleBits) - 1;
            int style = (position >= minPos) ? Sci.StyleAt(position) & stylemask : 0;
            StringBuilder sb = new StringBuilder();
            StringBuilder sbSub = new StringBuilder();
            int subCount = 0;
            char c = ' ';
            char c2;
            int startPos = position;
            int braceCount = 0;
            int sqCount = 0;
            int genCount = 0;
            bool hasGenerics = features.hasGenerics;
            bool hadWS = false;
            bool hadDot = ignoreWhiteSpace;
            bool inRegex = false;
            char dot = features.dot[features.dot.Length - 1];
            while (position > minPos)
            {
                position--;
                style = Sci.StyleAt(position) & stylemask;
                if (style == 14) // regex literal
                {
                    inRegex = true;
                }
                else if (!ASComplete.IsCommentStyle(style))
                {
                    c2 = c;
                    c = (char)Sci.CharAt(position);
                    // end of regex literal
                    if (inRegex)
                    {
                        inRegex = false;
                        if (expression.SubExpressions == null) expression.SubExpressions = new List<string>();
                        expression.SubExpressions.Add("");
                        sb.Insert(0, "RegExp.#" + (subCount++) + "~");
                    }
                    // array access
                    if (c == '[')
                    {
                        sqCount--;
                        if (sqCount == 0)
                        {
                            if (sbSub.Length > 0) sbSub.Insert(0, '[');
                            if (braceCount == 0) sb.Insert(0, ".[]");
                            continue;
                        }
                        if (sqCount < 0)
                        {
                            expression.Separator = ';';
                            break;
                        }
                    }
                    else if (c == ']')
                    {
                        sqCount++;
                    }
                    //
                    else if (c == '<' && hasGenerics)
                    {
                        genCount--;
                        if (genCount < 0)
                        {
                            expression.Separator = ';';
                            break;
                        }
                    }
                    // ignore sub-expressions (method calls' parameters)
                    else if (c == '(')
                    {
                        braceCount--;
                        if (braceCount == 0)
                        {
                            sbSub.Insert(0, c);
                            expression.SubExpressions.Add(sbSub.ToString());
                            sb.Insert(0, ".#" + (subCount++) + "~"); // method call or sub expression

                            int testPos = position - 1;
                            string testWord = ASComplete.GetWordLeft(Sci, ref testPos);
                            if (testWord == "return" || testWord == "case" || testWord == "defaut")
                            {
                                // ex: return (a as B).<complete>
                                expression.Separator = ';';
                                expression.WordBefore = testWord;
                                break;
                            }
                            else continue;
                        }
                        else if (braceCount < 0)
                        {
                            expression.Separator = ';';
                            int testPos = position - 1;
                            string testWord = ASComplete.GetWordLeft(Sci, ref testPos); // anonymous function
                            string testWord2 = ASComplete.GetWordLeft(Sci, ref testPos) ?? "null"; // regular function
                            if (testWord == features.functionKey || testWord == "catch"
                                || testWord2 == features.functionKey
                                || testWord2 == features.getKey || testWord2 == features.setKey)
                            {
                                expression.Separator = ',';
                                expression.coma = ComaExpression.FunctionDeclaration;
                            }
                            break;
                        }
                    }
                    else if (c == ')')
                    {
                        if (!hadDot)
                        {
                            expression.Separator = ';';
                            break;
                        }
                        if (braceCount == 0) // start sub-expression
                        {
                            if (expression.SubExpressions == null) expression.SubExpressions = new List<string>();
                            sbSub = new StringBuilder();
                        }
                        braceCount++;
                    }
                    else if (c == '>' && hasGenerics)
                    {
                        if (c2 == '.' || c2 == '(')
                            genCount++;
                        else break;
                    }
                    if (braceCount > 0 || sqCount > 0 || genCount > 0)
                    {
                        if (c == ';') // not expected: something's wrong
                        {
                            expression.Separator = ';';
                            break;
                        }
                        // build sub expression
                        sbSub.Insert(0, c);
                        continue;
                    }
                    // build expression
                    if (c <= 32)
                    {
                        if (genCount == 0) hadWS = true;
                    }
                    else if (c == dot)
                    {
                        if (features.dot.Length == 2)
                            hadDot = position > 0 && Sci.CharAt(position - 1) == features.dot[0];
                        else hadDot = true;
                        sb.Insert(0, c);
                    }
                    else if (characterClass.IndexOf(c) >= 0)
                    {
                        if (hadWS && !hadDot)
                        {
                            expression.Separator = ' ';
                            break;
                        }
                        hadWS = false;
                        hadDot = false;
                        sb.Insert(0, c);
                        startPos = position;
                    }
                    else if (c == ';')
                    {
                        expression.Separator = ';';
                        break;
                    }
                    else if (hasGenerics && (genCount > 0 || c == '<'))
                    {
                        sb.Insert(0, c);
                    }
                    else if (c == '{')
                    {
                        expression.coma = DisambiguateComa(Sci, position, minPos);
                        expression.Separator = (expression.coma == ComaExpression.None) ? ';' : ',';
                        break;
                    }
                    else if (c == ',')
                    {
                        expression.coma = DisambiguateComa(Sci, position, minPos);
                        expression.Separator = (expression.coma == ComaExpression.None) ? ';' : ',';
                        break;
                    }
                    else if (c == ':')
                    {
                        expression.Separator = ':';
                        break;
                    }
                    else if (c == '=')
                    {
                        expression.Separator = '=';
                        break;
                    }
                    else //if (hadWS && !hadDot)
                    {
                        if (c == '\'' || c == '"') expression.Separator = '"';
                        else expression.Separator = ';';
                        break;
                    }
                }
                // string literals only allowed in sub-expressions
                else
                {
                    if (braceCount == 0) // not expected: something's wrong
                    {
                        expression.Separator = ';';
                        break;
                    }
                }
            }

            // check if there is a particular keyword
            if (expression.Separator == ' ')
            {
                expression.WordBefore = ASComplete.GetWordLeft(Sci, ref position);
            }

            // result
            expression.Value = sb.ToString();
            expression.PositionExpression = startPos;

            return expression;
        }
Exemple #5
0
        private static StatementReturnType GetStatementReturnType(ScintillaNet.ScintillaControl Sci, ClassModel inClass, string line, int startPos)
        {
            Regex target = new Regex(@"[;\s\n\r]*", RegexOptions.RightToLeft);
            Match m = target.Match(line);
            if (!m.Success)
            {
                return null;
            }
            line = line.Substring(0, m.Index);

            if (line.Length == 0)
            {
                return null;
            }

            line = ReplaceAllStringContents(line);

            ASResult resolve = null;
            int pos = -1; 
            string word = null;
            int stylemask = (1 << Sci.StyleBits) - 1;
            ClassModel type = null;

            if (line[line.Length - 1] == ')')
            {
                pos = -1;
                int lastIndex = 0;
                int bracesBalance = 0;
                while (true)
                {
                    int pos1 = line.IndexOf("(", lastIndex);
                    int pos2 = line.IndexOf(")", lastIndex);
                    if (pos1 != -1 && pos2 != -1)
                    {
                        lastIndex = Math.Min(pos1, pos2);
                    }
                    else if (pos1 != -1 || pos2 != -1)
                    {
                        lastIndex = Math.Max(pos1, pos2);
                    }
                    else
                    {
                        break;
                    }
                    if (lastIndex == pos1)
                    {
                        bracesBalance++;
                        if (bracesBalance == 1)
                        {
                            pos = lastIndex;
                        }
                    }
                    else if (lastIndex == pos2)
                    {
                        bracesBalance--;
                    }
                    lastIndex++;
                }
            }
            else
            {
                pos = line.Length;
            }
            if (pos != -1)
            {
                line = line.Substring(0, pos);
                pos += startPos;
                pos -= line.Length - line.TrimEnd().Length + 1;
                pos = Sci.WordEndPosition(pos, true);
                resolve = ASComplete.GetExpressionType(Sci, pos);
                word = Sci.GetWordFromPosition(pos);
            }
            char c = (char)Sci.CharAt(pos);
            if (word != null && Char.IsDigit(word[0]))
            {
                type = inClass.InFile.Context.ResolveType("Number", inClass.InFile);
            }
            else if (word != null && (word == "true" || word == "false"))
            {
                type = inClass.InFile.Context.ResolveType("Boolean", inClass.InFile);
            }
            else if (!(ASComplete.IsTextStyle(Sci.StyleAt(pos - 1) & stylemask)))
            {
                type = inClass.InFile.Context.ResolveType("String", inClass.InFile);
            }
            else if (c == '}')
            {
                type = inClass.InFile.Context.ResolveType("Object", inClass.InFile);
            }
            else if (c == '>')
            {
                type = inClass.InFile.Context.ResolveType("XML", inClass.InFile);
            }
            else if (c == ']')
            {
                type = inClass.InFile.Context.ResolveType("Array", inClass.InFile);
            }

            if (resolve == null)
            {
                resolve = new ASResult();
            }
            if (resolve.Type == null)
            {
                resolve.Type = type;
            }

            return new StatementReturnType(resolve, pos, word);
        }
Exemple #6
0
		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;
		}
Exemple #7
0
		/// <summary>
		/// Character written in editor
		/// </summary>
		/// <param name="Value">Character inserted</param>
		static public bool OnChar(ScintillaNet.ScintillaControl Sci, int Value, bool autoHide)
		{
			if (autoHide && !ASContext.HelpersEnabled)
				return false;
			try
			{
				int eolMode = Sci.EOLMode;
				// code auto
				if (((Value == 10) && (eolMode != 1)) || ((Value == 13) && (eolMode == 1)))
				{
					DebugConsole.Trace("Struct");
					HandleStructureCompletion(Sci);
					return false;
				}
				
				// ignore repeated characters
				int position = Sci.CurrentPos;
				if ((Sci.CharAt(position-2) == Value) && (Sci.CharAt(position-1) == Value) && (Value != '*'))
					return false;
				
				// ignore text in comments & quoted text
				Sci.Colourise(0,-1);
				int stylemask = (1 << Sci.StyleBits) -1;
				int style = Sci.StyleAt(position-1) & stylemask;
				DebugConsole.Trace("style "+style);
				if (!IsTextStyle(style) && !IsTextStyle(Sci.StyleAt(position) & stylemask))
				{
					// documentation completion
					if (ASContext.DocumentationCompletionEnabled && IsCommentStyle(style))
						return ASDocumentation.OnChar(Sci, Value, position, style);
					else if (autoHide) return false;
				}
				
				// stop here if the class is not valid
				if (!ASContext.IsClassValid()) return false;
				
				// handle
				switch (Value)
				{
					case '.':
						return HandleDotCompletion(Sci, autoHide);
						
					case ' ':
						position--;
						string word = GetWordLeft(Sci, ref position);
						DebugConsole.Trace("Word? "+word);
						if (word.Length > 0)
						switch (word) 
						{
							case "new":
							case "extends":
							case "implements":
								return HandleNewCompletion(Sci, "", autoHide);
							case "import":
								return HandleImportCompletion(Sci, "", autoHide);
							case "public":
								return HandleDeclarationCompletion(Sci, "function static var", "", autoHide);
							case "private":
								return HandleDeclarationCompletion(Sci, "function static var", "", autoHide);
							case "static":
								return HandleDeclarationCompletion(Sci, "function private public var", "", autoHide);
						}
						break;
						
					case ':':
						ASContext.UnsetOutOfDate();
						bool result = HandleColonCompletion(Sci, "", autoHide);
						ASContext.SetOutOfDate();
						return result;
						
					case '(':
						return HandleFunctionCompletion(Sci);
					case ')':
						if (InfoTip.CallTipActive) InfoTip.Hide();
						return false;
					
					case '*':
						return CodeAutoOnChar(Sci, Value);
				}
			}
			catch (Exception ex) {
				ErrorHandler.ShowError("Completion error", ex);
			}
			
			// CodeAuto context
			if (!PluginCore.Controls.CompletionList.Active) LastExpression = null;
			return false;
		}
Exemple #8
0
		/// <summary>
		/// Display method signature
		/// </summary>
		/// <param name="Sci">Scintilla control</param>
		/// <returns>Auto-completion has been handled</returns>
		static public bool HandleFunctionCompletion(ScintillaNet.ScintillaControl Sci)
		{
			// find method
			int position = Sci.CurrentPos-1;
			int parCount = 0;
			int braCount = 0;
			int comaCount = 0;
			int arrCount = 0;
			int style = 0;
			int stylemask = (1 << Sci.StyleBits) -1;
			char c;
			while (position >= 0)
			{
				style = Sci.StyleAt(position) & stylemask;
				if (style == 19)
				{
					string keyword = GetWordLeft(Sci, ref position);
					DebugConsole.Trace("Keyword "+keyword);
					if (!"new".StartsWith(keyword))
					{
						position = -1;
						break;
					}
				}
				if (IsTextStyleEx(style))
				{
					c = (char)Sci.CharAt(position);
					if (c == ';') 
					{
						position = -1;
						break;
					}
					// skip {} () [] blocks
					if ( ((braCount > 0) && (c != '{')) 
					    || ((arrCount > 0) && (c != '[')) 
					    || ((parCount > 0) && (c != '(')))
					{
						position--;
						continue;
					}
					// new block
					if (c == '}') braCount++;
					else if (c == ']') arrCount++;
					else if (c == ')') parCount++;
					
					// block closed
					else if (c == '{') 
					{
						if (braCount == 0) comaCount = 0;
						else braCount--;
					}
					else if (c == '[') 
					{
						if (arrCount == 0) comaCount = 0;
						else arrCount--;
					}
					else if (c == '(') 
					{
						if (--parCount < 0)
							// function start found
							break;
					}
					
					// new parameter reached
					else if (c == ',' && parCount == 0 && Sci.BaseStyleAt(position) != 6)
						comaCount++;
				}
				position--;
			}
			// continuing calltip ?
			if (HasCalltip())
			{
				if (calltipPos == position)
				{
					ShowCalltip(Sci, comaCount);
					return true;
				}
				else InfoTip.Hide();
			}
			else if (position < 0) 
				return false;
			
			// get expression at cursor position
			ASExpr expr = GetExpression(Sci, position);
			DebugConsole.Trace("Expr: "+expr.Value);
			if (expr.Value == null || expr.Value.Length == 0 || expr.separator == ':'
			    || (expr.Keyword == "function" && expr.separator == ' '))
				return false;
			DebugConsole.Trace("** Display method parameters");
			DebugConsole.Trace(expr.Value);
			// Context
			expr.LocalVars = ParseLocalVars(expr);
			ASClass aClass = ASContext.CurrentClass; 
			// Expression before cursor
			ASResult result = EvalExpression(expr.Value, expr, aClass, true);
			
			// Show calltip
			if (!result.IsNull())
			{
				ASMember method = result.Member;
				if (method == null)
				{
					string constructor = ASContext.GetLastStringToken(result.Class.ClassName,".");
					method = result.Class.Methods.Search(constructor, FlagType.Constructor);
					if (method == null)
						return true;
				}
				else if ((method.Flags & FlagType.Function) == 0)
					return true;
				// calltip content
				calltipPos = position;
				calltipOffset = method.Name.Length;
				calltipDef = method.Name+"("+method.Parameters+")";
				if (method.Type.Length > 0) 
					calltipDef += " : "+method.Type;
				calltipMember = method;
				calltipDetails = UITools.ShowDetails;
				
				// show
				prevParam = "";
				ShowCalltip(Sci, comaCount);
			}
			return true;
		}
Exemple #9
0
		static public string GetWordLeft(ScintillaNet.ScintillaControl Sci, ref int position)
		{
			string word = "";
			string exclude = "(){};,+*/\\=:.%\"<>";
			bool skipWS = true;
			int style;
			int stylemask = (1 << Sci.StyleBits) -1;
			char c;
			while (position >= 0) 
			{
				style = Sci.StyleAt(position) & stylemask;
				if (IsTextStyleEx(style))
				{
					c = (char)Sci.CharAt(position);
					if (c <= ' ') 
					{
						if (!skipWS)
							break;
					}
					else if (exclude.IndexOf(c) >= 0) break;
					else if (style != 6)
					{
						word = c+word;
						skipWS = false;
					}
				}
				position--;
			}
			return word;
		}
Exemple #10
0
		/// <summary>
		/// Find Actionscript expression at cursor position
		/// TODO  Improve this method
		/// </summary>
		/// <param name="sci">Scintilla Control</param>
		/// <param name="position">Cursor position</param>
		/// <returns></returns>
		static private ASExpr GetExpression(ScintillaNet.ScintillaControl Sci, int position)
		{
			ASExpr expression = new ASExpr();
			int startPos = position;
			expression.Position = position;
			expression.separator = ' ';
			
			// get last expression (until ';') excluding comments
			int stylemask = (1 << Sci.StyleBits) -1;
			int style = (position > 0) ? Sci.StyleAt(position-1) & stylemask : 0;
			bool ignoreKey = false;
			if (style == 19)
			{
				DebugConsole.Trace("Ignore keyword");
				ignoreKey = true;
			}
			StringBuilder sb = new StringBuilder();
			char c;
			while ((position > 0) && (style != 19 || ignoreKey)) 
			{
				position--;
				style = Sci.StyleAt(position) & stylemask;
				if (IsTextStyle(style) || ignoreKey)
				{
					c = (char)Sci.CharAt(position);
					if (c == ';')
					{
						expression.separator = c;
						break;
					}
					else if (c == '\n' || c == '\r')
					{
						if (sb.ToString().Trim().Length == 0) 
							break;
					}
					sb.Insert(0,c);
					if (ignoreKey && IsTextStyle(style)) ignoreKey = false;
				}
				// we found a keyword
				else if (style == 19)
				{
					expression.separator = ' ';
					int keywordPos = position;
					string keyword = GetWordLeft(Sci, ref keywordPos);
					
					if ((keyword == "function") || (keyword == "get") || (keyword == "set"))
					{
						// we found a function declaration
						string test = sb.ToString().Trim();
						
						// ignore anonymous function
						if ((keyword == "function") && test.StartsWith("("))
						{
							keyword = null;
							break;
						}
						
						// guess context more precisely
						bool hasBraces = (test.IndexOf('{') >= 0);
						test = re_balancedBraces.Replace(test, ";");
						
						// is it inside the function?
						if (test.IndexOf('{') >= 0)
						{
							c = ' ';
							while ((position < startPos) && (sb.Length > 0))
							{
								position++;
								c = (char)Sci.CharAt(position);
								sb.Remove(0,1);
								if (c == '{') break;
							}
							expression.separator = c;
						}
						// is it NOT inside function parameters?
						else if (test.IndexOf(')') >= 0)
						{
							if (hasBraces)
							{
								expression.separator = '}';
								expression.Value = "";
								return expression;
							}
							else
							{
								// is it before the return type declaration?
								int colon = test.LastIndexOf(':');
								if ((colon < 0) || (colon < test.LastIndexOf(')')))
									// this is invalid
									return expression;
							}
						}
						// inside function parameters?
						else
						{
							int colon = test.LastIndexOf(':');
							if ((colon < 0) || (colon < test.LastIndexOf(',')))
								return expression;
						}
					}
					else expression.Keyword = keyword;
					
					// note that we found a "case" statement
					//else if (keyword == "case") expression.Keyword = "case";
					
					DebugConsole.Trace("Stopped at '"+keyword+"'");
					DebugConsole.Trace("Raw '"+sb.ToString()+"'");
					break;
				}
			}
			position++;
			string expr = sb.ToString();
			
			sb = null;
			if (expr.Length > 0 && (expr[expr.Length-1] <= 32 && Sci.CharAt(startPos) != '('))
			{
				expr = "";
				expression.separator = ' ';
				expression.Position = Sci.CurrentPos;
			}
			else expression.PositionExpression = position;
			
			// refine last expression
			if (expr.Length > 0) 
			{
				expr = re_balancedBraces.Replace(expr, ";");
				expression.SubExpressions = ExtractedSubex = new StringCollection();
				expr = re_balancedParenthesis.Replace(expr, new MatchEvaluator(ExtractSubex));
				//DebugConsole.Trace("Raw '"+expr+"' @"+expression.PositionExpression);
				Match m = re_refineExpression.Match(expr);
				if (!m.Success) return expression;
				if (m.Index > 0)
				{
					expression.separator = expr[m.Index-1];
					expression.PositionExpression = position += m.Index;
					// treat ':' as ';' after a case statement
					if (expression.separator == ':' && expression.Keyword == "case") expression.separator = ';';
					expression.Keyword = null;
				}
				//DebugConsole.Trace("Refined '"+m.Value+"' @"+m.Index);
				expr = re_dot.Replace( re_whiteSpace.Replace(m.Value, " ") , ".");
				expr = re_subexMarker.Replace(expr, "#").Trim();
				int space = Math.Max(expr.LastIndexOf(' '), expr.LastIndexOf(';'));
				if (space > 0) 
				{
					expression.separator = ' ';
					expr = expr.Substring(space+1);
				}
				//ErrorHandler.ShowInfo("Clean '"+expr+"' @"+expression.PositionExpression);
			}
			expression.Value = expr;
			
			// get context function body
			int braceCount = 0;
			StringBuilder body = new StringBuilder();
			StringBuilder context = new StringBuilder();
			while (braceCount >= 0)
			{
				while (position > 0) 
				{
					position--;
					style = Sci.StyleAt(position) & stylemask;
					if (IsTextStyleEx(style))
					{
						c = (char)Sci.CharAt(position);
						if (c == '}') 
						{
							body.Insert(0,c);
							braceCount++;
						}
						else if ((c == '{') && (--braceCount < 0)) break;
						if (braceCount == 0) body.Insert(0,c);
					}
				}
				if (braceCount >= 0) break;
				
				// get context function definition
				while (position > 0) 
				{
					position--;
					style = Sci.StyleAt(position) & stylemask;
					if (IsTextStyleEx(style))
					{
						c = (char)Sci.CharAt(position);
						if ((c == ';') || (c == '}') || (c == '{')) break;
						context.Insert(0,c);
					}
				}
				expression.ContextFunction = context.ToString();
				
				// ignore dynamic function definition
				if (!re_validFunction.IsMatch(expression.ContextFunction)) 
				{
					// stop if we reached the class definition
					if (re_classDefinition.IsMatch(expression.ContextFunction)) 
					{
						expression.ContextFunction = null;
						expression.PositionContext = 0;
						break;
					}
					// continue search for function definition
					body.Insert(0,'{').Insert(0,context.ToString());
					context = new StringBuilder();
					position++;
					braceCount++;
				}
				else {
					expression.ContextBody = body.ToString();
					expression.PositionContext = position+1;
				}
			}
			// result
			LastExpression = expression;
			return expression;
		}