Insert sequential line number only after specific character

Insert sequential line number only after specific character

4
NewbieNewbie
4

    Jun 09, 2021#1

    Hello,

    I'm using an older programming language called ATLAS and with this language you have to manually add line numbers which can be a daunting task when editing someone else's old code. I've read other posts on this forum about using the Insert Number function but none of them seem to address this scenario.

    My question/scenario is as follows: I need to add a line number but only after a specific character is detected. It's important to note that the line numbers are in column 2 to column 8. Is it possible for this to be achieved by a script? Or maybe I'm not using the Insert Number function correctly?

    A line end is signified by the dollar sign $. Here's an example of how the code looks.

    Code: Select all

     000100        *some code here*    $
     000101        *some more code here*       $
     000102        *this time we have some code
                                 that spans over multiple lines so
                                 I don't want to put a line number 
                                 on these lines*        $
     000103        *some more code*        $
    

    6,688587
    Grand MasterGrand Master
    6,688587

      Jun 10, 2021#2

      It is definitely possible to renumber the lines with a script. But the requirements for coding the script are not really clear for me.
      1. What is the rule to determine that an incremented line number with always six digits must be inserted or must replace an existing line number at column 2?
      2. You wrote: "only after a specific character". What is the specific character - an asterisk?
      3. Do you mean if the first character after the line number or leading spaces/tabs is an asterisk?
      4. Are always just spaces used between line number and code or is there a horizontal tab character or is both possible?
        That must be known for fine alignment on inserting a six digit line number.
      5. Does the line counting on first code line start with 000000 or with 000001?
      6. Which version of UltraEdit do you use on which platform?
      7. What is the typical file size of the ATLAS source code file?
        That is important to know as on small files with less than 20 MB it is more efficient to load all lines into memory of script interpreter, process them there and then output all lines as a block back to the file replacing all existing lines or just the lines from first line with modified line number to the end of file producing just one undo record and a few window updates instead of updating one line after the other in the file causing lots of undo records and lots of window updates which cause a long script execution time.
      8. Is it possible that the ATLAS source code files contain characters not included in code page for an ANSI encoded file according to country configured for your user account? In other words: Is it necessary to support also Unicode encoded ATLAS source code files?
        Support for Unicode encoded files could be very easy or very difficult depending on used version of UltraEdit. I suppose that ATLAS does not really support Unicode encoded files because of being an old programming language, but who knows which characters are used by you in comments on using UTF-8 encoding without byte order mark (BOM).
      Best regards from an UC/UE/UES for Windows user from Austria

      4
      NewbieNewbie
      4

        Jun 16, 2021#3

        Thank you for the response Mofi, see my answers below on your eight questions.
        1. The rule that a line number must be inserted or replace what's at column 2 is if the previous line ended with the dollar sign character $.
        2. The specific character is the united states dollar sign $.
        3. The start of a new numbered line only occurs when the previous line last character was a dollar sign $.
        4. Thank you for bringing this up, so we have to use spaces if we use tabs it messes up the compiler.
        5. 000001 - I want to clarify that each file starts at 000001, we don't have to continue the numbering across files.
        6. I use UltraEdit x64 version 25.20.0.88, but most of my colleagues are stuck on an old version 15.00.0.1047.
        7. I can't get an accurate average, but we're below 20 MB. I have never seen anything larger than 1 MB.
        8. There is no need to support Unicode encoding. The compiler recognizes a comment by the letter C in column 1. To my knowledge and the research that we've done, I don't think there's any Unicode encoding.

        6,688587
        Grand MasterGrand Master
        6,688587

          Jun 16, 2021#4

          Okay, the requirements for the coding of the script are quite clear now for me.

          I thought the $ was just used as a placeholder in the code template to mark the end of the lines with trailing whitespaces, but that character is really in the file with very important meaning.

          I think, it should be no problem for me to code a script on weekend which works with UltraEdit for Windows version 15.00.0.1047 and version 25.20.0.88.
          Best regards from an UC/UE/UES for Windows user from Austria

          4
          NewbieNewbie
          4

            Jun 17, 2021#5

            @Mofi Wow! Awesome! Thank you for the help I (we all) appreciate it! And yes you are correct the $ character is very important.

            6,688587
            Grand MasterGrand Master
            6,688587

              Jun 19, 2021#6

              Here is the script for this task tested with UltraEdit for Windows v15.00.0.1047 and v25.20.0.88 on a file with 70450 lines and 3.422.016 bytes which has 3.663.296 bytes after script execution due to the massive required changes done in less than two seconds with UE v25.20.0.88. The processing of the lines with UE v15.00.0.1047 is as fast as with UE v25.20.0.88, but UE v15.00.0.1047 takes four seconds to overwrite nearly the entire file content as necessary on my test and for that reason does the task in less than six seconds.

              The script was tested by me with file being a DOS, UNIX or MAC file opened without or with temporary conversion to DOS on being a UNIX or MAC file. I could not believe it, but the correct finding of line termination type was much more difficult than I thought.

              Code: Select all

              if (UltraEdit.document.length > 0)  // Is any file opened?
              {
                 // Define environment for this script.
                 UltraEdit.insertMode();
                 if (typeof(UltraEdit.columnModeOff) == "function") UltraEdit.columnModeOff();
                 else if (typeof(UltraEdit.activeDocument.columnModeOff) == "function") UltraEdit.activeDocument.columnModeOff();
              
                 // Get line and column number of the caret in the active file.
                 var nCaretLineNumber = UltraEdit.activeDocument.currentLineNum;
                 var nColumnNumber = UltraEdit.activeDocument.currentColumnNum;
                 if (typeof(UltraEdit.activeDocumentIdx) == "undefined") nColumnNumber++;
              
                 UltraEdit.activeDocument.selectAll();
                 if (UltraEdit.activeDocument.isSel())
                 {
                    // Determine the line termination type from the first line.
                    var asLineTerm = UltraEdit.activeDocument.selection.match(/\r?\n|\r/);
                    var sLineTerm = (asLineTerm != null) ? asLineTerm[0] : "\r\n";
                    // Load all lines into memory of script interpreter as an array of strings.
                    var asLines = UltraEdit.activeDocument.selection.split(sLineTerm);
              
                    // Define and initialize the variables.
                    var bInsertNumber = true;
                    var nFirstNonSpaceIndex;
                    var nFirstModifiedLine = 0;
                    var nLineNumber = 0;
                    var sCurrentLine;
                    var sLineNumber;
                    var sSpaces = "        ";
                    var sZeros = "000000";
              
                    // Process all lines of the file one after the other.
                    for (var nLine = 0; nLine < asLines.length; nLine++)
                    {
                       sCurrentLine = asLines[nLine];
                       if (!sCurrentLine.length)  // Is the current line an empty line?
                       {
                          bInsertNumber = true;   // Insert number on next non-empty line.
                          continue;               // Do nothing on the empty line.
                       }
                       if (bInsertNumber)         // Must this line have a line number?
                       {
                          // Build the string with a space and the six digit
                          // incremented line number with leading zeros.
                          nLineNumber++;
                          sLineNumber = nLineNumber.toString(10);
                          sLineNumber = " " + sZeros.substr(sLineNumber.length) + sLineNumber;
                          // Replace the space character and the six digits or seven spaces
                          // at beginning of the line with the incremented line number.
                          sCurrentLine = sCurrentLine.replace(/^ \d{6}\b| {7}/,sLineNumber);
                          // Insert the line number at beginning if the line does not start
                          // with a space and a six digit number or with at least seven
                          // spaces with inserting also up to eight spaces for alignment.
                          if (sCurrentLine.substr(0,7) != sLineNumber)
                          {
                             nFirstNonSpaceIndex = sCurrentLine.search(/[^ ]/);
                             // Has the current line less than eight spaces left
                             // to the first character not being a space character?
                             if (nFirstNonSpaceIndex < 8)
                             {
                                // Has the line no character not being a space character?
                                if (nFirstNonSpaceIndex < 0)
                                {
                                   nFirstNonSpaceIndex = sCurrentLine.length;
                                }
                                sLineNumber += sSpaces.substr(nFirstNonSpaceIndex);
                             }
                             sCurrentLine = sLineNumber + sCurrentLine;
                          }
                       }
                       else
                       {
                          // This line should have no line number and so replace the
                          // line number with spaces if this line has a line number.
                          sCurrentLine = sCurrentLine.replace(/^ \d{6}\b/,"       ");
                       }
                       // Is the updated current line different to the line in the file?
                       if (sCurrentLine != asLines[nLine])
                       {
                          // Replace the line read from file by updated line.
                          asLines[nLine] = sCurrentLine;
                          // Is that the first time a line is modified by the script?
                          if (!nFirstModifiedLine)
                          {
                             // Remember the line number of first modified line in file.
                             nFirstModifiedLine = nLine + 1;
                             // Is the first modified line not the first line in the file?
                             if (nLine)
                             {
                                // Remove all not modified lines from the
                                // array before the first modified line.
                                asLines.splice(0,nLine);
                                nLine = 0;
                             }
                          }
                       }
                       bInsertNumber = (sCurrentLine[sCurrentLine.length-1] == "$") ? true : false;
                    }
              
                    if (nFirstModifiedLine) // Is any line modified?
                    {
                       // Set caret in active file to beginning of first modified line.
                       UltraEdit.activeDocument.gotoLine(nFirstModifiedLine,1);
                       // Select all lines to the end of the file.
                       UltraEdit.activeDocument.selectToBottom();
                       // Join the lines in array together to a single string which is
                       // copied to user clipboard 9 or 8 in case of active clipboard
                       // is the user clipboard 9. Then paste the lines from clipboard
                       // into active file with overwriting the selection, clear the
                       // used user clipboard and reselect previously active clipboard.
                       var nClipboardIndex = UltraEdit.clipboardIdx;
                       UltraEdit.selectClipboard((nClipboardIndex != 9) ? 9 : 8);
                       UltraEdit.clipboardContent = asLines.join(sLineTerm);
                       UltraEdit.activeDocument.paste();
                       UltraEdit.clearClipboard();
                       UltraEdit.selectClipboard(nClipboardIndex);
                       // The next line is in real only needed for a MAC file opened in
                       // UE v15.00.0.1047 with a temporary automatic conversion to DOS.
                       UltraEdit.activeDocument.top();
                       UltraEdit.activeDocument.gotoLine(nCaretLineNumber,nColumnNumber);
                    }
                    else
                    {
                       UltraEdit.activeDocument.gotoLine(nCaretLineNumber,nColumnNumber);
                       UltraEdit.messageBox("All lines are already correct numbered.");
                    }
                 }
              }
              
              I was not sure how to handle empty lines. The script does nothing on an empty line, but always inserts/updates the incremented line number on next non-empty line. If an empty line should be ignored completely regarding to line number incrementing, it would be necessary to remove from the script the line:

              Code: Select all

                          bInsertNumber = true;   // Insert number on next non-empty line.
              Best regards from an UC/UE/UES for Windows user from Austria

              4
              NewbieNewbie
              4

                Jun 21, 2021#7

                Thank you Mofi! This works almost flawlessly! Question for you, what coding environment are you using to write these scripts? I see that they're JavaScript, right? Are you using an IDE? How do you debug them? Please teach me how to fish! :)

                Thanks a million!
                -Greg

                6,688587
                Grand MasterGrand Master
                6,688587

                  Jun 21, 2021#8

                  UltraEdit is used to write an UltraEdit script using JavaScript core interpreter. Debugging is usually not necessary for me, but can be down with using var_dump(variable) (not available in UE v15.00.0.1047), or UltraEdit.outputWindow.write("string without or with variable value(s)") on which script execution does not pause and UltraEdit.messageBox("string without or with variable value(s)") on which script execution is paused until user clicks on button OK.
                  Best regards from an UC/UE/UES for Windows user from Austria