File: TextStructureNavigation\VisualBasicTextStructureNavigatorProvider.vb
Web Access
Project: src\src\EditorFeatures\VisualBasic\Microsoft.CodeAnalysis.VisualBasic.EditorFeatures.vbproj (Microsoft.CodeAnalysis.VisualBasic.EditorFeatures)
' 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.ComponentModel.Composition
Imports Microsoft.CodeAnalysis.Editor.Implementation.TextStructureNavigation
Imports Microsoft.CodeAnalysis.Host.Mef
Imports Microsoft.VisualStudio.Text
Imports Microsoft.VisualStudio.Text.Operations
Imports Microsoft.VisualStudio.Utilities
 
Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.TextStructureNavigation
    <Export(GetType(ITextStructureNavigatorProvider))>
    <ContentType(ContentTypeNames.VisualBasicContentType)>
    Friend NotInheritable Class VisualBasicTextStructureNavigatorProvider
        Inherits AbstractTextStructureNavigatorProvider
 
        <ImportingConstructor()>
        <Obsolete(MefConstruction.ImportingConstructorMessage, True)>
        Public Sub New(
            selectorService As ITextStructureNavigatorSelectorService,
            contentTypeService As IContentTypeRegistryService,
            uiThreadOperationExecutor As IUIThreadOperationExecutor)
            MyBase.New(selectorService, contentTypeService, uiThreadOperationExecutor)
        End Sub
 
        Protected Overrides Function ShouldSelectEntireTriviaFromStart(trivia As SyntaxTrivia) As Boolean
            Return trivia.Kind() = SyntaxKind.CommentTrivia
        End Function
 
        Private Shared Function IsWithinNaturalLanguage(token As SyntaxToken, position As Integer) As Boolean
            Select Case token.Kind
                Case SyntaxKind.StringLiteralToken
                    ' This, in combination with the override of GetExtentOfWordFromToken() below, treats the closing
                    ' quote as a separate token.  This maintains behavior with VS2013.
                    If position = token.Span.End - 1 AndAlso token.Text.EndsWith("""", StringComparison.Ordinal) Then
                        Return False
                    End If
 
                    Return True
 
                Case SyntaxKind.CharacterLiteralToken
                    ' Before the opening quote is considered outside the character
                    If position = token.SpanStart Then
                        Return False
                    End If
 
                    Return True
 
                Case SyntaxKind.InterpolatedStringTextToken,
                     SyntaxKind.XmlTextLiteralToken
                    Return True
            End Select
 
            Return False
        End Function
 
        Protected Overrides Function GetExtentOfWordFromToken(navigator As ITextStructureNavigator, token As SyntaxToken, position As SnapshotPoint) As TextExtent
            If IsWithinNaturalLanguage(token, position) Then
                ' Defer to the editor to determine this.
                Return navigator.GetExtentOfWord(position)
            End If
 
            If token.Kind() = SyntaxKind.StringLiteralToken AndAlso position.Position = token.Span.End - 1 AndAlso token.Text.EndsWith("""", StringComparison.Ordinal) Then
                ' Special case to treat the closing quote of a string literal as a separate token.  This allows the
                ' cursor to stop during word navigation (Ctrl+LeftArrow, etc.) immediately before AND after the
                ' closing quote, just like it did in VS2013 and like it currently does for interpolated strings.
                Dim span = New Span(position.Position, 1)
                Return New TextExtent(New SnapshotSpan(position.Snapshot, Span), isSignificant:=True)
            Else
                Return GetTokenExtent(token, position.Snapshot)
            End If
        End Function
    End Class
End Namespace