123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306 |
- #pragma once
- #include "formatted_output.h"
- #include <util/generic/strbuf.h>
- #include <util/generic/hash.h>
- #include <utility>
- #include <util/generic/fwd.h>
- namespace NLastGetopt::NComp {
- class ICompleter;
- class TCompleterManager {
- public:
- TCompleterManager(TStringBuf command);
- /// Register new completer and get its function name.
- TStringBuf GetCompleterID(const ICompleter* completer);
- /// Generate zsh code for all collected completers.
- void GenerateZsh(TFormattedOutput& out);
- private:
- TStringBuf Command_;
- size_t Id_;
- TVector<std::pair<TString, const ICompleter*>> Queue_;
- };
- class ICompleter {
- public:
- virtual ~ICompleter() = default;
- public:
- /// Generate arbitrary bash code that modifies `COMPREPLY`.
- virtual void GenerateBash(TFormattedOutput& out) const = 0;
- /// Generate action that will be used with `_arguments`. If this completer requires a separate function,
- /// register it in the given manager and return function name assigned by manager.
- /// Supported forms are '()', '(items...)', '((items...))', 'command ...' and ' command ...'.
- /// Other forms, such as '{eval-string}', '->state', '=action' are not supported.
- virtual TStringBuf GenerateZshAction(TCompleterManager& manager) const = 0;
- /// Generate body of a zsh function (if Action points to a custom function).
- virtual void GenerateZsh(TFormattedOutput& out, TCompleterManager& manager) const = 0;
- };
- using ICompleterPtr = TSimpleSharedPtr<ICompleter>;
- /// Generate default completions.
- /// Output of this completer depends on shell settings.
- /// Usually ut generates file paths.
- ICompleterPtr Default();
- struct TAlternative {
- /// Description for this group of completions. Leave empty to use completer's default description.
- TString Description;
- /// Completer that generates values
- ICompleterPtr Completer;
- TAlternative(ICompleterPtr completer)
- : Description("")
- , Completer(std::move(completer))
- {
- }
- TAlternative(TString description, ICompleterPtr completer)
- : Description(std::move(description))
- , Completer(std::move(completer))
- {
- }
- };
- /// Run multiple completers and unite their output.
- /// Each completer's output placed in a separate group with its own description.
- ICompleterPtr Alternative(TVector<TAlternative> alternatives);
- struct TChoice {
- /// Option value.
- TString Choice;
- /// Description for a value.
- TString Description = "";
- TChoice(TString choice)
- : Choice(std::move(choice))
- {
- }
- TChoice(TString choice, TString description)
- : Choice(std::move(choice))
- , Description(std::move(description))
- {
- }
- };
- /// Complete items from a predefined list of choices.
- ICompleterPtr Choice(TVector<TChoice> choices);
- /// Complete files and directories. May filter results by pattern, e.g. `*.txt`.
- ICompleterPtr File(TString pattern= "");
- /// Complete directories.
- ICompleterPtr Directory();
- /// Complete hosts.
- ICompleterPtr Host();
- /// Complete process IDs.
- ICompleterPtr Pid();
- /// Complete users that're found in the system.
- ICompleterPtr User();
- /// Complete user groups that're found in the system.
- /// N: for some reason,
- ICompleterPtr Group();
- /// Complete URLs.
- ICompleterPtr Url();
- /// Complete TTY interfaces.
- ICompleterPtr Tty();
- /// Complete network interfaces.
- ICompleterPtr NetInterface();
- /// Complete timezone identifiers.
- ICompleterPtr TimeZone();
- /// Complete unix signal identifiers, e.g. `ABRT` or `KILL`.
- ICompleterPtr Signal();
- /// Complete domains.
- ICompleterPtr Domain();
- /// Custom completer. See `LaunchSelf` below.
- class TCustomCompleter {
- public:
- static void FireCustomCompleter(int argc, const char** argv);
- static void RegisterCustomCompleter(TCustomCompleter* completer) noexcept;
- struct TReg {
- TReg(TCustomCompleter* completer) noexcept {
- TCustomCompleter::RegisterCustomCompleter(completer);
- }
- };
- public:
- virtual ~TCustomCompleter() = default;
- public:
- /// @param argc total number of command line arguments.
- /// @param argv array of command line arguments.
- /// @param curIdx index of the currently completed argument, may be equal to `argc` if cursor is at the end
- /// of line.
- /// @param cur currently completed argument.
- /// @param prefix part of the currently completed argument before the cursor.
- /// @param suffix part of the currently completed argument after the cursor.
- virtual void GenerateCompletions(int argc, const char** argv, int curIdx, TStringBuf cur, TStringBuf prefix, TStringBuf suffix) = 0;
- virtual TStringBuf GetUniqueName() const = 0;
- protected:
- void AddCompletion(TStringBuf completion);
- private:
- TCustomCompleter* Next_ = nullptr;
- };
- /// Custom completer for objects that consist of multiple parts split by a common separator, such as file paths.
- class TMultipartCustomCompleter: public TCustomCompleter {
- public:
- TMultipartCustomCompleter(TStringBuf sep)
- : Sep_(sep)
- {
- Y_ABORT_UNLESS(!Sep_.empty());
- }
- public:
- void GenerateCompletions(int argc, const char** argv, int curIdx, TStringBuf cur, TStringBuf prefix, TStringBuf suffix) final;
- public:
- /// @param argc same as in `GenerateCompletions`.
- /// @param argv same as in `GenerateCompletions`.
- /// @param curIdx same as in `GenerateCompletions`.
- /// @param cur same as in `GenerateCompletions`.
- /// @param prefix same as in `GenerateCompletions`.
- /// @param suffix same as in `GenerateCompletions`.
- /// @param root part of the currently completed argument before the last separator.
- virtual void GenerateCompletionParts(int argc, const char** argv, int curIdx, TStringBuf cur, TStringBuf prefix, TStringBuf suffix, TStringBuf root) = 0;
- protected:
- TStringBuf Sep_;
- };
- #define Y_COMPLETER(N) \
- class T##N: public ::NLastGetopt::NComp::TCustomCompleter { \
- public: \
- void GenerateCompletions(int, const char**, int, TStringBuf, TStringBuf, TStringBuf) override; \
- TStringBuf GetUniqueName() const override { return #N; } \
- }; \
- T##N N = T##N(); \
- ::NLastGetopt::NComp::TCustomCompleter::TReg _Reg_##N = &N; \
- void T##N::GenerateCompletions( \
- Y_DECLARE_UNUSED int argc, \
- Y_DECLARE_UNUSED const char** argv, \
- Y_DECLARE_UNUSED int curIdx, \
- Y_DECLARE_UNUSED TStringBuf cur, \
- Y_DECLARE_UNUSED TStringBuf prefix, \
- Y_DECLARE_UNUSED TStringBuf suffix)
- #define Y_MULTIPART_COMPLETER(N, SEP) \
- class T##N: public ::NLastGetopt::NComp::TMultipartCustomCompleter { \
- public: \
- T##N() : ::NLastGetopt::NComp::TMultipartCustomCompleter(SEP) {} \
- void GenerateCompletionParts(int, const char**, int, TStringBuf, TStringBuf, TStringBuf, TStringBuf) override; \
- TStringBuf GetUniqueName() const override { return #N; } \
- }; \
- T##N N = T##N(); \
- ::NLastGetopt::NComp::TCustomCompleter::TReg _Reg_##N = &N; \
- void T##N::GenerateCompletionParts( \
- Y_DECLARE_UNUSED int argc, \
- Y_DECLARE_UNUSED const char** argv, \
- Y_DECLARE_UNUSED int curIdx, \
- Y_DECLARE_UNUSED TStringBuf cur, \
- Y_DECLARE_UNUSED TStringBuf prefix, \
- Y_DECLARE_UNUSED TStringBuf suffix, \
- Y_DECLARE_UNUSED TStringBuf root)
- /// Launches this binary with a specially formed flags and retrieves completions from stdout.
- ///
- /// Your application must be set up in a certain way for this to work.
- ///
- /// First, create a custom completer:
- ///
- /// ```
- /// Y_COMPLETER(SomeUniqueName) {
- /// AddCompletion("foo");
- /// AddCompletion("bar");
- /// AddCompletion("baz");
- /// }
- /// ```
- ///
- /// Then, use it with this function.
- ///
- /// On completion attempt, completer will call your binary with some special arguments.
- ///
- /// In your main, before any other logic, call `TCustomCompleter::FireCustomCompleter`. This function will
- /// check for said special arguments and invoke the right completer:
- ///
- /// ```
- /// int main(int argc, const char** argv) {
- /// TCustomCompleter::FireCustomCompleter(argc, argv);
- /// ...
- /// }
- /// ```
- ICompleterPtr LaunchSelf(TCustomCompleter& completer);
- /// Launches this binary with a specially formed flags and retrieves completions from stdout.
- ///
- /// Your application must be set up in a certain way for this to work. See `LaunchSelf` for more info.
- ///
- /// Multipart completion is designed for objects that consist of multiple parts split by a common separator.
- /// It is ideal for completing remote file paths, for example.
- ///
- /// Multipart completers format stdout in the following way.
- ///
- /// On the first line, they print a common prefix that should be stripped from all completions. For example,
- /// if you complete paths, this prefix would be a common directory.
- ///
- /// On the second line, they print a separator. If some completion ends with this separator, shell will not add
- /// a whitespace after the item is completed. For example, if you complete paths, the separator would be a slash.
- ///
- /// On the following lines, they print completions, as formed by the `AddCompletion` function.
- ///
- /// For example, if a user invokes completion like this:
- ///
- /// ```
- /// $ program //home/logs/<tab><tab>
- /// ```
- ///
- /// The stdout might look like this:
- ///
- /// ```
- /// //home/logs/
- /// /
- /// //home/logs/access-log
- /// //home/logs/redir-log
- /// //home/logs/blockstat-log
- /// ```
- ///
- /// Then autocompletion will look like this:
- ///
- /// ```
- /// $ program //home/logs/<tab><tab>
- /// -- yt path --
- /// access-log redir-log blockstat-log
- /// ```
- ///
- /// Note: stdout lines with completion suggestions *must* be formatted by the `AddCompletion` function
- /// because their format may change in the future.
- ///
- /// Note: we recommend using `Y_MULTIPART_COMPLETER` because it will handle all stdout printing for you.
- ICompleterPtr LaunchSelfMultiPart(TCustomCompleter& completer);
- }
|