@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 * API for replacing whitespace characters and some control characters with
5 * their printable representations. This is useful for debugging and
6 * displaying more helpful error messages to users.
7 *
8 */
9final class PHUIInvisibleCharacterView extends AphrontView {
10
11 private $inputText;
12 private $plainText = false;
13
14 // This is a list of the common invisible characters that are
15 // actually typeable. Other invisible characters will simply
16 // be displayed as their hex representations.
17 private static $invisibleChars = array(
18 "\x00" => 'NULL',
19 "\t" => 'TAB',
20 "\n" => 'NEWLINE',
21 "\x20" => 'SPACE',
22 );
23
24 public function __construct($input_text) {
25 $this->inputText = $input_text;
26 }
27
28 public function setPlainText($plain_text) {
29 $this->plainText = $plain_text;
30 return $this;
31 }
32
33 public function getStringParts() {
34 $input_text = $this->inputText;
35 $text_array = phutil_utf8v($input_text);
36
37 for ($ii = 0; $ii < count($text_array); $ii++) {
38 $char = $text_array[$ii];
39 $char_hex = bin2hex($char);
40 if (array_key_exists($char, self::$invisibleChars)) {
41 $text_array[$ii] = array(
42 'special' => true,
43 'value' => '<'.self::$invisibleChars[$char].'>',
44 );
45 } else if (ord($char) < 32) {
46 $text_array[$ii] = array(
47 'special' => true,
48 'value' => '<0x'.$char_hex.'>',
49 );
50 } else {
51 $text_array[$ii] = array(
52 'special' => false,
53 'value' => $char,
54 );
55 }
56 }
57 return $text_array;
58 }
59
60 private function renderHtmlArray() {
61 $html_array = array();
62 $parts = $this->getStringParts();
63 foreach ($parts as $part) {
64 if ($part['special']) {
65 $html_array[] = phutil_tag(
66 'span',
67 array('class' => 'invisible-special'),
68 $part['value']);
69 } else {
70 $html_array[] = $part['value'];
71 }
72 }
73 return $html_array;
74 }
75
76 private function renderPlainText() {
77 $parts = $this->getStringParts();
78 $res = '';
79 foreach ($parts as $part) {
80 $res .= $part['value'];
81 }
82 return $res;
83 }
84
85 public function render() {
86 require_celerity_resource('phui-invisible-character-view-css');
87 if ($this->plainText) {
88 return $this->renderPlainText();
89 } else {
90 return $this->renderHtmlArray();
91 }
92 }
93
94}