1
0
mirror of https://github.com/Jermolene/TiddlyWiki5 synced 2024-06-26 15:23:15 +00:00

Store macros in the render context so that they scope in the expected way

This commit is contained in:
Jeremy Ruston 2012-12-29 23:17:09 +00:00
parent ea13652a64
commit f496cd540e
7 changed files with 69 additions and 16 deletions

View File

@ -75,12 +75,12 @@ exports.parse = function() {
text = "";
}
// Save the macro definition
this.parser.macroDefinitions[this.match[1]] = {
type: "textmacro",
return [{
type: "macrodef",
name: this.match[1],
params: params,
text: text
};
}];
};
})();

View File

@ -57,6 +57,8 @@ exports.parse = function() {
if(tokens.length > 0) {
this.parser.amendRules(tokens[0],tokens.slice(1));
}
// No parse tree nodes to return
return [];
};
})();

View File

@ -44,21 +44,20 @@ var WikiParser = function(type,text,options) {
this.sourceLength = this.source.length;
// Set current parse position
this.pos = 0;
// Initialise the things that pragma rules can change
this.macroDefinitions = {}; // Hash map of macro definitions
// Instantiate the pragma parse rules
this.pragmaRules = this.instantiateRules(this.pragmaRuleClasses,"pragma",0);
// Instantiate the parser block and inline rules
this.blockRules = this.instantiateRules(this.blockRuleClasses,"block",0);
this.inlineRules = this.instantiateRules(this.inlineRuleClasses,"inline",0);
// Parse any pragmas
this.parsePragmas();
this.tree = this.parsePragmas();
// Parse the text into inline runs or blocks
if(options.parseAsInline) {
this.tree = this.parseInlineRun();
this.tree.push.apply(this.tree,this.parseInlineRun());
} else {
this.tree = this.parseBlocks();
this.tree.push.apply(this.tree,this.parseBlocks());
}
// Return the parse tree
};
/*
@ -125,22 +124,24 @@ WikiParser.prototype.findNextMatch = function(rules,startPos) {
Parse any pragmas at the beginning of a block of parse text
*/
WikiParser.prototype.parsePragmas = function() {
var tree = [];
while(true) {
// Skip whitespace
this.skipWhitespace();
// Check for the end of the text
if(this.pos >= this.sourceLength) {
return;
break;
}
// Check if we've arrived at a pragma rule match
var nextMatch = this.findNextMatch(this.pragmaRules,this.pos);
// If not, just exit
if(!nextMatch || nextMatch.matchIndex !== this.pos) {
return;
break;
}
// Process the pragma rule
nextMatch.rule.parse();
tree.push.apply(tree,nextMatch.rule.parse());
}
return tree;
};
/*

View File

@ -21,11 +21,9 @@ var MacroCallRenderer = function(renderTree,renderContext,parseTreeNode) {
this.renderContext = renderContext;
this.parseTreeNode = parseTreeNode;
// Find the macro definition
var macro,childTree;
if($tw.utils.hop(this.renderTree.parser.macroDefinitions,this.parseTreeNode.name)) {
macro = this.renderTree.parser.macroDefinitions[this.parseTreeNode.name];
}
var macro = this.findMacroDefinition(this.parseTreeNode.name);
// Insert an error message if we couldn't find the macro
var childTree;
if(!macro) {
childTree = [{type: "text", text: "<<Undefined macro: " + this.parseTreeNode.name + ">>"}];
} else {
@ -38,6 +36,20 @@ var MacroCallRenderer = function(renderTree,renderContext,parseTreeNode) {
this.children = this.renderTree.createRenderers(this.renderContext,childTree);
};
/*
Find a named macro definition
*/
MacroCallRenderer.prototype.findMacroDefinition = function(name) {
var context = this.renderContext;
while(context) {
if(context.macroDefinitions && context.macroDefinitions[name]) {
return context.macroDefinitions[name];
}
context = context.parentContext;
}
return undefined;
};
/*
Expand the parameters in a block of text
*/

View File

@ -0,0 +1,30 @@
/*\
title: $:/core/modules/rendertree/renderers/macrodef.js
type: application/javascript
module-type: wikirenderer
Macro definition renderer
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
/*
Macro definition renderer
*/
var MacroDefRenderer = function(renderTree,renderContext,parseTreeNode) {
// Store state information
this.renderTree = renderTree;
this.renderContext = renderContext;
this.parseTreeNode = parseTreeNode;
// Save the macro definition into the render context
this.renderContext.macroDefinitions = this.renderContext.macroDefinitions || {};
this.renderContext.macroDefinitions[this.parseTreeNode.name] = this.parseTreeNode;
};
exports.macrodef = MacroDefRenderer
})();

View File

@ -106,7 +106,14 @@ WidgetRenderer.prototype.refreshInDom = function(changedTiddlers) {
};
WidgetRenderer.prototype.getContextTiddlerTitle = function() {
return this.renderContext ? this.renderContext.tiddlerTitle : undefined;
var context = this.renderContext;
while(context) {
if($tw.utils.hop(context,"tiddlerTitle")) {
return context.tiddlerTitle;
}
context = context.parentContext;
}
return undefined;
};
/*

View File

@ -33,6 +33,7 @@ An renderContext consists of these fields:
parentContext: reference back to previous context in the stack
*/
WikiRenderTree.prototype.execute = function(renderContext) {
renderContext = renderContext || {};
this.rendererTree = this.createRenderers(renderContext,this.parser.tree);
};