Hacktoberfest 2026: as issues que os mantenedores marcaram para outubro, abertas e boas para iniciantes. Ver issues do Hacktoberfest

fix: Wrong completion context for chained commands in zsh

Aberta
#139 0 comentários 0 reações 0 responsáveis Ver no GitHub

Ninguém assumiu esta issue ainda.

Avaliação

Dificuldade
3/5
Tempo estimado
1-2 dias
Facilidade para iniciantes
82/100
Tipo de issue
Bug
Clareza
Claramente especificada
Status de atividade
Ativa
Stack de tecnologia
dart, zsh
Domínio
cli

Direção de pesquisa

Start with lib/src/installer/shell_completion_configuration.dart and CompletionState.fromEnvironment, which the issue identifies as passing and reading the completion context. Check the existing completion tests and how the words passed after completion -- relate to COMP_CWORD. Done means commands after |, && or ; suggest the current command’s options, while existing bash completion still works.

Escrita pelo modelo de indexação a partir do texto da issue.

Descrição

bug
Description

Thank you for this cool lib! I'm facing a minor bug when used with zsh.

In zsh, completing a command that isn't at the start of the command line (after |, && or ;) uses the wrong context. The zsh script passes COMP_LINE="$BUFFER", which is zsh's whole edit buffer, and CompletionState.fromEnvironment reads the arguments from COMP_LINE. So everything typed before the current command is treated as CLI arguments.

Steps To Reproduce

Take a CLI my_cli built on CompletionCommandRunner, with commands foo and bar that have different options, and install its completion in zsh with my_cli install-completion-files.

  1. my_cli foo | my_cli bar <TAB> suggests foo's options. The request is parsed as foo | my_cli bar '', so foo is taken as the command being completed.
  2. cd somewhere && my_cli bar <TAB> suggests nothing, so zsh falls back to file names.

Without a shell, this is the request zsh sends for step 1:

ZSH_NAME=zsh COMP_LINE='my_cli foo | my_cli bar ' COMP_POINT=24 COMP_CWORD=2 \
  my_cli completion -- my_cli bar ''

It prints foo's options.

Expected Behavior

A command after |, && or ; completes the same way as at the start of the line. Both my_cli foo | my_cli bar <TAB> and cd somewhere && my_cli bar <TAB> suggest bar's options, just like my_cli bar <TAB>. Bash already behaves this way.

Additional Context

Cause

  • The zsh template in lib/src/installer/shell_completion_configuration.dart runs COMP_CWORD="$((CURRENT-1))" COMP_LINE="$BUFFER" COMP_POINT="$CURSOR" … completion -- "${words[@]}". $BUFFER is the whole edit buffer, while $words and $CURRENT cover only the current command.
  • CompletionState.fromEnvironment takes the arguments from COMP_LINE (line.trimLeft().split(' ').skip(1)) and ignores the words passed after completion --.
  • Bash isn't affected, because bash itself limits COMP_LINE to the current command. With bash 3.2, echo x | mycmd a <TAB> sets COMP_LINE to mycmd a.

Suggested fix

Build the arguments from the words the scripts already pass after completion --, up to COMP_CWORD, instead of from COMP_LINE. Both scripts pass only the current command's words there, so this fixes zsh without changing the scripts or making users reinstall them.

Workaround

Until this is fixed, a CLI can narrow COMP_LINE itself before the request is handled, in its CompletionCommandRunner subclass:

@override
Future<int?> runCommand(ArgResults topLevelResults) {
  final command = topLevelResults.command;
  if (command?.name == HandleCompletionRequestCommand.commandName) {
    final words = command!.rest; // the words after `completion --`
    final environment = Platform.environment;
    final cword = int.tryParse(environment['COMP_CWORD'] ?? '');
    if (cword != null && cword >= 0 && cword < words.length) {
      final line = words.take(cword + 1).join(' ');
      environmentOverride = {...environment, 'COMP_LINE': line, 'COMP_POINT': '${line.length}'};
    }
  }
  return super.runCommand(topLevelResults);
}

Environment

  • cli_completion 0.6.0
  • Dart 3.13.3
  • zsh 5.9, macOS (arm64)
Linguagem predominante
Dart
Estrelas
54
Forks
6
Merge médio
24min
PRs com merge (30d)
1

Preparar o ambiente

  • Sem Dockerfile nem arquivo Docker Compose
  • Tem um modelo de pull request
  • Sem guia de contribuição

Primeiros passos

  1. Leia a issue inteira e depois o guia de contribuição do projeto.
  2. Comente na issue dizendo que vai assumir — evita que duas pessoas façam o mesmo trabalho.
  3. Faça um fork do repositório e trabalhe em uma branch.
  4. Abra um pull request que referencie o número da issue.

Mais de VeryGoodOpenSource/cli_completion

Todas as issues de VeryGoodOpenSource/cli_completion

Issues semelhantes

Mais issues de Dart

Receba novas issues na sua caixa de entrada

Um resumo curto de issues do GitHub para quem está começando.