From e1c10e4d58dad58f2a8b4b121b62bd56045bf852 Mon Sep 17 00:00:00 2001
From: chris <chris@jalakai.co.uk>
Date: Sun, 9 Apr 2006 23:49:58 +0200
Subject: [PATCH] Parser Update:

- revisions to header class and section handling
  header pattern simplified
  header class now writes section open and close instructions
  section call writer removed
  check for and update meta['first_header'] if required (see below)

- meta instruction added
  written by _finalize to front of instruction stack
  holds first header information

  plugins can now write first header information, or other page meta information
  to this data structure.

- get_first_heading updated to make use of meta['first_header']

- plugin instruction structure changed to include lexer state in the data portion
  of the instruction.
  OLD INSTRUCTION:  array('plugin', array(<plugin name>,<plugin_data>,$pos), $pos)
  NEW INSTRUCTION:  array('plugin', array(<plugin name>,<plugin_data>,$state), $pos)

- block handler/call writer update to better handle plugin PTypes 'block' & 'stack'.
  Lexer states are mapped as follows:
    DOKU_LEXER_ENTER, DOKU_LEXER_SPECIAL     : block_open, stack_open
    DOKU_LEXER_EXIT, DOKU_LEXER_SPECIAL      : block_close, stack_close
    DOKU_LEXER_MATCHED, DOKU_LEXER_UNMATCHED : plugin must handle <p>

  Plugin writers can now use these PTypes as intended !

darcs-hash:20060409214958-9b6ab-cd2cef97a6a2521e3a02175075b8ff4648035f69.gz
---
 inc/parser/handler.php | 123 ++++++++++++++++++++---------------------
 inc/parser/parser.php  |  13 +----
 inc/parser/xhtml.php   |   9 ++-
 inc/parserutils.php    |   7 +--
 4 files changed, 72 insertions(+), 80 deletions(-)

