How to get transclusion depth?

Is there a way to detect the transclusion depth within a tiddler? For example, I would like to be able to do something like this:

This tiddler is being transcluded at a depth of: <<transclusion-depth>>

To be more specific about the use case: I want to be able to define certain transcludables (tiddlers, or macros, custom widgets, variables, etc.) that allow things within them to access their slots at unknown depths (without having to use $fillignore). This would be really easy if I could define those transcludables something like this:

<$set name="outer-depth" value=<<transclusion-depth>>>
<$list filter="..." template="My Template"/>
</$set>

Because then, even at an unpredictable depth, anything that could turn up in the list above that also wants to use a slot given to the above tiddler (or macro etc.) could do so like this:

<$slot $name="spam" $depth={{{ [<transclusion-depth>subtract<outer-depth>] }}}/>

But I can’t find any way to do this.

I think you can do this with the transclusion Variable: https://tiddlywiki.com/#transclusion%20Variable, and/or the quality macro : https://tiddlywiki.com/#qualify%20Macro

I see that basically tells me what <currentTiddler> and <thisTiddler> are (along with other information if it’s non-text fields being transcluded)… not sure how it (or qualify) would help me here.

1 Like

Have you tried using the <<thisTiddler>> variable. It sets the variable to the tiddler in which it is coded?

  • I can look into this more but have not used the depth parameter yet, but as I understand it it is used to “look up” into the nth parent transclusion. It is available on the;
    • Parameters Widget
    • Slot widget
    • And made reference to in the $fillignore parameter of the transclusion widget

It seems only to accept an integer value

Try the <<thisTiddler>> Variable, perhaps using it to set another variable relating to the level of transclusion, and only if necessary;

When the $depth attribute is used to retrieve parameters from a parent transclusion (see below)

  • To get access to this variable in the N depth(s) above.

I don’t understand at all. How does <<thisTiddler>> help me access or track the depth from one transclusion to another?

At each level of transclusion you possibly can see the tiddler in which it is coded. Crafted correctly you may be able to manage or track different depths, Otherwise I cant offer much advice on depth, I am not practiced with it yet and not sure why you need it.

  • Surely with slot there is really only the current, and the place where the widget is called?

It can really help if you can give an easy to test example of what information you are trying to retrieve.

I didn’t want to have to do something at each level of transclusion, but if that’s the only way, then I think it would be simpler to wrap each tiddler with this:

<$set name="transclusion-depth" value={{{ [<transclusion-depth>add[1]] }}}>
(tiddler contents)
</$set>

It would be nicer if I could override the $transclude widget to keep track of transclusion depth:

\widget $transclude($variable, $tiddler, $field, $index, $subtiddler, $mode, $type, $output, $recursionMarker, $fillignore, ...)
\whitespace trim
<$set name=transclusion-depth value={{{ [<$fillignore>match[yes]then[0]else[1]add<transclusion-depth>] }}}>
<$genesis $type="$transclude" $remappable="no" $$variable=<<$variable>> $$tiddler=<<$tiddler>> $$field=<<$field>> $$index=<<$index>> $$subtiddler=<<$subtiddler>> $$mode=<<$mode>> $$type<<$type>> $$output=<<$output>> $$recursionMarker=<<$recursionMarker>> $$fillignore=<<$fillignore>> ...><$slots $name="ts-raw"/></$genesis>
\end

The problem is that the $transclude widget can take an arbitrary number of parameters that it uses as transclusion parameters, but as far as I know, there’s no way of allowing such arbitrary parameters in a custom widget definition.

  • This raises an idea for a request to allow something like **kwargs in TW macro/procedure/widget definitions. I have some ideas for this, but I will post them in a separate topic (and add a link here once posted).

Edit: it turns out that the $parameters widget’s $params attribute essentially enables **kwargs. Experimenting at tiddlywiki.com (note: DO NOT ATTEMPT TO OVERRIDE THE $TRANSCLUDE WIDGET IN YOUR OWN WIKI!!! A MINOR BUG MAY TURN THE WHOLE DISPLAY BLANK OR FILL IT WITH ERROR MESSAGES!!!), I came up with this:

\widget $transclude()
\whitespace trim
<$parameters $params="p">
<$set name="transclusionDepth" value={{{[[transclusionDepth]getvariable[]add[1]]}}}>
<$genesis $type="$transclude" $remappable="no" $names="[[p]getvariable[]jsonindexes[]]" $values="[[p]getvariable[]jsonget[]]">
<!-- <$slot $name="ts-raw"/> This part causes problems -->
</$genesis>
</$set>
</$parameters>
\end

