Jak pokolorować składnię Delphi używając funkcji PHP
Adam Boduch
Oto gotowa funkcja:
function _IsInArray($array, $element)
{
return isset($array[$element]);
}
function _IsCharValid($c)
{
if(($c >= 'a' && $c <= 'z') || ($c >= '0' && $c <= '9') || ($c >= 'A' && $c <= 'Z') || $c == '_')
{
return true;
}
return false;
}
function _HTMLEntity($c)
{
switch($c)
{
case '<':
return '<';
case '>':
return '>';
case '&':
return '&';
default:
return $c;
}
}
function highlight_delphi($source)
{
$source = str_replace(array("\r\n", "\r"), array("\n", "\n"), $source).' ';
$retval = '';
$code = &$source;
$clen = strlen($code);
$keywords = array(
'abstract' => true, 'and' => true, 'array' => true, 'as' => true, 'asm' => true, 'at' => true, 'begin' => true, 'case' => true,
'class' => true, 'const' => true, 'constructor' => true, 'contains' => true, 'destructor' => true,
'dispinterface' => true, 'div' => true, 'do' => true, 'downto' => true, 'else' => true, 'end' => true, 'except' => true,
'export' => true, 'exports' => true, 'external' => true, 'file' => true, 'finalization' => true, 'finally' => true,
'for' => true, 'function' => true, 'goto' => true, 'if' => true, 'implementation' => true, 'in' => true, 'inherited' => true,
'initialization' => true, 'inline' => true, 'interface' => true, 'is' => true, 'label' => true, 'library' => true,
'mod' => true, 'not' => true, 'object' => true, 'of' => true, 'on' => true, 'or' => true, 'overload' => true, 'override' => true,
'package' => true, 'packed' => true, 'private' => true, 'procedure' => true, 'program' => true, 'property' => true,
'protected' => true, 'public' => true, 'published' => true, 'raise' => true, 'record' => true, 'register' => true,
'repeat' => true, 'requires' => true, 'resourcestring' => true, 'set' => true, 'shl' => true, 'shr' => true, 'then' => true,
'threadvar' => true, 'to' => true, 'try' => true, 'type' => true, 'unit' => true, 'until' => true, 'uses' => true, 'var' => true,
'virtual' => true, 'while' => true, 'with' => true, 'xor' => true, 'assembler' => true, 'far' => true,
'near' => true, 'pascal' => true, 'register' => true, 'cdecl' => true, 'safecall' => true, 'stdcall' => true, 'varargs' => true);
$types = array(
'ansichar' => true, 'ansistring' => true, 'bool' => true, 'boolean' => true, 'byte' => true, 'bytebool' => true, 'cardinal' => true, 'char' => true,
'comp' => true, 'currency' => true, 'dword' => true, 'double' => true, 'extended' => true, 'int64' => true, 'integer' => true, 'iunknown' => true,
'longbool' => true, 'longint' => true, 'longword' => true, 'pansichar' => true, 'pansistring' => true, 'pbool' => true, 'pboolean' => true, 'pbyte' => true,
'pbytearray' => true, 'pcardinal' => true, 'pchar' => true, 'pcomp' => true, 'pcurrency' => true, 'pdword' => true, 'pdate' => true, 'pdatetime' => true,
'pdouble' => true, 'pextended' => true, 'pint64' => true, 'pinteger' => true, 'plongint' => true, 'plongword' => true, 'pointer' => true, 'ppointer' => true,
'pshortint' => true, 'pshortstring' => true, 'psingle' => true, 'psmallint' => true, 'pstring' => true, 'phandle' => true, 'pvariant' => true, 'pword' => true,
'pwordarray' => true, 'pwordbool' => true, 'pwidechar' => true, 'pwidestring' => true, 'real' => true, 'real48' => true, 'shortint' => true, 'shortstring' => true,
'single' => true, 'smallint' => true, 'string' => true, 'tclass' => true, 'tdate' => true, 'tdatetime' => true, 'textfile' => true, 'thandle' => true,
'tobject' => true, 'ttime' => true, 'variant' => true, 'widechar' => true, 'widestring' => true, 'word' => true, 'wordbool' => true);
$operators = array(
'+' => true, '-' => true, '*' => true, '/' => true, '^' => true, '.' => true, '>' => true,
'<' => true, '=' => true, ';' => true, ':' => true, ',' => true);
$brackets = array(
'(' => true, ')' => true, '[' => true, ']' => true);
$token = ''; $hex = false;
for($i = 0; $i < $clen; ++$i)
{
$char = $code[$i];
if(_IsCharValid($char))
{
$token .= $char;
if(_IsInArray(&$keywords, strtolower($token)))
{
if(_IsCharValid($code[$i + 1]))
{
continue;
}
$retval .= ('<span style="color: blue; font-weight: bold">' . $token . '</span>');
$token = '';
}
if(_IsInArray(&$types, strtolower($token)))
{
if(_IsCharValid($code[$i + 1]))
{
continue;
}
$retval .= ('<span style="color: maroon">' . $token . '</span>');
$token = '';
}
if(($token >= '0' && $token <= '9') || $hex)
{
$retval .= ('<span style="color: #800080">' . $token . '</span>');
$token = '';
}
}
else
{
$hex = false;
if($char == '$')
{
$retval .= '<span style="color: #800080">$</span>';
$hex = true;
continue;
}
if($token != '')
{
$retval .= $token;
$token = '';
}
if($char == '{' && $code[$i + 1] == '$')
{
$retval .= '<span style="color: #808080">';
$j = $i;
while($j < $clen && ($code[$j] != "}"))
{
$retval .= _HTMLEntity($code[$j]);
++$j;
}
if($j < $clen)
{
$retval .= '}';
}
$retval .= '</span>';
$i = $j;
}
elseif($char == '\'')
{
$retval .= '<span style="color: red">';
$j = $i + 1;
$retval .= '\'';
while($j < $clen && $code[$j] != '\'')
{
$retval .= _HTMLEntity($code[$j]);
++$j;
}
if($j < $clen)
{
$retval .= '\'';
}
$retval .= '</span>';
$i = $j;
}
elseif($char == '/' && $code[$i + 1] == '/')
{
$retval .= '<span style="color: #808080">';
$j = $i;
while($j < $clen && $code[$j] != "\n")
{
$retval .= _HTMLEntity($code[$j]);
++$j;
}
$retval .= '</span>';
$retval .= "\n";
$i = $j;
}
elseif($char == '{' && $code[$i + 1] != '$')
{
$retval .= '<span style="color: #808080">';
$j = $i;
while($j < $clen && $code[$j] != '}')
{
$retval .= _HTMLEntity($code[$j]);
++$j;
}
if($j < $clen)
{
$retval .= '}';
}
$retval .= '</span>';
$i = $j;
}
else
{
if(_IsInArray(&$operators, &$char))
{
$retval .= '<span style="color: #300000">' . _HTMLEntity($char) . '</span>';
continue;
}
elseif(_ISInArray(&$brackets, &$char))
{
$retval .= '<span style="color: #00BB00">' . _HTMLEntity($char) . '</span>';
continue;
}
$retval .= $char;
}
}
}
return $retval;
}
Może to nie jest wydajne, ale działa!
Teraz użycie: po prostu wystarczy wywołać funkcję highlight_delphi z kodem do pokolorowania jako pierwszy argument:
$source = 'unit bar;
interface
implementation
end.';
echo '<pre>' . highlight_delphi($source) . '</pre>';
Czy mi się wydaje, czy in_array() szuka liniowo? To co mam teraz daje O(1)...
no tak, ale po co w ogóle pisać array('begin'=>true, 'end'=>true) jak można array('begin', 'end') i wtedy in_array wystarczy
nie przygladalem sie kodowi, ale pierwsze co zauwazylem - po co ta funkcja _IsInArray, skoro jest standardowe in_array?
Teraz wszystko będzie działać, no ale to zupełnie inny kod jest :)
raczej o array_key_exists() powinno ci chodzić, ale to dlatego, że kod był pisany jak jeszcze tych funkcji nie znałem
a moze ktos ma gotowca? bo jakos u mnie nie chodzi nawet po porawieniu znakow.
Proponuję przerobić ten artykuł, bo znaki specialne mają błędy
"< i >< font color="000080" >// 1< br >< /font >< /i >");
"// 1
");
dlaczego mi się wydaje, że jak napisze // siema
to mi pokoloruje tylko // i wstawi 'i', a siema nie będzie pokolorowane :)
Można było zrobić ściślej :)
Aha... moga tu wystapic bledy, bo system tak parsuje kod html :[ Np. znak \ przed " trzeba wstawic.
vogel: to je funkcja php a nie delphi :P
Wow!! W SynEdicie jest to jakieś 10000 lini kodu więcej... :P