static public bool OnChar(ScintillaNet.ScintillaControl Sci, int Value, int position, int style) { if (style == 3 || style == 124) { switch (Value) { // documentation tag case '@': return HandleDocTagCompletion(Sci); // documentation bloc case '*': if ((position > 2) && (Sci.CharAt(position-3) == '/') && (Sci.CharAt(position-2) == '*') && ((position == 3) || (Sci.BaseStyleAt(position-4) != 3))) HandleBoxCompletion(Sci, position); break; } } return false; }
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? }
private void OnMouseHover(ScintillaNet.ScintillaControl sci, int position) { if (ASContext.Locked || !ASContext.Context.IsFileValid()) return; // get word at mouse position int style = sci.BaseStyleAt(position); DebugConsole.Trace("Style="+style); if (!ASComplete.IsTextStyle(style)) return; position = sci.WordEndPosition(position, true); ASResult result = ASComplete.GetExpressionType(sci, position); // set tooltip if (!result.IsNull()) { string text = ASComplete.GetToolTipText(result); DebugConsole.Trace("SHOW "+text); if (text == null) return; // show tooltip InfoTip.ShowAtMouseLocation(text); } }
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 void OnUpdateCallTip(ScintillaNet.ScintillaControl sci, int position) { if (ASComplete.HasCalltip()) { int pos = sci.CurrentPos - 1; char c = (char)sci.CharAt(pos); if ((c == ',' || c == '(') && sci.BaseStyleAt(pos) == 0) sci.Colourise(0, -1); ASComplete.HandleFunctionCompletion(sci, false, true); } }
/// <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; }
static private bool HandleStructureCompletion(ScintillaNet.ScintillaControl Sci) { try { int position = Sci.CurrentPos; int line = Sci.LineFromPosition(position); if (line == 0) return false; string txt = Sci.GetLine(line-1); int style = Sci.BaseStyleAt(position); int eolMode = Sci.EOLMode; // box comments if (IsCommentStyle(style) && (Sci.BaseStyleAt(position+1) == style)) { txt = txt.Trim(); if (txt.StartsWith("/*") || txt.StartsWith("*")) { Sci.ReplaceSel("* "); position = Sci.LineIndentPosition(line)+2; Sci.SetSel(position,position); return true; } } // braces else if (txt.TrimEnd().EndsWith("{") && (line > 1)) { // find matching brace int bracePos = Sci.LineEndPosition(line-1)-1; while ((bracePos > 0) && (Sci.CharAt(bracePos) != '{')) bracePos--; if (bracePos == 0 || Sci.BaseStyleAt(bracePos) != 10) return true; int match = Sci.SafeBraceMatch(bracePos); DebugConsole.Trace("match "+bracePos+" "+match); int start = line; int indent = Sci.GetLineIndentation(start-1); if (match > 0) { int endIndent = Sci.GetLineIndentation(Sci.LineFromPosition(match)); if (endIndent+Sci.TabWidth > indent) return false; } // find where to include the closing brace int startIndent = indent; int newIndent = indent+Sci.TabWidth; int count = Sci.LineCount; int lastLine = line; line++; while (line < count-1) { txt = Sci.GetLine(line).TrimEnd(); if (txt.Length != 0) { indent = Sci.GetLineIndentation(line); DebugConsole.Trace("indent "+(line+1)+" "+indent+" : "+txt); if (indent <= startIndent) break; lastLine = line; } else break; line++; } if (line >= count-1) lastLine = start; // insert closing brace DebugConsole.Trace("Insert at "+position); position = Sci.LineEndPosition(lastLine); Sci.InsertText(position, ASContext.MainForm.GetNewLineMarker(eolMode)+"}"); Sci.SetLineIndentation(lastLine+1, startIndent); return false; } } catch (Exception ex) { ErrorHandler.ShowError(ex.Message, ex); } return false; }