1<?php
2/**
3 * Plugin Linebreak: Inserts a line break
4 *
5 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
6 * @author     Christopher Smith <chris@jalakai.co.uk>
7 */
8
9// must be run within Dokuwiki
10if(!defined('DOKU_INC')) die();
11
12if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
13require_once(DOKU_PLUGIN.'action.php');
14
15/**
16 * All DokuWiki plugins to extend the parser/rendering mechanism
17 * need to inherit from this class
18 */
19class action_plugin_linebreak extends DokuWiki_Action_Plugin {
20
21    var $marker_id = 0;
22    var $linebreak_conversions = array();
23
24    /**
25     * return some info
26     */
27    function getInfo(){
28      return array(
29        'author' => 'Christopher Smith',
30        'email'  => 'chris@jalakai.co.uk',
31        'date'   => '2007-02-18',
32        'name'   => 'Linebreak Plugin',
33        'desc'   => 'Provide a line break for a new line in the raw wiki data',
34        'url'    => 'http://wiki.splitbrain.org/plugin:linebreak',
35      );
36    }
37
38    /**
39     * plugin should use this method to register its handlers with the dokuwiki's event controller
40     */
41    function register(&$controller) {
42      $controller->register_hook('PARSER_WIKITEXT_PREPROCESS', 'BEFORE',  $this, '_addspaces', NULL);
43      $controller->register_hook('PARSER_HANDLER_DONE','BEFORE', $this, '_fixsecedit', NULL);
44    }
45
46    /**
47     * add spaces before line breaks, required so syntax component pattern will match correctly
48     * record the offset changes so we can fix up the section edit offsets later
49     */
50    function _addspaces(&$event, $param) {
51
52      // preg pattern used to find line breaks which require spaces inserted before them
53      $pattern = '/(?!< )(\n+|$)/';
54
55      // marker to add at the start of the raw wiki data, it contains an id we use to access the location
56      // of the additional spaces added into the file
57      $marker = "~~LINEBREAK#{$this->marker_id}~~\n";
58
59      // get the location (offset) of all the spaces to be added
60      $linebreaks = array();
61      preg_match_all($pattern, $event->data, $linebreaks, PREG_OFFSET_CAPTURE);
62
63      for ($i=0; $i<count($linebreaks[0]); $i++) {
64        $conversion[] = $linebreaks[0][$i][1];
65      }
66
67      // save details of the added spaces
68      $this->linebreak_conversions[$this->marker_id] = $conversion;
69
70      // add in the spaces
71      $event->data = $marker.preg_replace($pattern,' $1',$event->data);
72
73      // update the marker id so that the next use gets a fresh id.
74      $this->marker_id++;
75    }
76
77    function _fixsecedit(&$event, $param) {
78
79      // find our linebreak marker instruction and get the marker id
80      $calls =& $event->data->calls;
81      $marker = null;
82
83      for ($i=0; $i < count($calls); $i++) {
84        if ($calls[$i][0] == 'plugin' && $calls[$i][1][0] == 'linebreak' && isset($calls[$i][1][1]['marker'])) {
85          $marker = $calls[$i][1][1]['marker'];
86          break;
87        }
88      }
89
90      if (is_null($marker)) return;
91
92      // calculate the amount added to the start of the raw wiki data for our marker tag
93      $this->base_delta = strlen("~~LINEBREAK#$marker~~\n");
94      $this->current_marker = $marker;
95
96      // iterate through the instruction list and set the file offset values (usually the $pos variable)
97      // back to the values they would be if no spaces had been added by this plugin
98      for ($i=0; $i < count($calls); $i++) {
99        if ($calls[$i][0] == 'section_edit') {
100          $calls[$i][1][0] = $this->_convert($calls[$i][1][0]);
101          $calls[$i][1][1] = $this->_convert($calls[$i][1][1]);
102          $calls[$i][2] = $this->_convert($calls[$i][2]);
103        } else {
104//          $calls[$i][2] = $this->_convert($calls[$i][2]);
105				}
106      }
107    }
108
109    /**
110     *  convert modified raw wiki offset value ($pos) back to the unmodified value
111     */
112    function _convert($pos) {
113      global $debug;
114
115      // file start values will still be file start values - don't change them
116      if ($pos <= 1) return $pos;
117
118      $pos -= $this->base_delta;
119      if ($pos < 0) return 0;
120
121      // simplify access to the conversion data
122      $conversion =& $this->linebreak_conversions[$this->current_marker];
123
124      for ($i=0; $i<count($conversion); $i++) {
125        // the conversion contains the original source position
126        // we need to add in the modifications up to that point and compare against $pos
127        // remembering we have already modified $pos for the marker string we added first
128        if ($conversion[$i] + $i >= $pos) {
129          return $pos - $i;
130        }
131      }
132
133      // $i will be one more than the number of modifications made
134      return $pos - $i -1;
135    }
136
137}
138
139//Setup VIM: ex: et ts=4 enc=utf-8 :