Hi, some days (or even weeks?) ago Lukas asked on IRC wether there is a way to get PHP code highlighted with linenumbers. The first reaction of most people (including me) was "no" since you can't copy&paste the code but after thinking I found out that <ol> works really fine. So I've implemented it that way and added an optional bool parameter to the highlight functions. Additionally I've added two other parameters to these functions: The first one is a bool that adds jump targets (<a id="[line]"/>), second one is a prefix to this number (<a id="[prefix][line]"/>) which is needed to make sure the jump target is unique even if more than one snippet is added to the output.
This doesn't work with .phps yet since we would a new php.ini setting which I didn't want to add or numbered output would need to become default. My patch is attached and, if it doesn't come through, available on http://www.schlueters.de/zend_highlight_20050312_1.diff a sample output is at http://www.schlueters.de/highlight_pma.html johannes -- Johannes Schlüter Mayflower GmbH / ThinkPHP http://thinkphp.de http://blog.thinkphp.de
Index: Zend/zend_highlight.h =================================================================== RCS file: /repository/ZendEngine2/zend_highlight.h,v retrieving revision 1.24 diff -u -r1.24 zend_highlight.h --- Zend/zend_highlight.h 8 Jan 2004 17:31:47 -0000 1.24 +++ Zend/zend_highlight.h 12 Mar 2005 14:40:12 -0000 @@ -41,11 +41,16 @@ BEGIN_EXTERN_C() ZEND_API void zend_highlight(zend_syntax_highlighter_ini *syntax_highlighter_ini TSRMLS_DC); +ZEND_API void zend_highlight_numbered(zend_syntax_highlighter_ini *syntax_highlighter_ini, zend_bool mark_lines, char *line_prefix TSRMLS_DC); ZEND_API void zend_strip(TSRMLS_D); ZEND_API int highlight_file(char *filename, zend_syntax_highlighter_ini *syntax_highlighter_ini TSRMLS_DC); +ZEND_API int highlight_file_ex(char *filename, zend_syntax_highlighter_ini *syntax_highlighter_ini, zend_bool numbered, zend_bool mark_lines, char *line_prefix TSRMLS_DC); ZEND_API int highlight_string(zval *str, zend_syntax_highlighter_ini *syntax_highlighter_ini, char *str_name TSRMLS_DC); +ZEND_API int highlight_string_ex(zval *str, zend_syntax_highlighter_ini *syntax_highlighter_ini, char *str_name, zend_bool numbered, zend_bool mark_lines, char *line_prefix TSRMLS_DC); ZEND_API void zend_html_putc(char c); +ZEND_API void zend_html_putc_ex(char c, char *last_color, int *line, char *line_prefix); ZEND_API void zend_html_puts(const char *s, uint len TSRMLS_DC); +ZEND_API void zend_html_puts_ex(const char *s, uint len, char *last_color, int *line, char *line_prefix TSRMLS_DC); END_EXTERN_C() extern zend_syntax_highlighter_ini syntax_highlighter_ini; Index: Zend/zend_highlight.c =================================================================== RCS file: /repository/ZendEngine2/zend_highlight.c,v retrieving revision 1.47 diff -u -r1.47 zend_highlight.c --- Zend/zend_highlight.c 2 Jan 2005 23:53:43 -0000 1.47 +++ Zend/zend_highlight.c 12 Mar 2005 14:40:12 -0000 @@ -53,9 +53,35 @@ } } +ZEND_API void zend_html_putc_ex(char c, char *last_color, int *line, char *line_prefix) +{ + if (c == '\n') { + /* the is needed to work around https://bugzilla.mozilla.org/show_bug.cgi?id=194831 */ + zend_printf(" </span></code></li>\n<li>"); + if (last_color != NULL) { + if (line && *line) { + if (line_prefix) { + zend_printf("<a id=\"%s%d\"/>", line_prefix, ++*line); + } else { + zend_printf("<a id=\"%d\"/>", ++*line); + } + } + zend_printf("<code><span style=\"color: %s\">", last_color); + } else { + zend_printf("<code><span>"); + } + } else { + zend_html_putc(c); + } +} ZEND_API void zend_html_puts(const char *s, uint len TSRMLS_DC) { + zend_html_puts_ex(s, len, NULL, NULL, NULL TSRMLS_CC); +} + +ZEND_API void zend_html_puts_ex(const char *s, uint len, char *last_color, int *line, char *line_prefix TSRMLS_DC) +{ const char *ptr=s, *end=s+len; #ifdef ZEND_MULTIBYTE @@ -83,7 +109,11 @@ ptr++; } } else { - zend_html_putc(*ptr++); + if (last_color == NULL) { + zend_html_putc(*ptr++); + } else { + zend_html_putc_ex(*ptr++, last_color, line, line_prefix); + } } } @@ -196,6 +226,108 @@ } +ZEND_API void zend_highlight_numbered(zend_syntax_highlighter_ini *syntax_highlighter_ini, zend_bool mark_lines, char *line_prefix TSRMLS_DC) +{ + zval token; + int token_type; + char *last_color = syntax_highlighter_ini->highlight_html; + char *next_color; + int in_string=0, post_heredoc = 0; + int line = 0; + + if (mark_lines) { + line = 1; + if (line_prefix) { + zend_printf("<ol><li><a id=\"%s%d\"/><code><span style=\"color: %s\">", line_prefix, line, last_color); + } else { + zend_printf("<ol><li><a id=\"%d\"/><code><span style=\"color: %s\">", line, last_color); + } + } else { + zend_printf("<ol><li><code><span style=\"color: %s\">", last_color); + } + /* highlight stuff coming back from zendlex() */ + token.type = 0; + while ((token_type=lex_scan(&token TSRMLS_CC))) { + switch (token_type) { + case T_INLINE_HTML: + next_color = syntax_highlighter_ini->highlight_html; + break; + case T_COMMENT: + case T_DOC_COMMENT: + next_color = syntax_highlighter_ini->highlight_comment; + break; + case T_OPEN_TAG: + case T_OPEN_TAG_WITH_ECHO: + next_color = syntax_highlighter_ini->highlight_default; + break; + case T_CLOSE_TAG: + next_color = syntax_highlighter_ini->highlight_default; + break; + case T_CONSTANT_ENCAPSED_STRING: + next_color = syntax_highlighter_ini->highlight_string; + break; + case '"': + next_color = syntax_highlighter_ini->highlight_string; + in_string = !in_string; + break; + case T_WHITESPACE: + zend_html_puts_ex(LANG_SCNG(yy_text), LANG_SCNG(yy_leng), last_color, &line, line_prefix TSRMLS_CC); /* no color needed */ + token.type = 0; + continue; + break; + default: + if (in_string) { + next_color = syntax_highlighter_ini->highlight_string; + } else if (token.type == 0) { + next_color = syntax_highlighter_ini->highlight_keyword; + } else { + next_color = syntax_highlighter_ini->highlight_default; + } + break; + } + + if (last_color != next_color) { + last_color = next_color; + zend_printf("</span><span style=\"color: %s\">", last_color); + + } + switch (token_type) { + case T_END_HEREDOC: + zend_html_puts_ex(token.value.str.val, token.value.str.len, last_color, &line, line_prefix TSRMLS_CC); + post_heredoc = 1; + break; + default: + zend_html_puts_ex(LANG_SCNG(yy_text), LANG_SCNG(yy_leng), last_color, &line, line_prefix TSRMLS_CC); + if (post_heredoc) { + zend_html_putc_ex('\n', last_color, &line, line_prefix); + post_heredoc = 0; + } + break; + } + + if (token.type == IS_STRING) { + switch (token_type) { + case T_OPEN_TAG: + case T_OPEN_TAG_WITH_ECHO: + case T_CLOSE_TAG: + case T_WHITESPACE: + case T_COMMENT: + case T_DOC_COMMENT: + break; + default: + efree(token.value.str.val); + break; + } + } else if (token_type == T_END_HEREDOC) { + efree(token.value.str.val); + } + token.type = 0; + } + zend_printf("</span>"); + zend_printf("</code></li></ol>"); +} + + ZEND_API void zend_strip(TSRMLS_D) { Index: Zend/zend_language_scanner.l =================================================================== RCS file: /repository/ZendEngine2/zend_language_scanner.l,v retrieving revision 1.124 diff -u -r1.124 zend_language_scanner.l --- Zend/zend_language_scanner.l 7 Mar 2005 16:48:49 -0000 1.124 +++ Zend/zend_language_scanner.l 12 Mar 2005 14:40:13 -0000 @@ -557,11 +557,11 @@ BEGIN_EXTERN_C() -int highlight_file(char *filename, zend_syntax_highlighter_ini *syntax_highlighter_ini TSRMLS_DC) +int highlight_file_ex(char *filename, zend_syntax_highlighter_ini *syntax_highlighter_ini, zend_bool numbered, zend_bool mark_lines, char *line_prefix TSRMLS_DC) { zend_lex_state original_lex_state; zend_file_handle file_handle; - + file_handle.type = ZEND_HANDLE_FILENAME; file_handle.filename = filename; file_handle.free_filename = 0; @@ -571,7 +571,11 @@ zend_message_dispatcher(ZMSG_FAILED_HIGHLIGHT_FOPEN, filename); return FAILURE; } - zend_highlight(syntax_highlighter_ini TSRMLS_CC); + if (numbered) { + zend_highlight_numbered(syntax_highlighter_ini, mark_lines, line_prefix TSRMLS_CC); + } else { + zend_highlight(syntax_highlighter_ini TSRMLS_CC); + } #ifdef ZEND_MULTIBYTE if (SCNG(script_org)) { efree(SCNG(script_org)); @@ -587,7 +591,12 @@ return SUCCESS; } -int highlight_string(zval *str, zend_syntax_highlighter_ini *syntax_highlighter_ini, char *str_name TSRMLS_DC) +int highlight_file(char *filename, zend_syntax_highlighter_ini *syntax_highlighter_ini TSRMLS_DC) +{ + return highlight_file_ex(filename, syntax_highlighter_ini, 0, 0, NULL TSRMLS_CC); +} + +int highlight_string_ex(zval *str, zend_syntax_highlighter_ini *syntax_highlighter_ini, char *str_name, zend_bool numbered, zend_bool mark_lines, char *line_prefix TSRMLS_DC) { zend_lex_state original_lex_state; zval tmp = *str; @@ -598,7 +607,11 @@ if (zend_prepare_string_for_scanning(str, str_name TSRMLS_CC)==FAILURE) { return FAILURE; } - zend_highlight(syntax_highlighter_ini TSRMLS_CC); + if (numbered) { + zend_highlight_numbered(syntax_highlighter_ini, mark_lines, line_prefix TSRMLS_CC); + } else { + zend_highlight(syntax_highlighter_ini TSRMLS_CC); + } #ifdef ZEND_MULTIBYTE if (SCNG(script_org)) { efree(SCNG(script_org)); @@ -613,6 +626,11 @@ zval_dtor(str); return SUCCESS; } + +int highlight_string(zval *str, zend_syntax_highlighter_ini *syntax_highlighter_ini, char *str_name TSRMLS_DC) +{ + return highlight_string_ex(str, syntax_highlighter_ini, str_name, 0, 0, NULL TSRMLS_CC); +} END_EXTERN_C() #ifdef ZEND_MULTIBYTE Index: ext/standard/basic_functions.c =================================================================== RCS file: /repository/php-src/ext/standard/basic_functions.c,v retrieving revision 1.705 diff -u -r1.705 basic_functions.c --- ext/standard/basic_functions.c 7 Mar 2005 19:37:26 -0000 1.705 +++ ext/standard/basic_functions.c 12 Mar 2005 14:40:14 -0000 @@ -2353,15 +2353,19 @@ syntax_highlighter_ini->highlight_string = INI_STR("highlight.string"); } -/* {{{ proto bool highlight_file(string file_name [, bool return] ) +/* {{{ proto bool highlight_file(string file_name [, bool return [, bool numbered [, bool mark_lines [, string mark_prefix]]]] ) Syntax highlight a source file */ PHP_FUNCTION(highlight_file) { zval *filename; zend_syntax_highlighter_ini syntax_highlighter_ini; zend_bool i = 0; + zend_bool numbered = 0; + zend_bool mark_lines = 0; + char *line_prefix = NULL; + int line_prefix_len = 0; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|b", &filename, &i) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|bbbs", &filename, &i, &numbered, &mark_lines, &line_prefix, &line_prefix_len) == FAILURE) { RETURN_FALSE; } convert_to_string(filename); @@ -2380,7 +2384,7 @@ php_get_highlight_struct(&syntax_highlighter_ini); - if (highlight_file(Z_STRVAL_P(filename), &syntax_highlighter_ini TSRMLS_CC) == FAILURE) { + if (highlight_file_ex(Z_STRVAL_P(filename), &syntax_highlighter_ini, numbered, mark_lines, line_prefix TSRMLS_CC) == FAILURE) { RETURN_FALSE; } @@ -2472,7 +2476,7 @@ } /* }}} */ -/* {{{ proto bool highlight_string(string string [, bool return] ) +/* {{{ proto bool highlight_string(string string [, bool return [, bool mark_lines [, string mark_prefix]]] ) Syntax highlight a string or optionally return it */ PHP_FUNCTION(highlight_string) { @@ -2480,9 +2484,13 @@ zend_syntax_highlighter_ini syntax_highlighter_ini; char *hicompiled_string_description; zend_bool i = 0; + zend_bool numbered = 0; + zend_bool mark_lines = 0; + char *line_prefix = NULL; + int line_prefix_len = 0; int old_error_reporting = EG(error_reporting); - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|b", &expr, &i) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|bbbs", &expr, &i, &numbered, &mark_lines, &line_prefix, &line_prefix_len) == FAILURE) { RETURN_FALSE; } convert_to_string(expr); @@ -2497,7 +2505,7 @@ hicompiled_string_description = zend_make_compiled_string_description("highlighted code" TSRMLS_CC); - if (highlight_string(expr, &syntax_highlighter_ini, hicompiled_string_description TSRMLS_CC) == FAILURE) { + if (highlight_string_ex(expr, &syntax_highlighter_ini, hicompiled_string_description, numbered, mark_lines, line_prefix TSRMLS_CC) == FAILURE) { efree(hicompiled_string_description); RETURN_FALSE; }
-- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php