public int GetDataTipText(TextSpan[] pSpan, out string pbstrText) { if (!_wpfTextView.TextBuffer.ContentType.IsOfType(PythonCoreConstants.ContentType)) { pbstrText = null; return(VSConstants.E_NOTIMPL); } if (pSpan.Length != 1) { throw new ArgumentException("Array parameter should contain exactly one TextSpan", "pSpan"); } // Adjust the span to expression boundaries. var snapshot = _wpfTextView.TextSnapshot; var start = LineAndColumnNumberToSnapshotPoint(snapshot, pSpan[0].iStartLine, pSpan[0].iStartIndex); var end = LineAndColumnNumberToSnapshotPoint(snapshot, pSpan[0].iEndLine, pSpan[0].iEndIndex); // If this is a zero-length span (which it usually is, unless there's selection), adjust it // to cover one char to the right, since an empty span at the beginning of the expression does // not count as belonging to that expression; if (start == end && start.Position != snapshot.Length) { end += 1; } var snapshotSpan = new SnapshotSpan(start, end); var trackingSpan = snapshot.CreateTrackingSpan(snapshotSpan.Span, SpanTrackingMode.EdgeExclusive); var rep = new ReverseExpressionParser(snapshot, _wpfTextView.TextBuffer, trackingSpan); var exprSpan = rep.GetExpressionRange(forCompletion: false); string expr = null; if (exprSpan != null) { SnapshotPointToLineAndColumnNumber(exprSpan.Value.Start, out pSpan[0].iStartLine, out pSpan[0].iStartIndex); SnapshotPointToLineAndColumnNumber(exprSpan.Value.End, out pSpan[0].iEndLine, out pSpan[0].iEndIndex); expr = VsProjectAnalyzer.ExpressionForDataTipAsync( _serviceProvider, _wpfTextView, exprSpan.Value, TimeSpan.FromSeconds(1.0) ).WaitAndUnwrapExceptions(Dispatcher.CurrentDispatcher); } else { // If it's not an expression, suppress the tip. pbstrText = null; return(VSConstants.E_FAIL); } return(_debugger.GetDataTipValue(_vsTextLines, pSpan, expr, out pbstrText)); }
internal static TextSpan?GetDataTipSpan(IWpfTextView wpfTextView, TextSpan selection) { // Adjust the span to expression boundaries. var snapshot = wpfTextView.TextSnapshot; var start = LineAndColumnNumberToSnapshotPoint(snapshot, selection.iStartLine, selection.iStartIndex); var end = LineAndColumnNumberToSnapshotPoint(snapshot, selection.iEndLine, selection.iEndIndex); // If this is a zero-length span (which it usually is, unless there's selection), adjust it // to cover one char to the right, since an empty span at the beginning of the expression does // not count as belonging to that expression; if (start == end && start.Position != snapshot.Length) { end += 1; } var snapshotSpan = new SnapshotSpan(start, end); var trackingSpan = snapshot.CreateTrackingSpan(snapshotSpan.Span, SpanTrackingMode.EdgeExclusive); var rep = new ReverseExpressionParser(snapshot, wpfTextView.TextBuffer, trackingSpan); var exprSpan = rep.GetExpressionRange(forCompletion: false); if (exprSpan == null) { return(null); } // Check whether this is an expression with side effects - if it does, we don't want to show a data tip for it. string text = exprSpan.Value.GetText(); var ast = new JSParser(text).Parse(new CodeSettings()); var sideEffectsDetectingVisitor = new SideEffectsDetectingVisitor(); ast.Walk(sideEffectsDetectingVisitor); if (sideEffectsDetectingVisitor.HasSideEffects) { return(null); } TextSpan dataTipSpan; SnapshotPointToLineAndColumnNumber(exprSpan.Value.Start, out dataTipSpan.iStartLine, out dataTipSpan.iStartIndex); SnapshotPointToLineAndColumnNumber(exprSpan.Value.End, out dataTipSpan.iEndLine, out dataTipSpan.iEndIndex); return(dataTipSpan); }
internal bool GetPrecedingExpression(out string text, out SnapshotSpan expressionExtent) { text = string.Empty; expressionExtent = 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; } } } expressionExtent = sourceSpan ?? new SnapshotSpan(Span.GetStartPoint(_snapshot), 0); return true; }
internal static MissingImportAnalysis GetMissingImports(IServiceProvider serviceProvider, ITextSnapshot snapshot, ITrackingSpan span) { ReverseExpressionParser parser = new ReverseExpressionParser(snapshot, snapshot.TextBuffer, span); var loc = span.GetSpan(snapshot.Version); int dummy; SnapshotPoint? dummyPoint; string lastKeywordArg; bool isParameterName; var exprRange = parser.GetExpressionRange(0, out dummy, out dummyPoint, out lastKeywordArg, out isParameterName); if (exprRange == null || isParameterName) { return MissingImportAnalysis.Empty; } IPythonProjectEntry entry; ModuleAnalysis analysis; if (!snapshot.TextBuffer.TryGetPythonProjectEntry(out entry) || entry == null || (analysis = entry.Analysis) == null) { return MissingImportAnalysis.Empty; } var text = exprRange.Value.GetText(); if (string.IsNullOrEmpty(text)) { return MissingImportAnalysis.Empty; } var analyzer = analysis.ProjectState; var index = (parser.GetStatementRange() ?? span.GetSpan(snapshot)).Start.Position; var location = TranslateIndex( index, snapshot, analysis ); var nameExpr = GetFirstNameExpression(analysis.GetAstFromText(text, location).Body); if (nameExpr != null && !IsImplicitlyDefinedName(nameExpr)) { var name = nameExpr.Name; lock (snapshot.TextBuffer.GetAnalyzer(serviceProvider)) { var hasVariables = analysis.GetVariables(name, location).Any(IsDefinition); var hasValues = analysis.GetValues(name, location).Any(); // if we have type information or an assignment to the variable we won't offer // an import smart tag. if (!hasValues && !hasVariables) { var applicableSpan = parser.Snapshot.CreateTrackingSpan( exprRange.Value.Span, SpanTrackingMode.EdgeExclusive ); return new MissingImportAnalysis(name, analysis.ProjectState, applicableSpan); } } } // if we have type information don't offer to add imports return MissingImportAnalysis.Empty; }
/// <summary> /// Gets a list of signatuers available for the expression at the provided location in the snapshot. /// </summary> internal static SignatureAnalysis GetSignatures(IServiceProvider serviceProvider, 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; string lastKeywordArg; bool isParameterName; var exprRange = parser.GetExpressionRange(1, out paramIndex, out sigStart, out lastKeywordArg, out isParameterName); if (exprRange == null || sigStart == null) { return new SignatureAnalysis("", 0, new ISignature[0]); } var text = new SnapshotSpan(exprRange.Value.Snapshot, new Span(exprRange.Value.Start, sigStart.Value.Position - exprRange.Value.Start)).GetText(); var applicableSpan = parser.Snapshot.CreateTrackingSpan(exprRange.Value.Span, SpanTrackingMode.EdgeInclusive); if (snapshot.TextBuffer.GetAnalyzer(serviceProvider).ShouldEvaluateForCompletion(text)) { var liveSigs = TryGetLiveSignatures(snapshot, paramIndex, text, applicableSpan, lastKeywordArg); if (liveSigs != null) { return liveSigs; } } var start = Stopwatch.ElapsedMilliseconds; var analysisItem = buffer.GetProjectEntry(); if (analysisItem != null) { var analysis = ((IPythonProjectEntry)analysisItem).Analysis; if (analysis != null) { var location = TranslateIndex(loc.Start, snapshot, analysis); IEnumerable<IOverloadResult> sigs; lock (snapshot.TextBuffer.GetAnalyzer(serviceProvider)) { sigs = analysis.GetSignatures(text, location); } 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, lastKeywordArg)); } return new SignatureAnalysis( text, paramIndex, result, lastKeywordArg ); } } return new SignatureAnalysis(text, paramIndex, new ISignature[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> internal static ExpressionAnalysis AnalyzeExpression(IServiceProvider serviceProvider, 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) { return ExpressionAnalysis.Empty; } string text = exprRange.Value.GetText(); var applicableSpan = parser.Snapshot.CreateTrackingSpan( exprRange.Value.Span, SpanTrackingMode.EdgeExclusive ); IPythonProjectEntry entry; if (buffer.TryGetPythonProjectEntry(out entry) && entry.Analysis != null && text.Length > 0) { var lineNo = parser.Snapshot.GetLineNumberFromPosition(loc.Start); return new ExpressionAnalysis( snapshot.TextBuffer.GetAnalyzer(serviceProvider), text, entry.Analysis, loc.Start, applicableSpan, parser.Snapshot ); } return ExpressionAnalysis.Empty; }
internal static MissingImportAnalysis GetMissingImports(ITextSnapshot snapshot, ITrackingSpan span) { ReverseExpressionParser parser = new ReverseExpressionParser(snapshot, snapshot.TextBuffer, span); var loc = span.GetSpan(snapshot.Version); int dummy; SnapshotPoint? dummyPoint; string lastKeywordArg; bool isParameterName; var exprRange = parser.GetExpressionRange(0, out dummy, out dummyPoint, out lastKeywordArg, out isParameterName); if (exprRange == null || isParameterName) { return MissingImportAnalysis.Empty; } var analysis = ((IPythonProjectEntry)snapshot.TextBuffer.GetProjectEntry()).Analysis; if (analysis == null) { return MissingImportAnalysis.Empty; } var text = exprRange.Value.GetText(); var analyzer = analysis.ProjectState; var index = span.GetStartPoint(snapshot).Position; var expr = Statement.GetExpression( analysis.GetAstFromTextByIndex( text, TranslateIndex( index, snapshot, analysis ) ).Body ); if (expr != null && expr is NameExpression) { var nameExpr = (NameExpression)expr; if (!IsImplicitlyDefinedName(nameExpr)) { var applicableSpan = parser.Snapshot.CreateTrackingSpan( exprRange.Value.Span, SpanTrackingMode.EdgeExclusive ); lock (snapshot.TextBuffer.GetAnalyzer()) { index = TranslateIndex( index, snapshot, analysis ); var variables = analysis.GetVariablesByIndex(text, index).Where(IsDefinition).Count(); var values = analysis.GetValuesByIndex(text, index).ToArray(); // if we have type information or an assignment to the variable we won't offer // an import smart tag. if (values.Length == 0 && variables == 0) { string name = nameExpr.Name; var imports = analysis.ProjectState.FindNameInAllModules(name); return new MissingImportAnalysis(imports, applicableSpan); } } } } // if we have type information don't offer to add imports return MissingImportAnalysis.Empty; }
/// <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; string lastKeywordArg; bool isParameterName; var exprRange = parser.GetExpressionRange(1, out paramIndex, out sigStart, out lastKeywordArg, out isParameterName, forSignatureHelp: true); if (exprRange == null || sigStart == null) { return new SignatureAnalysis(String.Empty, 0, new ISignature[0]); } var text = new SnapshotSpan(exprRange.Value.Snapshot, new Span(exprRange.Value.Start, sigStart.Value.Position - exprRange.Value.Start)).GetText(); var applicableSpan = parser.Snapshot.CreateTrackingSpan(exprRange.Value.Span, SpanTrackingMode.EdgeInclusive); var analysisItem = buffer.GetProjectEntry(); if (analysisItem != null) { var analysis = ((IJsProjectEntry)analysisItem).Analysis; if (analysis != null) { int index = TranslateIndex(loc.Start, snapshot, analysis); IEnumerable<IOverloadResult> sigs; lock (snapshot.TextBuffer.GetAnalyzer()) { sigs = analysis.GetSignaturesByIndex(text, index); } var result = new List<ISignature>(); foreach (var sig in sigs) { result.Add(new NodejsSignature(applicableSpan, sig, paramIndex, lastKeywordArg)); } return new SignatureAnalysis( text, paramIndex, result, lastKeywordArg ); } } return new SignatureAnalysis(text, paramIndex, new ISignature[0]); }
private static CompletionAnalysis TrySpecialCompletions(ITextSnapshot snapshot, ITrackingSpan span, ITrackingPoint point) { var snapSpan = span.GetSpan(snapshot); var buffer = snapshot.TextBuffer; var classifier = buffer.GetNodejsClassifier(); if (classifier == null) { return null; } var start = snapSpan.Start; var parser = new ReverseExpressionParser(snapshot, buffer, span); if (parser.IsInGrouping()) { var range = parser.GetExpressionRange(nesting: 1); if (range != null) { start = range.Value.Start; } } // Get the classifiers from beginning of the line to the beginning of snapSpan. // The contents of snapSpan differ depending on what is determined in // CompletionSource.GetApplicableSpan. // // In the case of: // var myIdentifier<cursor> // the applicable span will be "myIdentifier", so GetClassificationSpans will operate on "var " // // In the case of comments and string literals, the applicable span will be empty, // so snapSpan.Start will occur at the current cursor position. var tokens = classifier.GetClassificationSpans(new SnapshotSpan(start.GetContainingLine().Start, snapSpan.Start)); if (tokens.Count > 0) { // Check for context-sensitive intellisense var lastClass = tokens[tokens.Count - 1]; if (lastClass.ClassificationType == classifier.Provider.Comment || lastClass.ClassificationType == classifier.Provider.StringLiteral || (lastClass.ClassificationType == classifier.Provider.Keyword && _emptyCompletionContextKeywords.Contains(lastClass.Span.GetText()))) { // No completions in comments, strings, or directly after certain keywords. return CompletionAnalysis.EmptyCompletionContext; } return null; } return null; }
private static CompletionAnalysis TrySpecialCompletions(ITextSnapshot snapshot, ITrackingSpan span, ITrackingPoint point) { var snapSpan = span.GetSpan(snapshot); var buffer = snapshot.TextBuffer; var classifier = buffer.GetNodejsClassifier(); if (classifier == null) { return null; } var start = snapSpan.Start; var parser = new ReverseExpressionParser(snapshot, buffer, span); if (parser.IsInGrouping()) { var range = parser.GetExpressionRange(nesting: 1); if (range != null) { start = range.Value.Start; } } var tokens = classifier.GetClassificationSpans(new SnapshotSpan(start.GetContainingLine().Start, snapSpan.Start)); if (tokens.Count > 0) { // Check for context-sensitive intellisense var lastClass = tokens[tokens.Count - 1]; if (lastClass.ClassificationType == classifier.Provider.Comment) { // No completions in comments return CompletionAnalysis.EmptyCompletionContext; } else if (lastClass.ClassificationType == classifier.Provider.StringLiteral) { // String completion return CompletionAnalysis.EmptyCompletionContext; } return null; } return null; }
public int GetDataTipText(TextSpan[] pSpan, out string pbstrText) { if (!_wpfTextView.TextBuffer.ContentType.IsOfType(PythonCoreConstants.ContentType)) { pbstrText = null; return VSConstants.E_NOTIMPL; } if (pSpan.Length != 1) { throw new ArgumentException("Array parameter should contain exactly one TextSpan", "pSpan"); } // Adjust the span to expression boundaries. var snapshot = _wpfTextView.TextSnapshot; var start = LineAndColumnNumberToSnapshotPoint(snapshot, pSpan[0].iStartLine, pSpan[0].iStartIndex); var end = LineAndColumnNumberToSnapshotPoint(snapshot, pSpan[0].iEndLine, pSpan[0].iEndIndex); // If this is a zero-length span (which it usually is, unless there's selection), adjust it // to cover one char to the right, since an empty span at the beginning of the expression does // not count as belonging to that expression; if (start == end && start.Position != snapshot.Length) { end += 1; } var snapshotSpan = new SnapshotSpan(start, end); var trackingSpan = snapshot.CreateTrackingSpan(snapshotSpan.Span, SpanTrackingMode.EdgeExclusive); var rep = new ReverseExpressionParser(snapshot, _wpfTextView.TextBuffer, trackingSpan); var exprSpan = rep.GetExpressionRange(forCompletion: false); if (exprSpan != null) { SnapshotPointToLineAndColumnNumber(exprSpan.Value.Start, out pSpan[0].iStartLine, out pSpan[0].iStartIndex); SnapshotPointToLineAndColumnNumber(exprSpan.Value.End, out pSpan[0].iEndLine, out pSpan[0].iEndIndex); } else { // If it's not an expression, suppress the tip. pbstrText = null; return VSConstants.E_FAIL; } return _debugger.GetDataTipValue(_vsTextLines, pSpan, null, out pbstrText); }
internal static TextSpan? GetDataTipSpan(IWpfTextView wpfTextView, TextSpan selection) { // Adjust the span to expression boundaries. var snapshot = wpfTextView.TextSnapshot; var start = LineAndColumnNumberToSnapshotPoint(snapshot, selection.iStartLine, selection.iStartIndex); var end = LineAndColumnNumberToSnapshotPoint(snapshot, selection.iEndLine, selection.iEndIndex); // If this is a zero-length span (which it usually is, unless there's selection), adjust it // to cover one char to the right, since an empty span at the beginning of the expression does // not count as belonging to that expression; if (start == end && start.Position != snapshot.Length) { end += 1; } var snapshotSpan = new SnapshotSpan(start, end); var trackingSpan = snapshot.CreateTrackingSpan(snapshotSpan.Span, SpanTrackingMode.EdgeExclusive); var rep = new ReverseExpressionParser(snapshot, wpfTextView.TextBuffer, trackingSpan); var exprSpan = rep.GetExpressionRange(forCompletion: false); if (exprSpan == null) { return null; } // Check whether this is an expression with side effects - if it does, we don't want to show a data tip for it. string text = exprSpan.Value.GetText(); var ast = new JSParser(text).Parse(new CodeSettings()); var sideEffectsDetectingVisitor = new SideEffectsDetectingVisitor(); ast.Walk(sideEffectsDetectingVisitor); if (sideEffectsDetectingVisitor.HasSideEffects) { return null; } TextSpan dataTipSpan; SnapshotPointToLineAndColumnNumber(exprSpan.Value.Start, out dataTipSpan.iStartLine, out dataTipSpan.iStartIndex); SnapshotPointToLineAndColumnNumber(exprSpan.Value.End, out dataTipSpan.iEndLine, out dataTipSpan.iEndIndex); return dataTipSpan; }