Align Comments

NOTE: From Igor 9 onwards this functionality is available as a standard feature (as Align Comments in the Edit menu), which makes this script unnecessary. You may find it useful if you are working with an earlier version.

Aligns all comments in the selection of a procedure file to the same tab position. The distance is set by the comment furthest to the left or right. Use the function ToTabPos to set a fixed alignment distance in number of tabs.

EDIT: Updated the code to properly honor the first line, even if it is selected only partly, and included the ability to left-align the comments or use a fixed tab number.

NOTES:

  • The current font name, font size, and default tab width settings for procedures need to be set to the correct values at the beginning of below code.
  • This code will be loaded as an independent module. You'll have to show hidden items in the procedure browser to see the code.
     
#pragma TextEncoding = "UTF-8"
#pragma rtGlobals = 3       // Use modern global access method and strict wave access.
#pragma IndependentModule = AlignComments
#pragma version = 1.1

// Inspired by the Code Prettify snipped by Tony Withers
// https://www.wavemetrics.com/user/chozo

// To align comments in the selected code use:
// Left-aligned: cmd-7 (Mac), ctrl-7 (Windows)
// Right-aligned: cmd-8 (Mac), ctrl-8 (Windows)

// Dial in your procedure window settings here:
// You can find the default tab size under Procedure->Document Settings...

StrConstant FontName = "Courier New"
Constant FontSize = 11
Constant DefaultTab = 20    // in points

Menu "Edit"
    "Align Comments in Clipboard Code (Right)", /Q, PutScrapText AlignComments#AlignComments(GetScrapText())
    "Align Comments in Selected Code (Left)/7", /Q, AlignCommentsInSelection(1)
    "Align Comments in Selected Code (Right)/8", /Q, AlignCommentsInSelection(0)
End

Function AlignCommentsInSelection(Variable LeftOrRight)
    String strScrap = GetScrapText()
    DoIgorMenu "Edit" "Copy"
    PutScrapText AlignComments#AlignComments(GetScrapText(),AligntoLeft=LeftOrRight)
    DoIgorMenu "Edit" "Paste"
    PutScrapText strScrap // leave clipboard state unchanged
End

// For setting a determined tab position of all selected comments.
// Execute from the commandline as AlignComments#toTabPos(desiredPos).
Function toTabPos(Variable TabPos)                                                          // for aligning all comments to a certain tab position
    DisplayProcedure/W=$StringFromList(0,WinList("*", ";","WIN:128"))               // bring to front
    String strScrap = GetScrapText()
    DoIgorMenu "Edit" "Copy"
    PutScrapText AlignComments#AlignComments(GetScrapText(),TabPos=TabPos)
    DoIgorMenu "Edit" "Paste"
    PutScrapText strScrap
End

