编辑:

编辑:

我正在编写一个 bash 选项卡完成命令并且基础知识可以工作。

我试图让它变得更复杂一些,但 bash 手册并不是很好。

具体来说,手册提到了 shell 变量COMP_TYPE

我正在尝试找出触发每种类型的因素以及该类型是否会更改完成命令的输出的解释方式。

例如,有一种类型“%”,称为菜单。

我正在完成的命令需要一组开关,所以我想知道菜单类型是否实际显示某种菜单。

> dcli compile -o -w hello.dart

如果命令开关的 CLI 补全出现在带有一些格式的小菜单中,那就更好了。

有关如何触发类型以及如何处理输出的更多详细信息将非常有用。

编辑:

我正在寻求三件事的明确性:

  1. 如何选择特定类型。用户实际上是否键入 % 来触发菜单类型?

打字ls %似乎不会触发完成。

  1. 如果用户触发菜单类型 - 它实际上意味着完成应该做什么?即对于选项卡完成,我提供了一个选项列表,如果它是菜单类型,应该有什么不同?

  2. 如果用户触发菜单类型,它会改变 bash 处理完成命令输出的方式。使用正常的制表符补全,补全命令每行打印一个结果,bash 将这些结果显示为选项。那么用户选择菜单类型是否会改变完成命令可以输出的内容,或者是否会改变 bash 解释/使用输出的方式?

编辑2:

根据要求,这里是实现完成的 Dart 代码:


void main(List<String> args) {
  if (args.length < 2) {
    printerr('dcli_complete provides tab completion from the bash command line for dcli');
    printerr("You don't run dcli_complete directly");
    exit(-1);
  }

  //var appname = args[0];
  var word = args[1];

  var commands = Commands.applicationCommands;

  var results = <String>[];

  var priorCommandFound = false;

  // do we have a prior word.
  if (args.length == 3) {
    var priorWord = args[2];
    //print('prior word: $priorWord');
    if (priorWord.isNotEmpty) {
      var priorCommand = Commands.findCommand(priorWord, Commands.asMap(Commands.applicationCommands));

      if (priorCommand != null) {
        /// We found a command let it complete the expansion according to its own rules
        //print('priorCommand ${priorCommand.name}');
        results = priorCommand.completion(word);
        priorCommandFound = true;
      }
    }
  }

  if (!priorCommandFound) {
    // find all commands that matches the 'word' using it as prefix
    // and add them to the output.
    for (var command in commands) {
      if (command.name.startsWith(word)) {
        results.add(command.name);
      }
    }
  }
  for (var result in results) {
    print(result);
  }

complete找到“先前”命令时的示例方法。


 @override
  List<String> completion(String word) {
    return completionExpandScripts(word);
  }

List<String> completionExpandScripts(String word, {String workingDirectory = '.'}) {
  var root = workingDirectory;

  /// expand ~ to the home dir.
  if (word.startsWith('~')) {
    word = word.replaceAll('~', HOME);
  }

  var searchTerm = word;

  // a trailing slash and we treat the word as a directory.
  if (word.endsWith(Platform.pathSeparator)) {
    root = join(root, word);
    searchTerm = '';
  } else {
    // no trailing slash but the word may contain a directory path
    // in which case we use the last part as the search term
    // and append any remaining path to the root.
    if (word.isNotEmpty) {
      var parts = split(word);

      searchTerm = parts.last;

      if (parts.length > 1) {
        root = join(root, parts.sublist(0, parts.length - 1).join(Platform.pathSeparator));
      }
    }
  }

  /// if the resulting path is invalid return an empty list.
  if (!exists(root)) return <String>[];

  // /// if the work ends in a slash then we treat it as a directory
  // /// then we need to use the directory as the root so we
  // /// search in it.
  // if (exists(join(root, searchTerm))) {
  //   root = join(root, searchTerm);
  //   searchTerm = '';
  // }

  var entries = find('$searchTerm*', types: [Find.directory, Find.file], root: root, recursive: false).toList();

  var results = <String>[];
  for (var script in entries) {
    if (word.isEmpty || relative(script, from: workingDirectory).startsWith(word)) {
      var matchPath = join(root, script);
      String filePath;
      if (isDirectory(matchPath)) {
        // its a directory add trailing slash and returning.
        filePath = '${relative('$script', from: workingDirectory)}/';
      } else {
        filePath = relative(script, from: workingDirectory);
      }
      if (filePath.contains(' ')) {
        /// we quote filenames that include a space
        filePath = '"$filePath"';
      }
      results.add(filePath);
    }
  }

  return results;
}

编辑3:

这是迄今为止我找到的最详细的解释,但它仍然没有真正的帮助。

根据手册:

COMP_TYPE 设置为与导致调用完成函数的尝试完成类型相对应的整数值:TAB,用于正常完成,?,用于在连续制表符后列出完成,!,用于列出部分单词完成的替代项、 @ 列出补全(如果单词不是未修改的),或 % 表示菜单补全。该变量仅在 shell 函数和由可编程完成工具调用的外部命令中可用(请参阅下面的可编程完成)。

我可以得到TAB,?和 % 但我不知道如何得到!和 @。

您应该看到!' when a user hits TAB with“show-all-if-ambiguously”集(因此可能的补全立即列出)和@' if the user hits TAB with“show-all-if-unmodified”集(可能的补全没有公共前缀,因此不能有任何部分完成,因此会立即显示完成情况)。这些是 readline 所需完成类型的内部值,它们反映在 COMP_TYPE 的值中。

这篇堆栈溢出文章提供了有关 show-if-xxx 设置的作用的一些解释,但是它们似乎会影响 readline 的运行方式,但尚不清楚 readline 如何与我的完成命令交互。

https://stackoverflow.com/questions/42192384/show-all-if-ambigously-vs-show-all-if-unmodified

它也没有解释 '%' COMP_TYPE 及其触发方式。

相关内容