-
Notifications
You must be signed in to change notification settings - Fork 4k
/
AutomaticLineEnderCommandHandler.vb
110 lines (89 loc) · 5.1 KB
/
AutomaticLineEnderCommandHandler.vb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
Imports System.ComponentModel.Composition
Imports System.Threading
Imports Microsoft.CodeAnalysis
Imports Microsoft.CodeAnalysis.Editor.Implementation.AutomaticCompletion
Imports Microsoft.CodeAnalysis.Text
Imports Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion
Imports Microsoft.VisualStudio.Text.Operations
Imports Microsoft.VisualStudio.Utilities
Imports VSCommanding = Microsoft.VisualStudio.Commanding
Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.AutomaticCompletion
' <summary>
' visual basic automatic line ender command handler
' </summary>
<Export(GetType(VSCommanding.ICommandHandler))>
<ContentType(ContentTypeNames.VisualBasicContentType)>
<Name(PredefinedCommandHandlerNames.AutomaticLineEnder)>
<Order(Before:=PredefinedCommandHandlerNames.Completion)>
<Order(Before:=PredefinedCompletionNames.CompletionCommandHandler)>
Friend Class AutomaticLineEnderCommandHandler
Inherits AbstractAutomaticLineEnderCommandHandler
<ImportingConstructor>
Friend Sub New(undoRegistry As ITextUndoHistoryRegistry,
editorOperations As IEditorOperationsFactoryService,
asyncCompletionBroker As IAsyncCompletionBroker)
MyBase.New(undoRegistry, editorOperations, asyncCompletionBroker)
End Sub
Protected Overrides Sub NextAction(editorOperation As IEditorOperations, nextAction As Action)
' let the next action run
nextAction()
End Sub
Protected Overrides Function TreatAsReturn(document As Document, position As Integer, cancellationToken As CancellationToken) As Boolean
' No special handling in VB.
Return False
End Function
Protected Overrides Sub FormatAndApply(document As Document, position As Integer, cancellationToken As CancellationToken)
' vb does automatic line commit
' no need to do explicit formatting
End Sub
Protected Overrides Function GetEndingString(document As Document, position As Integer, cancellationToken As CancellationToken) As String
' prepare expansive information from document
Dim root = document.GetSyntaxRootSynchronously(cancellationToken)
Dim text = root.SyntaxTree.GetText(cancellationToken)
' get line where the caret is on
Dim line = text.Lines.GetLineFromPosition(position)
' find line break token if there is one
Dim lastToken = CType(root.FindTokenOnLeftOfPosition(line.End, includeSkipped:=False), SyntaxToken)
lastToken = If(lastToken.Kind = SyntaxKind.EndOfFileToken, lastToken.GetPreviousToken(includeZeroWidth:=True), lastToken)
' find last token of the line
If lastToken.Kind = SyntaxKind.None OrElse line.End < lastToken.Span.End Then
Return Nothing
End If
' properly ended
If Not lastToken.IsMissing AndAlso lastToken.IsLastTokenOfStatementWithEndOfLine() Then
Return Nothing
End If
' so far so good. check whether we need to add explicit line continuation here
Dim nonMissingToken = If(lastToken.IsMissing, lastToken.GetPreviousToken(), lastToken)
' now we have the last token, check whether it is at a valid location
If (line.Span.Contains(nonMissingToken.Span.End)) Then
' make sure that there is no trailing text after last token on the line if it is not at the end of the line
Dim endingString = text.ToString(TextSpan.FromBounds(nonMissingToken.Span.End, line.End))
If Not String.IsNullOrWhiteSpace(endingString) Then
Return Nothing
End If
End If
' check whether implicit line continuation is allowed
If SyntaxFacts.AllowsTrailingImplicitLineContinuation(CType(nonMissingToken, SyntaxToken)) Then
Return Nothing
End If
Dim nextToken = nonMissingToken.GetNextToken(includeZeroWidth:=True)
' if there is skipped token between previous and next token, don't do anything
If nonMissingToken.TrailingTrivia.Concat(nextToken.LeadingTrivia).Any(AddressOf HasSkippedText) Then
Return Nothing
End If
If nextToken.IsLastTokenOfStatementWithEndOfLine() Then
Return " _"
End If
Dim nextNonMissingToken = nextToken.GetNextNonZeroWidthTokenOrEndOfFile()
If nextNonMissingToken.Kind = SyntaxKind.EndOfFileToken Then
Return Nothing
End If
Return If(SyntaxFacts.AllowsLeadingImplicitLineContinuation(CType(nextToken, SyntaxToken)), Nothing, " _")
End Function
Private Shared Function HasSkippedText(trivia As SyntaxTrivia) As Boolean
Return trivia.Kind = SyntaxKind.SkippedTokensTrivia
End Function
End Class
End Namespace