1<?php 2 3use dokuwiki\Extension\SyntaxPlugin; 4 5/** 6 * DokuWiki Plugin number (Syntax Component) 7 * 8 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 9 * @author Vincent Tscherter <vincent@tscherter.net> 10 */ 11class syntax_plugin_number extends SyntaxPlugin 12{ 13 /** @inheritDoc */ 14 public function getType() 15 { 16 return 'substition'; 17 } 18 19 /** @inheritDoc */ 20 public function getPType() 21 { 22 return 'normal'; 23 } 24 25 /** @inheritDoc */ 26 public function getSort() 27 { 28 return 100; 29 } 30 31 /** @inheritDoc */ 32 public function connectTo($mode) 33 { 34 $this->Lexer->addSpecialPattern('{{n>.*?}}', $mode, 'plugin_number'); 35 } 36 37 /** @inheritDoc */ 38 public function handle($match, $state, $pos, Doku_Handler $handler) 39 { 40 41 $raw = substr($match, 4, -2); 42 $raw = strtolower($raw); 43 $raw = preg_replace('/[^0-9a-z_]/', '', $raw); 44 45 $data = []; 46 $data['raw'] = $raw; 47 48 if (preg_match('/^\d+(e\d+)?$/', $raw)) { 49 $data['type'] = 'dec'; 50 $data['value'] = intval($raw); 51 } else if (preg_match('/^0b[01]+$/', $raw)) { 52 $data['type'] = 'bin'; 53 $data['value'] = intval(substr($raw, 2), 2); 54 } else if (preg_match('/^0x[0-9a-f]+$/i', $raw)) { 55 $data['type'] = 'hex'; 56 $data['value'] = intval(substr($raw, 2), 16); 57 } else if (preg_match('/^[0-9a-z]+_[0-9]+$/i', $raw)) { 58 $data['type'] = 'padic'; 59 list($number, $base) = explode('_', $raw); 60 $data['value'] = intval($number, $base); 61 $data['number'] = $number; 62 $data['base'] = intval($base); 63 if ($data['base'] < 2 || $data['base'] > 36 || base_convert($data['value'], 10, $data['base']) != $number) 64 $data['value'] = NAN; 65 } else { 66 $data['value'] = NAN; 67 } 68 return $data; 69 } 70 71 static private function renderDec($value) 72 { 73 return '<code style="color: blue">'.$value.'</code>'; 74 } 75 76 static private function renderHex($value) 77 { 78 return '<code style="color: blue"><span style="color: red">0x</span>' 79 . (is_string($value) ? substr($value, 2) : dechex($value)) . '</code>'; 80 } 81 82 static private function renderBin($value) 83 { 84 return '<code style="color: blue"><span style="color: red">0b</span>' 85 . (is_string($value) ? substr($value, 2) : decbin($value)) . '</code>'; 86 } 87 88 const NUMBERSYSTEM = ';;Binary;Ternary;Quaternary;Quinary;Senary;Septenary;Octal;Nonary;Decimal;Undecimal;Duodecimal;Tridecimal;Tetradecimal;Pentadecimal;Hexadecimal;Heptadecimal;Octodecimal;Enneadecimal;Vigesimal;Unvigesimal;Duovigesimal;Trivigesimal;Tetravigesimal;Pentavigesimal;Hexavigesimal;Heptavigesimal;Octovigesimal;Enneavigesimal;Trigesimal;Untrigesimal;Duotrigesimal;Tritrigesimal;Tetratrigesimal;Pentatrigesimal; Hexatrigesimal'; 89 90 /** @inheritDoc */ 91 public function render($mode, Doku_Renderer $renderer, $data) 92 { 93 if ($mode !== 'xhtml') { 94 return false; 95 } 96 $value = $data['value']; 97 if (is_nan($value)) { 98 $renderer->doc .= '<code style="color: red">⚠️ warning: ' . $data['raw'] . ' is not a valid input</code>'; 99 return true; 100 } 101 if (!is_int($value) || $value >= PHP_INT_MAX) { 102 $renderer->doc .= '<code style="color: red">⚠️ warning: ' . $data['raw'] . ' is not a safe for conversion </code>'.$value; 103 return true; 104 } 105 $type = $data['type']; 106 if ($type == 'dec') { 107 $number = self::renderDec($data['raw']); 108 $tooltip = '<strong>Decimal number</strong> (base 10)<br>= ' 109 . self::renderBin($value) . ' (binary)'; 110 if ("~$value" != '~' . $data['raw']) { // 111 $tooltip .= '<br>= ' . self::renderDec($value) . ' (decimal)'; 112 } 113 $tooltip .= '<br>= ' . self::renderHex($value) . ' (hexadecimal)'; 114 } else if ($type == 'bin') { 115 $number = self::renderBin($data['raw']); 116 $tooltip = '<strong>Binary number</strong> (base 2)<br>= ' 117 . self::renderDec($value) . ' (decimal)<br>= ' 118 . self::renderHex($value) . ' (hexadecimal)'; 119 } else if ($type == 'hex') { 120 $number = self::renderHex($data['raw']); 121 $tooltip = '<strong>Hexadecimal number</strong> (base 16)<br>= ' 122 . self::renderBin($value) . ' (binary)<br>= ' 123 . self::renderDec($value) . ' (decimal)'; 124 } else if ($type == 'padic') { 125 $number = '<code style="color: blue"><span style="color: grey">[</span>' 126 . $data['number'] 127 . '<span style="color: grey">]</span><sub style="color: red">' 128 . $data['base'] . '</sub></code>'; 129 $tooltip = '<strong>' 130 . explode(';', self::NUMBERSYSTEM)[$data['base']] 131 . ' number</strong> (base ' . $data['base'] . ')<br>= ' 132 . self::renderBin($value) . ' (binary)<br>= ' 133 . self::renderDec($value) . ' (decimal)<br>= ' 134 . self::renderHex($value) . ' (hexadecimal)'; 135 } 136 // 137 $renderer->doc .= "<span class='plugin-number'><span class='plugin-number-tooltip'>$tooltip</span>$number</span>"; 138 139 return true; 140 } 141}