Page MenuHomePhabricator

D16541.id39808.diff
No OneTemporary

D16541.id39808.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
@@ -1652,6 +1652,8 @@
'PHUIInfoPanelExample' => 'applications/uiexample/examples/PHUIInfoPanelExample.php',
'PHUIInfoPanelView' => 'view/phui/PHUIInfoPanelView.php',
'PHUIInfoView' => 'view/form/PHUIInfoView.php',
+ 'PHUIInvisibleCharacterTestCase' => 'view/phui/__tests__/PHUIInvisibleCharacterTestCase.php',
+ 'PHUIInvisibleCharacterView' => 'view/phui/PHUIInvisibleCharacterView.php',
'PHUIListExample' => 'applications/uiexample/examples/PHUIListExample.php',
'PHUIListItemView' => 'view/phui/PHUIListItemView.php',
'PHUIListView' => 'view/phui/PHUIListView.php',
@@ -6319,6 +6321,8 @@
'PHUIInfoPanelExample' => 'PhabricatorUIExample',
'PHUIInfoPanelView' => 'AphrontView',
'PHUIInfoView' => 'AphrontView',
+ 'PHUIInvisibleCharacterTestCase' => 'PhabricatorTestCase',
+ 'PHUIInvisibleCharacterView' => 'AphrontView',
'PHUIListExample' => 'PhabricatorUIExample',
'PHUIListItemView' => 'AphrontTagView',
'PHUIListView' => 'AphrontTagView',
diff --git a/src/view/phui/PHUIInvisibleCharacterView.php b/src/view/phui/PHUIInvisibleCharacterView.php
new file mode 100644
--- /dev/null
+++ b/src/view/phui/PHUIInvisibleCharacterView.php
@@ -0,0 +1,75 @@
+<?php
+
+/**
+ * API for replacing whitespace characters and some control characters with
+ * their printable representations. This is useful for debugging and
+ * displaying more helpful error messages to users.
+ *
+ */
+final class PHUIInvisibleCharacterView extends AphrontView {
+
+ private $inputText;
+ private $plainText = false;
+
+ // This is a list of the common invisible characters that are
+ // actually typeable. Other invisible characters will simply
+ // be displayed as their hex representations.
+ private static $invisibleChars = array(
+ "\x00" => 'NULL',
+ "\t" => 'TAB',
+ "\n" => 'NEWLINE',
+ "\x20" => 'SPACE',
+ );
+
+ public function __construct($input_text, $plain_text = false) {
+ $this->inputText = $input_text;
+ $this->plainText = $plain_text;
+ }
+
+ private function renderHtmlArray() {
+ $input_text = $this->inputText;
+ $text_array = phutil_utf8v($input_text);
+
+ for ($ii = 0; $ii < count($text_array); $ii++) {
+ $char = $text_array[$ii];
+ $char_hex = bin2hex($char);
+ if (array_key_exists($char, self::$invisibleChars)) {
+ $text_array[$ii] = phutil_tag(
+ 'span',
+ array('class' => 'invisible-special'),
+ '<'.self::$invisibleChars[$char].'>');
+ } else if (ord($char) < 32) {
+ $text_array[$ii] = phutil_tag(
+ 'span',
+ array('class' => 'invisible-special'),
+ '<0x'.$char_hex.'>');
+ }
+ }
+ return $text_array;
+ }
+
+ private function renderPlainText() {
+ $input_text = $this->inputText;
+ $text_array = phutil_utf8v($input_text);
+
+ for ($ii = 0; $ii < count($text_array); $ii++) {
+ $char = $text_array[$ii];
+ $char_hex = bin2hex($char);
+ if (array_key_exists($char, self::$invisibleChars)) {
+ $text_array[$ii] = '<'.self::$invisibleChars[$char].'>';
+ } else if (ord($char) < 32) {
+ $text_array[$ii] = '<0x'.$char_hex.'>';
+ }
+ }
+ return implode($text_array);
+ }
+
+ public function render() {
+ if ($this->plainText) {
+ return $this->renderPlainText();
+ } else {
+ return $this->renderHtmlArray();
+ }
+ }
+
+}
diff --git a/src/view/phui/__tests__/PHUIInvisibleCharacterTestCase.php b/src/view/phui/__tests__/PHUIInvisibleCharacterTestCase.php
new file mode 100644
--- /dev/null
+++ b/src/view/phui/__tests__/PHUIInvisibleCharacterTestCase.php
@@ -0,0 +1,100 @@
+<?php
+
+final class PHUIInvisibleCharacterTestCase extends PhabricatorTestCase {
+
+ public function testEmptyString() {
+ $view = new PHUIInvisibleCharacterView('');
+ $res = $view->render();
+ $this->assertEqual($res, array());
+ }
+
+ public function testEmptyPlainText() {
+ $view = new PHUIInvisibleCharacterView('', true);
+ $res = $view->render();
+ $this->assertEqual($res, '');
+ }
+
+ public function testHtmlWithNamedChars() {
+ $test_input = "\x00\n\t ";
+ $view = new PHUIInvisibleCharacterView($test_input);
+ $res = $view->render();
+ $this->assertEqual($res[0]->getHtmlContent(), $this->getNullHtml());
+ $this->assertEqual($res[1]->getHtmlContent(), $this->getNewlineHtml());
+ $this->assertEqual($res[2]->getHtmlContent(), $this->getTabHtml());
+ $this->assertEqual($res[3]->getHtmlContent(), $this->getSpaceHtml());
+ }
+
+ public function testPlainWithNamedChars() {
+ $test_input = "\x00\n\t ";
+ $view = new PHUIInvisibleCharacterView($test_input, true);
+ $res = $view->render();
+ $this->assertEqual($res, '<NULL><NEWLINE><TAB><SPACE>');
+ }
+
+ public function testHtmlWithHexChars() {
+ $test_input = "abc\x01";
+ $view = new PHUIInvisibleCharacterView($test_input);
+ $res = $view->render();
+ $this->assertEqual($res[3]->getHtmlContent(), $this->getHexHtml());
+ }
+
+ public function testPlainWithHexChars() {
+ $test_input = "abc\x01";
+ $view = new PHUIInvisibleCharacterView($test_input, true);
+ $res = $view->render();
+ $this->assertEqual($res, 'abc<0x01>');
+ }
+
+ public function testHTMLWithNamedAsHex() {
+ $test_input = "\x00\x0a\x09\x20";
+ $view = new PHUIInvisibleCharacterView($test_input);
+ $res = $view->render();
+ $this->assertEqual($res[0]->getHtmlContent(), $this->getNullHtml());
+ $this->assertEqual($res[1]->getHtmlContent(), $this->getNewlineHtml());
+ $this->assertEqual($res[2]->getHtmlContent(), $this->getTabHtml());
+ $this->assertEqual($res[3]->getHtmlContent(), $this->getSpaceHtml());
+ }
+
+ public function testPlainWithNamedAsHex() {
+ $test_input = "\x00\x0a\x09\x20";
+ $view = new PHUIInvisibleCharacterView($test_input, true);
+ $res = $view->render();
+ $this->assertEqual($res, '<NULL><NEWLINE><TAB><SPACE>');
+ }
+
+ private function getNullHtml() {
+ return phutil_tag(
+ 'span',
+ array('class' => 'invisible-special'),
+ '<NULL>')
+ ->getHtmlContent();
+ }
+ private function getTabHtml() {
+ return phutil_tag(
+ 'span',
+ array('class' => 'invisible-special'),
+ '<TAB>')
+ ->getHtmlContent();
+ }
+ private function getNewlineHtml() {
+ return phutil_tag(
+ 'span',
+ array('class' => 'invisible-special'),
+ '<NEWLINE>')
+ ->getHtmlContent();
+ }
+ private function getSpaceHtml() {
+ return phutil_tag(
+ 'span',
+ array('class' => 'invisible-special'),
+ '<SPACE>')
+ ->getHtmlContent();
+ }
+ private function getHexHtml() {
+ return phutil_tag(
+ 'span',
+ array('class' => 'invisible-special'),
+ '<0x01>')
+ ->getHtmlContent();
+ }
+}

File Metadata

Mime Type
text/plain
Expires
Sat, Jan 25, 4:15 PM (16 h, 15 m)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7051614
Default Alt Text
D16541.id39808.diff (6 KB)

Event Timeline