http://www.mediawiki.org/wiki/Special:Code/MediaWiki/93717

Revision: 93717
Author:   brion
Date:     2011-08-02 09:40:00 +0000 (Tue, 02 Aug 2011)
Log Message:
-----------
ParserPlayground -- checking in my airplane work :D

Starting on primitive parser environment with extension points for parser 
functions & tag hooks, start on moving the <ref> support out to a tag hook 
extension.

Doing this one as a 'pure-wiki-tree' extension which expands to additional 
nodes within the tree which can be rendered by the core renderer.

Modified Paths:
--------------
    trunk/extensions/ParserPlayground/ParserPlayground.php
    trunk/extensions/ParserPlayground/modules/ext.parserPlayground.js
    trunk/extensions/ParserPlayground/modules/ext.parserPlayground.renderer.js
    trunk/extensions/ParserPlayground/modules/pegParser.pegjs.txt
    trunk/extensions/ParserPlayground/tests/parserTests.js
    trunk/extensions/ParserPlayground/tests/parserTests.pegjs

Added Paths:
-----------
    trunk/extensions/ParserPlayground/modules/ext.cite.taghook.ref.js
    trunk/extensions/ParserPlayground/modules/mediawiki.parser.environment.js

Modified: trunk/extensions/ParserPlayground/ParserPlayground.php
===================================================================
--- trunk/extensions/ParserPlayground/ParserPlayground.php      2011-08-02 
09:38:46 UTC (rev 93716)
+++ trunk/extensions/ParserPlayground/ParserPlayground.php      2011-08-02 
09:40:00 UTC (rev 93717)
@@ -61,6 +61,9 @@
 
 $wgResourceModules['ext.parserPlayground'] = array(
        'scripts' => array(
+               'mediawiki.parser.environment.js',
+               'ext.cite.taghook.ref.js',
+
                'lib.jsdiff.js',
                'lib.pegjs.js',
                'jquery.nodetree.js',

Added: trunk/extensions/ParserPlayground/modules/ext.cite.taghook.ref.js
===================================================================
--- trunk/extensions/ParserPlayground/modules/ext.cite.taghook.ref.js           
                (rev 0)
+++ trunk/extensions/ParserPlayground/modules/ext.cite.taghook.ref.js   
2011-08-02 09:40:00 UTC (rev 93717)
@@ -0,0 +1,160 @@
+/**
+ * The ref / references tags don't do any fancy HTML, so we can actually
+ * implement this in terms of parse tree manipulations, skipping the need
+ * for renderer-specific plugins as well.
+ *
+ * Pretty neat huh!
+ */
+
+MWRefTagHook = function( env ) {
+       if (!('cite' in env)) {
+               env.cite = {
+                       refGroups: {}
+               };
+       }
+       var refGroups = env.cite.refGroups;
+
+       var getRefGroup = function(group) {
+               if (!(group in refGroups)) {
+                       var refs = [],
+                               byName = {};
+                       refGroups[group] = {
+                               refs: refs,
+                               byName: byName,
+                               add: function(node, options) {
+                                       var ref;
+                                       if (options.name && options.name in 
byName) {
+                                               ref = byName[options.name];
+                                       } else {
+                                               var n = refs.length;
+                                               var key = n + '';
+                                               if (options.name) {
+                                                       key = options.name + 
'-' + key;
+                                               }
+                                               ref = {
+                                                       node: node,
+                                                       index: n,
+                                                       groupIndex: n, // @fixme
+                                                       name: options.name,
+                                                       group: options.group,
+                                                       key: key,
+                                                       target: 'cite_note-' + 
key,
+                                                       linkbacks: []
+                                               };
+                                               refs[n] = ref;
+                                               if (options.name) {
+                                                       byName[options.name] = 
ref;
+                                               }
+                                       }
+                                       ref.linkbacks.push(
+                                               'cite_ref-' + ref.key + '-' + 
ref.linkbacks.length
+                                       );
+                                       return ref;
+                               }
+                       }
+               }
+               return refGroups[group];
+       };
+
+       this.execute = function( node ) {
+               var options = $.extend({
+                       name: null,
+                       group: null
+               }, node.params);
+               
+               var group = getRefGroup(options.group);
+               var ref = group.add(node, options);
+               var linkback = ref.linkbacks[ref.linkbacks.length - 1];
+
+               var bits = []
+               if (options.group) {
+                       bits.push(options.group);
+               }
+               bits.push(env.formatNum( ref.groupIndex + 1 ));
+
+               return {
+                       type: 'span',
+                       attrs: {
+                               id: linkback,
+                               'class': 'reference'
+                       },
+                       content: [
+                               {
+                                       type: 'hashlink',
+                                       target: '#' + ref.target,
+                                       content: [
+                                               '[' + bits.join(' ')  + ']'
+                                       ]
+                               },
+                       ],
+                       origNode: node
+               };
+       };
+};
+
+MWReferencesTagHook = function( env ) {
+       var refGroups = env.cite.refGroups;
+       
+       var arrow = '↑';
+       var renderLine = function( ref ) {
+               var out = {
+                       type: 'li',
+                       attrs: {
+                               id: 'cite-note-' + ref.target
+                       },
+                       content: []
+               };
+               if (ref.linkbacks.length == 1) {
+                       out.content.push({
+                               type: 'hashlink',
+                               target: '#' + ref.linkbacks[0],
+                               content: [
+                                       arrow
+                               ]
+                       })
+               } else {
+                       out.content.push(arrow)
+                       $.each(ref.linkbacks, function(i, linkback) {
+                               out.contents.push({
+                                       type: 'hashlink',
+                                       target: '#' + ref.linkbacks[0],
+                                       content: [
+                                               env.formatNum( ref.groupIndex + 
'.' + i)
+                                       ]
+                               });
+                       })
+               }
+               out.content.push(' ');
+               out.content.push({
+                       type: 'placeholder',
+                       content: ref.node.content
+               });
+               return out;
+       };
+       this.execute = function( node ) {
+               var options = $.extend({
+                       name: null,
+                       group: null
+               }, node.params);
+               if (options.group in refGroups) {
+                       var group = refGroups[options.group];
+                       return {
+                               type: 'ol',
+                               attrs: {
+                                       'class': 'references'
+                               },
+                               content: $.each(group, renderLine),
+                               origNode: node
+                       }
+               } else {
+                       return {
+                               type: 'placeholder',
+                               origNode: node
+                       }
+               }
+       }
+}
+
+if (typeof module == "object") {
+       module.exports.MWRefTagHook = MWRefTagHook;
+}

Modified: trunk/extensions/ParserPlayground/modules/ext.parserPlayground.js
===================================================================
--- trunk/extensions/ParserPlayground/modules/ext.parserPlayground.js   
2011-08-02 09:38:46 UTC (rev 93716)
+++ trunk/extensions/ParserPlayground/modules/ext.parserPlayground.js   
2011-08-02 09:40:00 UTC (rev 93717)
@@ -124,12 +124,17 @@
                                var pp = context.parserPlayground;
                                pp.parser = new parserClass();
                                // hack
+                               pp.env = new MWParserEnvironment({
+                                       tagHooks: {
+                                               'ref': MWRefTagHook
+                                       }
+                               });
                                if (pp.parser instanceof MediaWikiParser) {
                                        pp.serializer = pp.parser;
                                        pp.renderer = pp.parser;
                                } else {
                                        pp.serializer = new MWTreeSerializer();
-                                       pp.renderer = new MWTreeRenderer();
+                                       pp.renderer = new 
MWTreeRenderer(pp.env);
                                }
                                context.parserPlayground.fn.initDisplay();
                                $.cookie('pp-editmode', className, {

Modified: 
trunk/extensions/ParserPlayground/modules/ext.parserPlayground.renderer.js
===================================================================
--- trunk/extensions/ParserPlayground/modules/ext.parserPlayground.renderer.js  
2011-08-02 09:38:46 UTC (rev 93716)
+++ trunk/extensions/ParserPlayground/modules/ext.parserPlayground.renderer.js  
2011-08-02 09:40:00 UTC (rev 93717)
@@ -1,9 +1,9 @@
 /**
  * @param {ParserContext} context
  */
-function MWTreeRenderer(context) {
+function MWTreeRenderer(env) {
        // whee
-       this.context = context || {};
+       this.env = env || {};
 }
 
 /**
@@ -45,6 +45,7 @@
                        // A sequence of block-level elements...
                        var page = $('<div class="parseNode"></div>');
                        subParseArray(tree.content, page);
+                       /*
                        if (self.context.refs) {
                                // We're at the end; drop all the remaining 
refs!
                                subParseArray([{
@@ -52,6 +53,7 @@
                                        name: 'references'
                                }], page);
                        }
+                       */
                        node = page[0];
                        break;
                case 'para':
@@ -111,7 +113,42 @@
                        t.append('}}');
                        node = t[0];
                        break;
+               case 'placeholder':
+                       if ('content' in tree) {
+                               var $place = $('<span>'); // hmmmm
+                               subParseArray(tree.content, $place);
+                               node = $place[0];
+                       }
+                       break;
+               case 'span':
+                       var $span = $('<span>');
+                       if ('attrs' in tree) {
+                               $.map(tree.attrs, function(val, key) {
+                                       $span.attr(key, val); // @fixme safety!
+                               });
+                               if ('content' in tree) {
+                                       subParseArray(tree.content, $span);
+                               }
+                       }
+                       node = $span[0];
+                       break;
+               case 'hashlink':
+                       var $a = $('<a>');
+                       $a.attr('href', '#' + tree.target);
+                       subParseArray(tree.content, $a);
+                       node = $a[0];
+                       break;
                case 'ext':
+                       var hook = this.env.getTagHook(tree.name);
+                       if (!hook) {
+                               console.log('kabooom! no ext ' + tree.name)
+                       }
+                       var transformed = hook.execute(tree);
+                       var $ext = $('<span>'); // hmmmm
+                       subParseArray([transformed], $ext);
+                       node = $ext[0];
+                       // @fixme 
+                       /*
                        if (tree.name == 'ref') {
                                // Save the reference for later!
                                // @fixme names etc?
@@ -176,6 +213,7 @@
                                callback(null, 'Unrecognized extension in parse 
tree');
                                return;
                        }
+                       */
                        break;
                case 'comment':
                        var h = $('<span class="parseNode 
comment"></span>').text('<!--' + tree.text + '-->');

Added: trunk/extensions/ParserPlayground/modules/mediawiki.parser.environment.js
===================================================================
--- trunk/extensions/ParserPlayground/modules/mediawiki.parser.environment.js   
                        (rev 0)
+++ trunk/extensions/ParserPlayground/modules/mediawiki.parser.environment.js   
2011-08-02 09:40:00 UTC (rev 93717)
@@ -0,0 +1,86 @@
+var MWParserEnvironment = function(opts) {
+       var options = {
+               tagHooks: {},
+               parserFunctions: {}
+       };
+       $.extend(options, opts);
+       this.tagHooks = options.tagHooks;
+       this.parserFunctions = options.parserFunctions;
+};
+
+$.extend(MWParserEnvironment.prototype, {
+       // Does this need separate UI/content inputs?
+       formatNum: function( num ) {
+               return num + '';
+       },
+
+       getVariable: function( varname, options ) {
+               //
+       },
+
+       /**
+        * @return MWParserFunction
+        */
+       getParserFunction: function( name ) {
+               if (name in this.parserFunctions) {
+                       return new this.parserFunctions[name]( this );
+               } else {
+                       return null;
+               }
+       },
+
+       /**
+        * @return MWParserTagHook
+        */
+       getTagHook: function( name ) {
+               if (name in this.tagHooks) {
+                       return new this.tagHooks[name](this);
+               } else {
+                       return null;
+               }
+       }
+       
+});
+
+
+
+/**
+ * @parm MWParserEnvironment env
+ * @constructor
+ */
+MWParserTagHook = function( env ) {
+       if (!env) {
+               throw new Error( 'Tag hook requires a parser environment.' );
+       }
+       this.env = env;
+};
+
+/**
+ * @param string text (or a parse tree?)
+ * @param object params map of named parameters (strings or parse frames?)
+ * @return either a string or a parse frame -- finalize this?
+ */
+MWParserTagHook.execute = function( text, params ) {
+       return '';
+};
+
+
+MWParserFunction = function( env) {
+       if (!env) {
+               throw new Error( 'Parser funciton requires a parser 
environment.');
+       }
+       this.env = env;
+};
+
+/**
+ * @param string text (or a parse tree?)
+ * @param object params map of named parameters (strings or parse frames?)
+ * @return either a string or a parse frame -- finalize this?
+ */
+MWParserFunction.execute = function( text, params ) {
+       return '';
+};
+
+if (typeof module == "object") {
+       module.exports.MWParserEnvironment = MWParserEnvironment;
+}

Modified: trunk/extensions/ParserPlayground/modules/pegParser.pegjs.txt
===================================================================
--- trunk/extensions/ParserPlayground/modules/pegParser.pegjs.txt       
2011-08-02 09:38:46 UTC (rev 93716)
+++ trunk/extensions/ParserPlayground/modules/pegParser.pegjs.txt       
2011-08-02 09:40:00 UTC (rev 93717)
@@ -239,8 +239,9 @@
 
 ref = ref_full / ref_empty
 
+/* Can we do backreferences to genericize this? */
 ref_full
-  = start:ref_start ">" content:ref_content+ close:ref_end {
+  = start:ref_start ">" content:ref_content* close:ref_end {
     return {
         type: 'ext',
         name: 'ref',

Modified: trunk/extensions/ParserPlayground/tests/parserTests.js
===================================================================
--- trunk/extensions/ParserPlayground/tests/parserTests.js      2011-08-02 
09:38:46 UTC (rev 93716)
+++ trunk/extensions/ParserPlayground/tests/parserTests.js      2011-08-02 
09:40:00 UTC (rev 93717)
@@ -39,6 +39,9 @@
 global.PEG = _require('lib.pegjs.js');
 
 // Our code...
+_import('mediawiki.parser.environment.js', ['MWParserEnvironment']);
+_import('ext.cite.taghook.ref.js', ['MWRefTagHook']);
+
 _import('ext.parserPlayground.serializer.js', ['MWTreeSerializer']);
 _import('ext.parserPlayground.renderer.js', ['MWTreeRenderer']);
 _import('ext.parserPlayground.pegParser.js', ['PegParser']);
@@ -47,10 +50,16 @@
 PegParser.src = fs.readFileSync(path.join(basePath, 'pegParser.pegjs.txt'), 
'utf8');
 
 var parser = new PegParser();
-var renderer = new MWTreeRenderer();
 
+var testFileName = '../../../tests/parser/parserTests.txt'; // default
+if (process.argv.length > 2) {
+       // hack :D
+       testFileName = process.argv[2];
+       console.log(testFileName);
+}
+
 var testParser = PEG.buildParser(fs.readFileSync('parserTests.pegjs', 'utf8'));
-var testFile = fs.readFileSync('../../../tests/parser/parserTests.txt', 
'utf8');
+var testFile = fs.readFileSync(testFileName, 'utf8');
 
 
 try {
@@ -108,6 +117,12 @@
                if (err) {
                        console.log('PARSE FAIL', err);
                } else {
+                       var environment = new MWParserEnvironment({
+                               tagHooks: {
+                                       'ref': MWRefTagHook
+                               }
+                       });
+                       var renderer = new MWTreeRenderer(environment);
                        renderer.treeToHtml(tree, function(node, err) {
                                if (err) {
                                        console.log('RENDER FAIL', err);

Modified: trunk/extensions/ParserPlayground/tests/parserTests.pegjs
===================================================================
--- trunk/extensions/ParserPlayground/tests/parserTests.pegjs   2011-08-02 
09:38:46 UTC (rev 93716)
+++ trunk/extensions/ParserPlayground/tests/parserTests.pegjs   2011-08-02 
09:40:00 UTC (rev 93717)
@@ -33,7 +33,8 @@
     comment /
     article /
     test /
-    line
+    line /
+    hooks
 
 
 
@@ -112,3 +113,18 @@
 end_test =
     "!!" ws? "end" ws? eol
 
+
+hooks =
+    start_hooks text:text end_hooks
+{
+    return {
+        type: 'hooks',
+        text: text
+    }
+}
+
+start_hooks =
+    "!!" ws? "hooks" ":"? ws? eol
+
+end_hooks =
+    "!!" ws? "endhooks" ws? eol


_______________________________________________
MediaWiki-CVS mailing list
MediaWiki-CVS@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-cvs

Reply via email to