Вход Регистрация
Файл: vendor/psy/psysh/src/Command/HistoryCommand.php
Строк: 322
<?php

/*
 * This file is part of Psy Shell.
 *
 * (c) 2012-2022 Justin Hileman
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace PsyCommand;

use 
PsyInputFilterOptions;
use 
PsyOutputShellOutput;
use 
PsyReadlineReadline;
use 
SymfonyComponentConsoleFormatterOutputFormatter;
use 
SymfonyComponentConsoleInputInputInterface;
use 
SymfonyComponentConsoleInputInputOption;
use 
SymfonyComponentConsoleOutputOutputInterface;

/**
 * Psy Shell history command.
 *
 * Shows, searches and replays readline history. Not too shabby.
 */
class HistoryCommand extends Command
{
    private 
$filter;
    private 
$readline;

    
/**
     * {@inheritdoc}
     */
    
public function __construct($name null)
    {
        
$this->filter = new FilterOptions();

        
parent::__construct($name);
    }

    
/**
     * Set the Shell's Readline service.
     *
     * @param Readline $readline
     */
    
public function setReadline(Readline $readline)
    {
        
$this->readline $readline;
    }

    
/**
     * {@inheritdoc}
     */
    
protected function configure()
    {
        list(
$grep$insensitive$invert) = FilterOptions::getOptions();

        
$this
            
->setName('history')
            ->
setAliases(['hist'])
            ->
setDefinition([
                new 
InputOption('show''s'InputOption::VALUE_REQUIRED'Show the given range of lines.'),
                new 
InputOption('head''H'InputOption::VALUE_REQUIRED'Display the first N items.'),
                new 
InputOption('tail''T'InputOption::VALUE_REQUIRED'Display the last N items.'),

                
$grep,
                
$insensitive,
                
$invert,

                new 
InputOption('no-numbers''N'InputOption::VALUE_NONE'Omit line numbers.'),

                new 
InputOption('save'''InputOption::VALUE_REQUIRED'Save history to a file.'),
                new 
InputOption('replay'''InputOption::VALUE_NONE'Replay.'),
                new 
InputOption('clear'''InputOption::VALUE_NONE'Clear the history.'),
            ])
            ->
setDescription('Show the Psy Shell history.')
            ->
setHelp(
                <<<'HELP'
Show, search, save or replay the Psy Shell history.

e.g.
<return>>>> history --grep /[bB]acon/</return>
<return>>>> history --show 0..10 --replay</return>
<return>>>> history --clear</return>
<return>>>> history --tail 1000 --save somefile.txt</return>
HELP
            );
    }

    
/**
     * {@inheritdoc}
     *
     * @return int 0 if everything went fine, or an exit code
     */
    
protected function execute(InputInterface $inputOutputInterface $output)
    {
        
$this->validateOnlyOne($input, ['show''head''tail']);
        
$this->validateOnlyOne($input, ['save''replay''clear']);

        
$history $this->getHistorySlice(
            
$input->getOption('show'),
            
$input->getOption('head'),
            
$input->getOption('tail')
        );
        
$highlighted false;

        
$this->filter->bind($input);
        if (
$this->filter->hasFilter()) {
            
$matches = [];
            
$highlighted = [];
            foreach (
$history as $i => $line) {
                if (
$this->filter->match($line$matches)) {
                    if (isset(
$matches[0])) {
                        
$chunks explode($matches[0], $history[$i]);
                        
$chunks array_map([__CLASS__'escape'], $chunks);
                        
$glue sprintf('<urgent>%s</urgent>'self::escape($matches[0]));

                        
$highlighted[$i] = implode($glue$chunks);
                    }
                } else {
                    unset(
$history[$i]);
                }
            }
        }

        if (
$save $input->getOption('save')) {
            
$output->writeln(sprintf('Saving history in %s...'$save));
            
file_put_contents($saveimplode(PHP_EOL$history).PHP_EOL);
            
$output->writeln('<info>History saved.</info>');
        } elseif (
$input->getOption('replay')) {
            if (!(
$input->getOption('show') || $input->getOption('head') || $input->getOption('tail'))) {
                throw new 
InvalidArgumentException('You must limit history via --head, --tail or --show before replaying');
            }

            
$count count($history);
            
$output->writeln(sprintf('Replaying %d line%s of history'$count, ($count !== 1) ? 's' ''));
            
$this->getApplication()->addInput($history);
        } elseif (
$input->getOption('clear')) {
            
$this->clearHistory();
            
$output->writeln('<info>History cleared.</info>');
        } else {
            
$type $input->getOption('no-numbers') ? ShellOutput::NUMBER_LINES;
            if (!
$highlighted) {
                
$type $type OutputInterface::OUTPUT_RAW;
            }

            
$output->page($highlighted ?: $history$type);
        }

        return 
0;
    }

    
/**
     * Extract a range from a string.
     *
     * @param string $range
     *
     * @return array [ start, end ]
     */
    
private function extractRange(string $range): array
    {
        if (
preg_match('/^d+$/'$range)) {
            return [
$range$range 1];
        }

        
$matches = [];
        if (
$range !== '..' && preg_match('/^(d*)..(d*)$/'$range$matches)) {
            
$start $matches[1] ? (int) $matches[1] : 0;
            
$end $matches[2] ? (int) $matches[2] + PHP_INT_MAX;

            return [
$start$end];
        }

        throw new 
InvalidArgumentException('Unexpected range: '.$range);
    }

    
/**
     * Retrieve a slice of the readline history.
     *
     * @param string|null $show
     * @param string|null $head
     * @param string|null $tail
     *
     * @return array A slice of history
     */
    
private function getHistorySlice($show$head$tail): array
    {
        
$history $this->readline->listHistory();

        
// don't show the current `history` invocation
        
array_pop($history);

        if (
$show) {
            list(
$start$end) = $this->extractRange($show);
            
$length $end $start;
        } elseif (
$head) {
            if (!
preg_match('/^d+$/'$head)) {
                throw new 
InvalidArgumentException('Please specify an integer argument for --head');
            }

            
$start 0;
            
$length = (int) $head;
        } elseif (
$tail) {
            if (!
preg_match('/^d+$/'$tail)) {
                throw new 
InvalidArgumentException('Please specify an integer argument for --tail');
            }

            
$start count($history) - $tail;
            
$length = (int) $tail 1;
        } else {
            return 
$history;
        }

        return 
array_slice($history$start$lengthtrue);
    }

    
/**
     * Validate that only one of the given $options is set.
     *
     * @param InputInterface $input
     * @param array          $options
     */
    
private function validateOnlyOne(InputInterface $input, array $options)
    {
        
$count 0;
        foreach (
$options as $opt) {
            if (
$input->getOption($opt)) {
                
$count++;
            }
        }

        if (
$count 1) {
            throw new 
InvalidArgumentException('Please specify only one of --'.implode(', --'$options));
        }
    }

    
/**
     * Clear the readline history.
     */
    
private function clearHistory()
    {
        
$this->readline->clearHistory();
    }

    public static function 
escape(string $string): string
    
{
        return 
OutputFormatter::escape($string);
    }
}
Онлайн: 0
Реклама