// The optional variable TabPos lets you choose a fixed offset (in tab widths) for all comments.
// For example, TabPos = 30 will position all comments at 30 tabs, if possible.
Function/S AlignComments(String strText, [Variable TabPos, Variable AlignToLeft])
    Variable LorR = 0
    if(!ParamIsDefault(AlignToLeft))
        LorR = AlignToLeft
    endif
   
    Variable fsPix = FontSize * ScreenResolution/72                                     // font size in pix
    Variable TabPix = floor(DefaultTab * ScreenResolution/72)                           // tab width in pix
   
    Wave/T wText = ListToTextWave(strText, "\r")
    Variable endsWithReturn = (cmpstr(strText[strlen(strText)-1], "\r") == 0)
    Variable entries = numpnts(wText)

    String strEverything = "", strStartOfFirst   = "", strEndOfFirst = wText[0]     // extract the start of the first line from the whole text
    strEverything = ProcedureText("",0,StringFromList(0,WinList("*", ";","WIN:128")))
    strEverything = ReplaceString(strText,strEverything,"\rCUT\r")                  // create a break at selected text
    strEverything = StringFromList(0, strEverything, "\rCUT\r")                     // only the stuff before the selection
    if (cmpstr(strEverything[strlen(strEverything)-1], "\r") != 0 && strlen(strEverything)>0)   // only if it is not a full line
        Wave/T wBegin = ListToTextWave(strEverything, "\r")
        strStartOfFirst = wBegin[numpnts(wBegin)-1]                                     // the extra part of the first line
    endif

    if (strlen(strStartOfFirst) > 0)                                                            // put the full firt line in here
        wText[0] = strStartOfFirst + strEndOfFirst                                          // this is needed to calculate the correct line length
    endif
    wText += SelectString(p<(entries-1) || endsWithReturn, "", "\r")

    Make/D/FREE/N=(entries) CodeSize = 0                                                    // saves the code size in 'tab widths'
    Make/T/FREE/N=(entries) CodeOnly, CommentOnly
   
    Variable i,j, bytes = 0, strSize = 0
    String strLine = "", strCode = ""
   
    for (i = 0; i < entries; i += 1)
        strLine = wText[i]
        //bytes = strsearch(strLine, "//",Inf,1)
        bytes = startOfComment(strLine)                                                     // is there a comment?
        bytes = bytes == strlen(strLine) ? -1 : bytes                                       // no comment found

        if (i == 0 && strlen(strStartOfFirst) > bytes)                                  // if the full comment in not selected -> skip
            bytes = -1
        endif
       
        if(bytes > 1)
            strCode = strLine[0,bytes-1]
            if(GrepString(strCode, "\S"))                                                   // line contains non-whitespace
                CodeOnly[i]     = strCode                                                       // just the code
                CommentOnly[i]  = strLine[bytes,Inf]                                        // just the comment
                if (cmpstr(strCode[strlen(strCode)-1], " ") == 0)
                    CodeOnly[i]     = RemoveEnding(CodeOnly[i] , " ")                       // get rid of a possible space character in front of the comments
                    CodeOnly[i]     += "\t"
                endif
               
                // Below code calculates the line length in units of 'tab length'.
                // Multiplication by TabPix would give the length in pix.
                Wave/T wTabList = ListToTextWave(CodeOnly[i], "\t")                     // split code line by tabs
                for (j = 0; j < DimSize(wTabList,0); j += 1)
                    strCode = wTabList[j]
                    if (strlen(strCode) > 0)                                                    // tab only or code?
                        strSize = FontSizeStringWidth(FontName,fsPix,0,strCode,"")      // get the length of all characters
                        if (mod(strSize,TabPix) < 0.05)                                     // does this have roughly the size of a certain no. of tabs?
                            strSize = ceil(strSize/TabPix + 1)                              // a full tab length is added
                        else
                            strSize = ceil(strSize/TabPix)                                  // this will add a fractional tab length
                        endif
                        CodeSize[i] += strSize
                    else
                        CodeSize[i] += 1                                                            // if it's just a tab then add one tab length
                    endif
                endfor
                if (cmpstr(strCode[strlen(strCode)-1], "\t") == 0)                      // no tab in last entry -> not aligned to the next tab position
                    CodeSize[i] -= 1
                endif
            endif
        endif
    endfor
   
    wText[0] = strEndOfFirst + "\r"                                                         // put only the end line back (in case there is no modification)
    if (strlen(strStartOfFirst) > 0)                                                            // remove the first part of the first line again
        CodeOnly[0] = ReplaceString(strStartOfFirst,CodeOnly[0],"")
    endif
   
    Variable AlignDistance = 0                                                              // how many tabs define the new alignment
    if(!ParamIsDefault(TabPos))
        AlignDistance = TabPos
    else
        Extract/Free CodeSize,SizeVals,CodeSize!=0
        AlignDistance = LorR == 1 ? max(WaveMin(SizeVals),AlignDistance) :  max(WaveMax(SizeVals),AlignDistance)
    endif
   
    CodeSize = CodeSize[p] > 0 ? AlignDistance - CodeSize[p] : 0                        // how many tabs to add or subtract
    for (i = 0; i < entries; i += 1)
        String newTabs = ""
        if(abs(CodeSize[i]) > 0)
            for (j = 0; j < abs(CodeSize[i]); j += 1)
                if (CodeSize[i] < 0)
                    CodeOnly[i] = RemoveEnding(CodeOnly[i],"\t")
                else
                    newTabs += "\t"
                endif
            endfor
            wText[i] = CodeOnly[i] + newTabs + CommentOnly[i]
        endif
    endfor
       
    wfprintf strText, "%s", wText
    return strText
