$search
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