It seemed that even using <p> in filters is a variable transclusion and caused a recursive transclusion error (not totally sure on that, I had to do a few things to get rid of the various errors), so I changed all those to getvariable[]. But if I uncomment the slot, I get transclusion recursion errors in various parts of the UI, probably because of nested transclude widgets.

Another Edit: maybe I could override the $transclude widget, but not globally - only in the place (template or widget, etc.) where I would be filling slots. I think using nested transcludes would still cause issues wherever the $transclude widget is overridden though (unless I left the slot commented in the above code, which would effectively disable the contents-as-fallback mechanism of the transclude widget).

Edit: Also see this PR: $parameters widgets now claim index parameters sequentially by flibbles · Pull Request #7962 · Jermolene/TiddlyWiki5 · GitHub


I’m not really sure, what you try to achieve. But I’m pretty sure you do not need to mess with that parameter. It’s there to handle extreme edge cases.

Can you be more specific about a “real usecase” other than “I just want to test it”.


It’s fine to play with it for scientific reasons, but I would try hard, to avoid it in production. It will “rob” you of all the flexibility templates and macro calls usually have. It will probably create super brittle code if done wrong.

Almost every widget or procedure that we call in v5.3.x will end up to create 1 or more transclusions. So every time you clean up your code for better readability it potentially changes transclusion depth.
Every time the core UI is changed it may end up changing the depth your code relies on.

Just my personal opinion.

1 Like

The qualify macro use the transclusion variable and returns a unique string that encodes its position within the widget tree, as identified by the stack of transcluded tiddlers that lead to that position. I’m not sure but given that description I’m guessing that the number you get from the qualify macro can be used to detect a transclusion depth.

@telumire It doesn’t seem to offer a way to “decode” the string to get the “stack of transcluded tiddlers”, and the transclusion variable referenced before doesn’t include the whole stack. I don’t think these will help me here.

I’m confused. If one refactors one’s code in a way where the <$slot> widget gets moved to a macro, is that an extreme edge case? Because, as you say:

And this is true even if you weren’t originally using the $depth attribute - simply moving it to a macro, which is a variable that gets transcluded, changes the needed depth from 1 to 2.

In my mind, it’s inflexible and brittle as it is.

The whole point of my desire for a <<transclusionDepth>> variable was to be able to use the slot at any depth without messing with the $depth attribute. All I’d need to do is:

<$let slotDepth=<<transclusionDepth>>>
<$transclude ...>
<$fill name="cheese">
...
</$fill>
</$transclude>
</$let>

Then when I use the slot, I can use it like this:

<$slot $name="cheese" depth={{{ [<transclusionDepth>subtract<slotDepth>] }}} >...</$slot>

By thus computing the $depth value, I could flexibly refactor my code all I want (or upgrade the wiki) and let the transclusion depth change however it will, without breaking my slot.

I was intending to make a plugin or “edition” that would fill slots, and custom widgets designed to be used that would do things with those slots. I didn’t want the users to have to only use the custom widget at a specific depth, or to have to know the depth at which they’re using it, so it would be nice to let the widget compute the $depth attribute so that the user doesn’t have to worry about it.

I am now considering alternatives in order to avoid using slots at all, since they don’t seem to afford this flexibility.

Something like this, but aggregating count instead of aggregating tiddler titles, right?

TiddlerTransclusionLevels.json (877 Bytes)

@Charlie_Veniot Yeah, that’s the basic idea, but also without having to specify a special template to keep track of the count (besides, I could need to transclude a widget or macro).

Yes, even if you change your own code, if there is any need to use the depth of something, it is most likely to be to the parent or grandparent process, that is the relative depth, -1 or -2 conceptually. Very unlikely an absolute depth.

I think your issue stems from the same issue I raised, because the slot contents are only returned using a widget (read as a final output mechanism) there is little we can do to make use of the contents. And this includes the contents of the calling widget/procedure which is what slots are all about. Accessing ts-raw without the slot widget?

  • Since we can’t use those contents much at any level we can’t set variables etc… that will be available in a child widget or process either.
  • So we then look to the depth parameter and it all gets really confusing.
  • What do you mean with these words? surely there is no need to use the word transclude here? Just
    • I could need to include a widget or macro

    • Or do you mean something different?

At least in a way, yes. I wanted to access slots at an unknown relative depth. My thought was that if the absolute transclusion depth were available as a variable, then the relative depth would be easily computable, but if slots were available as variables as in the idea in your post, that would also make it a lot easier.

@pmario provided a good answer:

As the $transclude widget documentation says:

The $transclude widget dynamically includes the content from another tiddler or variable

