bash タブ補完コマンドを作成中で、基本操作が機能します。
もう少し複雑にしようとしましたが、bashマニュアルはあまり良くありません。
特にマニュアルにはシェル変数が記載されていますCOMP_TYPE
。
各タイプをトリガーする要素と、そのタイプが完了したコマンドの出力が解釈される方法を変更するかどうかを把握しようとしています。
たとえば、メニューというタイプの「%」があります。
私が完了するコマンドにはスイッチセットが必要なので、メニュータイプが実際にどのようなメニューを表示しているのか疑問に思います。
> dcli compile -o -w hello.dart
コマンドスイッチのCLIコンプリートは、いくつかの書式で小さなメニューに表示されたら良いでしょう。
型をトリガーする方法と出力を処理する方法の詳細は便利です。
編集する:
私は3つのことについて明確さを探しています。
- 特定のタイプを選択する方法。ユーザーは実際に%を入力してメニュータイプを実行しますか?
入力してもls %
完了がトリガーされないようです。
ユーザーがメニューの種類をトリガーする場合に何をすべきかをすることは実際に何を意味しますか?つまり、タブを完成させるためのオプションのリストを提供します。メニュータイプの場合は何が違うのですか?
ユーザがメニュータイプをトリガすると、bash が完了コマンド出力を処理する方法が変更されます。一般的なタブ補完では、Completeコマンドは1行に1つの結果を出力し、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 とそれがどのようにトリガーされるかを説明しません。