automatic formatting of comments

automatic formatting of comments

6
NewbieNewbie
6

    May 13, 2020#1

    It seems UE must be able to do this natively, without a script, but I don't see how....

    I want to be able to write a comment (say, in Python) and have UE automatically format it to some fixed width, prefixing each line with #. And ideally, I then want to edit the comment and have it automatically reformatted, including extending lines that are now below the max width.

    Can it do this? Am I just missing what seems to be a pretty basic feature?

    6,603548
    Grand MasterGrand Master
    6,603548

      May 14, 2020#2

      UltraEdit is not designed specific for Python programming nor any other programming language. It does not support automatic formatting of comment blocks for any programming language customizable to meet the user requirements like maximum line length with automatic word wrap within a comment block and keeping indentation within comment block and start or not start all lines except the first line of a comment block with a user specific character or string. So if you want to quickly reformat a comment block after editing to meet your requirements, you have to code an UltraEdit script for this task and execute it, for example, by hotkey whenever editing the comment block is finished by you and the comment block needs to be just reformatted finally.
      Best regards from an UC/UE/UES for Windows user from Austria

      6
      NewbieNewbie
      6

        May 14, 2020#3

        I know it's not designed for any specific language, but this general formatting capability is applicable to programming in most any language (and even many non-programming tasks). It would be a nice capability to incorporate natively.

        6,603548
        Grand MasterGrand Master
        6,603548

          May 14, 2020#4

          The feature UltraEdit has is an automatic word wrap while typing with keeping indentation. A C/C++/JS/CSS programmer using block comments with /* and */ can make use of this. I don't know much about Python and so I don't know if this feature could be useful also for Python programmers.

          The settings for automatic word wrap with inserting CR/LF can be set at Advanced - Settings or Configuration - Editor - Word wrap / tab settings. All the settings below the customizable file extension list are for the files with a file extension of currently selected list item. See the forum topic File extension based word wrap, tab and indent settings for more details.

          Next there must be enabled the settings at Advanced - Settings or Configuration - Editor display - Formatting to indent also each automatically wrapped line.

          It is also possible to execute the command Reformat paragraph to reformat an existing paragraph according to the settings set in the dialog window Reformatting Options.

          But there is no special programming language specific comment formatting feature available as some IDEs have.

          I have some problems to understand what you really want as you have not described that. I know many different commenting styles from having viewed many different source codes. So I cannot really help you with more detailed suggestions as those very general hints on which settings and commands are supported by UltraEdit to reformat lines.
          Best regards from an UC/UE/UES for Windows user from Austria

          6
          NewbieNewbie
          6

            May 16, 2020#5

            Mofi, thanks for much for your help and insight.

            I must not understand now the wrap feature you mentioned works. I have it configured to "Wrap after column #, insert CR/LF", but when I type a line and hit my wrap column #, nothing happens.

            ETA: I got the wrap feature to work, I needed to check the "default word wrap on for each file" option. 

            I was able to get the desired effect using the reformat paragraph option, and that's helpful.

            In Python, there are no true multi-line comments (yes, some people use multi-line docstrings as comments), so each line needs to be prefixed with #. So the reformatting functionality I want would basically need to remove all # from the beginning of the lines and line feeds from the ends, reformat the resulting single paragraph, and then prefix each line with "# ". It seems this would be a pretty easy feature to implement as a native feature, and something I will probably try to address with a macro. 

            Hmmm...I just tried to implement this using a macro, and it doesn't appear that you can call reformat paragraph from a macro. So I will try an actual script later.

              May 16, 2020#6

              I cobbled together this script that seems to do what I want. Any comments regarding how to improve it are welcomed!

              Code: Select all

              // basic framework code is from https://www.ultraedit.com/resources/scripts/jsDeminifyReformat.js
              var bColumnMode = false;
              if (typeof(UltraEdit.columnMode) == "boolean") bColumnMode = UltraEdit.columnMode;
              else if (typeof(UltraEdit.activeDocument.columnMode) == "boolean") bColumnMode = UltraEdit.activeDocument.columnMode;
              
              if (!bColumnMode) {
                if (!UltraEdit.activeDocument.isSel()) {
                  exit();
                }
                var code = '';
                var re = '';
              
                code = UltraEdit.activeDocument.selection;
                re = /^# /g;
                code = code.replace(re, '');
                re = /\r\n# /g;
                code = code.replace(re, ' ');
                
                // wrap at 78 to allow for '# ' prefix  
                code = wordWrap(code, 78);
                
                var re = /^/g;
                code = code.replace(re, '# ');
                re = /\r\n/g;
                code = code.replace(re, '\r\n# ');
               
                var nActiveClipboard = UltraEdit.clipboardIdx;
                UltraEdit.selectClipboard(9);
                UltraEdit.clipboardContent 
                UltraEdit.clipboardContent = code;
                UltraEdit.activeDocument.paste();
                UltraEdit.clearClipboard();
                UltraEdit.selectClipboard(nActiveClipboard);
              }
              
              // from https://stackoverflow.com/questions/14484787/wrap-text-in-javascript
              function wordWrap(str, maxWidth) {
                  var newLineStr = "\r\n"; done = false; res = '';
                  while (str.length > maxWidth) {                 
                      found = false;
                      // Inserts new line at first whitespace of the line
                      for (i = maxWidth - 1; i >= 0; i--) {
                          if (testWhite(str.charAt(i))) {
                              res = res + [str.slice(0, i), newLineStr].join('');
                              str = str.slice(i + 1);
                              found = true;
                              break;
                          }
                      }
                      // Inserts new line at maxWidth position, the word is too long to wrap
                      if (!found) {
                          res += [str.slice(0, maxWidth), newLineStr].join('');
                          str = str.slice(maxWidth);
                      }
                  }
                  return res + str;
              }
              
              function testWhite(x) {
                  var white = new RegExp(/^\s$/);
                  return white.test(x.charAt(0));
              };

              6,603548
              Grand MasterGrand Master
              6,603548

                May 22, 2020#7

                The variable definition lines var code = ''; and var re = ''; should be modified to just var code; and var re; to define just the two variables without a type instead of defining them as string variables with an empty string assigned. The variable code becomes a String object on next non-empty line and variable re a RegExp object on next but one non-empty line.

                The line var re = /^/g; should be modified to just re = /^/g; as the variable re is already defined on line 7 above.

                The line UltraEdit.clipboardContent should be removed from the script.

                The semicolon at end of the script file should be also removed.

                There is no function exit(). For that reason the script execution is terminated with an error if there is nothing selecting on running this script. One solution is modifying the first two IF conditions to:

                Code: Select all

                if (!bColumnMode && UltraEdit.activeDocument.isSel()) {
                So the script with those small improvements would be:

                Code: Select all

                // basic framework code is from https://www.ultraedit.com/resources/scripts/jsDeminifyReformat.js
                var bColumnMode = false;
                if (typeof(UltraEdit.columnMode) == "boolean") bColumnMode = UltraEdit.columnMode;
                else if (typeof(UltraEdit.activeDocument.columnMode) == "boolean") bColumnMode = UltraEdit.activeDocument.columnMode;
                
                if (!bColumnMode && UltraEdit.activeDocument.isSel()) {
                  var code;
                  var re;
                
                  code = UltraEdit.activeDocument.selection;
                  re = /^# /g;
                  code = code.replace(re, '');
                  re = /\r\n# /g;
                  code = code.replace(re, ' ');
                
                  // wrap at 78 to allow for '# ' prefix
                  code = wordWrap(code, 78);
                
                  re = /^/g;
                  code = code.replace(re, '# ');
                  re = /\r\n/g;
                  code = code.replace(re, '\r\n# ');
                
                  var nActiveClipboard = UltraEdit.clipboardIdx;
                  UltraEdit.selectClipboard(9);
                  UltraEdit.clipboardContent = code;
                  UltraEdit.activeDocument.paste();
                  UltraEdit.clearClipboard();
                  UltraEdit.selectClipboard(nActiveClipboard);
                }
                
                
                // from https://stackoverflow.com/questions/14484787/wrap-text-in-javascript
                function wordWrap(str, maxWidth) {
                    var newLineStr = "\r\n"; done = false; res = '';
                    while (str.length > maxWidth) {
                        found = false;
                        // Inserts new line at first whitespace of the line
                        for (i = maxWidth - 1; i >= 0; i--) {
                            if (testWhite(str.charAt(i))) {
                                res = res + [str.slice(0, i), newLineStr].join('');
                                str = str.slice(i + 1);
                                found = true;
                                break;
                            }
                        }
                        // Inserts new line at maxWidth position, the word is too long to wrap
                        if (!found) {
                            res += [str.slice(0, maxWidth), newLineStr].join('');
                            str = str.slice(maxWidth);
                        }
                    }
                    return res + str;
                }
                
                function testWhite(x) {
                    var white = new RegExp(/^\s$/);
                    return white.test(x.charAt(0));
                }
                
                A further improved version of the script above is:

                Code: Select all

                // basic framework code is from https://www.ultraedit.com/resources/scripts/jsDeminifyReformat.js
                var bColumnMode = false;
                if (typeof(UltraEdit.columnMode) == "boolean") bColumnMode = UltraEdit.columnMode;
                else if (typeof(UltraEdit.activeDocument.columnMode) == "boolean") bColumnMode = UltraEdit.activeDocument.columnMode;
                
                if (!bColumnMode && UltraEdit.activeDocument.isSel()) {
                
                  var comment = UltraEdit.activeDocument.selection;
                  comment = comment.replace(/^[\t ]*# ?/,'');
                  comment = comment.replace(/\r\n[\t ]*# ?/g,' ');
                  // wrap at 78 to allow for '# ' prefix
                  comment = wordWrap(comment, 78);
                
                  var nActiveClipboard = UltraEdit.clipboardIdx;
                  UltraEdit.selectClipboard(9);
                  UltraEdit.clipboardContent = "# " + comment.replace(/\r\n(?!$)/g,'\r\n# ');
                  UltraEdit.activeDocument.paste();
                  UltraEdit.clearClipboard();
                  UltraEdit.selectClipboard(nActiveClipboard);
                }
                
                
                // from https://stackoverflow.com/questions/14484787/wrap-text-in-javascript
                function wordWrap(str, maxWidth) {
                    var newLineStr = "\r\n"; done = false; res = '';
                    while (str.length > maxWidth) {
                        found = false;
                        // Inserts new line at first whitespace of the line
                        for (i = maxWidth - 1; i >= 0; i--) {
                            if (testWhite(str.charAt(i))) {
                                res = res + [str.slice(0, i), newLineStr].join('');
                                str = str.slice(i + 1);
                                found = true;
                                break;
                            }
                        }
                        // Inserts new line at maxWidth position, the word is too long to wrap
                        if (!found) {
                            res += [str.slice(0, maxWidth), newLineStr].join('');
                            str = str.slice(maxWidth);
                        }
                    }
                    return res + str;
                }
                
                function testWhite(x) {
                    var white = new RegExp(/^\s$/);
                    return white.test(x.charAt(0));
                }
                
                The improvements are:
                1. It removes also leading horizontal tabs and normal spaces from all lines with # at beginning.
                2. # at beginning of a line is also removed if the next character is not a space before word-wrap.
                3. There is no # and space appended to end of selected comment block if the selected block ends with carriage return + line-feed to avoid commenting out the next line with code.
                Please let me know if you would like to have a further improved script on which the indentation on first comment line is used for all other comment lines, too.
                Best regards from an UC/UE/UES for Windows user from Austria

                6
                NewbieNewbie
                6

                  May 23, 2020#8

                  Wow, thanks for the detailed feedback and improved script -- that was very kind of you! That was my first attempt at Javascript. I am surprised it allowed some of those mistakes...several of those errors are things I"m used to have a compiler/interpreter catch.

                  I would love to have a script that recognizes the indentation of the first line and uses it for the rest of the block!

                  6,603548
                  Grand MasterGrand Master
                  6,603548

                    May 24, 2020#9

                    Here is a further improved version of the script which supports duplicating the indentation of first selected line to all other lines of selected block. The indentation can be done with horizontal  tabs or spaces or even a mixture of tabs/spaces. The tab stop value to use for a horizontal tab must be defined at top of the script. UltraEdit for Windows v27.00 does not offer a  read-only property to get the tab stop value of active file according to the user's configuration.

                    Code: Select all

                    if (UltraEdit.document.length > 0)
                    {
                       // The column mode property is a property of the UltraEdit object in
                       // UltraEdit for Windows and UEStudio, but a property of the document
                       // object in UltraEdit for Linux and for Mac.
                       var bColumnMode = false;
                       if (typeof(UltraEdit.columnMode) == "boolean") bColumnMode = UltraEdit.columnMode;
                       else if (typeof(UltraEdit.activeDocument.columnMode) == "boolean") bColumnMode = UltraEdit.activeDocument.columnMode;
                    
                       if (!bColumnMode && !UltraEdit.activeDocument.hexMode && UltraEdit.activeDocument.isSel())
                       {
                         var nMaxLineLength = 80;  // Maximum length of a comment line
                         var nTabStopValue = 2;    // Tab stop value which must be greater 0.
                         var sBeginComment = "# "; // Beginning of each comment line
                         // Note: The two sComment.replace() must be adapted on changing this string.
                    
                         var sComment = UltraEdit.activeDocument.selection;
                    
                         // Determine indentation of first selected line with limiting indentation
                         // to half of maximum line length with including the string length of the
                         // beginning of each comment line in the maximum indentation length.
                         var nMaxIndentLength = ((nMaxLineLength & (~1)) / 2) - sBeginComment.length;
                         var nIndent = 0;
                         for (var nCharIndex = 0; nCharIndex < sComment.length; nCharIndex++)
                         {
                           var nCharCode = sComment.charCodeAt(nCharIndex);
                           if (nCharCode == 32)      // Is next character a normal space character?
                           {
                             if (nIndent >= nMaxIndentLength) break;
                             nIndent++;
                           }
                           else if (nCharCode == 9)  // Is next character a horizontal tab character?
                           {
                             var nNewIndent = nIndent + nTabStopValue;
                             nNewIndent -= nNewIndent % nTabStopValue;
                             if (nNewIndent > nMaxIndentLength) break;
                             nIndent = nNewIndent;
                           }
                           else break;   // This character is neither a space nor a tab.
                         }
                         var sIndent = sComment.substr(0,nCharIndex) + sBeginComment;
                         nIndent += sBeginComment.length;
                    
                         // All carriage return + line-feed pairs are removed from selected comment
                         // block by the second replace below. It is necessary to keep the last line
                         // termination on selected comment block ending with a line-feed to avoid
                         // a concentation of last comment line with next not selected line in file.
                         var sBlockEnd = (sComment.charCodeAt(sComment.length-1) == 10) ? "\r\n" : "";
                    
                         sComment = sComment.replace(/^[\t ]*(?:# ?)?/,'');
                         sComment = sComment.replace(/(?:[\t ]*\r\n[\t ]*(?:# ?)?)+/g,' ');
                         sComment = sComment.replace(/[\t ]+$/,'');
                    
                         // Wrap the comment block with taking length of indentation into account.
                         sComment = wordWrap(sComment,nMaxLineLength - nIndent - 1);
                    
                         var nActiveClipboard = UltraEdit.clipboardIdx;
                         UltraEdit.selectClipboard(9);
                         UltraEdit.clipboardContent = sIndent + sComment.replace(/\r\n/g,"\r\n"+sIndent) + sBlockEnd;
                         UltraEdit.activeDocument.paste();
                         UltraEdit.clearClipboard();
                         UltraEdit.selectClipboard(nActiveClipboard);
                       }
                    
                    
                       // from https://stackoverflow.com/questions/14484787/wrap-text-in-javascript
                       function wordWrap(str, maxWidth) {
                         var newLineStr = "\r\n";
                         var res = '';
                         var white = new RegExp(/^\s$/);
                         while (str.length > maxWidth) {
                           var found = false;
                           // Inserts new line at first whitespace of the line
                           for (var i = maxWidth - 1; i >= 0; i--) {
                             if (white.test(str.charAt(i))) {
                               res = res + [str.slice(0, i), newLineStr].join('');
                               str = str.slice(i + 1);
                               found = true;
                               break;
                             }
                           }
                           // Inserts new line at maxWidth position, the word is too long to wrap
                           if (!found) {
                             res += [str.slice(0, maxWidth), newLineStr].join('');
                             str = str.slice(maxWidth);
                           }
                         }
                         return res + str;
                       }
                    }
                    
                    The function wordWrap is improved also a little bit for faster execution.
                    Best regards from an UC/UE/UES for Windows user from Austria

                    6
                    NewbieNewbie
                    6

                      May 28, 2020#10

                      Mofi, thanks so much for your updated version! I finally had a chance to play with it a bit, and it seems to work as expected. I am going to take the time to review and understand your other changes, too...they're very helpful to improving my scripting in the future.