ExpressionResult FindExpression(ProjectDom dom, CodeCompletionContext ctx) { NewFSharpExpressionFinder expressionFinder = new NewFSharpExpressionFinder (dom); try { return expressionFinder.FindExpression (Editor.Text, ctx.TriggerOffset); } catch (Exception ex) { LoggingService.LogWarning (ex.Message, ex); return null; } }
public ICompletionDataList HandleKeywordCompletion(CodeCompletionContext completionContext, ExpressionResult result, int wordStart, string word) { if (stateTracker.Engine.IsInsideDocLineComment || stateTracker.Engine.IsInsideOrdinaryCommentOrString) return null; DomLocation location = new DomLocation (completionContext.TriggerLine, completionContext.TriggerLineOffset); switch (word) { case "using": if (result.ExpressionContext != ExpressionContext.NamespaceNameExcepted) return null; return CreateCompletionData (location, new NamespaceResolveResult (""), result, null); case "namespace": result.ExpressionContext = ExpressionContext.NamespaceNameExcepted; return CreateCompletionData (location, new NamespaceResolveResult (""), result, null); case "case": return CreateCaseCompletionData (location, result); case ",": case ":": if (result.ExpressionContext == ExpressionContext.InheritableType) { IType cls = NRefactoryResolver.GetTypeAtCursor (Document.CompilationUnit, Document.FileName, new DomLocation (completionContext.TriggerLine, completionContext.TriggerLineOffset)); CompletionDataList completionList = new ProjectDomCompletionDataList (); List<string> namespaceList = GetUsedNamespaces (); FSharpTextEditorCompletion.CompletionDataCollector col = new FSharpTextEditorCompletion.CompletionDataCollector (completionList, Document.CompilationUnit, location); bool isInterface = false; HashSet<string> baseTypeNames = new HashSet<string> (); if (cls != null) { baseTypeNames.Add (cls.Name); if (cls.ClassType == ClassType.Struct) isInterface = true; } int tokenIndex = completionContext.TriggerOffset; // Search base types " : [Type1, ... ,TypeN,] <Caret>" string token = null; do { token = GetPreviousToken (ref tokenIndex, false); if (string.IsNullOrEmpty (token)) break; token = token.Trim (); if (Char.IsLetterOrDigit (token[0]) || token[0] == '_') { IType baseType = dom.SearchType (new SearchTypeRequest (Document.CompilationUnit, token)); if (baseType != null) { if (baseType.ClassType != ClassType.Interface) isInterface = true; baseTypeNames.Add (baseType.Name); } } } while (token != ":"); foreach (object o in dom.GetNamespaceContents (namespaceList, true, true)) { IType type = o as IType; if (type != null && (type.IsStatic || type.IsSealed || baseTypeNames.Contains (type.Name) || isInterface && type.ClassType != ClassType.Interface)) { continue; } col.Add (o); } // Add inner classes Stack<IType> innerStack = new Stack<IType> (); innerStack.Push (cls); while (innerStack.Count > 0) { IType curType = innerStack.Pop (); foreach (IType innerType in curType.InnerTypes) { if (innerType != cls) // don't add the calling class as possible base type col.Add (innerType); } if (curType.DeclaringType != null) innerStack.Push (curType.DeclaringType); } return completionList; } break; case "is": case "as": { CompletionDataList completionList = new ProjectDomCompletionDataList (); ExpressionResult expressionResult = FindExpression (dom, completionContext, wordStart - Editor.CursorPosition); NRefactoryResolver resolver = new NRefactoryResolver (dom, Document.CompilationUnit, ICSharpCode.NRefactory.SupportedLanguage.CSharp, Editor, Document.FileName); ResolveResult resolveResult = resolver.Resolve (expressionResult, new DomLocation (completionContext.TriggerLine, completionContext.TriggerLineOffset)); if (resolveResult != null && resolveResult.ResolvedType != null) { CompletionDataCollector col = new CompletionDataCollector (completionList, Document.CompilationUnit, location); IType foundType = null; if (word == "as") { ExpressionContext exactContext = new NewFSharpExpressionFinder (dom).FindExactContextForAsCompletion (Editor, Document.CompilationUnit, Document.FileName, resolver.CallingType); if (exactContext is ExpressionContext.TypeExpressionContext) { foundType = dom.SearchType (new SearchTypeRequest (resolver.Unit, ((ExpressionContext.TypeExpressionContext)exactContext).Type, resolver.CallingType)); AddAsCompletionData (col, foundType); } } if (foundType == null) foundType = dom.SearchType (new SearchTypeRequest (resolver.Unit, resolveResult.ResolvedType, resolver.CallingType)); if (foundType != null) { foreach (IType type in dom.GetSubclasses (foundType)) { if (type.IsSpecialName || type.Name.StartsWith ("<")) continue; AddAsCompletionData (col, type); } } List<string> namespaceList = GetUsedNamespaces (); foreach (object o in dom.GetNamespaceContents (namespaceList, true, true)) { if (o is IType) { IType type = (IType)o; if (type.ClassType != ClassType.Interface || type.IsSpecialName || type.Name.StartsWith ("<")) continue; if (foundType != null && !dom.GetInheritanceTree (foundType).Any (x => x.FullName == type.FullName)) continue; AddAsCompletionData (col, type); continue; } if (o is Namespace) continue; col.Add (o); } return completionList; } result.ExpressionContext = ExpressionContext.TypeName; return CreateCtrlSpaceCompletionData (completionContext, result); } case "override": // Look for modifiers, in order to find the beginning of the declaration int firstMod = wordStart; int i = wordStart; for (int n = 0; n < 3; n++) { string mod = GetPreviousToken (ref i, true); if (mod == "public" || mod == "protected" || mod == "private" || mod == "internal" || mod == "sealed") { firstMod = i; } else if (mod == "static") { // static methods are not overridable return null; } else break; } IType overrideCls = NRefactoryResolver.GetTypeAtCursor (Document.CompilationUnit, Document.FileName, new DomLocation (completionContext.TriggerLine, completionContext.TriggerLineOffset)); if (overrideCls != null && (overrideCls.ClassType == ClassType.Class || overrideCls.ClassType == ClassType.Struct)) { string modifiers = Editor.GetText (firstMod, wordStart); return GetOverrideCompletionData (completionContext, overrideCls, modifiers); } return null; case "partial": // Look for modifiers, in order to find the beginning of the declaration firstMod = wordStart; i = wordStart; for (int n = 0; n < 3; n++) { string mod = GetPreviousToken (ref i, true); if (mod == "public" || mod == "protected" || mod == "private" || mod == "internal" || mod == "sealed") { firstMod = i; } else if (mod == "static") { // static methods are not overridable return null; } else break; } overrideCls = NRefactoryResolver.GetTypeAtCursor (Document.CompilationUnit, Document.FileName, new DomLocation (completionContext.TriggerLine, completionContext.TriggerLineOffset)); if (overrideCls != null && (overrideCls.ClassType == ClassType.Class || overrideCls.ClassType == ClassType.Struct)) { string modifiers = Editor.GetText (firstMod, wordStart); return GetPartialCompletionData (completionContext, overrideCls, modifiers); } return null; case "new": IType callingType = NRefactoryResolver.GetTypeAtCursor (Document.CompilationUnit, Document.FileName, new DomLocation (Editor.CursorLine, Editor.CursorColumn)); ExpressionContext newExactContext = new NewFSharpExpressionFinder (dom).FindExactContextForNewCompletion (Editor, Document.CompilationUnit, Document.FileName, callingType); if (newExactContext is ExpressionContext.TypeExpressionContext) return CreateTypeCompletionData (location, callingType, newExactContext, ((ExpressionContext.TypeExpressionContext)newExactContext).Type, ((ExpressionContext.TypeExpressionContext)newExactContext).UnresolvedType); if (newExactContext == null) { int j = completionContext.TriggerOffset - 4; string token = GetPreviousToken (ref j, true); string yieldToken = GetPreviousToken (ref j, true); if (token == "return") { NRefactoryResolver resolver = new NRefactoryResolver (dom, Document.CompilationUnit, ICSharpCode.NRefactory.SupportedLanguage.CSharp, Editor, Document.FileName); resolver.SetupResolver (new DomLocation (completionContext.TriggerLine, completionContext.TriggerLineOffset)); IReturnType returnType = resolver.CallingMember.ReturnType; if (yieldToken == "yield" && returnType.GenericArguments.Count > 0) returnType = returnType.GenericArguments[0]; if (resolver.CallingMember != null) return CreateTypeCompletionData (location, callingType, newExactContext, null, returnType); } } return CreateCtrlSpaceCompletionData (completionContext, null); case "if": case "elif": if (stateTracker.Engine.IsInsidePreprocessorDirective) return GetDefineCompletionData (); return null; case "yield": CompletionDataList yieldDataList = new CompletionDataList (); yieldDataList.DefaultCompletionString = "return"; yieldDataList.Add ("break", "md-keyword"); yieldDataList.Add ("return", "md-keyword"); return yieldDataList; } return null; }
CompletionDataList CreateCtrlSpaceCompletionData(CodeCompletionContext ctx, ExpressionResult expressionResult) { // Console.WriteLine (Environment.StackTrace); // Console.WriteLine ("---------"); NRefactoryResolver resolver = new NRefactoryResolver (dom, Document.CompilationUnit, ICSharpCode.NRefactory.SupportedLanguage.CSharp, Editor, Document.FileName); DomLocation cursorLocation = new DomLocation (ctx.TriggerLine, ctx.TriggerLineOffset); resolver.SetupResolver (cursorLocation); // System.Console.WriteLine ("ctrl+space expression result:" + expressionResult); CompletionDataList result = new ProjectDomCompletionDataList (); CompletionDataCollector col = new CompletionDataCollector (result, Document.CompilationUnit, cursorLocation); if (expressionResult == null) { AddPrimitiveTypes (col); resolver.AddAccessibleCodeCompletionData (ExpressionContext.Global, col); } else if (expressionResult.ExpressionContext == ExpressionContext.TypeDeclaration) { AddPrimitiveTypes (col); AddNRefactoryKeywords (col, ICSharpCode.NRefactory.Parser.CSharp.Tokens.TypeLevel); resolver.AddAccessibleCodeCompletionData (expressionResult.ExpressionContext, col); } else if (expressionResult.ExpressionContext == ExpressionContext.InterfaceDeclaration) { AddPrimitiveTypes (col); AddNRefactoryKeywords (col, ICSharpCode.NRefactory.Parser.CSharp.Tokens.InterfaceLevel); resolver.AddAccessibleCodeCompletionData (expressionResult.ExpressionContext, col); } else if (expressionResult.ExpressionContext == ExpressionContext.MethodBody) { col.Add ("global", "md-keyword"); col.Add ("var", "md-keyword"); AddNRefactoryKeywords (col, ICSharpCode.NRefactory.Parser.CSharp.Tokens.StatementStart); AddPrimitiveTypes (col); resolver.AddAccessibleCodeCompletionData (expressionResult.ExpressionContext, col); } else if (expressionResult.ExpressionContext == ExpressionContext.InterfacePropertyDeclaration) { col.Add ("get", "md-keyword"); col.Add ("set", "md-keyword"); } else if (expressionResult.ExpressionContext == ExpressionContext.Attribute) { col.Add ("assembly", "md-keyword"); col.Add ("module", "md-keyword"); col.Add ("type", "md-keyword"); col.Add ("method", "md-keyword"); col.Add ("field", "md-keyword"); col.Add ("property", "md-keyword"); col.Add ("event", "md-keyword"); col.Add ("param", "md-keyword"); col.Add ("return", "md-keyword"); resolver.AddAccessibleCodeCompletionData (expressionResult.ExpressionContext, col); } else if (expressionResult.ExpressionContext == ExpressionContext.BaseConstructorCall) { col.Add ("this", "md-keyword"); col.Add ("base", "md-keyword"); } else if (expressionResult.ExpressionContext == ExpressionContext.ParameterType || expressionResult.ExpressionContext == ExpressionContext.FirstParameterType) { col.Add ("ref", "md-keyword"); col.Add ("out", "md-keyword"); col.Add ("params", "md-keyword"); // C# 3.0 extension method if (expressionResult.ExpressionContext == ExpressionContext.FirstParameterType) col.Add ("this", "md-keyword"); AddPrimitiveTypes (col); resolver.AddAccessibleCodeCompletionData (expressionResult.ExpressionContext, col); } else if (expressionResult.ExpressionContext == ExpressionContext.PropertyDeclaration) { AddNRefactoryKeywords (col, ICSharpCode.NRefactory.Parser.CSharp.Tokens.InPropertyDeclaration); } else if (expressionResult.ExpressionContext == ExpressionContext.EventDeclaration) { col.Add ("add", "md-keyword"); col.Add ("remove", "md-keyword"); } //else if (expressionResult.ExpressionContext == ExpressionContext.FullyQualifiedType) {} else if (expressionResult.ExpressionContext == ExpressionContext.Default) { col.Add ("global", "md-keyword"); col.Add ("var", "md-keyword"); AddPrimitiveTypes (col); AddNRefactoryKeywords (col, ICSharpCode.NRefactory.Parser.CSharp.Tokens.ExpressionStart); AddNRefactoryKeywords (col, ICSharpCode.NRefactory.Parser.CSharp.Tokens.ExpressionContent); resolver.AddAccessibleCodeCompletionData (expressionResult.ExpressionContext, col); } else if (expressionResult.ExpressionContext == ExpressionContext.Global) { AddNRefactoryKeywords (col, ICSharpCode.NRefactory.Parser.CSharp.Tokens.GlobalLevel); CodeTemplateService.AddCompletionDataForMime ("text/x-fsharp", result); } else if (expressionResult.ExpressionContext == ExpressionContext.ObjectInitializer) { ExpressionContext exactContext = new NewFSharpExpressionFinder (dom).FindExactContextForObjectInitializer (Editor, resolver.Unit, Document.FileName, resolver.CallingType); if (exactContext is ExpressionContext.TypeExpressionContext) { IReturnType objectInitializer = ((ExpressionContext.TypeExpressionContext)exactContext).UnresolvedType; IType foundType = dom.SearchType (new SearchTypeRequest (Document.CompilationUnit, objectInitializer, resolver.CallingType)); if (foundType == null) foundType = dom.GetType (objectInitializer); if (foundType != null) { bool includeProtected = DomType.IncludeProtected (dom, foundType, resolver.CallingType); foreach (IType type in dom.GetInheritanceTree (foundType)) { foreach (IProperty property in type.Properties) { if (property.IsAccessibleFrom (dom, resolver.CallingType, resolver.CallingMember, includeProtected)) { col.Add (property); } } } } } // result.Add ("global", "md-literal"); // AddPrimitiveTypes (result); // resolver.AddAccessibleCodeCompletionData (expressionResult.ExpressionContext, result); } else if (expressionResult.ExpressionContext == ExpressionContext.AttributeArguments) { col.Add ("global", "md-keyword"); AddPrimitiveTypes (col); string attributeName = NewFSharpExpressionFinder.FindAttributeName (Editor, Document.CompilationUnit, Document.FileName); if (attributeName != null) { IType type = dom.SearchType (new SearchTypeRequest (resolver.Unit, new DomReturnType (attributeName + "Attribute"), resolver.CallingType)); if (type == null) type = dom.SearchType (new SearchTypeRequest (resolver.Unit, new DomReturnType (attributeName), resolver.CallingType)); if (type != null) { foreach (IProperty property in type.Properties) { col.Add (property); } } } } else if (expressionResult.ExpressionContext == ExpressionContext.IdentifierExpected) { if (!string.IsNullOrEmpty (expressionResult.Expression)) expressionResult.Expression = expressionResult.Expression.Trim (); MemberResolveResult resolveResult = resolver.Resolve (expressionResult, cursorLocation) as MemberResolveResult; if (resolveResult != null && resolveResult.ResolvedMember == null && resolveResult.ResolvedType != null) { string name = FSharpAmbience.NetToFSharpTypeName (resolveResult.ResolvedType.FullName); if (name != resolveResult.ResolvedType.FullName) { col.Add (Char.ToLower (name[0]).ToString (), "md-field"); } else { name = resolveResult.ResolvedType.Name; List<string> names = new List<string> (); int lastNameStart = 0; for (int i = 1; i < name.Length; i++) { if (Char.IsUpper (name[i])) { names.Add (name.Substring (lastNameStart, i - lastNameStart)); lastNameStart = i; } } names.Add (name.Substring (lastNameStart, name.Length - lastNameStart)); StringBuilder possibleName = new StringBuilder (); for (int i = 0; i < names.Count; i++) { possibleName.Length = 0; for (int j = i; j < names.Count; j++) { if (string.IsNullOrEmpty (names[j])) continue; if (j == i) names[j] = Char.ToLower (names[j][0]) + names[j].Substring (1); possibleName.Append (names[j]); } if (possibleName.Length > 0) col.Add (possibleName.ToString (), "md-field"); } result.IsSorted = true; } } else { col.Add ("global", "md-keyword"); col.Add ("var", "md-keyword"); AddPrimitiveTypes (col); resolver.AddAccessibleCodeCompletionData (expressionResult.ExpressionContext, col); } } else if (expressionResult.ExpressionContext == ExpressionContext.TypeName) { col.Add ("global", "md-keyword"); AddPrimitiveTypes (col); resolver.AddAccessibleCodeCompletionData (expressionResult.ExpressionContext, col); } else { col.Add ("global", "md-keyword"); col.Add ("var", "md-keyword"); AddPrimitiveTypes (col); resolver.AddAccessibleCodeCompletionData (expressionResult.ExpressionContext, col); } if (resolver.CallingMember is IMethod) { foreach (ITypeParameter tp in ((IMethod)resolver.CallingMember).TypeParameters) { col.Add (tp.Name, "md-keyword"); } } return result; }