Creating a recursive macro

I know there are tools out there to do this, and I will probably end up using one of them. But I’m curious as to why my own approach is not working.

Add this to an existing wiki to see the failing behavior: hierarchyTest.json (940 Bytes)

The idea is that TiddlerC has field parent with value "TiddlerB". And TiddlerB as parent of TiddlerA. This macro, when fed TiddlerC should return the list "TiddlerA", "TiddlerB", and "TiddlerC". But it just returns "TiddlerC".

Is the following code conceptually close, requiring just a tweak? Or is it fundamentally misguided?

\define hierarchy-body(title)
<$list filter="""[<__title__>parent[]]""" variable="parent">
<$macrocall $name="hierarchy-body" title=<<parent>>/>
</$list>
<li>$title$</li>
\end

\define hierarchy(title)
<ul>
<$macrocall $name="hierarchy-body" title={{{ $title$ }}}/>
</ul>
\end

Result: <<hierarchy "TiddlerC">>

It would be really good if you showed the output you would like vs the output that you are getting.

Hi,
Try this. But there is no recursion protection other than the inner list !is[blank]. So there is a lot that can break stuff.

The inner list is only there to stop.

The recursion builds the list, not the list-widget

\define hierarchy-body(title)
<li><<__title__>></li>  <!-- Move it to the end to change the order -->
  <$let parent={{{ [<__title__>get[parent]] }}}>
    <$list filter="[<parent>!is[blank]]">
      <$macrocall $name="hierarchy-body" title=<<parent>>/>
    </$list>
  </$let>
\end

\define hierarchy(title)
<ul>
<$macrocall $name="hierarchy-body" title=<<__title__>>/>
</ul>
\end

Result: <<hierarchy "TiddlerC">>

have fun!
mario

1 Like

Thank you. That did it precisely, although I did move the current element to the bottom.

I will probably find one of the existing solutions out there instead of this, but, not having done anything like this before, I wanted to try it, and couldn’t figure out if my problem was a syntax issue or a fundamental logical one. It looks like it was mostly syntax, still my bane in TW!

If I did want to create further protections, I would expect to keep a list of visited nodes and stop when the current value is already in that list. Is there anything else substantive required?

Thank you very much for the help!

1 Like

Sorry, I was aiming for something equivalent to

* [[TiddlerA]]
* [[TiddlerB]]
* [[TiddlerC]]

but only received

* [[TiddlerC]]

The markup details aren’t terribly important, as they would likely change for my real use-case. Properly performing recursion in a TW macro is the main issue, and, per @pmario, it looks like I was reasonably close… for some definition of “reasonably”. :slight_smile:

One follow-up, if I may.

Is there a straightforward way of doing the same as the above but simply creating a list of titles rather than markup? I assume it wouldn’t be a macro, which, I believe, are mostly meant to create HTML, but would there be some useful way of writing a recursive filter or some such? I’m still working in a 5.2.5 mode, but the wiki I’m working on is new enough that I should be easily able to upgrade if the 5.3 tools would make it easier.

You can feed the <currentTiddler> into the <$text /> widget inside each loop, instead of HTML, to get a plain-text output.

Or use the <$link /> widget to get just a title link.

Thank you. I’m on to the next problem. But I will try that soon.

The important behaviour of recursions is, that it builds the “tree”. You do not need to use list widgets to “gather” the elements like for tag-based solution.

Yea it should work that way.

Just to be sure. Using “macros” will create a completely different code, than using “procedures” and “functions” with v5.3.0. So there will be a lot to experiment with.

have fun!
mario

Note that the last of visited nodes need only be the current branch not the whole list.

There are existing discussions elsewhere in recursion.

I have included protection by testing the current leaf/node is not in its own branch, but not yet come up with a solution that is easy to read and use by a broad audience.

  • this may prove easier in 5.3.0

By the way upgrading wikis can be trivial and as long as you have a backup is quite safe. I have already upgraded a few large daily use wikis with no problems.

In this case, it’s not really a tree, or perhaps it’s a degenerate one.

Although the parent relation describes a tree overall, here I start from the bottom and need only the path from the root to the leaf – definitely easier than the tags hierarchy.

When we were discussing breadcrumbs a few months ago, I came up with some Javascript code to do this, but when my TW work went on hold, I never followed up to try to get it working in TW. I hope to get back to that soon.

Yes, I look forward to trying that. I haven’t really gotten my head around the changes yet.

Yes, I have done several conversions. But what I really want to do with 5.3.0 is to take the time to update the older techniques I’ve used to the newer ones wherever it makes sense. That’s a much bigger job. I’m excited for it and nervous about it all at once.

  • Recurcive macros do produce the complete tree on screen, its inside the process of “walking the tree” that we are out on a branch. It is only here we need to test the current tiddler is not in its own branch, for simple loops.
  • I belive this is true, even in the case of loops caused by two or three links, because as soon as you start to get in a loop it will not continue, but I need to more rigorously confirm this again, from memory its true.

