Beispiel #1
0
        private static CompletionContext TrySpecialCompletions(ReverseExpressionParser parser, Span loc)
        {
            if (parser.Tokens.Count > 0)
            {
                // Check for context-sensitive intellisense
                var lastClass = parser.Tokens[parser.Tokens.Count - 1];

                if (lastClass.ClassificationType == parser.Classifier.Provider.Comment)
                {
                    // No completions in comments
                    return(EmptyCompletionContext);
                }
                else if (lastClass.ClassificationType == parser.Classifier.Provider.StringLiteral)
                {
                    // String completion
                    return(new StringLiteralCompletionContext(lastClass.Span.GetText(), loc.Start, parser.Span, parser.Buffer));
                }

                // Import completions
                var first = parser.Tokens[0];
                if (IsKeyword(first, "import"))
                {
                    return(ImportCompletionContext.Make(first, lastClass, loc, parser.Snapshot, parser.Span, parser.Buffer, IsSpaceCompletion(parser, loc)));
                }
                else if (IsKeyword(first, "from"))
                {
                    return(FromImportCompletionContext.Make(parser.Tokens, first, loc, parser.Snapshot, parser.Span, parser.Buffer, IsSpaceCompletion(parser, loc)));
                }
                return(null);
            }

            return(EmptyCompletionContext);
        }
Beispiel #2
0
        public static CompletionContext GetSignatureContext(ITextSnapshot snapshot, ITextBuffer buffer, ITrackingSpan span)
        {
            ReverseExpressionParser parser = new ReverseExpressionParser(snapshot, buffer, span);

            var loc = parser.Span.GetSpan(parser.Snapshot.Version);

            int paramIndex;
            var exprRange = parser.GetExpressionRange(1, out paramIndex);

            if (exprRange == null)
            {
                return(EmptyCompletionContext);
            }
            var text = exprRange.Value.GetText();

            var applicableSpan = parser.Snapshot.CreateTrackingSpan(
                exprRange.Value.Span,
                SpanTrackingMode.EdgeExclusive
                );

            return(new NormalCompletionContext(
                       text,
                       loc.Start,
                       parser.Snapshot,
                       applicableSpan,
                       parser.Buffer,
                       paramIndex
                       ));
        }
Beispiel #3
0
        private static CompletionAnalysis GetNormalCompletionContext(ReverseExpressionParser parser, Span loc, bool intersectMembers = true, bool hideAdvancedMembers = false)
        {
            var exprRange = parser.GetExpressionRange();

            if (exprRange == null)
            {
                return(CompletionAnalysis.EmptyCompletionContext);
            }
            if (IsSpaceCompletion(parser, loc))
            {
                return(CompletionAnalysis.EmptyCompletionContext);
            }

            var text = exprRange.Value.GetText();

            var applicableSpan = parser.Snapshot.CreateTrackingSpan(
                exprRange.Value.Span,
                SpanTrackingMode.EdgeExclusive
                );

            return(new NormalCompletionAnalysis(
                       text,
                       loc.Start,
                       parser.Snapshot,
                       applicableSpan,
                       parser.Buffer,
                       -1,
                       intersectMembers,
                       hideAdvancedMembers
                       ));
        }
