有没有办法在文本文件中自动缩进VB.NET代码

Mat*_*lko 8 .net vb.net codedom code-formatting indentation

我想正确缩进文本文件中包含的一些VB.NET代码.有办法做到这一点吗?

例如从这开始:

Public Shared Function CanReachPage(page As String) As Boolean
Try
Using client = New WebClient()
Using stream = client.OpenRead(page)
Return True
End Using
End Using
Catch
Return False
End Try
End Function
Run Code Online (Sandbox Code Playgroud)

完成这个:

Public Shared Function CanReachPage(page As String) As Boolean
    Try
        Using client = New WebClient()
            Using stream = client.OpenRead(page)
                Return True
            End Using
        End Using
    Catch
        Return False
    End Try
End Function
Run Code Online (Sandbox Code Playgroud)

到目前为止,我搜索过的所有内容都引导我使用IndentedTextWriter类,但我发现的唯一示例是手动缩进这样的行:.NET Console TextWriter,它理解缩进/ Unindent/IndentLevel

额外的功劳:如果可能的话,我还想添加正确的间距:

例如Dim i As String="Hello"+"GoodBye" - >Dim i As String = "Hello" + "GoodBye"

Mat*_*lko 0

我决定尝试自己滚动。在某些边缘情况下,这并不能 100% 有效,但它非常可靠:

