Shell.php 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. <?php
  2. namespace Symfony\Components\Console;
  3. use Symfony\Components\Console\Application;
  4. use Symfony\Components\Console\Input\StringInput;
  5. use Symfony\Components\Console\Output\ConsoleOutput;
  6. /*
  7. * This file is part of the symfony framework.
  8. *
  9. * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
  10. *
  11. * This source file is subject to the MIT license that is bundled
  12. * with this source code in the file LICENSE.
  13. */
  14. /**
  15. * A Shell wraps an Application to add shell capabilities to it.
  16. *
  17. * This class only works with a PHP compiled with readline support
  18. * (either --with-readline or --with-libedit)
  19. *
  20. * @package symfony
  21. * @subpackage cli
  22. * @author Fabien Potencier <fabien.potencier@symfony-project.com>
  23. */
  24. class Shell
  25. {
  26. protected $application;
  27. protected $history;
  28. protected $output;
  29. /**
  30. * Constructor.
  31. *
  32. * If there is no readline support for the current PHP executable
  33. * a \RuntimeException exception is thrown.
  34. *
  35. * @param Application $application An application instance
  36. */
  37. public function __construct(Application $application)
  38. {
  39. if (!function_exists('readline'))
  40. {
  41. throw new \RuntimeException('Unable to start the shell as the Readline extension is not enabled.');
  42. }
  43. $this->application = $application;
  44. $this->history = getenv('HOME').'/.history_'.$application->getName();
  45. $this->output = new ConsoleOutput();
  46. }
  47. /**
  48. * Runs the shell.
  49. */
  50. public function run()
  51. {
  52. $this->application->setAutoExit(false);
  53. $this->application->setCatchExceptions(true);
  54. readline_read_history($this->history);
  55. readline_completion_function(array($this, 'autocompleter'));
  56. $this->output->write($this->getHeader());
  57. while (true)
  58. {
  59. $command = readline($this->application->getName().' > ');
  60. if (false === $command)
  61. {
  62. $this->output->write("\n");
  63. break;
  64. }
  65. readline_add_history($command);
  66. readline_write_history($this->history);
  67. if (0 !== $ret = $this->application->run(new StringInput($command), $this->output))
  68. {
  69. $this->output->write(sprintf('<error>The command terminated with an error status (%s)</error>', $ret));
  70. }
  71. }
  72. }
  73. /**
  74. * Tries to return autocompletion for the current entered text.
  75. *
  76. * @param string $text The last segment of the entered text
  77. * @param integer $position The current position
  78. */
  79. protected function autocompleter($text, $position)
  80. {
  81. $info = readline_info();
  82. $text = substr($info['line_buffer'], 0, $info['end']);
  83. if ($info['point'] !== $info['end'])
  84. {
  85. return true;
  86. }
  87. // task name?
  88. if (false === strpos($text, ' ') || !$text)
  89. {
  90. return array_keys($this->application->getCommands());
  91. }
  92. // options and arguments?
  93. try
  94. {
  95. $command = $this->application->findCommand(substr($text, 0, strpos($text, ' ')));
  96. }
  97. catch (\Exception $e)
  98. {
  99. return true;
  100. }
  101. $list = array('--help');
  102. foreach ($command->getDefinition()->getOptions() as $option)
  103. {
  104. $list[] = '--'.$option->getName();
  105. }
  106. return $list;
  107. }
  108. /**
  109. * Returns the shell header.
  110. *
  111. * @return string The header string
  112. */
  113. protected function getHeader()
  114. {
  115. return <<<EOF
  116. Welcome to the <info>{$this->application->getName()}</info> shell.
  117. At the prompt, type <comment>help</comment> for some help,
  118. or <comment>list</comment> to get a list available commands.
  119. To exist the shell, type <comment>^D</comment>.
  120. EOF;
  121. }
  122. }