End

// comment search function by Tony Withers
Function startOfComment(String strLine)
    Variable startByte, commentByte, startQuote, endQuote, lineLength
    lineLength=strlen(strLine)
    startByte=0
    do
        if(startByte>=(lineLength-1))
            return lineLength
        endif
        commentByte = strsearch(strLine, "//", startByte)
        if(commentByte == -1)
            return lineLength
        endif
        // found "//"
        startQuote=strsearch(strLine, "\"", startByte)
        if(startQuote==-1 || startQuote>commentByte) // no quotes before //, we're done
            return commentByte
        endif
        // we have a quotation mark before //
       
        do
            endQuote=startQuote
            do
                endQuote=strsearch(strLine, "\"", endQuote+1)
                if(endQuote==-1)
                    return lineLength
                endif
                // endQuote is possible end of quote
                // remove escaped backslashes!
                strLine[startQuote,endQuote]=ReplaceString("\\\\", strLine[startQuote,endQuote], "  ")
            while(cmpstr(strLine[endQuote-1], "\\")==0) // ignore escaped quotes
           
            // found end of quote
            if(endQuote>commentByte) // commentByte was within commented text
                startByte=endQuote+1
                break // look for another comment mark
            else
                startQuote=strsearch(strLine, "\"", endQuote+1)
                if(startQuote==-1 || startQuote>commentByte) // no quotes before //, we're done
                    return commentByte
                endif
            endif
            // if we get to here we've found another start-of-quoted-text before //
        while(1) // next quoted text before //
    while(1) // next comment marker
End

 

AlignComments_v05.ipf (3.78 KB) AlignComments_v08.ipf (5.05 KB) AlignComments_v10.ipf (6 KB) AlignComments_v11_1.ipf (8.4 KB)

tricky!

See also the related snippet for comment wrapping. It doesn't help with what you're trying to do, but it does attempt to deal with indentation for long comments.

You will likely want to put your snippet into an independent module for compatibility with auto-compile.

In reply to by tony

Yes, thanks for the comment, I will do that. I am also planning to upgrade the code to optionally align to the rightmost or leftmost comment. Do you have any idea how to improve the following points:

  • Fetch the current font and tab settings programmatically. GetDefaultFont() only works for graphs...
  • Modify the selection in the procedure window to always include the whole first line, or alternatively get the text for the first line separately. I can get the selection with GetSelection(), but then what?

Btw, are you interested / do you plan to wrap all these snippets for procedure windows into a full tool set at some point?

In reply to by chozo

OK, here is the version as independent module. There are two menu entries now for aligning all selected comments to the leftmost (if possible) or rightmost comment. Also I have added a command-line function to set a fixed tab position. I have added the new version (v0.8) above.

#pragma TextEncoding = "UTF-8"
#pragma rtGlobals=3     // Use modern global access method and strict wave access.
#pragma IndependentModule = AlignComments
#pragma version=0.8

// Inspired by the Code Prettify snipped from Tony Withers
// https://www.wavemetrics.com/user/chozo
// To align comments in the selected code use:
// Left-aligned: cmd-7 (Mac), ctrl-7 (Windows)
// Right-aligned: cmd-8 (Mac), ctrl-8 (Windows)

// Dial in your procedure window settings here:
// You can find the default tab size under Procedure->Document Settings...

StrConstant FontName = "Courier New"
Constant FontSize = 11
Constant DefaultTab = 20    // in points

Menu "Edit"
    "Align Comments in Clipboard Code (Right)", /Q, PutScrapText AlignComments#AlignComments(GetScrapText())
    "Align Comments in Selected Code (Left)/7", /Q, AlignCommentsInSelection(1)
    "Align Comments in Selected Code (Right)/8", /Q, AlignCommentsInSelection(0)
End

Function AlignCommentsInSelection(Variable LeftOrRight)
    String strScrap = GetScrapText()
    DoIgorMenu "Edit" "Copy"
    PutScrapText AlignComments#AlignComments(GetScrapText(),AligntoLeft=LeftOrRight)
    DoIgorMenu "Edit" "Paste"
    PutScrapText strScrap // leave clipboard state unchanged
