8000 Console - make:subscriber - interactive mode autocomplete - bug · Issue #26321 · symfony/symfony · GitHub
[go: up one dir, main page]

Skip to content

Console - make:subscriber - interactive mode autocomplete - bug #26321

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
ybenhssaien opened this issue Feb 26, 2018 · 3 comments
Closed

Console - make:subscriber - interactive mode autocomplete - bug #26321

ybenhssaien opened this issue Feb 26, 2018 · 3 comments

Comments

@ybenhssaien
Copy link
Contributor
ybenhssaien commented Feb 26, 2018
Q A
Bug report? yes
Feature request? no
BC Break report? no
RFC? no
Symfony version 4.0.4

Description :

Using the command make:subscriber with an event suscriber kernel.controller on the interactive mode (Responding to the 'What event do you want to subscribe to?' question).
Submited : kernel.controller
Result : kernel.controller_arguments

Console :

image

Result :

image

Bug caused by :

When puting an Enter character on the console, a last check is made to verify even the character is a new line \n or a tabulation \t, then choose the returned autocomplete from the matches array with an $ofs = 0 which return $matches[0] = 'kernel.controller_arguments on the following lines :

}
} elseif (ord($c) < 32) {
if ("\t" === $c || "\n" === $c) {
if ($numMatches > 0 && -1 !== $ofs) {
$ret = $matches[$ofs];

@ybenhssaien
Copy link
Contributor Author

Rewriting the same function, this is my suggestion and not well tested :

/**
* Autocompletes a question.
*
* @param OutputInterface $output
* @param Question $question
* @param array $autocomplete
*/
private function autocomplete(OutputInterface $output, Question $question, $inputStream, array $autocomplete): string
{
$word = $this->readLineFromStream();

  /* if the typed word exits on autocomplete list will return it */
  if(in_array($word, $autocomplete)){
    return $word;
  }

  /* calculate the word matches from autocomplete */
  $matches = $this->getWordMatchesSuggestion($word, $autocomplete);

  if(count($matches) > 0){
    do{
      $response = $this->suggestWordsList($output, $matches);
    }while($response && !in_array($response, $autocomplete));

    /* replace the old word only if response is different than false and the old one */
    if($response && $word != $response){
      $word = $response;
    }
  }

  return $word;
}

/**
 * Ask question with keywords list and return response
 *
 * @param OutputInterface $output
 * @param array           $suggestionList
 * @param int             $returnedRows
 */
private function suggestWordsList(OutputInterface $output, $suggestionList = array())
{
  /* Suggest new words based on matches result */
  $output->writeln(sprintf('Did you mean : %s ? type No if you want to keep your choice.', implode(', ', $suggestionList)));
  $response = $this->readLineFromStream();

  return ('no' == strtolower($response))?false:$response;
}

/**
 * Return similar word list from suggestion list.
 *
 * @param OutputInterface $output
 * @param array           $suggestionList
 * @param int             $returnedRows
 */
private function getWordMatchesSuggestion($word, array $suggestionList, int $returnedRows = 1)
{
  $wordLength = strlen($word);
  $minCharsToMatch = $wordLength/2;

  foreach ($suggestionList as $suggestion) {
    /* calculate matches keys */ 
    $matchesKeys = similar_text($word, $suggestion);
    if($matchesKeys > $minCharsToMatch){
      if(isset($matches[$matchesKeys])){
        $matches[$matchesKeys] = array_merge((array)$matches[$matchesKeys], (array)$suggestion);
      }else{
        $matches[$matchesKeys] = $suggestion;
      }
    }
  }

  /* sort the matches keywords */
  krsort($matches);

  return ($returnedRows > 1)?array_slice($matches, 0, $returnedRows):current($matches);
}

/**
 * read line from console.
 */
private function readLineFromStream(){
  /* read until getting an empty word */
  do{
    $word = trim(fgets(STDIN));
  }while(empty($word));

  return $word;
}

@Simperfit
Copy link
Contributor

Do you want to provide a pull request directly ?

ybenhssaien added a commit to ybenhssaien/symfony that referenced this issue Mar 12, 2018
ybenhssaien added a commit to ybenhssaien/symfony that referenced this issue Mar 12, 2018
ybenhssaien added a commit to ybenhssaien/symfony that referenced this issue Mar 12, 2018
ybenhssaien added a commit to ybenhssaien/symfony that referenced this issue Mar 12, 2018
ybenhssaien added a commit to ybenhssaien/symfony that referenced this issue Mar 13, 2018
ybenhssaien added a commit to ybenhssaien/symfony that referenced this issue Mar 14, 2018
@nicolas-grekas
Copy link
Member

Fixed by #26875.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants
0