The `\import` pragma isn't valid before other macros?

I’m further developing my mnemonic medium platform (that Grok TiddlyWiki is built on) and wanted to make an option where the person configuring the plugin could provide an arbitrary macro containing action widgets, to be triggered from somewhere within the plugin at an appropriate time. To edit settings like this, I have a custom control panel that provides text entry fields and documentation for a variety of settings:

The way this control panel works is there are a bunch of config tiddlers that have fields describing how they should show up in the control panel, and the text field of each is bound to the text entry field. Pretty standard. But the macro thing didn’t work the way I expected:

  • First I tried tagging the tiddler being edited with $:/tags/Macro. This caused the entire page to re-render and scroll up to the top every time the text was edited. This understandable, I guess, though I’m spoiled by the recent version that prevented loss of focus when editing fields of the current tiddler!
  • Then I tried removing the tag and \importing the tiddler into a different tiddler containing the sendFeedbackLink macro (where the user-defined macro is called). This caused all of the macros in that tiddler to fail to be defined.

In this case I was able to use an $importvariables widget within the calling macro instead:

\define sendFeedbackLink(tooltip:"Suggest an improvement to this question.", icon:"" text:"send feedback")
<$importvariables filter="[[$:/config/sobjornstad/TakeAway/AuthorProvided/FeedbackActions]]">
<$button class="tc-btn-invisible tc-tiddlylink" tooltip=<<__tooltip__>>>
	<<sendFeedbackAction>>
	$icon$ $text$
</$button>
</$importvariables>
\end

Is it intended that \import doesn’t work properly within a tiddler containing macros after the directive? If so, we should probably add this to the documentation and suggest a workaround.

(Also, I’m not sure \import would have worked anyway – anything imported by \import presumably goes out of scope at the end of the tiddler, so it probably wouldn’t be accessible at the time the macro is called by somebody outside of that tiddler. I don’t think TiddlyWiki macros offer “closures” like this, do they? Maybe this should be mentioned too.)

No. I do that a lot. It works fine.

How does your import pragma look like?

MWE on TW 5.2.2 running on Node:

Tiddler test1:

\import [[test2]]

\define macro1() Test

Tiddler test2:

\define macro2() Test 2

<<macro1>> doesn’t yield any output, but if I remove the \import line it does.

To see the result needs the macros present in the body

\import [[test2]]

\define macro1() Test

# <<macro1>>
# <<macro2>>

The result is

  1. Test
  2. Test 2

So it is working for me.

Sorry, I left out an important part. Calling <<macro1>> does work within test1, as you say, but it doesn’t do anything in any other tiddler, even though test1 is tagged $:/tags/Macro.

Understood.

I never expected this to occur because import is typically used to import macros without making them global.

I tested the approach for you to take is to transclude rather than import. It does not work.

test3

# <<macro1>>
# <<macro2>>
  • only macro 1 works

Test4 tagged $:/tags/Macro

\define macro1() Test
{{test2}}

Perhaps the way I would say this is;

Import pragma or macro definitions by transclusion can not be nested

I also looked at the ImportVariablesWidget but it needs to wrap the area where it is valid and its existence in a tiddler tagged $:/tags/Macro is not globalised.

Some alternatives

  • You could edit the $:/core/ui/ViewTemplate/body/default tiddler to wrap the import variables around the text field.
  • Since macros are in effect variables perhaps you could make use of the new ## SetMultipleVariablesWidget
    in some way (un tested)

Your simple solution is to tag [[test2]] with $:/tags/Macro

In a way I think it reasonable to expect the import pragma to only operate in the scope of the current tiddler, given the global method is to tag the tiddler containing the macro definitions with $:/tags/Macro

  • Perhaps you could use import variables widget inside the view template but the macros will only be valid within the widget and thus only part of the view template.
  • alternatively using cascades make your own "conditional "ViewTemplate Body that wraps it with the import variables widget

[Edited] to state $:/core/ui/ViewTemplate/body/default not the edit one

You say

only macro 1 works

But neither macro1 nor macro2 works for me when called in a different tiddler. I’m not particularly surprised that macro2 doesn’t work (I wasn’t expecting it not to at first, but that’s a perfectly logical design decision, and like I said in my original post, I found a way around it in my case, the <$importvariables> just needs to go inside the outer macro).

The problem is that the \import directive is preventing any macros in that tiddler from being available globally, even ones which have nothing whatsoever to do with the import and are fully defined without any of its contents. It seems like that isn’t happening for you though?

Here’s a copy of empty.html with the tiddlers I showed above, to be sure we’re looking at the same thing: https://drive.google.com/file/d/1MUa4T95yg8VnJbJh4ojEFfcyvTAeSAI0/view?usp=sharing

Editing test 1 to read

\define macro1() Test
\import [[test2]]

Now shows the result of macro1: in [[Call Macros]]

  • Note the change in order
  • This is most likely needed because \import [[test2]] being invalid is damaging \define macro1() Test when ordered as in your test.

Interesting. Why do you say \import [[test2]] is “invalid” though? It works within this tiddler. Seems more like a bug (or an undocumented requirement).

I am pretty sure this is the case. Globally $:/tags/Macro tiddlers work because they are imported in to the page template using \import which creates an $importvariables widget.

The way that the $importvariables widget works is that it looks at the widget tree for the target tiddler and imports the first $set widget and any immediate children that are $set widgets. Macros are internally represented as set widgets so this works for importing macros.

However, when the macro tiddler starts with \import, the first thing that the importing $importvariables widget sees in the widget tree of the target tiddler,is an $importvariables widget (rather than a $set widget), and it therefore does not import anything from that tiddler.

3 Likes

On TiddlyWiki — a non-linear personal web notebook

Both of your examples work for me.

But nested import does not work as expected.