1
0
mirror of https://github.com/Jermolene/TiddlyWiki5 synced 2025-10-30 15:13:00 +00:00

Extend transclude widget to work with old-style macros and use it for the macrocall shortcut syntax

This commit is contained in:
jeremy@jermolene.com
2022-05-08 15:59:20 +01:00
parent 9be05f6f38
commit e9630328f1
7 changed files with 152 additions and 46 deletions

View File

@@ -175,7 +175,36 @@ exports.parseMacroParameter = function(source,pos) {
};
/*
Look for a macro invocation. Returns null if not found, or {type: "macrocall", name:, parameters:, start:, end:}
Look for a macro invocation. Returns null if not found, or {type: "transclude", attributes:, start:, end:}
*/
exports.parseMacroInvocationAsTransclusion = function(source,pos) {
var node = $tw.utils.parseMacroInvocation(source,pos);
if(node) {
var positionalName = 0,
transclusion = {
type: "transclude",
start: node.start,
end: node.end
};
$tw.utils.addAttributeToParseTreeNode(transclusion,"$variable",node.name);
$tw.utils.each(node.params,function(param) {
var name = param.name;
if(name) {
if(name.charAt(0) === "$") {
name = "$" + name;
}
$tw.utils.addAttributeToParseTreeNode(transclusion,{name: name,type: "string", value: param.value, start: param.start, end: param.end});
} else {
$tw.utils.addAttributeToParseTreeNode(transclusion,{name: (positionalName++) + "",type: "string", value: param.value, start: param.start, end: param.end});
}
});
return transclusion;
}
return node;
};
/*
Look for a macro invocation. Returns null if not found, or {type: "macrocall", name:, params:, start:, end:}
*/
exports.parseMacroInvocation = function(source,pos) {
var node = {

View File

@@ -27,7 +27,7 @@ exports.findNextMatch = function(startPos) {
var nextStart = startPos;
// Try parsing at all possible macrocall openers until we match
while((nextStart = this.parser.source.indexOf("<<",nextStart)) >= 0) {
var nextCall = $tw.utils.parseMacroInvocation(this.parser.source,nextStart);
var nextCall = $tw.utils.parseMacroInvocationAsTransclusion(this.parser.source,nextStart);
if(nextCall) {
var c = this.parser.source.charAt(nextCall.end);
// Ensure EOL after parsed macro

View File

@@ -27,7 +27,7 @@ exports.findNextMatch = function(startPos) {
var nextStart = startPos;
// Try parsing at all possible macrocall openers until we match
while((nextStart = this.parser.source.indexOf("<<",nextStart)) >= 0) {
this.nextCall = $tw.utils.parseMacroInvocation(this.parser.source,nextStart);
this.nextCall = $tw.utils.parseMacroInvocationAsTransclusion(this.parser.source,nextStart);
if(this.nextCall) {
return nextStart;
}

View File

@@ -166,27 +166,45 @@ TranscludeWidget.prototype.getTransclusionTarget = function() {
}
var parser;
if(this.transcludeVariable) {
var variableInfo = this.getVariableInfo(this.transcludeVariable).srcVariable;
if(variableInfo) {
var variableInfo = this.getVariableInfo(this.transcludeVariable,{params: this.getOrderedTransclusionParameters()}),
srcVariable = variableInfo.srcVariable;
if(srcVariable) {
var mode = parseAsInline ? "inlineParser" : "blockParser";
if(variableInfo[mode]) {
parser = variableInfo[mode];
if(srcVariable.isCacheable && srcVariable[mode]) {
parser = srcVariable[mode];
} else {
parser = this.wiki.parseText(this.transcludeType,variableInfo.value || "",{parseAsInline: parseAsInline});
variableInfo[mode] = parser;
}
if(parser && variableInfo.isFunctionDefinition) {
parser = {
tree: [
{
type: "parameters",
children: parser.tree
}
]
parser = this.wiki.parseText(this.transcludeType,variableInfo.text || "",{parseAsInline: parseAsInline});
if(srcVariable.isCacheable) {
srcVariable[mode] = parser;
}
}
if(parser) {
if(srcVariable.isFunctionDefinition) {
parser = {
tree: [
{
type: "parameters",
children: parser.tree
}
]
}
$tw.utils.each(srcVariable.params,function(param) {
$tw.utils.addAttributeToParseTreeNode(parser.tree[0],param.name,param["default"])
});
} else if(srcVariable.isMacroDefinition) {
// Wrap the parse tree in a vars widget assigning the parameters to variables named "__paramname__"
parser = {
tree: [
{
type: "vars",
children: parser.tree
}
]
}
$tw.utils.each(variableInfo.params,function(param) {
$tw.utils.addAttributeToParseTreeNode(parser.tree[0],"__" + param.name + "__",param.value)
});
}
$tw.utils.each(variableInfo.params,function(param) {
$tw.utils.addAttributeToParseTreeNode(parser.tree[0],param.name,param["default"])
});
}
}
} else {
@@ -218,6 +236,39 @@ TranscludeWidget.prototype.getTransclusionTarget = function() {
}
};
/*
Fetch all the string parameters as an ordered array of {name:, value:} where the name is optional
*/
TranscludeWidget.prototype.getOrderedTransclusionParameters = function() {
var result = [];
// Collect the parameters
for(var name in this.stringParametersByName) {
var value = this.stringParametersByName[name];
result.push({name: name, value: value});
}
// Sort numerical parameter names first
result.sort(function(a,b) {
var aIsNumeric = !isNaN(a.name),
bIsNumeric = !isNaN(b.name);
if(aIsNumeric && bIsNumeric) {
return a.name - b.name;
} else if(aIsNumeric) {
return -1;
} else if(bIsNumeric) {
return 1;
} else {
return a.name === b.name ? 0 : (a.name < b.name ? -1 : 1);
}
});
// Remove names from numerical parameters
$tw.utils.each(result,function(param,index) {
if(!isNaN(param.name)) {
delete param.name;
}
});
return result;
};
/*
Fetch the value of a parameter
*/

View File

@@ -122,14 +122,14 @@ Widget.prototype.getVariableInfo = function(name,options) {
if(parentWidget && name in parentWidget.variables) {
var variable = parentWidget.variables[name],
originalValue = variable.value,
value = originalValue,
params = this.resolveVariableParameters(variable.params,actualParams);
// Substitute any parameters specified in the definition
$tw.utils.each(params,function(param) {
value = $tw.utils.replaceString(value,new RegExp("\\$" + $tw.utils.escapeRegExp(param.name) + "\\$","mg"),param.value);
});
// Only substitute variable references if this variable was defined with the \define pragma
value = originalValue;
// Only substitute parameter and variable references if this variable was defined with the \define pragma
if(variable.isMacroDefinition) {
var params = this.resolveVariableParameters(variable.params,actualParams);
// Substitute any parameters specified in the definition
$tw.utils.each(params,function(param) {
value = $tw.utils.replaceString(value,new RegExp("\\$" + $tw.utils.escapeRegExp(param.name) + "\\$","mg"),param.value);
});
value = this.substituteVariableReferences(value,options);
}
return {