Beispiel #4
0
        private bool ShouldTriggerIdentifierCompletionSession(out bool commitByDefault)
        {
            commitByDefault = true;

            if (_bufferParser == null ||
                !_provider.PythonService.AdvancedOptions.AutoListIdentifiers ||
                !_provider.PythonService.AdvancedOptions.AutoListMembers)
            {
                return(false);
            }

            SnapshotPoint?caretPoint = _textView.BufferGraph.MapDownToFirstMatch(
                _textView.Caret.Position.BufferPosition,
                PointTrackingMode.Positive,
                EditorExtensions.IsPythonContent,
                PositionAffinity.Predecessor
                );

            if (!caretPoint.HasValue)
            {
                return(false);
            }

            var snapshot = caretPoint.Value.Snapshot;

            var statement = new ReverseExpressionParser(
                snapshot,
                snapshot.TextBuffer,
                snapshot.CreateTrackingSpan(caretPoint.Value.Position, 0, SpanTrackingMode.EdgeNegative)
                ).GetStatementRange();

            if (!statement.HasValue || caretPoint.Value <= statement.Value.Start)
            {
                return(false);
            }

            var text = new SnapshotSpan(statement.Value.Start, caretPoint.Value).GetText();

            if (string.IsNullOrEmpty(text))
            {
                return(false);
            }

            var       languageVersion = _bufferParser._parser.InterpreterFactory.Configuration.Version.ToLanguageVersion();
            PythonAst ast;

            using (var parser = Parser.CreateParser(new StringReader(text), languageVersion, new ParserOptions())) {
                ast = parser.ParseSingleStatement();
            }

            var walker = new ExpressionCompletionWalker(caretPoint.Value.Position - statement.Value.Start.Position);

            ast.Walk(walker);
            commitByDefault = walker.CommitByDefault;
            return(walker.CanComplete);
        }
Beispiel #5
0
        /// <summary>
        /// Gets a ExpressionAnalysis for the expression at the provided span.  If the span is in
        /// part of an identifier then the expression is extended to complete the identifier.
        /// </summary>
        public static ExpressionAnalysis AnalyzeExpression(ITextSnapshot snapshot, ITrackingSpan span, bool forCompletion = true)
        {
            var buffer = snapshot.TextBuffer;
            ReverseExpressionParser parser = new ReverseExpressionParser(snapshot, buffer, span);

            var loc       = parser.Span.GetSpan(parser.Snapshot.Version);
            var exprRange = parser.GetExpressionRange(forCompletion);

            if (exprRange == null)
            {
                if (parser.Tokens.Count > 0)
                {
                    var    lastToken  = parser.Tokens[parser.Tokens.Count - 1];
                    string wholeToken = GetWholeTokenRight(snapshot, lastToken.Span);
                    if (wholeToken != null)
                    {
                        return(new ExpressionAnalysis(wholeToken, null, lastToken.Span.Start.GetContainingLine().LineNumber, null));
                    }
                }
                return(ExpressionAnalysis.Empty);
            }

            // extend right for any partial expression the user is hovering on, for example:
            // "x.Baz" where the user is hovering over the B in baz we want the complete
            // expression.
            string text = GetWholeTokenRight(snapshot, exprRange.Value);

            if (text == null)
            {
                return(ExpressionAnalysis.Empty);
            }

            var applicableSpan = parser.Snapshot.CreateTrackingSpan(
                exprRange.Value.Span,
                SpanTrackingMode.EdgeExclusive
                );

            IProjectEntry analysisItem;

            if (buffer.TryGetAnalysis(out analysisItem))
            {
                var analysis = ((IPythonProjectEntry)analysisItem).Analysis;
                if (analysis != null && text.Length > 0)
                {
                    var lineNo = parser.Snapshot.GetLineNumberFromPosition(loc.Start);
                    return(new ExpressionAnalysis(
                               text,
                               analysis,
                               lineNo + 1,
                               applicableSpan));
                }
            }

            return(ExpressionAnalysis.Empty);
        }
        internal bool GetPrecedingExpression(out string text, out SnapshotSpan statementExtent)
        {
            text            = string.Empty;
            statementExtent = default(SnapshotSpan);

            var startSpan = _snapshot.CreateTrackingSpan(Span.GetSpan(_snapshot).Start.Position, 0, SpanTrackingMode.EdgeInclusive);
            var parser    = new ReverseExpressionParser(_snapshot, _snapshot.TextBuffer, startSpan);

            using (var e = parser.GetEnumerator()) {
                if (e.MoveNext() &&
                    e.Current != null &&
                    e.Current.ClassificationType.IsOfType(PredefinedClassificationTypeNames.Number))
                {
                    return(false);
                }
            }

            var sourceSpan = parser.GetExpressionRange();

            if (sourceSpan.HasValue && sourceSpan.Value.Length > 0)
            {
                text = sourceSpan.Value.GetText();
                if (text.EndsWith("."))
                {
                    text = text.Substring(0, text.Length - 1);
                    if (text.Length == 0)
                    {
                        // don't return all available members on empty dot.
                        return(false);
                    }
                }
                else
                {
                    int cut = text.LastIndexOfAny(new[] { '.', ']', ')' });
                    if (cut != -1)
                    {
                        text = text.Substring(0, cut);
                    }
                    else
                    {
                        text = String.Empty;
                    }
                }
            }


            statementExtent = parser.GetStatementRange() ?? new SnapshotSpan(Span.GetStartPoint(_snapshot), 0);

            return(true);
        }