End

// For setting a determined tab position of all selected comments
// Execute from the commandline as AlignComments#toTabPos(desiredPos)
Function toTabPos(Variable TabPos)                                                          // for aligning all comments to a certain tab position
    DisplayProcedure/W=$StringFromList(0,WinList("*", ";","WIN:128"))               // bring to front
    String strScrap = GetScrapText()
    DoIgorMenu "Edit" "Copy"
    PutScrapText AlignComments#AlignComments(GetScrapText(),TabPos=TabPos)
    DoIgorMenu "Edit" "Paste"
    PutScrapText strScrap
End

// The optional variable TabPos lets you choose a fixed offset (in tab widths) for all comments.
// For example, TabPos = 30 will position all comments at 30 tabs, if possible
Function/S AlignComments(String strText, [Variable TabPos, Variable AlignToLeft])
    Variable LorR = 0
    if(!ParamIsDefault(AlignToLeft))
        LorR = AlignToLeft
    endif
   
    Variable fsPix = FontSize * ScreenResolution/72                                     // font size in pix
    Variable TabPix = floor(DefaultTab * ScreenResolution/72)                           // tab width in pix
   
    strText = ReplaceString(" //", strText, "//")                                           // get rid of a space character in front of the comments
   
    Wave/T wText = ListToTextWave(strText, "\r")
    Variable endsWithReturn = (cmpstr(strText[strlen(strText)-1], "\r") == 0)
    Variable entries = numpnts(wText)  
    wText += SelectString(p<(entries-1) || endsWithReturn, "", "\r")
   
    Make/D/FREE/N=(entries) CodeSize = 0                                                    // saves the code size in 'tab widths'
    Make/T/FREE/N=(entries) CodeOnly, CommentOnly
   
    Variable i,j, bytes = 0, strSize = 0
    String strLine = "", strCode = ""
   
    for (i = 0; i < entries; i += 1)
        strLine = wText[i]
        bytes = strsearch(strLine, "//",Inf,1)                                              // is there a comment?
        if(bytes > 1)
            strCode = strLine[0,bytes-1]
            if(GrepString(strCode, "\S"))                                                   // line contains non-whitespace
                CodeOnly[i]     = strCode                                                       // just the code
                CommentOnly[i]  = strLine[bytes,inf]                                        // just the comment
               
                // Below code calculates the line length in units of 'tab length'
                // Multiplication by TabPix would give the length in pix.
                Wave/T wTabList = ListToTextWave(strCode, "\t")                         // split code line by tabs
                for (j = 0; j < DimSize(wTabList,0); j += 1)
                    strCode = wTabList[j]
                    if (strlen(strCode) > 0)                                                    // tab only or code?
                        strSize = FontSizeStringWidth(FontName,fsPix,0,strCode,"")      // get the length of all characters
                        if (mod(strSize,TabPix) < 0.05)                                     // does this have roughly the size of a certain no. of tabs?
                            strSize = ceil(strSize/TabPix + 1)                              // a full tab length is added
                        else
                            strSize = ceil(strSize/TabPix)                                  // this will add a fractional tab length
                        endif
                        CodeSize[i] += strSize
                    else
                        CodeSize[i] += 1                                                            // if it's just a tab then add one tab length
                    endif
                endfor
                if (cmpstr(strCode[strlen(strCode)-1], "\t") == 0)                      // no tab in last entry => not aligned to the next tab position
                    CodeSize[i] -= 1
                endif
               
            endif
        endif
    endfor
   
    Variable AlignDistance = 0                                                              // how many tabs define the new alignment
    if(!ParamIsDefault(TabPos))
        AlignDistance = TabPos
    else
        Extract/Free CodeSize,SizeVals,CodeSize!=0
        AlignDistance = LorR == 1 ? max(WaveMin(SizeVals),AlignDistance) :  max(WaveMax(SizeVals),AlignDistance)
    endif
   
    CodeSize = CodeSize[p] > 0 ? AlignDistance - CodeSize[p] : 0                        // how many tabs to add or subtract
    for (i = 0; i < entries; i += 1)
        String newTabs = ""
        if(abs(CodeSize[i]) > 0)
            for (j = 0; j < abs(CodeSize[i]); j += 1)
                if (CodeSize[i] < 0)
                    CodeOnly[i] = RemoveEnding(CodeOnly[i],"\t")
                else
                    newTabs += "\t"
                endif
            endfor
            wText[i] = CodeOnly[i] + newTabs + CommentOnly[i]
        endif
    endfor
       
    wfprintf strText, "%s", wText
    return strText
