diff options
author | amatanhead <amatanhead@yandex-team.ru> | 2022-02-10 16:50:04 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:50:04 +0300 |
commit | 8879605a63ac17539be5b3bd41b529791f4d4b02 (patch) | |
tree | 5739c7303cbe09d02b881e25bb294a4a173422a0 /library/cpp/getopt/small/completion_generator.cpp | |
parent | 830fe7ae4073c2707f3f3138303ccc56052c0327 (diff) | |
download | ydb-8879605a63ac17539be5b3bd41b529791f4d4b02.tar.gz |
Restoring authorship annotation for <amatanhead@yandex-team.ru>. Commit 1 of 2.
Diffstat (limited to 'library/cpp/getopt/small/completion_generator.cpp')
-rw-r--r-- | library/cpp/getopt/small/completion_generator.cpp | 1554 |
1 files changed, 777 insertions, 777 deletions
diff --git a/library/cpp/getopt/small/completion_generator.cpp b/library/cpp/getopt/small/completion_generator.cpp index ac41988217..0ff83e1c07 100644 --- a/library/cpp/getopt/small/completion_generator.cpp +++ b/library/cpp/getopt/small/completion_generator.cpp @@ -1,791 +1,791 @@ -#include "completion_generator.h" - +#include "completion_generator.h" + #include <util/generic/overloaded.h> - -#include <util/string/ascii.h> -#include <util/generic/hash_set.h> - -#include "last_getopt_parse_result.h" - -using NLastGetopt::NEscaping::Q; -using NLastGetopt::NEscaping::QQ; -using NLastGetopt::NEscaping::C; -using NLastGetopt::NEscaping::CC; -using NLastGetopt::NEscaping::S; -using NLastGetopt::NEscaping::SS; -using NLastGetopt::NEscaping::B; -using NLastGetopt::NEscaping::BB; - -namespace NLastGetopt { - -#define L out.Line() -#define I auto Y_GENERATE_UNIQUE_ID(indent) = out.Indent() - - TCompletionGenerator::TCompletionGenerator(const TModChooser* modChooser) - : Options_(modChooser) - { - Y_VERIFY(modChooser != nullptr); - } - - TCompletionGenerator::TCompletionGenerator(const TOpts* opts) - : Options_(opts) - { - Y_VERIFY(opts != nullptr); - } - - void TZshCompletionGenerator::Generate(TStringBuf command, IOutputStream& stream) { - TFormattedOutput out; - NComp::TCompleterManager manager{command}; - - L << "#compdef " << command; - L; - L << "_" << command << "() {"; - { - I; - L << "local state line desc modes context curcontext=\"$curcontext\" ret=1"; - L << "local words_orig=(\"${words[@]}\")"; - L << "local current_orig=\"$((CURRENT - 1))\""; - L << "local prefix_orig=\"$PREFIX\""; - L << "local suffix_orig=\"$SUFFIX\""; - L; + +#include <util/string/ascii.h> +#include <util/generic/hash_set.h> + +#include "last_getopt_parse_result.h" + +using NLastGetopt::NEscaping::Q; +using NLastGetopt::NEscaping::QQ; +using NLastGetopt::NEscaping::C; +using NLastGetopt::NEscaping::CC; +using NLastGetopt::NEscaping::S; +using NLastGetopt::NEscaping::SS; +using NLastGetopt::NEscaping::B; +using NLastGetopt::NEscaping::BB; + +namespace NLastGetopt { + +#define L out.Line() +#define I auto Y_GENERATE_UNIQUE_ID(indent) = out.Indent() + + TCompletionGenerator::TCompletionGenerator(const TModChooser* modChooser) + : Options_(modChooser) + { + Y_VERIFY(modChooser != nullptr); + } + + TCompletionGenerator::TCompletionGenerator(const TOpts* opts) + : Options_(opts) + { + Y_VERIFY(opts != nullptr); + } + + void TZshCompletionGenerator::Generate(TStringBuf command, IOutputStream& stream) { + TFormattedOutput out; + NComp::TCompleterManager manager{command}; + + L << "#compdef " << command; + L; + L << "_" << command << "() {"; + { + I; + L << "local state line desc modes context curcontext=\"$curcontext\" ret=1"; + L << "local words_orig=(\"${words[@]}\")"; + L << "local current_orig=\"$((CURRENT - 1))\""; + L << "local prefix_orig=\"$PREFIX\""; + L << "local suffix_orig=\"$SUFFIX\""; + L; std::visit(TOverloaded{ - [&out, &manager](const TModChooser* modChooser) { - GenerateModesCompletion(out, *modChooser, manager); - }, - [&out, &manager](const TOpts* opts) { - GenerateOptsCompletion(out, *opts, manager); - } - }, Options_); - L; - L << "return ret"; - } - L << "}"; - L; - manager.GenerateZsh(out); - - out.Print(stream); - } - - void TZshCompletionGenerator::GenerateModesCompletion(TFormattedOutput& out, const TModChooser& chooser, NComp::TCompleterManager& manager) { - auto modes = chooser.GetUnsortedModes(); - - L << "_arguments -C \\"; - L << " '(- : *)'{-h,--help}'[show help information]' \\"; - if (chooser.GetVersionHandler() != nullptr) { - L << " '(- : *)'{-v,--version}'[display version information]' \\"; - } - if (!chooser.IsSvnRevisionOptionDisabled()) { - L << " '(- : *)--svnrevision[show build information]' \\"; - } - L << " '(-v --version -h --help --svnrevision)1: :->modes' \\"; - L << " '(-v --version -h --help --svnrevision)*:: :->args' \\"; - L << " && ret=0"; - L; - L << "case $state in"; - { - I; - - L << "modes)"; - { - I; - - size_t tag = 0; - bool empty = true; - - L << "desc='modes'"; - L << "modes=("; - for (auto& mode : modes) { - if (mode->Hidden) { - continue; - } - if (!mode->Name.empty()) { - I; - if (!mode->Description.empty()) { - L << QQ(mode->Name) << ":" << QQ(mode->Description); - } else { - L << QQ(mode->Name); - } - empty = false; - } else { - L << ")"; - if (!empty) { - L << "_describe -t 'mode-group-" << tag << "' $desc modes"; - } - L; - if (mode->Description.empty()) { - L << "desc='modes'"; - } else { - L << "desc=" << SS(mode->Description); - } - L << "modes=("; - empty = true; - ++tag; - } - } - L << ")"; - if (!empty) { - L << "_describe -t 'mode-group-" << tag << "' $desc modes"; - } - L; - - L << ";;"; - } - - L << "args)"; - { - I; - - L << "case $line[1] in"; - { - I; - - for (auto& mode : modes) { - if (mode->Name.empty() || mode->Hidden) { - continue; - } - - auto& line = L << SS(mode->Name); - for (auto& alias : mode->Aliases) { - line << "|" << SS(alias); - } - line << ")"; - - { - I; - - if (auto mainArgs = dynamic_cast<TMainClassArgs*>(mode->Main)) { - GenerateOptsCompletion(out, mainArgs->GetOptions(), manager); - } else if (auto mainModes = dynamic_cast<TMainClassModes*>(mode->Main)) { - GenerateModesCompletion(out, mainModes->GetSubModes(), manager); - } else { - GenerateDefaultOptsCompletion(out, manager); - } - - L << ";;"; - } - } - } - L << "esac"; - L << ";;"; - } - } - L << "esac"; - } - - void TZshCompletionGenerator::GenerateOptsCompletion(TFormattedOutput& out, const TOpts& opts, NComp::TCompleterManager& manager) { - L << "_arguments -s \\"; - { - I; - - if (opts.ArgPermutation_ == EArgPermutation::REQUIRE_ORDER) { - L << "-S \\"; - } - - for (auto opt: opts.GetOpts()) { - if (!opt->Hidden_) { - GenerateOptCompletion(out, opts, *opt, manager); - } - } - - auto argSpecs = opts.GetFreeArgSpecs(); - size_t numFreeArgs = opts.GetFreeArgsMax(); - bool unlimitedArgs = false; - if (numFreeArgs == TOpts::UNLIMITED_ARGS) { - numFreeArgs = argSpecs.empty() ? 0 : (argSpecs.rbegin()->first + 1); - unlimitedArgs = true; - } - - for (size_t i = 0; i < numFreeArgs; ++i) { - auto& spec = argSpecs[i]; - auto& line = L << "'" << (i + 1) << ":"; - if (spec.IsOptional()) { - line << ":"; - } - auto argHelp = spec.GetCompletionArgHelp(opts.GetDefaultFreeArgTitle()); - if (argHelp) { - line << Q(argHelp); - } else { - line << " "; - } - line << ":"; - if (spec.Completer_) { - line << spec.Completer_->GenerateZshAction(manager); - } else { - line << "_default"; - } - line << "' \\"; - } - - if (unlimitedArgs) { - auto& spec = opts.GetTrailingArgSpec(); - auto& line = L << "'*:"; - auto argHelp = spec.GetCompletionArgHelp(opts.GetDefaultFreeArgTitle()); - if (argHelp) { - line << Q(argHelp); - } else { - line << " "; - } - line << ":"; - if (spec.Completer_) { - line << spec.Completer_->GenerateZshAction(manager); - } else { - line << "_default"; - } - line << "' \\"; - } - - L << "&& ret=0"; - } - } - - void TZshCompletionGenerator::GenerateDefaultOptsCompletion(TFormattedOutput& out, NComp::TCompleterManager&) { - L << "_arguments \\"; - L << " '(- *)'{-h,--help}'[show help information]' \\"; - L << " '(- *)--svnrevision[show build information]' \\"; - L << " '(-h --help --svnrevision)*: :_files' \\"; - L << " && ret=0"; - } - - void TZshCompletionGenerator::GenerateOptCompletion(TFormattedOutput& out, const TOpts& opts, const TOpt& opt, NComp::TCompleterManager& manager) { - auto& line = L; - - THashSet<TString> disableOptions; - if (opt.DisableCompletionForOptions_) { - disableOptions.insert("-"); - } else { - if (!opt.AllowMultipleCompletion_) { - for (auto shortName: opt.GetShortNames()) { - disableOptions.insert(TString("-") + shortName); - } - for (auto& longName: opt.GetLongNames()) { - disableOptions.insert("--" + longName); - } - } - for (auto disabledShortName : opt.DisableCompletionForChar_) { - auto disabledOpt = opts.FindCharOption(disabledShortName); - if (disabledOpt) { - for (auto shortName: disabledOpt->GetShortNames()) { - disableOptions.insert(TString("-") + shortName); - } - for (auto& longName: disabledOpt->GetLongNames()) { - disableOptions.insert("--" + longName); - } - } else { - disableOptions.insert(TString("-") + disabledShortName); - } - } - for (auto& disabledLongName : opt.DisableCompletionForLongName_) { - auto disabledOpt = opts.FindLongOption(disabledLongName); - if (disabledOpt) { - for (auto shortName: disabledOpt->GetShortNames()) { - disableOptions.insert(TString("-") + shortName); - } - for (auto& longName: disabledOpt->GetLongNames()) { - disableOptions.insert("--" + longName); - } - } else { - disableOptions.insert("--" + disabledLongName); - } - } - } - if (opt.DisableCompletionForFreeArgs_) { - disableOptions.insert(":"); - disableOptions.insert("*"); - } else { - for (auto i : opt.DisableCompletionForFreeArg_) { - disableOptions.insert(ToString(i + 1)); - } - } - - TStringBuf sep = ""; - - if (!disableOptions.empty()) { - line << "'("; - for (auto& disableOption : disableOptions) { - line << sep << disableOption; - sep = " "; - } - line << ")"; - } - - sep = ""; - TStringBuf mul = ""; - TStringBuf quot = ""; - - if (opt.GetShortNames().size() + opt.GetLongNames().size() > 1) { - if (!disableOptions.empty()) { - line << "'"; - } - line << "{"; - quot = "'"; - } else { - if (disableOptions.empty()) { - line << "'"; - } - } - - if (opt.AllowMultipleCompletion_) { - mul = "*"; - } - - for (auto& flag : opt.GetShortNames()) { - line << sep << quot << mul << "-" << Q(TStringBuf(&flag, 1)) << quot; - sep = ","; - } - - for (auto& flag : opt.GetLongNames()) { - line << sep << quot << mul << "--" << Q(flag) << quot; - sep = ","; - } - - if (opt.GetShortNames().size() + opt.GetLongNames().size() > 1) { - line << "}'"; - } - - if (opt.GetCompletionHelp()) { - line << "["; - line << Q(opt.GetCompletionHelp()); - line << "]"; - } - - if (opt.HasArg_ != EHasArg::NO_ARGUMENT) { - if (opt.HasArg_ == EHasArg::OPTIONAL_ARGUMENT) { - line << ":"; - } - - line << ":"; - - if (opt.GetCompletionArgHelp()) { - line << C(opt.GetCompletionArgHelp()); - } else { - line << " "; - } - - line << ":"; - - if (opt.Completer_) { - line << C(opt.Completer_->GenerateZshAction(manager)); - } else { - line << "_default"; - } - } - - line << "' \\"; - } - - void TBashCompletionGenerator::Generate(TStringBuf command, IOutputStream& stream) { - TFormattedOutput out; - NComp::TCompleterManager manager{command}; - - L << "_" << command << "() {"; - { - I; - L << "COMPREPLY=()"; - L; - L << "local i args opts items candidates"; - L; - L << "local cur prev words cword"; - L << "_get_comp_words_by_ref -n \"\\\"'><=;|&(:\" cur prev words cword"; - L; - L << "local need_space=\"1\""; - L << "local IFS=$' \\t\\n'"; - L; + [&out, &manager](const TModChooser* modChooser) { + GenerateModesCompletion(out, *modChooser, manager); + }, + [&out, &manager](const TOpts* opts) { + GenerateOptsCompletion(out, *opts, manager); + } + }, Options_); + L; + L << "return ret"; + } + L << "}"; + L; + manager.GenerateZsh(out); + + out.Print(stream); + } + + void TZshCompletionGenerator::GenerateModesCompletion(TFormattedOutput& out, const TModChooser& chooser, NComp::TCompleterManager& manager) { + auto modes = chooser.GetUnsortedModes(); + + L << "_arguments -C \\"; + L << " '(- : *)'{-h,--help}'[show help information]' \\"; + if (chooser.GetVersionHandler() != nullptr) { + L << " '(- : *)'{-v,--version}'[display version information]' \\"; + } + if (!chooser.IsSvnRevisionOptionDisabled()) { + L << " '(- : *)--svnrevision[show build information]' \\"; + } + L << " '(-v --version -h --help --svnrevision)1: :->modes' \\"; + L << " '(-v --version -h --help --svnrevision)*:: :->args' \\"; + L << " && ret=0"; + L; + L << "case $state in"; + { + I; + + L << "modes)"; + { + I; + + size_t tag = 0; + bool empty = true; + + L << "desc='modes'"; + L << "modes=("; + for (auto& mode : modes) { + if (mode->Hidden) { + continue; + } + if (!mode->Name.empty()) { + I; + if (!mode->Description.empty()) { + L << QQ(mode->Name) << ":" << QQ(mode->Description); + } else { + L << QQ(mode->Name); + } + empty = false; + } else { + L << ")"; + if (!empty) { + L << "_describe -t 'mode-group-" << tag << "' $desc modes"; + } + L; + if (mode->Description.empty()) { + L << "desc='modes'"; + } else { + L << "desc=" << SS(mode->Description); + } + L << "modes=("; + empty = true; + ++tag; + } + } + L << ")"; + if (!empty) { + L << "_describe -t 'mode-group-" << tag << "' $desc modes"; + } + L; + + L << ";;"; + } + + L << "args)"; + { + I; + + L << "case $line[1] in"; + { + I; + + for (auto& mode : modes) { + if (mode->Name.empty() || mode->Hidden) { + continue; + } + + auto& line = L << SS(mode->Name); + for (auto& alias : mode->Aliases) { + line << "|" << SS(alias); + } + line << ")"; + + { + I; + + if (auto mainArgs = dynamic_cast<TMainClassArgs*>(mode->Main)) { + GenerateOptsCompletion(out, mainArgs->GetOptions(), manager); + } else if (auto mainModes = dynamic_cast<TMainClassModes*>(mode->Main)) { + GenerateModesCompletion(out, mainModes->GetSubModes(), manager); + } else { + GenerateDefaultOptsCompletion(out, manager); + } + + L << ";;"; + } + } + } + L << "esac"; + L << ";;"; + } + } + L << "esac"; + } + + void TZshCompletionGenerator::GenerateOptsCompletion(TFormattedOutput& out, const TOpts& opts, NComp::TCompleterManager& manager) { + L << "_arguments -s \\"; + { + I; + + if (opts.ArgPermutation_ == EArgPermutation::REQUIRE_ORDER) { + L << "-S \\"; + } + + for (auto opt: opts.GetOpts()) { + if (!opt->Hidden_) { + GenerateOptCompletion(out, opts, *opt, manager); + } + } + + auto argSpecs = opts.GetFreeArgSpecs(); + size_t numFreeArgs = opts.GetFreeArgsMax(); + bool unlimitedArgs = false; + if (numFreeArgs == TOpts::UNLIMITED_ARGS) { + numFreeArgs = argSpecs.empty() ? 0 : (argSpecs.rbegin()->first + 1); + unlimitedArgs = true; + } + + for (size_t i = 0; i < numFreeArgs; ++i) { + auto& spec = argSpecs[i]; + auto& line = L << "'" << (i + 1) << ":"; + if (spec.IsOptional()) { + line << ":"; + } + auto argHelp = spec.GetCompletionArgHelp(opts.GetDefaultFreeArgTitle()); + if (argHelp) { + line << Q(argHelp); + } else { + line << " "; + } + line << ":"; + if (spec.Completer_) { + line << spec.Completer_->GenerateZshAction(manager); + } else { + line << "_default"; + } + line << "' \\"; + } + + if (unlimitedArgs) { + auto& spec = opts.GetTrailingArgSpec(); + auto& line = L << "'*:"; + auto argHelp = spec.GetCompletionArgHelp(opts.GetDefaultFreeArgTitle()); + if (argHelp) { + line << Q(argHelp); + } else { + line << " "; + } + line << ":"; + if (spec.Completer_) { + line << spec.Completer_->GenerateZshAction(manager); + } else { + line << "_default"; + } + line << "' \\"; + } + + L << "&& ret=0"; + } + } + + void TZshCompletionGenerator::GenerateDefaultOptsCompletion(TFormattedOutput& out, NComp::TCompleterManager&) { + L << "_arguments \\"; + L << " '(- *)'{-h,--help}'[show help information]' \\"; + L << " '(- *)--svnrevision[show build information]' \\"; + L << " '(-h --help --svnrevision)*: :_files' \\"; + L << " && ret=0"; + } + + void TZshCompletionGenerator::GenerateOptCompletion(TFormattedOutput& out, const TOpts& opts, const TOpt& opt, NComp::TCompleterManager& manager) { + auto& line = L; + + THashSet<TString> disableOptions; + if (opt.DisableCompletionForOptions_) { + disableOptions.insert("-"); + } else { + if (!opt.AllowMultipleCompletion_) { + for (auto shortName: opt.GetShortNames()) { + disableOptions.insert(TString("-") + shortName); + } + for (auto& longName: opt.GetLongNames()) { + disableOptions.insert("--" + longName); + } + } + for (auto disabledShortName : opt.DisableCompletionForChar_) { + auto disabledOpt = opts.FindCharOption(disabledShortName); + if (disabledOpt) { + for (auto shortName: disabledOpt->GetShortNames()) { + disableOptions.insert(TString("-") + shortName); + } + for (auto& longName: disabledOpt->GetLongNames()) { + disableOptions.insert("--" + longName); + } + } else { + disableOptions.insert(TString("-") + disabledShortName); + } + } + for (auto& disabledLongName : opt.DisableCompletionForLongName_) { + auto disabledOpt = opts.FindLongOption(disabledLongName); + if (disabledOpt) { + for (auto shortName: disabledOpt->GetShortNames()) { + disableOptions.insert(TString("-") + shortName); + } + for (auto& longName: disabledOpt->GetLongNames()) { + disableOptions.insert("--" + longName); + } + } else { + disableOptions.insert("--" + disabledLongName); + } + } + } + if (opt.DisableCompletionForFreeArgs_) { + disableOptions.insert(":"); + disableOptions.insert("*"); + } else { + for (auto i : opt.DisableCompletionForFreeArg_) { + disableOptions.insert(ToString(i + 1)); + } + } + + TStringBuf sep = ""; + + if (!disableOptions.empty()) { + line << "'("; + for (auto& disableOption : disableOptions) { + line << sep << disableOption; + sep = " "; + } + line << ")"; + } + + sep = ""; + TStringBuf mul = ""; + TStringBuf quot = ""; + + if (opt.GetShortNames().size() + opt.GetLongNames().size() > 1) { + if (!disableOptions.empty()) { + line << "'"; + } + line << "{"; + quot = "'"; + } else { + if (disableOptions.empty()) { + line << "'"; + } + } + + if (opt.AllowMultipleCompletion_) { + mul = "*"; + } + + for (auto& flag : opt.GetShortNames()) { + line << sep << quot << mul << "-" << Q(TStringBuf(&flag, 1)) << quot; + sep = ","; + } + + for (auto& flag : opt.GetLongNames()) { + line << sep << quot << mul << "--" << Q(flag) << quot; + sep = ","; + } + + if (opt.GetShortNames().size() + opt.GetLongNames().size() > 1) { + line << "}'"; + } + + if (opt.GetCompletionHelp()) { + line << "["; + line << Q(opt.GetCompletionHelp()); + line << "]"; + } + + if (opt.HasArg_ != EHasArg::NO_ARGUMENT) { + if (opt.HasArg_ == EHasArg::OPTIONAL_ARGUMENT) { + line << ":"; + } + + line << ":"; + + if (opt.GetCompletionArgHelp()) { + line << C(opt.GetCompletionArgHelp()); + } else { + line << " "; + } + + line << ":"; + + if (opt.Completer_) { + line << C(opt.Completer_->GenerateZshAction(manager)); + } else { + line << "_default"; + } + } + + line << "' \\"; + } + + void TBashCompletionGenerator::Generate(TStringBuf command, IOutputStream& stream) { + TFormattedOutput out; + NComp::TCompleterManager manager{command}; + + L << "_" << command << "() {"; + { + I; + L << "COMPREPLY=()"; + L; + L << "local i args opts items candidates"; + L; + L << "local cur prev words cword"; + L << "_get_comp_words_by_ref -n \"\\\"'><=;|&(:\" cur prev words cword"; + L; + L << "local need_space=\"1\""; + L << "local IFS=$' \\t\\n'"; + L; std::visit(TOverloaded{ - [&out, &manager](const TModChooser* modChooser) { - GenerateModesCompletion(out, *modChooser, manager, 1); - }, - [&out, &manager](const TOpts* opts) { - GenerateOptsCompletion(out, *opts, manager, 1); - } - }, Options_); - L; - L; - L << "__ltrim_colon_completions \"$cur\""; - L; - L << "IFS=$'\\n'"; - L << "if [ ${#COMPREPLY[@]} -ne 0 ]; then"; - { - I; - L << "if [[ -z $need_space ]]; then"; - { - I; - L << "COMPREPLY=( $(printf \"%q\\n\" \"${COMPREPLY[@]}\") )"; - } - L << "else"; - { - I; - L << "COMPREPLY=( $(printf \"%q \\n\" \"${COMPREPLY[@]}\") )"; - } - L << "fi"; - } - L << "fi"; - L; - L << "return 0"; - } - L << "}"; - L; - L << "complete -o nospace -o default -F _" << command << " " << command; - - out.Print(stream); - } - - void TBashCompletionGenerator::GenerateModesCompletion(TFormattedOutput& out, const TModChooser& chooser, NComp::TCompleterManager& manager, size_t level) { - auto modes = chooser.GetUnsortedModes(); - - L << "if [[ ${cword} == " << level << " ]] ; then"; - { - I; - L << "if [[ ${cur} == -* ]] ; then"; - { - I; - auto& line = L << "COMPREPLY+=( $(compgen -W '-h --help"; - if (chooser.GetVersionHandler() != nullptr) { - line << " -v --version"; - } - if (!chooser.IsSvnRevisionOptionDisabled()) { - line << " --svnrevision"; - } - line << "' -- ${cur}) )"; - } - L << "else"; - { - I; - auto& line = L << "COMPREPLY+=( $(compgen -W '"; - TStringBuf sep = ""; - for (auto& mode : modes) { + [&out, &manager](const TModChooser* modChooser) { + GenerateModesCompletion(out, *modChooser, manager, 1); + }, + [&out, &manager](const TOpts* opts) { + GenerateOptsCompletion(out, *opts, manager, 1); + } + }, Options_); + L; + L; + L << "__ltrim_colon_completions \"$cur\""; + L; + L << "IFS=$'\\n'"; + L << "if [ ${#COMPREPLY[@]} -ne 0 ]; then"; + { + I; + L << "if [[ -z $need_space ]]; then"; + { + I; + L << "COMPREPLY=( $(printf \"%q\\n\" \"${COMPREPLY[@]}\") )"; + } + L << "else"; + { + I; + L << "COMPREPLY=( $(printf \"%q \\n\" \"${COMPREPLY[@]}\") )"; + } + L << "fi"; + } + L << "fi"; + L; + L << "return 0"; + } + L << "}"; + L; + L << "complete -o nospace -o default -F _" << command << " " << command; + + out.Print(stream); + } + + void TBashCompletionGenerator::GenerateModesCompletion(TFormattedOutput& out, const TModChooser& chooser, NComp::TCompleterManager& manager, size_t level) { + auto modes = chooser.GetUnsortedModes(); + + L << "if [[ ${cword} == " << level << " ]] ; then"; + { + I; + L << "if [[ ${cur} == -* ]] ; then"; + { + I; + auto& line = L << "COMPREPLY+=( $(compgen -W '-h --help"; + if (chooser.GetVersionHandler() != nullptr) { + line << " -v --version"; + } + if (!chooser.IsSvnRevisionOptionDisabled()) { + line << " --svnrevision"; + } + line << "' -- ${cur}) )"; + } + L << "else"; + { + I; + auto& line = L << "COMPREPLY+=( $(compgen -W '"; + TStringBuf sep = ""; + for (auto& mode : modes) { if (!mode->Hidden && !mode->NoCompletion) { line << sep << B(mode->Name); sep = " "; } - } - line << "' -- ${cur}) )"; - } - L << "fi"; - } - L << "else"; - { - I; - L << "case \"${words[" << level << "]}\" in"; - { - I; - - for (auto& mode : modes) { + } + line << "' -- ${cur}) )"; + } + L << "fi"; + } + L << "else"; + { + I; + L << "case \"${words[" << level << "]}\" in"; + { + I; + + for (auto& mode : modes) { if (mode->Name.empty() || mode->Hidden || mode->NoCompletion) { - continue; - } - - auto& line = L << BB(mode->Name); - for (auto& alias : mode->Aliases) { - line << "|" << BB(alias); - } - line << ")"; - - { - I; - - if (auto mainArgs = dynamic_cast<TMainClassArgs*>(mode->Main)) { - GenerateOptsCompletion(out, mainArgs->GetOptions(), manager, level + 1); - } else if (auto mainModes = dynamic_cast<TMainClassModes*>(mode->Main)) { - GenerateModesCompletion(out, mainModes->GetSubModes(), manager, level + 1); - } else { - GenerateDefaultOptsCompletion(out, manager); - } - - L << ";;"; - } - } - } - L << "esac"; - } - L << "fi"; - } - - void TBashCompletionGenerator::GenerateOptsCompletion(TFormattedOutput& out, const TOpts& opts, NComp::TCompleterManager&, size_t level) { - auto unorderedOpts = opts.GetOpts(); - - L << "if [[ ${cur} == -* ]] ; then"; - { - I; - auto& line = L << "COMPREPLY+=( $(compgen -W '"; - TStringBuf sep = ""; - for (auto& opt : unorderedOpts) { + continue; + } + + auto& line = L << BB(mode->Name); + for (auto& alias : mode->Aliases) { + line << "|" << BB(alias); + } + line << ")"; + + { + I; + + if (auto mainArgs = dynamic_cast<TMainClassArgs*>(mode->Main)) { + GenerateOptsCompletion(out, mainArgs->GetOptions(), manager, level + 1); + } else if (auto mainModes = dynamic_cast<TMainClassModes*>(mode->Main)) { + GenerateModesCompletion(out, mainModes->GetSubModes(), manager, level + 1); + } else { + GenerateDefaultOptsCompletion(out, manager); + } + + L << ";;"; + } + } + } + L << "esac"; + } + L << "fi"; + } + + void TBashCompletionGenerator::GenerateOptsCompletion(TFormattedOutput& out, const TOpts& opts, NComp::TCompleterManager&, size_t level) { + auto unorderedOpts = opts.GetOpts(); + + L << "if [[ ${cur} == -* ]] ; then"; + { + I; + auto& line = L << "COMPREPLY+=( $(compgen -W '"; + TStringBuf sep = ""; + for (auto& opt : unorderedOpts) { if (opt->IsHidden()) { continue; } - for (auto& shortName : opt->GetShortNames()) { - line << sep << "-" << B(TStringBuf(&shortName, 1)); - sep = " "; - } - for (auto& longName: opt->GetLongNames()) { - line << sep << "--" << B(longName); - sep = " "; - } - } - line << "' -- ${cur}) )"; - } - L << "else"; - { - I; - L << "case ${prev} in"; - { - I; - for (auto& opt : unorderedOpts) { + for (auto& shortName : opt->GetShortNames()) { + line << sep << "-" << B(TStringBuf(&shortName, 1)); + sep = " "; + } + for (auto& longName: opt->GetLongNames()) { + line << sep << "--" << B(longName); + sep = " "; + } + } + line << "' -- ${cur}) )"; + } + L << "else"; + { + I; + L << "case ${prev} in"; + { + I; + for (auto& opt : unorderedOpts) { if (opt->HasArg_ == EHasArg::NO_ARGUMENT || opt->IsHidden()) { - continue; - } - - auto& line = L; - TStringBuf sep = ""; - for (auto& shortName : opt->GetShortNames()) { - line << sep << "'-" << B(TStringBuf(&shortName, 1)) << "'"; - sep = "|"; - } - for (auto& longName: opt->GetLongNames()) { - line << sep << "'--" << B(longName) << "'"; - sep = "|"; - } - line << ")"; - { - I; - if (opt->Completer_ != nullptr) { - opt->Completer_->GenerateBash(out); - } - L << ";;"; - } - } - - L << "*)"; - { - I; - - L << "args=0"; - auto& line = L << "opts='@("; - TStringBuf sep = ""; - for (auto& opt : unorderedOpts) { + continue; + } + + auto& line = L; + TStringBuf sep = ""; + for (auto& shortName : opt->GetShortNames()) { + line << sep << "'-" << B(TStringBuf(&shortName, 1)) << "'"; + sep = "|"; + } + for (auto& longName: opt->GetLongNames()) { + line << sep << "'--" << B(longName) << "'"; + sep = "|"; + } + line << ")"; + { + I; + if (opt->Completer_ != nullptr) { + opt->Completer_->GenerateBash(out); + } + L << ";;"; + } + } + + L << "*)"; + { + I; + + L << "args=0"; + auto& line = L << "opts='@("; + TStringBuf sep = ""; + for (auto& opt : unorderedOpts) { if (opt->HasArg_ == EHasArg::NO_ARGUMENT || opt->IsHidden()) { - continue; - } - for (auto& shortName : opt->GetShortNames()) { - line << sep << "-" << B(TStringBuf(&shortName, 1)); - sep = "|"; - } - for (auto& longName: opt->GetLongNames()) { - line << sep << "--" << B(longName); - sep = "|"; - } - } - line << ")'"; - L << "for (( i=" << level << "; i < cword; i++ )); do"; - { - I; - L << "if [[ ${words[i]} != -* && ${words[i-1]} != $opts ]]; then"; - { - I; - L << "(( args++ ))"; - } - L << "fi"; - } - L << "done"; - L; - - auto argSpecs = opts.GetFreeArgSpecs(); - size_t numFreeArgs = opts.GetFreeArgsMax(); - bool unlimitedArgs = false; - if (numFreeArgs == TOpts::UNLIMITED_ARGS) { - numFreeArgs = argSpecs.empty() ? 0 : (argSpecs.rbegin()->first + 1); - unlimitedArgs = true; - } - - L << "case ${args} in"; - { - I; - - for (size_t i = 0; i < numFreeArgs; ++i) { - L << i << ")"; - { - I; - auto& spec = argSpecs[i]; - if (spec.Completer_ != nullptr) { - spec.Completer_->GenerateBash(out); - } - L << ";;"; - } - } - if (unlimitedArgs) { - L << "*)"; - { - I; - auto& spec = opts.GetTrailingArgSpec(); - if (spec.Completer_ != nullptr) { - spec.Completer_->GenerateBash(out); - } - L << ";;"; - } - } - } - L << "esac"; - L << ";;"; - } - } - L << "esac"; - } - L << "fi"; - } - - void TBashCompletionGenerator::GenerateDefaultOptsCompletion(TFormattedOutput& out, NComp::TCompleterManager&) { - L << "if [[ ${cur} == -* ]] ; then"; - { - I; - L << "COMPREPLY+=( $(compgen -W '-h --help --svnrevision' -- ${cur}) )"; - } - L << "fi"; - } - -#undef I -#undef L - - TString NEscaping::Q(TStringBuf string) { - TStringBuilder out; - out.reserve(string.size()); - for (auto c: string) { - switch (c) { - case '\a': - case '\b': - case '\f': - case '\n': - case '\r': - case '\t': - case '\v': - out << " "; - break; - case '\\': - out << "\\\\"; - break; - case '\'': - out << "''"; - break; - case '\"': - out << "\\\""; - break; - case '[': - out << "\\["; - break; - case ']': - out << "\\]"; - break; - case ':': - out << "\\:"; - break; - case '+': - out << "\\+"; - break; - case '=': - out << "\\="; - break; - default: - out << c; - break; - } - } - return out; - } - - TString NEscaping::QQ(TStringBuf string) { - auto q = Q(string); - return "'" + q + "'"; - } - - TString NEscaping::C(TStringBuf string) { - TStringBuilder out; - out.reserve(string.size() + 1); - for (auto c: string) { - switch (c) { - case '\a': - case '\b': - case '\f': - case '\n': - case '\r': - case '\t': - case '\v': - out << " "; - break; - case '\'': - out << "''"; - break; - case ':': - out << "\\:"; - break; - default: - out << c; - break; - } - } - return out; - } - - TString NEscaping::CC(TStringBuf string) { - auto c = C(string); - return "'" + c + "'"; - } - - TString NEscaping::S(TStringBuf string) { - TStringBuilder out; - out.reserve(string.size() + 1); - for (auto c: string) { - switch (c) { - case '\a': - case '\b': - case '\f': - case '\n': - case '\r': - case '\t': - case '\v': - out << " "; - break; - case '\'': - out << "''"; - break; - default: - out << c; - break; - } - } - return out; - } - - TString NEscaping::SS(TStringBuf string) { - auto s = S(string); - return "'" + s + "'"; - } - - TString NEscaping::B(TStringBuf string) { - TStringBuilder out; - out.reserve(string.size() + 1); - for (auto c: string) { - switch (c) { - case '\a': - case '\b': - case '\f': - case '\n': - case '\r': - case '\t': - case '\v': - out << " "; - break; - case '\'': - out << "'\"'\"'"; - break; - default: - out << c; - break; - } - } - return out; - } - - TString NEscaping::BB(TStringBuf string) { - auto b = B(string); - return "'" + b + "'"; - } -} + continue; + } + for (auto& shortName : opt->GetShortNames()) { + line << sep << "-" << B(TStringBuf(&shortName, 1)); + sep = "|"; + } + for (auto& longName: opt->GetLongNames()) { + line << sep << "--" << B(longName); + sep = "|"; + } + } + line << ")'"; + L << "for (( i=" << level << "; i < cword; i++ )); do"; + { + I; + L << "if [[ ${words[i]} != -* && ${words[i-1]} != $opts ]]; then"; + { + I; + L << "(( args++ ))"; + } + L << "fi"; + } + L << "done"; + L; + + auto argSpecs = opts.GetFreeArgSpecs(); + size_t numFreeArgs = opts.GetFreeArgsMax(); + bool unlimitedArgs = false; + if (numFreeArgs == TOpts::UNLIMITED_ARGS) { + numFreeArgs = argSpecs.empty() ? 0 : (argSpecs.rbegin()->first + 1); + unlimitedArgs = true; + } + + L << "case ${args} in"; + { + I; + + for (size_t i = 0; i < numFreeArgs; ++i) { + L << i << ")"; + { + I; + auto& spec = argSpecs[i]; + if (spec.Completer_ != nullptr) { + spec.Completer_->GenerateBash(out); + } + L << ";;"; + } + } + if (unlimitedArgs) { + L << "*)"; + { + I; + auto& spec = opts.GetTrailingArgSpec(); + if (spec.Completer_ != nullptr) { + spec.Completer_->GenerateBash(out); + } + L << ";;"; + } + } + } + L << "esac"; + L << ";;"; + } + } + L << "esac"; + } + L << "fi"; + } + + void TBashCompletionGenerator::GenerateDefaultOptsCompletion(TFormattedOutput& out, NComp::TCompleterManager&) { + L << "if [[ ${cur} == -* ]] ; then"; + { + I; + L << "COMPREPLY+=( $(compgen -W '-h --help --svnrevision' -- ${cur}) )"; + } + L << "fi"; + } + +#undef I +#undef L + + TString NEscaping::Q(TStringBuf string) { + TStringBuilder out; + out.reserve(string.size()); + for (auto c: string) { + switch (c) { + case '\a': + case '\b': + case '\f': + case '\n': + case '\r': + case '\t': + case '\v': + out << " "; + break; + case '\\': + out << "\\\\"; + break; + case '\'': + out << "''"; + break; + case '\"': + out << "\\\""; + break; + case '[': + out << "\\["; + break; + case ']': + out << "\\]"; + break; + case ':': + out << "\\:"; + break; + case '+': + out << "\\+"; + break; + case '=': + out << "\\="; + break; + default: + out << c; + break; + } + } + return out; + } + + TString NEscaping::QQ(TStringBuf string) { + auto q = Q(string); + return "'" + q + "'"; + } + + TString NEscaping::C(TStringBuf string) { + TStringBuilder out; + out.reserve(string.size() + 1); + for (auto c: string) { + switch (c) { + case '\a': + case '\b': + case '\f': + case '\n': + case '\r': + case '\t': + case '\v': + out << " "; + break; + case '\'': + out << "''"; + break; + case ':': + out << "\\:"; + break; + default: + out << c; + break; + } + } + return out; + } + + TString NEscaping::CC(TStringBuf string) { + auto c = C(string); + return "'" + c + "'"; + } + + TString NEscaping::S(TStringBuf string) { + TStringBuilder out; + out.reserve(string.size() + 1); + for (auto c: string) { + switch (c) { + case '\a': + case '\b': + case '\f': + case '\n': + case '\r': + case '\t': + case '\v': + out << " "; + break; + case '\'': + out << "''"; + break; + default: + out << c; + break; + } + } + return out; + } + + TString NEscaping::SS(TStringBuf string) { + auto s = S(string); + return "'" + s + "'"; + } + + TString NEscaping::B(TStringBuf string) { + TStringBuilder out; + out.reserve(string.size() + 1); + for (auto c: string) { + switch (c) { + case '\a': + case '\b': + case '\f': + case '\n': + case '\r': + case '\t': + case '\v': + out << " "; + break; + case '\'': + out << "'\"'\"'"; + break; + default: + out << c; + break; + } + } + return out; + } + + TString NEscaping::BB(TStringBuf string) { + auto b = B(string); + return "'" + b + "'"; + } +} |