annotate vendor/psy/psysh/src/Psy/Formatter/DocblockFormatter.php @ 0:4c8ae668cc8c

Initial import (non-working)
author Chris Cannam
date Wed, 29 Nov 2017 16:09:58 +0000
parents
children
rev   line source
Chris@0 1 <?php
Chris@0 2
Chris@0 3 /*
Chris@0 4 * This file is part of Psy Shell.
Chris@0 5 *
Chris@0 6 * (c) 2012-2017 Justin Hileman
Chris@0 7 *
Chris@0 8 * For the full copyright and license information, please view the LICENSE
Chris@0 9 * file that was distributed with this source code.
Chris@0 10 */
Chris@0 11
Chris@0 12 namespace Psy\Formatter;
Chris@0 13
Chris@0 14 use Psy\Util\Docblock;
Chris@0 15 use Symfony\Component\Console\Formatter\OutputFormatter;
Chris@0 16
Chris@0 17 /**
Chris@0 18 * A pretty-printer for docblocks.
Chris@0 19 */
Chris@0 20 class DocblockFormatter implements Formatter
Chris@0 21 {
Chris@0 22 private static $vectorParamTemplates = array(
Chris@0 23 'type' => 'info',
Chris@0 24 'var' => 'strong',
Chris@0 25 );
Chris@0 26
Chris@0 27 /**
Chris@0 28 * Format a docblock.
Chris@0 29 *
Chris@0 30 * @param \Reflector $reflector
Chris@0 31 *
Chris@0 32 * @return string Formatted docblock
Chris@0 33 */
Chris@0 34 public static function format(\Reflector $reflector)
Chris@0 35 {
Chris@0 36 $docblock = new Docblock($reflector);
Chris@0 37 $chunks = array();
Chris@0 38
Chris@0 39 if (!empty($docblock->desc)) {
Chris@0 40 $chunks[] = '<comment>Description:</comment>';
Chris@0 41 $chunks[] = self::indent(OutputFormatter::escape($docblock->desc), ' ');
Chris@0 42 $chunks[] = '';
Chris@0 43 }
Chris@0 44
Chris@0 45 if (!empty($docblock->tags)) {
Chris@0 46 foreach ($docblock::$vectors as $name => $vector) {
Chris@0 47 if (isset($docblock->tags[$name])) {
Chris@0 48 $chunks[] = sprintf('<comment>%s:</comment>', self::inflect($name));
Chris@0 49 $chunks[] = self::formatVector($vector, $docblock->tags[$name]);
Chris@0 50 $chunks[] = '';
Chris@0 51 }
Chris@0 52 }
Chris@0 53
Chris@0 54 $tags = self::formatTags(array_keys($docblock::$vectors), $docblock->tags);
Chris@0 55 if (!empty($tags)) {
Chris@0 56 $chunks[] = $tags;
Chris@0 57 $chunks[] = '';
Chris@0 58 }
Chris@0 59 }
Chris@0 60
Chris@0 61 return rtrim(implode("\n", $chunks));
Chris@0 62 }
Chris@0 63
Chris@0 64 /**
Chris@0 65 * Format a docblock vector, for example, `@throws`, `@param`, or `@return`.
Chris@0 66 *
Chris@0 67 * @see DocBlock::$vectors
Chris@0 68 *
Chris@0 69 * @param array $vector
Chris@0 70 * @param array $lines
Chris@0 71 *
Chris@0 72 * @return string
Chris@0 73 */
Chris@0 74 private static function formatVector(array $vector, array $lines)
Chris@0 75 {
Chris@0 76 $template = array(' ');
Chris@0 77 foreach ($vector as $type) {
Chris@0 78 $max = 0;
Chris@0 79 foreach ($lines as $line) {
Chris@0 80 $chunk = $line[$type];
Chris@0 81 $cur = empty($chunk) ? 0 : strlen($chunk) + 1;
Chris@0 82 if ($cur > $max) {
Chris@0 83 $max = $cur;
Chris@0 84 }
Chris@0 85 }
Chris@0 86
Chris@0 87 $template[] = self::getVectorParamTemplate($type, $max);
Chris@0 88 }
Chris@0 89 $template = implode(' ', $template);
Chris@0 90
Chris@0 91 return implode("\n", array_map(function ($line) use ($template) {
Chris@0 92 $escaped = array_map(array('Symfony\Component\Console\Formatter\OutputFormatter', 'escape'), $line);
Chris@0 93
Chris@0 94 return rtrim(vsprintf($template, $escaped));
Chris@0 95 }, $lines));
Chris@0 96 }
Chris@0 97
Chris@0 98 /**
Chris@0 99 * Format docblock tags.
Chris@0 100 *
Chris@0 101 * @param array $skip Tags to exclude
Chris@0 102 * @param array $tags Tags to format
Chris@0 103 *
Chris@0 104 * @return string formatted tags
Chris@0 105 */
Chris@0 106 private static function formatTags(array $skip, array $tags)
Chris@0 107 {
Chris@0 108 $chunks = array();
Chris@0 109
Chris@0 110 foreach ($tags as $name => $values) {
Chris@0 111 if (in_array($name, $skip)) {
Chris@0 112 continue;
Chris@0 113 }
Chris@0 114
Chris@0 115 foreach ($values as $value) {
Chris@0 116 $chunks[] = sprintf('<comment>%s%s</comment> %s', self::inflect($name), empty($value) ? '' : ':', OutputFormatter::escape($value));
Chris@0 117 }
Chris@0 118
Chris@0 119 $chunks[] = '';
Chris@0 120 }
Chris@0 121
Chris@0 122 return implode("\n", $chunks);
Chris@0 123 }
Chris@0 124
Chris@0 125 /**
Chris@0 126 * Get a docblock vector template.
Chris@0 127 *
Chris@0 128 * @param string $type Vector type
Chris@0 129 * @param int $max Pad width
Chris@0 130 *
Chris@0 131 * @return string
Chris@0 132 */
Chris@0 133 private static function getVectorParamTemplate($type, $max)
Chris@0 134 {
Chris@0 135 if (!isset(self::$vectorParamTemplates[$type])) {
Chris@0 136 return sprintf('%%-%ds', $max);
Chris@0 137 }
Chris@0 138
Chris@0 139 return sprintf('<%s>%%-%ds</%s>', self::$vectorParamTemplates[$type], $max, self::$vectorParamTemplates[$type]);
Chris@0 140 }
Chris@0 141
Chris@0 142 /**
Chris@0 143 * Indent a string.
Chris@0 144 *
Chris@0 145 * @param string $text String to indent
Chris@0 146 * @param string $indent (default: ' ')
Chris@0 147 *
Chris@0 148 * @return string
Chris@0 149 */
Chris@0 150 private static function indent($text, $indent = ' ')
Chris@0 151 {
Chris@0 152 return $indent . str_replace("\n", "\n" . $indent, $text);
Chris@0 153 }
Chris@0 154
Chris@0 155 /**
Chris@0 156 * Convert underscored or whitespace separated words into sentence case.
Chris@0 157 *
Chris@0 158 * @param string $text
Chris@0 159 *
Chris@0 160 * @return string
Chris@0 161 */
Chris@0 162 private static function inflect($text)
Chris@0 163 {
Chris@0 164 $words = trim(preg_replace('/[\s_-]+/', ' ', preg_replace('/([a-z])([A-Z])/', '$1 $2', $text)));
Chris@0 165
Chris@0 166 return implode(' ', array_map('ucfirst', explode(' ', $words)));
Chris@0 167 }
Chris@0 168 }