📄 geshi.php
字号:
// Short-cut through all the multiline code $rest_of_comment = htmlentities(substr($part, $i + $com_len, $close_pos - $i), ENT_COMPAT, $this->encoding); if ( ($this->lexic_permissions['COMMENTS']['MULTI'] || $test_str_match == GESHI_START_IMPORTANT) && ($this->line_numbers != GESHI_NO_LINE_NUMBERS || count($this->highlight_extra_lines) > 0) ) { // strreplace to put close span and open span around multiline newlines $test_str .= str_replace("\n", "</span>\n<span$attributes>", $rest_of_comment); } else { $test_str .= $rest_of_comment; } if ( $this->lexic_permissions['COMMENTS']['MULTI'] || $test_str_match == GESHI_START_IMPORTANT ) { $test_str .= '</span>'; } $i = $close_pos + $com_len - 1; // parse the rest $result .= $this->parse_non_string_part( $stuff_to_parse ); $stuff_to_parse = ''; break; } } // If we haven't matched a multiline comment, try single-line comments if ( !$COMMENT_MATCHED ) { foreach ( $this->language_data['COMMENT_SINGLE'] as $comment_key => $comment_mark ) { $com_len = strlen($comment_mark); $test_str = substr( $part, $i, $com_len ); if ( $this->language_data['CASE_SENSITIVE'][GESHI_COMMENTS] ) { $match = ( $comment_mark == $test_str ); } else { $match = ( strtolower($comment_mark) == strtolower($test_str) ); } if ( $match ) { $COMMENT_MATCHED = true; if ( $this->lexic_permissions['COMMENTS'][$comment_key] ) { if ( !$this->use_classes ) { $attributes = ' style="' . $this->language_data['STYLES']['COMMENTS'][$comment_key] . '"'; } else { $attributes = ' class="co' . $comment_key . '"'; } $test_str = "<span$attributes>" . htmlentities($this->change_case($test_str), ENT_COMPAT, $this->encoding); } else { $test_str = htmlentities($test_str, ENT_COMPAT, $this->encoding); } $close_pos = strpos( $part, "\n", $i ); if ( $close_pos === false ) { $close_pos = strlen($part); } $test_str .= htmlentities(substr($part, $i + $com_len, $close_pos - $i - $com_len), ENT_COMPAT, $this->encoding); if ( $this->lexic_permissions['COMMENTS'][$comment_key] ) { $test_str .= "</span>"; } $test_str .= "\n"; $i = $close_pos; // parse the rest $result .= $this->parse_non_string_part( $stuff_to_parse ); $stuff_to_parse = ''; break; } } } } // Otherwise, convert it to HTML form elseif ( $STRING_OPEN != '' ) { $char = htmlentities($char, ENT_COMPAT, $this->encoding); } // Where are we adding this char? if ( !$COMMENT_MATCHED ) { if ( ($STRING_OPEN == '') && !$CLOSE_STRING ) { $stuff_to_parse .= $char; } else { $result .= $char; $CLOSE_STRING = false; } } else { $result .= $test_str; $COMMENT_MATCHED = false; } } // Parse the last bit $result .= $this->parse_non_string_part( $stuff_to_parse ); $stuff_to_parse = ''; } else { $result .= htmlentities($part, ENT_COMPAT, $this->encoding); } // Close the <span> that surrounds the block if ( $this->strict_mode && $this->lexic_permissions['SCRIPT'] ) { $result .= '</span>'; } } // Else not a block to highlight else { $result .= htmlentities($part, ENT_COMPAT, $this->encoding); } } // Parse the last stuff (redundant?) $result .= $this->parse_non_string_part( $stuff_to_parse ); // Lop off the very first and last spaces $result = substr($result, 1, strlen($result) - 1); // Are we still in a string? if ( $STRING_OPEN ) { $result .= '</span>'; } // We're finished: stop timing $this->set_time($start_time, microtime()); return $this->finalise($result); } /** * method: indent * -------------- * Swaps out spaces and tabs for HTML indentation. Not needed if * the code is in a pre block... */ function indent ( $result ) { $result = str_replace(' ', ' ', $result); $result = str_replace(' ', ' ', $result); $result = str_replace("\n ", "\n ", $result); $result = str_replace("\t", $this->get_tab_replacement(), $result); if ( $this->line_numbers == GESHI_NO_LINE_NUMBERS ) { $result = nl2br($result); } return $result; } /** * method: change_case * ------------------- * Changes the case of a keyword for those languages where a change is asked for */ function change_case ( $instr ) { if ( $this->language_data['CASE_KEYWORDS'] == GESHI_CAPS_UPPER ) { return strtoupper($instr); } elseif ( $this->language_data['CASE_KEYWORDS'] == GESHI_CAPS_LOWER ) { return strtolower($instr); } return $instr; } /** * method: add_url_to_keyword * -------------------------- * Adds a url to a keyword where needed. * Added in 1.0.2 */ function add_url_to_keyword ( $keyword, $group, $start_or_end ) { if ( isset($this->language_data['URLS'][$group]) && $this->language_data['URLS'][$group] != '' && substr($keyword, 0, 5) != '</' ) { // There is a base group for this keyword if ( $start_or_end == 'BEGIN' ) { // HTML workaround... not good form (tm) but should work for 1.0.X $keyword = ( substr($keyword, 0, 4) == '<' ) ? substr($keyword, 4) : $keyword; $keyword = ( substr($keyword, -4) == '>' ) ? substr($keyword, 0, strlen($keyword) - 4) : $keyword; if ( $keyword != '' ) { $keyword = ( $this->language_data['CASE_SENSITIVE'][$group] ) ? $keyword : strtolower($keyword); return '<|UR1|"' . str_replace(array('{FNAME}', '.'), array(htmlentities($keyword, ENT_COMPAT, $this->encoding), '<DOT>'), $this->language_data['URLS'][$group]) . '">'; } return ''; } else { return '</a>'; } } } /** * method: parse_non_string_part * ----------------------------- * Takes a string that has no strings or comments in it, and highlights * stuff like keywords, numbers and methods. */ function parse_non_string_part ( &$stuff_to_parse ) { $stuff_to_parse = ' ' . quotemeta(htmlentities($stuff_to_parse, ENT_COMPAT, $this->encoding)); // These vars will disappear in the future $func = '$this->change_case'; $func2 = '$this->add_url_to_keyword'; // // Regular expressions // foreach ( $this->language_data['REGEXPS'] as $key => $regexp ) { if ( $this->lexic_permissions['REGEXPS'][$key] ) { if ( is_array($regexp) ) { $stuff_to_parse = preg_replace( "#" . $regexp[GESHI_SEARCH] . "#{$regexp[GESHI_MODIFIERS]}", "{$regexp[GESHI_BEFORE]}<|!REG3XP$key!>{$regexp[GESHI_REPLACE]}|>{$regexp[GESHI_AFTER]}", $stuff_to_parse); } else { $stuff_to_parse = preg_replace( "#(" . $regexp . ")#", "<|!REG3XP$key!>\\1|>", $stuff_to_parse); } } } // // Highlight numbers. This regexp sucks... anyone with a regexp that WORKS // here wins a cookie if they send it to me. At the moment there's two doing // almost exactly the same thing, except the second one prevents a number // being highlighted twice (eg <span...><span...>5</span></span>) // Put /NUM!/ in for the styles, which gets replaced at the end. // if ( $this->lexic_permissions['NUMBERS'] && preg_match('#[0-9]#', $stuff_to_parse ) ) { $stuff_to_parse = preg_replace('#([^a-zA-Z0-9\#])([0-9]+)([^a-zA-Z0-9])#', "\\1<|/NUM!/>\\2|>\\3", $stuff_to_parse); $stuff_to_parse = preg_replace('#([^a-zA-Z0-9\#>])([0-9]+)([^a-zA-Z0-9])#', "\\1<|/NUM!/>\\2|>\\3", $stuff_to_parse); } // Highlight keywords // if there is a couple of alpha symbols there *might* be a keyword if ( preg_match('#[a-zA-Z]{2,}#', $stuff_to_parse) ) { foreach ( $this->language_data['KEYWORDS'] as $k => $keywordset ) { if ( $this->lexic_permissions['KEYWORDS'][$k] ) { foreach ( $keywordset as $keyword ) { $keyword = quotemeta($keyword); // // This replacement checks the word is on it's own (except if brackets etc // are next to it), then highlights it. We don't put the color=" for the span // in just yet - otherwise languages with the keywords "color" or "or" have // a fit. // if ( false !== stristr($stuff_to_parse, $keyword ) ) { $stuff_to_parse .= ' '; // Might make a more unique string for putting the number in soon // Basically, we don't put the styles in yet because then the styles themselves will // get highlighted if the language has a CSS keyword in it (like CSS, for example ;)) $styles = "/$k/"; $keyword = quotemeta($keyword); if ( $this->language_data['CASE_SENSITIVE'][$k] ) { $stuff_to_parse = preg_replace("#([^a-zA-Z0-9\$_\|\.\#;>])($keyword)([^a-zA-Z0-9_<\|%\-&])#e", "'\\1' . $func2('\\2', '$k', 'BEGIN') . '<|$styles>' . $func('\\2') . '|>' . $func2('\\2', '$k', 'END') . '\\3'", $stuff_to_parse); } else { // Change the case of the word. $stuff_to_parse = preg_replace("#([^a-zA-Z0-9\$_\|\.\#;>])($keyword)([^a-zA-Z0-9_<\|%\-&])#ie", "'\\1' . $func2('\\2', '$k', 'BEGIN') . '<|$styles>' . $func('\\2') . '|>' . $func2('\\2', '$k', 'END') . '\\3'", $stuff_to_parse); } $stuff_to_parse = substr($stuff_to_parse, 0, strlen($stuff_to_parse) - 1); } } } } } // // Now that's all done, replace /[number]/ with the correct styles // foreach ( $this->language_data['KEYWORDS'] as $k => $kws ) { if ( !$this->use_classes ) { $attributes = ' style="' . $this->language_data['STYLES']['KEYWORDS'][$k] . '"'; } else { $attributes = ' class="kw' . $k . '"'; } $stuff_to_parse = str_replace("/$k/", $attributes, $stuff_to_parse); } // Put number styles in if ( !$this->use_classes && $this->lexic_permissions['NUMBERS'] ) { $attributes = ' style="' . $this->language_data['STYLES']['NUMBERS'][0] . '"'; } else { $attributes = ' class="nu0"'; } $stuff_to_parse = str_replace('/NUM!/', $attributes, $stuff_to_parse); // // Highlight methods and fields in objects // if ( $this->lexic_permissions['METHODS'] && $this->language_data['OOLANG'] ) { foreach ( $this->language_data['OBJECT_SPLITTERS'] as $key => $splitter ) { if ( false !== stristr($stuff_to_parse, $this->language_data['OBJECT_SPLITTERS'][$key]) ) { if ( !$this->use_classes ) { $attributes = ' style="' . $this->language_data['STYLES']['METHODS'][$key] . '"'; } else { $attributes = ' class="me' . $key . '"'; } $stuff_to_parse = preg_replace("#(" . quotemeta($this->language_data['OBJECT_SPLITTERS'][$key]) . "[\s]*)([a-zA-Z\*\(][a-zA-Z0-9_\*]*)#", "\\1<|$attributes>\\2|>", $stuff_to_parse); } } } // // Highlight brackets. Yes, I've tried adding a semi-colon to this list. // You try it, and see what happens ;) // TODO: Fix lexic permissions not converting entities if shouldn't // be highlighting regardless // if ( $this->lexic_permissions['BRACKETS'] ) { $code_entities_match = array('[', ']', '(', ')', '{', '}'); if ( !$this->use_classes ) { $code_entities_replace = array( '<| style="' . $this->language_data['STYLES']['BRACKETS'][0] . '">[|>', '<| style="' . $this->language_data['STYLES']['BRACKETS'][0] . '">]|>', '<| style="' . $this->language_data['STYLES']['BRACKETS'][0] . '">(|>', '<| style="' . $this->language_data['STYLES']['BRACKETS'][0] . '">)|>', '<| style="' . $this->language_data['STYLES']['BRACKETS'][0] . '">{|>', '<| style="' . $this->language_data['STYLES']['BRACKETS'][0] . '">}|>', ); } else { $code_entities_replace = array( '<| class="br0">[|>', '<| class="br0">]|>', '<| class="br0">(|>', '<| class="br0">)|>', '<| class="br0">{|>', '<| class="br0">}|>', ); } $stuff_to_parse = str_replace( $code_entities_match, $code_entities_replace, $stuff_to_parse ); } // // Add class/style for regexps // foreach ( $this->language_data['REGEXPS'] as $key => $regexp ) { if ( $this->lexic_permissions['REGEXPS'][$key] ) { if ( !$this->use_classes ) { $attributes = ' style="' . $this->language_data['STYLES']['REGEXPS'][$key] . '"'; } else { $attributes = ' class="re' . $key . '"'; } $stuff_to_parse = str_replace("!REG3XP$key!", "$attributes", $stuff_to_parse); } } // Replace <DOT> with . for urls $stuff_to_parse = str_replace('<DOT>', '.', $stuff_to_parse); // Replace <|UR1| with <a href= for urls also if ( isset($this->link_styles[GESHI_LINK]) ) { if ( $this->use_classes ) { $stuff_to_parse = str_replace('<|UR1|', '<a' . $this->link_target . ' href=', $stuff_to_parse); } else { $stuff_to_parse = str_replace('<|UR1|', '<a' . $this->link_target . ' style="' . $this->link_styles[GESHI_LINK] . '" href=', $stuff_to_parse); } } else { $stuff_to_parse = str_replace('<|UR1|', '<a' . $this->link_target . ' href=', $stuff_to_parse); } // // NOW we add the span thingy ;) // $stuff_to_parse = str_replace('<|', '<span', $stuff_to_parse); $stuff_to_parse = str_replace ( '|>', '</span>', $stuff_to_parse ); return substr(stripslashes($stuff_to_parse), 1); } /** * method: set_time * ---------------- * Sets the time taken to parse the code */ function set_time ( $start_time, $end_time ) { $start = explode(' ', $start_time); $end = explode(' ', $end_time); $this->time = $end[0] + $end[1] - $start[0] - $start[1]; } /** * method: get_time * ---------------- * Gets the time taken to parse the code */ function get_time () { return $this->time; } /** * method: load_language * --------------------- * Gets language information and stores it for later use */ function load_language () { $file_name = $this->language_path . $this->language . '.php'; if ( !is_readable($file_name)) { $this->error = GESHI_ERROR_NO_SUCH_LANG; return; } require($file_name);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -