Inserting characters before/after selected text

Inserting characters before/after selected text

18
Basic UserBasic User
18

    Jun 17, 2011#1

    Can someone help me? How would I script to add characters at the beginning and of a highlighted string? For instance, say you have:

    The quick brown fox jumps over the lazy dog's back.

    Quick through fox is highlight, as simulated above by the red lettering. How would I add in (begin) before "quick", and (end), after "fox"?

    Thanks.

    6,603548
    Grand MasterGrand Master
    6,603548

      Jun 17, 2011#2

      With a script this is very easy because scripts support variables and selected text is a string object. Therefore the script can be coded to insert text around selected text with a simple write command as demonstrated below for inserting (begin) at beginning and (end) at end of a selection.

      Code: Select all

      // Execute this script only with any file opened and column mode not enabled.
      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)
         {
           // The script can't be used for a selection in hex edit mode.
           if (!UltraEdit.activeDocument.hexMode)
           {
               if (UltraEdit.activeDocument.isSel())
               {
                  var bInsertMode = (typeof(UltraEdit.insOvrMode) == "boolean") ? UltraEdit.insOvrMode : true;
                  UltraEdit.insertMode();
                  // The replace is for duplicating every ^ because on write every ^^ is written as ^.
                  UltraEdit.activeDocument.write("(begin)" + UltraEdit.activeDocument.selection.replace(/\^/g,"^^") + "(end)");
                  if (!bInsertMode) UltraEdit.overStrikeMode();
               }
               else  // Tell McFly that something isn't selected.
               {
                  UltraEdit.messageBox("HELLO! McFly, select some text!", "Nothing Selected...");
               }
            }
         }
      }
      Duplicating every ^ in selected string is only required if at Advanced - Configuration - Search - Miscellaneous the character ^ is set for setting Special character used in find/replace strings (normally ^) as it is by default to be able to use in non regular expression finds/replaces the special characters as listed in table of the Find/Replace command help pages. This character is also used as special character for UltraEdit regular expression finds and replaces, see first table on help page Regular Expressions (Legacy). The Unix and the Perl regular expression engines use a backslash character as special (escape) character.

      In my point of view the special character should not be active on simple write, just for finds and replaces. But in UE v17.10.0.1015 it is necessary to escape every ^ with an additional ^ to get right content written into the file.

      Edit: This issue was fixed with UE v23.20.0.34 and UES v16.20.0.7. Since these versions of UE/UES character ^ in a string to write into a file with command write is interpreted always as a literal character and must not be escaped anymore with one more ^.

      2
      NewbieNewbie
      2

        Aug 01, 2011#3

        I need a simple script that does exactly what this script does... Problem I'm working with a Scala file so therefore (I assume because RegEx can be used in write) the written text has been modified. Currently I need to create blocks on Scala code that has ^^ characters. The script as written converts ^^ to ^. It's scala code so it's a problem for most editors as scala is essentially a really massive ANTR parsing mechanism. So I don't know if it's going to foul other parts of scala code as well. Anyway... is there some simple way to get the character position start of selection and then move to the end of the current selection insert ending text then move to where the start of the selection was and insert the starting text. Obviously order of insertion doesn't matter but I assume the if I can get character positions I need to do the end first so that the starting position won't change before I insert starting text.

        I want:
        selected text
        to yield
        {selected text}

        Current Problem selected text

        Code: Select all

        """[^=].*""".r ^^ Textual
        currently yields:

        Code: Select all

        {"""[^=].*""".r ^ Textual}
                         ^ missing second caret
        I did find UltraEdit.activeDocument.currentPos but I can't find it's complement UltraEdit.activeDocument.goToPos. Further it's not clear how to "unselect" preferably "toEnd" or "toStart" and I assume currentPos will return start, and I should be able to get current selection length (So long as the RegEx won't foul that as well)

        6,603548
        Grand MasterGrand Master
        6,603548

          Aug 01, 2011#4

          I have not known until now that UltraEdit converts on write a ^^ character sequence to just ^. I have modified my script to workaround this problem and you can now use it for your Scala files.

          Edit: With UE v23.20.0.34 and UES v16.20.0.7 it is not necessary anymore to escape each ^ with one more ^ in a string to write with command write into a file because this issue was fixed in these versions of UE/UES.

          2
          NewbieNewbie
          2

            Aug 01, 2011#5

            Thanks for the quick response. I'm just learning scala so I don't know if ^^ is the only problem. I'm still trying to figure out something that completely bypasses the problem, i.e. positioning of some kind. Maybe bookmarks or something.

            Code: Select all

            var lineNum = UltraEdit.activeDocument.selection.currentLineNum;
            var colNum = UltraEdit.activeDocument.selection.currentColumnNum;
            
            UltraEdit.activeDocument.key("RIGHT ARROW");
            UltraEdit.activeDocument.key("LEFT ARROW");
            UltraEdit.activeDocument.write("}" + Pos );
            
            while( Pos > UltraEdit.activeDocument.currentPos )
                UltraEdit.activeDocument.key("LEFT ARROW");
            
            //UltraEdit.activeDocument.write("{");
            The code above doesn't work, but perhaps following:
            • Make a temporary bookmark of selected,
            • move to end of selection,
            • insert ending text,
            • goto bookmark,
            • move to start of selection,
            • insert starting text,
            • remove temporary bookmark.
            It's almost as if fighting the editor is the problem, i.e. updating the document while the script is running. I'm fully aware that this is a problem which is why my attempts are working with the end first.

            How about getting to the file somehow?

            6,603548
            Grand MasterGrand Master
            6,603548

              Aug 01, 2011#6

              Modifying content of a file with a script while file content can be changed outside by another application will produce surely often damaged files.

              I have posted at Insert characters/strings before and after selected block several methods how to insert strings or tags around a selection. I prefer for myself for the most often needed "insert string" cases the solution with templates because they offer the fastest and best method, especially because it works also if nothing is selected and caret position after template execution can be controlled. For the rarely used cases I use tags and the tag list view.

              Macros and scripts are those which are often used by users not knowing that the templates and tags features offer the same much easier.

              I have analyzed in the meantime why for ^^ in selection a temporary replacement in memory with ^^^^ is necessary and explained the reason in my initial post at bottom of the script. You can be 100% sure that this does not happen on other characters. And I will report this issue additionally by email to IDM support because in my point of view the script command UltraEdit.activeDocument.write() should not simply write ^^ as is into the file as UltraEdit.outputWindow.write() does for printing the same string into the output window.

              Edit: This wrong behavior was fixed with UE v23.20.0.34 and UES v16.20.0.7.


              But to answer your question because you want to insert strings around current selection as much complicated as possible, here is a first approach for a script solution:

              Code: Select all

              // Execute this script only with any file opened and column mode not enabled.
              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)
                 {
                    // The script can't be used for a selection in hex edit mode.
                    if (!UltraEdit.activeDocument.hexMode)
                    {
                       if (UltraEdit.activeDocument.isSel())
                       {
                          var bInsertMode =(typeof(UltraEdit.insOvrMode) == "boolean") ? UltraEdit.insOvrMode : true;
                          UltraEdit.insertMode();
                          var nLine = UltraEdit.activeDocument.currentLineNum;
                          var nColumn = UltraEdit.activeDocument.currentColumnNum;
                          // Depending on version of UltraEdit the returned column number
                          // starts counting the columns with 0 or with 1, but for setting
                          // the caret always a column count starting with 1 is required.
                          if (typeof(UltraEdit.activeDocumentIdx) == "undefined") nColumn++;
                          var nSelectedChars = UltraEdit.activeDocument.selection.length;
                          UltraEdit.activeDocument.endSelect();
                          UltraEdit.activeDocument.gotoLine(nLine,nColumn-nSelectedChars);
                          UltraEdit.activeDocument.write("{");
                          UltraEdit.activeDocument.gotoLine(nLine,nColumn + 1);
                          UltraEdit.activeDocument.write("}");
                          if (!bInsertMode) UltraEdit.overStrikeMode();
                       }
                       else  // Tell McFly that something isn't selected.
                       {
                          UltraEdit.messageBox("HELLO! McFly, select some text!", "Nothing Selected...");
                       }
                    }
                 }
              }
              But this solution has several problems:
              • It works only for selections within a line. It does not work for multi-line selections. Multi-line selections would need analyzing the selected strings to find out how many lines are selected and how many characters are selected at end of first and at beginning of last selected line. This is not so easy, especially because of type of line terminator can be either DOS, or UNIX or MAC. Uuaargghh! I don't want to think further here.
              • The returned line and column numbers are for current position of caret in the file. But from within a script it is not possible to determine if the caret is blinking at end of the selection because selection was made from left to right respectively top to bottom by the user, or is blinking at beginning of selection because the user selected from right to left respectively bottom to top.
              Another solution:

              Code: Select all

              // Execute this script only with any file opened and column mode not enabled.
              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)
                 {
                    // The script can't be used for a selection in hex edit mode.
                    if (!UltraEdit.activeDocument.hexMode)
                    {
                       if (UltraEdit.activeDocument.isSel())
                       {
                          var bInsertMode = (typeof(UltraEdit.insOvrMode) == "boolean") ? UltraEdit.insOvrMode : true;
                          UltraEdit.insertMode();
                          var nPosition = UltraEdit.activeDocument.currentPos;
                          var nSelectedChars = UltraEdit.activeDocument.selection.length;
                          var_dump(nPosition);
                          UltraEdit.activeDocument.gotoPos(nPosition);
                          UltraEdit.activeDocument.write("{");
                          nPosition += nSelectedChars + 1;
                          UltraEdit.activeDocument.gotoPos(nPosition);
                          UltraEdit.activeDocument.write("}");
                          if (!bInsertMode) UltraEdit.overStrikeMode();
                       }
                       else  // Tell McFly that something isn't selected.
                       {
                          UltraEdit.messageBox("HELLO! McFly, select some text!", "Nothing Selected...");
                       }
                    }
                 }
              }
              
              Command UltraEdit.activeDocument.gotoPos(nPosition); requires UltraEdit v17.10 or later. It does not exist in previous versions of UltraEdit. UltraEdit.activeDocument.currentPos contains always the byte position (not character position which is different to byte position for Unicode files) at beginning of the selection independent of caret position, i.e. independent of direction of selection. So this script solves both problems of previous script.

              But depending on string length inserted at beginning the number after nPosition += nSelectedChars + must be always correct set which makes writing such scripts more problematic than my initial script which does not depend on which strings are inserted at beginning and end of the currently selected text.

              The script above works fine only for ASCII/ANSI files because for single byte encoded text files without BOM the byte position is equal the character position. But for Unicode files it does not work because the command UltraEdit.activeDocument.gotoPos(); requires the character position and not the byte position. So for Unicode files (with a BOM) the line

              Code: Select all

                      var nPosition = UltraEdit.activeDocument.currentPos;
              must be replaced by

              Code: Select all

                      var nPosition = (UltraEdit.activeDocument.currentPos - 2) / 2;
              to get the correct result. For UTF-16 files without BOM - 2 needs to be removed. In other words, this solution can work for one user, but might not work for another user because of using different type of files.

              Also this solution produces two undo steps, while my initial script solution as well as using a template, a tag, or the first macro solution (see referenced topic) produces only one unto step.

              It's up to you if you want a simple solution as I suggested by using templates, tags, macros (could be coded also as scripts), or my initial script, or if you want a complicated solution with line/column or byte/character positioning with all their disadvantages.

              PS: UltraEdit.activeDocument.currentPos was initially designed for hex editing mode which is the reason why it contains the number of bytes from top to current position in the file. The command UltraEdit.activeDocument.gotoLine() is in hex edit mode in real a "goto byte offset" command as you can see when you press Ctrl+G in text edit mode versus Ctrl+G in hex edit mode. But the users requested a "goto character position" unfortunately without taking into account that property currentPos does not contain always the number of characters from top to current position in the file because that is true only for ASCII/ANSI files.