123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165 |
- #include "completer_command.h"
- #include "completion_generator.h"
- #include "last_getopt.h"
- #include "wrap.h"
- #include <library/cpp/colorizer/colors.h>
- #include <util/string/subst.h>
- namespace NLastGetopt {
- TString MakeInfo(TStringBuf command, TStringBuf flag) {
- TString info = (
- "This command generates shell script with completion function and prints it to `stdout`, "
- "allowing one to re-direct the output to the file of their choosing. "
- "Where you place the file will depend on which shell and operating system you are using."
- "\n"
- "\n"
- "\n"
- "{B}BASH (Linux){R}:"
- "\n"
- "\n"
- "For system-wide commands, completion files are stored in `/etc/bash_completion.d/`. "
- "For user commands, they are stored in `~/.local/share/bash-completion/completions`. "
- "So, pipe output of this script to a file in one of these directories:"
- "\n"
- "\n"
- " $ mkdir -p ~/.local/share/bash-completion/completions"
- "\n"
- " $ {command} {completion} bash >"
- "\n"
- " ~/.local/share/bash-completion/completions/{command}"
- "\n"
- "\n"
- "You'll need to restart your shell for changes to take effect."
- "\n"
- "\n"
- "\n"
- "{B}BASH (OSX){R}:"
- "\n"
- "\n"
- "You'll need `bash-completion` (or `bash-completion@2` if you're using non-default, newer bash) "
- "homebrew formula. Completion files are stored in `/usr/local/etc/bash_completion.d`:"
- "\n"
- "\n"
- " $ mkdir -p $(brew --prefix)/etc/bash_completion.d"
- "\n"
- " $ {command} {completion} bash >"
- "\n"
- " $(brew --prefix)/etc/bash_completion.d/{command}"
- "\n"
- "\n"
- "Alternatively, just source the script in your `~/.bash_profile`."
- "\n"
- "\n"
- "You'll need to restart your shell for changes to take effect."
- "\n"
- "\n"
- "\n"
- "{B}ZSH{R}:"
- "\n"
- "\n"
- "Zsh looks for completion scripts in any directory listed in `$fpath` variable. We recommend placing "
- "completions to `~/.zfunc`:"
- "\n"
- "\n"
- " $ mkdir -m755 -p ~/.zfunc"
- "\n"
- " $ {command} {completion} zsh > ~/.zfunc/_{command}"
- "\n"
- "\n"
- "Add the following lines to your `.zshrc` just before `compinit`:"
- "\n"
- "\n"
- " fpath+=~/.zfunc"
- "\n"
- "\n"
- "You'll need to restart your shell for changes to take effect.");
- SubstGlobal(info, "{command}", command);
- SubstGlobal(info, "{completion}", flag);
- SubstGlobal(info, "{B}", NColorizer::StdErr().LightDefault());
- SubstGlobal(info, "{R}", NColorizer::StdErr().Reset());
- return info;
- }
- NComp::ICompleterPtr ShellChoiceCompleter() {
- return NComp::Choice({{"zsh"}, {"bash"}});
- }
- TOpt MakeCompletionOpt(const TOpts* opts, TString command, TString name) {
- return TOpt()
- .AddLongName(name)
- .Help("generate tab completion script for zsh or bash")
- .CompletionHelp("generate tab completion script")
- .OptionalArgument("shell-syntax")
- .CompletionArgHelp("shell syntax for completion script")
- .IfPresentDisableCompletion()
- .Completer(ShellChoiceCompleter())
- .Handler1T<TString>([opts, command, name](TStringBuf shell) {
- if (shell.empty()) {
- Cerr << Wrap(80, MakeInfo(command, "--" + name)) << Endl;
- } else if (shell == "bash") {
- TBashCompletionGenerator(opts).Generate(command, Cout);
- } else if (shell == "zsh") {
- TZshCompletionGenerator(opts).Generate(command, Cout);
- } else {
- Cerr << "Unknown shell name " << TString{shell}.Quote() << Endl;
- exit(1);
- }
- exit(0);
- });
- }
- class TCompleterMode: public TMainClassArgs {
- public:
- TCompleterMode(const TModChooser* modChooser, TString command, TString modName)
- : Command_(std::move(command))
- , Modes_(modChooser)
- , ModName_(std::move(modName))
- {
- }
- protected:
- void RegisterOptions(NLastGetopt::TOpts& opts) override {
- TMainClassArgs::RegisterOptions(opts);
- opts.SetTitle("Generate tab completion scripts for zsh or bash");
- opts.AddSection("Description", MakeInfo(Command_, ModName_));
- opts.SetFreeArgsNum(1);
- opts.GetFreeArgSpec(0)
- .Title("<shell-syntax>")
- .Help("shell syntax for completion script (bash or zsh)")
- .CompletionArgHelp("shell syntax for completion script")
- .Completer(ShellChoiceCompleter());
- }
- int DoRun(NLastGetopt::TOptsParseResult&& parsedOptions) override {
- auto arg = parsedOptions.GetFreeArgs()[0];
- arg.to_lower();
- if (arg == "bash") {
- TBashCompletionGenerator(Modes_).Generate(Command_, Cout);
- } else if (arg == "zsh") {
- TZshCompletionGenerator(Modes_).Generate(Command_, Cout);
- } else {
- Cerr << "Unknown shell name " << arg.Quote() << Endl;
- parsedOptions.PrintUsage();
- return 1;
- }
- return 0;
- }
- private:
- TString Command_;
- const TModChooser* Modes_;
- TString ModName_;
- };
- THolder<TMainClassArgs> MakeCompletionMod(const TModChooser* modChooser, TString command, TString modName) {
- return MakeHolder<TCompleterMode>(modChooser, std::move(command), std::move(modName));
- }
- }
|