Script for equal sign alignment

Script for equal sign alignment

344
MasterMaster
344

    Apr 18, 2007#1

    Hi guys,

    here is my align script I was unable to do with UE macro language.
    Imagine you have (huge) code like this

    Code: Select all

        lala   =  abc
      lalalalala     =   def
        la  = ghi
      baba = jkl asdf sdsdfas
    and want it to be like this (left align)

    Code: Select all

        lala       = abc
         lalalalala = def
         la         = ghi
         baba       = jkl asdf sdsdfas
    or that (right align)

    Code: Select all

              lala = abc
         lalalalala = def
                 la = ghi
               baba = jkl asdf sdsdfas
    So from now on you can call my script.

    Here is last version of the script alignEqual.js.

    Code: Select all

    // alignEqual.js
    // Bego
    // Aligns the SELECTION by the equal sign. Might be configured for Left or Right alignment!
    // Version 1.1  25.10.2007 result once was shifting 1 column to the left for each run: pos1 = getColOfFirstChar();// - 1;
    //         1.2  25.10.2007 Now MYSIGN can be really sth. else like "=", e.g. "/", but yet still only ONE character.
    //         1.3  25.10.2007 Shifting result in 1.1 was problem of configuration of HOME key when pressed twice.
    //                         Made it safe now. CloseFile workaround 13.20+2
    //         1.4  03.07.2014 Script revised by Mofi.
    //                         Avoid usage of command setActive() as not working up to UE v14.20.0.
    //                         This script works now with all versions of UE/UES, even with
    //                         UE v13.00 and UES v6.20 although very slow with those versions.
    
    var MYSIGN = "=";
    var MYALIGN = "R"; // (L)eft or (R)ight
    
    // Is any file opened and the alignment string is not an empty string?
    if ((UltraEdit.document.length > 0) && (MYSIGN.length > 0))
    {
       // Always select all on testing script during development.
       // UltraEdit.activeDocument.selectAll();
       // Nothing is done if nothing is selected on script start.
       if (UltraEdit.activeDocument.isSel())
       {
          UltraEdit.insertMode();
          if (typeof(UltraEdit.columnModeOff) == "function") UltraEdit.columnModeOff();
          else if (typeof(UltraEdit.activeDocument.columnModeOff) == "function") UltraEdit.activeDocument.columnModeOff();
    
          var pos1 = 0;
          var maxColEqual = 0;
    
          // Column number property available since UE v13.10 / UES v6.30.
          // A very slow workaround is needed for UE v13.00 and UES v6.20.
          var bColProperty = (typeof(UltraEdit.activeDocument.currentColumnNum) == "number") ? true : false;
    
          // Starting with UE v16.00 / UES v10.00 the property currentColumnNum
          // contains the column number with number 1 for first column in line.
          // Older versions return 0 for first column. This difference must be
          // compensated by subtracting 0 or 1 depending on version of UE / UES.
          var colStart = (typeof(UltraEdit.activeDocumentIdx) == "undefined") ? 0 : 1;
    
          var sourceDoc = UltraEdit.document[getActiveDocumentIndex()];
    
          UltraEdit.selectClipboard(9);
          sourceDoc.copy();
    
          UltraEdit.newFile();
          var orgDoc = UltraEdit.activeDocument;
          orgDoc.paste();
          orgDoc.top();
    
          pos1 = getColOfFirstChar();
          stripEqualRemoveLeadingSpaces();
    
          maxColEqual = getMaxColEqual();
          stuff(pos1, maxColEqual, MYALIGN);
    
          orgDoc.selectAll();
          orgDoc.copy();
          sourceDoc.paste();
          UltraEdit.clearClipboard();
          UltraEdit.selectClipboard(0);
          UltraEdit.closeFile(orgDoc.path,2);
       }
    }
    
    ///////////////////////////////////////////////////////////////////////////////////////////////////
    
    function stuff(pPos1, pMaxCol, pAlign)
    {
       var col;
       var spaces = "                                                                 ";
    
       orgDoc.top();
       // Go through once again and stuff spaces, depending on the
       // position of the equal sign and the calculated maxPosition.
       while (orgDoc.findReplace.find(MYSIGN))
       {
          // Cancel the current selection.
          orgDoc.key("LEFT ARROW"); orgDoc.key("RIGHT ARROW");
          col = getCurrentColumNum();
          if (pAlign == "R")
          {
             orgDoc.key("HOME");
             orgDoc.write(spaces.substr(0,pMaxCol - col + pPos1));
          }
          else
          {
             // The caret is positioned now at beginning of the found string
             // in UE < v14.00 and UES < v6.50. But in all later versions the
             // caret is now after the found string and therefore on space
             // after the alignment string. Caret must be moved backwards.
             if (orgDoc.isChar(" "))
             {
                for (var nLength = 0; nLength < MYSIGN.length; nLength++)
                {
                   orgDoc.key("LEFT ARROW");
                }
             }
             orgDoc.write(spaces.substr(0,pMaxCol - col));
             orgDoc.key("HOME");
             orgDoc.write(spaces.substr(0,pPos1));
          }
          orgDoc.key("END");
       }
    }
    
    function getMaxColEqual()
    {
       // Get the most right equal sign in the selection. This is the
       // orientation for the stuffing spaces at the beginning of the line.
       var maxCol = 0;
       var Column = 0;
    
       orgDoc.top();
       orgDoc.findReplace.regExp = false;
       while (orgDoc.findReplace.find(MYSIGN))
       {
          if (bColProperty)
          {
             Column = orgDoc.currentColumnNum - colStart;
          }
          else
          {  // Cancel selection and update column number internally.
             orgDoc.key("LEFT ARROW");
             orgDoc.key("RIGHT ARROW");
             Column = getCurrentColumNum();
          }
          orgDoc.key("END"); // Continue search in next line.
          if (Column > maxCol)
          {
             maxCol = Column;
          }
       }
       return maxCol;
    }
    
    function stripEqualRemoveLeadingSpaces()
    {
       // ONE space before and after equal sign.
       orgDoc.top();
       UltraEdit.perlReOn();
       orgDoc.findReplace.searchDown=true;
       orgDoc.findReplace.matchCase=true;
       orgDoc.findReplace.matchWord=false;
       orgDoc.findReplace.regExp = true;
       orgDoc.findReplace.preserveCase=true;
       orgDoc.findReplace.replaceAll = true;
       var strFind = "[\\t ]*" + MYSIGN + "[\\t ]*";
       orgDoc.findReplace.replace(strFind, " " + MYSIGN + " ");
       // Remove all leading tabs and spaces.
       orgDoc.findReplace.replace("^[\\t ]*", "");
    }
    
    function getColOfFirstChar()
    {
       // Determines in which column the line starts with content.
       // V1.3: Maybe do it twice since HOME key might toggle
       //       between start of line and start of first char.
       orgDoc.key("HOME");
       if (orgDoc.isColNum(1))
       {
          orgDoc.key("HOME");
       }
       // With configuration setting "Home key always goes to column 1" the
       // caret is still not positioned at first non whitespace character.
       // This loop moves the caret to first character in first line not
       // being a space or a horizontal tab character.
       while (orgDoc.isChar(" ") || orgDoc.isChar("\t"))
       {
          orgDoc.key("RIGHT ARROW");
       }
       return getCurrentColumNum();
    }
    
    function getActiveDocumentIndex()
    {
       // There is an active document index property since UE v16.00 / UES v10.00.
       if (typeof(UltraEdit.activeDocumentIdx) == "number")
       {
          return UltraEdit.activeDocumentIdx;
       }
       // Workaround solution for UE < v16.00 and UES < v10.00.
       for (var i = 0; i < UltraEdit.document.length; i++)
       {
          if (UltraEdit.activeDocument.path == UltraEdit.document[i].path)
          {
             return i;
          }
       }
       return (-1);
    }
    
    // Function to work around missing currentColumnNum property in UE v13.00
    // and UES v6.20 making this script very slow on execution with those old
    // versions of UltraEdit / UEStudio.
    function getCurrentColumNum()
    {
       if (bColProperty)
       {
          return (orgDoc.currentColumnNum - colStart);
       }
       var CurColumn = 0;
       // isColNum starts column counting with 1 for first column.
       while (!orgDoc.isColNum(++CurColumn));
       // But returned must be a column number with 0 for first column.
       return (--CurColumn);
    }
    
    Version 1.3 was posted by me at 20:17 on 2007-10-25 and had also posted code from other forum members.

    Thanks to toddm and especially to jorrasdk who helped a lot to write version 1.3 of the script.

    Hope it is helpful.

    rds Bego

    Update by Mofi: Script of Bego revised to work with any version of UltraEdit or UEStudio supporting scripts. See also the alternate script posted below making the alignment in memory instead of a temporary created new file which is faster as it avoids lots of display updates during script execution.
    Normally using all newest english version incl. each hotfix. Win 10 64 bit

    80
    Advanced UserAdvanced User
    80

      Oct 25, 2007#2

      Bego, I didn't spend more than a couple minutes looking at your script, but I'm wondering if you know offhand how to make it align other strings like <=.

      I tried changing MYSIGN and that didn't work.

      Also, the code I'm trying to align is indented and after aligning there is one less indentation space. Is this expected?

      Thanks.

      344
      MasterMaster
      344

        Oct 25, 2007#3

        Hi todd,

        Unfortunately the script is quite hard based for aligning ONE character.
        For more I would also have to think about more and I don't have the time right now, but will do that enhancement as soon as possible.
        But I disabled the feature "move to left one columns" ;-)

          Oct 25, 2007#4

          @todd: Version 1.3 supports also already more than one character, e.g. change the definition line to this

          Code: Select all

          var MYSIGN = "<=";
          and this

          Code: Select all

            la skdjlfh j    <=  lskdjfh kj
                gf saf<=sdafhkj 
             sdaf <=   sdlökfjdafkj
                   lskdf <= lskdafjsal
             lksja j     <= lskdafsa
             lkj <= salkj sda 
             slkdjgh kkgkfsd       <= sdahskja fskdja sda
             lfkjsda <=    sdakjnlökfjsda
          turns to that

          Code: Select all

            la skdjlfh j    <= lskdjfh kj
            gf saf          <= sdafhkj 
            sdaf            <= sdlökfjdafkj
            lskdf           <= lskdafjsal
            lksja j         <= lskdafsa
            lkj             <= salkj sda 
            slkdjgh kkgkfsd <= sdahskja fskdja sda
            lfkjsda         <= sdakjnlökfjsda
          Please tell me if it works.

          rds Bego
          Normally using all newest english version incl. each hotfix. Win 10 64 bit

          80
          Advanced UserAdvanced User
          80

            Oct 25, 2007#5

            Works great. Thanks Bego!

            27
            Basic UserBasic User
            27

              Jun 17, 2014#6

              Sorry to post a message on a - very - old topic but I start to use this script in my project. I've made some changes but I've some questions:
              1. Is it possible to make all operations outside a temporay window? Maybe in memory.
              2. If not, is it possible to hide this window?
              Thanks for your answers.

              6,686585
              Grand MasterGrand Master
              6,686585

                Jun 22, 2014#7

                Yes, it is possible to do the alignment completely in memory, but only if
                • there are no horizontal tabs between non whitespace characters in text left the equal sign,
                • the file does not contain Unicode characters in the selected block,
                • the selected block is not too large (dozens/hundreds of MB).
                The script below makes the alignment in memory and works even with UltraEdit v13.00 which was the first version with scripting support.

                Code: Select all

                var sAlignString = "=";    // Alignment is made on this string.
                var bRightAlign = true;    // Alignment can be left or right.
                
                // Is any file opened and the alignment string is not an empty string?
                if ((UltraEdit.document.length > 0) && (sAlignString.length > 0))
                {
                   // Nothing is done if nothing is selected on script start.
                   if (UltraEdit.activeDocument.isSel())
                   {
                      // Define environment for this script.
                      UltraEdit.insertMode();
                      if (typeof(UltraEdit.columnModeOff) == "function") UltraEdit.columnModeOff();
                      else if (typeof(UltraEdit.activeDocument.columnModeOff) == "function") UltraEdit.activeDocument.columnModeOff();
                
                      // Determine line termination used currently in active file.
                      var sLineTerm = "\r\n";
                      if (typeof(UltraEdit.activeDocument.lineTerminator) == "number")
                      {
                         // The two lines below require UE v16.00 or UES v10.00 or later.
                         if (UltraEdit.activeDocument.lineTerminator == 1) sLineTerm = "\n";
                         else if (UltraEdit.activeDocument.lineTerminator == 2) sLineTerm = "\r";
                      }
                      else  // This version of UE/UES does not offer line terminator property.
                      {
                         var nLineTermPos = UltraEdit.activeDocument.selection.search(/\r?\n|\r/);
                         if (nLineTermPos >= 0)
                         {
                            sLineTerm = UltraEdit.activeDocument.selection.substr(nLineTermPos,2).replace(/^(\r?\n|\r).*$/,"$1");
                         }
                      }
                
                      // Get all selected lines into memory as an array of strings.
                      // An error in the line below on script execution is
                      // caused usually by a too large block for this script.
                      var asLines = UltraEdit.activeDocument.selection.split(sLineTerm);
                
                      // Determine indent for aligned lines from first selected line.
                      var sIndent = "";
                      var nFirstNonWhitespace = asLines[0].search(/[^\t ]/);
                      if (nFirstNonWhitespace > 0)
                      {
                         sIndent = asLines[0].substr(0,nFirstNonWhitespace);
                      }
                
                      // Determine longest string left the alignment string.
                      var sLeft = "";
                      var nAlignPos = 0;
                      var nMaxLeftLength = 0;
                      for(var nLine = 0; nLine < asLines.length; nLine++)
                      {
                         // Find first occurrence of the alignment string in the line.
                         nAlignPos = asLines[nLine].indexOf(sAlignString);
                         if (nAlignPos > 0)
                         {
                            // There is an alignment string found not at beginning of
                            // the line. Get the string left of the alignment string
                            // without the whitespaces at beginning of the line and
                            // left of the alignment string.
                            sLeft = asLines[nLine].substr(0,nAlignPos);
                
                            // There is also a trim method of JavaScript String object,
                            // but trimming is made manually for downwards compatibility.
                            sLeft = sLeft.replace(/^[\t ]+/,"");
                            sLeft = sLeft.replace(/[\t ]+$/,"");
                
                            // If this string left the alignment string is longer
                            // than all other strings before, remember the length.
                            if (sLeft.length > nMaxLeftLength)
                            {
                               nMaxLeftLength = sLeft.length;
                            }
                         }
                      }
                
                      // Build the string consisting only of spaces for alignment.
                      // This string is empty if no alignment string found or
                      // all alignment strings are at beginning of the lines.
                      var sSpaces = "";
                      while(nMaxLeftLength)
                      {
                         sSpaces += " ";
                         nMaxLeftLength--;
                      }
                
                      // Build now the lines new with appropriate alignment.
                      var nAlignSpaces = 0;
                      for(nLine = 0; nLine < asLines.length; nLine++)
                      {
                         // Find first occurrence of the alignment string in the line.
                         nAlignPos = asLines[nLine].indexOf(sAlignString);
                         // Modify only lines containing the alignment string at all.
                         if (nAlignPos >= 0)
                         {
                            sLeft = asLines[nLine].substr(0,nAlignPos);
                            sLeft = sLeft.replace(/^[\t ]+/,"");
                            sLeft = sLeft.replace(/[\t ]+$/,"");
                
                            // Calculate the number of spaces which must be inserted
                            // after the indent for right alignment or left to the
                            // alignment string on left alignment.
                            if (sSpaces.length)
                            {
                               nAlignSpaces = sSpaces.length - sLeft.length;
                               sLeft += " ";  // Insert always 1 space before alignment
                            }                 // string except there is no line with a
                                              // text left the alignment string.
                
                            // Build the string left the alignment string.
                            if (!bRightAlign)
                            {
                               sLeft = sIndent + sLeft + sSpaces.substr(0,nAlignSpaces);
                            }
                            else
                            {
                               sLeft = sIndent + sSpaces.substr(0,nAlignSpaces) + sLeft;
                            }
                
                            // Get string right of the alignment string.
                            var sRight = asLines[nLine].substr(nAlignPos+sAlignString.length);
                
                            // Remove tabs and spaces at beginning and insert a single space.
                            sRight = sRight.replace(/^[\t ]*/," ");
                
                            // Build the complete line now aligned well.
                            asLines[nLine] = sLeft + sAlignString + sRight;
                         }
                      }
                      // Overwrite the selected block with the aligned lines.
                      UltraEdit.activeDocument.write(asLines.join(sLineTerm));
                   }
                }
                
                Best regards from an UC/UE/UES for Windows user from Austria

                27
                Basic UserBasic User
                27

                  Jun 23, 2014#8

                  Thanks mofi for your example and your explanations. I think I keep both, because as you say, it's faster on few lines, which is the most case on my project, so in this case I will use "arrays" and in other cases I will use "new file".

                    Jul 01, 2014#9

                    I've another little question.
                    I've updated the script to let the user enter the sign to align, but in order to be more efficient, I'm wondering if it's possible to keep (store?) the last value, given by user, between each call of the script? (during the same session of UltraEdit)

                    6,686585
                    Grand MasterGrand Master
                    6,686585

                      Jul 01, 2014#10

                      Values can be passed from one execution of a script to next execution only via a file or via one of the user clipboards of UltraEdit if not used by the user.

                      Persistent storage of a script variable value in a file

                      The storage of a value in a file is persistent even over different editing sessions and global over multiple running instances of UE/UES on which a script is executed.

                      But usage of a small file for storing values for a script makes a script slower as the file must be first checked on existence, next opened, read by the script, if necessary modified, saved and closed. And of course the directory into which the file should be saved using Save As command on first save must exist already, too.

                      All those actions listed above can be avoided if the value is stored directly in a text file created once manually with a constant path/file name and which of course is not write-protected by using Find/Replace in Files commands as shown below.

                      Code: Select all

                      // This script code requires at least UE v14.20 or UES v09.00.
                      
                      var sAlignString = "=";
                      
                      // Get current content of output window into user clipboard 8.
                      UltraEdit.selectClipboard(8);
                      UltraEdit.outputWindow.copy();
                      
                      // Run a Find in Files searching for the identifier string in the file
                      // specified below with found lines written to output window. An UltraEdit
                      // regular expression search is used instead of a non regex search because
                      // of making sure that the identifier string is found at beginning of a
                      // line and for escaping the equal sign with character ^ although the equal
                      // sign must not be escaped as it has no special meaning. This is mainly
                      // done to avoid that the search string also written to output window is
                      // equal the identifier string with the assigned alignment string which
                      // makes the next JavaScript regular expression replace for getting the
                      // alignment string easier. And with this little trick also the output
                      // format of Find in Files does not really matter.
                      UltraEdit.ueReOn();
                      UltraEdit.frInFiles.filesToSearch=0;
                      UltraEdit.frInFiles.directoryStart="";
                      UltraEdit.frInFiles.searchInFilesTypes="C:\\Temp\\AlignString.txt";
                      UltraEdit.frInFiles.regExp=true;
                      UltraEdit.frInFiles.matchCase=true;
                      UltraEdit.frInFiles.matchWord=false;
                      UltraEdit.frInFiles.useEncoding=false;
                      UltraEdit.frInFiles.openMatchingFiles=false;
                      UltraEdit.frInFiles.useOutputWindow=true;
                      UltraEdit.frInFiles.preserveCase=false;
                      UltraEdit.frInFiles.searchSubs=false;
                      UltraEdit.frInFiles.logChanges=true;
                      UltraEdit.frInFiles.find("%LastAlignString^=");
                      
                      // Copy the lines in output window to user clipboard 9.
                      UltraEdit.selectClipboard(9);
                      UltraEdit.outputWindow.copy();
                      
                      // Get just the alignment string if it could be found in the file.
                      var sReadAlignString = UltraEdit.clipboardContent.replace(/^[\s\S]*LastAlignString=([^\r\n]+)[\s\S]*$/,"$1");
                      
                      // The replace method of JavaScript String object returns the string itself
                      // if the regular expression did not match because of LastAlignString= with
                      // at least 1 more character not found in file respectively output window.
                      if (sReadAlignString != UltraEdit.clipboardContent)
                      {
                         sAlignString = sReadAlignString; // Last saved alignment string found.
                      }
                      UltraEdit.clearClipboard();         // Clear user clipboard 9.
                      
                      // Ask user of script for alignment string with showing current string.
                      // The multiline prompt text requires UE v18.10.0.1014 and UES v12.10
                      // or any later version. Previous versions of UE/UES support only a
                      //short single line prompt text.
                      var sNewAlignString = UltraEdit.getString("Currently alignment string is: "+sAlignString+"\n\nEnter new string for alignment or hit RETURN.",1);
                      
                      // Has the user entered a string?
                      if (sNewAlignString.length)
                      {
                         // Is the entered string different to what is stored in data file?
                         if (sNewAlignString != sAlignString)
                         {
                            // Save in the data file the new alignment string.
                            UltraEdit.frInFiles.replace("%LastAlignString=?+","LastAlignString="+sNewAlignString);
                            sAlignString = sNewAlignString;
                         }
                      }
                      
                      // Now it is a good time to clear output window and restore the initial
                      // content of the output window before usage of Find/Replace in Files. The
                      // last carriage return + linefeed must be removed before writing content
                      // back to output window as write command adds itself a line termination.
                      UltraEdit.outputWindow.clear();
                      UltraEdit.selectClipboard(8);
                      UltraEdit.outputWindow.write(UltraEdit.clipboardContent.replace(/\r?\n$/,""));
                      UltraEdit.clearClipboard();         // Clear user clipboard 8.
                      
                      // Select the standard clipboard of the operating system.
                      UltraEdit.selectClipboard(0);
                      
                      The complete file name C:\Temp\AlignString.txt as used in the script must be adapted in this script snippet.


                      Session storage of a script variable value in a user clipboard

                      Much faster is the usage of one of the user clipboards of UltraEdit as global session based buffer for the values of script variables as the script snippet below demonstrates.

                      Code: Select all

                      // This script code requires at least UE v14.20 or UES v09.00.
                      
                      var sAlignString = "=";
                      
                      // User clipboard 7 is used to hold the last entered alignment string
                      // within current editing session. For a little security an identifier
                      // is also added which must be found at beginning of clipboard content.
                      UltraEdit.selectClipboard(7);
                      if (UltraEdit.clipboardContent.indexOf("LastAlignString=") == 0)
                      {
                         sAlignString = UltraEdit.clipboardContent.substr(16);
                      }
                      
                      // Ask user of script for alignment string with showing current string.
                      // The multiline prompt text requires UE v18.10.0.1014 and UES v12.10
                      // or any later version. Previous versions of UE/UES support only a
                      //short single line prompt text.
                      var sNewAlignString = UltraEdit.getString("Currently alignment string is: "+sAlignString+"\n\nEnter new string for alignment or hit RETURN.",1);
                      
                      // Has the user entered a string?
                      if (sNewAlignString.length)
                      {
                         // Is the entered string different to what is stored in clipboard?
                         if (sNewAlignString != sAlignString)
                         {
                            // Write this alignment string to clipboard 7 for next run of the script.
                            sAlignString = sNewAlignString;
                            UltraEdit.clipboardContent = "LastAlignString=" + sAlignString;
                         }
                      }
                      
                      // Select the standard clipboard of the operating system.
                      UltraEdit.selectClipboard(0);
                      
                      This script snippet is designed for keeping the value of only 1 variable in user clipboard 7. Of course it is possible to use any other of the 9 user clipboards. And it is also possible to keep multiple variables in a single user clipboard even from different scripts if the code in all scripts is written accordingly for example by using an INI file like structure for the data in the user clipboard.

                      Variable values stored in a user clipboard can be read only by scripts executed within same editing session. The values are lost once UE/UES instance is terminated. And each instance of UE/UES has its own "variable buffer" as the user clipboards are not shared between the running instances of UE/UES like the clipboard of the operating system.
                      Best regards from an UC/UE/UES for Windows user from Austria