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? }
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? }
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); if (resolve.IsNull()) resolve = null; word = Sci.GetWordFromPosition(pos); } IASContext ctx = inClass.InFile.Context; m = Regex.Match(line, "new\\s+([\\w\\d.<>,_$-]+)+(<[^]]+>)|(<[^]]+>)", RegexOptions.IgnoreCase); if (m.Success) { string m1 = m.Groups[1].Value; string m2 = m.Groups[2].Value; string cname; if (string.IsNullOrEmpty(m1) && string.IsNullOrEmpty(m2)) cname = m.Groups[0].Value; else cname = String.Concat(m1, m2); if (cname.StartsWith("<")) cname = "Vector." + cname; // literal vector type = ctx.ResolveType(cname, inClass.InFile); if (!type.IsVoid()) resolve = null; } else { char c = (char)Sci.CharAt(pos); if (c == '"' || c == '\'') { type = ctx.ResolveType("String", inClass.InFile); } else if (c == '}') { type = ctx.ResolveType(ctx.Features.objectKey, inClass.InFile); } else if (c == '>') { type = ctx.ResolveType("XML", inClass.InFile); } else if (c == ']') { resolve = ASComplete.GetExpressionType(Sci, pos + 1); if (resolve.Type != null) type = resolve.Type; else type = ctx.ResolveType(ctx.Features.arrayKey, inClass.InFile); resolve = null; } else if (word != null && Char.IsDigit(word[0])) { type = ctx.ResolveType(ctx.Features.numberKey, inClass.InFile); } else if (word == "true" || word == "false") { type = ctx.ResolveType(ctx.Features.booleanKey, inClass.InFile); } if (type != null && type.IsVoid()) type = null; } if (resolve == null) resolve = new ASResult(); if (resolve.Type == null) resolve.Type = type; return new StatementReturnType(resolve, pos, word); }
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); }