2022-03-14 16:22:30 -04:00
< ? php
/*
* This file is part of the Symfony package .
*
* ( c ) Fabien Potencier < fabien @ symfony . com >
*
* For the full copyright and license information , please view the LICENSE
* file that was distributed with this source code .
*/
namespace Symfony\Component\Console\Command ;
2023-02-24 06:26:40 -05:00
use Symfony\Component\Console\Attribute\AsCommand ;
2022-03-14 16:22:30 -04:00
use Symfony\Component\Console\Input\InputArgument ;
use Symfony\Component\Console\Input\InputInterface ;
use Symfony\Component\Console\Input\InputOption ;
use Symfony\Component\Console\Output\ConsoleOutputInterface ;
use Symfony\Component\Console\Output\OutputInterface ;
use Symfony\Component\Process\Process ;
/**
* Dumps the completion script for the current shell .
*
* @ author Wouter de Jong < wouter @ wouterj . nl >
*/
2023-02-24 06:26:40 -05:00
#[AsCommand(name: 'completion', description: 'Dump the shell completion script')]
2022-03-14 16:22:30 -04:00
final class DumpCompletionCommand extends Command
{
2023-02-24 06:26:40 -05:00
/**
* @ deprecated since Symfony 6.1
*/
2022-03-14 16:22:30 -04:00
protected static $defaultName = 'completion' ;
2023-02-24 06:26:40 -05:00
/**
* @ deprecated since Symfony 6.1
*/
2022-03-14 16:22:30 -04:00
protected static $defaultDescription = 'Dump the shell completion script' ;
2023-02-24 06:26:40 -05:00
private array $supportedShells ;
2022-03-14 16:22:30 -04:00
protected function configure ()
{
$fullCommand = $_SERVER [ 'PHP_SELF' ];
$commandName = basename ( $fullCommand );
2023-02-24 06:26:40 -05:00
$fullCommand = @ realpath ( $fullCommand ) ? : $fullCommand ;
$shell = $this -> guessShell ();
[ $rcFile , $completionFile ] = match ( $shell ) {
'fish' => [ '~/.config/fish/config.fish' , " /etc/fish/completions/ $commandName .fish " ],
2023-05-29 11:13:32 -04:00
'zsh' => [ '~/.zshrc' , '$fpath[1]/_' . $commandName ],
2023-02-24 06:26:40 -05:00
default => [ '~/.bashrc' , " /etc/bash_completion.d/ $commandName " ],
};
2022-03-14 16:22:30 -04:00
2023-05-29 11:13:32 -04:00
$supportedShells = implode ( ', ' , $this -> getSupportedShells ());
2022-03-14 16:22:30 -04:00
$this
-> setHelp ( <<< EOH
The < info >% command . name %</> command dumps the shell completion script required
2023-05-29 11:13:32 -04:00
to use shell autocompletion ( currently , { $supportedShells } completion are supported ) .
2022-03-14 16:22:30 -04:00
< comment > Static installation
-------------------</>
Dump the script to a global completion file and restart your shell :
2023-02-24 06:26:40 -05:00
< info >% command . full_name % { $shell } | sudo tee { $completionFile } </>
2022-03-14 16:22:30 -04:00
Or dump the script to a local file and source it :
2023-02-24 06:26:40 -05:00
< info >% command . full_name % { $shell } > completion . sh </>
2022-03-14 16:22:30 -04:00
< comment > # source the file whenever you use the project</>
< info > source completion . sh </>
2023-02-24 06:26:40 -05:00
< comment > # or add this line at the end of your "{$rcFile}" file:</>
2022-03-14 16:22:30 -04:00
< info > source / path / to / completion . sh </>
< comment > Dynamic installation
--------------------</>
2023-02-24 06:26:40 -05:00
Add this to the end of your shell configuration file ( e . g . < info > " { $rcFile } " </> ) :
2022-03-14 16:22:30 -04:00
2023-02-24 06:26:40 -05:00
< info > eval " $ ( { $fullCommand } completion { $shell } ) " </>
2022-03-14 16:22:30 -04:00
EOH
)
2023-02-24 06:26:40 -05:00
-> addArgument ( 'shell' , InputArgument :: OPTIONAL , 'The shell type (e.g. "bash"), the value of the "$SHELL" env var will be used if this is not given' , null , $this -> getSupportedShells ( ... ))
2022-03-14 16:22:30 -04:00
-> addOption ( 'debug' , null , InputOption :: VALUE_NONE , 'Tail the completion debug log' )
;
}
protected function execute ( InputInterface $input , OutputInterface $output ) : int
{
$commandName = basename ( $_SERVER [ 'argv' ][ 0 ]);
if ( $input -> getOption ( 'debug' )) {
$this -> tailDebugLog ( $commandName , $output );
2023-05-29 11:13:32 -04:00
return 0 ;
2022-03-14 16:22:30 -04:00
}
$shell = $input -> getArgument ( 'shell' ) ? ? self :: guessShell ();
$completionFile = __DIR__ . '/../Resources/completion.' . $shell ;
if ( ! file_exists ( $completionFile )) {
$supportedShells = $this -> getSupportedShells ();
2023-02-24 06:26:40 -05:00
if ( $output instanceof ConsoleOutputInterface ) {
$output = $output -> getErrorOutput ();
}
if ( $shell ) {
$output -> writeln ( sprintf ( '<error>Detected shell "%s", which is not supported by Symfony shell completion (supported shells: "%s").</>' , $shell , implode ( '", "' , $supportedShells )));
} else {
$output -> writeln ( sprintf ( '<error>Shell not detected, Symfony shell completion only supports "%s").</>' , implode ( '", "' , $supportedShells )));
}
2022-03-14 16:22:30 -04:00
2023-05-29 11:13:32 -04:00
return 2 ;
2022-03-14 16:22:30 -04:00
}
2023-02-24 06:26:40 -05:00
$output -> write ( str_replace ([ '{{ COMMAND_NAME }}' , '{{ VERSION }}' ], [ $commandName , CompleteCommand :: COMPLETION_API_VERSION ], file_get_contents ( $completionFile )));
2022-03-14 16:22:30 -04:00
2023-05-29 11:13:32 -04:00
return 0 ;
2022-03-14 16:22:30 -04:00
}
private static function guessShell () : string
{
return basename ( $_SERVER [ 'SHELL' ] ? ? '' );
}
private function tailDebugLog ( string $commandName , OutputInterface $output ) : void
{
$debugFile = sys_get_temp_dir () . '/sf_' . $commandName . '.log' ;
if ( ! file_exists ( $debugFile )) {
touch ( $debugFile );
}
$process = new Process ([ 'tail' , '-f' , $debugFile ], null , null , null , 0 );
$process -> run ( function ( string $type , string $line ) use ( $output ) : void {
$output -> write ( $line );
});
}
/**
* @ return string []
*/
private function getSupportedShells () : array
{
2023-05-29 11:13:32 -04:00
if ( isset ( $this -> supportedShells )) {
return $this -> supportedShells ;
}
$shells = [];
foreach ( new \DirectoryIterator ( __DIR__ . '/../Resources/' ) as $file ) {
if ( str_starts_with ( $file -> getBasename (), 'completion.' ) && $file -> isFile ()) {
$shells [] = $file -> getExtension ();
}
}
sort ( $shells );
return $this -> supportedShells = $shells ;
2022-03-14 16:22:30 -04:00
}
}