Public Class VBIndenter

    Private _classIndents As New List(Of Integer)
    Private _moduleIndents As New List(Of Integer)
    Private _subIndents As New List(Of Integer)
    Private _functionIndents As New List(Of Integer)
    Private _propertyIndents As New List(Of Integer)
    Private _structureIndents As New List(Of Integer)
    Private _enumIndents As New List(Of Integer)
    Private _usingIndents As New List(Of Integer)
    Private _withIndents As New List(Of Integer)
    Private _ifIndents As New List(Of Integer)
    Private _tryIndents As New List(Of Integer)
    Private _getIndents As New List(Of Integer)
    Private _setIndents As New List(Of Integer)
    Private _forIndents As New List(Of Integer)
    Private _selectIndents As New List(Of Integer)
    Private _doIndents As New List(Of Integer)
    Private _whileIndents As New List(Of Integer)

    Public Property IndentWidth As Integer = 4
    Public Property IndentChar As Char = " "c

    Public Sub Indent(txt As TextBox)

        Dim lastLabelIndent As Integer = 0
        Dim lastRegionIndent As Integer = 0
        Dim currentIndent As Integer = 0
        Dim inProperty As Boolean = False
        Dim lineText As String
        Dim newLineIndent As Integer
        Dim lines As String() = txt.Lines

        For i As Integer = 0 To lines.Count - 1

            Dim line = lines(i)

            'get the trimmed line without any comments
            lineText = StripComments(line)

            'only change the indent on lines that are code
            If lineText.Length > 0 Then

                'special case for regions and labels - they always have zero indent
                If lineText.StartsWith("#") Then
                    lastRegionIndent = currentIndent
                    currentIndent = 0
                ElseIf lineText.EndsWith(":") Then
                    lastLabelIndent = currentIndent
                    currentIndent = 0
                End If

                'if we are in a property and we see something 
                If (_propertyIndents.Count > 0) Then
                    If Not lineText.StartsWith("End") Then
                        If lineText.StartsWith("Class ") OrElse lineText.Contains(" Class ") Then
                            _propertyIndents.RemoveAt(_propertyIndents.Count - 1)
                            currentIndent -= 1
                        ElseIf lineText.StartsWith("Module ") OrElse lineText.Contains(" Module ") Then
                            _propertyIndents.RemoveAt(_propertyIndents.Count - 1)
                            currentIndent -= 1
                        ElseIf lineText.StartsWith("Sub ") OrElse lineText.Contains(" Sub ") Then
                            _propertyIndents.RemoveAt(_propertyIndents.Count - 1)
                            currentIndent -= 1
                        ElseIf lineText.StartsWith("Function ") OrElse lineText.Contains(" Function ") Then
                            _propertyIndents.RemoveAt(_propertyIndents.Count - 1)
                            currentIndent -= 1
                        ElseIf lineText.StartsWith("Property ") OrElse lineText.Contains(" Property ") Then
                            _propertyIndents.RemoveAt(_propertyIndents.Count - 1)
                            currentIndent -= 1
                        ElseIf lineText.StartsWith("Structure ") OrElse lineText.Contains(" Structure ") Then
                            _propertyIndents.RemoveAt(_propertyIndents.Count - 1)
                            currentIndent -= 1
                        ElseIf lineText.StartsWith("Enum ") OrElse lineText.Contains(" Enum ") Then
                            _propertyIndents.RemoveAt(_propertyIndents.Count - 1)
                            currentIndent -= 1
                        End If
                    Else
                        If lineText = "End Class" Then
                            _propertyIndents.RemoveAt(_propertyIndents.Count - 1)
                        End If
                    End If
                End If

                If lineText = "End Class" Then
                    currentIndent = _classIndents.Item(_classIndents.Count - 1)
                    _classIndents.RemoveAt(_classIndents.Count - 1)
                ElseIf lineText = "End Module" Then
                    currentIndent = _moduleIndents.Item(_moduleIndents.Count - 1)
                    _moduleIndents.RemoveAt(_moduleIndents.Count - 1)
                ElseIf lineText = "End Sub" Then
                    currentIndent = _subIndents.Item(_subIndents.Count - 1)
                    _subIndents.RemoveAt(_subIndents.Count - 1)
                ElseIf lineText = "End Function" Then
                    currentIndent = _functionIndents.Item(_functionIndents.Count - 1)
                    _functionIndents.RemoveAt(_functionIndents.Count - 1)
                ElseIf lineText = "End Property" Then
                    currentIndent = _propertyIndents.Item(_propertyIndents.Count - 1)
                    _propertyIndents.RemoveAt(_propertyIndents.Count - 1)
                ElseIf lineText = "End Try" Then
                    currentIndent = _tryIndents.Item(_tryIndents.Count - 1)
                    _tryIndents.RemoveAt(_tryIndents.Count - 1)
                ElseIf lineText = "End With" Then
                    currentIndent = _withIndents.Item(_withIndents.Count - 1)
                    _withIndents.RemoveAt(_withIndents.Count - 1)
                ElseIf lineText = "End Get" Then
                    currentIndent = _getIndents.Item(_getIndents.Count - 1)
                    _getIndents.RemoveAt(_getIndents.Count - 1)
                ElseIf lineText = "End Set" Then
                    currentIndent = _setIndents.Item(_setIndents.Count - 1)
                    _setIndents.RemoveAt(_setIndents.Count - 1)
                ElseIf lineText = "End If" Then
                    currentIndent = _ifIndents.Item(_ifIndents.Count - 1)
                    _ifIndents.RemoveAt(_ifIndents.Count - 1)
                ElseIf lineText = "End Using" Then
                    currentIndent = _usingIndents.Item(_usingIndents.Count - 1)
                    _usingIndents.RemoveAt(_usingIndents.Count - 1)
                ElseIf lineText = "End Structure" Then
                    currentIndent = _structureIndents.Item(_structureIndents.Count - 1)
                    _structureIndents.RemoveAt(_structureIndents.Count - 1)
                ElseIf lineText = "End Select" Then
                    currentIndent = _selectIndents.Item(_selectIndents.Count - 1)
                    _selectIndents.RemoveAt(_selectIndents.Count - 1)
                ElseIf lineText = "End Enum" Then
                    currentIndent = _enumIndents.Item(_enumIndents.Count - 1)
                    _enumIndents.RemoveAt(_enumIndents.Count - 1)
                ElseIf lineText = "End While" OrElse lineText = "Wend" Then
                    currentIndent = _whileIndents.Item(_whileIndents.Count - 1)
                    _whileIndents.RemoveAt(_whileIndents.Count - 1)
                ElseIf lineText = "Next" OrElse lineText.StartsWith("Next ") Then
                    currentIndent = _forIndents.Item(_forIndents.Count - 1)
                    _forIndents.RemoveAt(_forIndents.Count - 1)
                ElseIf lineText = "Loop" OrElse lineText.StartsWith("Loop ") Then
                    currentIndent = _doIndents.Item(_doIndents.Count - 1)
                    _doIndents.RemoveAt(_doIndents.Count - 1)
                ElseIf lineText.StartsWith("Else") Then
                    currentIndent = _ifIndents.Item(_ifIndents.Count - 1)
                ElseIf lineText.StartsWith("Catch") Then
                    currentIndent = _tryIndents.Item(_tryIndents.Count - 1)
                ElseIf lineText.StartsWith("Case") Then
                    currentIndent = _selectIndents.Item(_selectIndents.Count - 1) + 1
                ElseIf lineText = "Finally" Then
                    currentIndent = _tryIndents.Item(_tryIndents.Count - 1)
                End If

            End If

            'find the current indent
            newLineIndent = currentIndent * Me.IndentWidth
            'change the indent of the current line 
            line = New String(IndentChar, newLineIndent) & line.TrimStart
            lines(i) = line

            If lineText.Length > 0 Then
                If lineText.StartsWith("#") Then
                    currentIndent = lastRegionIndent
                ElseIf lineText.EndsWith(":") Then
                    currentIndent = lastLabelIndent
                End If

                If Not lineText.StartsWith("End") Then
                    If (lineText.StartsWith("Class ") OrElse lineText.Contains(" Class ")) Then
                        _classIndents.Add(currentIndent)
                        currentIndent += 1
                    ElseIf (lineText.StartsWith("Module ") OrElse lineText.Contains(" Module ")) Then
                        _moduleIndents.Add(currentIndent)
                        currentIndent += 1
                    ElseIf (lineText.StartsWith("Sub ") OrElse lineText.Contains(" Sub ")) Then
                        _subIndents.Add(currentIndent)
                        currentIndent += 1
                    ElseIf (lineText.StartsWith("Function ") OrElse lineText.Contains(" Function ")) Then
                        _functionIndents.Add(currentIndent)
                        currentIndent += 1
                    ElseIf (lineText.StartsWith("Property ") OrElse lineText.Contains(" Property ")) Then
                        _propertyIndents.Add(currentIndent)
                        currentIndent += 1
                    ElseIf (lineText.StartsWith("Structure ") OrElse lineText.Contains(" Structure ")) Then
                        _structureIndents.Add(currentIndent)
                        currentIndent += 1
                    ElseIf (lineText.StartsWith("Enum ") OrElse lineText.Contains(" Enum ")) Then
                        _enumIndents.Add(currentIndent)
                        currentIndent += 1
                    ElseIf lineText.Contains("Using ") Then
                        _usingIndents.Add(currentIndent)
                        currentIndent += 1
                    ElseIf lineText.StartsWith("Select Case") Then
                        _selectIndents.Add(currentIndent)
                        currentIndent += 1
                    ElseIf lineText = "Try" Then
                        _tryIndents.Add(currentIndent)
                        currentIndent += 1
                    ElseIf lineText = "Get" Then
                        _getIndents.Add(currentIndent)
                        currentIndent += 1
                    ElseIf lineText.StartsWith("Set") AndAlso Not lineText.Contains("=") Then
                        _setIndents.Add(currentIndent)
                        currentIndent += 1
                    ElseIf lineText.StartsWith("With") Then
                        _withIndents.Add(currentIndent)
                        currentIndent += 1
                    ElseIf lineText.StartsWith("If") AndAlso lineText.EndsWith("Then") Then
                        _ifIndents.Add(currentIndent)
                        currentIndent += 1
                    ElseIf lineText.StartsWith("For") Then
                        _forIndents.Add(currentIndent)
                        currentIndent += 1
                    ElseIf lineText.StartsWith("While") Then
                        _whileIndents.Add(currentIndent)
                        currentIndent += 1
                    ElseIf lineText.StartsWith("Do") Then
                        _doIndents.Add(currentIndent)
                        currentIndent += 1
                    ElseIf lineText.StartsWith("Case") Then
                        currentIndent += 1
                    ElseIf lineText.StartsWith("Else") Then
                        currentIndent = _ifIndents.Item(_ifIndents.Count - 1) + 1
                    ElseIf lineText.StartsWith("Catch") Then
                        currentIndent = _tryIndents.Item(_tryIndents.Count - 1) + 1
                    ElseIf lineText = "Finally" Then
                        currentIndent = _tryIndents.Item(_tryIndents.Count - 1) + 1
                    End If
                End If
            End If
        Next
        'update the textbox
        txt.Lines = lines
    End Sub

    Private Function StripComments(ByVal code As String) As String
        If code.IndexOf("'"c) >= 0 Then
            code = code.Substring(0, code.IndexOf("'"c))
        End If
        Return code.Trim
    End Function
End Class
Run Code Online (Sandbox Code Playgroud)

用法:

将一些代码放入 TextBox ( TextBox1) 中,然后像这样调用压头:

Dim id As New VBIndenter
id.Indent(TextBox1)
Run Code Online (Sandbox Code Playgroud)