diff --git a/inc/parser/handler.php b/inc/parser/handler.php
index 1b73c458f..2088942a1 100644
--- a/inc/parser/handler.php
+++ b/inc/parser/handler.php
@@ -10,6 +10,10 @@ class Doku_Handler {
     var $calls = array();
 
     var $meta = array(
+        'first_heading' => '',
+    );
+
+    var $status = array(
         'section' => FALSE,
     );
 
@@ -25,9 +29,10 @@ class Doku_Handler {
     }
 
     function _finalize(){
-        if ( $this->meta['section'] ) {
-            $S = & new Doku_Handler_Section();
-            $this->calls = $S->process($this->calls);
+
+        if ( $this->status['section'] ) {
+           $last_call = end($this->calls);
+           array_push($this->calls,array('section_close',array(), $last_call[2]));
         }
 
         if ( $this->rewriteBlocks ) {
@@ -36,6 +41,7 @@ class Doku_Handler {
         }
 
         array_unshift($this->calls,array('document_start',array(),0));
+        array_unshift($this->calls,array('meta',array($this->meta),0));
         $last_call = end($this->calls);
         array_push($this->calls,array('document_end',array(),$last_call[2]));
     }
@@ -63,7 +69,7 @@ class Doku_Handler {
         if($plugin != null){
             $data = $plugin->handle($match, $state, $pos, $this);
         }
-        $this->_addCall('plugin',array($pluginname,$data,$pos),$pos);
+        $this->_addCall('plugin',array($pluginname,$data,$state),$pos);
         return TRUE;
     }
 
@@ -79,29 +85,21 @@ class Doku_Handler {
 
     function header($match, $state, $pos) {
         $match = trim($match);
-        $levels = array(
-            '======'=>1,
-            '====='=>2,
-            '===='=>3,
-            '==='=>4,
-            '=='=>5,
-        );
-        $hsplit = preg_split( '/(={2,})/u', $match,-1,
-            PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY );
 
-        // Locate the level - default to level 1 if no match (title contains == signs)
-        if ( isset($hsplit[0]) && array_key_exists($hsplit[0], $levels) ) {
-            $level = $levels[$hsplit[0]];
-        } else {
-            $level = 1;
-        }
+        list($header,$title) = split(' ',$match,2);
+        $level = 7 - strlen($header);
 
         // Strip markers and whitespaces
         $title = trim($match,'=');
         $title = trim($title,' ');
 
+        if ($this->status['section']) $this->_addCall('section_close',array(),$pos);
+
         $this->_addCall('header',array($title,$level,$pos), $pos);
-        $this->meta['section'] = TRUE;
+
+        $this->_addCall('section_open',array($level),$pos);
+        $this->status['section'] = TRUE;
+        if (!$this->meta['first_heading']) $this->meta['first_heading'] = $title;
         return TRUE;
     }
 
@@ -1203,6 +1201,12 @@ class Doku_Handler_Section {
                 $inSection = TRUE;
 
             } else {
+
+                if ($call[0] == 'section_open' )  {
+                    $inSection = TRUE;
+                } else if ($call[0] == 'section_open' ) {
+                    $inSection = FALSE;
+                }
                 $sectionCalls[] = $call;
             }
         }
@@ -1274,14 +1278,10 @@ class Doku_Handler_Block {
             $ptype = $p->getPType();
             if($ptype == 'block'){
                 $this->blockOpen[]  = 'plugin_'.$n;
-                $this->blockOpen[]  = 'plugin_'.$n.'_open';
                 $this->blockClose[] = 'plugin_'.$n;
-                $this->blockClose[] = 'plugin_'.$n.'_close';
             }elseif($ptype == 'stack'){
                 $this->stackOpen[]  = 'plugin_'.$n;
-                $this->stackOpen[]  = 'plugin_'.$n.'_open';
                 $this->stackClose[] = 'plugin_'.$n;
-                $this->stackClose[] = 'plugin_'.$n.'_close';
             }
         }
     }
@@ -1313,6 +1313,8 @@ class Doku_Handler_Block {
         }else{
             $this->calls[] = array('p_close',array(), $pos);
         }
+
+        $this->inParagraph = FALSE;
     }
 
     /**
@@ -1325,17 +1327,19 @@ class Doku_Handler_Block {
     function process($calls) {
         foreach ( $calls as $key => $call ) {
             $cname = $call[0];
-            if($cname == 'plugin') $cname='plugin_'.$call[1][0];
+            if($cname == 'plugin') {
+                $cname='plugin_'.$call[1][0];
+
+                $plugin = true;
+                $plugin_open = (($call[1][2] == DOKU_LEXER_ENTER) || ($call[1][2] == DOKU_LEXER_SPECIAL));
+                $plugin_close = (($call[1][2] == DOKU_LEXER_EXIT) || ($call[1][2] == DOKU_LEXER_SPECIAL));
+            } else {
+                $plugin = false;
+            }
 
             // Process blocks which are stack like... (contain linefeeds)
-            if ( in_array($cname,$this->stackOpen ) ) {
-                /*
-                if ( $this->atStart ) {
-                    $this->calls[] = array('p_open',array(), $call[2]);
-                    $this->atStart = FALSE;
-                    $this->inParagraph = TRUE;
-                }
-                */
+            if ( in_array($cname,$this->stackOpen ) && (!$plugin || $plugin_open) ) {
+
                 $this->calls[] = $call;
 
                 // Hack - footnotes shouldn't immediately contain a p_open
@@ -1347,10 +1351,9 @@ class Doku_Handler_Block {
                 continue;
             }
 
-            if ( in_array($cname,$this->stackClose ) ) {
+            if ( in_array($cname,$this->stackClose ) && (!$plugin || $plugin_close)) {
 
                 if ( $this->inParagraph ) {
-                    //$this->calls[] = array('p_close',array(), $call[2]);
                     $this->closeParagraph($call[2]);
                 }
                 $this->calls[] = $call;
@@ -1362,18 +1365,9 @@ class Doku_Handler_Block {
 
                 if ( $cname == 'eol' ) {
 
-
-                    /* XXX
-                    if ( $this->inParagraph ) {
-                        $this->calls[] = array('p_close',array(), $call[2]);
-                    }
-                    $this->calls[] = array('p_open',array(), $call[2]);
-                    $this->inParagraph = TRUE;
-                    */
-
-                    # Check this isn't an eol instruction to skip...
+                    // Check this isn't an eol instruction to skip...
                     if ( $this->skipEolKey != $key ) {
-                         # Look to see if the next instruction is an EOL
+                        // Look to see if the next instruction is an EOL
                         if ( isset($calls[$key+1]) && $calls[$key+1][0] == 'eol' ) {
 
                             if ( $this->inParagraph ) {
@@ -1385,7 +1379,7 @@ class Doku_Handler_Block {
                             $this->inParagraph = TRUE;
 
 
-                            # Mark the next instruction for skipping
+                            // Mark the next instruction for skipping
                             $this->skipEolKey = $key+1;
 
                         }else{
@@ -1398,19 +1392,15 @@ class Doku_Handler_Block {
                 } else {
 
                     $storeCall = TRUE;
-                    if ( $this->inParagraph && in_array($cname, $this->blockOpen) ) {
-                        //$this->calls[] = array('p_close',array(), $call[2]);
+                    if ( $this->inParagraph && (in_array($cname, $this->blockOpen) && (!$plugin || $plugin_open))) {
                         $this->closeParagraph($call[2]);
-                        $this->inParagraph = FALSE;
                         $this->calls[] = $call;
                         $storeCall = FALSE;
                     }
 
-                    if ( in_array($cname, $this->blockClose) ) {
+                    if ( in_array($cname, $this->blockClose) && (!$plugin || $plugin_close)) {
                         if ( $this->inParagraph ) {
-                            //$this->calls[] = array('p_close',array(), $call[2]);
                             $this->closeParagraph($call[2]);
-                            $this->inParagraph = FALSE;
                         }
                         if ( $storeCall ) {
                             $this->calls[] = $call;
@@ -1418,15 +1408,24 @@ class Doku_Handler_Block {
                         }
 
                         // This really sucks and suggests this whole class sucks but...
-                        if ( isset($calls[$key+1])
-                            &&
-                            !in_array($calls[$key+1][0], $this->blockOpen)
-                            &&
-                            !in_array($calls[$key+1][0], $this->blockClose)
-                            ) {
+                        if ( isset($calls[$key+1])) {
+                            $cname_plusone = $calls[$key+1][0];
+                            if ($cname_plusone == 'plugin') {
+                                $cname_plusone = 'plugin'.$calls[$key+1][1][0];
+                                
+                                // plugin test, true if plugin has a state which precludes it requiring blockOpen or blockClose
+                                $plugin_plusone = true;
+                                $plugin_test = ($call[$key+1][1][2] == DOKU_LEXER_MATCHED) || ($call[$key+1][1][2] == DOKU_LEXER_MATCHED);
+                            } else {
+                                $plugin_plusone = false;
+                            }
+                            if ((!in_array($cname_plusone, $this->blockOpen) && !in_array($cname_plusone, $this->blockClose)) ||
+                                ($plugin_plusone && $plugin_test)
+                                ) {
 
-                            $this->calls[] = array('p_open',array(), $call[2]);
-                            $this->inParagraph = TRUE;
+                                $this->calls[] = array('p_open',array(), $call[2]);
+                                $this->inParagraph = TRUE;
+                            }
                         }
                     }
 
@@ -1487,4 +1486,4 @@ class Doku_Handler_Block {
     }
 }
 
-//Setup VIM: ex: et ts=4 enc=utf-8 :
+//Setup VIM: ex: et ts=4 enc=utf-8 :
\ No newline at end of file
diff --git a/inc/parser/parser.php b/inc/parser/parser.php
index a99d8da34..e5a58f336 100644
--- a/inc/parser/parser.php
+++ b/inc/parser/parser.php
@@ -222,22 +222,11 @@ class Doku_Parser_Mode_header extends Doku_Parser_Mode {
 
     function preConnect() {
         //we're not picky about the closing ones, two are enough
-
-        // Header 1 is special case - match 6 or more
         $this->Lexer->addSpecialPattern(
-                            '[ \t]*={6,}[^\n]+={2,}[ \t]*(?=\n)',
+                            '[ \t]*={2,6}[^\n]+={2,}[ \t]*(?=\n)',
                             'base',
                             'header'
                         );
-
-        // For the rest, match exactly
-        for ( $i = 5; $i > 1; $i--) {
-            $this->Lexer->addSpecialPattern(
-                                '[ \t]*={'.$i.'}[^\n]+={2,}[ \t]*(?=\n)',
-                                'base',
-                                'header'
-                            );
-        }
     }
 
     function getSort() {
diff --git a/inc/parser/xhtml.php b/inc/parser/xhtml.php
index 221e18da0..b3b341f9b 100644
--- a/inc/parser/xhtml.php
+++ b/inc/parser/xhtml.php
@@ -45,6 +45,12 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
 
     var $store = '';
 
+    var $meta = array();
+
+    function meta($data) {
+      if (is_array($data)) $this->meta = $data;
+    }
+
     function document_start() {
         //reset some internals
         $this->toc     = array();
@@ -562,6 +568,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
         $link['more']   = '';
         $link['class']  = $class;
         $link['url']    = $url;
+
         $link['name']   = $name;
         $link['title']  = $this->_xmlEntities($url);
         if($conf['relnofollow']) $link['more'] .= ' rel="nofollow"';
@@ -1060,4 +1067,4 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
     }
 }
 
-//Setup VIM: ex: et ts=4 enc=utf-8 :
+//Setup VIM: ex: et ts=4 enc=utf-8 :
\ No newline at end of file
diff --git a/inc/parserutils.php b/inc/parserutils.php
index 13c9396a0..b295ae152 100644
--- a/inc/parserutils.php
+++ b/inc/parserutils.php
@@ -390,11 +390,8 @@ function p_get_first_heading($id){
   $file = wikiFN($id);
   if (@file_exists($file)) {
     $instructions = p_cached_instructions($file,true);
-    foreach ( $instructions as $instruction ) {
-      if ($instruction[0] == 'header') {
-        return trim($instruction[1][0]);
-      }
-    }
+		$meta = $instructions[0][1];
+		return isset($meta[0]['first_heading']) ? trim($meta[0]['first_heading']) : NULL;
   }
   return NULL;
 }
-- 
GitLab