Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Comment/Uncomment Macro and more

0.00/5 (No votes)
18 May 2002 1  
Useful Visual Studio macros to simplify commenting code

Comment/Un-comment Macro Comment/Un-comment Macro

The macros presented here act as a comment "toggle". With a single keystroke, it will add comment text to the selected code or it will remove the comment if already present. It correctly handles selected words, single lines or multiple selected lines. It also handles several special cases. All editing is performed in memory so that the editor can provide a single "undo" for the operation. This macro has proved useful for many programmers and can greatly simplify the common, tedious programming task of enabling or disabling blocks of code.

Overview and Requirements

Providing useful comments in your source code is very important for understanding the code and for future maintenance. Comments are also useful during development to enable or disable code that is being tested. The basic act of editing text to enter or remove comments can be tedious. This is especially true if you have a large quantity of lines to comment or you have to deal with embedded /* */ style comments. My solution to simplify entering comments is to let the editor do most of the work. The editor does not provide this functionality (probably because it would have to enforce a particular style). We can easily add this functionality with a few macros.

Adding comments to code is somewhat dependent on the programmer's preferred coding style. Naturally my macro adheres to my preferred style, but the style choices also have practical advantages. In general, I prefer // style comments. Here is the required functionality I desired from the macro:

  • Comment based upon the current selection
  • Assignable to a single keystroke
  • Should "toggle", e.g. add or remove a comment depending on the presence of a comment
  • Not break due to the presence of existing comments
  • Handle single lines and multiple lines
  • Comment selected words
  • Allow the user to "undo" the comment/un-comment action

Finally, there is a special case editing action I find myself performing frequently. I often add a comment at the end of the line explaining what the line does. Over time, perhaps, this single line of code expands to multiple lines or deserves better white space separation, so I move the comment above the line. I have provided a macro that toggles between each comment location.

Installation

Install the macro by unzipping the solesby.dsm file to a desired location. Choose the Tools->Macros menu option, expand the dialog with the Options button, and then load the macro file. You may need to use the Browse button if you save the file outside your Visual Studio macro directory.

You will also want to map the macro to a key to make it useful. I map the CustomCommentOut macro to the keystroke control-/. This combination is not used in the default Visual Studio configuration and is also intuitive for C/C++ programmers. I then map the CommentLineToggle macro to the keystroke control-shift-/.

Details of Operation

The macro behaves differently under different conditions. The operation is determined by the current selection as well as the text itself. If the text has already been commented, then the macro will remove the comments. If it has not been commented, comments will be added. The selection determines the style of comments used. Hopefully the varying operations will be intuitive, but each is demonstrated below.

Single Line Selection

Commenting a single line

The most basic operation is commenting a single line. This situation is identified by the lack of a selection (i.e. the cursor is on the desired line without any words selected). "//" style comments are added preserving the current indentation. Comments are removed from either the beginning of the line or the beginning of the indented text.

Multiple Line Selection

Commenting a single line

When multiple lines are selected, "//" style comments are placed at the beginning of the line. This style of comment is useful for commenting out a large block of text. "//" style comments are used instead of "/* */" style comments so that embedded comments do not produce errors.

Commenting a single line

The macro's decision to add or remove comments is based on the last line of the selection rather than the first. This allows you to easily comment out a logical block of code, which often has a comment on the line preceding it. When you remove the comment, the documentation comment(s) will remain intact.

Word Selection

Commenting a single line

If text is selected within a single line, then the assumption is that you wish to control comments for the selected text. "/* */" style comments are added surrounding the selected text. If the selection has already been commented, the comments are removed. The selection of commented text can include the comments or just the text within the comments.

End-of-line Comments

Commenting a single line

This macro moves comments from the end of the line to the line above and vice versa. This is a separate macro and should be assigned to a different keystroke (e.g. control-shift-/).

Code for Macros

CustomCommentOut

Here is the key part of the comment macro. Note: this code is dependent on other functions and has older methods also present. You should download the file instead of copying this sample code directly.

'----------------------------------------------------------------------------------

' This will comment/uncomment out single lines or blocks. Single lines are commented

' with the same indention level. Blocks are commented at the beginning of the line.

' Assign this to a key (e.g. ctrl-/) and it will toggle the current line/block of code.

' This will handle both "//" and "'" style comments

