Overview

Packages

  • Argv

Classes

  • Horde_Argv_AmbiguousOptionException
  • Horde_Argv_BadOptionException
  • Horde_Argv_Exception
  • Horde_Argv_HelpFormatter
  • Horde_Argv_IndentedHelpFormatter
  • Horde_Argv_Option
  • Horde_Argv_OptionConflictException
  • Horde_Argv_OptionContainer
  • Horde_Argv_OptionException
  • Horde_Argv_OptionGroup
  • Horde_Argv_OptionValueException
  • Horde_Argv_Parser
  • Horde_Argv_TitledHelpFormatter
  • Horde_Argv_Translation
  • Horde_Argv_Values
  • Overview
  • Package
  • Class
  • Tree
  1: <?php
  2: /**
  3:  * Provides HelpFormatter, used by Horde_Argv_Parser to generate formatted
  4:  * help text.
  5:  *
  6:  * This package is ported from Python's Optik (http://optik.sourceforge.net/).
  7:  *
  8:  * @author   Chuck Hagenbuch <chuck@horde.org>
  9:  * @author   Mike Naberezny <mike@maintainable.com>
 10:  * @license  http://www.horde.org/licenses/bsd BSD
 11:  * @category Horde
 12:  * @package  Argv
 13:  */
 14: 
 15: /**
 16:  * Abstract base class for formatting option help.  Horde_Argv_Parser
 17:  * instances should use one of the HelpFormatter subclasses for
 18:  * formatting help; by default IndentedHelpFormatter is used.
 19:  *
 20:  *  Instance attributes:
 21:  *    parser : Horde_Argv_Parser
 22:  *      the controlling Horde_Argv_Parser instance
 23:  *    indent_increment : int
 24:  *      the number of columns to indent per nesting level
 25:  *    max_help_position : int
 26:  *      the maximum starting column for option help text
 27:  *    help_position : int
 28:  *      the calculated starting column for option help text;
 29:  *      initially the same as the maximum
 30:  *    width : int
 31:  *      total number of columns for output (pass None to constructor for
 32:  *      this value to be taken from the $COLUMNS environment variable)
 33:  *    level : int
 34:  *      current indentation level
 35:  *    current_indent : int
 36:  *      current indentation level (in columns)
 37:  *    help_width : int
 38:  *      number of columns available for option help text (calculated)
 39:  *    default_tag : str
 40:  *      text to replace with each option's default value, "%default"
 41:  *      by default.  Set to false value to disable default value expansion.
 42:  *    option_strings : { Option : str }
 43:  *      maps Option instances to the snippet of help text explaining
 44:  *      the syntax of that option, e.g. "-h, --help" or
 45:  *      "-fFILE, --file=FILE"
 46:  *    _short_opt_fmt : str
 47:  *      format string controlling how short options with values are
 48:  *      printed in help text.  Must be either "%s%s" ("-fFILE") or
 49:  *      "%s %s" ("-f FILE"), because those are the two syntaxes that
 50:  *      Horde_Argv supports.
 51:  *    _long_opt_fmt : str
 52:  *      similar but for long options; must be either "%s %s" ("--file FILE")
 53:  *      or "%s=%s" ("--file=FILE").
 54:  *
 55:  * @category Horde
 56:  * @package  Argv
 57:  */
 58: abstract class Horde_Argv_HelpFormatter
 59: {
 60:     const NO_DEFAULT_VALUE = 'none';
 61: 
 62:     public $parser = null;
 63: 
 64:     public function __construct($indent_increment, $max_help_position,
 65:                                 $width = null, $short_first = false)
 66:     {
 67:         $this->indent_increment = $indent_increment;
 68:         $this->help_position = $this->max_help_position = $max_help_position;
 69:         if (is_null($width)) {
 70:             if (!empty($_ENV['COLUMNS'])) {
 71:                 $width = $_ENV['COLUMNS'];
 72:             } else {
 73:                 $width = 80;
 74:             }
 75:             $width -= 2;
 76:         }
 77:         $this->width = $width;
 78:         $this->current_indent = 0;
 79:         $this->level = 0;
 80:         $this->help_width = null; // computed later
 81:         $this->short_first = $short_first;
 82:         $this->default_tag = "%default";
 83:         $this->option_strings = array();
 84:         $this->_short_opt_fmt = "%s %s";
 85:         $this->_long_opt_fmt = "%s=%s";
 86:     }
 87: 
 88:     public function setParser($parser)
 89:     {
 90:         $this->parser = $parser;
 91:     }
 92: 
 93:     public function setShortOptDelimiter($delim)
 94:     {
 95:         if (!in_array($delim, array('', ' '))) {
 96:             throw new InvalidArgumentException('invalid metavar delimiter for short options: ' . $delim);
 97:         }
 98:         $this->_short_opt_fmt = "%s$delim%s";
 99:     }
100: 
101:     public function setLongOptDelimiter($delim)
102:     {
103:         if (!in_array($delim, array('=', ' '))) {
104:             throw new InvalidArgumentException('invalid metavar delimiter for long options: ' . $delim);
105:         }
106:         $this->_long_opt_fmt = "%s$delim%s";
107:     }
108: 
109:     public function indent()
110:     {
111:         $this->current_indent += $this->indent_increment;
112:         $this->level += 1;
113:     }
114: 
115:     public function dedent()
116:     {
117:         $this->current_indent -= $this->indent_increment;
118:         assert($this->current_indent >= 0); // Indent decreased below 0
119:         $this->level -= 1;
120:     }
121: 
122:     public abstract function formatUsage($usage);
123: 
124:     public abstract function formatHeading($heading);
125: 
126:     /**
127:      * Format a paragraph of free-form text for inclusion in the
128:      * help output at the current indentation level.
129:      */
130:     protected function _formatText($text)
131:     {
132:         $text_width = $this->width - $this->current_indent;
133:         $indent = str_repeat(' ', $this->current_indent);
134:         return wordwrap($indent . $text, $text_width, "\n" . $indent);
135:     }
136: 
137:     public function formatDescription($description)
138:     {
139:         if ($description) {
140:             return $this->_formatText($description) . "\n";
141:         } else {
142:             return '';
143:         }
144:     }
145: 
146:     public function formatEpilog($epilog)
147:     {
148:         if ($epilog) {
149:             return "\n" . $this->_formatText($epilog) . "\n";
150:         } else {
151:             return '';
152:         }
153:     }
154: 
155:     public function expandDefault($option)
156:     {
157:         if (is_null($this->parser) || !$this->default_tag) {
158:             return $option->help;
159:         }
160: 
161:         $default_value = isset($this->parser->defaults[$option->dest]) ? $this->parser->defaults[$option->dest] : null;
162:         if ($default_value == Horde_Argv_Option::$NO_DEFAULT || !$default_value) {
163:             $default_value = self::NO_DEFAULT_VALUE;
164:         }
165: 
166:         return str_replace($this->default_tag, (string)$default_value, $option->help);
167:     }
168: 
169:     /**
170:      * The help for each option consists of two parts:
171:      *   * the opt strings and metavars
172:      *     eg. ("-x", or "-fFILENAME, --file=FILENAME")
173:      *   * the user-supplied help string
174:      *     eg. ("turn on expert mode", "read data from FILENAME")
175:      *
176:      * If possible, we write both of these on the same line:
177:      *   -x      turn on expert mode
178:      *
179:      * But if the opt string list is too long, we put the help
180:      * string on a second line, indented to the same column it would
181:      * start in if it fit on the first line.
182:      *   -fFILENAME, --file=FILENAME
183:      *           read data from FILENAME
184:      */
185:     public function formatOption($option)
186:     {
187:         $result = array();
188:         $opts = isset($this->option_strings[(string)$option]) ? $this->option_strings[(string)$option] : null;
189:         $opt_width = $this->help_position - $this->current_indent - 2;
190:         if (strlen($opts) > $opt_width) {
191:             $opts = sprintf('%' . $this->current_indent . "s%s\n", "", $opts);
192:             $indent_first = $this->help_position;
193:         } else {
194:             // start help on same line as opts
195:             $opts = sprintf("%" . $this->current_indent . "s%-" . $opt_width . "s  ", "", $opts);
196:             $indent_first = 0;
197:         }
198:         $result[] = $opts;
199:         if ($option->help) {
200:             $help_text = $this->expandDefault($option);
201:             $help_lines = explode("\n", wordwrap($help_text, $this->help_width));
202:             $result[] = sprintf("%" . $indent_first . "s%s\n", '', $help_lines[0]);
203:             for ($i = 1, $i_max = count($help_lines); $i < $i_max; $i++) {
204:                 $result[] = sprintf("%" . $this->help_position . "s%s\n", "", $help_lines[$i]);
205:             }
206:         } elseif (substr($opts, -1) != "\n") {
207:             $result[] = "\n";
208:         }
209:         return implode('', $result);
210:     }
211: 
212:     public function storeOptionStrings($parser)
213:     {
214:         $this->indent();
215:         $max_len = 0;
216:         foreach ($parser->optionList as $opt) {
217:             $strings = $this->formatOptionStrings($opt);
218:             $this->option_strings[(string)$opt] = $strings;
219:             $max_len = max($max_len, strlen($strings) + $this->current_indent);
220:         }
221:         $this->indent();
222:         foreach ($parser->optionGroups as $group) {
223:             foreach ($group->optionList as $opt) {
224:                 $strings = $this->formatOptionStrings($opt);
225:                 $this->option_strings[(string)$opt] = $strings;
226:                 $max_len = max($max_len, strlen($strings) + $this->current_indent);
227:             }
228:         }
229:         $this->dedent();
230:         $this->dedent();
231:         $this->help_position = min($max_len + 2, $this->max_help_position);
232:         $this->help_width = $this->width - $this->help_position;
233:     }
234: 
235:     /**
236:      * Return a comma-separated list of option strings & metavariables.
237:      */
238:     public function formatOptionStrings($option)
239:     {
240:         if ($option->takesValue()) {
241:             $metavar = $option->metavar ? $option->metavar : strtoupper($option->dest);
242:             $short_opts = array();
243:             foreach ($option->shortOpts as $sopt) {
244:                 $short_opts[] = sprintf($this->_short_opt_fmt, $sopt, $metavar);
245:             }
246:             $long_opts = array();
247:             foreach ($option->longOpts as $lopt) {
248:                 $long_opts[] = sprintf($this->_long_opt_fmt, $lopt, $metavar);
249:             }
250:         } else {
251:             $short_opts = $option->shortOpts;
252:             $long_opts = $option->longOpts;
253:         }
254: 
255:         if ($this->short_first) {
256:             $opts = array_merge($short_opts, $long_opts);
257:         } else {
258:             $opts = array_merge($long_opts, $short_opts);
259:         }
260: 
261:         return implode(', ', $opts);
262:     }
263: 
264: }
265: 
API documentation generated by ApiGen