#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