(emphasis added)

And as we know macros are also a kind of variable. Even custom widgets are implemented as a kind of variable:

Custom widgets are implemented as a special kind of variable. The only thing that distinguishes them from ordinary variables is the way that they can be called as a custom widget with attributes mapped to parameters.

Normally I wouldn’t use that word for widgets, procedures, or variables because that’s just the implementation under the hood. But in this case, it’s relevant that the underlying mechanism is a transclusion, because this changes the transclusion depth, and thus, changes the $depth value needed to use slots. For example, if you copy the following code into a new tiddler and open the preview:

\define myMacro() <$slot $name="ts-raw"/>

\widget $my.widget() <<myMacro>>

<$my.widget> slot content </$my.widget>

You’ll find that the slot content isn’t displayed. (As per the custom widgets documentation linked above, ts-slot is the slot that TW automatically fills in a custom widget to provide access to the the children of that widget, slot content in this case.) But if you change the first line to:

\define myMacro() <$slot $name="ts-raw" $depth=2/>

Then it displays. This is because the macro call is technically a variable transclusion, so to use the slot widget’s slot within the macro, we have to specify that it is not a slot filled in the macro call but filled in the widget call, its parent in the tree.

(If you change the preview type to widget tree, you can see that the widget and macro are both rendered via transclusions. However, despite the simplicity of the code example, the widget tree is too unwieldy to share here.)

That’s why I chose to use that word - not just because it’s a transclusion under the hood, but because the fact that it’s a transclusion is relevant to this particular issue of wanting to use $slots without having to know the transclusion depth.

To my understanding this is an incorrect use of the slot widget. The slot widget is designed to be used inside a widget definition, be it a custom widget, or one that overrides a core widget.

  • It is interesting that you point out it works when placed inside a macro definition but this is just a side effect. Macros are deprecated and procedures recommended).
  • Interesting but non-standard

Actually I think this view point is confusing the issue, seriously.

Lets go back to the slot widget, what do you want to use it for?, I have learned how to use them and never needed to consider depth.

  • As I understand it the depth already is a relative term, and no need to work it out, there is arguably no useful absolute depth.
  • If one was to use depth, most likely it would ONLY be for access to the grandparent or higher within a specific set of code, such as a reiterative or recursive code set. The default depth is the one before.
    • And the ways variables flow down to its children, even this is unlikely to be needed.
      • Perhaps except in the event of meta things, like writing code that writes code, or generates templates and objects like buttons.
  • I think there is value in building a code structure that uses the slot widget in standard ways, and only then asking how you can make use of the depth.

Being a bit of a hacker myself, I did guess that using depth may give us some interesting hacks into the tiddlywiki core processes and provide some creative design opportunities. But I have not yet found a compelling reason to do so.

It’s not a side effect. It works because the macro is called by a widget. It’s only incorrect if I call the macro outside the widget.

Perhaps I should amend the example:

\widget $my.widget() 
\define myMacro() <$slot $name="ts-raw"/> <!-- add $depth=2 to make it work -->

<<myMacro>>

\end $my.widget

<$my.widget> slot content </$my.widget>

This would make it a little more clear that the macro can only be called inside the widget, I think.

From what I understand, this is only relevant when using parameters; for reusable code snippets with no parameters, \define and \procedure work exactly the same, do they not?

This means you are only using them directly in the widget definition or transcluded tiddler. In a way, this is where I was going wrong - assuming that you ought to be able to easily use them that widget or tiddler’s children. (Keyword “easily”) I am looking to things other than slots now (although there’s no alternative to the ts-raw slot).

Edit: as for the relative vs absolute depth: $depth is a relative depth, yes. I wanted absolute depth available (as a variable) in order to be able to easily compute the needed relative depth (as in the examples above).

  • To me it (needing the depth) is a side effect of

putting the slot widget inside a macro.

But why not just;

\widget $my.widget() 
<$slot $name="ts-raw"/> 
\end $my. Widget

<$my.widget> slot content </$my.widget>

It does make it clearer.

  • There is a little more to it than that but the part you say is not wrong.
  • It is a problem using both macros and procedures when some sort of evaluation needs to take place, because some uses will need you to wikify it first.
    • But this is also true when your macro includes the slot statement, however your invocation of that macro <<myMacro>> is just that it gets wikifeld in the final render.

I do think I know where your queries were generated. There is some incompletness in the code for manapulating slots and I have reased this in the past

I would argue I see no case where you need to do this. As the coder you can see what the depth is and encode that.

  • In the example above, inside the macro you need depth 2, in the body depth 1 the default.
1 Like