No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.
 
 
 

324 líneas
7.8 KiB

  1. // -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*-
  2. /******************************************************************************
  3. *
  4. * file: ZshCompletionOutput.h
  5. *
  6. * Copyright (c) 2006, Oliver Kiddle
  7. * All rights reverved.
  8. *
  9. * See the file COPYING in the top directory of this distribution for
  10. * more information.
  11. *
  12. * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS
  13. * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  14. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  15. * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  16. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  17. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  18. * DEALINGS IN THE SOFTWARE.
  19. *
  20. *****************************************************************************/
  21. #ifndef TCLAP_ZSHCOMPLETIONOUTPUT_H
  22. #define TCLAP_ZSHCOMPLETIONOUTPUT_H
  23. #include <string>
  24. #include <vector>
  25. #include <list>
  26. #include <iostream>
  27. #include <map>
  28. #include "CmdLineInterface.h"
  29. #include "CmdLineOutput.h"
  30. #include "XorHandler.h"
  31. #include "Arg.h"
  32. namespace TCLAP {
  33. /**
  34. * A class that generates a Zsh completion function as output from the usage()
  35. * method for the given CmdLine and its Args.
  36. */
  37. class ZshCompletionOutput : public CmdLineOutput
  38. {
  39. public:
  40. ZshCompletionOutput();
  41. /**
  42. * Prints the usage to stdout. Can be overridden to
  43. * produce alternative behavior.
  44. * \param c - The CmdLine object the output is generated for.
  45. */
  46. virtual void usage(CmdLineInterface& c);
  47. /**
  48. * Prints the version to stdout. Can be overridden
  49. * to produce alternative behavior.
  50. * \param c - The CmdLine object the output is generated for.
  51. */
  52. virtual void version(CmdLineInterface& c);
  53. /**
  54. * Prints (to stderr) an error message, short usage
  55. * Can be overridden to produce alternative behavior.
  56. * \param c - The CmdLine object the output is generated for.
  57. * \param e - The ArgException that caused the failure.
  58. */
  59. virtual void failure(CmdLineInterface& c,
  60. ArgException& e );
  61. protected:
  62. void basename( std::string& s );
  63. void quoteSpecialChars( std::string& s );
  64. std::string getMutexList( CmdLineInterface& _cmd, Arg* a );
  65. void printOption( Arg* it, std::string mutex );
  66. void printArg( Arg* it );
  67. std::map<std::string, std::string> common;
  68. char theDelimiter;
  69. };
  70. ZshCompletionOutput::ZshCompletionOutput()
  71. : common(std::map<std::string, std::string>()),
  72. theDelimiter('=')
  73. {
  74. common["host"] = "_hosts";
  75. common["hostname"] = "_hosts";
  76. common["file"] = "_files";
  77. common["filename"] = "_files";
  78. common["user"] = "_users";
  79. common["username"] = "_users";
  80. common["directory"] = "_directories";
  81. common["path"] = "_directories";
  82. common["url"] = "_urls";
  83. }
  84. inline void ZshCompletionOutput::version(CmdLineInterface& _cmd)
  85. {
  86. std::cout << _cmd.getVersion() << std::endl;
  87. }
  88. inline void ZshCompletionOutput::usage(CmdLineInterface& _cmd )
  89. {
  90. std::list<Arg*> argList = _cmd.getArgList();
  91. std::string progName = _cmd.getProgramName();
  92. std::string xversion = _cmd.getVersion();
  93. theDelimiter = _cmd.getDelimiter();
  94. basename(progName);
  95. std::cout << "#compdef " << progName << std::endl << std::endl <<
  96. "# " << progName << " version " << _cmd.getVersion() << std::endl << std::endl <<
  97. "_arguments -s -S";
  98. for (ArgListIterator it = argList.begin(); it != argList.end(); it++)
  99. {
  100. if ( (*it)->shortID().at(0) == '<' )
  101. printArg((*it));
  102. else if ( (*it)->getFlag() != "-" )
  103. printOption((*it), getMutexList(_cmd, *it));
  104. }
  105. std::cout << std::endl;
  106. }
  107. inline void ZshCompletionOutput::failure( CmdLineInterface& _cmd,
  108. ArgException& e )
  109. {
  110. static_cast<void>(_cmd); // unused
  111. std::cout << e.what() << std::endl;
  112. }
  113. inline void ZshCompletionOutput::quoteSpecialChars( std::string& s )
  114. {
  115. size_t idx = s.find_last_of(':');
  116. while ( idx != std::string::npos )
  117. {
  118. s.insert(idx, 1, '\\');
  119. idx = s.find_last_of(':', idx);
  120. }
  121. idx = s.find_last_of('\'');
  122. while ( idx != std::string::npos )
  123. {
  124. s.insert(idx, "'\\'");
  125. if (idx == 0)
  126. idx = std::string::npos;
  127. else
  128. idx = s.find_last_of('\'', --idx);
  129. }
  130. }
  131. inline void ZshCompletionOutput::basename( std::string& s )
  132. {
  133. size_t p = s.find_last_of('/');
  134. if ( p != std::string::npos )
  135. {
  136. s.erase(0, p + 1);
  137. }
  138. }
  139. inline void ZshCompletionOutput::printArg(Arg* a)
  140. {
  141. static int count = 1;
  142. std::cout << " \\" << std::endl << " '";
  143. if ( a->acceptsMultipleValues() )
  144. std::cout << '*';
  145. else
  146. std::cout << count++;
  147. std::cout << ':';
  148. if ( !a->isRequired() )
  149. std::cout << ':';
  150. std::cout << a->getName() << ':';
  151. std::map<std::string, std::string>::iterator compArg = common.find(a->getName());
  152. if ( compArg != common.end() )
  153. {
  154. std::cout << compArg->second;
  155. }
  156. else
  157. {
  158. std::cout << "_guard \"^-*\" " << a->getName();
  159. }
  160. std::cout << '\'';
  161. }
  162. inline void ZshCompletionOutput::printOption(Arg* a, std::string mutex)
  163. {
  164. std::string flag = a->flagStartChar() + a->getFlag();
  165. std::string name = a->nameStartString() + a->getName();
  166. std::string desc = a->getDescription();
  167. // remove full stop and capitalisation from description as
  168. // this is the convention for zsh function
  169. if (!desc.compare(0, 12, "(required) "))
  170. {
  171. desc.erase(0, 12);
  172. }
  173. if (!desc.compare(0, 15, "(OR required) "))
  174. {
  175. desc.erase(0, 15);
  176. }
  177. size_t len = desc.length();
  178. if (len && desc.at(--len) == '.')
  179. {
  180. desc.erase(len);
  181. }
  182. if (len)
  183. {
  184. desc.replace(0, 1, 1, tolower(desc.at(0)));
  185. }
  186. std::cout << " \\" << std::endl << " '" << mutex;
  187. if ( a->getFlag().empty() )
  188. {
  189. std::cout << name;
  190. }
  191. else
  192. {
  193. std::cout << "'{" << flag << ',' << name << "}'";
  194. }
  195. if ( theDelimiter == '=' && a->isValueRequired() )
  196. std::cout << "=-";
  197. quoteSpecialChars(desc);
  198. std::cout << '[' << desc << ']';
  199. if ( a->isValueRequired() )
  200. {
  201. std::string arg = a->shortID();
  202. arg.erase(0, arg.find_last_of(theDelimiter) + 1);
  203. if ( arg.at(arg.length()-1) == ']' )
  204. arg.erase(arg.length()-1);
  205. if ( arg.at(arg.length()-1) == ']' )
  206. {
  207. arg.erase(arg.length()-1);
  208. }
  209. if ( arg.at(0) == '<' )
  210. {
  211. arg.erase(arg.length()-1);
  212. arg.erase(0, 1);
  213. }
  214. size_t p = arg.find('|');
  215. if ( p != std::string::npos )
  216. {
  217. do
  218. {
  219. arg.replace(p, 1, 1, ' ');
  220. }
  221. while ( (p = arg.find_first_of('|', p)) != std::string::npos );
  222. quoteSpecialChars(arg);
  223. std::cout << ": :(" << arg << ')';
  224. }
  225. else
  226. {
  227. std::cout << ':' << arg;
  228. std::map<std::string, std::string>::iterator compArg = common.find(arg);
  229. if ( compArg != common.end() )
  230. {
  231. std::cout << ':' << compArg->second;
  232. }
  233. }
  234. }
  235. std::cout << '\'';
  236. }
  237. inline std::string ZshCompletionOutput::getMutexList( CmdLineInterface& _cmd, Arg* a)
  238. {
  239. XorHandler xorHandler = _cmd.getXorHandler();
  240. std::vector< std::vector<Arg*> > xorList = xorHandler.getXorList();
  241. if (a->getName() == "help" || a->getName() == "version")
  242. {
  243. return "(-)";
  244. }
  245. std::ostringstream list;
  246. if ( a->acceptsMultipleValues() )
  247. {
  248. list << '*';
  249. }
  250. for ( int i = 0; static_cast<unsigned int>(i) < xorList.size(); i++ )
  251. {
  252. for ( ArgVectorIterator it = xorList[i].begin();
  253. it != xorList[i].end();
  254. it++)
  255. if ( a == (*it) )
  256. {
  257. list << '(';
  258. for ( ArgVectorIterator iu = xorList[i].begin();
  259. iu != xorList[i].end();
  260. iu++ )
  261. {
  262. bool notCur = (*iu) != a;
  263. bool hasFlag = !(*iu)->getFlag().empty();
  264. if ( iu != xorList[i].begin() && (notCur || hasFlag) )
  265. list << ' ';
  266. if (hasFlag)
  267. list << (*iu)->flagStartChar() << (*iu)->getFlag() << ' ';
  268. if ( notCur || hasFlag )
  269. list << (*iu)->nameStartString() << (*iu)->getName();
  270. }
  271. list << ')';
  272. return list.str();
  273. }
  274. }
  275. // wasn't found in xor list
  276. if (!a->getFlag().empty()) {
  277. list << "(" << a->flagStartChar() << a->getFlag() << ' ' <<
  278. a->nameStartString() << a->getName() << ')';
  279. }
  280. return list.str();
  281. }
  282. } //namespace TCLAP
  283. #endif