DOxygen and Dev Studio
So, with a little more time on my hands, I've been working on some portfolio stuff. For me, this means coding. Now at work, I had a handily little macro that I had scavenged together that added DOxygen comments to my code (bound to a keypress). Unfortunately, I left all that at work (and I don't have it backed up anywhere).
I've also had some time to play around with some CSS and jScript from Google code. This is pretty neat: http://code.google.com/p/syntaxhighlighter/ and it was very easy to add to this blog. It supports a variety of languages and looks awesome. I recommend you try it!
So, this was an excellent opportunity for me to create a new one and post it here. As well, I can discuss some of the things I ran into along my way.
It's pretty simple how I went about developing this set of macros. First off, I wanted one 'entry' function for determining what kind of comment I was making. This was pretty simple, and the method I used for determining if I'm commenting the top of a file, a class, a method or a function is pretty straightforward (potentially not the best, but I'll juice that up as time goes on). I boil it down to this:
a) if the current line is line zero, it's a file header comment.
b) if the current line contains a 'class' keyword, we're documenting a class
c) if the current line contains a '::', we're documenting a method
d) if the next line has a '{', it's a function
Like I said, it's pretty simple (read: stupid) but I'll enhance it later.
After that, it's just a matter of populating the comments with the right data.
Now, I did run into an interesting problem (which is where the majority of my day went). One thing I wanted to do was process all my method parameters and generate documentation for them. So, the process for that went like this:
1) generate an 'arguments' string. This is essentially everything between the '(' and ')'. This is a little problematic, because I need to deal with parameters that are spread across multiple lines. This was pretty easy to do. Then came stripping out the unnecessary characters (left and right trimming the '(' and ')' characters). I figured that I could do a string replace for all '(' and ')' characters with a space. Then use the Trim function in vb to strip out what I didn't want. However, I noticed that I was still having spaces at the end of my string. Or at least what I thought was spaces. It took a while for me to realize that they were non-printable characters ( specifically, there was a carriage return embedded before my ')' ... which wasn't in the source file). Anyway, there's a host of other reasons why I'd want to get rid of additional characters in my argument list, so I built a function that trimmed out additional 'fluff' characters, including tabs, line feeds, carriage returns and a few other non-printable characters). And then Trimmed the results. The code looks like this:
First, creating the argument string:
Second, the TrimAll function:
2) tokenize the arguments. VB has a 'split' function that breaks a string up into a string array based on a delimiter character. So, to break it down into arguments, it's a matter of splitting on a ',' character. After this, use VB's 'For Each' iterator to walk over the array of arguments and then tokenize each argument into another string array to get a list of types and variables. Simply grabbing the last array element gives me my variable name, which I can then print out.
OK. So after all that, here's the full code listing. Copy and paste into a new module. You'll probably want to change the 'Ash Matheson' to something more appropriate.
---------------------------------------cut here------------------------------------
---------------------------------------cut here------------------------------------
linkage, for downloading: link
I've also had some time to play around with some CSS and jScript from Google code. This is pretty neat: http://code.google.com/p/syntaxhighlighter/ and it was very easy to add to this blog. It supports a variety of languages and looks awesome. I recommend you try it!
So, this was an excellent opportunity for me to create a new one and post it here. As well, I can discuss some of the things I ran into along my way.
It's pretty simple how I went about developing this set of macros. First off, I wanted one 'entry' function for determining what kind of comment I was making. This was pretty simple, and the method I used for determining if I'm commenting the top of a file, a class, a method or a function is pretty straightforward (potentially not the best, but I'll juice that up as time goes on). I boil it down to this:
a) if the current line is line zero, it's a file header comment.
b) if the current line contains a 'class' keyword, we're documenting a class
c) if the current line contains a '::', we're documenting a method
d) if the next line has a '{', it's a function
Like I said, it's pretty simple (read: stupid) but I'll enhance it later.
After that, it's just a matter of populating the comments with the right data.
Now, I did run into an interesting problem (which is where the majority of my day went). One thing I wanted to do was process all my method parameters and generate documentation for them. So, the process for that went like this:
1) generate an 'arguments' string. This is essentially everything between the '(' and ')'. This is a little problematic, because I need to deal with parameters that are spread across multiple lines. This was pretty easy to do. Then came stripping out the unnecessary characters (left and right trimming the '(' and ')' characters). I figured that I could do a string replace for all '(' and ')' characters with a space. Then use the Trim function in vb to strip out what I didn't want. However, I noticed that I was still having spaces at the end of my string. Or at least what I thought was spaces. It took a while for me to realize that they were non-printable characters ( specifically, there was a carriage return embedded before my ')' ... which wasn't in the source file). Anyway, there's a host of other reasons why I'd want to get rid of additional characters in my argument list, so I built a function that trimmed out additional 'fluff' characters, including tabs, line feeds, carriage returns and a few other non-printable characters). And then Trimmed the results. The code looks like this:
First, creating the argument string:
' Get all the arguments from the method Dim args As String Dim linenumber As Integer selection.SelectLine() args = selection.Text ' strip off the method return/method name (everything before the '(' Dim argsarray() As String = Split(args, "(") Dim nextline As String args = argsarray(1) While InStr(args, ")") = 0 selection.LineDown() nextline = selection.Text args = args & nextline End While args = Replace(args, ")", " ") args = TrimAll(args) argsarray = Split(args, ",") selection.GotoLine(linenumber)
Second, the TrimAll function:
Function TrimAll(ByVal TextIn As String) As String Try ' Replace ALL Duplicate Characters in String with a Single Instance Dim result As String result = Replace(TextIn, ")", " ") result = Replace(result, vbTab, " ") result = Replace(result, vbNullChar, " ") result = Replace(result, vbCr, " ") result = Replace(result, vbLf, " ") result = Trim(result) TrimAll = result Catch Exp As Exception TrimAll = TextIn ' Oops End Try Return TrimAll End Function
2) tokenize the arguments. VB has a 'split' function that breaks a string up into a string array based on a delimiter character. So, to break it down into arguments, it's a matter of splitting on a ',' character. After this, use VB's 'For Each' iterator to walk over the array of arguments and then tokenize each argument into another string array to get a list of types and variables. Simply grabbing the last array element gives me my variable name, which I can then print out.
OK. So after all that, here's the full code listing. Copy and paste into a new module. You'll probably want to change the 'Ash Matheson' to something more appropriate.
---------------------------------------cut here------------------------------------
Imports System Imports EnvDTE Imports EnvDTE80 Imports EnvDTE90 Imports System.Diagnostics Public Module Documentation Function TrimAll(ByVal TextIn As String) As String Try ' Replace ALL Duplicate Characters in String with a Single Instance Dim result As String result = Replace(TextIn, ")", " ") result = Replace(result, vbTab, " ") result = Replace(result, vbNullChar, " ") result = Replace(result, vbCr, " ") result = Replace(result, vbLf, " ") result = Trim(result) TrimAll = result Catch Exp As Exception TrimAll = TextIn ' Oops End Try Return TrimAll End Function Sub PerformDocumentation() Try Dim objTextDoc As TextDocument Dim editPoint As EnvDTE.EditPoint Dim selection As TextSelection objTextDoc = DTE.ActiveDocument.Object("TextDocument") editPoint = objTextDoc.StartPoint.CreateEditPoint selection = objTextDoc.Selection selection.StartOfLine() If selection.ActivePoint.Line = 1 Then GenerateFileHeader() ElseIf selection.FindText("class") = True Then 'Class declaration GenerateClassHeader() ElseIf selection.FindText("::") = True Then 'Method definition GenerateMethodHeader() Else selection.LineDown() If selection.FindText("{") Then 'Some Function definition selection.LineUp() GenerateFunctionHeader() End If End If Catch ex As Exception Dim messagebox As System.Windows.Forms.MessageBox messagebox.Show(ex.Message) Finally End Try End Sub Sub GenerateMethodHeader() DTE.UndoContext.Open("MethodHeader") Try Dim selection As TextSelection selection = DTE.ActiveDocument.Selection ' Get all the arguements from the method Dim args As String Dim linenumber As Integer linenumber = selection.ActivePoint.Line selection.SelectLine() args = selection.Text ' strip off the method return/method name (everything before the '(' Dim argsarray() As String = Split(args, "(") Dim nextline As String args = argsarray(1) While InStr(args, ")") = 0 selection.LineDown() nextline = selection.Text args = args & nextline End While args = Replace(args, ")", " ") args = TrimAll(args) argsarray = Split(args, ",") selection.GotoLine(linenumber) selection.StartOfLine() selection.NewLine() selection.StartOfLine() selection.Text = "/// *********************************************************************" selection.NewLine() selection.StartOfLine() selection.Text = "/// @brief " linenumber = selection.ActivePoint.Line ' This is where we want to return to selection.NewLine() selection.StartOfLine() selection.Text = "/// " selection.NewLine() selection.StartOfLine() selection.Text = "/// " selection.NewLine() selection.StartOfLine() selection.Text = "/// @return " ' now for our args For Each arguement As String In argsarray Dim tokenArray() As String Dim character As Char selection.NewLine() selection.StartOfLine() tokenArray = Split(Trim(arguement), " ") selection.Text = "/// @param " & tokenArray(tokenArray.Length - 1) Next selection.NewLine() selection.StartOfLine() selection.Text = "/// *********************************************************************" selection.NewLine() selection.GotoLine(linenumber) Catch ex As Exception Dim messagebox As System.Windows.Forms.MessageBox messagebox.Show(ex.Message) Finally DTE.UndoContext.Close() End Try End Sub Sub GenerateFunctionHeader() DTE.UndoContext.Open("FunctionHeader") Try Dim selection As TextSelection selection = DTE.ActiveDocument.Selection ' Get all the arguements from the method Dim args As String Dim linenumber As Integer selection.SelectLine() args = selection.Text ' strip off the method return/method name (everything before the '(' Dim argsarray() As String = Split(args, "(") Dim nextline As String args = argsarray(1) While InStr(args, ")") = 0 selection.LineDown() nextline = selection.Text args = args & nextline End While args = Replace(args, ")", " ") args = TrimAll(args) argsarray = Split(args, ",") selection.NewLine() selection.StartOfLine() selection.Text = "/// *********************************************************************" selection.NewLine() selection.StartOfLine() selection.Text = "/// @brief " linenumber = selection.ActivePoint.Line ' This is where we want to return to selection.NewLine() selection.StartOfLine() selection.Text = "/// " selection.NewLine() selection.StartOfLine() selection.Text = "/// " selection.NewLine() selection.StartOfLine() selection.Text = "/// @return " ' now for our args For Each arguement As String In argsarray Dim tokenArray() As String Dim character As Char selection.NewLine() selection.StartOfLine() tokenArray = Split(Trim(arguement), " ") selection.Text = "/// @param " & tokenArray(tokenArray.Length - 1) Next selection.NewLine() selection.StartOfLine() selection.Text = "/// *********************************************************************" selection.GotoLine(linenumber) Catch ex As Exception Finally DTE.UndoContext.Close() End Try End Sub Sub GenerateClassHeader() DTE.UndoContext.Open("ClassHeader") Try Dim selection As TextSelection Dim linenumber As Integer selection = DTE.ActiveDocument.Selection selection.StartOfLine() selection.NewLine() selection.StartOfLine() selection.Text = "/// *********************************************************************" selection.NewLine() selection.StartOfLine() selection.Text = "/// @brief " linenumber = selection.ActivePoint.Line ' This is where we want to return to selection.NewLine() selection.StartOfLine() selection.Text = "/// " selection.NewLine() selection.StartOfLine() selection.Text = "/// " selection.NewLine() selection.StartOfLine() selection.Text = "/// *********************************************************************" selection.NewLine() selection.GotoLine(linenumber) selection.EndOfLine() Catch ex As Exception Finally DTE.UndoContext.Close() End Try End Sub Sub GenerateFileHeader() DTE.UndoContext.Open("Generate File Header") Try DTE.ActiveDocument.Selection.StartOfDocument() Dim CurrentDate CurrentDate = System.DateTime.Now.ToShortDateString() Dim CurrentTime CurrentTime = System.DateTime.Now.ToShortTimeString() Dim Author = "Ash Matheson" Dim FileType Dim selection As TextSelection selection = DTE.ActiveDocument.Selection selection.Text = "/// Time-stamp: <@(#)" & ActiveDocument.Name & " " & CurrentDate & " - " & CurrentTime & " " & Author & ">" selection.NewLine() selection.StartOfLine() selection.Text = "/// *********************************************************************" selection.NewLine() selection.StartOfLine() selection.Text = "/// @file : " & ActiveDocument.Name selection.NewLine() selection.StartOfLine() selection.Text = "///" selection.NewLine() selection.StartOfLine() selection.Text = "/// @author " & Author selection.NewLine() selection.StartOfLine() selection.Text = "/// @date " & CurrentDate selection.NewLine() selection.StartOfLine() selection.Text = "///" selection.NewLine() selection.StartOfLine() If InStr(ActiveDocument.Name, ".h") <> 0 Then FileType = "Declaration of class " Else FileType = "Implementation of methods for class " End If selection.Text = "/// Purpose : " & FileType selection.NewLine() selection.StartOfLine() selection.Text = "///" selection.NewLine() selection.StartOfLine() selection.Text = "/// @brief " selection.NewLine() selection.StartOfLine() selection.Text = "/// *********************************************************************" selection.NewLine() selection.StartOfLine() selection.Text = "/// Version History:" selection.NewLine() selection.StartOfLine() selection.Text = "///" selection.NewLine() selection.StartOfLine() selection.Text = "/// V 0.10 " & CurrentDate & " BN : First Revision" selection.NewLine() selection.StartOfLine() selection.Text = "///" selection.NewLine() selection.StartOfLine() selection.Text = "/// *********************************************************************" selection.NewLine() selection.StartOfLine() selection.NewLine() selection.NewLine() Catch ex As Exception Dim messagebox As System.Windows.Forms.MessageBox messagebox.Show(ex.Message) Finally DTE.UndoContext.Close() End Try End Sub End Module
---------------------------------------cut here------------------------------------
linkage, for downloading: link
Comments