'----------------------------------------------------------------------------------


Sub CustomCommentOut ()
'DESCRIPTION: Comments out a selected block of text. (ctrl-/)

'             [ by Adam Solesby -- http://solesby.com ]

    Dim win
    set win = ActiveWindow
    If win.type <> "Text" Then
      MsgBox "This macro can only be run when a text editor window is active."
    Else
        TypeOfFile = FileType(ActiveDocument)
        '    MsgBox "Type: " + CStr(TypeOfFile)

        If TypeOfFile > 0 And TypeOfFile < 6 Then
            If TypeOfFile > 3 Then
                CommentType = "'"    ' VB

                CommentWidth = 1
            Else
                CommentType = "//"    ' C++ and java style comments


                CommentWidth = 2
            End If

            StartLine = ActiveDocument.Selection.TopLine
            EndLine = ActiveDocument.Selection.BottomLine
            If EndLine < StartLine Then
                Temp = StartLine
                StartLine = EndLine
                EndLine = Temp
            End If

            ' single line with words selected

            If EndLine = StartLine And Len(ActiveDocument.Selection) > 0 Then
                s = ActiveDocument.Selection.Text
                n = Len(ActiveDocument.Selection)

                ' convert "/*sample text*/" => "sample text" ("/*sample text*/" selected)

                If left(s,2) = "/*" and Right(s,2) = "*/" Then
                    ActiveDocument.Selection = Mid(s,3,n-4)
                Else

                    ActiveDocument.Selection.CharLeft
                    ActiveDocument.Selection.CharLeft dsMove, 2
                    ActiveDocument.Selection.CharRight dsExtend, n + 4
                    s2 = ActiveDocument.Selection.Text

                    ' convert "/*sample text*/" => "sample text" ("sample text" selected)

                    If left(s2,2) = "/*" and Right(s2,2) = "*/" Then
                        ActiveDocument.Selection = s

                    ' convert "sample text" => "/*sample text*/" ("sample text" selected)

                    Else
                        ActiveDocument.Selection.CharLeft
                        ActiveDocument.Selection.CharRight dsMove, 2
                        ActiveDocument.Selection.CharRight dsExtend, n
                        ActiveDocument.Selection = "/*" & s & "*/"
                    End If

                End If

            ' Single line -- comment at start of text

            '   have to check for comments at start of line and start of text

            ElseIf EndLine = StartLine Then

                ActiveDocument.Selection.StartOfLine dsFirstColumn
                ActiveDocument.Selection.CharRight dsExtend, CommentWidth

                If ActiveDocument.Selection = CommentType Then
                    ActiveDocument.Selection.Delete
                Else
                    ActiveDocument.Selection.StartOfLine dsFirstText
                    ActiveDocument.Selection.CharRight dsExtend, CommentWidth

                    If ActiveDocument.Selection = CommentType Then

                        ActiveDocument.Selection.CharLeft
                        ActiveDocument.Selection.EndOfLine dsExtend
                        s = ActiveDocument.Selection.Text
                        s = LTrim( Mid ( s, 3 ) )

                        Do While Left(s,1) = vbTab
                            s = LTrim( Mid( s, 2 ) )
                        Loop

                        ActiveDocument.Selection = s

                    Else
                        ActiveDocument.Selection.StartOfLine dsFirstText
                        ActiveDocument.Selection = CommentType + vbTab + ActiveDocument.Selection
                    End If
                End If
                ActiveDocument.Selection.StartOfLine dsFirstText

            ' Multi-line -- comment at start of line

            Else
                CommentLoc = dsFirstColumn ' or dsFirstText if you prefer


                ' check whether commenting on or off based on the _last_ line of selection

                ActiveDocument.Selection.GoToLine EndLine
                ActiveDocument.Selection.StartOfLine CommentLoc
                ActiveDocument.Selection.CharRight dsExtend, CommentWidth
                If ActiveDocument.Selection = CommentType Then
                    bAddComment = False
                Else
                    bAddComment = True
                End If

                ' work with strings so that we can do a single undo in editor

                ActiveDocument.Selection.MoveTo StartLine, 1
                ActiveDocument.Selection.MoveTo EndLine, dsEndOfLine, dsExtend
                s = ActiveDocument.Selection.Text

                If bAddComment Then
                    s = CommentType & Replace( s, vbNewLine , vbNewLine & CommentType )
                Else
                    s = Replace( s, vbNewLine & CommentType, vbNewLine )
                    s = Mid( s, Len(CommentType)+1 )
                End If

                ActiveDocument.Selection = s


            End If
        Else
            MsgBox("Unable to comment out the highlighted text" + vbLf + _
                "because the file type was unrecognized." + vbLf + _
                "If the file has not yet been saved, " + vbLf + _
                "please save it and try again.")
        End If
    End If
