@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.)
hq.recaptime.dev/wiki/Phorge
phorge
phabricator
1<?php
2
3/**
4 * Parser that converts `pygmetize` output or similar HTML blocks from "class"
5 * attributes to "style" attributes.
6 */
7final class PhutilPygmentizeParser extends Phobject {
8
9 private $map = array();
10
11 public function setMap(array $map) {
12 $this->map = $map;
13 return $this;
14 }
15
16 public function getMap() {
17 return $this->map;
18 }
19
20 public function parse($block) {
21 $class_look = 'class="';
22 $class_len = strlen($class_look);
23
24 $class_start = null;
25
26 $map = $this->map;
27
28 $len = strlen($block);
29 $out = '';
30 $mode = 'text';
31 for ($ii = 0; $ii < $len; $ii++) {
32 $c = $block[$ii];
33 switch ($mode) {
34 case 'text':
35 // We're in general text between tags, and just passing characters
36 // through unmodified.
37 if ($c == '<') {
38 $mode = 'tag';
39 }
40 $out .= $c;
41 break;
42 case 'tag':
43 // We're inside a tag, and looking for `class="` so we can rewrite
44 // it.
45 if ($c == '>') {
46 $mode = 'text';
47 }
48 if ($c == 'c') {
49 if (!substr_compare($block, $class_look, $ii, $class_len)) {
50 $mode = 'class';
51 $ii += $class_len;
52 $class_start = $ii;
53 }
54 }
55
56 if ($mode != 'class') {
57 $out .= $c;
58 }
59 break;
60 case 'class':
61 // We're inside a `class="..."` tag, and looking for the ending quote
62 // so we can replace it.
63 if ($c == '"') {
64 $class = substr($block, $class_start, $ii - $class_start);
65
66 // If this class is present in the map, rewrite it into an inline
67 // style attribute.
68 if (isset($map[$class])) {
69 $out .= 'style="'.phutil_escape_html($map[$class]).'"';
70 } else {
71 $out .= 'class="'.$class.'"';
72 }
73
74 $mode = 'tag';
75 }
76 break;
77 }
78 }
79
80 return $out;
81 }
82
83}