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 10

Learn More

Igor XOP Toolkit

Learn More

Igor NIDAQ Tools MX

Learn More