-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Parameterised transclusions #6666
Conversation
Everything is draft.
The changes in 0bffae2 mean that we don't need to explicitly maintain the ordered attributes
… overridden widget
…rrors Of course, it doesn't actually need to be a JS widget, it could be a wikitext widget...
Really interesting stuff, and I can see the appeal of simplifying the wikitext and shortcut syntaxes. |
@Jermolene, just for clarity and if I understand the doc correctly, the render of the Widget Syntax Invocation example quoted below misses a line and should read:
Fred
|
@Jermolene I applaud the objectives of this piece of work and will do what I can to help, text and support this initiative. A couple of points about what I see as critical to keeping this understandable to new and average users.
As you suggest I think the Add support for string literal attributes with textual substitution |
Thanks @tw-FRed, fixed.
Yes @AnthonyMuscio, I think we do need to review all the associated terminology. I've had to invent some new terms and some of the old terms might no longer be such a good fit. For example, I'm not sure that "macros" makes sense now; we might consider "function".
The term "slot" is taken from the web custom elements specification: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/slot Generally, the implementation of custom widgets is very similar to the custom elements spec, so it seems to make sense to share terminology.
I think you're suggesting that the transclude widget use the presence of a I don't think that will work; the
That won't work. A key change here is that we have a single widget that can transclude variables or tiddlers. So we need to have the explicit attribute names so that we know which is which. It would be ambiguous whether |
Hi @Jermolene, this feature looks very powerful indeed! FWIW, a name that came to mind was In the spirit of grand unification, I was wondering whether we couldn't do without the
|
I don't think, the idea is too far off. ...
That's right
Since there is no There could be a possibility for an empty Just some thoughts. |
I've pushed some significant changes, and made substantial edits to the original post at the top of this PR. The changes are:
Thanks @xcazin I have been considering that possibility. The advantage of the present arrangement is that because the widget is working with tiddler titles (or variable names) it can easily cache the results of parsing. With a generic |
I'll check out the code and have a closer look soon. Looks very interesting. |
I am in the bush so cant review with a fine tooth comb. So friendly feed back. Do you actualy intend to drop the use of parameter:"value" and use "=" in both function definition and calls? If so this is added complexity going forward so could we do one of the following?
Can we use $macrocall for functions and if we do what happens? Because I think it relates to the handling in this functions; Personaly I have long felt it would help if we made available in wikitext to be able to convert between keyword="value" pairs and variables with values and the reverse, generate a set of keyword value pairs and handling the delimiters ' " """. An example may be programatically building a set of keyword value pairs and passing them to actioncreatetiddler or taking a set of variables and save them as settings in a tiddler field or text. Another example would be uri's do not permit spaces so a link field could contain a link plus more info eg Please note I am not trying to abuse by going off topic. Functions as proposed will be at least translating keyword/value pairs to variables if not in the reverse. This seems to me importiant to concider now, if not ultimately spawning another issue. |
So that they are at the top of the recent tab
I am now merging this PR, a few days later than scheduled in #7279. Part of the rationale is that this PR is now very long and the comments are hard to navigate. We can still make refinements to these changes. |
@Jermolene Procedure Parameter Handling has caption: Procedure Definitions has caption: |
Thanks @kookma much appreciated. I'll attend to those as soon as I can. |
Direct call to function only returns the first output. Look at the below examples. A function is defined and is used in several ways.
In the above examples all works except |
As I understand it, it is as intended. See the table in this comment #6666 (comment) for full details on the behavior (though that table is not up to date from this change: #7009). |
Much appreciated! Is this table added to documentation? It is needed to understand how different new variables work! |
@kookma I think it's time to create new issues with questions like the last post. So they can be handled and closed independently. |
Thank you @btheado It would be great if you could make a PR for an updated version of the table? I'd be open to suggestions, but perhaps as a new tiddler "Variable Usage"? |
This thread is now locked – please create a new ticket with any further questions, comments or bug reports. |
Introduction
This PR introduces a number of improvements and new features related to some of TiddlyWiki's most fundamental components: macros, widgets, operators and transclusion.
The motivation is to fix one of TiddlyWiki 5's early design flaws: the reliance on macros using textual substitution as the primary way to modularise and reuse wikitext and filters.
Experience has shown that while macros are a good match for a small number of tasks, they are brittle and error prone for many common operations. Over the years we have introduced mitigations for the worst problems but these have come at a cost of increased complexity.
The changes in this PR provide powerful new ways to achieve common tasks, and unlock completely new capabilities that were previously impossible in wikitext.
Some smaller improvements are also needed to enable these new features:
New filter operators for reading JSON data– superseded by JSON Filter Operators (Revised Attempt) #6936A new– cherrypicked to Introduce genesis widget #6961<$genesis>
widget that permits any other widget to be dynamically created, with dynamic attributesA new– cherrypicked into Improve recursion detection #6970<$error>
widget for displaying core error messagesMore effective protection against infinitely recursive functions and procedures– cherrypicked into Improve recursion detection #6970All of these changes are intended to be backwards compatible, and should not affect existing functionality. While they represent a new field of opportunities for wikitext authors, equally it is entirely possible for authors to ignore all these new features and continue to use TiddlyWiki 5 in the way that they have always done.
Background
TiddlyWiki 5 macros were originally based on the technique we call "textual substitution": the string values of the parameters provided when calling a macro would be plugged into the macro definition before it was wikified in the usual way.
A typical example of the approach in early versions of TiddlyWiki 5:
The technique worked well enough to get the basics of the TiddlyWiki 5 user interface up and running, but it was clear from the start that it was annoyingly brittle. For example, the macro above would fail with tiddler titles containing double closing curly braces. Trying to use it with the title
foo}}bar
would lead to the macro being expanded to the following invalid syntax:As a result, for a long time, the TiddlyWiki 5 user interface failed if a variety of combinations of special characters were found in tiddler titles. Long time users will remember a warning that popped up in the edit template whenever a potentially troublesome character was detected.
Over the years we've mitigated almost all of these issues, particularly by providing access to the macro parameters as variables. For backwards compatibility, this was done without affecting the existing syntax, which required us to adopt the clumsy protocol of wrapping the parameter name in double underscores to get the name of the corresponding variable.
This has all worked well enough for us to fix the UI issues with special characters in tiddler titles, but is very inconsistent and complex, requiring users to grasp multiple mutually exclusive conceptual models for what is going on.
New Features and Improvements
The approach taken by this PR is to add new functionality by extending and augmenting the system without disturbing existing functionality.
This lays the groundwork for macros and related features to be deprecated, which is the point at which users are advised not to use old features, and instead given clear pointers to the equivalent modern functionality.
The new transclusion architecture is not by itself sufficient to enable us to fully deprecate macros yet. To handle the remaining use cases we propose a new backtick quoted attribute format that allows for the substitution of variable values. See #6663 for details.
Procedures
Procedures are the modern replacement for macros. The key difference is that the parameters are only available as wikitext variables (without requiring double underscores), and that textual substitution does not occur.
The syntax for defining a procedure closely resembles the existing syntax for defining a macro:
Procedures are invoked using the same shortcut syntax that is used for macros:
Procedures can also be invoked as transcluded variable attributes using the syntax
<div class=<<hello>>>
. Note that the plain, unwikified text of the procedure will be used, without any parameter processing.Custom Widgets
Custom widgets are defined with the
\widget
pragma, which works analogously to the\procedure
pragma.The names of user defined widgets must start with the prefix
$$
.Built-in widgets can be overridden by using a single
$
. Note that it is not possible to create new widgets named with a single$
, only to override existing built-in widgets. This is to prevent users creating widgets whose names clash with future core widgets.Invoking a custom widget transcludes the contents of the variable containing the definition. The widget definition can transclude the content of the calling widget by using the construction
<$slot $name="ts-raw"/>
.For example:
The custom widget is invoked in the usual way:
That example would render as:
Functions
Functions are analogous to procedures except that they encapsulate filter expressions rather than wikitext. They are defined in the same way:
Functions can be invoked via the new
function
operator:Functions can also be invoked as transcluded variable attributes. For example:
Custom Filter Operator Functions
If a user defined function name starts with a period then it can also be invoked directly as a custom filter operator:
Transclude Widget Updates
Many of these improvements depend for their implementation on a significantly upgraded
<$transclude>
widget. To accommodate the new functionality without breaking backwards compatibility, the widget now operates in two modes:$tiddler
,$field
,$index
etc.tiddler
,field
,index
. It is engaged when none of the attributes start with a $ characterLike macros, procedures are implemented as a special type of variable. The syntax for invoking procedures using the
<$transclude>
widget is as follows:Note how the attributes
$variable
,$tiddler
,$field
,$index
etc. that start with a single dollar sign are used to define what to transclude, while the plain attributes are used as parameters to be passed to the procedure.The transclude widget can be used to pass named parameters to the transclusion. The transcluded content can reference the parameters via the
<$parameters>
widget.Parameterised Transclusion
The transclusion shortcut syntax has been extended to allow parameters to be passed to all types of transclusion, not just transclusions of macros/procedures/custom widgets.
The parameters are passed according to their position in the corresponding parameters declaration, not by name.
For example, with the text below in a tiddler titled "FooBar":
The shortcut syntax for invoking the parameterised transclusion uses a single vertical bar to separate them from the title of the tiddler being transcluded:
Parameters can be omitted to skip them. For example:
Note that omitting the first parameter
{{FooBar||second|third}}
creates an ambiguity because the resulting double vertical bar causes it to be interpreted as{{title||template|param1}}
.Slotted Parameters
"Slots" provide a way to pass complex structured data to a transclusion instead of the simple string values supported by string parameters.
Slots are named areas that are defined within transcluded text using the
<$slot>
widget. They are replaced with custom content provided by a corresponding<$fill>
widget inside the transclusion invocation. For example:The syntax for invoking the procedure using the
<$transclude>
widget uses the<$fill>
widget to pass the content for the slot:The result would be equivalent to:
The contents of the
<$slot>
widget provide the default contents that are used in case a value is not provided for a named slot. For example:The entire contents of the transclude widget invocation is available as the special slot fill value
ts-raw
.Specifying Content to Display When Target is Missing
Up until now, the content of the transclude widget has been used as the fallback content to display when the target of the transclusion is missing.
To allow room for the new
<$fill>
widget, the new behaviour is to use the special slot valuets-missing
if present, and if there are no<$fill>
widgets present, then falling back to the content of the transclude widget.Open Questions
These need to be settled before merging:
$$
the best prefix for custom widgets? We have a (very) loose guideline that$
stands for "system", and it is used as a kind of warning sign for system-y stuff that generally doesn't need to bother casual users. But we don't have an equivalent prefix for a user defined namespace. Perhaps.
, as we're using with custom operators?<$fill>
a good name? The rationale is that it pairs logically with<$slot>
(which in turn reflects the W3C<slot>
element). The trouble is that end users won't see the<$slot>
widget until they start writing their own relatively complex procedures/widgets, and until that point<$fill>
won't make much senseFuture Possibilities
These can be addressed after merging:
Progress
This PR is fully functional, and very, very nearly complete.
Incomplete:
widget.getVariableInfo()
Completed
\function
definitions\parameters
construction$:/tags/Global
alongside$:/tags/Macro
Documentation progress
conditional
attributeNotes for documentation
Other tickets that can be closed when this is merged