Þorvarður wrote: ↑2021-06-21 05:42:47 You are using commands that I'm not yet familiar with (substring, deleteInRange, insertAtIndex), and I have forgotten why you always do things in reversed order.
The key to such macros is the thing NWP calls a
TextSelection object. This isn't really a difficult concept. A TextSelection—I'll just call it a selection from now on—is pretty much the analog to the thing that you can create with the cursor; it's a run of characters out of larger text. The way NWP handles these is by remembering, as a unit, the starting point, the length, and the text (object) on which the selection is made, or maybe I should say intended. That's because NWP doesn't actually make the selection. So it's more of a "potential" or "virtual" selection.
So let's consider an example. Imagine I had the following text:
This is an apple. Would you like an apple?
Now let's compare the following two commands:
Code: Select all
Find All 'apple'
$doc.text.findAll 'apple'
The first will select and "hilite" the two instances of the word "apple".
The second will not visibly do anything. Instead it will return two such "virtual" selections. As already noted these selections are determined by starting point, length, and text (object). The starting point of the first instance of "apple" is 11, the length 5, and the text is a Nisus internal identifier for this text object. The second instance is pretty much the same, except that the starting point is 36.
One point to keep in mind with this is that the
text of a selection is always the entire (larger) text on which the selection is being made. The part that is actually selected—the word "apple" in this case—is the
subtext. The two numbers that pick the selection out of the larger text can be viewed as a unit, in which case we call them the
range.
The neat part of all of this is that we can now manipulate the larger text using this information. Nisus text objects have a large number of commands that allow us to edit the text using such information.
.deleteInRange will logically enough delete the part of the text that is specfied by the range. So if we use the range of the first instance of "apple", then the .deleteInRange command would result in the following text:
This is an . Would you like an apple?
Similar commands can be used to replace parts, add parts, etc.
Okay, now why do we need to edit such text objects in reverse order? The "weak" point of such selections is that they really just consist of such range information, and the range really just consists of numbers. The selection is "virtual". If I wait too long, the text object might change, and then the range numbers might be "off", and no longer point to the part of the text object originally intended.
Imagine I replaced the first instance of "apple" with "banana". Now my whole text object will be one character longer (because "apple" has 5 letters and "banana" has 6). But this also means that the starting point of the second instance of "apple" will change from 36 to 37. Conversely the range defined by the numbers 36 and 5 will now point to the subtext " appl" rather than the intended "apple". So we will want to work backwards, because changes always push towards the end. If we replace the second instance first, it will still be in the correct location. And even though the overall length of the text changes, the first instance will still be in the same spot as before.
We might call this "don't look back" editing mode, the "Louis XIV principle" (Après moi le deluge!).
The last small point is the
.substring command. This is just the same as subtext, except that we ignore the formatting. One could have used either. But in general if the formatting is not germane to the task, I use the string variant.
Hope this makes things a bit clearer.