File: Venus\VisualBasicContainedLanguage.vb
Web Access
Project: src\src\VisualStudio\VisualBasic\Impl\Microsoft.VisualStudio.LanguageServices.VisualBasic.vbproj (Microsoft.VisualStudio.LanguageServices.VisualBasic)
' 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 Microsoft.CodeAnalysis
Imports Microsoft.CodeAnalysis.Diagnostics
Imports Microsoft.CodeAnalysis.Editor.Host
Imports Microsoft.CodeAnalysis.Editor.Shared.Extensions
Imports Microsoft.CodeAnalysis.Editor.VisualBasic.Utilities
Imports Microsoft.CodeAnalysis.Formatting.Rules
Imports Microsoft.CodeAnalysis.VisualBasic
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Imports Microsoft.CodeAnalysis.Workspaces.ProjectSystem
Imports Microsoft.VisualStudio.ComponentModelHost
Imports Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem
Imports Microsoft.VisualStudio.LanguageServices.Implementation.Venus
Imports Microsoft.VisualStudio.Shell.Interop
Imports Microsoft.VisualStudio.Utilities
Imports IVsTextBufferCoordinator = Microsoft.VisualStudio.TextManager.Interop.IVsTextBufferCoordinator
Imports VsTextSpan = Microsoft.VisualStudio.TextManager.Interop.TextSpan
 
Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Venus
    Friend Class VisualBasicContainedLanguage
        Inherits ContainedLanguage
        Implements IVsContainedLanguageStaticEventBinding
 
        <Obsolete("Use the constructor that omits the IVsHierarchy and UInteger parameters instead.", True)>
        Public Sub New(bufferCoordinator As IVsTextBufferCoordinator,
                componentModel As IComponentModel,
                project As ProjectSystemProject,
                hierarchy As IVsHierarchy,
                itemid As UInteger,
                languageServiceGuid As Guid)
 
            Me.New(
                bufferCoordinator,
                componentModel,
                project,
                languageServiceGuid)
        End Sub
 
        Public Sub New(bufferCoordinator As IVsTextBufferCoordinator,
                componentModel As IComponentModel,
                project As ProjectSystemProject,
                languageServiceGuid As Guid)
 
            MyBase.New(
                bufferCoordinator,
                componentModel,
                componentModel.GetService(Of VisualStudioWorkspace)(),
                project.Id,
                project,
                languageServiceGuid,
                VisualBasicHelperFormattingRule.Instance)
        End Sub
 
        Public Function AddStaticEventBinding(pszClassName As String,
                                              pszUniqueMemberID As String,
                                              pszObjectName As String,
                                              pszNameOfEvent As String) As Integer Implements IVsContainedLanguageStaticEventBinding.AddStaticEventBinding
            Me.ComponentModel.GetService(Of IUIThreadOperationExecutor)().Execute(
                EditorFeaturesResources.IntelliSense,
                defaultDescription:="",
                allowCancellation:=False,
                showProgress:=False,
                action:=Sub(c)
                            Dim visualStudioWorkspace = ComponentModel.GetService(Of VisualStudioWorkspace)()
                            Dim document = GetThisDocument()
                            ContainedLanguageStaticEventBinding.AddStaticEventBinding(
                                document, visualStudioWorkspace, pszClassName, pszUniqueMemberID, pszObjectName, pszNameOfEvent, c.UserCancellationToken)
                        End Sub)
            Return VSConstants.S_OK
        End Function
 
        Public Function EnsureStaticEventHandler(pszClassName As String,
                                                 pszObjectTypeName As String,
                                                 pszObjectName As String,
                                                 pszNameOfEvent As String,
                                                 pszEventHandlerName As String,
                                                 itemidInsertionPoint As UInteger,
                                                 ByRef pbstrUniqueMemberID As String,
                                                 ByRef pbstrEventBody As String,
                                                 pSpanInsertionPoint() As VsTextSpan) As Integer Implements IVsContainedLanguageStaticEventBinding.EnsureStaticEventHandler
 
            Dim thisDocument = GetThisDocument()
            Dim targetDocumentId = Me.ContainedDocument.FindProjectDocumentIdWithItemId(itemidInsertionPoint)
            Dim targetDocument = thisDocument.Project.Solution.GetDocument(targetDocumentId)
            If targetDocument Is Nothing Then
                Throw New InvalidOperationException("Can't generate into that itemid")
            End If
 
            Dim idBodyAndInsertionPoint = ContainedLanguageCodeSupport.EnsureEventHandler(
                thisDocument,
                targetDocument,
                pszClassName,
                pszObjectName,
                pszObjectTypeName,
                pszNameOfEvent,
                pszEventHandlerName,
                itemidInsertionPoint,
                useHandlesClause:=True,
                additionalFormattingRule:=LineAdjustmentFormattingRule.Instance,
                cancellationToken:=Nothing)
 
            pbstrUniqueMemberID = idBodyAndInsertionPoint.Item1
            pbstrEventBody = idBodyAndInsertionPoint.Item2
            pSpanInsertionPoint(0) = idBodyAndInsertionPoint.Item3
            Return VSConstants.S_OK
        End Function
 
        Public Function GetStaticEventBindingsForObject(pszClassName As String,
                                                        pszObjectName As String,
                                                        ByRef pcMembers As Integer,
                                                        ppbstrEventNames As IntPtr,
                                                        ppbstrDisplayNames As IntPtr,
                                                        ppbstrMemberIDs As IntPtr) As Integer Implements IVsContainedLanguageStaticEventBinding.GetStaticEventBindingsForObject
            Dim members As Integer
            Me.ComponentModel.GetService(Of IUIThreadOperationExecutor)().Execute(
                EditorFeaturesResources.IntelliSense,
                defaultDescription:="",
                allowCancellation:=False,
                showProgress:=Nothing,
                action:=Sub(c)
                            Dim eventNamesAndMemberNamesAndIds = ContainedLanguageStaticEventBinding.GetStaticEventBindings(
                                GetThisDocument(), pszClassName, pszObjectName, c.UserCancellationToken)
                            members = eventNamesAndMemberNamesAndIds.Count()
                            CreateBSTRArray(ppbstrEventNames, eventNamesAndMemberNamesAndIds.Select(Function(e) e.Item1))
                            CreateBSTRArray(ppbstrDisplayNames, eventNamesAndMemberNamesAndIds.Select(Function(e) e.Item2))
                            CreateBSTRArray(ppbstrMemberIDs, eventNamesAndMemberNamesAndIds.Select(Function(e) e.Item3))
                        End Sub)
 
            pcMembers = members
            Return VSConstants.S_OK
        End Function
 
        Public Function RemoveStaticEventBinding(pszClassName As String,
                                                 pszUniqueMemberID As String,
                                                 pszObjectName As String,
                                                 pszNameOfEvent As String) As Integer Implements IVsContainedLanguageStaticEventBinding.RemoveStaticEventBinding
 
            Me.ComponentModel.GetService(Of IUIThreadOperationExecutor)().Execute(
                EditorFeaturesResources.IntelliSense,
                defaultDescription:="",
                allowCancellation:=False,
                showProgress:=Nothing,
                action:=Sub(c)
                            Dim visualStudioWorkspace = ComponentModel.GetService(Of VisualStudioWorkspace)()
                            Dim document = GetThisDocument()
                            ContainedLanguageStaticEventBinding.RemoveStaticEventBinding(
                                document, visualStudioWorkspace, pszClassName, pszUniqueMemberID, pszObjectName, pszNameOfEvent, c.UserCancellationToken)
                        End Sub)
            Return VSConstants.S_OK
        End Function
 
        Private Class VisualBasicHelperFormattingRule
            Inherits CompatAbstractFormattingRule
 
            Public Shared Shadows Instance As AbstractFormattingRule = New VisualBasicHelperFormattingRule()
 
            Public Overrides Sub AddIndentBlockOperationsSlow(list As List(Of IndentBlockOperation), node As SyntaxNode, ByRef nextOperation As NextIndentBlockOperationAction)
                ' we need special behavior for VB due to @Helper code generation weird-ness.
                ' this will looking for code gen specific style to make it not so expansive
                If IsEndHelperPattern(node) Then
                    Return
                End If
 
                Dim multiLineLambda = TryCast(node, MultiLineLambdaExpressionSyntax)
                If multiLineLambda IsNot Nothing AndAlso IsHelperSubLambda(multiLineLambda) Then
                    Return
                End If
 
                MyBase.AddIndentBlockOperationsSlow(list, node, nextOperation)
            End Sub
 
            Private Shared Function IsHelperSubLambda(multiLineLambda As MultiLineLambdaExpressionSyntax) As Boolean
                If multiLineLambda.Kind <> SyntaxKind.MultiLineSubLambdaExpression Then
                    Return False
                End If
 
                If multiLineLambda.SubOrFunctionHeader Is Nothing OrElse
                   multiLineLambda.SubOrFunctionHeader.ParameterList Is Nothing OrElse
                   multiLineLambda.SubOrFunctionHeader.ParameterList.Parameters.Count <> 1 OrElse
                   multiLineLambda.SubOrFunctionHeader.ParameterList.Parameters(0).Identifier.Identifier.Text <> "__razor_helper_writer" Then
                    Return False
                End If
 
                Return True
            End Function
 
            Private Shared Function IsEndHelperPattern(node As SyntaxNode) As Boolean
                If Not node.HasStructuredTrivia Then
                    Return False
                End If
 
                Dim method = TryCast(node, MethodBlockSyntax)
                If method Is Nothing OrElse method.Statements.Count <> 2 Then
                    Return False
                End If
 
                Dim statementWithEndHelper = method.Statements(0)
                Dim endToken = statementWithEndHelper.GetFirstToken()
                If endToken.Kind <> SyntaxKind.EndKeyword Then
                    Return False
                End If
 
                Dim helperToken = endToken.GetNextToken(includeSkipped:=True)
                If helperToken.Kind <> SyntaxKind.IdentifierToken OrElse
                   Not String.Equals(helperToken.Text, "Helper", StringComparison.OrdinalIgnoreCase) Then
                    Return False
                End If
 
                Dim asToken = helperToken.GetNextToken(includeSkipped:=True)
                If asToken.Kind <> SyntaxKind.AsKeyword Then
                    Return False
                End If
 
                Return True
            End Function
        End Class
    End Class
End Namespace