1<?php
2/**
3 * APIDoc plugin by marcus.runsten@stilit.se
4 *
5 * ToDo: Add coude highlighting
6 */
7
8if(!defined('DOKU_INC')) die("Caller error");
9
10class syntax_plugin_apidoc_data_class {
11	public $name="", $filename="", $extends="", $description="";
12	public $methods=array();
13	public $fields=array();
14
15	public function __construct( $f ) {
16		switch( min( count( $f ), 4 ) ) {
17			case 4:
18				$this->description = $f[3];
19			case 3:
20				$this->extends = $f[2];
21			case 2:
22				$this->filename = $f[1];
23			case 1:
24				$this->name = $f[0];
25			default:
26		}
27	}
28}
29
30class syntax_plugin_apidoc_data_field {
31	public $definition="", $name="", $description="";
32
33	public function __construct( $f ) {
34		switch( min( count( $f ), 3 ) ) {
35			case 3:
36				$this->description = $f[2];
37			case 2:
38				$this->definition = $f[1];
39			case 1:
40				$this->name = $f[0];
41			default:
42		}
43	}
44}
45
46class syntax_plugin_apidoc_data_method {
47	public $name="", $definition="", $description="", $parameters=array(), $returns="";
48
49	public function __construct( $f ) {
50		switch( min( count( $f ), 4 ) ) {
51			case 4:
52				$this->description = $f[3];
53			case 3:
54				$this->returns = $f[2];
55			case 2:
56				$this->definition = $f[1];
57			case 1:
58				$this->name = $f[0];
59			default:
60		}
61	}
62}
63
64class syntax_plugin_apidoc_data_parameter {
65	public $name="", $type="", $defaultvalue="", $description="";
66
67	public function __construct( $f, &$c ) {
68		switch( min( count( $f ), 4 ) ) {
69			case 4:
70				$this->description = $f[3];
71			case 3:
72				$this->defaultvalue = $f[2];
73			case 2:
74				$this->type = $f[1];
75			case 1:
76			$this->name = $f[0];
77			default:
78		}
79	}
80}
81
82class syntax_plugin_apidoc extends DokuWiki_Syntax_Plugin {
83
84	function getInfo(){
85      return array(
86        'author' => 'Marcus Runsten',
87        'email'  => 'marcus@stilit.se',
88        'date'   => '2015-11-12',
89        'name'   => 'API Documentation Plugin',
90        'desc'   => 'Adds syntax for API Documentation to DokuWiki. Version 1.1',
91        'url'    => 'http://www.stilit.se/?page_id=107'
92      );
93	}
94
95	function getType(){ return 'protected';}
96    function getPType(){ return 'block';}
97    function getSort(){ return 100; }
98
99	function connectTo($mode) {
100		$this->Lexer->addEntryPattern( '<apidoc(?=>.*?</apidoc>)', $mode, 'plugin_apidoc' );
101	}
102
103    function postConnect() {
104      $this->Lexer->addExitPattern('</apidoc>', 'plugin_apidoc');
105    }
106
107	function handle($match, $state, $pos, &$handler){
108        switch ($state) {
109          case DOKU_LEXER_ENTER:
110	        $this->syntax = substr($match, 1);
111			return false;
112
113          case DOKU_LEXER_UNMATCHED:
114			  file_put_contents( "/tmp/handle.txt", "Hanterar " . $match );
115			  if( $this->syntax == 'apidoc' ) {
116				  return $this->apidoc_parse( substr( $match, 1 ) );
117			  }
118        }
119        return false;
120    }
121
122    /**
123     * Create output
124     */
125    function render($mode, &$renderer, $data) {
126		if( $data ) $renderer->doc .= $data[0];
127		return true;
128    }
129
130	private function apidoc_highlight( $str, $bool ) {
131		$p = array( "/[\"\'].*?[\"\']/",
132					"/\[\[(.*?);(.*?)\]\]/",
133					"/\[\[(.*?)\]\]/",
134					"/[\d]x[\d]+?|[\d]/",
135					"/(^)([\w]+?)(\(.*?\))|(\s)([\w]+?)(\(.*?\))/",
136					"/[()]/",
137					"/[\\[\\]]/",
138					"/[\\{\\}]/",
139					'/(\$\w+?)([\s$])/',
140					"/(?i)const\s|public|private|protected|new/",
141					"/(?i)string|integer|boolean|bool|int|char|function/"
142					 );
143
144		$r = array( '<span class="apidoc_highlight_string">$0</span>',
145					'<a href="$1" class="apidoc_link">$2</a>',
146					'<a href="$1" class="apidoc_link">$1</a>',
147					'<span class="apidoc_highlight_digit">$0</span>',
148					'$1$4<span class="apidoc_highlight_method">$2$5</span>$3$6 ',
149					'<span class="apidoc_highlight_bracket">$0</span>',
150					'<span class="apidoc_highlight_squarebracket">$0</span>',
151					'<span class="apidoc_highlight_birdbracket">$0</span>',
152					'<span class="apidoc_highlight_variable">$1</span>$2',
153					'<span class="apidoc_highlight_avail">$0</span>',
154					'<span class="apidoc_highlight_type">$0</span>',
155					 );
156		return preg_replace( $p, $r, $str );
157	}
158
159	private function apidoc_out_html( $data ) {
160		$html = "<p class='apidoc_head'><span class='apidoc_classname apidoc_code'>";
161		$html .= $this->apidoc_highlight( $data->name, true );
162		$html .= "</span></p><table class='apidoc'><tr><td><div class='apidoc_left'><p class='apidoc_left_head'>Fields</p><ul class='apidoc_left_content'>";
163
164		foreach( $data->fields AS $f ) {
165			$html .= "<li><a href='#field_" . $f->name . "'><span class='apidoc_code'>" . $this->apidoc_highlight( $f->name, true ) . "</span></a></li>";
166		}
167
168		$html .= "</ul><p class='apidoc_left_head'>Methods</p><ul class='apidoc_left_content'>";
169		foreach( $data->methods AS $m ) {
170			$html .= "<li><a href='#method_" . $m->name . "'><span class='apidoc_code'>" . $this->apidoc_highlight( $m->name, true ) . "</span></a></li>";
171		}
172
173		$html .= "</ul></div></td><td class='apidoc_right'>";
174
175		$html .= "<p class='apidoc_right_bighead apidoc_code'>" . $this->apidoc_highlight( $data->name, true ) . "</p>";
176		$html .= "<p class='apidoc_right'><span class='apidoc_bold'>Filename : </span> " . $data->filename . "<br />";
177		$html .= "<span class='apidoc_bold'>Extends : </span><span class='apidoc_code'>" . $this->apidoc_highlight( $data->extends, true ) . "</span></p>";
178		$html .= "<p class='apidoc_right_head'>Description</p>";
179		$html .= "<p class='apidoc_right'>" . $data->description . "</p>";
180
181		$html .= "<p class='apidoc_right_bighead'>Fields</p>";
182		foreach( $data->fields AS $f ) {
183			$html .= "<div id='field_" . $f->name . "' class='apidoc_right_field'>";
184			$html .= "<p class='apidoc_right_head apidoc_code'>" . $this->apidoc_highlight( $f->name, true ) . "</p>";
185			$html .= "<p class='apidoc_right'><span class='apidoc_bold'>Definition : </span><span class='apidoc_code'>" . $this->apidoc_highlight( $f->definition, true ) . "<br />";
186			$html .= "<span class='apidoc_bold'>Description</span><br />" . $f->description . "</p>";
187			$html .= "</div>";
188		}
189
190		$html .= "<p class='apidoc_right_bighead'>Methods</p>";
191		foreach( $data->methods AS $m ) {
192			$html .= "<div id='method_" . $m->name . "' class='apidoc_right_method'>";
193			$html .= "<p class='apidoc_right_head apidoc_code'>" . $this->apidoc_highlight( $m->name, true ) . "</p>";
194			$html .= "<p class='apidoc_right'><span class='apidoc_bold'>Definition : </span><span class='apidoc_code'>" . $this->apidoc_highlight( $m->definition, true ) . "</span></p>";
195			$html .= "<p class='apidoc_right'><span class='apidoc_bold'>Returns : </span><span class='apidoc_code'>" . $this->apidoc_highlight( $m->returns, true ) . "</span></p>";
196			$html .= "<p class='apidoc_right'><span class='apidoc_bold'>Description</span><br />" . $m->description . "</p>";
197
198			$html .= "<div class='apidoc_right_parameters'>";
199			$html .= "<p class='apidoc_right_head'>Parameters</p>";
200			foreach( $m->parameters AS $p ) {
201				$html .= "<div class='apidoc_right_param'>";
202				$html .= "<p class='apidoc_right_head apidoc_code'>" . $this->apidoc_highlight( $p->name, true ) . "</p>";
203				$html .= "<p class='apidoc_right'>";
204				$html .= "<span class='apidoc_bold'>Type : </span><span class='apidoc_code'>" . $this->apidoc_highlight( $p->type, true ) . "</span><br />";
205				$html .= "<span class='apidoc_bold'>Default value : </span><span class='apidoc_code'>" . $this->apidoc_highlight( $p->defaultvalue, true ) . "</span>";
206				$html .= "</p>";
207				$html .= "<p class='apidoc_right'><span class='apidoc_bold'>Description</span><br />" . $p->description . "</p>";
208				$html .= "</div>";
209			}
210
211			$html .= "</div>";
212
213			$html .= "</div>";
214		}
215
216
217		return $html;
218	}
219
220	private function apidoc_parse( $str ) {
221		$data = $this->apidoc_parse_data( $str );
222		if( !$data ) return false;
223
224		$data = $this->apidoc_sort_data( $data );
225		if( !$data ) return false;
226
227		$html = $this->apidoc_out_html( $data );
228
229		return array( $html );
230	}
231
232	private function apidoc_parse_data( $str ) {
233		$rData = null;
234		$co = null;
235
236		$matches = preg_split( "/(CLASS|FIELD|METHOD|PARAMETER)\|/", $str, -1, PREG_SPLIT_DELIM_CAPTURE );
237		for( $i=0; $i < count( $matches )-1; $i++ ) {
238			switch( $matches[$i] ) {
239				case 'CLASS':
240					$rData = new syntax_plugin_apidoc_data_class( explode( "|", $matches[++$i] ) );
241					break;
242				case 'FIELD':
243					if( $rData == null ) return false;
244					$co = $rData->fields[] = new syntax_plugin_apidoc_data_field( explode( "|", $matches[++$i] ) );
245					break;
246				case 'METHOD':
247					if( $rData == null ) return false;
248					$co = $rData->methods[] = new syntax_plugin_apidoc_data_method( explode( "|", $matches[++$i] ) );
249					break;
250				case 'PARAMETER':
251					if( $rData == null || $co == null ) return false;
252					$co->parameters[] = new syntax_plugin_apidoc_data_parameter( explode( "|", $matches[++$i] ) );
253				default:	// Do nothing
254					break;
255			}
256		}
257		return $rData;
258	}
259
260	private function apidoc_sort( $arr ) {
261		$tgt = array();
262		while( count( $arr ) > 0 ) {
263			$smallest = 0;
264			for( $i=0; $i < count( $arr ); $i++ ) if( strcasecmp( $arr[$smallest]->name, $arr[$i]->name ) > 0 ) $smallest = $i;
265			$tgt[] = $arr[$smallest];
266			unset( $arr[$smallest] );
267			$arr = array_values( $arr );
268		}
269		return $tgt;
270	}
271
272	private function apidoc_sort_data( $data ) {
273		$data->fields = $this->apidoc_sort( $data->fields );
274		$data->methods = $this->apidoc_sort( $data->methods );
275		for( $i=0; $i < count( $data->methods ); $i++ ) $data->methods[$i]->parameters = $this->apidoc_sort( $data->methods[$i]->parameters );
276		return $data;
277	}
278}
279
280?>
281