Skip to content

Commit

Permalink
feat: support start an interactive shell for run application
Browse files Browse the repository at this point in the history
  • Loading branch information
inhere committed Jan 23, 2021
1 parent 9d9aeca commit 4187376
Show file tree
Hide file tree
Showing 8 changed files with 160 additions and 17 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,10 @@ Provide console parameter parsing, command run, color style output, user informa
- Commonly used special format information display (`section`, `panel`, `padding`, `helpPanel`, `table`, `tree`, `title`, `list`, `multiList`)
- Rich dynamic information display (`pending/loading`, `pointing`, `spinner`, `counterTxt`, `dynamicText`, `progressTxt`, `progressBar`)
- Common user information interaction support (`select`, `multiSelect`, `confirm`, `ask/question`, `askPassword/askHiddenInput`)
- Support for predefined parameter definitions like `symfony/console` (giving parameter values ​​by position, recommended when strict parameter restrictions are required)
- Support for predefined parameter definitions like `symfony/console` (giving parameter values by position, recommended when strict parameter restrictions are required)
- The color output is `windows` `linux` `mac` compatible. Environments that do not support color will automatically remove the relevant CODE.
- Quickly generate auto-completion scripts for the current application in the `bash/zsh` environment
- NEW: Support start an interactive shell for run application

### Built-in tools

Expand Down
65 changes: 62 additions & 3 deletions src/AbstractApplication.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,14 @@
use Inhere\Console\Concern\ApplicationHelpTrait;
use Inhere\Console\Concern\InputOutputAwareTrait;
use Inhere\Console\Concern\SimpleEventAwareTrait;
use Inhere\Console\Util\Interact;
use InvalidArgumentException;
use Throwable;
use Toolkit\Cli\Style;
use Toolkit\Cli\Util\LineParser;
use Toolkit\Stdlib\Helper\PhpHelper;
use Toolkit\Sys\Proc\ProcessUtil;
use Toolkit\Sys\Proc\Signal;
use function array_keys;
use function array_merge;
use function error_get_last;
Expand Down Expand Up @@ -59,7 +63,8 @@ abstract class AbstractApplication implements ApplicationInterface