Beispiel #7
0
        /// <summary>
        /// Gets a CompletionContext providing a list of possible members the user can dot through.
        /// </summary>
        public static CompletionContext GetMemberCompletionContext(ITextSnapshot snapshot, ITextBuffer buffer, ITrackingSpan span)
        {
            ReverseExpressionParser parser = new ReverseExpressionParser(snapshot, buffer, span);

            var loc       = parser.Span.GetSpan(parser.Snapshot.Version);
            var line      = parser.Snapshot.GetLineFromPosition(loc.Start);
            var lineStart = line.Start;

            var textLen = loc.End - lineStart.Position;

            if (textLen <= 0)
            {
                // Ctrl-Space on an empty line, we just want to get global vars
                return(new NormalCompletionContext(String.Empty, loc.Start, parser.Snapshot, parser.Span, parser.Buffer, 0));
            }

            return(TrySpecialCompletions(parser, loc) ??
                   GetNormalCompletionContext(parser, loc));
        }
Beispiel #8
0
        /// <summary>
        /// Gets a CompletionContext for the expression at the provided span.  If the span is in
        /// part of an identifier then the expression is extended to complete the identifier.
        /// </summary>
        public static CompletionContext GetExpressionContext(ITextSnapshot snapshot, ITextBuffer buffer, ITrackingSpan span)
        {
            ReverseExpressionParser parser = new ReverseExpressionParser(snapshot, buffer, span);

            var loc       = parser.Span.GetSpan(parser.Snapshot.Version);
            var exprRange = parser.GetExpressionRange();

            if (exprRange == null)
            {
                return(EmptyCompletionContext);
            }

            // extend right for any partial expression the user is hovering on, for example:
            // "x.Baz" where the user is hovering over the B in baz we want the complete
            // expression.
            var text       = exprRange.Value.GetText();
            var endingLine = exprRange.Value.End.GetContainingLine();
            var endText    = snapshot.GetText(exprRange.Value.End.Position, endingLine.End.Position - exprRange.Value.End.Position);

            for (int i = 0; i < endText.Length; i++)
            {
                if (!Char.IsLetterOrDigit(endText[i]) && endText[i] != '_')
                {
                    text += endText.Substring(0, i);
                    break;
                }
            }

            var applicableSpan = parser.Snapshot.CreateTrackingSpan(
                exprRange.Value.Span,
                SpanTrackingMode.EdgeExclusive
                );

            return(new NormalCompletionContext(
                       text,
                       loc.Start,
                       parser.Snapshot,
                       applicableSpan,
                       parser.Buffer,
                       -1
                       ));
        }
Beispiel #9
0
        /// <summary>
        /// Gets a CompletionList providing a list of possible members the user can dot through.
        /// </summary>
        public static CompletionAnalysis GetCompletions(ITextSnapshot snapshot, ITrackingSpan span, bool intersectMembers = true, bool hideAdvancedMembers = false)
        {
            var buffer = snapshot.TextBuffer;
            ReverseExpressionParser parser = new ReverseExpressionParser(snapshot, buffer, span);

            var loc       = parser.Span.GetSpan(parser.Snapshot.Version);
            var line      = parser.Snapshot.GetLineFromPosition(loc.Start);
            var lineStart = line.Start;

            var textLen = loc.End - lineStart.Position;

            if (textLen <= 0)
            {
                // Ctrl-Space on an empty line, we just want to get global vars
                return(new NormalCompletionAnalysis(String.Empty, loc.Start, parser.Snapshot, parser.Span, parser.Buffer, 0));
            }

            return(TrySpecialCompletions(parser, loc) ??
                   GetNormalCompletionContext(parser, loc, intersectMembers, hideAdvancedMembers));
        }
