MultiEd's Icon


Macros: Loops

The tutorial looks at the writing macros that loop. It assumes that you are already familiar with macros. If not, it is suggested that you look at the first 3 lessons in the Introduction to macros Tutorial.

Lesson 1: A simple loop

For example of using loops, suppose that you have a text file that contains "<" and ">" symbols that you want to convert to a web page. One of the first things that you need to do is replace the "<" and ">" by "&lt;" and "&gt;". Lets write a macro to replace all these symbols.

{Sleep 300}<{HOME}>{Loop}{Find <}{IfFound &lt;}{EndLoop}<{HOME}>{Loop}{Find >}{IfFound &gt;}{EndLoop}

Do not press the "Enter" key when typing this macro.
If you copy and paste it, don't include any blank lines

Lets look at the first half of the macro in detail.

The {Loop} and {EndLoop} virtual commands can also be used with the commands {NextLine}, {NextBlankLine}, {NextIndentedLine} and even with {F3}(search) if either the top or bottom find/replace panel is being used.

*** Optional command for debugging
{Sleep 300}{Comment
*** Replace & by &amp;
<{HOME}>{Loop}{Find &}{IfFound &amp;}{EndLoop}{Comment
*** Replace < by &lt;
<{HOME}>{Loop}{Find <}{IfFound &lt;}{EndLoop}{Comment
*** Replace > by &gt;
<{HOME}>{Loop}{Find >}{IfFound &gt;}{EndLoop}{Comment
*** Insert a break tag at the beginning of every line after the first
<{HOME}>{Loop}{NextLine}{IfFound {Literal <br>}}{EndLoop}

Right click to download LoopsLesson1.macro.

Perhaps you wondered how these macros macros converted to html so it could be shown in this web page. It was complicated because "&" had to be converted to "&amp;" before we could convert the "<" and ">"s. And break tags had to be added to the beginning of every line to preserve the line structure. Doing all the conversions manually would have been a long, error prone process. So the macro shown in this section was used to convert both the original macro and itself! There are two new loops. Notice first was used to convert "&" to "&amp;". It had to be the first loop to avoid changing the "&"s in the substitutions for "<" and ">". The last loop inserts the breaks at the beginning of every line (other than the first line.) Comments were added to make the macro more readable.

The macro was copied to a new file and then run. The result was copied into the .html page. The tags to color the text were then added.

Adding the break tags required two new virtual commands.

Probably the best way to test the longer macro is copy it from the box and paste it to an empty .html file and then into an empty Macro Control window. (Make sure you do not include a blank line when you copy the macro.) Try clicking the WEB button to see the unacceptable representation of the file. Then after running the macro, click the WEB button again to view the results in your browser. You can also test it on the shorter macro.

Lesson 2: A double loop

Lets suppose that you have a web page with several ordered (<ol>) and unordered (<ul>) lists. To avoid complications, we will assume that file does not contain nested ordered lists. We want to change the list items in the ordered list to use the "olListItem" class but don't want change the unordered lists. To accomplish this, we will change <li> to <li class="olListItem"> but only if the item is in an ordered lists. That means we will have to search for all the ordered lists and when we find one, we will have to search for all the <li>'s in that list.

{Loop}{Find <ol}{IfFound {SetMarker end}{Find </ol>}{SetSelection}
... }{EndLoop}

This will take a double loop. The outer loop will search for "<ol". (We only search for "<ol" in case the tag has attributes.) After it is found, the inner loop will search for "<li>". The problem is that the search will have to be restricted to the ordered list. To do this after finding "<ol" we will need to find the end of the ordered list denoted by the tag "</ol>" and select the entire list. This requires that we set a marker at the beginning of the list before we do the search for the end of the list. Then after we find the end of the list, we can select the entire list.

{SetMarker end}{Loop}{FindInSelection <li>}{IfFound {literal <li class="olListItem">}{SetSelection}}{EndLoop}

Lets turn to the inner loop. We will need to restrict our search to the selection using {FindInSelection "<li>"} If it is found, we need to replace the tag with "<li class="olListItem">". Before ending the loop, we need to remember at this point, there is no selection. But we are restricting the search to a selection. Solution: Before starting the loop we need to set a marker at the end of the ordered list which has already been selected. After typing the new tag, we will set the selection again. The new selection will go from the end of the new tag to the end of the ordered list.

{Sleep 300}{Comment
****** Start loop to find an ordered list and select the entire list
}<{HOME}>{Loop}{Find <ol}{IfFound {SetMarker end}{Find </ol>}{SetSelection}{Comment
****** Now find the <li> in the selection, change it, and preserve
****** the remainder of the selection
}{SetMarker end}{Loop}{FindInSelection <li>}{IfFound {literal <li class="olListItem">}{SetSelection}}{EndLoop}{Comment
****** If inner loop was executed, there was success in finding <ol
****** End of outer loop

If you type this macro, remember that you should press enter only inside of comments.
If you copy the macro, be sure to not copy any extra spaces or empty lines. Right click to download

We are almost done. To make sure that we process the entire file, we need to move the cursor to the beginning of the file. This can be done using "<{HOME}>". A more important problem is that the inner loop will always end with a failure - the failure to find another "<li>". But the search for "<ol" was a success or we wouldn't have been processing the inner loop and we need to search to see if there is another ordered list. Hence we need to add the "{Success}" command before ending the outer "{IfFound ,,,}". The "{Sleep 300}" command was added as a debugging aid and should be removed after the macro works correctly to speed things up significantly. But watching the macro work in slow motion is a great aid in understanding how it works.

A test page is available at TestPages/LoopsLesson2.html. THE BEST WAY TO USE THE LINK is to right click and save it to a file. Then load the file into MultiEd. The complete macro can be found at TestPages/LoopsLesson2.macro. But you can test the macro by just copying the box into an empty Macro Control window and the clicking the "Run" button..

- - - - - -

{SetMarker end}{Loop}{FindInSelection<li }{IfFound {SetMarkerA}{Find >}{SetSelectionA}{literal <li class="olListItem">}{SetSelection}}{EndLoop}

A careful reader would note that we searched for "<li>" in the inner loop. What if that tag has some attributes? The situation gets much more difficult. A common solution for this type of situation is to use the code something like this:

{FindInSelection <li}{IfFound {SetMarkerA}{Find >}{SetSelectionA} ... }

The "A" at that end of the {SetMarkerA} and {SetSelectionA} specify that we want to use an alt marker leaving the original marker at the end of the ordered loop unchanged. At that point the entire tag has been selected just as in the original macro.

The complete macro can be found at TestPages/LoopsLesson2Adv.macro. It can be pasted into the Macro Control Window. A test page is available at TestPages/LoopsLesson2Adv.html . THE BEST WAY TO USE THE LINK is to right click and save it to a file. Then load the file into MultiEd and view it in your browser. Then click the "Run" button in the Macro Control and load the resulting page into your browser.

For additional examples of using macros, see MultiEd's help page ~Macro examples~. For a tutorial on macros that begins with the basics, see the Introduction to Macros tutorial.

You are encouraged to contact me a with comments about these tutorials and suggestions for improving them.

Return to the beginning of this file         Return to the tutorial home page

Revised: 10/5/2011