-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfunction.highlight.php
113 lines (80 loc) · 2.63 KB
/
function.highlight.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
<?php
/**
* Highlights PHP syntax from the given string and formats it as HTML
*
* @version 1.0
* @author digitalnature, http://digitalnature.eu
* @param string $code
* @return string
*/
function highlight($code){
static
// tracks style inclusion state
$didStyles = false,
// caches tokenizer constants
$constants = null;
// get all tokenizer constants if this is the first call;
// we will use constants names as class names (eg. T_DOC_COMMENT => .tDocComment)
if(!$constants){
$constants = get_defined_constants();
// throw away constants that don't start with 'T_'
array_walk($constants, function($value, $key) use(&$constants){
if(strpos($key, 'T_') !== 0)
unset($constants[$key]);
});
}
$output = $styles = '';
$tokens = token_get_all((string)$code);
// iterate tokens and generate HTML
foreach($tokens as $token){
if($token[0] === T_OPEN_TAG) { continue; }
if($token[0] === T_CLOSE_TAG) { continue; }
// turn whitespace into a string token
if($token[0] === T_WHITESPACE)
$token = $token[1];
if(is_string($token)){
$output .= htmlspecialchars($token, ENT_QUOTES);
continue;
}
list($id, $text, $line) = $token;
// escape for HTML output
$text = htmlspecialchars($text, ENT_QUOTES);
// could be function name; attempt to linkify it
if($id === T_STRING){
try{
$reflector = new \ReflectionFunction($text);
if($reflector->isInternal())
$text = sprintf('<a href="http://php.net/manual/en/function.%s.php" target="_blank">%s</a>', str_replace('_', '-', $text), $text);
}catch(\Exception $e){
// not an internal function...
}
}
// get the token name
if(($class = array_search($id, $constants)) !== false){
// generate class name (camelize)
$class = lcfirst(implode('', array_map('ucwords', explode('_', strtolower($class)))));
$output .= sprintf('<span class="%s">%s</span>', $class, $text);
// we should never reach this point (!?)
}else{
$output .= $text;
}
}
// include styles if this is the first call
if(!$didStyles){
ob_start();
// assume document is html5;
// scoped styles are not yet supported by all browsers,
// but the class names are unique enough to avoid conflicts
?>
<style scoped>
/*<![CDATA[*/
<?php readfile(__DIR__ . '/highlight.css'); ?>
/*]]>*/
</style>
<?php
// normalize spacing
$styles = preg_replace('/\s+/', ' ', trim(ob_get_clean()));
$didStyles = true;
}
return sprintf('<pre class="code">%s%s</pre>', $styles, $output);
}