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