End Sub

CommentLineToggle

Below is the implementation for the end-of-line comment toggle.

'----------------------------------------------------------------------------------

' This function toggles between end-of-line comments and line-before comment

'

'    // comment here

'    void function();         <==>       void function(); // comment here

'

'----------------------------------------------------------------------------------

Sub CommentLineToggle()
'DESCRIPTION: This toggles between end-of-line comments and line-before comment (ctrl-shift-/)

'             [ by Adam Solesby -- http://solesby.com ]


    StartLine   = ActiveDocument.Selection.TopLine
    EndLine     = ActiveDocument.Selection.BottomLine
    StartColumn = ActiveDocument.Selection.CurrentColumn

    If StartLine <> EndLine Then Exit Sub

    ActiveDocument.Selection.StartOfLine dsFirstText
    ActiveDocument.Selection.CharRight dsExtend, 2

    ' Check for comment-only line

    If ActiveDocument.Selection = "//" Then

        ' Found a previous-line comment, e.g.:

        '     // this is a comment above the line

        '    void function();


        ' cut and paste on line below

        ActiveDocument.Selection.SelectLine
        ActiveDocument.Selection.Cut
        ActiveDocument.Selection.EndOfLine
        ActiveDocument.Selection.Paste
        ActiveDocument.Selection.Backspace
        bFound = ActiveDocument.Selection.FindText("//", dsMatchBackward)
        If bFound Then
            ActiveDocument.Selection.CharLeft
            ActiveDocument.Selection.DeleteWhitespace dsHorizontal
            ActiveDocument.Selection = " "
        End If

    Else
        ActiveDocument.Selection.EndOfLine
        ActiveDocument.Selection.SelectLine
        bFound = ActiveDocument.Selection.FindText("//", dsMatchBackward)

        If bFound Then

            ' Found an end-of-line comment, e.g.:

            '     void function() // this is a comment

            If StartLine = ActiveDocument.Selection.CurrentLine Then

                ' cut and paste on line above

                ActiveDocument.Selection.CharLeft
                ActiveDocument.Selection.NewLine
                ActiveDocument.Selection.DeleteWhitespace dsHorizontal
                ActiveDocument.Selection.LineDown dsExtend
                ActiveDocument.Selection.Cut
                ActiveDocument.Selection.LineUp
                ActiveDocument.Selection.Paste
                ActiveDocument.Selection.WordRight dsExtend
                ActiveDocument.Selection.Copy
                ActiveDocument.Selection.LineUp
                ActiveDocument.Selection.StartOfLine dsFirstColumn
                ActiveDocument.Selection.Paste

            Else
                ActiveDocument.Selection.MoveTo StartLine, StartColumn
            End If
        End If
    End If
End Sub

History

Quite a while ago I posted early versions of some of my Visual Studio macros. The most useful and popular of these macros was one that could toggle comments for a single line or multiple lines of code. Since then I have received several suggestions from users of the code as well as enhanced the macros for my own purposes. This article presents the new and improved macros. It also provides a little more explanation that will hopefully let more people see how they might be able to use them. Thank you to all who have sent suggestions.

The original macro simply looped through each line and toggled the comment for the line. This had several disadvantages: (a) If you tried to "undo" the action, you would simply undo the last line affected. Undoing the action on many lines was annoying. (b) Each line was toggled individually. This could leave a mix of commented and un-commented lines.

As described above, the macro now performs the text operation on a string in memory and only provides a single editor selection update. This allows the entire comment toggle operation to be undone. Also the decision to comment or un-comment is based on the block (actually the last line of the block) and performs the same operation on every line in the selection. Finally, several users requested the handling of selected words using /* */ style comments.

For more information, please visit my website: http://www.solesby.com

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here