/** @var array */
protected static $globalOptions = [
'--debug' => 'Setting the application runtime debug level(0 - 4)',
'--debug' => 'Setting the runtime log debug level(quiet 0 - 5 crazy)',
'--ishell' => 'Run application an interactive shell environment',
'--profile' => 'Display timing and memory usage information',
'--no-color' => 'Disable color/ANSI for message output',
'-h, --help' => 'Display this help message',
Expand Down Expand Up @@ -356,16 +361,21 @@ public function handleException($e): void
protected function filterSpecialCommand(string $command): bool
{
if (!$command) {
if ($this->input->getSameOpt(['V', 'version'])) {
if ($this->input->getSameBoolOpt(GlobalOption::VERSION_OPTS)) {
$this->showVersionInfo();
return true;
}

if ($this->input->getSameOpt(['h', 'help'])) {
if ($this->input->getSameBoolOpt(GlobalOption::HELP_OPTS)) {
$this->showHelpInfo();
return true;
}

if ($this->input->getBoolOpt(GlobalOption::ISHELL)) {
$this->startInteractiveShell();
return true;
}

// default run list command
// $command = $this->defaultCommand ? 'list';
$command = 'list';
Expand All @@ -390,6 +400,55 @@ protected function filterSpecialCommand(string $command): bool
return true;
}

/**********************************************************
* start interactive shell
**********************************************************/

/**
* start an interactive shell run
*/
protected function startInteractiveShell(): void
{
$in = $this->input;
$out = $this->output;

$out->colored("Will start interactive shell for run application");

if (!($hasPcntl = ProcessUtil::hasPcntl())) {
$this->debugf('php is not enable "pcntl" extension, cannot listen CTRL+C signal');
}

if ($hasPcntl) {
// register signal.
ProcessUtil::installSignal(Signal::INT, static function () use ($out) {
$out->colored("\nQuit by CTRL+C");
exit(0);
});
}

while (true) {
$line = Interact::readln('<comment>CMD ></comment> ');
if ($line === 'exit' || $line === 'quit') {
break;
}

if ($hasPcntl) {
// listen signal.
ProcessUtil::dispatchSignal();
}

$args = LineParser::parseIt($line);

// reload and parse args
$in->parse($args);

// \vdump($in);
$this->run(false);
}

$out->colored("\nQuit. ByeBye!");
}

/**
* @param string $name
* @param string|array $aliases
Expand Down
30 changes: 21 additions & 9 deletions src/Concern/ApplicationHelpTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -99,17 +99,29 @@ public function showHelpInfo(string $command = ''): void
$delimiter = $this->delimiter;
$binName = $in->getScriptName();

// built in options
$globalOptions = FormatUtil::alignOptions(self::$globalOptions);

/** @var Output $out */
$out = $this->output;
$out->helpPanel([
'usage' => "$binName <info>{command}</info> [--opt -v -h ...] [arg0 arg1 arg2=value2 ...]",
'example' => [
"$binName test (run a independent command)",
"$binName home{$delimiter}index (run a command of the group)",
"$binName help {command} (see a command help information)",
"$binName home{$delimiter}index -h (see a command help of the group)",
"$binName --auto-completion --shell-env [zsh|bash] [--gen-file stdout]",
]
'Usage' => "$binName <info>{command}</info> [--opt -v -h ...] [arg0 arg1 arg2=value2 ...]",
'Options' => $globalOptions,
'Example' => [
"$binName test run a independent command",
"$binName home index run a sub-command of the group",
sprintf("$binName home%sindex run a sub-command of the group", $delimiter),
"$binName help {command} see a command help information",
"$binName home index -h see a sub-command help of the group",
sprintf("$binName home%sindex -h see a sub-command help of the group", $delimiter),
],
'Help' => [
'Generate shell auto completion scripts:',
" <info>$binName --auto-completion --shell-env [zsh|bash] [--gen-file stdout]</info>",
' eg:',
" $binName --auto-completion --shell-env bash --gen-file stdout",
" $binName --auto-completion --shell-env bash --gen-file myapp.sh",
],
]);
}

Expand Down Expand Up @@ -261,7 +273,7 @@ protected function dumpAutoCompletion(string $shellEnv, array $data): void

// info
$glue = ' ';
$genFile = (string)$input->getLongOpt('gen-file');
$genFile = $input->getStringOpt('gen-file');
$filename = 'auto-completion.' . $shellEnv;
$tplDir = dirname(__DIR__, 2) . '/resource/templates';

Expand Down
4 changes: 2 additions & 2 deletions src/Controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -309,11 +309,11 @@ final public function execute($input, $output)

// if user custom handle not found logic.
if ($this->onNotFound($action)) {
$this->debugf('user custom handle the action:%s not found logic', $action);
$this->debugf('user custom handle the action "%s" not found logic', $action);
return 0;
}

$this->debugf('action:%s not found on the group controller', $action);
$this->debugf('action "%s" not found on the group controller', $action);

// if you defined the method '$this->notFoundCallback' , will call it
// if (($notFoundCallback = $this->notFoundCallback) && method_exists($this, $notFoundCallback)) {
Expand Down
7 changes: 7 additions & 0 deletions src/GlobalOption.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ class GlobalOption

public const DEBUG = 'debug';

public const ISHELL = 'ishell';

public const VERSION = 'version';

public const PROFILE = 'profile';
Expand All @@ -21,8 +23,13 @@ class GlobalOption

public const NO_INTERACTIVE = 'no-interactive';

public const HELP_OPTS = ['h', 'help'];

public const VERSION_OPTS = ['V', 'version'];

public const KEY_MAP = [
'debug' => 1,
'ishell' => 1,
'profile' => 1,
'no-color' => 1,
'h' => 1,
Expand Down
13 changes: 12 additions & 1 deletion src/IO/Input.php
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,22 @@ protected function collectInfo(array $args): void
$this->tokens = $args;
$this->script = array_shift($args);
$this->flags = $args; // no script

// bin name
$this->scriptName = basename($this->script);

// full script
$this->fullScript = implode(' ', $args);
}

/**
* re-parse args/opts from given args
*
* @param array $args
*/
public function parse(array $args): void
{
$this->doParse($args);
}

/**
Expand Down Expand Up @@ -140,7 +151,7 @@ public function read(string $question = '', bool $nl = false): string
fwrite(Cli::getOutputStream(), $question . ($nl ? "\n" : ''));
}

return trim(fgets($this->inputStream));
return trim((string)fgets($this->inputStream));
}

/***********************************************************************************
Expand Down
53 changes: 53 additions & 0 deletions src/IO/Input/StringInput.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php declare(strict_types=1);
/**
* Created by PhpStorm.
* User: Inhere
* Date: 2018/1/30 0030
* Time: 23:41
*/

namespace Inhere\Console\IO\Input;

use Inhere\Console\IO\Input;
use Toolkit\Cli\Flags;
use Toolkit\Cli\Util\LineParser;

/**
* Class StringInput
*
* @package Inhere\Console\IO\Input
*/
class StringInput extends Input
{
/**
* Input constructor.
*
* @param string $line
* @param bool $parsing
*/
public function __construct(string $line, bool $parsing = true)
{
parent::__construct([], false);

if ($parsing && $line) {
$flags = LineParser::parseIt($line);

$this->doParse($flags);
}
}

/**
* @param array $args
*/
protected function doParse(array $args): void
{
[
$this->args,
$this->sOpts,
$this->lOpts
] = Flags::parseArray($args);

// find command name
$this->command = $this->findCommandName();
}
}
2 changes: 1 addition & 1 deletion src/Util/Interact.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public static function readln($message = null, $nl = false, array $opts = []): s

$stream = $opts['stream'] ?? Cli::getInputStream();

return trim(fgets($stream));
return trim((string)fgets($stream));
}

/**
Expand Down

0 comments on commit 4187376

Please sign in to comment.