Page MenuHomePhabricator

D15845.id38182.diff
No OneTemporary

D15845.id38182.diff

diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -295,6 +295,8 @@
'PhutilProtocolChannel' => 'channel/PhutilProtocolChannel.php',
'PhutilProxyException' => 'error/PhutilProxyException.php',
'PhutilProxyIterator' => 'utils/PhutilProxyIterator.php',
+ 'PhutilPygmentizeParser' => 'parser/PhutilPygmentizeParser.php',
+ 'PhutilPygmentizeParserTestCase' => 'parser/__tests__/PhutilPygmentizeParserTestCase.php',
'PhutilPygmentsSyntaxHighlighter' => 'markup/syntax/highlighter/PhutilPygmentsSyntaxHighlighter.php',
'PhutilPythonFragmentLexer' => 'lexer/PhutilPythonFragmentLexer.php',
'PhutilQsprintfInterface' => 'xsprintf/PhutilQsprintfInterface.php',
@@ -850,6 +852,8 @@
'Phobject',
'Iterator',
),
+ 'PhutilPygmentizeParser' => 'Phobject',
+ 'PhutilPygmentizeParserTestCase' => 'PhutilTestCase',
'PhutilPygmentsSyntaxHighlighter' => 'Phobject',
'PhutilPythonFragmentLexer' => 'PhutilLexer',
'PhutilQueryStringParser' => 'Phobject',
diff --git a/src/parser/PhutilPygmentizeParser.php b/src/parser/PhutilPygmentizeParser.php
new file mode 100644
--- /dev/null
+++ b/src/parser/PhutilPygmentizeParser.php
@@ -0,0 +1,83 @@
+<?php
+
+/**
+ * Parser that converts `pygmetize` output or similar HTML blocks from "class"
+ * attributes to "style" attributes.
+ */
+final class PhutilPygmentizeParser extends Phobject {
+
+ private $map = array();
+
+ public function setMap(array $map) {
+ $this->map = $map;
+ return $this;
+ }
+
+ public function getMap() {
+ return $this->map;
+ }
+
+ public function parse($block) {
+ $class_look = 'class="';
+ $class_len = strlen($class_look);
+
+ $class_start = null;
+
+ $map = $this->map;
+
+ $len = strlen($block);
+ $out = '';
+ $mode = 'text';
+ for ($ii = 0; $ii < $len; $ii++) {
+ $c = $block[$ii];
+ switch ($mode) {
+ case 'text':
+ // We're in general text between tags, and just passing characers
+ // through unmodified.
+ if ($c == '<') {
+ $mode = 'tag';
+ }
+ $out .= $c;
+ break;
+ case 'tag':
+ // We're inside a tag, and looking for `class="` so we can rewrite
+ // it.
+ if ($c == '>') {
+ $mode = 'text';
+ }
+ if ($c == 'c') {
+ if (!substr_compare($block, $class_look, $ii, $class_len)) {
+ $mode = 'class';
+ $ii += $class_len;
+ $class_start = $ii;
+ }
+ }
+
+ if ($mode != 'class') {
+ $out .= $c;
+ }
+ break;
+ case 'class':
+ // We're inside a `class="..."` tag, and looking for the ending quote
+ // so we can replace it.
+ if ($c == '"') {
+ $class = substr($block, $class_start, $ii - $class_start);
+
+ // If this class is present in the map, rewrite it into an inline
+ // style attribute.
+ if (isset($map[$class])) {
+ $out .= 'style="'.phutil_escape_html($map[$class]).'"';
+ } else {
+ $out .= 'class="'.$class.'"';
+ }
+
+ $mode = 'tag';
+ }
+ break;
+ }
+ }
+
+ return $out;
+ }
+
+}
diff --git a/src/parser/__tests__/PhutilPygmentizeParserTestCase.php b/src/parser/__tests__/PhutilPygmentizeParserTestCase.php
new file mode 100644
--- /dev/null
+++ b/src/parser/__tests__/PhutilPygmentizeParserTestCase.php
@@ -0,0 +1,43 @@
+<?php
+
+final class PhutilPygmentizeParserTestCase extends PhutilTestCase {
+
+ public function testPygmentizeParser() {
+ $this->tryParser(
+ '',
+ '',
+ array(),
+ pht('Empty'));
+
+ $this->tryParser(
+ '<span class="mi">1</span>',
+ '<span style="color: #ff0000">1</span>',
+ array(
+ 'mi' => 'color: #ff0000',
+ ),
+ pht('Simple'));
+
+ $this->tryParser(
+ '<span class="mi">1</span>',
+ '<span class="mi">1</span>',
+ array(),
+ pht('Missing Class'));
+
+ $this->tryParser(
+ '<span data-symbol-name="X" class="nc">X</span>',
+ '<span data-symbol-name="X" style="color: #ff0000">X</span>',
+ array(
+ 'nc' => 'color: #ff0000',
+ ),
+ pht('Extra Attribute'));
+ }
+
+ private function tryParser($input, $expect, array $map, $label) {
+ $actual = id(new PhutilPygmentizeParser())
+ ->setMap($map)
+ ->parse($input);
+
+ $this->assertEqual($expect, $actual, pht('Pygmentize Parser: %s', $label));
+ }
+
+}

File Metadata

Mime Type
text/plain
Expires
Wed, Mar 19, 2:39 AM (1 w, 5 h ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7710697
Default Alt Text
D15845.id38182.diff (4 KB)

Event Timeline