public CompletionItemEx CreateCompletionItem(string text, CompletionItemKind kind, IMember member, IPythonType self = null, string label = null) { var t = member?.GetPythonType(); var docFormat = _docSource.DocumentationFormat; if (Options.addBrackets && (kind == CompletionItemKind.Constructor || kind == CompletionItemKind.Function || kind == CompletionItemKind.Method)) { label = text; text += "($0)"; docFormat = InsertTextFormat.Snippet; } return(new CompletionItemEx { label = label ?? text, insertText = text, insertTextFormat = docFormat, // Place regular items first, advanced entries last sortText = char.IsLetter(text, 0) ? "1" : "2", kind = kind, documentation = !t.IsUnknown() ? _docSource.GetHover(label ?? text, member, self) : null, // Custom fields used by the LS extensions that may modify // the completion list. Not passed to the client. Member = member, PythonType = self }); }
public Hover GetHover(IDocumentAnalysis analysis, SourceLocation location) { if (analysis is EmptyAnalysis) { return(new Hover { contents = Resources.AnalysisIsInProgressHover }); } ExpressionLocator.FindExpression(analysis.Ast, location, FindExpressionOptions.Hover, out var node, out var statement, out var scope); if (node is ConstantExpression || node is FString || !(node is Expression expr)) { // node is FString only if it didn't save an f-string subexpression return(null); // No hover for literals. } var range = new Range { start = expr.GetStart(analysis.Ast), end = expr.GetEnd(analysis.Ast) }; var eval = analysis.ExpressionEvaluator; switch (statement) { case FromImportStatement fi when node is NameExpression nex: { var contents = HandleFromImport(fi, location, scope, analysis); if (contents != null) { return(new Hover { contents = contents, range = range }); } break; } case ImportStatement imp: { var contents = HandleImport(imp, location, scope, analysis); if (contents != null) { return(new Hover { contents = contents, range = range }); } break; } } IMember value; IPythonType type; using (eval.OpenScope(analysis.Document, scope)) { value = analysis.ExpressionEvaluator.GetValueFromExpression(expr); type = value?.GetPythonType(); if (type == null) { return(null); } } IPythonType self = null; string name = null; // If expression is A.B, trim applicable span to 'B'. if (expr is MemberExpression mex) { name = mex.Name; range = new Range { start = mex.Target.GetEnd(analysis.Ast), end = range.end }; // In case of a member expression get the target since if we end up with method // of a generic class, the function will need specific type to determine its return // value correctly. I.e. in x.func() we need to determine type of x (self for func). var v = analysis.ExpressionEvaluator.GetValueFromExpression(mex.Target); self = v?.GetPythonType(); } // Figure out name, if any name = name ?? (node as NameExpression)?.Name; // Special case hovering over self or cls if ((name.EqualsOrdinal("self") || name.EqualsOrdinal("cls")) && type is IPythonClassType) { return(new Hover { contents = _docSource.GetHover(null, type), range = range }); } name = name == null && statement is ClassDefinition cd ? cd.Name : name; name = name == null && statement is FunctionDefinition fd ? fd.Name : name; return(new Hover { contents = _docSource.GetHover(name, value, self), range = range }); }
public Hover GetHover(IDocumentAnalysis analysis, SourceLocation location) { if (analysis is EmptyAnalysis) { return(new Hover { contents = Resources.AnalysisIsInProgressHover }); } ExpressionLocator.FindExpression(analysis.Ast, location, FindExpressionOptions.Hover, out var node, out var statement, out var hoverScopeStatement); if (!HasHover(node) || !(node is Expression expr)) { return(null); } var range = new Range { start = expr.GetStart(analysis.Ast), end = expr.GetEnd(analysis.Ast) }; var eval = analysis.ExpressionEvaluator; switch (statement) { case FromImportStatement fi when node is NameExpression nex: { var contents = HandleFromImport(fi, location, hoverScopeStatement, analysis); if (contents != null) { return(new Hover { contents = contents, range = range }); } break; } case ImportStatement imp: { var contents = HandleImport(imp, location, hoverScopeStatement, analysis); if (contents != null) { return(new Hover { contents = contents, range = range }); } break; } } IMember value; IPythonType type; using (eval.OpenScope(analysis.Document, hoverScopeStatement)) { // Here we can be hovering over a class member. Class members are declared // as members as well as special variables in the class scope. If this is // a name expression (rather than a member expression) and it is a class // variable NOT in the immediate class scope, filter it out. Consider: // class A: // x = 1 // y = x // hover over 'x' in 'y = x' should produce proper tooltip. However, in // class A: // x = 1 // def func(self): // y = x // hover over 'x' in 'y = x' should not produce tooltip. IVariable variable = null; if (expr is NameExpression nex) { analysis.ExpressionEvaluator.LookupNameInScopes(nex.Name, out _, out variable, LookupOptions.All); if (IsInvalidClassMember(variable, hoverScopeStatement, location.ToIndex(analysis.Ast))) { return(null); } } value = variable?.Value ?? analysis.ExpressionEvaluator.GetValueFromExpression(expr, LookupOptions.All); type = value?.GetPythonType(); if (type == null) { return(null); } } IPythonType self = null; string name = null; // If expression is A.B, trim applicable span to 'B'. if (expr is MemberExpression mex) { name = mex.Name; range = new Range { start = mex.Target.GetEnd(analysis.Ast), end = range.end }; // In case of a member expression get the target since if we end up with method // of a generic class, the function will need specific type to determine its return // value correctly. I.e. in x.func() we need to determine type of x (self for func). var v = analysis.ExpressionEvaluator.GetValueFromExpression(mex.Target); self = v?.GetPythonType(); } // Figure out name, if any name = name ?? (node as NameExpression)?.Name; // Special case hovering over self or cls if ((name.EqualsOrdinal("self") || name.EqualsOrdinal("cls")) && type is IPythonClassType) { return(new Hover { contents = _docSource.GetHover(null, type), range = range }); } name = name == null && statement is ClassDefinition cd ? cd.Name : name; name = name == null && statement is FunctionDefinition fd ? fd.Name : name; return(new Hover { contents = _docSource.GetHover(name, value, self), range = range }); }