diff --git a/src/markup/engine/remarkup/blockrule/PhutilRemarkupCodeBlockRule.php b/src/markup/engine/remarkup/blockrule/PhutilRemarkupCodeBlockRule.php index d3904be..b8fef85 100644 --- a/src/markup/engine/remarkup/blockrule/PhutilRemarkupCodeBlockRule.php +++ b/src/markup/engine/remarkup/blockrule/PhutilRemarkupCodeBlockRule.php @@ -1,228 +1,252 @@ 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; + $block_style = null; if ($this->getEngine()->isHTMLMailMode()) { + $map = $this->getEngine()->getConfig('phutil.codeblock.style-map'); + + if ($map) { + $raw_body = id(new PhutilPygmentizeParser()) + ->setMap($map) + ->parse((string)$code_body); + $code_body = phutil_safe_html($raw_body); + } + + $style_rules = array( + 'padding: 6px 12px;', + 'font-size: 13px;', + 'font-weight: bold;', + 'display: inline-block;', + 'border-top-left-radius: 3px;', + 'border-top-right-radius: 3px;', + 'color: rgba(0,0,0,.75);', + ); + + if ($options['counterexample']) { + $style_rules[] = 'background: #f7e6e6'; + } else { + $style_rules[] = 'background: rgba(71, 87, 120, 0.08);'; + } + $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;', + 'style' => implode(' ', $style_rules), ); + + $block_style = 'margin: 12px 0;'; } 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', + 'class' => $class, + 'style' => $block_style, + 'data-code-lang' => $options['lang'], + 'data-sigil' => 'remarkup-code-block', ); return phutil_tag( 'div', $attributes, array($name_header, $code_body)); } private function highlightSource($text, array $options) { if ($options['counterexample']) { $aux_class = ' remarkup-counterexample'; } else { $aux_class = null; } $aux_style = null; if ($this->getEngine()->isHTMLMailMode()) { + $aux_style = array( + 'font: 11px/15px "Menlo", "Consolas", "Monaco", monospace;', + 'padding: 12px;', + 'margin: 0;', + ); + if ($options['counterexample']) { - $aux_style = 'border: 1px solid #c0392b; - background: #f4dddb; - font-size: 10x; - padding: 8px;'; + $aux_style[] = 'background: #f7e6e6;'; } else { - $aux_style = 'border: 1px solid #f1c40f; - background: #fdf5d4; - font-size: 10x; - padding: 8px;'; + $aux_style[] = 'background: rgba(71, 87, 120, 0.08);'; } + + $aux_style = implode(' ', $aux_style); } if ($options['lines']) { // Put a minimum size on this because the scrollbar is otherwise // unusable. $height = max(6, (int)$options['lines']); $aux_style = $aux_style .' ' .'max-height: ' .(2 * $height) .'em; overflow: auto;'; } $engine = $this->getEngine()->getConfig('syntax-highlighter.engine'); if (!$engine) { $engine = 'PhutilDefaultSyntaxHighlighterEngine'; } $engine = newv($engine, array()); $engine->setConfig( 'pygments.enabled', $this->getEngine()->getConfig('pygments.enabled')); return phutil_tag( 'pre', array( 'class' => 'remarkup-code'.$aux_class, 'style' => $aux_style, ), PhutilSafeHTML::applyFunction( 'rtrim', $engine->highlightSource($options['lang'], $text))); } }