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.