AskCommand::doExecute()   B
last analyzed

Complexity

Conditions 10
Paths 50

Size

Total Lines 52
Code Lines 28

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 10
eloc 28
c 1
b 0
f 0
nc 50
nop 2
dl 0
loc 52
rs 7.6666

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Startwind\Forrest\CliCommand\Ai;
4
5
use Startwind\Forrest\CliCommand\Command\CommandCommand;
6
use Startwind\Forrest\Util\OutputHelper;
7
use Symfony\Component\Console\Command\Command as SymfonyCommand;
8
use Symfony\Component\Console\Input\InputArgument;
9
use Symfony\Component\Console\Input\InputInterface;
10
use Symfony\Component\Console\Input\InputOption;
11
use Symfony\Component\Console\Output\OutputInterface;
12
use Startwind\Forrest\Command\Answer\Answer;
13
use Symfony\Component\Console\Question\Question;
14
15
class AskCommand extends CommandCommand
16
{
17
    public const COMMAND_NAME = 'ai:ask';
18
19
    protected static $defaultName = self::COMMAND_NAME;
20
    protected static $defaultDescription = 'Suggest an answer to a question.';
21
22
    protected function configure(): void
23
    {
24
        $this->addArgument('question', InputArgument::IS_ARRAY, 'The question you want to have answered.', []);
25
        $this->addOption('force', null, InputOption::VALUE_NONE, 'Run the command without asking for permission.');
26
        $this->addOption('silent', null, InputOption::VALUE_NONE, 'Run the command without explanation.');
27
28
        parent::configure();
29
    }
30
31
    protected function doExecute(InputInterface $input, OutputInterface $output): int
32
    {
33
        $this->enrichRepositories();
34
35
        $silent = $input->getOption('silent');
36
37
        if (!$silent) {
38
            \Startwind\Forrest\Output\OutputHelper::renderHeader($output);
39
        }
40
41
        $aiQuestion = trim(implode(' ', $input->getArgument('question')));
42
43
        if ($aiQuestion == 'how') {
44
            OutputHelper::writeErrorBox($output, ["Please provide a question."]);
45
            return SymfonyCommand::FAILURE;
46
        }
47
48
        if ($aiQuestion && !str_ends_with($aiQuestion, '?')) {
49
            $aiQuestion = $aiQuestion . '?';
50
        }
51
52
        /** @var \Symfony\Component\Console\Helper\QuestionHelper $questionHelper */
53
        $questionHelper = $this->getHelper('question');
54
55
        if (!$aiQuestion) {
56
            OutputHelper::writeInfoBox($output, ["Hi, I am Forrest, your AI command line helper. How can I help you?"]);
57
            $output->writeln('');
58
            $aiQuestion = $questionHelper->ask($input, $output, new Question('  Your question: '));
59
            $output->writeln(['', '']);
60
        } else {
61
            if (!$silent) {
62
                OutputHelper::writeInfoBox($output, [
63
                    "Question: " . ucfirst($aiQuestion)
64
                ]);
65
            }
66
        }
67
68
        $answers = $this->getRepositoryCollection()->ask($aiQuestion);
69
70
        foreach ($answers as $repoAnswers) {
71
            foreach ($repoAnswers as $answer) {
72
                /** @var Answer $answer */
73
                $output->writeln(OutputHelper::indentText($this->formatCliText($answer->getAnswer())));
74
                $command = $answer->getCommand();
75
76
                if ($command->getPrompt()) {
77
                    return $this->runCommand($answer->getCommand(), []);
78
                }
79
            }
80
        }
81
82
        return SymfonyCommand::SUCCESS;
83
    }
84
85
    private function formatCliText(string $text): string
86
    {
87
        preg_match_all('#```shell((.|\n)*?)```#', $text, $matches);
88
89
        if (count($matches[1]) == 1) {
90
            $shell = $matches[1][0];
91
92
            $shellNew = implode("\n", OutputHelper::indentText(trim($shell), 2, 100, ' | '));
93
94
            $text = str_replace($matches[0][0], $shellNew, $text);
95
        }
96
97
        preg_match_all('#`(.*)`#', $text, $matches);
98
99
        if (count($matches[1]) > 0) {
100
            foreach ($matches[0] as $key => $match) {
101
                $text = str_replace($match, '<options=bold>' . $matches[1][$key] . '</>', $text);
102
            }
103
        }
104
105
        return $text;
106
    }
107
}
108