private static CompletionResult GetResultFromImportSearch(IImportSearchResult importSearchResult, CompletionContext context, bool prependStar, SourceSpan?applicableSpan = null) { var document = context.Analysis.Document; var mres = document.Interpreter.ModuleResolution; IPythonModule module; switch (importSearchResult) { case ModuleImport moduleImports: module = mres.GetImportedModule(moduleImports.FullName); break; case PossibleModuleImport possibleModuleImport: module = mres.GetImportedModule(possibleModuleImport.PossibleModuleFullName); break; case ImplicitPackageImport _: module = null; break; default: return(CompletionResult.Empty); } var completions = new List <CompletionItem>(); if (prependStar) { completions.Add(CompletionItemSource.Star); } if (module != null) { completions.AddRange(module.GetMemberNames() .Where(n => !string.IsNullOrEmpty(n)) .Select(n => context.ItemSource.CreateCompletionItem(n, module.GetMember(n)))); } if (importSearchResult is IImportChildrenSource children) { foreach (var childName in children.GetChildrenNames()) { if (!children.TryGetChildImport(childName, out var imports)) { continue; } switch (imports) { case ImplicitPackageImport packageImport: completions.Add(CompletionItemSource.CreateCompletionItem(packageImport.Name, CompletionItemKind.Module)); break; case ModuleImport moduleImport when !moduleImport.ModulePath.PathEquals(document.FilePath): completions.Add(CompletionItemSource.CreateCompletionItem(moduleImport.Name, CompletionItemKind.Module)); break; } } } return(new CompletionResult(completions, applicableSpan)); }
public static CompletionResult GetCompletionsInFromImport(FromImportStatement fromImport, CompletionContext context) { // No more completions after '*', ever! if (fromImport.Names != null && fromImport.Names.Any(n => n?.Name == "*" && context.Position > n.EndIndex)) { return(CompletionResult.Empty); } var document = context.Analysis.Document; var mres = document.Interpreter.ModuleResolution; foreach (var(name, asName) in ZipLongest(fromImport.Names, fromImport.AsNames).Reverse()) { if (asName != null && context.Position >= asName.StartIndex) { return(CompletionResult.Empty); } if (name != null) { if (context.Position > name.EndIndex && name.EndIndex > name.StartIndex) { var applicableSpan = context.GetApplicableSpanFromLastToken(fromImport); return(new CompletionResult(Enumerable.Repeat(CompletionItemSource.AsKeyword, 1), applicableSpan)); } if (context.Position >= name.StartIndex) { var applicableSpan = name.GetSpan(context.Ast); var importSearchResult = mres.CurrentPathResolver.FindImports(document.FilePath, fromImport); return(GetResultFromImportSearch(importSearchResult, context, false, applicableSpan)); } } } if (fromImport.ImportIndex > fromImport.StartIndex && context.Position > fromImport.ImportIndex + 6) { var importSearchResult = mres.CurrentPathResolver.FindImports(document.FilePath, fromImport); var result = GetResultFromImportSearch(importSearchResult, context, true); if (result != CompletionResult.Empty) { return(result); } } if (fromImport.ImportIndex > 0 && context.Position >= fromImport.ImportIndex) { var applicableSpan = new SourceSpan( context.IndexToLocation(fromImport.ImportIndex), context.IndexToLocation(Math.Min(fromImport.ImportIndex + 6, fromImport.EndIndex)) ); return(new CompletionResult(Enumerable.Repeat(CompletionItemSource.ImportKeyword, 1), applicableSpan)); } if (context.Position > fromImport.Root.EndIndex && fromImport.Root.EndIndex > fromImport.Root.StartIndex) { SourceSpan?applicableSpan = null; if (context.Position > fromImport.EndIndex) { // Only end up here for "from ... imp", and "imp" is not counted // as part of our span var token = context.TokenSource.Tokens.LastOrDefault(); if (token.Key.End >= context.Position) { applicableSpan = context.TokenSource.GetTokenSpan(token.Key); } } return(new CompletionResult(Enumerable.Repeat(CompletionItemSource.ImportKeyword, 1), applicableSpan)); } if (context.Position > fromImport.Root.StartIndex && fromImport.Root is RelativeModuleName relativeName) { var rootNames = relativeName.Names.Select(n => n.Name); var importSearchResult = mres.CurrentPathResolver.GetImportsFromRelativePath(document.FilePath, relativeName.DotCount, rootNames); return(GetResultFromImportSearch(importSearchResult, context, false)); } if (fromImport.Root.Names.Count > 1 && context.Position > fromImport.Root.Names[0].EndIndex) { var rootNames = fromImport.Root.Names.TakeWhile(n => n.EndIndex < context.Position).Select(n => n.Name); var importSearchResult = mres.CurrentPathResolver.GetImportsFromAbsoluteName(document.FilePath, rootNames, fromImport.ForceAbsolute); return(GetResultFromImportSearch(importSearchResult, context, false)); } return(context.Position > fromImport.KeywordEndIndex ? new CompletionResult(GetAllImportableModules(context)) : null); }
public static CompletionResult GetCompletions(ScopeStatement scope, Node statement, Node expression, CompletionContext context) { if (!(expression is ErrorExpression)) { return(CompletionResult.Empty); } if (statement is AssignmentStatement assign && expression == assign.Right) { return(CompletionResult.Empty); } var tokens = context.TokenSource.Tokens.Reverse().ToArray(); var es = new ExpressionSource(context.TokenSource); string code; SourceLocation location; var items = Enumerable.Empty <CompletionItem>(); SourceSpan? applicableSpan; Expression e; var lastToken = tokens.FirstOrDefault(); if (lastToken.Value == null) { return(CompletionResult.Empty); } var nextLast = tokens.ElementAtOrDefault(1).Value?.Kind ?? TokenKind.EndOfFile; switch (lastToken.Value.Kind) { case TokenKind.Dot: code = es.ReadExpression(tokens.Skip(1)); applicableSpan = new SourceSpan(context.Location, context.Location); e = GetExpressionFromText(code, context, out var s1, out _); items = ExpressionCompletion.GetCompletionsFromMembers(e, s1, context); break; case TokenKind.KeywordDef when lastToken.Key.End < context.Position && scope is FunctionDefinition fd: { applicableSpan = new SourceSpan(context.Location, context.Location); location = context.TokenSource.GetTokenSpan(lastToken.Key).Start; if (FunctionDefinitionCompletion.TryGetCompletionsForOverride(fd, context, location, out var result)) { items = result.Completions; } break; } case TokenKind.Name when nextLast == TokenKind.Dot: code = es.ReadExpression(tokens.Skip(2)); applicableSpan = new SourceSpan(context.TokenSource.GetTokenSpan(lastToken.Key).Start, context.Location); e = GetExpressionFromText(code, context, out var s2, out _); items = ExpressionCompletion.GetCompletionsFromMembers(e, s2, context); break; case TokenKind.Name when nextLast == TokenKind.KeywordDef && scope is FunctionDefinition fd: { applicableSpan = new SourceSpan(context.TokenSource.GetTokenSpan(lastToken.Key).Start, context.Location); location = context.TokenSource.GetTokenSpan(tokens.ElementAt(1).Key).Start; if (FunctionDefinitionCompletion.TryGetCompletionsForOverride(fd, context, location, out var result)) { items = result.Completions; } break; } case TokenKind.KeywordFor: case TokenKind.KeywordAs: return(lastToken.Key.Start <= context.Position && context.Position <= lastToken.Key.End ? null : CompletionResult.Empty); case TokenKind.Error: return(null); default: return(CompletionResult.Empty); } return(new CompletionResult(items, applicableSpan)); }
public static CompletionResult GetCompletions(Node statement, ScopeStatement scopeStatement, CompletionContext context) { SourceSpan?applicableSpan = null; var eval = context.Analysis.ExpressionEvaluator; var options = GetOptions(statement, context.Position, out var span); if (span.HasValue) { applicableSpan = new SourceSpan(context.IndexToLocation(span.Value.Start), context.IndexToLocation(span.Value.End)); } var scope = context.Analysis.FindScope(context.Location); IEnumerable <CompletionItem> items; using (eval.OpenScope(scope)) { // Get variables declared in the module. var variables = eval.CurrentScope.EnumerateTowardsGlobal.SelectMany(s => s.Variables).ToArray(); items = variables.Select(v => context.ItemSource.CreateCompletionItem(v.Name, v)).ToArray(); } // Get builtins var builtins = context.Analysis.Document.Interpreter.ModuleResolution.BuiltinsModule; var builtinItems = builtins.GetMemberNames() .Select(n => { var m = builtins.GetMember(n); if ((options & CompletionListOptions.ExceptionsOnly) == CompletionListOptions.ExceptionsOnly && !IsExceptionType(m.GetPythonType())) { return(null); } return(context.ItemSource.CreateCompletionItem(n, m)); }).ExcludeDefault(); items = items.Concat(builtinItems); // Add possible function arguments. var finder = new ExpressionFinder(context.Ast, new FindExpressionOptions { Calls = true }); if (finder.GetExpression(context.Position) is CallExpression callExpr && callExpr.GetArgumentAtIndex(context.Ast, context.Position, out _)) { var value = eval.GetValueFromExpression(callExpr.Target); if (value?.GetPythonType() is IPythonFunctionType ft) { var arguments = ft.Overloads.SelectMany(o => o.Parameters).Select(p => p?.Name) .Where(n => !string.IsNullOrEmpty(n)) .Distinct() .Except(callExpr.Args.MaybeEnumerate().Select(a => a.Name).Where(n => !string.IsNullOrEmpty(n))) .Select(n => CompletionItemSource.CreateCompletionItem($"{n}=", CompletionItemKind.Variable)) .ToArray(); items = items.Concat(arguments).ToArray(); } } var keywords = GetKeywordItems(context, options, scopeStatement); items = items.Concat(keywords); return(new CompletionResult(items, applicableSpan)); }
public static IEnumerable <CompletionItem> GetCompletionsFromMembers(Expression e, ScopeStatement scope, CompletionContext context) { using (context.Analysis.ExpressionEvaluator.OpenScope(context.Analysis.Document, scope)) { return(GetItemsFromExpression(e, context)); } }
private static IEnumerable <CompletionItem> GetItemsFromExpression(Expression e, CompletionContext context) { var value = context.Analysis.ExpressionEvaluator.GetValueFromExpression(e); if (!value.IsUnknown()) { var items = new List <CompletionItem>(); var type = value.GetPythonType(); var names = type.GetMemberNames().ToArray(); foreach (var t in names) { var m = type.GetMember(t); if (m is IVariable v && v.Source != VariableSource.Declaration) { continue; } items.Add(context.ItemSource.CreateCompletionItem(t, m, type)); } return(items); } return(Enumerable.Empty <CompletionItem>()); }
private static CompletionItem ToOverrideCompletionItem(IPythonFunctionOverload o, ClassDefinition cd, CompletionContext context, string indent) { return(new CompletionItem { label = o.Name, insertText = MakeOverrideCompletionString(indent, o, cd.Name, context), insertTextFormat = InsertTextFormat.PlainText, kind = CompletionItemKind.Method }); }
private static string MakeOverrideCompletionString(string indentation, IPythonFunctionOverload overload, string className, CompletionContext context) { var sb = new StringBuilder(); var first = overload.Parameters.FirstOrDefault(); var fn = overload.ClassMember as IPythonFunctionType; var skipFirstParameters = fn?.IsStatic == true ? overload.Parameters : overload.Parameters.Skip(1); sb.AppendLine(overload.Name + "(" + string.Join(", ", overload.Parameters.Select(p => MakeOverrideParameter(p, p.DefaultValueString))) + "):"); sb.Append(indentation); if (overload.Parameters.Count > 0) { var parameterString = string.Join(", ", skipFirstParameters.Select(p => MakeOverrideParameter(p, p.Name))); if (context.Ast.LanguageVersion.Is3x()) { sb.AppendFormat("return super().{0}({1})", overload.Name, parameterString); } else if (!string.IsNullOrEmpty(className)) { sb.AppendFormat("return super({0}, {1}).{2}({3})", className, first?.Name ?? string.Empty, overload.Name, parameterString); } else { sb.Append("pass"); } } else { sb.Append("pass"); } return(sb.ToString()); }
private static IEnumerable <CompletionItem> GetClassItems(IPythonClassType cls, Expression e, CompletionContext context) { var eval = context.Analysis.ExpressionEvaluator; // See if we are completing on self. Note that we may be inside inner function // that does not necessarily have 'self' argument so we are looking beyond local // scope. We then check that variable type matches the class type, if any. var selfVariable = eval.LookupNameInScopes("self"); var completingOnSelf = cls.Equals(selfVariable?.GetPythonType()) && e is NameExpression nex && nex.Name == "self"; var items = new List <CompletionItem>(); var names = cls.GetMemberNames().ToArray(); foreach (var t in names) { var m = cls.GetMember(t); if (m is IVariable v && v.Source != VariableSource.Declaration) { continue; } // If this is class member completion, unmangle private member names. var unmangledName = cls.UnmangleMemberName(t); if (!string.IsNullOrEmpty(unmangledName)) { // Hide private variables outside of the class scope. if (!completingOnSelf && cls.IsPrivateMember(t)) { continue; } items.Add(context.ItemSource.CreateCompletionItem(unmangledName, m, cls)); } else { items.Add(context.ItemSource.CreateCompletionItem(t, m, cls)); } } return(items); }
public CompletionResult GetCompletions(IDocumentAnalysis analysis, SourceLocation location) { var context = new CompletionContext(analysis, location, _itemSource); ExpressionLocator.FindExpression(analysis.Ast, location, FindExpressionOptions.Complete, out var expression, out var statement, out var scope); switch (expression) { case MemberExpression me when me.Target != null && me.DotIndex > me.StartIndex && context.Position > me.DotIndex: return(new CompletionResult(ExpressionCompletion.GetCompletionsFromMembers(me.Target, scope, context))); case ConstantExpression ce1 when ce1.Value is double || ce1.Value is float: // no completions on integer ., the user is typing a float return(CompletionResult.Empty); case ConstantExpression ce2 when ce2.Value is string: case ConstantExpression ce3 when ce3.Value is AsciiString: // no completions in strings case null when context.Ast.IsInsideComment(context.Location): case null when context.Ast.IsInsideString(context.Location): return(CompletionResult.Empty); } if (statement is ImportStatement import) { var result = ImportCompletion.TryGetCompletions(import, context); if (result != null) { return(result); } } if (statement is FromImportStatement fromImport) { var result = ImportCompletion.GetCompletionsInFromImport(fromImport, context); if (result != null) { return(result); } } switch (statement) { case FunctionDefinition fd when FunctionDefinitionCompletion.TryGetCompletionsForOverride(fd, context, null, out var result): return(result); case FunctionDefinition fd when FunctionDefinitionCompletion.NoCompletions(fd, context.Position, context.Ast): return(CompletionResult.Empty); case ClassDefinition cd: if (!ClassDefinitionCompletion.NoCompletions(cd, context, out var addMetadataArg)) { var result = TopLevelCompletion.GetCompletions(statement, scope, context); return(addMetadataArg ? new CompletionResult(result.Completions.Append(CompletionItemSource.MetadataArg), result.ApplicableSpan) : result); } return(CompletionResult.Empty); case ForStatement forStatement when ForCompletion.TryGetCompletions(forStatement, context, out var result): return(result); case WithStatement withStatement when WithCompletion.TryGetCompletions(withStatement, context, out var result): return(result); case RaiseStatement raiseStatement when RaiseCompletion.TryGetCompletions(raiseStatement, context, out var result): return(result); case TryStatementHandler tryStatement when ExceptCompletion.TryGetCompletions(tryStatement, context, out var result): return(result); default: { var result = ErrorExpressionCompletion.GetCompletions(scope, statement, expression, context); if (result == null) { return(CompletionResult.Empty); } return(result == CompletionResult.Empty ? TopLevelCompletion.GetCompletions(statement, scope, context) : result); } } }
private static IReadOnlyList <CompletionItem> GetChildModules(string[] names, CompletionContext context) { if (!names.Any()) { return(Array.Empty <CompletionItem>()); } var mres = context.Analysis.Document.Interpreter.ModuleResolution; var fullName = string.Join(".", names.Take(names.Length - 1)); var import = mres.CurrentPathResolver.GetModuleImportFromModuleName(fullName); if (string.IsNullOrEmpty(import?.ModulePath)) { return(Array.Empty <CompletionItem>()); } var packages = mres.GetPackagesFromDirectory(Path.GetDirectoryName(import.ModulePath)); return(packages.Select(n => CompletionItemSource.CreateCompletionItem(n, CompletionItemKind.Module)).ToArray()); }
private static string MakeOverrideCompletionString(string indentation, IPythonFunctionOverload overload, string className, CompletionContext context) { var sb = new StringBuilder(); var first = overload.Parameters.FirstOrDefault(); var fn = overload.ClassMember as IPythonFunctionType; var skipFirstParameters = fn?.IsStatic == true ? overload.Parameters : overload.Parameters.Skip(1); var addComma = false; var addMarker = false; sb.Append(overload.Name); sb.Append('('); foreach (var p in overload.Parameters) { if (addComma) { sb.Append(", "); } else { addComma = true; } if (p.Kind == ParameterKind.PositionalOnly) { addMarker = true; } else if (addMarker && p.Kind != ParameterKind.PositionalOnly) { sb.Append("/, "); addMarker = false; } sb.Append(MakeOverrideParameter(p, p.DefaultValueString)); } if (addMarker) { sb.Append(", /"); } sb.AppendLine("):"); sb.Append(indentation); if (overload.Parameters.Count > 0) { // Return in __init__ not good practice, only add return statement if overload is not __init__ if (!overload.Name.Equals("__init__")) { sb.Append("return "); } var parameterString = string.Join(", ", skipFirstParameters.Select(p => MakeOverrideParameter(p, p.Name))); if (context.Ast.LanguageVersion.Is3x()) { sb.AppendFormat("super().{0}({1})", overload.Name, parameterString); } else if (!string.IsNullOrEmpty(className)) { sb.AppendFormat("super({0}, {1}).{2}({3})", className, first?.Name ?? string.Empty, overload.Name, parameterString); } else { sb.Append("pass"); } } else { sb.Append("pass"); } return(sb.ToString()); }
private static IEnumerable <CompletionItem> GetItemsFromExpression(Expression e, CompletionContext context) { var eval = context.Analysis.ExpressionEvaluator; var value = eval.GetValueFromExpression(e); if (!value.IsUnknown()) { var type = value.GetPythonType(); if (type is IPythonClassType cls) { return(GetClassItems(cls, e, context)); } return(type.GetMemberNames() .Select(name => context.ItemSource.CreateCompletionItem(name, type.GetMember(name), type))); } return(Enumerable.Empty <CompletionItem>()); }