fork
This commit is contained in:
commit
6f2b105ca0
11
.gitignore
vendored
Normal file
11
.gitignore
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
.svn
|
||||
# .project
|
||||
Thumbs.db
|
||||
.DS_Store*
|
||||
# .settings
|
||||
# .buildpath
|
||||
*.pyc
|
||||
.idea/
|
||||
/log.txt
|
||||
*.sublime-workspace
|
||||
.c9
|
9
.gitmodules
vendored
Normal file
9
.gitmodules
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
[submodule "js/jquery-colorpicker"]
|
||||
path = js/jquery-colorpicker
|
||||
url=git://github.com/aramk/colorpicker.git
|
||||
[submodule "langs/ada"]
|
||||
path = langs/ada
|
||||
url = https://github.com/antiphasis/crayon-lang-ada.git
|
||||
[submodule "langs/vbnet"]
|
||||
path = langs/vbnet
|
||||
url=https://github.com/NuGardt/crayon-lang-vbnet.git
|
13
crayon-syntax-highlighter.sublime-project
Normal file
13
crayon-syntax-highlighter.sublime-project
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"folders":
|
||||
[
|
||||
{
|
||||
"follow_symlinks": true,
|
||||
"path": ".",
|
||||
"folder_exclude_patterns": [
|
||||
"min",
|
||||
"trans"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
36
crayon_fonts.class.php
Normal file
36
crayon_fonts.class.php
Normal file
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
require_once ('global.php');
|
||||
require_once (CRAYON_RESOURCE_PHP);
|
||||
|
||||
/* Manages fonts once they are loaded. */
|
||||
class CrayonFonts extends CrayonUserResourceCollection {
|
||||
// Properties and Constants ===============================================
|
||||
|
||||
const DEFAULT_FONT = 'monaco';
|
||||
const DEFAULT_FONT_NAME = 'Monaco';
|
||||
|
||||
// Methods ================================================================
|
||||
|
||||
function __construct() {
|
||||
$this->set_default(self::DEFAULT_FONT, self::DEFAULT_FONT_NAME);
|
||||
$this->directory(CRAYON_FONT_PATH);
|
||||
$this->relative_directory(CRAYON_FONT_DIR);
|
||||
$this->extension('css');
|
||||
|
||||
CrayonLog::debug("Setting font directories");
|
||||
$upload = CrayonGlobalSettings::upload_path();
|
||||
if ($upload) {
|
||||
$this->user_directory($upload . CRAYON_FONT_DIR);
|
||||
if (!is_dir($this->user_directory())) {
|
||||
CrayonGlobalSettings::mkdir($this->user_directory());
|
||||
CrayonLog::debug($this->user_directory(), "FONT USER DIR");
|
||||
}
|
||||
} else {
|
||||
CrayonLog::syslog("Upload directory is empty: " . $upload . " cannot load fonts.");
|
||||
}
|
||||
CrayonLog::debug($this->directory());
|
||||
CrayonLog::debug($this->user_directory());
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
633
crayon_formatter.class.php
Normal file
633
crayon_formatter.class.php
Normal file
@ -0,0 +1,633 @@
|
||||
<?php
|
||||
require_once('global.php');
|
||||
require_once(CRAYON_HIGHLIGHTER_PHP);
|
||||
require_once(CRAYON_SETTINGS_PHP);
|
||||
require_once(CRAYON_PARSER_PHP);
|
||||
require_once(CRAYON_THEMES_PHP);
|
||||
|
||||
/* Manages formatting the html with html and css. */
|
||||
|
||||
class CrayonFormatter {
|
||||
// Properties and Constants ===============================================
|
||||
/* Used to temporarily store the array of CrayonElements passed to format_code(), so that
|
||||
format_matches() can access them and identify which elements were captured and format
|
||||
accordingly. This must be static for preg_replace_callback() to access it.*/
|
||||
private static $elements = array();
|
||||
|
||||
// Delimiters
|
||||
// Current crayon undergoing delimiter replace
|
||||
private static $curr;
|
||||
private static $delimiters;
|
||||
private static $delim_regex;
|
||||
private static $delim_pieces;
|
||||
|
||||
// Methods ================================================================
|
||||
private function __construct() {
|
||||
}
|
||||
|
||||
/* Formats the code using the parsed language elements. */
|
||||
public static function format_code($code, $language, $hl = NULL) {
|
||||
// Ensure the language is defined
|
||||
if ($language != NULL && $hl->is_highlighted()) {
|
||||
$code = self::clean_code($code, FALSE, FALSE, FALSE, TRUE);
|
||||
/* Perform the replace on the code using the regex, pass the captured matches for
|
||||
formatting before they are replaced */
|
||||
try {
|
||||
CrayonParser::parse($language->id());
|
||||
// Match language regex
|
||||
$elements = $language->elements();
|
||||
$regex = $language->regex();
|
||||
if (!empty($regex) && !empty($elements)) {
|
||||
// Get array of CrayonElements
|
||||
self::$elements = array_values($elements);
|
||||
$code = preg_replace_callback($regex, 'CrayonFormatter::format_match', $code);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$error = 'An error occured when formatting: ' . $e->message();
|
||||
$hl ? $hl->log($error) : CrayonLog::syslog($error);
|
||||
}
|
||||
return $code;
|
||||
} else {
|
||||
return self::clean_code($code, TRUE, TRUE, TRUE, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
/* Performs a replace to format each match based on the captured element. */
|
||||
private static function format_match($matches) {
|
||||
/* First index in $matches is full match, subsequent indices are groups.
|
||||
* Minimum number of elements in array is 2, so minimum captured group is 0. */
|
||||
$captured_group_number = count($matches) - 2;
|
||||
$code = $matches[0];
|
||||
if (array_key_exists($captured_group_number, self::$elements)) {
|
||||
$captured_element = self::$elements[$captured_group_number];
|
||||
// Avoid capturing and formatting internal Crayon elements
|
||||
if ($captured_element->name() == CrayonParser::CRAYON_ELEMENT) {
|
||||
return $code; // Return as is
|
||||
} else {
|
||||
// Separate lines and add css class, keep extended class last to allow overriding
|
||||
$fallback_css = CrayonLangs::known_elements($captured_element->fallback());
|
||||
$element_css = $captured_element->css();
|
||||
$css = !empty($fallback_css) ? $fallback_css . ' ' . $element_css : $element_css;
|
||||
return self::split_lines($code, $css);
|
||||
}
|
||||
} else {
|
||||
// All else fails, return the match
|
||||
return $matches[0];
|
||||
}
|
||||
}
|
||||
|
||||
/* Prints the formatted code, option to override the line numbers with a custom string */
|
||||
public static function print_code($hl, $code, $line_numbers = TRUE, $print = TRUE) {
|
||||
global $CRAYON_VERSION;
|
||||
|
||||
// We can print either block or inline, inline is treated differently, factor out common stuff here
|
||||
$output = '';
|
||||
// Used for style tag
|
||||
$main_style = $code_style = $toolbar_style = $info_style = $font_style = $line_style = $pre_style = '';
|
||||
// Unique ID for this instance of Crayon
|
||||
$uid = 'crayon-' . $hl->id();
|
||||
// Print theme id
|
||||
// We make the assumption that the id is correct (checked in crayon_wp)
|
||||
$theme_id = $hl->setting_val(CrayonSettings::THEME);
|
||||
$theme_id_dashed = CrayonUtil::space_to_hyphen($theme_id);
|
||||
if (!$hl->setting_val(CrayonSettings::ENQUEUE_THEMES)) {
|
||||
$output .= CrayonResources::themes()->get_css($theme_id);
|
||||
}
|
||||
|
||||
// Print font id
|
||||
// We make the assumption that the id is correct (checked in crayon_wp)
|
||||
$font_id = $hl->setting_val(CrayonSettings::FONT);
|
||||
$font_id_dashed = CrayonUtil::space_to_hyphen($font_id);
|
||||
if (!$hl->setting_val(CrayonSettings::ENQUEUE_FONTS)) {
|
||||
$output .= CrayonResources::fonts()->get_css($font_id);
|
||||
}
|
||||
|
||||
// Inline margin
|
||||
if ($hl->is_inline()) {
|
||||
$inline_margin = $hl->setting_val(CrayonSettings::INLINE_MARGIN) . 'px !important;';
|
||||
}
|
||||
|
||||
// Determine font size
|
||||
// TODO improve logic
|
||||
if ($hl->setting_val(CrayonSettings::FONT_SIZE_ENABLE)) {
|
||||
$_font_size = $hl->setting_val(CrayonSettings::FONT_SIZE);
|
||||
$_font_size = $_font_size . 'px !important;';
|
||||
$_line_height = $hl->setting_val(CrayonSettings::LINE_HEIGHT);
|
||||
// Don't allow line height to be less than font size
|
||||
$line_height = ($_line_height > $_font_size ? $_line_height : $_font_size) . 'px !important;';
|
||||
$toolbar_height = $_font_size * 1.5 . 'px !important;';
|
||||
$info_height = $_font_size * 1.4 . 'px !important;';
|
||||
|
||||
$font_style .= "font-size: $_font_size line-height: $line_height";
|
||||
$toolbar_style .= "font-size: $_font_size";
|
||||
$line_style .= "height: $line_height";
|
||||
|
||||
if ($hl->is_inline()) {
|
||||
$font_style .= "font-size: $_font_size";
|
||||
} else {
|
||||
$toolbar_style .= "height: $toolbar_height line-height: $toolbar_height";
|
||||
$info_style .= "min-height: $info_height line-height: $info_height";
|
||||
}
|
||||
} else if (!$hl->is_inline()) {
|
||||
if (($_font_size = CrayonGlobalSettings::get(CrayonSettings::FONT_SIZE)) !== FALSE) {
|
||||
$_font_size = $_font_size->def() . 'px !important;';
|
||||
$line_height = ($_font_size * 1.4) . 'px !important;';
|
||||
}
|
||||
}
|
||||
|
||||
$tab = $hl->setting_val(CrayonSettings::TAB_SIZE);
|
||||
$pre_style = "-moz-tab-size:$tab; -o-tab-size:$tab; -webkit-tab-size:$tab; tab-size:$tab;";
|
||||
|
||||
// This will return from function with inline print
|
||||
if ($hl->is_inline()) {
|
||||
$wrap = !$hl->setting_val(CrayonSettings::INLINE_WRAP) ? 'crayon-syntax-inline-nowrap' : '';
|
||||
$output .= '
|
||||
<span id="' . $uid . '" class="crayon-syntax crayon-syntax-inline ' . $wrap . ' crayon-theme-' . $theme_id_dashed . ' crayon-theme-' . $theme_id_dashed . '-inline crayon-font-' . $font_id_dashed . '" style="' . $font_style . '">' .
|
||||
'<span class="crayon-pre crayon-code" style="' . $font_style . ' ' . $pre_style . '">' . $code . '</span>' .
|
||||
'</span>';
|
||||
return $output;
|
||||
}
|
||||
|
||||
// Below code only for block (default) printing
|
||||
|
||||
// Generate the code lines and separate each line as a div
|
||||
$print_code = '';
|
||||
$print_nums = '';
|
||||
$hl->line_count(preg_match_all("#(?:^|(?<=\r\n|\n))[^\r\n]*#", $code, $code_lines));
|
||||
|
||||
// The line number to start from
|
||||
$start_line = $hl->setting_val(CrayonSettings::START_LINE);
|
||||
$marking = $hl->setting_val(CrayonSettings::MARKING);
|
||||
$striped = $hl->setting_val(CrayonSettings::STRIPED);
|
||||
$range = $hl->setting_val(CrayonSettings::RANGES) ? $hl->range() : FALSE;
|
||||
for ($i = 1; $i <= $hl->line_count(); $i++) {
|
||||
// Check if the current line is in the range of code to display
|
||||
if ($range) {
|
||||
if ($i < $range[0]) {
|
||||
continue;
|
||||
} else if ($i > $range[1]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
$code_line = $code_lines[0][$i - 1];
|
||||
|
||||
// If line is blank, add a space so the div has the correct height
|
||||
if ($code_line == '') {
|
||||
$code_line = ' ';
|
||||
}
|
||||
|
||||
// Check if the current line has been selected
|
||||
$marked_lines = $hl->marked();
|
||||
// Check if lines need to be marked as important
|
||||
if ($marking && in_array($i, $marked_lines)) {
|
||||
$marked_num = ' crayon-marked-num';
|
||||
$marked_line = ' crayon-marked-line';
|
||||
// If multiple lines are marked, only show borders for top and bottom lines
|
||||
if (!in_array($i - 1, $marked_lines)) {
|
||||
$marked_num .= ' crayon-top';
|
||||
$marked_line .= ' crayon-top';
|
||||
}
|
||||
// Single lines are both the top and bottom of the multiple marked lines
|
||||
if (!in_array($i + 1, $marked_lines)) {
|
||||
$marked_num .= ' crayon-bottom';
|
||||
$marked_line .= ' crayon-bottom';
|
||||
}
|
||||
} else {
|
||||
$marked_num = $marked_line = '';
|
||||
}
|
||||
// Stripe odd lines
|
||||
if ($striped && $i % 2 == 0) {
|
||||
$striped_num = ' crayon-striped-num';
|
||||
$striped_line = ' crayon-striped-line';
|
||||
} else {
|
||||
$striped_num = $striped_line = '';
|
||||
}
|
||||
// Generate the lines
|
||||
$line_num = $start_line + $i - 1;
|
||||
$line_id = $uid . '-' . $line_num;
|
||||
$print_code .= '<div class="crayon-line' . $marked_line . $striped_line . '" id="' . $line_id . '">' . $code_line . '</div>';
|
||||
if (!is_string($line_numbers)) {
|
||||
$print_nums .= '<div class="crayon-num' . $marked_num . $striped_num . '" data-line="' . $line_id . '">' . $line_num . '</div>';
|
||||
}
|
||||
}
|
||||
// If $line_numbers is a string, display it
|
||||
if (is_string($line_numbers) && !empty($line_numbers)) {
|
||||
$print_nums .= '<div class="crayon-num">' . $line_numbers . '</div>';
|
||||
} else if (empty($line_numbers)) {
|
||||
$print_nums = FALSE;
|
||||
}
|
||||
// Determine whether to print title, encode characters
|
||||
$title = $hl->title();
|
||||
// Decode if needed
|
||||
if ($hl->setting_val(CrayonSettings::DECODE_ATTRIBUTES)) {
|
||||
$title = CrayonUtil::html_entity_decode($title);
|
||||
}
|
||||
$print_title = '<span class="crayon-title">' . $title . '</span>';
|
||||
// Determine whether to print language
|
||||
$print_lang = '';
|
||||
// XXX Use for printing the regex
|
||||
if ($hl->language()) {
|
||||
$lang = $hl->language()->name();
|
||||
switch ($hl->setting_index(CrayonSettings::SHOW_LANG)) {
|
||||
case 0 :
|
||||
if ($hl->language()->id() == CrayonLangs::DEFAULT_LANG) {
|
||||
break;
|
||||
}
|
||||
// Falls through
|
||||
case 1 :
|
||||
$print_lang = '<span class="crayon-language">' . $lang . '</span>';
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Disable functionality for errors
|
||||
$error = $hl->error();
|
||||
// Combined settings for code
|
||||
$code_settings = '';
|
||||
// Disable mouseover for touchscreen devices and mobiles, if we are told to
|
||||
$touch = FALSE; // Whether we have detected a touchscreen device
|
||||
if ($hl->setting_val(CrayonSettings::TOUCHSCREEN) && CrayonUtil::is_touch()) {
|
||||
$touch = TRUE;
|
||||
$code_settings .= ' touchscreen';
|
||||
}
|
||||
|
||||
// Disabling Popup
|
||||
if (!$hl->setting_val(CrayonSettings::POPUP)) {
|
||||
$code_settings .= ' no-popup';
|
||||
}
|
||||
|
||||
// Minimize
|
||||
if (!$hl->setting_val(CrayonSettings::MINIMIZE)) {
|
||||
$code_settings .= ' minimize';
|
||||
}
|
||||
|
||||
// Draw the plain code and toolbar
|
||||
$toolbar_settings = $print_plain_button = $print_copy_button = '';
|
||||
$toolbar_index = $hl->setting_index(CrayonSettings::TOOLBAR);
|
||||
if (empty($error) && ($toolbar_index != 2 || $hl->setting_val(CrayonSettings::MINIMIZE))) {
|
||||
// Enable mouseover setting for toolbar
|
||||
if ($toolbar_index == 0 && !$touch) {
|
||||
// No touchscreen detected
|
||||
$toolbar_settings .= ' mouseover';
|
||||
if ($hl->setting_val(CrayonSettings::TOOLBAR_OVERLAY)) {
|
||||
$toolbar_settings .= ' overlay';
|
||||
}
|
||||
if ($hl->setting_val(CrayonSettings::TOOLBAR_HIDE)) {
|
||||
$toolbar_settings .= ' hide';
|
||||
}
|
||||
if ($hl->setting_val(CrayonSettings::TOOLBAR_DELAY)) {
|
||||
$toolbar_settings .= ' delay';
|
||||
}
|
||||
} else if ($toolbar_index == 1) {
|
||||
// Always display the toolbar
|
||||
$toolbar_settings .= ' show';
|
||||
} else if ($toolbar_index == 2) {
|
||||
$toolbar_settings .= ' never-show';
|
||||
}
|
||||
|
||||
$buttons = array();
|
||||
|
||||
if ($hl->setting_val(CrayonSettings::NUMS_TOGGLE)) {
|
||||
$buttons['nums'] = crayon__('Toggle Line Numbers');
|
||||
}
|
||||
|
||||
if ($hl->setting_val(CrayonSettings::PLAIN) && $hl->setting_val(CrayonSettings::PLAIN_TOGGLE)) {
|
||||
$buttons['plain'] = crayon__('Toggle Plain Code');
|
||||
}
|
||||
|
||||
if ($hl->setting_val(CrayonSettings::WRAP_TOGGLE)) {
|
||||
$buttons['wrap'] = crayon__('Toggle Line Wrap');
|
||||
}
|
||||
|
||||
if ($hl->setting_val(CrayonSettings::EXPAND_TOGGLE)) {
|
||||
$buttons['expand'] = crayon__('Expand Code');
|
||||
}
|
||||
|
||||
if (!$touch && $hl->setting_val(CrayonSettings::PLAIN) && $hl->setting_val(CrayonSettings::COPY)) {
|
||||
$buttons['copy'] = crayon__('Copy');
|
||||
}
|
||||
|
||||
if ($hl->setting_val(CrayonSettings::POPUP)) {
|
||||
$buttons['popup'] = crayon__('Open Code In New Window');
|
||||
}
|
||||
|
||||
$buttons_str = '';
|
||||
foreach ($buttons as $button => $value) {
|
||||
$buttons_str .= '<div class="crayon-button crayon-' . $button . '-button"';
|
||||
if (!is_array($value)) {
|
||||
$value = array('title' => $value);
|
||||
}
|
||||
foreach ($value as $k => $v) {
|
||||
$buttons_str .= ' ' . $k . '="' . $v . '"';
|
||||
}
|
||||
$buttons_str .= '><div class="crayon-button-icon"></div></div>';
|
||||
}
|
||||
|
||||
/* The table is rendered invisible by CSS and enabled with JS when asked to. If JS
|
||||
is not enabled or fails, the toolbar won't work so there is no point to display it. */
|
||||
$print_plus = $hl->is_mixed() && $hl->setting_val(CrayonSettings::SHOW_MIXED) ? '<span class="crayon-mixed-highlight" title="' . crayon__('Contains Mixed Languages') . '"></span>' : '';
|
||||
$buttons = $print_plus . $buttons_str . $print_lang;
|
||||
$toolbar = '
|
||||
<div class="crayon-toolbar" data-settings="' . $toolbar_settings . '" style="' . $toolbar_style . '">' . $print_title . '
|
||||
<div class="crayon-tools" style="' . $toolbar_style . '">' . $buttons . '</div></div>
|
||||
<div class="crayon-info" style="' . $info_style . '"></div>';
|
||||
|
||||
} else {
|
||||
$toolbar = $buttons = $plain_settings = '';
|
||||
}
|
||||
|
||||
if (empty($error) && $hl->setting_val(CrayonSettings::PLAIN)) {
|
||||
// Different events to display plain code
|
||||
switch ($hl->setting_index(CrayonSettings::SHOW_PLAIN)) {
|
||||
case 0 :
|
||||
$plain_settings = 'dblclick';
|
||||
break;
|
||||
case 1 :
|
||||
$plain_settings = 'click';
|
||||
break;
|
||||
case 2 :
|
||||
$plain_settings = 'mouseover';
|
||||
break;
|
||||
default :
|
||||
$plain_settings = '';
|
||||
}
|
||||
if ($hl->setting_val(CrayonSettings::SHOW_PLAIN_DEFAULT)) {
|
||||
$plain_settings .= ' show-plain-default';
|
||||
}
|
||||
$readonly = $touch ? '' : 'readonly';
|
||||
$print_plain = $print_plain_button = '';
|
||||
$textwrap = !$hl->setting_val(CrayonSettings::WRAP) ? 'wrap="soft"' : '';
|
||||
$print_plain = '<textarea ' . $textwrap . ' class="crayon-plain print-no" data-settings="' . $plain_settings . '" ' . $readonly . ' style="' . $pre_style . ' ' . $font_style . '">' . "\n" . self::clean_code($hl->code()) . '</textarea>';
|
||||
} else {
|
||||
$print_plain = $plain_settings = $plain_settings = '';
|
||||
}
|
||||
|
||||
// Line numbers visibility
|
||||
$num_vis = $num_settings = '';
|
||||
if ($line_numbers === FALSE) {
|
||||
$num_vis = 'crayon-invisible';
|
||||
} else {
|
||||
$num_settings = ($hl->setting_val(CrayonSettings::NUMS) ? 'show' : 'hide');
|
||||
}
|
||||
|
||||
// Determine scrollbar visibility
|
||||
$code_settings .= $hl->setting_val(CrayonSettings::SCROLL) && !$touch ? ' scroll-always' : ' scroll-mouseover';
|
||||
|
||||
// Disable animations
|
||||
if ($hl->setting_val(CrayonSettings::DISABLE_ANIM)) {
|
||||
$code_settings .= ' disable-anim';
|
||||
}
|
||||
|
||||
// Wrap
|
||||
if ($hl->setting_val(CrayonSettings::WRAP)) {
|
||||
$code_settings .= ' wrap';
|
||||
}
|
||||
|
||||
// Expand
|
||||
if ($hl->setting_val(CrayonSettings::EXPAND)) {
|
||||
$code_settings .= ' expand';
|
||||
}
|
||||
|
||||
// Determine dimensions
|
||||
if ($hl->setting_val(CrayonSettings::HEIGHT_SET)) {
|
||||
$height_style = self::dimension_style($hl, CrayonSettings::HEIGHT);
|
||||
// XXX Only set height for main, not code (if toolbar always visible, code will cover main)
|
||||
if ($hl->setting_index(CrayonSettings::HEIGHT_UNIT) == 0) {
|
||||
$main_style .= $height_style;
|
||||
}
|
||||
}
|
||||
if ($hl->setting_val(CrayonSettings::WIDTH_SET)) {
|
||||
$width_style = self::dimension_style($hl, CrayonSettings::WIDTH);
|
||||
$code_style .= $width_style;
|
||||
if ($hl->setting_index(CrayonSettings::WIDTH_UNIT) == 0) {
|
||||
$main_style .= $width_style;
|
||||
}
|
||||
}
|
||||
|
||||
// Determine margins
|
||||
if ($hl->setting_val(CrayonSettings::TOP_SET)) {
|
||||
$code_style .= ' margin-top: ' . $hl->setting_val(CrayonSettings::TOP_MARGIN) . 'px;';
|
||||
}
|
||||
if ($hl->setting_val(CrayonSettings::BOTTOM_SET)) {
|
||||
$code_style .= ' margin-bottom: ' . $hl->setting_val(CrayonSettings::BOTTOM_MARGIN) . 'px;';
|
||||
}
|
||||
if ($hl->setting_val(CrayonSettings::LEFT_SET)) {
|
||||
$code_style .= ' margin-left: ' . $hl->setting_val(CrayonSettings::LEFT_MARGIN) . 'px;';
|
||||
}
|
||||
if ($hl->setting_val(CrayonSettings::RIGHT_SET)) {
|
||||
$code_style .= ' margin-right: ' . $hl->setting_val(CrayonSettings::RIGHT_MARGIN) . 'px;';
|
||||
}
|
||||
|
||||
// Determine horizontal alignment
|
||||
$align_style = '';
|
||||
switch ($hl->setting_index(CrayonSettings::H_ALIGN)) {
|
||||
case 1 :
|
||||
$align_style = ' float: left;';
|
||||
break;
|
||||
case 2 :
|
||||
$align_style = ' float: none; margin-left: auto; margin-right: auto;';
|
||||
break;
|
||||
case 3 :
|
||||
$align_style = ' float: right;';
|
||||
break;
|
||||
}
|
||||
$code_style .= $align_style;
|
||||
|
||||
// Determine allowed float elements
|
||||
if ($hl->setting_val(CrayonSettings::FLOAT_ENABLE)) {
|
||||
$clear_style = ' clear: none;';
|
||||
} else {
|
||||
$clear_style = '';
|
||||
}
|
||||
$code_style .= $clear_style;
|
||||
|
||||
// Determine if operating system is mac
|
||||
$crayon_os = CrayonUtil::is_mac() ? 'mac' : 'pc';
|
||||
|
||||
// Produce output
|
||||
$output .= '
|
||||
<div id="' . $uid . '" class="crayon-syntax crayon-theme-' . $theme_id_dashed . ' crayon-font-' . $font_id_dashed . ' crayon-os-' . $crayon_os . ' print-yes notranslate" data-settings="' . $code_settings . '" style="' . $code_style . ' ' . $font_style . '">
|
||||
' . $toolbar . '
|
||||
<div class="crayon-plain-wrap">' . $print_plain . '</div>' . '
|
||||
<div class="crayon-main" style="' . $main_style . '">
|
||||
<table class="crayon-table">
|
||||
<tr class="crayon-row">';
|
||||
|
||||
if ($print_nums !== FALSE) {
|
||||
$output .= '
|
||||
<td class="crayon-nums ' . $num_vis . '" data-settings="' . $num_settings . '">
|
||||
<div class="crayon-nums-content" style="' . $font_style . '">' . $print_nums . '</div>
|
||||
</td>';
|
||||
}
|
||||
// XXX
|
||||
$output .= '
|
||||
<td class="crayon-code"><div class="crayon-pre" style="' . $font_style . ' ' . $pre_style . '">' . $print_code . '</div></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>';
|
||||
// Debugging stats
|
||||
$runtime = $hl->runtime();
|
||||
if (!$hl->setting_val(CrayonSettings::DISABLE_RUNTIME) && is_array($runtime) && !empty($runtime)) {
|
||||
$output = '<!-- Crayon Syntax Highlighter v' . $CRAYON_VERSION . ' -->'
|
||||
. CRAYON_NL . $output . CRAYON_NL . '<!-- ';
|
||||
foreach ($hl->runtime() as $type => $time) {
|
||||
$output .= '[' . $type . ': ' . sprintf('%.4f seconds', $time) . '] ';
|
||||
}
|
||||
$output .= '-->' . CRAYON_NL;
|
||||
}
|
||||
// Determine whether to print to screen or save
|
||||
if ($print) {
|
||||
echo $output;
|
||||
} else {
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
|
||||
public static function print_error($hl, $error, $line_numbers = 'ERROR', $print = TRUE) {
|
||||
if (get_class($hl) != CRAYON_HIGHLIGHTER) {
|
||||
return;
|
||||
}
|
||||
// Either print the error returned by the handler, or a custom error message
|
||||
if ($hl->setting_val(CrayonSettings::ERROR_MSG_SHOW)) {
|
||||
$error = $hl->setting_val(CrayonSettings::ERROR_MSG);
|
||||
}
|
||||
$error = self::split_lines(trim($error), 'crayon-error');
|
||||
return self::print_code($hl, $error, $line_numbers, $print);
|
||||
}
|
||||
|
||||
// Delimiters =============================================================
|
||||
|
||||
public static function format_mixed_code($code, $language, $hl) {
|
||||
self::$curr = $hl;
|
||||
self::$delim_pieces = array();
|
||||
// Remove crayon internal element from INPUT code
|
||||
$code = preg_replace('#' . CrayonParser::CRAYON_ELEMENT_REGEX_CAPTURE . '#msi', '', $code);
|
||||
|
||||
if (self::$delimiters == NULL) {
|
||||
self::$delimiters = CrayonResources::langs()->delimiters();
|
||||
}
|
||||
|
||||
// Find all delimiters in all languages
|
||||
if (self::$delim_regex == NULL) {
|
||||
self::$delim_regex = '#(' . implode(')|(', array_values(self::$delimiters)) . ')#msi';
|
||||
}
|
||||
|
||||
// Extract delimited code, replace with internal elements
|
||||
$internal_code = preg_replace_callback(self::$delim_regex, 'CrayonFormatter::delim_to_internal', $code);
|
||||
|
||||
// Format with given language
|
||||
$formatted_code = CrayonFormatter::format_code($internal_code, $language, $hl);
|
||||
|
||||
// Replace internal elements with delimited pieces
|
||||
$formatted_code = preg_replace_callback('#\{\{crayon-internal:(\d+)\}\}#', 'CrayonFormatter::internal_to_code', $formatted_code);
|
||||
|
||||
return $formatted_code;
|
||||
}
|
||||
|
||||
public static function delim_to_internal($matches) {
|
||||
// Mark as mixed so we can show (+)
|
||||
self::$curr->is_mixed(TRUE);
|
||||
$capture_group = count($matches) - 2;
|
||||
$capture_groups = array_keys(self::$delimiters);
|
||||
$lang_id = $capture_groups[$capture_group];
|
||||
if (($lang = CrayonResources::langs()->get($lang_id)) === NULL) {
|
||||
return $matches[0];
|
||||
}
|
||||
$internal = sprintf('{{crayon-internal:%d}}', count(self::$delim_pieces));
|
||||
// TODO fix
|
||||
self::$delim_pieces[] = CrayonFormatter::format_code($matches[0], $lang, self::$curr);
|
||||
return $internal;
|
||||
}
|
||||
|
||||
public static function internal_to_code($matches) {
|
||||
return self::$delim_pieces[intval($matches[1])];
|
||||
}
|
||||
|
||||
// Auxiliary Methods ======================================================
|
||||
/* Prepares code for formatting. */
|
||||
public static function clean_code($code, $escape = TRUE, $spaces = FALSE, $tabs = FALSE, $lines = FALSE) {
|
||||
if (empty($code)) {
|
||||
return $code;
|
||||
}
|
||||
/* Convert <, > and & characters to entities, as these can appear as HTML tags and entities. */
|
||||
if ($escape) {
|
||||
$code = CrayonUtil::htmlspecialchars($code);
|
||||
}
|
||||
if ($spaces) {
|
||||
// Replace 2 spaces with html escaped characters
|
||||
$code = preg_replace('#[ ]{2}#msi', ' ', $code);
|
||||
}
|
||||
if ($tabs && CrayonGlobalSettings::val(CrayonSettings::TAB_CONVERT)) {
|
||||
// Replace tabs with 4 spaces
|
||||
$code = preg_replace('#\t#', str_repeat(' ', CrayonGlobalSettings::val(CrayonSettings::TAB_SIZE)), $code);
|
||||
}
|
||||
if ($lines) {
|
||||
$code = preg_replace('#(\r\n)|\r|\n#msi', "\r\n", $code);
|
||||
}
|
||||
return $code;
|
||||
}
|
||||
|
||||
/* Converts the code to entities and wraps in a <pre><code></code></pre> */
|
||||
public static function plain_code($code, $encoded = TRUE) {
|
||||
if (is_array($code)) {
|
||||
// When used as a preg_replace_callback
|
||||
$code = $code[1];
|
||||
}
|
||||
if (!$encoded) {
|
||||
$code = CrayonUtil::htmlentities($code);
|
||||
}
|
||||
if (CrayonGlobalSettings::val(CrayonSettings::TRIM_WHITESPACE)) {
|
||||
$code = trim($code);
|
||||
}
|
||||
return '<pre class="crayon-plain-tag">' . $code . '</pre>';
|
||||
}
|
||||
|
||||
public static function split_lines($code, $class) {
|
||||
$code = self::clean_code($code, TRUE, TRUE, TRUE, FALSE);
|
||||
$class = preg_replace('#(\w+)#m', 'crayon-$1', $class);
|
||||
$code = preg_replace('#^([^\r\n]+)(?=\r\n|\r|\n|$)#m', '<span class="' . $class . '">$1</span>', $code);
|
||||
return $code;
|
||||
}
|
||||
|
||||
private static function dimension_style($hl, $name) {
|
||||
$mode = $unit = '';
|
||||
switch ($name) {
|
||||
case CrayonSettings::HEIGHT :
|
||||
$mode = CrayonSettings::HEIGHT_MODE;
|
||||
$unit = CrayonSettings::HEIGHT_UNIT;
|
||||
break;
|
||||
case CrayonSettings::WIDTH :
|
||||
$mode = CrayonSettings::WIDTH_MODE;
|
||||
$unit = CrayonSettings::WIDTH_UNIT;
|
||||
break;
|
||||
}
|
||||
// XXX Uses actual index value to identify options
|
||||
$mode = $hl->setting_index($mode);
|
||||
$unit = $hl->setting_index($unit);
|
||||
$dim_mode = $dim_unit = '';
|
||||
if ($mode !== FALSE) {
|
||||
switch ($mode) {
|
||||
case 0 :
|
||||
$dim_mode .= 'max-';
|
||||
break;
|
||||
case 1 :
|
||||
$dim_mode .= 'min-';
|
||||
break;
|
||||
}
|
||||
}
|
||||
$dim_mode .= $name;
|
||||
if ($unit !== FALSE) {
|
||||
switch ($unit) {
|
||||
case 0 :
|
||||
$dim_unit = 'px';
|
||||
break;
|
||||
case 1 :
|
||||
$dim_unit = '%';
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ' ' . $dim_mode . ': ' . $hl->setting_val($name) . $dim_unit . ';';
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
423
crayon_highlighter.class.php
Normal file
423
crayon_highlighter.class.php
Normal file
@ -0,0 +1,423 @@
|
||||
<?php
|
||||
// Class includes
|
||||
require_once ('global.php');
|
||||
require_once (CRAYON_PARSER_PHP);
|
||||
require_once (CRAYON_FORMATTER_PHP);
|
||||
require_once (CRAYON_SETTINGS_PHP);
|
||||
require_once (CRAYON_LANGS_PHP);
|
||||
|
||||
/* The main class for managing the syntax highlighter */
|
||||
class CrayonHighlighter {
|
||||
// Properties and Constants ===============================================
|
||||
private $id = '';
|
||||
// URL is initially NULL, meaning none provided
|
||||
private $url = NULL;
|
||||
private $code = '';
|
||||
private $formatted_code = '';
|
||||
private $title = '';
|
||||
private $line_count = 0;
|
||||
private $marked_lines = array();
|
||||
private $range = NULL;
|
||||
private $error = '';
|
||||
// Determine whether the code needs to be loaded, parsed or formatted
|
||||
private $needs_load = FALSE;
|
||||
private $needs_format = FALSE;
|
||||
// Record the script run times
|
||||
private $runtime = array();
|
||||
// Whether the code is mixed
|
||||
private $is_mixed = FALSE;
|
||||
// Inline code on a single floating line
|
||||
private $is_inline = FALSE;
|
||||
private $is_highlighted = TRUE;
|
||||
|
||||
// Objects
|
||||
// Stores the CrayonLang being used
|
||||
private $language = NULL;
|
||||
// A copy of the current global settings which can be overridden
|
||||
private $settings = NULL;
|
||||
|
||||
// Methods ================================================================
|
||||
function __construct($url = NULL, $language = NULL, $id = NULL) {
|
||||
if ($url !== NULL) {
|
||||
$this->url($url);
|
||||
}
|
||||
|
||||
if ($language !== NULL) {
|
||||
$this->language($language);
|
||||
}
|
||||
// Default ID
|
||||
$id = $id !== NULL ? $id : uniqid();
|
||||
$this->id($id);
|
||||
}
|
||||
|
||||
/* Tries to load the code locally, then attempts to load it remotely */
|
||||
private function load() {
|
||||
if (empty($this->url)) {
|
||||
$this->error('The specified URL is empty, please provide a valid URL.');
|
||||
return;
|
||||
}
|
||||
// Try to replace the URL with an absolute path if it is local, used to prevent scripts
|
||||
// from executing when they are loaded.
|
||||
$url = $this->url;
|
||||
if ($this->setting_val(CrayonSettings::DECODE_ATTRIBUTES)) {
|
||||
$url = CrayonUtil::html_entity_decode($url);
|
||||
}
|
||||
$url = CrayonUtil::pathf($url);
|
||||
$site_http = CrayonGlobalSettings::site_url();
|
||||
$scheme = parse_url($url, PHP_URL_SCHEME);
|
||||
// Try to replace the site URL with a path to force local loading
|
||||
if (empty($scheme)) {
|
||||
// No url scheme is given - path may be given as relative
|
||||
$url = CrayonUtil::path_slash($site_http) . CrayonUtil::path_slash($this->setting_val(CrayonSettings::LOCAL_PATH)) . $url;
|
||||
}
|
||||
$http_code = 0;
|
||||
// If available, use the built in wp remote http get function.
|
||||
if (function_exists('wp_remote_get')) {
|
||||
$url_uid = 'crayon_' . CrayonUtil::str_uid($url);
|
||||
$cached = get_transient($url_uid, 'crayon-syntax');
|
||||
CrayonSettingsWP::load_cache();
|
||||
if ($cached !== FALSE) {
|
||||
$content = $cached;
|
||||
$http_code = 200;
|
||||
} else {
|
||||
$response = @wp_remote_get($url, array('sslverify' => false, 'timeout' => 20));
|
||||
$content = wp_remote_retrieve_body($response);
|
||||
$http_code = wp_remote_retrieve_response_code($response);
|
||||
$cache = $this->setting_val(CrayonSettings::CACHE);
|
||||
$cache_sec = CrayonSettings::get_cache_sec($cache);
|
||||
if ($cache_sec > 1 && $http_code >= 200 && $http_code < 400) {
|
||||
set_transient($url_uid, $content, $cache_sec);
|
||||
CrayonSettingsWP::add_cache($url_uid);
|
||||
}
|
||||
}
|
||||
} else if (in_array(parse_url($url, PHP_URL_SCHEME), array('ssl', 'http', 'https'))) {
|
||||
// Fallback to cURL. At this point, the URL scheme must be valid.
|
||||
$ch = curl_init($url);
|
||||
curl_setopt($ch, CURLOPT_HEADER, FALSE);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
|
||||
// For https connections, we do not require SSL verification
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
|
||||
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 20);
|
||||
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);
|
||||
curl_setopt($ch, CURLOPT_FRESH_CONNECT, FALSE);
|
||||
curl_setopt($ch, CURLOPT_MAXREDIRS, 5);
|
||||
if (isset($_SERVER['HTTP_USER_AGENT'])) {
|
||||
curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']);
|
||||
}
|
||||
$content = curl_exec($ch);
|
||||
$error = curl_error($ch);
|
||||
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
curl_close($ch);
|
||||
}
|
||||
if ($http_code >= 200 && $http_code < 400) {
|
||||
$this->code($content);
|
||||
} else {
|
||||
if (empty($this->code)) {
|
||||
// If code is also given, just use that
|
||||
$this->error("The provided URL ('$this->url'), parsed remotely as ('$url'), could not be accessed.");
|
||||
}
|
||||
}
|
||||
$this->needs_load = FALSE;
|
||||
}
|
||||
|
||||
/* Central point of access for all other functions to update code. */
|
||||
public function process() {
|
||||
$tmr = new CrayonTimer();
|
||||
$this->runtime = NULL;
|
||||
if ($this->needs_load) {
|
||||
$tmr->start();
|
||||
$this->load();
|
||||
$this->runtime[CRAYON_LOAD_TIME] = $tmr->stop();
|
||||
}
|
||||
if (!empty($this->error) || empty($this->code)) {
|
||||
// Disable highlighting for errors and empty code
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->language === NULL) {
|
||||
$this->language_detect();
|
||||
}
|
||||
if ($this->needs_format) {
|
||||
$tmr->start();
|
||||
try {
|
||||
// Parse before hand to read modes
|
||||
$code = $this->code;
|
||||
// If inline, then combine lines into one
|
||||
if ($this->is_inline) {
|
||||
$code = preg_replace('#[\r\n]+#ms', '', $code);
|
||||
if ($this->setting_val(CrayonSettings::TRIM_WHITESPACE)) {
|
||||
$code = trim($code);
|
||||
}
|
||||
}
|
||||
// Decode html entities (e.g. if using visual editor or manually encoding)
|
||||
if ($this->setting_val(CrayonSettings::DECODE)) {
|
||||
$code = CrayonUtil::html_entity_decode($code);
|
||||
}
|
||||
// Save code so output is plain output is the same
|
||||
$this->code = $code;
|
||||
|
||||
// Allow mixed if langauge supports it and setting is set
|
||||
CrayonParser::parse($this->language->id());
|
||||
if (!$this->setting_val(CrayonSettings::MIXED) || !$this->language->mode(CrayonParser::ALLOW_MIXED)) {
|
||||
// Format the code with the generated regex and elements
|
||||
$this->formatted_code = CrayonFormatter::format_code($code, $this->language, $this);
|
||||
} else {
|
||||
// Format the code with Mixed Highlighting
|
||||
$this->formatted_code = CrayonFormatter::format_mixed_code($code, $this->language, $this);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$this->error($e->message());
|
||||
return;
|
||||
}
|
||||
$this->needs_format = FALSE;
|
||||
$this->runtime[CRAYON_FORMAT_TIME] = $tmr->stop();
|
||||
}
|
||||
}
|
||||
|
||||
/* Used to format the glue in between code when finding mixed languages */
|
||||
private function format_glue($glue, $highlight = TRUE) {
|
||||
// TODO $highlight
|
||||
return CrayonFormatter::format_code($glue, $this->language, $this, $highlight);
|
||||
}
|
||||
|
||||
/* Sends the code to the formatter for printing. Apart from the getters and setters, this is
|
||||
the only other function accessible outside this class. $show_lines can also be a string. */
|
||||
function output($show_lines = TRUE, $print = TRUE) {
|
||||
$this->process();
|
||||
if (empty($this->error)) {
|
||||
// If no errors have occured, print the formatted code
|
||||
$ret = CrayonFormatter::print_code($this, $this->formatted_code, $show_lines, $print);
|
||||
} else {
|
||||
$ret = CrayonFormatter::print_error($this, $this->error, '', $print);
|
||||
}
|
||||
// Reset the error message at the end of the print session
|
||||
$this->error = '';
|
||||
// If $print = FALSE, $ret will contain the output
|
||||
return $ret;
|
||||
}
|
||||
|
||||
// Getters and Setters ====================================================
|
||||
function code($code = NULL) {
|
||||
if ($code === NULL) {
|
||||
return $this->code;
|
||||
} else {
|
||||
// Trim whitespace
|
||||
if ($this->setting_val(CrayonSettings::TRIM_WHITESPACE)) {
|
||||
$code = preg_replace("#(?:^\\s*\\r?\\n)|(?:\\r?\\n\\s*$)#", '', $code);
|
||||
}
|
||||
|
||||
if ($this->setting_val(CrayonSettings::TRIM_CODE_TAG)) {
|
||||
$code = preg_replace('#^\s*<\s*code[^>]*>#msi', '', $code);
|
||||
$code = preg_replace('#</\s*code[^>]*>\s*$#msi', '', $code);
|
||||
}
|
||||
|
||||
$before = $this->setting_val(CrayonSettings::WHITESPACE_BEFORE);
|
||||
if ($before > 0) {
|
||||
$code = str_repeat("\n", $before) . $code;
|
||||
}
|
||||
$after = $this->setting_val(CrayonSettings::WHITESPACE_AFTER);
|
||||
if ($after > 0) {
|
||||
$code = $code . str_repeat("\n", $after);
|
||||
}
|
||||
|
||||
if (!empty($code)) {
|
||||
$this->code = $code;
|
||||
$this->needs_format = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function language($id = NULL) {
|
||||
if ($id === NULL || !is_string($id)) {
|
||||
return $this->language;
|
||||
}
|
||||
|
||||
if ( ($lang = CrayonResources::langs()->get($id)) != FALSE || ($lang = CrayonResources::langs()->alias($id)) != FALSE ) {
|
||||
// Set the language if it exists or look for an alias
|
||||
$this->language = $lang;
|
||||
} else {
|
||||
$this->language_detect();
|
||||
}
|
||||
|
||||
// Prepare the language for use, even if we have no code, we need the name
|
||||
CrayonParser::parse($this->language->id());
|
||||
}
|
||||
|
||||
function language_detect() {
|
||||
// Attempt to detect the language
|
||||
if (!empty($id)) {
|
||||
$this->log("The language '$id' could not be loaded.");
|
||||
}
|
||||
$this->language = CrayonResources::langs()->detect($this->url, $this->setting_val(CrayonSettings::FALLBACK_LANG));
|
||||
}
|
||||
|
||||
function url($url = NULL) {
|
||||
if ($url === NULL) {
|
||||
return $this->url;
|
||||
} else {
|
||||
$this->url = $url;
|
||||
$this->needs_load = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
function title($title = NULL) {
|
||||
if (!CrayonUtil::str($this->title, $title)) {
|
||||
return $this->title;
|
||||
}
|
||||
}
|
||||
|
||||
function line_count($line_count = NULL) {
|
||||
if (!CrayonUtil::num($this->line_count, $line_count)) {
|
||||
return $this->line_count;
|
||||
}
|
||||
}
|
||||
|
||||
function marked($str = NULL) {
|
||||
if ($str === NULL) {
|
||||
return $this->marked_lines;
|
||||
}
|
||||
// If only an int is given
|
||||
if (is_int($str)) {
|
||||
$array = array($str);
|
||||
return CrayonUtil::arr($this->marked_lines, $array);
|
||||
}
|
||||
// A string with ints separated by commas, can also contain ranges
|
||||
$array = CrayonUtil::trim_e($str);
|
||||
$array = array_unique($array);
|
||||
$lines = array();
|
||||
foreach ($array as $line) {
|
||||
// Check for ranges
|
||||
if (strpos($line, '-') !== FALSE) {
|
||||
$ranges = CrayonUtil::range_str($line);
|
||||
$lines = array_merge($lines, $ranges);
|
||||
} else {
|
||||
// Otherwise check the string for a number
|
||||
$line = intval($line);
|
||||
if ($line !== 0) {
|
||||
$lines[] = $line;
|
||||
}
|
||||
}
|
||||
}
|
||||
return CrayonUtil::arr($this->marked_lines, $lines);
|
||||
}
|
||||
|
||||
function range($str = NULL) {
|
||||
if ($str === NULL) {
|
||||
return $this->range;
|
||||
} else {
|
||||
$range = CrayonUtil::range_str_single($str);
|
||||
if ($range) {
|
||||
$this->range = $range;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
function log($var) {
|
||||
if ($this->setting_val(CrayonSettings::ERROR_LOG)) {
|
||||
CrayonLog::log($var);
|
||||
}
|
||||
}
|
||||
|
||||
function id($id = NULL) {
|
||||
if ($id == NULL) {
|
||||
return $this->id;
|
||||
} else {
|
||||
$this->id = strval($id);
|
||||
}
|
||||
}
|
||||
|
||||
function error($string = NULL) {
|
||||
if (!$string) {
|
||||
return $this->error;
|
||||
}
|
||||
$this->error .= $string;
|
||||
$this->log($string);
|
||||
// Add the error string and ensure no further processing occurs
|
||||
$this->needs_load = FALSE;
|
||||
$this->needs_format = FALSE;
|
||||
}
|
||||
|
||||
// Set and retreive settings
|
||||
// TODO fix this, it's too limiting
|
||||
function settings($mixed = NULL) {
|
||||
if ($this->settings == NULL) {
|
||||
$this->settings = CrayonGlobalSettings::get_obj();
|
||||
}
|
||||
|
||||
if ($mixed === NULL) {
|
||||
return $this->settings;
|
||||
} else if (is_string($mixed)) {
|
||||
return $this->settings->get($mixed);
|
||||
} else if (is_array($mixed)) {
|
||||
$this->settings->set($mixed);
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Retrieve a single setting's value for use in the formatter. By default, on failure it will
|
||||
* return TRUE to ensure FALSE is only sent when a setting is found. This prevents a fake
|
||||
* FALSE when the formatter checks for a positive setting (Show/Enable) and fails. When a
|
||||
* negative setting is needed (Hide/Disable), $default_return should be set to FALSE. */
|
||||
// TODO fix this (see above)
|
||||
function setting_val($name = NULL, $default_return = TRUE) {
|
||||
if (is_string($name) && $setting = $this->settings($name)) {
|
||||
return $setting->value();
|
||||
} else {
|
||||
// Name not valid
|
||||
return (is_bool($default_return) ? $default_return : TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
// Set a setting value
|
||||
// TODO fix this (see above)
|
||||
function setting_set($name = NULL, $value = TRUE) {
|
||||
$this->settings->set($name, $value);
|
||||
}
|
||||
|
||||
// Used to find current index in dropdown setting
|
||||
function setting_index($name = NULL) {
|
||||
$setting = $this->settings($name);
|
||||
if (is_string($name) && $setting->is_array()) {
|
||||
return $setting->index();
|
||||
} else {
|
||||
// Returns -1 to avoid accidentally selecting an item in a dropdown
|
||||
return CrayonSettings::INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
function formatted_code() {
|
||||
return $this->formatted_code;
|
||||
}
|
||||
|
||||
function runtime() {
|
||||
return $this->runtime;
|
||||
}
|
||||
|
||||
function is_highlighted($highlighted = NULL) {
|
||||
if ($highlighted === NULL) {
|
||||
return $this->is_highlighted;
|
||||
} else {
|
||||
$this->is_highlighted = $highlighted;
|
||||
}
|
||||
}
|
||||
|
||||
function is_mixed($mixed = NULL) {
|
||||
if ($mixed === NULL) {
|
||||
return $this->is_mixed;
|
||||
} else {
|
||||
$this->is_mixed = $mixed;
|
||||
}
|
||||
}
|
||||
|
||||
function is_inline($inline = NULL) {
|
||||
if ($inline === NULL) {
|
||||
return $this->is_inline;
|
||||
} else {
|
||||
$inline = CrayonUtil::str_to_bool($inline, FALSE);
|
||||
$this->is_inline = $inline;
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
544
crayon_langs.class.php
Normal file
544
crayon_langs.class.php
Normal file
@ -0,0 +1,544 @@
|
||||
<?php
|
||||
require_once ('global.php');
|
||||
require_once (CRAYON_RESOURCE_PHP);
|
||||
|
||||
class CrayonLangsResourceType {
|
||||
const EXTENSION = 0;
|
||||
const ALIAS = 1;
|
||||
const DELIMITER = 2;
|
||||
}
|
||||
|
||||
/* Manages languages once they are loaded. The parser directly loads them, saves them here. */
|
||||
class CrayonLangs extends CrayonUserResourceCollection {
|
||||
// Properties and Constants ===============================================
|
||||
// CSS classes for known elements
|
||||
private static $known_elements = array('COMMENT' => 'c', 'PREPROCESSOR' => 'p', 'STRING' => 's', 'KEYWORD' => 'k',
|
||||
'STATEMENT' => 'st', 'RESERVED' => 'r', 'TYPE' => 't', 'TAG' => 'ta', 'MODIFIER' => 'm', 'IDENTIFIER' => 'i',
|
||||
'ENTITY' => 'e', 'VARIABLE' => 'v', 'CONSTANT' => 'cn', 'OPERATOR' => 'o', 'SYMBOL' => 'sy',
|
||||
'NOTATION' => 'n', 'FADED' => 'f', CrayonParser::HTML_CHAR => 'h', CrayonParser::CRAYON_ELEMENT => 'crayon-internal-element');
|
||||
const DEFAULT_LANG = 'default';
|
||||
const DEFAULT_LANG_NAME = 'Default';
|
||||
|
||||
const RESOURCE_TYPE = 'CrayonLangsResourceType';
|
||||
|
||||
// Used to cache the objects, since they are unlikely to change during a single run
|
||||
private static $resource_cache = array();
|
||||
|
||||
// Methods ================================================================
|
||||
public function __construct() {
|
||||
$this->set_default(self::DEFAULT_LANG, self::DEFAULT_LANG_NAME);
|
||||
$this->directory(CRAYON_LANG_PATH);
|
||||
$this->relative_directory(CRAYON_LANG_DIR);
|
||||
$this->extension('txt');
|
||||
|
||||
CrayonLog::debug("Setting lang directories");
|
||||
$upload = CrayonGlobalSettings::upload_path();
|
||||
if ($upload) {
|
||||
$this->user_directory($upload . CRAYON_LANG_DIR);
|
||||
if (!is_dir($this->user_directory())) {
|
||||
CrayonGlobalSettings::mkdir($this->user_directory());
|
||||
CrayonLog::debug($this->user_directory(), "LANG USER DIR");
|
||||
}
|
||||
} else {
|
||||
CrayonLog::syslog("Upload directory is empty: " . $upload . " cannot load languages.");
|
||||
}
|
||||
CrayonLog::debug($this->directory());
|
||||
CrayonLog::debug($this->user_directory());
|
||||
}
|
||||
|
||||
public function filename($id, $user = NULL) {
|
||||
return $id."/$id.".$this->extension();
|
||||
}
|
||||
|
||||
// XXX Override
|
||||
public function load_process() {
|
||||
parent::load_process();
|
||||
$this->load_exts();
|
||||
$this->load_aliases();
|
||||
$this->load_delimiters(); // TODO check for setting?
|
||||
}
|
||||
|
||||
public function load_resources($dir = NULL) {
|
||||
parent::load_resources($dir);
|
||||
|
||||
}
|
||||
|
||||
// XXX Override
|
||||
public function create_user_resource_instance($id, $name = NULL) {
|
||||
return new CrayonLang($id, $name);
|
||||
}
|
||||
|
||||
// XXX Override
|
||||
public function add_default() {
|
||||
$result = parent::add_default();
|
||||
if ($this->is_state_loading() && !$result) {
|
||||
// Default not added, must already be loaded, ready to parse
|
||||
CrayonParser::parse(self::DEFAULT_LANG);
|
||||
}
|
||||
}
|
||||
|
||||
/* Attempts to detect the language based on extension, otherwise falls back to fallback language given.
|
||||
* Returns a CrayonLang object. */
|
||||
public function detect($path, $fallback_id = NULL) {
|
||||
$this->load();
|
||||
extract(pathinfo($path));
|
||||
|
||||
// If fallback id if given
|
||||
if ($fallback_id == NULL) {
|
||||
// Otherwise use global fallback
|
||||
$fallback_id = CrayonGlobalSettings::get(CrayonSettings::FALLBACK_LANG);
|
||||
}
|
||||
// Attempt to use fallback
|
||||
$fallback = $this->get($fallback_id);
|
||||
// Use extension before trying fallback
|
||||
$extension = isset($extension) ? $extension : '';
|
||||
|
||||
if ( !empty($extension) && ($lang = $this->ext($extension)) || ($lang = $this->get($extension)) ) {
|
||||
// If extension is found, attempt to find a language for it.
|
||||
// If that fails, attempt to load a language with the same id as the extension.
|
||||
return $lang;
|
||||
} else if ($fallback != NULL || $fallback = $this->get_default()) {
|
||||
// Resort to fallback if loaded, or fallback to default
|
||||
return $fallback;
|
||||
} else {
|
||||
// No language found
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Load all extensions and add them into each language. */
|
||||
private function load_exts() {
|
||||
// Load only once
|
||||
if (!$this->is_state_loading()) {
|
||||
return;
|
||||
}
|
||||
if ( ($lang_exts = self::load_attr_file(CRAYON_LANG_EXT)) !== FALSE ) {
|
||||
foreach ($lang_exts as $lang_id=>$exts) {
|
||||
$lang = $this->get($lang_id);
|
||||
$lang->ext($exts);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Load all extensions and add them into each language. */
|
||||
private function load_aliases() {
|
||||
// Load only once
|
||||
if (!$this->is_state_loading()) {
|
||||
return;
|
||||
}
|
||||
if ( ($lang_aliases = self::load_attr_file(CRAYON_LANG_ALIAS)) !== FALSE ) {
|
||||
foreach ($lang_aliases as $lang_id=>$aliases) {
|
||||
$lang = $this->get($lang_id);
|
||||
$lang->alias($aliases);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Load all extensions and add them into each language. */
|
||||
private function load_delimiters() {
|
||||
// Load only once
|
||||
if (!$this->is_state_loading()) {
|
||||
return;
|
||||
}
|
||||
if ( ($lang_delims = self::load_attr_file(CRAYON_LANG_DELIM)) !== FALSE ) {
|
||||
foreach ($lang_delims as $lang_id=>$delims) {
|
||||
$lang = $this->get($lang_id);
|
||||
$lang->delimiter($delims);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Used to load aliases and extensions to languages
|
||||
private function load_attr_file($path) {
|
||||
if ( ($lines = CrayonUtil::lines($path, 'lwc')) !== FALSE) {
|
||||
$attributes = array(); // key = language id, value = array of attr
|
||||
foreach ($lines as $line) {
|
||||
preg_match('#^[\t ]*([^\r\n\t ]+)[\t ]+([^\r\n]+)#', $line, $matches);
|
||||
if (count($matches) == 3 && $lang = $this->get($matches[1])) {
|
||||
// If the langauges of the attribute exists, return it in an array
|
||||
// TODO merge instead of replace key?
|
||||
$attributes[$matches[1]] = explode(' ', $matches[2]);
|
||||
}
|
||||
}
|
||||
return $attributes;
|
||||
} else {
|
||||
CrayonLog::syslog('Could not load attr file: ' . $path);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns the CrayonLang for the given extension */
|
||||
public function ext($ext) {
|
||||
$this->load();
|
||||
foreach ($this->get() as $lang) {
|
||||
if ($lang->has_ext($ext)) {
|
||||
return $lang;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Returns the CrayonLang for the given alias */
|
||||
public function alias($alias) {
|
||||
$this->load();
|
||||
foreach ($this->get() as $lang) {
|
||||
if ($lang->has_alias($alias)) {
|
||||
return $lang;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Fetches a resource. Type is an int from CrayonLangsResourceType. */
|
||||
public function fetch($type, $reload = FALSE, $keep_empty_fetches = FALSE) {
|
||||
$this->load();
|
||||
|
||||
if (!array_key_exists($type, self::$resource_cache) || $reload) {
|
||||
$fetches = array();
|
||||
foreach ($this->get() as $lang) {
|
||||
|
||||
switch ($type) {
|
||||
case CrayonLangsResourceType::EXTENSION:
|
||||
$fetch = $lang->ext();
|
||||
break;
|
||||
case CrayonLangsResourceType::ALIAS:
|
||||
$fetch = $lang->alias();
|
||||
break;
|
||||
case CrayonLangsResourceType::DELIMITER:
|
||||
$fetch = $lang->delimiter();
|
||||
break;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ( !empty($fetch) || $keep_empty_fetches ) {
|
||||
$fetches[$lang->id()] = $fetch;
|
||||
}
|
||||
}
|
||||
self::$resource_cache[$type] = $fetches;
|
||||
}
|
||||
return self::$resource_cache[$type];
|
||||
}
|
||||
|
||||
public function extensions($reload = FALSE) {
|
||||
return $this->fetch(CrayonLangsResourceType::EXTENSION, $reload);
|
||||
}
|
||||
|
||||
public function aliases($reload = FALSE) {
|
||||
return $this->fetch(CrayonLangsResourceType::ALIAS, $reload);
|
||||
}
|
||||
|
||||
public function delimiters($reload = FALSE) {
|
||||
return $this->fetch(CrayonLangsResourceType::DELIMITER, $reload);
|
||||
}
|
||||
|
||||
public function extensions_inverted($reload = FALSE) {
|
||||
$extensions = $this->extensions($reload);
|
||||
$inverted = array();
|
||||
foreach ($extensions as $lang=>$exts) {
|
||||
foreach ($exts as $ext) {
|
||||
$inverted[$ext] = $lang;
|
||||
}
|
||||
}
|
||||
return $inverted;
|
||||
}
|
||||
|
||||
public function ids_and_aliases($reload = FALSE) {
|
||||
$fetch = $this->fetch(CrayonLangsResourceType::ALIAS, $reload, TRUE);
|
||||
foreach ($fetch as $id=>$alias_array) {
|
||||
$ids_and_aliases[] = $id;
|
||||
foreach ($alias_array as $alias) {
|
||||
$ids_and_aliases[] = $alias;
|
||||
}
|
||||
}
|
||||
return $ids_and_aliases;
|
||||
}
|
||||
|
||||
/* Return the array of valid elements or a particular element value */
|
||||
public static function known_elements($name = NULL) {
|
||||
if ($name === NULL) {
|
||||
return self::$known_elements;
|
||||
} else if (is_string($name) && array_key_exists($name, self::$known_elements)) {
|
||||
return self::$known_elements[$name];
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Verify an element is valid */
|
||||
public static function is_known_element($name) {
|
||||
return self::known_elements($name) !== FALSE;
|
||||
}
|
||||
|
||||
/* Compare two languages by name */
|
||||
public static function langcmp($a, $b) {
|
||||
$a = strtolower($a->name());
|
||||
$b = strtolower($b->name());
|
||||
if ($a == $b) {
|
||||
return 0;
|
||||
} else {
|
||||
return ($a < $b) ? -1 : 1;
|
||||
}
|
||||
}
|
||||
|
||||
public static function sort_by_name($langs) {
|
||||
// Sort by name
|
||||
usort($langs, 'CrayonLangs::langcmp');
|
||||
$sorted_lags = array();
|
||||
foreach ($langs as $lang) {
|
||||
$sorted_lags[$lang->id()] = $lang;
|
||||
}
|
||||
return $sorted_lags;
|
||||
}
|
||||
|
||||
public function is_parsed($id = NULL) {
|
||||
if ($id === NULL) {
|
||||
// Determine if all langs are successfully parsed
|
||||
foreach ($this->get() as $lang) {
|
||||
if ($lang->state() != CrayonLang::PARSED_SUCCESS) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
} else if (($lang = $this->get($id)) != FALSE) {
|
||||
return $lang->is_parsed();
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
public function is_default($id) {
|
||||
if (($lang = $this->get($id)) != FALSE) {
|
||||
return $lang->is_default();
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Individual language. */
|
||||
class CrayonLang extends CrayonVersionResource {
|
||||
private $ext = array();
|
||||
private $aliases = array();
|
||||
private $delimiters = '';
|
||||
// Associative array of CrayonElement objects
|
||||
private $elements = array();
|
||||
//private $regex = '';
|
||||
private $state = self::UNPARSED;
|
||||
private $modes = array();
|
||||
// Whether this language allows Multiple Highlighting from other languages
|
||||
const PARSED_ERRORS = -1;
|
||||
const UNPARSED = 0;
|
||||
const PARSED_SUCCESS = 1;
|
||||
|
||||
function __construct($id, $name = NULL) {
|
||||
parent::__construct($id, $name);
|
||||
$this->modes = CrayonParser::modes();
|
||||
}
|
||||
|
||||
// Override
|
||||
function clean_id($id) {
|
||||
$id = CrayonUtil::space_to_hyphen( strtolower(trim($id)) );
|
||||
return preg_replace('/[^\w\-+#]/msi', '', $id);
|
||||
}
|
||||
|
||||
function ext($ext = NULL) {
|
||||
if ($ext === NULL) {
|
||||
return $this->ext;
|
||||
} else if (is_array($ext) && !empty($ext)) |