public function getHighlightFuture($language, $source)
 {
     if ($language === null) {
         $language = PhutilLanguageGuesser::guessLanguage($source);
     }
     $have_pygments = !empty($this->config['pygments.enabled']);
     if ($language == 'php' && xhpast_is_available()) {
         return id(new PhutilXHPASTSyntaxHighlighter())->getHighlightFuture($source);
     }
     if ($language == 'console') {
         return id(new PhutilConsoleSyntaxHighlighter())->getHighlightFuture($source);
     }
     if ($language == 'diviner' || $language == 'remarkup') {
         return id(new PhutilDivinerSyntaxHighlighter())->getHighlightFuture($source);
     }
     if ($language == 'rainbow') {
         return id(new PhutilRainbowSyntaxHighlighter())->getHighlightFuture($source);
     }
     if ($language == 'php') {
         return id(new PhutilLexerSyntaxHighlighter())->setConfig('lexer', new PhutilPHPFragmentLexer())->setConfig('language', 'php')->getHighlightFuture($source);
     }
     if ($language == 'py') {
         return id(new PhutilLexerSyntaxHighlighter())->setConfig('lexer', new PhutilPythonFragmentLexer())->setConfig('language', 'py')->getHighlightFuture($source);
     }
     if ($language == 'invisible') {
         return id(new PhutilInvisibleSyntaxHighlighter())->getHighlightFuture($source);
     }
     if ($have_pygments) {
         return id(new PhutilPygmentsSyntaxHighlighter())->setConfig('language', $language)->getHighlightFuture($source);
     }
     return id(new PhutilDefaultSyntaxHighlighter())->getHighlightFuture($source);
 }
 public function testGuessing()
 {
     $dir = dirname(__FILE__) . '/languageguesser/';
     foreach (Filesystem::listDirectory($dir, $hidden = false) as $test) {
         $source = Filesystem::readFile($dir . $test);
         if (strpos($test, '.') !== false) {
             $expect = head(explode('.', $test));
         } else {
             $expect = null;
         }
         $this->assertEqual($expect, PhutilLanguageGuesser::guessLanguage($source), "Guessed language for '{$test}'.");
     }
 }
 public function getHighlightFuture($language, $source)
 {
     if ($language === null) {
         $language = PhutilLanguageGuesser::guessLanguage($source);
     }
     $have_pygments = !empty($this->config['pygments.enabled']);
     if ($language == 'php' && PhutilXHPASTBinary::isAvailable()) {
         return id(new PhutilXHPASTSyntaxHighlighter())->getHighlightFuture($source);
     }
     if ($language == 'console') {
         return id(new PhutilConsoleSyntaxHighlighter())->getHighlightFuture($source);
     }
     if ($language == 'diviner' || $language == 'remarkup') {
         return id(new PhutilDivinerSyntaxHighlighter())->getHighlightFuture($source);
     }
     if ($language == 'rainbow') {
         return id(new PhutilRainbowSyntaxHighlighter())->getHighlightFuture($source);
     }
     if ($language == 'php') {
         return id(new PhutilLexerSyntaxHighlighter())->setConfig('lexer', new PhutilPHPFragmentLexer())->setConfig('language', 'php')->getHighlightFuture($source);
     }
     if ($language == 'py') {
         return id(new PhutilLexerSyntaxHighlighter())->setConfig('lexer', new PhutilPythonFragmentLexer())->setConfig('language', 'py')->getHighlightFuture($source);
     }
     if ($language == 'json') {
         return id(new PhutilLexerSyntaxHighlighter())->setConfig('lexer', new PhutilJSONFragmentLexer())->getHighlightFuture($source);
     }
     if ($language == 'invisible') {
         return id(new PhutilInvisibleSyntaxHighlighter())->getHighlightFuture($source);
     }
     // Don't invoke Pygments for plain text, since it's expensive and has
     // no effect.
     if ($language !== 'text' && $language !== 'txt') {
         if ($have_pygments) {
             return id(new PhutilPygmentsSyntaxHighlighter())->setConfig('language', $language)->getHighlightFuture($source);
         }
     }
     return id(new PhutilDefaultSyntaxHighlighter())->getHighlightFuture($source);
 }
 public function markupText($text, $children)
 {
     if (preg_match('/^\\s*```/', $text)) {
         // If this is a ```-style block, trim off the backticks and any leading
         // blank line.
         $text = preg_replace('/^\\s*```(\\s*\\n)?/', '', $text);
         $text = preg_replace('/```\\s*$/', '', $text);
     }
     $lines = explode("\n", $text);
     while ($lines && !strlen(last($lines))) {
         unset($lines[last_key($lines)]);
     }
     $options = array('counterexample' => false, 'lang' => null, 'name' => null, 'lines' => null);
     $parser = new PhutilSimpleOptions();
     $custom = $parser->parse(head($lines));
     if ($custom) {
         $valid = true;
         foreach ($custom as $key => $value) {
             if (!array_key_exists($key, $options)) {
                 $valid = false;
                 break;
             }
         }
         if ($valid) {
             array_shift($lines);
             $options = $custom + $options;
         }
     }
     // Normalize the text back to a 0-level indent.
     $min_indent = 80;
     foreach ($lines as $line) {
         for ($ii = 0; $ii < strlen($line); $ii++) {
             if ($line[$ii] != ' ') {
                 $min_indent = min($ii, $min_indent);
                 break;
             }
         }
     }
     $text = implode("\n", $lines);
     if ($min_indent) {
         $indent_string = str_repeat(' ', $min_indent);
         $text = preg_replace('/^' . $indent_string . '/m', '', $text);
     }
     if ($this->getEngine()->isTextMode()) {
         $out = array();
         $header = array();
         if ($options['counterexample']) {
             $header[] = 'counterexample';
         }
         if ($options['name'] != '') {
             $header[] = 'name=' . $options['name'];
         }
         if ($header) {
             $out[] = implode(', ', $header);
         }
         $text = preg_replace('/^/m', '  ', $text);
         $out[] = $text;
         return implode("\n", $out);
     }
     if (empty($options['lang'])) {
         // If the user hasn't specified "lang=..." explicitly, try to guess the
         // language. If we fail, fall back to configured defaults.
         $lang = PhutilLanguageGuesser::guessLanguage($text);
         if (!$lang) {
             $lang = nonempty($this->getEngine()->getConfig('phutil.codeblock.language-default'), 'text');
         }
         $options['lang'] = $lang;
     }
     $code_body = $this->highlightSource($text, $options);
     $name_header = null;
     if ($this->getEngine()->isHTMLMailMode()) {
         $header_attributes = array('style' => 'padding: 6px 8px;
       background: #fdf5d4;
       color: rgba(0,0,0,.75);
       font-weight: bold;
       display: inline-block;
       border-top: 1px solid #f1c40f;
       border-left: 1px solid #f1c40f;
       border-right: 1px solid #f1c40f;
       margin-bottom: -1px;');
     } else {
         $header_attributes = array('class' => 'remarkup-code-header');
     }
     if ($options['name']) {
         $name_header = phutil_tag('div', $header_attributes, $options['name']);
     }
     $class = 'remarkup-code-block';
     if ($options['counterexample']) {
         $class = 'remarkup-code-block code-block-counterexample';
     }
     $attributes = array('class' => $class, 'data-code-lang' => $options['lang'], 'data-sigil' => 'remarkup-code-block');
     return phutil_tag('div', $attributes, array($name_header, $code_body));
 }
 public function markupText($text)
 {
     if (preg_match('/^```/', $text)) {
         // If this is a ```-style block, trim off the backticks.
         $text = preg_replace('/```\\s*$/', '', substr($text, 3));
     }
     $lines = explode("\n", $text);
     $options = array('counterexample' => false, 'lang' => null, 'name' => null, 'lines' => null);
     $custom = PhutilSimpleOptions::parse(head($lines));
     if ($custom) {
         $valid = true;
         foreach ($custom as $key => $value) {
             if (!array_key_exists($key, $options)) {
                 $valid = false;
                 break;
             }
         }
         if ($valid) {
             array_shift($lines);
             $options = $custom + $options;
         }
     }
     if ($options['counterexample']) {
         $aux_class = ' remarkup-counterexample';
     } else {
         $aux_class = null;
     }
     // Normalize the text back to a 0-level indent.
     $min_indent = 80;
     foreach ($lines as $line) {
         for ($ii = 0; $ii < strlen($line); $ii++) {
             if ($line[$ii] != ' ') {
                 $min_indent = min($ii, $min_indent);
                 break;
             }
         }
     }
     if ($min_indent) {
         $indent_string = str_repeat(' ', $min_indent);
         $text = preg_replace('/^' . $indent_string . '/m', '', implode("\n", $lines));
     } else {
         $text = implode("\n", $lines);
     }
     if (empty($options['lang'])) {
         // If the user hasn't specified "lang=..." explicitly, try to guess the
         // language. If we fail, fall back to configured defaults.
         $lang = PhutilLanguageGuesser::guessLanguage($text);
         if (!$lang) {
             $lang = nonempty($this->getEngine()->getConfig('phutil.codeblock.language-default'), 'php');
         }
         $options['lang'] = $lang;
     }
     $name_header = null;
     if ($options['name']) {
         $name_header = phutil_render_tag('div', array('class' => 'remarkup-code-header'), phutil_escape_html($options['name']));
     }
     $aux_style = null;
     if ($options['lines']) {
         // Put a minimum size on this because the scrollbar is otherwise
         // unusable.
         $height = max(6, (int) $options['lines']);
         $aux_style = 'max-height: ' . 2 * $height . 'em;';
     }
     $engine = $this->getEngine()->getConfig('syntax-highlighter.engine');
     if (!$engine) {
         $engine = 'PhutilDefaultSyntaxHighlighterEngine';
     }
     $engine = newv($engine, array());
     $engine->setConfig('pygments.enabled', $this->getEngine()->getConfig('pygments.enabled'));
     $code_body = phutil_render_tag('pre', array('class' => 'remarkup-code' . $aux_class, 'style' => $aux_style), $engine->highlightSource($options['lang'], $text));
     return phutil_render_tag('div', array('class' => 'remarkup-code-block', 'data-code-lang' => $options['lang']), $name_header . $code_body);
 }
 public function markupText($text)
 {
     if (preg_match('/^```/', $text)) {
         // If this is a ```-style block, trim off the backticks.
         $text = preg_replace('/```\\s*$/', '', substr($text, 3));
     }
     $lines = explode("\n", $text);
     $options = array('counterexample' => false, 'lang' => null, 'name' => null, 'lines' => null);
     $parser = new PhutilSimpleOptions();
     $custom = $parser->parse(head($lines));
     if ($custom) {
         $valid = true;
         foreach ($custom as $key => $value) {
             if (!array_key_exists($key, $options)) {
                 $valid = false;
                 break;
             }
         }
         if ($valid) {
             array_shift($lines);
             $options = $custom + $options;
         }
     }
     // Normalize the text back to a 0-level indent.
     $min_indent = 80;
     foreach ($lines as $line) {
         for ($ii = 0; $ii < strlen($line); $ii++) {
             if ($line[$ii] != ' ') {
                 $min_indent = min($ii, $min_indent);
                 break;
             }
         }
     }
     $text = implode("\n", $lines);
     if ($min_indent) {
         $indent_string = str_repeat(' ', $min_indent);
         $text = preg_replace('/^' . $indent_string . '/m', '', $text);
     }
     if ($this->getEngine()->isTextMode()) {
         $out = array();
         $header = array();
         if ($options['counterexample']) {
             $header[] = 'counterexample';
         }
         if ($options['name'] != '') {
             $header[] = 'name=' . $options['name'];
         }
         if ($header) {
             $out[] = implode(', ', $header);
         }
         $text = preg_replace('/^/m', '  ', $text);
         $text = preg_replace('/^\\s+$/m', '', $text);
         $out[] = $text;
         return implode("\n", $out);
     }
     if (empty($options['lang'])) {
         // If the user hasn't specified "lang=..." explicitly, try to guess the
         // language. If we fail, fall back to configured defaults.
         $lang = PhutilLanguageGuesser::guessLanguage($text);
         if (!$lang) {
             $lang = nonempty($this->getEngine()->getConfig('phutil.codeblock.language-default'), 'php');
         }
         $options['lang'] = $lang;
     }
     $code_body = $this->highlightSource($text, $options);
     $name_header = null;
     if ($options['name']) {
         $name_header = phutil_tag('div', array('class' => 'remarkup-code-header'), $options['name']);
     }
     return phutil_tag('div', array('class' => 'remarkup-code-block', 'data-code-lang' => $options['lang']), array($name_header, $code_body));
 }