|
' Licensed to the .NET Foundation under one or more agreements.
' The .NET Foundation licenses this file to you under the MIT license.
' See the LICENSE file in the project root for more information.
Imports System.Threading
Imports Microsoft.CodeAnalysis
Imports Microsoft.CodeAnalysis.Editor
Imports Microsoft.CodeAnalysis.Shared.Extensions
Imports Microsoft.CodeAnalysis.VisualBasic.Extensions
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Imports Microsoft.VisualStudio.ComponentModelHost
Imports Microsoft.VisualStudio.LanguageServices.Implementation.DebuggerIntelliSense
Imports Microsoft.VisualStudio.Text
Imports Microsoft.VisualStudio.Text.Editor
Imports Microsoft.VisualStudio.Text.Projection
Imports Microsoft.VisualStudio.TextManager.Interop
Imports Microsoft.VisualStudio.Utilities
Imports TextSpan = Microsoft.VisualStudio.TextManager.Interop.TextSpan
Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic
Friend Class VisualBasicDebuggerIntelliSenseContext
Inherits AbstractDebuggerIntelliSenseContext
Private _innerMostContainingNodeIsExpression As Boolean
Private Const StatementTerminator As String = vbCrLf
Public Sub New(wpfTextView As IWpfTextView,
vsTextView As IVsTextView,
debuggerBuffer As IVsTextLines,
contextBuffer As ITextBuffer,
currentStatementSpan As TextSpan(),
componentModel As IComponentModel,
serviceProvider As IServiceProvider)
MyBase.New(
wpfTextView,
vsTextView,
debuggerBuffer,
contextBuffer,
currentStatementSpan,
componentModel,
serviceProvider,
componentModel.GetService(Of IContentTypeRegistryService).GetContentType(ContentTypeNames.VisualBasicContentType))
End Sub
' Test constructor
Public Sub New(wpfTextView As IWpfTextView,
textBuffer As ITextBuffer,
span As TextSpan(),
componentModel As IComponentModel,
isImmediateWindow As Boolean)
MyBase.New(
wpfTextView,
textBuffer,
span,
componentModel,
componentModel.GetService(Of IContentTypeRegistryService).GetContentType(ContentTypeNames.VisualBasicContentType),
isImmediateWindow)
End Sub
Protected Overrides Function GetAdjustedBuffer(contextPoint As Integer, document As Document, debuggerMappedSpan As ITrackingSpan) As IProjectionBuffer
Dim tree = document.GetSyntaxTreeSynchronously(CancellationToken.None)
Dim token = tree.FindTokenOnLeftOfPosition(contextPoint, CancellationToken.None)
Dim adjustedStart = token.FullSpan.End
Dim containingNode = token.Parent.AncestorsAndSelf().Where(Function(s) TypeOf s Is ExpressionSyntax OrElse
TypeOf s Is MethodBaseSyntax OrElse
s.IsExecutableBlock()).FirstOrDefault()
If containingNode IsNot Nothing Then
If TypeOf containingNode Is ExpressionSyntax AndAlso Not IsRightSideOfLocalDeclaration(containingNode) Then
_innerMostContainingNodeIsExpression = True
adjustedStart = containingNode.Span.End
Else
Dim statement = containingNode.GetExecutableBlockStatements().FirstOrDefault()
If statement IsNot Nothing Then
adjustedStart = statement.FullSpan.End
ElseIf TypeOf containingNode Is MethodBlockBaseSyntax Then
' Something like
' Sub Goo(o as integer)
' [| End Sub |]
adjustedStart = DirectCast(containingNode, MethodBlockBaseSyntax).EndBlockStatement.SpanStart
Else
adjustedStart = containingNode.Span.End
End If
End If
End If
Dim beforeAdjustedStart = GetPreviousStatementBufferAndSpan(adjustedStart, document)
Dim afterAdjustedStart = ContextBuffer.CurrentSnapshot.CreateTrackingSpanFromIndexToEnd(adjustedStart, SpanTrackingMode.EdgePositive)
Return ProjectionBufferFactoryService.CreateProjectionBuffer(
projectionEditResolver:=Nothing,
sourceSpans:={beforeAdjustedStart, debuggerMappedSpan, StatementTerminator, afterAdjustedStart},
options:=ProjectionBufferOptions.None,
contentType:=ContentType)
End Function
Private Shared Function IsRightSideOfLocalDeclaration(containingNode As SyntaxNode) As Boolean
' Right side of a variable declaration but not inside a lambda or query clause
Dim variableDeclarator = containingNode.GetAncestor(Of VariableDeclaratorSyntax)
If variableDeclarator IsNot Nothing Then
Dim methodBase = containingNode.GetAncestor(Of LambdaExpressionSyntax)()
Dim queryClause = containingNode.GetAncestor(Of QueryClauseSyntax)()
If (methodBase Is Nothing OrElse methodBase.DescendantNodes().Contains(variableDeclarator)) AndAlso
(queryClause Is Nothing OrElse queryClause.DescendantNodes().Contains(variableDeclarator)) Then
Dim equalsValueClause = containingNode.GetAncestor(Of EqualsValueSyntax)
Return equalsValueClause.IsChildNode(Of VariableDeclaratorSyntax)(Function(v) v.Initializer)
End If
End If
Return False
End Function
Private Function GetPreviousStatementBufferAndSpan(contextPoint As Integer, document As Document) As ITrackingSpan
' This text can be validly inserted at the end of an expression context to allow
' intellisense to trigger a new expression context
Dim forceExpressionContext = ".__o("
If Not _innerMostContainingNodeIsExpression Then
' We're after some statement, could be a for loop, using block, try block, etc, fake a
' local declaration on the following line
forceExpressionContext = vbCrLf + "Dim __o = "
End If
' Since VB is line-based, we're going to add
Dim previousTrackingSpan = ContextBuffer.CurrentSnapshot.CreateTrackingSpan(Span.FromBounds(0, contextPoint), SpanTrackingMode.EdgeNegative)
Dim buffer = ProjectionBufferFactoryService.CreateProjectionBuffer(
projectionEditResolver:=Nothing,
sourceSpans:={previousTrackingSpan, forceExpressionContext},
options:=ProjectionBufferOptions.None,
contentType:=Me.ContentType)
Return buffer.CurrentSnapshot.CreateTrackingSpan(0, buffer.CurrentSnapshot.Length, SpanTrackingMode.EdgeNegative)
End Function
Public Overrides ReadOnly Property CompletionStartsOnQuestionMark As Boolean
Get
Return True
End Get
End Property
End Class
End Namespace
|