End

 

In reply to by chozo

Procedure windows cannot, for the most part, be controlled programatically. So as far as I know there is no way to modify the selection.

But you can use the ProcedureText function to get all of the text of a procedure window, and then parse off the first line of the text. 

In reply to by chozo

The sorts of things you're looking for are easy to do with notebooks, but I don't know any way to do that with procedure windows, which makes sense because users were probably never expected to adjust the behaviour of that window. If we could use hook functions with procedure windows that would be great for adding contextual menus, but I can also see that it might make sense to put in requests for new features for Igor 9 (or 10?) rather than trying to 'roll our own'. Something that I would like is an operation to query the current state of ALL of the user-editable settings for Igor.

You could try using ProcedureText() to grab the whole procedure and then looking for a unique match of selected text within the procedure text... I just checked and it looks like the current text of uncompiled and unsaved ipf files is retrieved by ProcedureText(), so there may be some mileage in that.

I do maintain a TextEditTools.ipf procedure file for myself, but it doesn't contain much, just the snippets mentioned above and a transpose paste function. If the collection of user contributions grows then it might make sense to put together a compilation of utility text-editing code.

Tony and Adam,

Thank you very much for the input! I have modified the code again to grab the first line from ProcedureText(). Works great so far. I guess nothing can be done about having to dial in the font settings for now. I have attached the new version above.

#pragma TextEncoding = "UTF-8"
#pragma rtGlobals = 3       // Use modern global access method and strict wave access.
#pragma IndependentModule = AlignComments
#pragma version = 1.0

// Inspired by the Code Prettify snipped by Tony Withers
// https://www.wavemetrics.com/user/chozo

// To align comments in the selected code use:
// Left-aligned: cmd-7 (Mac), ctrl-7 (Windows)
// Right-aligned: cmd-8 (Mac), ctrl-8 (Windows)

// Dial in your procedure window settings here:
// You can find the default tab size under Procedure->Document Settings...

StrConstant FontName = "Courier New"
Constant FontSize = 11
Constant DefaultTab = 20    // in points

Menu "Edit"
    "Align Comments in Clipboard Code (Right)", /Q, PutScrapText AlignComments#AlignComments(GetScrapText())
    "Align Comments in Selected Code (Left)/7", /Q, AlignCommentsInSelection(1)
    "Align Comments in Selected Code (Right)/8", /Q, AlignCommentsInSelection(0)
End

Function AlignCommentsInSelection(Variable LeftOrRight)
    String strScrap = GetScrapText()
    DoIgorMenu "Edit" "Copy"
    PutScrapText AlignComments#AlignComments(GetScrapText(),AligntoLeft=LeftOrRight)
    DoIgorMenu "Edit" "Paste"
    PutScrapText strScrap // leave clipboard state unchanged
End

// For setting a determined tab position of all selected comments.
// Execute from the commandline as AlignComments#toTabPos(desiredPos).
Function toTabPos(Variable TabPos)                                                          // for aligning all comments to a certain tab position
    DisplayProcedure/W=$StringFromList(0,WinList("*", ";","WIN:128"))               // bring to front
    String strScrap = GetScrapText()
    DoIgorMenu "Edit" "Copy"
    PutScrapText AlignComments#AlignComments(GetScrapText(),TabPos=TabPos)
    DoIgorMenu "Edit" "Paste"
    PutScrapText strScrap
End

