- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

# ZshCompletionOutput.h

Go to the documentation of this file.

    00001 // -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*-
    00002
    00003 /******************************************************************************
    00004  *
    00005  *  file:  ZshCompletionOutput.h
    00006  *
    00007  *  Copyright (c) 2006, Oliver Kiddle
    00008  *  All rights reverved.
    00009  *
    00010  *  See the file COPYING in the top directory of this distribution for
    00011  *  more information.
    00012  *
    00013  *  THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS
    00014  *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    00015  *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
    00016  *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    00017  *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    00018  *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
    00019  *  DEALINGS IN THE SOFTWARE.
    00020  *
    00021  *****************************************************************************/
    00022
    00023 #ifndef TCLAP_ZSHCOMPLETIONOUTPUT_H
    00024 #define TCLAP_ZSHCOMPLETIONOUTPUT_H
    00025
    00026 #include <string>
    00027 #include <vector>
    00028 #include <list>
    00029 #include <iostream>
    00030 #include <map>
    00031
    00032 #include <tclap/CmdLineInterface.h>
    00033 #include <tclap/CmdLineOutput.h>
    00034 #include <tclap/XorHandler.h>
    00035 #include <tclap/Arg.h>
    00036
    00037 namespace TCLAP {
    00038
    00043 class ZshCompletionOutput : public CmdLineOutput
    00044 {
    00045
    00046     public:
    00047
    00048         ZshCompletionOutput();
    00049
    00055         virtual void usage(CmdLineInterface& c);
    00056
    00062         virtual void version(CmdLineInterface& c);
    00063
    00070         virtual void failure(CmdLineInterface& c,
    00071                              ArgException& e );
    00072
    00073     protected:
    00074
    00075         void basename( std::string& s );
    00076         void quoteSpecialChars( std::string& s );
    00077
    00078         std::string getMutexList( CmdLineInterface& _cmd, Arg* a );
    00079         void printOption( Arg* it, std::string mutex );
    00080         void printArg( Arg* it );
    00081
    00082         std::map<std::string, std::string> common;
    00083         char theDelimiter;
    00084 };
    00085
    00086 ZshCompletionOutput::ZshCompletionOutput()
    00087 : common(std::map<std::string, std::string>()),
    00088   theDelimiter('=')
    00089 {
    00090     common["host"] = "_hosts";
    00091     common["hostname"] = "_hosts";
    00092     common["file"] = "_files";
    00093     common["filename"] = "_files";
    00094     common["user"] = "_users";
    00095     common["username"] = "_users";
    00096     common["directory"] = "_directories";
    00097     common["path"] = "_directories";
    00098     common["url"] = "_urls";
    00099 }
    00100
    00101 inline void ZshCompletionOutput::version(CmdLineInterface& _cmd)
    00102 {
    00103     std::cout << _cmd.getVersion() << std::endl;
    00104 }
    00105
    00106 inline void ZshCompletionOutput::usage(CmdLineInterface& _cmd )
    00107 {
    00108     std::list<Arg*> argList = _cmd.getArgList();
    00109     std::string progName = _cmd.getProgramName();
    00110     std::string xversion = _cmd.getVersion();
    00111     theDelimiter = _cmd.getDelimiter();
    00112     basename(progName);
    00113
    00114     std::cout << "#compdef " << progName << std::endl << std::endl <<
    00115         "# " << progName << " version " << _cmd.getVersion() << std::endl << std::endl <<
    00116         "_arguments -s -S";
    00117
    00118     for (ArgListIterator it = argList.begin(); it != argList.end(); it++)
    00119     {
    00120         if ( (*it)->shortID().at(0) == '<' )
    00121             printArg((*it));
    00122         else if ( (*it)->getFlag() != "-" )
    00123             printOption((*it), getMutexList(_cmd, *it));
    00124     }
    00125
    00126     std::cout << std::endl;
    00127 }
    00128
    00129 inline void ZshCompletionOutput::failure( CmdLineInterface& _cmd,
    00130                                 ArgException& e )
    00131 {
    00132     static_cast<void>(_cmd); // unused
    00133     std::cout << e.what() << std::endl;
    00134 }
    00135
    00136 inline void ZshCompletionOutput::quoteSpecialChars( std::string& s )
    00137 {
    00138     size_t idx = s.find_last_of(':');
    00139     while ( idx != std::string::npos )
    00140     {
    00141         s.insert(idx, 1, '\\');
    00142         idx = s.find_last_of(':', idx);
    00143     }
    00144     idx = s.find_last_of('\'');
    00145     while ( idx != std::string::npos )
    00146     {
    00147         s.insert(idx, "'\\'");
    00148         if (idx == 0)
    00149             idx = std::string::npos;
    00150         else
    00151             idx = s.find_last_of('\'', --idx);
    00152     }
    00153 }
    00154
    00155 inline void ZshCompletionOutput::basename( std::string& s )
    00156 {
    00157     size_t p = s.find_last_of('/');
    00158     if ( p != std::string::npos )
    00159     {
    00160         s.erase(0, p + 1);
    00161     }
    00162 }
    00163
    00164 inline void ZshCompletionOutput::printArg(Arg* a)
    00165 {
    00166     static int count = 1;
    00167
    00168     std::cout << " \\" << std::endl << "  '";
    00169     if ( a->acceptsMultipleValues() )
    00170         std::cout << '*';
    00171     else
    00172         std::cout << count++;
    00173     std::cout << ':';
    00174     if ( !a->isRequired() )
    00175         std::cout << ':';
    00176
    00177     std::cout << a->getName() << ':';
    00178     std::map<std::string, std::string>::iterator compArg = common.find(a->getName());
    00179     if ( compArg != common.end() )
    00180     {
    00181         std::cout << compArg->second;
    00182     }
    00183     else
    00184     {
    00185         std::cout << "_guard \"^-*\" " << a->getName();
    00186     }
    00187     std::cout << '\'';
    00188 }
    00189
    00190 inline void ZshCompletionOutput::printOption(Arg* a, std::string mutex)
    00191 {
    00192     std::string flag = a->flagStartChar() + a->getFlag();
    00193     std::string name = a->nameStartString() + a->getName();
    00194     std::string desc = a->getDescription();
    00195
    00196     // remove full stop and capitalisation from description as
    00197     // this is the convention for zsh function
    00198     if (!desc.compare(0, 12, "(required)  "))
    00199     {
    00200         desc.erase(0, 12);
    00201     }
    00202     if (!desc.compare(0, 15, "(OR required)  "))
    00203     {
    00204         desc.erase(0, 15);
    00205     }
    00206     size_t len = desc.length();
    00207     if (len && desc.at(--len) == '.')
    00208     {
    00209         desc.erase(len);
    00210     }
    00211     if (len)
    00212     {
    00213         desc.replace(0, 1, 1, tolower(desc.at(0)));
    00214     }
    00215
    00216     std::cout << " \\" << std::endl << "  '" << mutex;
    00217
    00218     if ( a->getFlag().empty() )
    00219     {
    00220         std::cout << name;
    00221     }
    00222     else
    00223     {
    00224         std::cout << "'{" << flag << ',' << name << "}'";
    00225     }
    00226     if ( theDelimiter == '=' && a->isValueRequired() )
    00227         std::cout << "=-";
    00228     quoteSpecialChars(desc);
    00229     std::cout << '[' << desc << ']';
    00230
    00231     if ( a->isValueRequired() )
    00232     {
    00233         std::string arg = a->shortID();
    00234         arg.erase(0, arg.find_last_of(theDelimiter) + 1);
    00235         if ( arg.at(arg.length()-1) == ']' )
    00236             arg.erase(arg.length()-1);
    00237         if ( arg.at(arg.length()-1) == ']' )
    00238         {
    00239             arg.erase(arg.length()-1);
    00240         }
    00241         if ( arg.at(0) == '<' )
    00242         {
    00243             arg.erase(arg.length()-1);
    00244             arg.erase(0, 1);
    00245         }
    00246         size_t p = arg.find('|');
    00247         if ( p != std::string::npos )
    00248         {
    00249             do
    00250             {
    00251                 arg.replace(p, 1, 1, ' ');
    00252             }
    00253             while ( (p = arg.find_first_of('|', p)) != std::string::npos );
    00254             quoteSpecialChars(arg);
    00255             std::cout << ": :(" << arg << ')';
    00256         }
    00257         else
    00258         {
    00259             std::cout << ':' << arg;
    00260             std::map<std::string, std::string>::iterator compArg = common.find(arg);
    00261             if ( compArg != common.end() )
    00262             {
    00263                 std::cout << ':' << compArg->second;
    00264             }
    00265         }
    00266     }
    00267
    00268     std::cout << '\'';
    00269 }
    00270
    00271 inline std::string ZshCompletionOutput::getMutexList( CmdLineInterface& _cmd, Arg* a)
    00272 {
    00273     XorHandler xorHandler = _cmd.getXorHandler();
    00274     std::vector< std::vector<Arg*> > xorList = xorHandler.getXorList();
    00275
    00276     if (a->getName() == "help" || a->getName() == "version")
    00277     {
    00278         return "(-)";
    00279     }
    00280
    00281     std::ostringstream list;
    00282     if ( a->acceptsMultipleValues() )
    00283     {
    00284         list << '*';
    00285     }
    00286
    00287     for ( int i = 0; static_cast<unsigned int>(i) < xorList.size(); i++ )
    00288     {
    00289         for ( ArgVectorIterator it = xorList[i].begin();
    00290             it != xorList[i].end();
    00291             it++)
    00292         if ( a == (*it) )
    00293         {
    00294             list << '(';
    00295             for ( ArgVectorIterator iu = xorList[i].begin();
    00296                 iu != xorList[i].end();
    00297                 iu++ )
    00298             {
    00299                 bool notCur = (*iu) != a;
    00300                 bool hasFlag = !(*iu)->getFlag().empty();
    00301                 if ( iu != xorList[i].begin() && (notCur || hasFlag) )
    00302                     list << ' ';
    00303                 if (hasFlag)
    00304                     list << (*iu)->flagStartChar() << (*iu)->getFlag() << ' ';
    00305                 if ( notCur || hasFlag )
    00306                     list << (*iu)->nameStartString() << (*iu)->getName();
    00307             }
    00308             list << ')';
    00309             return list.str();
    00310         }
    00311     }
    00312
    00313     // wasn't found in xor list
    00314     if (!a->getFlag().empty()) {
    00315         list << "(" << a->flagStartChar() << a->getFlag() << ' ' <<
    00316             a->nameStartString() << a->getName() << ')';
    00317     }
    00318
    00319     return list.str();
    00320 }
    00321
    00322 } //namespace TCLAP
    00323 #endif