Beispiel #10
0
        private static CompletionContext GetNormalCompletionContext(ReverseExpressionParser parser, Span loc)
        {
            var exprRange = parser.GetExpressionRange();

            if (exprRange == null)
            {
                return(EmptyCompletionContext);
            }
            var text = exprRange.Value.GetText();

            var applicableSpan = parser.Snapshot.CreateTrackingSpan(
                exprRange.Value.Span,
                SpanTrackingMode.EdgeExclusive
                );

            return(new NormalCompletionContext(
                       text,
                       loc.Start,
                       parser.Snapshot,
                       applicableSpan,
                       parser.Buffer,
                       -1
                       ));
        }
Beispiel #11
0
        private static bool IsSpaceCompletion(ReverseExpressionParser parser, Span loc)
        {
            var keySpan = new SnapshotSpan(parser.Snapshot, loc.Start - 1, 1);

            return(keySpan.GetText() == " ");
        }
Beispiel #12
0
        /// <summary>
        /// Gets a list of signatuers available for the expression at the provided location in the snapshot.
        /// </summary>
        public static SignatureAnalysis GetSignatures(ITextSnapshot snapshot, ITrackingSpan span)
        {
            var buffer = snapshot.TextBuffer;
            ReverseExpressionParser parser = new ReverseExpressionParser(snapshot, buffer, span);

            var loc = parser.Span.GetSpan(parser.Snapshot.Version);

            int           paramIndex;
            SnapshotPoint?sigStart;
            var           exprRange = parser.GetExpressionRange(1, out paramIndex, out sigStart);

            if (exprRange == null || sigStart == null)
            {
                return(new SignatureAnalysis("", 0, new ISignature[0]));
            }

            Debug.Assert(sigStart != null);
            var text = new SnapshotSpan(exprRange.Value.Snapshot, new Span(exprRange.Value.Start, sigStart.Value.Position - exprRange.Value.Start)).GetText();
            //var text = exprRange.Value.GetText();
            var applicableSpan = parser.Snapshot.CreateTrackingSpan(exprRange.Value.Span, SpanTrackingMode.EdgeInclusive);

            if (snapshot.TextBuffer.GetAnalyzer().ShouldEvaluateForCompletion(text))
            {
                var liveSigs = TryGetLiveSignatures(snapshot, paramIndex, text, applicableSpan);
                if (liveSigs != null)
                {
                    return(liveSigs);
                }
            }

            var start = Stopwatch.ElapsedMilliseconds;

            var analysisItem = buffer.GetAnalysis();

            if (analysisItem != null)
            {
                var analysis = ((IPythonProjectEntry)analysisItem).Analysis;
                if (analysis != null)
                {
                    var lineNo = parser.Snapshot.GetLineNumberFromPosition(loc.Start);

                    var sigs = analysis.GetSignatures(text, lineNo + 1);
                    var end  = Stopwatch.ElapsedMilliseconds;

                    if (/*Logging &&*/ (end - start) > CompletionAnalysis.TooMuchTime)
                    {
                        Trace.WriteLine(String.Format("{0} lookup time {1} for signatures", text, end - start));
                    }

                    var result = new List <ISignature>();
                    foreach (var sig in sigs)
                    {
                        result.Add(new PythonSignature(applicableSpan, sig, paramIndex));
                    }

                    return(new SignatureAnalysis(
                               text,
                               paramIndex,
                               result
                               ));
                }
            }
            return(new SignatureAnalysis(text, paramIndex, new ISignature[0]));
        }