// The optional variable TabPos lets you choose a fixed offset (in tab widths) for all comments.
// For example, TabPos = 30 will position all comments at 30 tabs, if possible.
Function/S AlignComments(String strText, [Variable TabPos, Variable AlignToLeft])
    Variable LorR = 0
    if(!ParamIsDefault(AlignToLeft))
        LorR = AlignToLeft
    endif
   
    Variable fsPix = FontSize * ScreenResolution/72                                     // font size in pix
    Variable TabPix = floor(DefaultTab * ScreenResolution/72)                           // tab width in pix
   
    strText = ReplaceString(" //", strText, "//")                                           // get rid of a possible space character in front of the comments
   
    Wave/T wText = ListToTextWave(strText, "\r")
    Variable endsWithReturn = (cmpstr(strText[strlen(strText)-1], "\r") == 0)
    Variable entries = numpnts(wText)  

    String strEverything = ""                                                                   // extract the start of the first line from the whole text
    strEverything = ProcedureText("",0,StringFromList(0,WinList("*", ";","WIN:128")))
    strEverything = ReplaceString(strText,strEverything,"\rCUT\r")                  // create a break at selected text
    strEverything = StringFromList(0, strEverything, "\rCUT\r")                     // only the stuff before the selection
    Wave/T wBegin = ListToTextWave(strEverything, "\r")
    String strStartOfFirst  = wBegin[numpnts(wBegin)-1]                                 // the extra part of the first line
    String strEndOfFirst    = wText[0]

    if (strlen(strStartOfFirst) > 0)                                                            // put the full firt line in here
        wText[0] = strStartOfFirst + strEndOfFirst                                          // this is needed to calculate the correct line length
    endif
    wText += SelectString(p<(entries-1) || endsWithReturn, "", "\r")
   
    Make/D/FREE/N=(entries) CodeSize = 0                                                    // saves the code size in 'tab widths'
    Make/T/FREE/N=(entries) CodeOnly, CommentOnly
   
    Variable i,j, bytes = 0, strSize = 0
    String strLine = "", strCode = ""
   
    for (i = 0; i < entries; i += 1)
        strLine = wText[i]
        bytes = strsearch(strLine, "//",Inf,1)                                              // is there a comment?
        if(bytes > 1)
            strCode = strLine[0,bytes-1]
            if(GrepString(strCode, "\S"))                                                   // line contains non-whitespace
                CodeOnly[i]     = strCode                                                       // just the code
                CommentOnly[i]  = strLine[bytes,inf]                                        // just the comment
               
                // Below code calculates the line length in units of 'tab length'.
                // Multiplication by TabPix would give the length in pix.
                Wave/T wTabList = ListToTextWave(strCode, "\t")                         // split code line by tabs
                for (j = 0; j < DimSize(wTabList,0); j += 1)
                    strCode = wTabList[j]
                    if (strlen(strCode) > 0)                                                    // tab only or code?
                        strSize = FontSizeStringWidth(FontName,fsPix,0,strCode,"")      // get the length of all characters
                        if (mod(strSize,TabPix) < 0.05)                                     // does this have roughly the size of a certain no. of tabs?
                            strSize = ceil(strSize/TabPix + 1)                              // a full tab length is added
                        else
                            strSize = ceil(strSize/TabPix)                                  // this will add a fractional tab length
                        endif
                        CodeSize[i] += strSize
                    else
                        CodeSize[i] += 1                                                            // if it's just a tab then add one tab length
                    endif
                endfor
                if (cmpstr(strCode[strlen(strCode)-1], "\t") == 0)                      // no tab in last entry -> not aligned to the next tab position
                    CodeSize[i] -= 1
                endif
            endif
        endif
    endfor
   
    if (strlen(strStartOfFirst) > 0)                                                            // remove the first part of the first line again
        CodeOnly[0] = ReplaceString(strStartOfFirst,CodeOnly[0],"")
    endif
   
    Variable AlignDistance = 0                                                              // how many tabs define the new alignment
    if(!ParamIsDefault(TabPos))
        AlignDistance = TabPos
    else
        Extract/Free CodeSize,SizeVals,CodeSize!=0
        AlignDistance = LorR == 1 ? max(WaveMin(SizeVals),AlignDistance) :  max(WaveMax(SizeVals),AlignDistance)
    endif
   
    CodeSize = CodeSize[p] > 0 ? AlignDistance - CodeSize[p] : 0                        // how many tabs to add or subtract
    for (i = 0; i < entries; i += 1)
        String newTabs = ""
        if(abs(CodeSize[i]) > 0)
            for (j = 0; j < abs(CodeSize[i]); j += 1)
                if (CodeSize[i] < 0)
                    CodeOnly[i] = RemoveEnding(CodeOnly[i],"\t")
                else
                    newTabs += "\t"
                endif
            endfor
            wText[i] = CodeOnly[i] + newTabs + CommentOnly[i]
        endif
    endfor
       
    wfprintf strText, "%s", wText
    return strText
