public override ICompletionDataList HandleCodeCompletion(CodeCompletionContext completionContext, char completionChar, ref int triggerWordLength) { // IDisposable timer = null; try { if (dom == null /*|| Document.CompilationUnit == null*/) return null; if (completionChar != '#' && stateTracker.Engine.IsInsidePreprocessorDirective) return null; // timer = Counters.ResolveTime.BeginTiming (); DomLocation location = new DomLocation (completionContext.TriggerLine, completionContext.TriggerLineOffset - 1); stateTracker.UpdateEngine (); ExpressionResult result; int cursor, newCursorOffset = 0; switch (completionChar) { case ':': case '.': if (stateTracker.Engine.IsInsideDocLineComment || stateTracker.Engine.IsInsideOrdinaryCommentOrString) return null; result = FindExpression (dom, completionContext); if (result == null || result.Expression == null) return null; int idx = result.Expression.LastIndexOf ('.'); if (idx > 0) result.Expression = result.Expression.Substring (0, idx); NRefactoryResolver resolver = new NRefactoryResolver (dom, Document.CompilationUnit, ICSharpCode.NRefactory.SupportedLanguage.CSharp, Editor, Document.FileName); ResolveResult resolveResult = resolver.Resolve (result, location); if (resolver.ResolvedExpression is ICSharpCode.NRefactory.Ast.PrimitiveExpression) { ICSharpCode.NRefactory.Ast.PrimitiveExpression pex = (ICSharpCode.NRefactory.Ast.PrimitiveExpression)resolver.ResolvedExpression; if (!tryToForceCompletion && !(pex.Value is string || pex.Value is char || pex.Value is bool)) return null; } return CreateCompletionData (location, resolveResult, result, resolver); case '#': if (stateTracker.Engine.IsInsidePreprocessorDirective) return GetDirectiveCompletionData (); return null; case '>': cursor = Editor.SelectionStartPosition; if (stateTracker.Engine.IsInsideDocLineComment) { string lineText = Editor.GetLineText (completionContext.TriggerLine); int startIndex = Math.Min (completionContext.TriggerLineOffset - 1, lineText.Length - 1); while (startIndex >= 0 && lineText[startIndex] != '<') { --startIndex; if (lineText[startIndex] == '/') { // already closed. startIndex = -1; break; } } if (startIndex >= 0) { int endIndex = startIndex; while (endIndex <= completionContext.TriggerLineOffset && endIndex < lineText.Length && !Char.IsWhiteSpace (lineText[endIndex])) { endIndex++; } string tag = endIndex - startIndex - 1 > 0 ? lineText.Substring (startIndex + 1, endIndex - startIndex - 2) : null; if (!String.IsNullOrEmpty (tag) && commentTags.IndexOf (tag) >= 0) { Editor.InsertText (cursor, "</" + tag + ">"); Editor.CursorPosition = cursor; return null; } } } return null; /* Disabled because it gives problems when declaring arrays - for example string [] should not pop up code completion. case '[': if (stateTracker.Engine.IsInsideDocLineComment || stateTracker.Engine.IsInsideOrdinaryCommentOrString) return null; result = FindExpression (dom, completionContext); if (result.ExpressionContext == ExpressionContext.Attribute) return CreateCtrlSpaceCompletionData (completionContext, result); return null;*/ case '<': if (stateTracker.Engine.IsInsideDocLineComment) return GetXmlDocumentationCompletionData (); return null; case '(': if (stateTracker.Engine.IsInsideDocLineComment || stateTracker.Engine.IsInsideOrdinaryCommentOrString) return null; result = FindExpression (dom, completionContext, -1); if (result == null || result.Expression == null) return null; resolver = new NRefactoryResolver (dom, Document.CompilationUnit, ICSharpCode.NRefactory.SupportedLanguage.CSharp, Editor, Document.FileName); resolveResult = resolver.Resolve (result, new DomLocation (completionContext.TriggerLine, completionContext.TriggerLineOffset - 2)); if (resolveResult != null && resolver.ResolvedExpression is ICSharpCode.NRefactory.Ast.TypeOfExpression) { CompletionDataList completionList = new ProjectDomCompletionDataList (); CompletionDataCollector col = new CompletionDataCollector (completionList, Document.CompilationUnit, location); AddPrimitiveTypes (col); foreach (object o in dom.GetNamespaceContents (GetUsedNamespaces (), true, true)) { col.Add (o); } return completionList; } return null; case '/': cursor = Editor.SelectionStartPosition; if (cursor < 2) break; if (stateTracker.Engine.IsInsideDocLineComment) { string lineText = Editor.GetLineText (completionContext.TriggerLine); bool startsDocComment = true; int slashes = 0; for (int i = 0; i < completionContext.TriggerLineOffset && i < lineText.Length; i++) { if (lineText[i] == '/') { slashes++; continue; } if (!Char.IsWhiteSpace (lineText[i])) { startsDocComment = false; break; } } // check if lines above already start a doc comment for (int i = completionContext.TriggerLine - 1; i >= 0; i--) { string text = Editor.GetLineText (i).Trim (); if (text.Length == 0) continue; if (text.StartsWith ("///")) { startsDocComment = false; break; } break; } // check if following lines start a doc comment for (int i = completionContext.TriggerLine + 1; i < Editor.LineCount; i++) { string text = Editor.GetLineText (i); if (text == null) break; text = text.Trim (); if (text.Length == 0) continue; if (text.StartsWith ("///")) { startsDocComment = false; break; } break; } if (!startsDocComment || slashes != 3) break; StringBuilder generatedComment = new StringBuilder (); bool generateStandardComment = true; ParsedDocument currentParsedDocument = Document.UpdateParseDocument (); IType insideClass = NRefactoryResolver.GetTypeAtCursor (currentParsedDocument.CompilationUnit, Document.FileName, location); if (insideClass != null) { string indent = GetLineWhiteSpace (lineText); if (insideClass.ClassType == ClassType.Delegate) { AppendSummary (generatedComment, indent, out newCursorOffset); IMethod m = null; foreach (IMethod method in insideClass.Methods) m = method; AppendMethodComment (generatedComment, indent, m); generateStandardComment = false; } else { if (!IsInsideClassBody (insideClass, completionContext.TriggerLine, completionContext.TriggerLineOffset)) break; string body = GenerateBody (insideClass, completionContext.TriggerLine, indent, out newCursorOffset); if (!String.IsNullOrEmpty (body)) { generatedComment.Append (body); generateStandardComment = false; } } } if (generateStandardComment) { string indent = GetLineWhiteSpace (Editor.GetLineText (completionContext.TriggerLine)); AppendSummary (generatedComment, indent, out newCursorOffset); } Editor.EndAtomicUndo (); Editor.BeginAtomicUndo (); Editor.InsertText (cursor, generatedComment.ToString ()); Editor.CursorPosition = cursor + newCursorOffset; return null; } return null; case ' ': if (stateTracker.Engine.IsInsideDocLineComment || stateTracker.Engine.IsInsideOrdinaryCommentOrString) return null; result = FindExpression (dom, completionContext); if (result == null) return null; int tokenIndex = completionContext.TriggerOffset; string token = GetPreviousToken (ref tokenIndex, false); if (token == "=") { int j = tokenIndex; string prevToken = GetPreviousToken (ref j, false); if (prevToken == "=" || prevToken == "+" || prevToken == "-") { token = prevToken + token; tokenIndex = j; } } switch (token) { case "=": case "==": result = FindExpression (dom, completionContext, tokenIndex - completionContext.TriggerOffset - 1); resolver = new NRefactoryResolver (dom, Document.CompilationUnit, ICSharpCode.NRefactory.SupportedLanguage.CSharp, Editor, Document.FileName); resolveResult = resolver.Resolve (result, location); if (resolveResult != null) { IType resolvedType = dom.GetType (resolveResult.ResolvedType); if (resolvedType != null && resolvedType.ClassType == ClassType.Enum) { CompletionDataList completionList = new ProjectDomCompletionDataList (); CompletionDataCollector cdc = new CompletionDataCollector (completionList, Document.CompilationUnit, location); IReturnType returnType = new DomReturnType (resolvedType); bool added = false; foreach (IUsing u in Document.CompilationUnit.Usings) { foreach (KeyValuePair<string, IReturnType> alias in u.Aliases) { if (alias.Value.ToInvariantString () == returnType.ToInvariantString ()) { cdc.Add (alias.Key, "md-class"); added = true; } } } if (!added) cdc.Add (returnType); foreach (object o in CreateCtrlSpaceCompletionData (completionContext, result)) { MemberCompletionData memberData = o as MemberCompletionData; if (memberData == null || memberData.Member == null) continue; if (memberData.Member is IMember) { returnType = ((IMember)memberData.Member).ReturnType; } else if (memberData.Member is IParameter) { returnType = ((IParameter)memberData.Member).ReturnType; } else { returnType = ((LocalVariable)memberData.Member).ReturnType; } if (returnType != null && returnType.FullName == resolvedType.FullName) completionList.Add (memberData); } completionList.AutoCompleteEmptyMatch = false; return completionList; } } return null; case "+=": case "-=": if (stateTracker.Engine.IsInsideDocLineComment || stateTracker.Engine.IsInsideOrdinaryCommentOrString) return null; result = FindExpression (dom, completionContext, tokenIndex - completionContext.TriggerOffset); resolver = new NRefactoryResolver (dom, Document.CompilationUnit, ICSharpCode.NRefactory.SupportedLanguage.CSharp, Editor, Document.FileName); resolveResult = resolver.Resolve (result, location); if (resolveResult is MemberResolveResult) { MemberResolveResult mrr = resolveResult as MemberResolveResult; IEvent evt = mrr.ResolvedMember as IEvent; if (evt == null) return null; IType delegateType = dom.GetType (evt.ReturnType); if (delegateType == null || delegateType.ClassType != ClassType.Delegate) return null; CompletionDataList completionList = new ProjectDomCompletionDataList (); CompletionDataCollector cdc = new CompletionDataCollector (completionList, Document.CompilationUnit, location); IType declaringType = resolver.CallingType; if (Document.LastErrorFreeParsedDocument != null) { declaringType = Document.LastErrorFreeParsedDocument.CompilationUnit.GetType (declaringType.FullName, declaringType.TypeParameters.Count); } IType typeFromDatabase = dom.GetType (declaringType.FullName, new DomReturnType (declaringType).GenericArguments) ?? declaringType; bool includeProtected = DomType.IncludeProtected (dom, typeFromDatabase, resolver.CallingType); foreach (IType type in dom.GetInheritanceTree (typeFromDatabase)) { foreach (IMethod method in type.Methods) { if (method.IsAccessibleFrom (dom, resolver.CallingType, resolver.CallingMember, includeProtected) && MatchDelegate (delegateType, method)) { ICompletionData data = cdc.Add (method); data.SetText (data.CompletionText + ";"); } } } if (token == "+=") { IMethod delegateMethod = delegateType.Methods.First (); completionList.Add ("delegate", "md-keyword", GettextCatalog.GetString ("Creates anonymous delegate."), "delegate {\n" + stateTracker.Engine.ThisLineIndent + TextEditorProperties.IndentString + "|\n" + stateTracker.Engine.ThisLineIndent +"};"); StringBuilder sb = new StringBuilder ("("); for (int k = 0; k < delegateMethod.Parameters.Count; k++) { if (k > 0) sb.Append (", "); sb.Append (CompletionDataCollector.ambience.GetString (Document.CompilationUnit.ShortenTypeName (delegateMethod.Parameters[k].ReturnType, Document.TextEditor.CursorLine, Document.TextEditor.CursorColumn), OutputFlags.ClassBrowserEntries | OutputFlags.UseFullName)); sb.Append (" "); sb.Append (delegateMethod.Parameters[k].Name); } sb.Append (")"); completionList.Add ("delegate" + sb, "md-keyword", GettextCatalog.GetString ("Creates anonymous delegate."), "delegate" + sb + " {\n" + stateTracker.Engine.ThisLineIndent + TextEditorProperties.IndentString + "|\n" + stateTracker.Engine.ThisLineIndent +"};"); string varName = GetPreviousToken (ref tokenIndex, false); varName = GetPreviousToken (ref tokenIndex, false); if (varName != ".") { varName = null; } else { List<string> names = new List<string> (); while (varName == ".") { varName = GetPreviousToken (ref tokenIndex, false); if (varName == "this") { names.Add ("handle"); } else if (varName != null) { string trimmedName = varName.Trim (); if (trimmedName.Length == 0) break; names.Insert (0, trimmedName); } varName = GetPreviousToken (ref tokenIndex, false); } varName = String.Join ("", names.ToArray ()); } completionList.Add (new EventCreationCompletionData (((Mono.TextEditor.ITextEditorDataProvider)Document.GetContent<Mono.TextEditor.ITextEditorDataProvider> ()).GetTextEditorData (), varName, delegateType, evt, sb.ToString (), resolver.CallingMember, typeFromDatabase)); } return completionList; } return null; } return HandleKeywordCompletion (completionContext, result, tokenIndex, token); default: if ((Char.IsLetter (completionChar) || completionChar == '_') && TextEditorProperties.EnableAutoCodeCompletion && !stateTracker.Engine.IsInsideDocLineComment && !stateTracker.Engine.IsInsideOrdinaryCommentOrString) { char prevCh = completionContext.TriggerOffset > 2 ? Editor.GetCharAt (completionContext.TriggerOffset - 2) : '\0'; char nextCh = completionContext.TriggerOffset < Editor.TextLength ? Editor.GetCharAt (completionContext.TriggerOffset) : ' '; const string allowedChars = ";[(){}+-*/%^?:&|~!<>="; if (!Char.IsWhiteSpace (nextCh) && allowedChars.IndexOf (nextCh) < 0) return null; if (Char.IsWhiteSpace (prevCh) || allowedChars.IndexOf (prevCh) >= 0) { result = FindExpression (dom, completionContext, -1); if (result == null) return null; if (result.ExpressionContext != ExpressionContext.IdentifierExpected) { triggerWordLength = 1; bool autoSelect = true; int cpos; if ((prevCh == ',' || prevCh == '(') && GetParameterCompletionCommandOffset (out cpos)) { CodeCompletionContext ctx = CompletionWidget.CreateCodeCompletionContext (cpos); NRefactoryParameterDataProvider provider = ParameterCompletionCommand (ctx) as NRefactoryParameterDataProvider; if (provider != null) { int i = provider.GetCurrentParameterIndex (ctx) - 1; if (i < provider.Methods[0].Parameters.Count) { IType returnType = dom.GetType (provider.Methods[0].Parameters[i].ReturnType); autoSelect = returnType == null || returnType.ClassType != ClassType.Delegate; } } } CompletionDataList dataList = CreateCtrlSpaceCompletionData (completionContext, result); dataList.AutoSelect = autoSelect; return dataList; } } } break; } } catch (Exception e) { System.Console.WriteLine("cce: " +e); } finally { // if (timer != null) // timer.Dispose (); } return null; }
CompletionDataList GetDefineCompletionData() { if (Document.Project == null) return null; Dictionary<string, string> symbols = new Dictionary<string, string> (); CompletionDataList cp = new ProjectDomCompletionDataList (); foreach (DotNetProjectConfiguration conf in Document.Project.Configurations) { FSharpCompilerParameters cparams = conf.CompilationParameters as FSharpCompilerParameters; if (cparams != null) { string[] syms = cparams.DefineSymbols.Split (';'); foreach (string s in syms) { string ss = s.Trim (); if (ss.Length > 0 && !symbols.ContainsKey (ss)) { symbols [ss] = ss; cp.Add (ss, "md-literal"); } } } } return cp; }
CompletionDataList GetPartialCompletionData(CodeCompletionContext ctx, IType type, string modifiers) { CompletionDataList result = new ProjectDomCompletionDataList (); CompoundType partialType = dom.GetType (type.FullName) as CompoundType; if (partialType != null) { List<IMethod> methods = new List<IMethod> (); // gather all partial methods without implementation foreach (IType part in partialType.Parts) { if (part.Location == type.Location && part.CompilationUnit.FileName == type.CompilationUnit.FileName) continue; foreach (IMethod method in part.Methods) { if (method.IsPartial && method.BodyRegion.End.Line == 0 && !ContainsDeclaration (type, method)) { methods.Add (method); } } } // now filter all methods that are implemented in the compound class foreach (IType part in partialType.Parts) { if (part.Location == type.Location && part.CompilationUnit.FileName == type.CompilationUnit.FileName) continue; for (int i = 0; i < methods.Count; i++) { IMethod curMethod = methods[i]; IMethod method = GetDeclaration (part, curMethod); if (method != null && method.BodyRegion.End.Line != 0) { methods.RemoveAt (i); i--; continue; } } } foreach (IMethod method in methods) { NewOverrideCompletionData data = new NewOverrideCompletionData (dom, Editor, ctx.TriggerOffset, type, method); data.GenerateBody = false; result.Add (data); } } return result; }
CompletionDataList CreateTypeCompletionData(DomLocation location, IType callingType, ExpressionContext context, IReturnType returnType, IReturnType returnTypeUnresolved) { CompletionDataList result = new ProjectDomCompletionDataList (); // "var o = new " needs special treatment. if (returnType == null && returnTypeUnresolved != null && returnTypeUnresolved.FullName == "var") returnType = returnTypeUnresolved = DomReturnType.Object; // ExpressionContext.TypeExpressionContext tce = context as ExpressionContext.TypeExpressionContext; CompletionDataCollector col = new CompletionDataCollector (result, Document.CompilationUnit, location); IType type = null; if (returnType != null) type = dom.GetType (returnType); if (type == null) type = dom.SearchType (new SearchTypeRequest (Document.CompilationUnit, returnTypeUnresolved, null)); if (type == null || !(type.IsAbstract || type.ClassType == ClassType.Interface)) { if (type == null || type.ConstructorCount == 0 || type.Methods.Any (c => c.IsConstructor && c.IsAccessibleFrom (dom, callingType, type, callingType != null && dom.GetInheritanceTree (callingType).Any (x => x.FullName == type.FullName)))) { if (returnTypeUnresolved != null) { col.FullyQualify = true; ICompletionData unresovedCompletionData = col.Add (returnTypeUnresolved); col.FullyQualify = false; result.DefaultCompletionString = StripGenerics (unresovedCompletionData.CompletionText); } else { ICompletionData unresovedCompletionData = col.Add (returnType); result.DefaultCompletionString = StripGenerics (unresovedCompletionData.CompletionText); } } } // if (tce != null && tce.Type != null) { // result.DefaultCompletionString = StripGenerics (col.AddCompletionData (result, tce.Type).CompletionString); // } // else { // } if (type == null) return result; HashSet<string> usedNamespaces = new HashSet<string> (GetUsedNamespaces ()); if (type.FullName == DomReturnType.Object.FullName) AddPrimitiveTypes (col); foreach (IType curType in dom.GetSubclasses (type)) { if (context != null && context.FilterEntry (curType)) continue; if ((curType.TypeModifier & TypeModifier.HasOnlyHiddenConstructors) == TypeModifier.HasOnlyHiddenConstructors) continue; if (usedNamespaces.Contains (curType.Namespace)) { if (curType.ConstructorCount > 0) { if (!(curType.Methods.Any (c => c.IsConstructor && c.IsAccessibleFrom (dom, curType, callingType, callingType != null && dom.GetInheritanceTree (callingType).Any (x => x.FullName == curType.FullName))))) continue; } col.Add (curType); } else { string nsName = curType.Namespace; int idx = nsName.IndexOf ('.'); if (idx >= 0) nsName = nsName.Substring (0, idx); col.Add (new Namespace (nsName)); } } // add aliases if (returnType != null) { foreach (IUsing u in Document.CompilationUnit.Usings) { foreach (KeyValuePair<string, IReturnType> alias in u.Aliases) { if (alias.Value.ToInvariantString () == returnType.ToInvariantString ()) result.Add (alias.Key, "md-class"); } } } return result; }