VisualBasicContainedLanguage.vb 10.3 KB
Newer Older
S
Sam Harwell 已提交
1
' Copyright (c) Microsoft.  All Rights Reserved.  Licensed under the Apache License, Version 2.0.  See License.txt in the project root for license information.
2 3 4 5 6 7 8 9 10 11

Imports Microsoft.CodeAnalysis
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.Options
Imports Microsoft.CodeAnalysis.VisualBasic
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Imports Microsoft.VisualStudio.ComponentModelHost
12
Imports Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem
13 14 15 16 17 18 19 20
Imports Microsoft.VisualStudio.LanguageServices.Implementation.Venus
Imports Microsoft.VisualStudio.Shell.Interop
Imports IVsTextBufferCoordinator = Microsoft.VisualStudio.TextManager.Interop.IVsTextBufferCoordinator
Imports VsTextSpan = Microsoft.VisualStudio.TextManager.Interop.TextSpan

Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Venus

    Friend Class VisualBasicContainedLanguage
C
CyrusNajmabadi 已提交
21
        Inherits ContainedLanguage(Of VisualBasicPackage, VisualBasicLanguageService)
22 23
        Implements IVsContainedLanguageStaticEventBinding

B
beep boop 已提交
24
        Public Sub New(bufferCoordinator As IVsTextBufferCoordinator,
25
                componentModel As IComponentModel,
26
                project As VisualStudioProject,
27 28 29 30
                hierarchy As IVsHierarchy,
                itemid As UInteger,
                languageService As VisualBasicLanguageService,
                sourceCodeKind As SourceCodeKind)
31
            MyBase.New(bufferCoordinator, componentModel, project, hierarchy, itemid, projectTrackerOpt:=Nothing, project.Id, languageService, VisualBasicHelperFormattingRule.Instance)
32 33 34 35 36 37 38
        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 IWaitIndicator)().Wait(
39
                BasicVSResources.IntelliSense,
40 41
                allowCancel:=False,
                action:=Sub(c)
42
                            Dim visualStudioWorkspace = ComponentModel.GetService(Of VisualStudioWorkspace)()
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
                            Dim document = GetThisDocument()
                            ContainedLanguageStaticEventBinding.AddStaticEventBinding(
                                document, visualStudioWorkspace, pszClassName, pszUniqueMemberID, pszObjectName, pszNameOfEvent, c.CancellationToken)
                        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,
77
                additionalFormattingRule:=New LineAdjustmentFormattingRule(),
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
                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 IWaitIndicator)().Wait(
94
                BasicVSResources.IntelliSense,
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
                allowCancel:=False,
                action:=Sub(c)
                            Dim eventNamesAndMemberNamesAndIds = ContainedLanguageStaticEventBinding.GetStaticEventBindings(
                                GetThisDocument(), pszClassName, pszObjectName, c.CancellationToken)
                            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 IWaitIndicator)().Wait(
115
                BasicVSResources.IntelliSense,
116 117
                allowCancel:=False,
                action:=Sub(c)
118
                            Dim visualStudioWorkspace = ComponentModel.GetService(Of VisualStudioWorkspace)()
119 120 121 122 123 124 125 126 127 128 129 130 131
                            Dim document = GetThisDocument()
                            ContainedLanguageStaticEventBinding.RemoveStaticEventBinding(
                                document, visualStudioWorkspace, pszClassName, pszUniqueMemberID, pszObjectName, pszNameOfEvent, c.CancellationToken)
                        End Sub)
            Return VSConstants.S_OK
        End Function

        Private Class VisualBasicHelperFormattingRule
            Inherits AbstractFormattingRule

            Public Shared Shadows Instance As IFormattingRule = New VisualBasicHelperFormattingRule()

            Public Overrides Sub AddIndentBlockOperations(list As List(Of IndentBlockOperation), node As SyntaxNode, optionSet As OptionSet, nextOperation As NextAction(Of IndentBlockOperation))
132
                ' we need special behavior for VB due to @Helper code generation weird-ness.
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
                ' 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.AddIndentBlockOperations(list, node, optionSet, 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