편집하다:

편집하다:

bash 탭 완성 명령을 작성 중이고 기본 작업이 작동합니다.

조금 더 복잡하게 만들려고 노력했지만 bash 매뉴얼이 별로 좋지 않습니다.

특히 매뉴얼에는 쉘 변수가 언급되어 있습니다 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, 일반 완성의 경우, ?, 연속된 탭 뒤의 완성 목록 표시, !, 부분 단어 완성 항목에 대한 대체 목록 표시, @ 목록 완성(단어가 수정되지 않은 경우) 또는 %(메뉴 완성). 이 변수는 프로그래밍 가능 완성 도구에 의해 호출되는 셸 함수 및 외부 명령에서만 사용할 수 있습니다(아래 프로그래밍 가능 완성 참조).

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과 그것이 어떻게 트리거되는지 설명하지 않습니다.

관련 정보