End

 

looking at the file AlignComments_v10.ipf:

you need to remove the prepended piece of the first line before pasting the adjusted text over the selection.

Also, you might worry about comment markers buried inside quotation marks, for instance in a line like

                bytes = strsearch(strLine, "//",Inf,1)

Here is an (untested) attempt to find the start of comments that doesn't get caught out by lines like

print "this is \"not a // comment\"" // and // this " is

 

// returns byte offset for comment marker in strLine
// or strlen(strLine) when no comment found.
function startOfComment(string strLine)
   
    variable startByte, commentByte, startQuote, endQuote, lineLength
    lineLength=strlen(strLine)
    startByte=0
    do
        if(startByte>=(lineLength-1))
            return lineLength
        endif
        commentByte = strsearch(strLine, "//", startByte)
        if(commentByte == -1)
            return lineLength
        endif
        // found "//"
        startQuote=strsearch(strLine, "\"", startByte)
        if(startQuote==-1 || startQuote>commentByte) // no quotes before //, we're done
            return commentByte
        endif
        // we have a quotation mark before //
       
        do
            endQuote=startQuote
            do
                endQuote=strsearch(strLine, "\"", endQuote+1)
                if(endQuote==-1)
                    return lineLength
                endif
                // endQuote is possible end of quote
                // remove escaped backslashes!
                strLine[startQuote,endQuote]=ReplaceString("\\\\", strLine[startQuote,endQuote], "  ")
            while(cmpstr(strLine[endQuote-1], "\\")==0) // ignore escaped quotes
           
            // found end of quote
            if(endQuote>commentByte) // commentByte was within commented text
                startByte=endQuote+1
                break // look for another comment mark
            else
                startQuote=strsearch(strLine, "\"", endQuote+1)
                if(startQuote==-1 || startQuote>commentByte) // no quotes before //, we're done
                    return commentByte
                endif
            endif
            // if we get to here we've found another start-of-quoted-text before //
        while(1) // next quoted text before //
    while(1) // next comment marker
end

 

Tony, thank you for your help with this. Indeed, properly selecting whole lines screwed up the code insertion thanks to the added handling of the first line in the last version. Oops. There were other hiccups as well.

I was searching for the start of a comment from the right. But as you have mentioned, two // in a comment or // in code without any comment would have been aligned as well. I have included your comment search function now. I hope that is OK.

I have added a new version (this time in the first post).

great. let me know if you find any problems with the comment search function. i updated the prettify code to use the more robust comment searching, though it's not critical to get it right for that purpose.

Aligning comments is a nice feature!

But do we really want to align code with tabs even when we are indenting with tabs?I don't think this will work.

Consider the following example

Function Dostuff()

    variable a // some double
    int i // some integer
End

If the comments ought to be right aligned they should be that for every tab width. As IMHO the tab width is settable by the user and that should not obstruct the code.

If I now align with tabs manually in IP

Function Dostuff()

    variable a  // some double
    int i           // some integer
End

which looks different here in the forum as a tab consists of 8 spaces here vs 4 in IP. You need to copy and paste to IP to see that it is correctly aligned with a tab width of 4.

I am actually not sure I understand. Is this a problem with the snippet? Yes, aligning comments with tabs is futile if you are looking at the code in another software, as tab widths change widely. The above snippet only aligns the comments so that they look 'good' within Igor. Unless we get the feature that comments are aligned/shown in a separate space next to the code, no matter the number of tabs before them, there is really no other solution than to align the stuff for one program and stick with it (or use the align functionality within each of these programs if available).

By the way, an additional complication arises with the forum, since tabs are replaced with a number of space characters. I don't know a way to get the original code with tabs out of a post.

Forum

Support

Gallery

Igor Pro 9

Learn More

Igor XOP Toolkit

Learn More

Igor NIDAQ Tools MX

Learn More