Right. I certainly could use a recursive macro to display the whole tree, but I’m using this one to display the path from the root to a particular leaf. “Recursive” here simply means that the macro calls itself. If I had a parent-child hierarchy tree like this:

      _____A_____
     /	         \
  __B__         __G__
 /     \       /     \
C	  __D__   H       I
     /     \          |
    E       F         J 

I could use a macro to capture that whole thing in, say, nested lists. But what I need it for is to display a breadcrumb-like list of links. Each tiddler in this particular hierarchy has a title and a url, and in tiddler F I want to display it this like

Link to A > Link to B > Link to D > Link to F .

This is much simpler than our earlier breadcrumbs discussions because my data is in a single tree, and not as with tags, in possibly multiple positions.

The answers are in previous discussions including two additional operators, using the kin filter and more. Although they protect you from loops if there are none all the better. Also look at the TocP plugin, as it has operators for any field to drive the tree, and the parent field “out of the box”, no recursive TiddlyWiki Script needed (from memory).

1 Like

Just to be sure. You know about my tocP-plugin? Wikilabs Home — A home for: Plugins, Editions and Themes!

It’s a parent-field based table of contents macro, with a bit more configuration options.
The field name is configurable. So it’s possible for a tiddler to be part of as many “trees” as needed.

I think it should be relatively straight forward to create a breadcrumb like view, similar to the pending PR for the tw-com .breadcrumbs macro. It’s just some CSS changes and the tocP recursive macro could be used to create the structure.

I did a complete rewrite of the tocP-macros lately and I wanted to create a video and a new intro post. But I did not have the time yet.

-mario

1 Like

While creating the .breadcrumbs macros I also thought it should be possible to create a structure like this one. I’m in tiddler B, but I also want to show the “path down”

Link to A > Link to B > Link to D > Link to F

So both directions should be visible. The breadcrumb for tiddlers A, B, D and F would always be the same. Only the current tiddler would have no link.

I did not implement that behaviour for the .breadcrumbs yet, but I did think about it.

I think from tiddler B onwards it would be needed to show a toc-like structure, since there may be several possible paths

If the paths up and down have to be deterministic, it would be needed to create “double linked lists” instead of a “sinlge linked list” like the “parent-based” structure is atm. But that’s a completely different thing

Yes, thank you. As I said at the outset, I will probably use an existing solution. This investigation is mostly to help me learn.

I misspoke earlier. I do not actually have a tree, but instead a forest. There are a handful of root nodes, and each leaf will belong to exactly one tree. I don’t think this makes any significant difference to what I need to do, not with the code you corrected for me. But I don’t know it that’s a problem with tocP. I will investigate soon.

The project is a documentation consolidation one. I’m working on a system which has documentation in Sharepoint, Confluence, GitLab and GitHub wikis and Pages, file shares, and MS Teams files. It’s a total mess and we need to understand the full set of documentation, see what’s still active and correct and eventually try to bring it together in one location. But the first step is simply to find everything, and the TW I’m writing is to collects links, descriptions, and various metadata about the various documents so that we can add organization before we try to put it all in one place. (I will argue that this one place should be a single TW; I will probably lose that argument, but having people work with TW might help demonstrate its power and improve my chances!) The tiddler for a particular document should use the parent-field based breadcrumbs to show its location in context.

That is great for a reusable configurable tool. But my needs are simpler; I’m never showing the full hierarchy, only a single path from root to leaf, or possibly, a path from root to branch. Hence the breadcrumbs-like styling.

I’m struggling to find circumstances in which that would be useful. Do you have a use in mind? To me, if I’m looking at Link to B, then I might want to show the remaining hierarchy ((C|D(E|F))), and I might want to know the path to the root, but how would I know on Link to B that my target leaf is Link to F, rather than Link to C or Link to E?

Sure. … It’s a completely different usecase. eg: If you design a D&D campaign.

As the designer you need to have an overview about the whole picture and all possible outcomes. If you are at B next steps may be (C | D) but final states may be (C | E | F).

As a player at state B you only get to see next steps (C | D) from the decision tree.

Just an example, where it can make sense. But I was struggling with a breadcrumb-like visual representation of such a configuration. May be a combination between breadcrumbs and tocP may be an option. – just brainstorming

-m

That’s cool. So an existing ultra flexible tool may be overkill atm. I think it’s a good way to start simple and then adjust to your usecase when the need for more functionality comes up.

I had ideas slightly different from yours in the breadcrumbs discussion a few months back. I went as far as figuring out some fairly simple JS code to generate the basics list for each possibly breadcrumb hierarchy given a tiddlers-with-tags configuration. But then I stopped doing much TW for a while. I’d like to get back to that, although my periodic table work is higher priority. My imagined representation of multiple paths was to have a <select ...> for the entire breadcrumbs trail. If there were multiple paths, you could simply select one of them from an unobtrusive dropdown, with some simple algorithm to sort them and pick the default.

Sure, that makes sense, but that doesn’t explain the “path down”. Somehow the user needs to be on Link B but know that the target is Link F I’m sure there are use-cases for that, but I have yet to come up with one.