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 | b6f3a80f7c2c8b7dbb0c01b056fdc1fd8cd820e9 (patch) | |
tree | 5d5cb817648f650d76cf1076100726fd9b8448e8 /library/cpp/getopt/small/completer.cpp | |
parent | 8879605a63ac17539be5b3bd41b529791f4d4b02 (diff) | |
download | ydb-b6f3a80f7c2c8b7dbb0c01b056fdc1fd8cd820e9.tar.gz |
Restoring authorship annotation for <amatanhead@yandex-team.ru>. Commit 2 of 2.
Diffstat (limited to 'library/cpp/getopt/small/completer.cpp')
-rw-r--r-- | library/cpp/getopt/small/completer.cpp | 724 |
1 files changed, 362 insertions, 362 deletions
diff --git a/library/cpp/getopt/small/completer.cpp b/library/cpp/getopt/small/completer.cpp index 0536e4cccf..3fff684adb 100644 --- a/library/cpp/getopt/small/completer.cpp +++ b/library/cpp/getopt/small/completer.cpp @@ -1,367 +1,367 @@ -#include "completer.h" - -#include "completion_generator.h" - -#include <util/string/cast.h> -#include <util/generic/fwd.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::NComp { -#define L out.Line() -#define I auto Y_GENERATE_UNIQUE_ID(indent) = out.Indent() - - TCompleterManager::TCompleterManager(TStringBuf command) - : Command_(command) - , Id_(0) - { - } - - TStringBuf TCompleterManager::GetCompleterID(const ICompleter* completer) { - return Queue_.emplace_back(TStringBuilder() << "_" << Command_ << "__completer_" << ++Id_, completer).first; - } - - void TCompleterManager::GenerateZsh(TFormattedOutput& out) { - while (!Queue_.empty()) { - auto[name, completer] = Queue_.back(); - Queue_.pop_back(); - - L << "(( $+functions[" << name << "] )) ||"; - L << name << "() {"; - { - I; - completer->GenerateZsh(out, *this); - } - L << "}"; - L; - } - } - - class TAlternativeCompleter: public ICompleter { - public: - TAlternativeCompleter(TVector<TAlternative> alternatives) - : Alternatives_(std::move(alternatives)) - { - } - - void GenerateBash(TFormattedOutput& out) const override { - for (auto& alternative: Alternatives_) { - if (alternative.Completer != nullptr) { - alternative.Completer->GenerateBash(out); - } - } - } - - TStringBuf GenerateZshAction(TCompleterManager& manager) const override { - return manager.GetCompleterID(this); - } - - void GenerateZsh(TFormattedOutput& out, TCompleterManager& manager) const override { - // We should use '_alternative' here, but it doesn't process escape codes in group descriptions, - // so we dispatch alternatives ourselves. - - L << "local expl action"; - - size_t i = 0; - for (auto& alternative: Alternatives_) { - auto tag = "alt-" + ToString(++i); - auto action = alternative.Completer ? alternative.Completer->GenerateZshAction(manager) : TStringBuf(); - - L; - - if (action.empty()) { - L << "_message -e " << SS(tag) << " " << SS(alternative.Description); - } else if (action.StartsWith("((") && action.EndsWith("))")) { - L << "action=" << action.substr(1, action.size() - 2); - L << "_describe -t " << SS(tag) << " " << SS(alternative.Description) << " action -M 'r:|[_-]=* r:|=*'"; - } else if (action.StartsWith("(") && action.EndsWith(")")) { - L << "action=" << action << ""; - L << "_describe -t " << SS(tag) << " " << SS(alternative.Description) << " action -M 'r:|[_-]=* r:|=*'"; - } else if (action.StartsWith(' ')) { - L << action.substr(1); - } else { - L << "_description " << SS(tag) << " expl " << SS(alternative.Description); - TStringBuf word, args; - action.Split(' ', word, args); - L << word << " \"${expl[@]}\" " << args; - } - } - } - - private: - TVector<TAlternative> Alternatives_; - }; - - ICompleterPtr Alternative(TVector<TAlternative> alternatives) { - return MakeSimpleShared<TAlternativeCompleter>(std::move(alternatives)); - } - - class TSimpleCompleter: public ICompleter { - public: - TSimpleCompleter(TString bashCode, TString action) - : BashCode(std::move(bashCode)) - , Action(std::move(action)) - { - } - - void GenerateBash(TFormattedOutput& out) const override { - if (BashCode) { - L << BashCode; - } - } - - TStringBuf GenerateZshAction(TCompleterManager&) const override { - return Action; - } - - void GenerateZsh(TFormattedOutput&, TCompleterManager&) const override { - Y_FAIL("unreachable"); - } - - private: - TString BashCode; - TString Action; - }; - - ICompleterPtr Choice(TVector<TChoice> choices) { - auto bash = TStringBuilder() << "COMPREPLY+=( $(compgen -W '"; - TStringBuf sep = ""; - for (auto& choice : choices) { - bash << sep << B(choice.Choice); - sep = " "; - } - bash << "' -- ${cur}) )"; - - auto action = TStringBuilder(); - action << "(("; - for (auto& choice: choices) { - action << " " << SS(choice.Choice); - if (choice.Description) {{ - action << ":" << SS(choice.Description); - }} - } - action << "))"; - return MakeSimpleShared<TSimpleCompleter>(bash, action); - } - - TString Compgen(TStringBuf flags) { - return TStringBuilder() << "COMPREPLY+=( $(compgen " << flags << " -- ${cur}) )"; - } - - ICompleterPtr Default() { - return MakeSimpleShared<TSimpleCompleter>("", "_default"); - } - - ICompleterPtr File(TString pattern) { - if (pattern) { - pattern = " -g " + SS(pattern); - } - return MakeSimpleShared<TSimpleCompleter>("", "_files" + pattern); - } - - ICompleterPtr Directory() { - return MakeSimpleShared<TSimpleCompleter>("", "_files -/"); - } - - ICompleterPtr Host() { - return MakeSimpleShared<TSimpleCompleter>(Compgen("-A hostname"), "_hosts"); - } - - ICompleterPtr Pid() { - return MakeSimpleShared<TSimpleCompleter>("", "_pids"); - } - - ICompleterPtr User() { - return MakeSimpleShared<TSimpleCompleter>(Compgen("-A user"), "_users"); - } - - ICompleterPtr Group() { - // For some reason, OSX freezes when trying to perform completion for groups. - // You can try removing this ifdef and debugging it, but be prepared to force-shutdown your machine - // (and possibly reinstall OSX if force-shutdown breaks anything). -#ifdef _darwin_ - return MakeSimpleShared<TSimpleCompleter>("", ""); -#else - return MakeSimpleShared<TSimpleCompleter>(Compgen("-A group"), "_groups"); -#endif - } - - ICompleterPtr Url() { - return MakeSimpleShared<TSimpleCompleter>("", "_urls"); - } - - ICompleterPtr Tty() { - return MakeSimpleShared<TSimpleCompleter>("", "_ttys"); - } - - ICompleterPtr NetInterface() { - return MakeSimpleShared<TSimpleCompleter>("", "_net_interfaces"); - } - - ICompleterPtr TimeZone() { - return MakeSimpleShared<TSimpleCompleter>("", "_time_zone"); - } - - ICompleterPtr Signal() { - return MakeSimpleShared<TSimpleCompleter>(Compgen("-A signal"), "_signals"); - } - - ICompleterPtr Domain() { - return MakeSimpleShared<TSimpleCompleter>("", "_domains"); - } - - namespace { - TCustomCompleter* Head = nullptr; +#include "completer.h" + +#include "completion_generator.h" + +#include <util/string/cast.h> +#include <util/generic/fwd.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::NComp { +#define L out.Line() +#define I auto Y_GENERATE_UNIQUE_ID(indent) = out.Indent() + + TCompleterManager::TCompleterManager(TStringBuf command) + : Command_(command) + , Id_(0) + { + } + + TStringBuf TCompleterManager::GetCompleterID(const ICompleter* completer) { + return Queue_.emplace_back(TStringBuilder() << "_" << Command_ << "__completer_" << ++Id_, completer).first; + } + + void TCompleterManager::GenerateZsh(TFormattedOutput& out) { + while (!Queue_.empty()) { + auto[name, completer] = Queue_.back(); + Queue_.pop_back(); + + L << "(( $+functions[" << name << "] )) ||"; + L << name << "() {"; + { + I; + completer->GenerateZsh(out, *this); + } + L << "}"; + L; + } + } + + class TAlternativeCompleter: public ICompleter { + public: + TAlternativeCompleter(TVector<TAlternative> alternatives) + : Alternatives_(std::move(alternatives)) + { + } + + void GenerateBash(TFormattedOutput& out) const override { + for (auto& alternative: Alternatives_) { + if (alternative.Completer != nullptr) { + alternative.Completer->GenerateBash(out); + } + } + } + + TStringBuf GenerateZshAction(TCompleterManager& manager) const override { + return manager.GetCompleterID(this); + } + + void GenerateZsh(TFormattedOutput& out, TCompleterManager& manager) const override { + // We should use '_alternative' here, but it doesn't process escape codes in group descriptions, + // so we dispatch alternatives ourselves. + + L << "local expl action"; + + size_t i = 0; + for (auto& alternative: Alternatives_) { + auto tag = "alt-" + ToString(++i); + auto action = alternative.Completer ? alternative.Completer->GenerateZshAction(manager) : TStringBuf(); + + L; + + if (action.empty()) { + L << "_message -e " << SS(tag) << " " << SS(alternative.Description); + } else if (action.StartsWith("((") && action.EndsWith("))")) { + L << "action=" << action.substr(1, action.size() - 2); + L << "_describe -t " << SS(tag) << " " << SS(alternative.Description) << " action -M 'r:|[_-]=* r:|=*'"; + } else if (action.StartsWith("(") && action.EndsWith(")")) { + L << "action=" << action << ""; + L << "_describe -t " << SS(tag) << " " << SS(alternative.Description) << " action -M 'r:|[_-]=* r:|=*'"; + } else if (action.StartsWith(' ')) { + L << action.substr(1); + } else { + L << "_description " << SS(tag) << " expl " << SS(alternative.Description); + TStringBuf word, args; + action.Split(' ', word, args); + L << word << " \"${expl[@]}\" " << args; + } + } + } + + private: + TVector<TAlternative> Alternatives_; + }; + + ICompleterPtr Alternative(TVector<TAlternative> alternatives) { + return MakeSimpleShared<TAlternativeCompleter>(std::move(alternatives)); + } + + class TSimpleCompleter: public ICompleter { + public: + TSimpleCompleter(TString bashCode, TString action) + : BashCode(std::move(bashCode)) + , Action(std::move(action)) + { + } + + void GenerateBash(TFormattedOutput& out) const override { + if (BashCode) { + L << BashCode; + } + } + + TStringBuf GenerateZshAction(TCompleterManager&) const override { + return Action; + } + + void GenerateZsh(TFormattedOutput&, TCompleterManager&) const override { + Y_FAIL("unreachable"); + } + + private: + TString BashCode; + TString Action; + }; + + ICompleterPtr Choice(TVector<TChoice> choices) { + auto bash = TStringBuilder() << "COMPREPLY+=( $(compgen -W '"; + TStringBuf sep = ""; + for (auto& choice : choices) { + bash << sep << B(choice.Choice); + sep = " "; + } + bash << "' -- ${cur}) )"; + + auto action = TStringBuilder(); + action << "(("; + for (auto& choice: choices) { + action << " " << SS(choice.Choice); + if (choice.Description) {{ + action << ":" << SS(choice.Description); + }} + } + action << "))"; + return MakeSimpleShared<TSimpleCompleter>(bash, action); + } + + TString Compgen(TStringBuf flags) { + return TStringBuilder() << "COMPREPLY+=( $(compgen " << flags << " -- ${cur}) )"; + } + + ICompleterPtr Default() { + return MakeSimpleShared<TSimpleCompleter>("", "_default"); + } + + ICompleterPtr File(TString pattern) { + if (pattern) { + pattern = " -g " + SS(pattern); + } + return MakeSimpleShared<TSimpleCompleter>("", "_files" + pattern); + } + + ICompleterPtr Directory() { + return MakeSimpleShared<TSimpleCompleter>("", "_files -/"); + } + + ICompleterPtr Host() { + return MakeSimpleShared<TSimpleCompleter>(Compgen("-A hostname"), "_hosts"); + } + + ICompleterPtr Pid() { + return MakeSimpleShared<TSimpleCompleter>("", "_pids"); + } + + ICompleterPtr User() { + return MakeSimpleShared<TSimpleCompleter>(Compgen("-A user"), "_users"); + } + + ICompleterPtr Group() { + // For some reason, OSX freezes when trying to perform completion for groups. + // You can try removing this ifdef and debugging it, but be prepared to force-shutdown your machine + // (and possibly reinstall OSX if force-shutdown breaks anything). +#ifdef _darwin_ + return MakeSimpleShared<TSimpleCompleter>("", ""); +#else + return MakeSimpleShared<TSimpleCompleter>(Compgen("-A group"), "_groups"); +#endif + } + + ICompleterPtr Url() { + return MakeSimpleShared<TSimpleCompleter>("", "_urls"); + } + + ICompleterPtr Tty() { + return MakeSimpleShared<TSimpleCompleter>("", "_ttys"); + } + + ICompleterPtr NetInterface() { + return MakeSimpleShared<TSimpleCompleter>("", "_net_interfaces"); + } + + ICompleterPtr TimeZone() { + return MakeSimpleShared<TSimpleCompleter>("", "_time_zone"); + } + + ICompleterPtr Signal() { + return MakeSimpleShared<TSimpleCompleter>(Compgen("-A signal"), "_signals"); + } + + ICompleterPtr Domain() { + return MakeSimpleShared<TSimpleCompleter>("", "_domains"); + } + + namespace { + TCustomCompleter* Head = nullptr; TStringBuf SpecialFlag = "---CUSTOM-COMPLETION---"; - } - - void TCustomCompleter::FireCustomCompleter(int argc, const char** argv) { - if (!argc) { - return; - } - - for (int i = 1; i < argc - 4; ++i) { - if (SpecialFlag == argv[i]) { - auto name = TStringBuf(argv[i + 1]); - auto curIdx = FromString<int>(argv[i + 2]); - auto prefix = TStringBuf(argv[i + 3]); - auto suffix = TStringBuf(argv[i + 4]); - - auto cur = TStringBuf(); - if (0 <= curIdx && curIdx < i) { - cur = TStringBuf(argv[curIdx]); - } - if (cur && !prefix && !suffix) { - prefix = cur; // bash does not send prefix and suffix - } - - auto head = Head; - while (head) { - if (head->GetUniqueName() == name) { - head->GenerateCompletions(i, argv, curIdx, cur, prefix, suffix); - } - head = head->Next_; - } - - exit(0); - } - } - } - - void TCustomCompleter::RegisterCustomCompleter(TCustomCompleter* completer) noexcept { - Y_VERIFY(completer); - completer->Next_ = Head; - Head = completer; - } - - void TCustomCompleter::AddCompletion(TStringBuf completion) { - Cout << completion << Endl; // this was easy =) - // TODO: support option descriptions and messages - } - - void TMultipartCustomCompleter::GenerateCompletions(int argc, const char** argv, int curIdx, TStringBuf cur, TStringBuf prefix, TStringBuf suffix) { - auto root = TStringBuf(); - if (prefix.Contains(Sep_)) { - auto tmp = TStringBuf(); - prefix.RSplit(Sep_, root, tmp); - } - - if (root) { - Cout << root << Sep_ << Endl; - } else { - Cout << Endl; - } - - Cout << Sep_ << Endl; - - GenerateCompletionParts(argc, argv, curIdx, cur, prefix, suffix, root); - } - - class TLaunchSelf: public ICompleter { - public: - TLaunchSelf(TCustomCompleter* completer) - : Completer_(completer) - { - } - - void GenerateBash(TFormattedOutput& out) const override { - L << "IFS=$'\\n'"; + } + + void TCustomCompleter::FireCustomCompleter(int argc, const char** argv) { + if (!argc) { + return; + } + + for (int i = 1; i < argc - 4; ++i) { + if (SpecialFlag == argv[i]) { + auto name = TStringBuf(argv[i + 1]); + auto curIdx = FromString<int>(argv[i + 2]); + auto prefix = TStringBuf(argv[i + 3]); + auto suffix = TStringBuf(argv[i + 4]); + + auto cur = TStringBuf(); + if (0 <= curIdx && curIdx < i) { + cur = TStringBuf(argv[curIdx]); + } + if (cur && !prefix && !suffix) { + prefix = cur; // bash does not send prefix and suffix + } + + auto head = Head; + while (head) { + if (head->GetUniqueName() == name) { + head->GenerateCompletions(i, argv, curIdx, cur, prefix, suffix); + } + head = head->Next_; + } + + exit(0); + } + } + } + + void TCustomCompleter::RegisterCustomCompleter(TCustomCompleter* completer) noexcept { + Y_VERIFY(completer); + completer->Next_ = Head; + Head = completer; + } + + void TCustomCompleter::AddCompletion(TStringBuf completion) { + Cout << completion << Endl; // this was easy =) + // TODO: support option descriptions and messages + } + + void TMultipartCustomCompleter::GenerateCompletions(int argc, const char** argv, int curIdx, TStringBuf cur, TStringBuf prefix, TStringBuf suffix) { + auto root = TStringBuf(); + if (prefix.Contains(Sep_)) { + auto tmp = TStringBuf(); + prefix.RSplit(Sep_, root, tmp); + } + + if (root) { + Cout << root << Sep_ << Endl; + } else { + Cout << Endl; + } + + Cout << Sep_ << Endl; + + GenerateCompletionParts(argc, argv, curIdx, cur, prefix, suffix, root); + } + + class TLaunchSelf: public ICompleter { + public: + TLaunchSelf(TCustomCompleter* completer) + : Completer_(completer) + { + } + + void GenerateBash(TFormattedOutput& out) const override { + L << "IFS=$'\\n'"; L << "COMPREPLY+=( $(compgen -W \"$(${words[@]} " << SpecialFlag << " " << Completer_->GetUniqueName() << " \"${cword}\" \"\" \"\" 2> /dev/null)\" -- ${cur}) )"; - L << "IFS=$' \\t\\n'"; - } - - TStringBuf GenerateZshAction(TCompleterManager& manager) const override { - return manager.GetCompleterID(this); - } - - void GenerateZsh(TFormattedOutput& out, TCompleterManager&) const override { + L << "IFS=$' \\t\\n'"; + } + + TStringBuf GenerateZshAction(TCompleterManager& manager) const override { + return manager.GetCompleterID(this); + } + + void GenerateZsh(TFormattedOutput& out, TCompleterManager&) const override { L << "compadd ${@} ${expl[@]} -- \"${(@f)$(${words_orig[@]} " << SpecialFlag << " " << Completer_->GetUniqueName() << " \"${current_orig}\" \"${prefix_orig}\" \"${suffix_orig}\" 2> /dev/null)}\""; - } - - private: - TCustomCompleter* Completer_; - }; - - ICompleterPtr LaunchSelf(TCustomCompleter& completer) { - return MakeSimpleShared<TLaunchSelf>(&completer); - } - - class TLaunchSelfMultiPart: public ICompleter { - public: - TLaunchSelfMultiPart(TCustomCompleter* completer) - : Completer_(completer) - { - } - - void GenerateBash(TFormattedOutput& out) const override { - L << "IFS=$'\\n'"; + } + + private: + TCustomCompleter* Completer_; + }; + + ICompleterPtr LaunchSelf(TCustomCompleter& completer) { + return MakeSimpleShared<TLaunchSelf>(&completer); + } + + class TLaunchSelfMultiPart: public ICompleter { + public: + TLaunchSelfMultiPart(TCustomCompleter* completer) + : Completer_(completer) + { + } + + void GenerateBash(TFormattedOutput& out) const override { + L << "IFS=$'\\n'"; L << "items=( $(${words[@]} " << SpecialFlag << " " << Completer_->GetUniqueName() << " \"${cword}\" \"\" \"\" 2> /dev/null) )"; - L << "candidates=$(compgen -W \"${items[*]:1}\" -- \"$cur\")"; - L << "COMPREPLY+=( $candidates )"; - L << "[[ $candidates == *\"${items[1]}\" ]] && need_space=\"\""; - L << "IFS=$' \\t\\n'"; - } - - TStringBuf GenerateZshAction(TCompleterManager& manager) const override { - return manager.GetCompleterID(this); - } - - void GenerateZsh(TFormattedOutput& out, TCompleterManager&) const override { + L << "candidates=$(compgen -W \"${items[*]:1}\" -- \"$cur\")"; + L << "COMPREPLY+=( $candidates )"; + L << "[[ $candidates == *\"${items[1]}\" ]] && need_space=\"\""; + L << "IFS=$' \\t\\n'"; + } + + TStringBuf GenerateZshAction(TCompleterManager& manager) const override { + return manager.GetCompleterID(this); + } + + void GenerateZsh(TFormattedOutput& out, TCompleterManager&) const override { L << "local items=( \"${(@f)$(${words_orig[@]} " << SpecialFlag << " " << Completer_->GetUniqueName() << " \"${current_orig}\" \"${prefix_orig}\" \"${suffix_orig}\" 2> /dev/null)}\" )"; - L; - L << "local rempat=${items[1]}"; - L << "shift items"; - L; - L << "local sep=${items[1]}"; - L << "shift items"; - L; - L << "local files=( ${items:#*\"${sep}\"} )"; - L << "local filenames=( ${files#\"${rempat}\"} )"; - L << "local dirs=( ${(M)items:#*\"${sep}\"} )"; - L << "local dirnames=( ${dirs#\"${rempat}\"} )"; - L; - L << "local need_suf"; - L << "compset -S \"${sep}*\" || need_suf=\"1\""; - L; - L << "compadd ${@} ${expl[@]} -d filenames -- ${(q)files}"; - L << "compadd ${@} ${expl[@]} ${need_suf:+-S\"${sep}\"} -q -d dirnames -- ${(q)dirs%\"${sep}\"}"; - } - - private: - TCustomCompleter* Completer_; - }; - - ICompleterPtr LaunchSelfMultiPart(TCustomCompleter& completer) { - return MakeSimpleShared<TLaunchSelfMultiPart>(&completer); - } - -#undef I -#undef L -} + L; + L << "local rempat=${items[1]}"; + L << "shift items"; + L; + L << "local sep=${items[1]}"; + L << "shift items"; + L; + L << "local files=( ${items:#*\"${sep}\"} )"; + L << "local filenames=( ${files#\"${rempat}\"} )"; + L << "local dirs=( ${(M)items:#*\"${sep}\"} )"; + L << "local dirnames=( ${dirs#\"${rempat}\"} )"; + L; + L << "local need_suf"; + L << "compset -S \"${sep}*\" || need_suf=\"1\""; + L; + L << "compadd ${@} ${expl[@]} -d filenames -- ${(q)files}"; + L << "compadd ${@} ${expl[@]} ${need_suf:+-S\"${sep}\"} -q -d dirnames -- ${(q)dirs%\"${sep}\"}"; + } + + private: + TCustomCompleter* Completer_; + }; + + ICompleterPtr LaunchSelfMultiPart(TCustomCompleter& completer) { + return MakeSimpleShared<TLaunchSelfMultiPart>(&completer); + } + +#undef I +#undef L +} |