tclap  1.2.0
ZshCompletionOutput.h
Go to the documentation of this file.
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 reverved.
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 
44 {
45 
46  public:
47 
49 
55  virtual void usage(CmdLineInterface& c);
56 
62  virtual void version(CmdLineInterface& c);
63 
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;
84 };
85 
87 {
88  common["host"] = "_hosts";
89  common["hostname"] = "_hosts";
90  common["file"] = "_files";
91  common["filename"] = "_files";
92  common["user"] = "_users";
93  common["username"] = "_users";
94  common["directory"] = "_directories";
95  common["path"] = "_directories";
96  common["url"] = "_urls";
97 }
98 
100 {
101  std::cout << _cmd.getVersion() << std::endl;
102 }
103 
105 {
106  std::list<Arg*> argList = _cmd.getArgList();
107  std::string progName = _cmd.getProgramName();
108  std::string version = _cmd.getVersion();
109  theDelimiter = _cmd.getDelimiter();
110  basename(progName);
111 
112  std::cout << "#compdef " << progName << std::endl << std::endl <<
113  "# " << progName << " version " << _cmd.getVersion() << std::endl << std::endl <<
114  "_arguments -s -S";
115 
116  for (ArgListIterator it = argList.begin(); it != argList.end(); it++)
117  {
118  if ( (*it)->shortID().at(0) == '<' )
119  printArg((*it));
120  else if ( (*it)->getFlag() != "-" )
121  printOption((*it), getMutexList(_cmd, *it));
122  }
123 
124  std::cout << std::endl;
125 }
126 
128  ArgException& e )
129 {
130  static_cast<void>(_cmd); // unused
131  std::cout << e.what() << std::endl;
132 }
133 
134 inline void ZshCompletionOutput::quoteSpecialChars( std::string& s )
135 {
136  size_t idx = s.find_last_of(':');
137  while ( idx != std::string::npos )
138  {
139  s.insert(idx, 1, '\\');
140  idx = s.find_last_of(':', idx);
141  }
142  idx = s.find_last_of('\'');
143  while ( idx != std::string::npos )
144  {
145  s.insert(idx, "'\\'");
146  if (idx == 0)
147  idx = std::string::npos;
148  else
149  idx = s.find_last_of('\'', --idx);
150  }
151 }
152 
153 inline void ZshCompletionOutput::basename( std::string& s )
154 {
155  size_t p = s.find_last_of('/');
156  if ( p != std::string::npos )
157  {
158  s.erase(0, p + 1);
159  }
160 }
161 
163 {
164  static int count = 1;
165 
166  std::cout << " \\" << std::endl << " '";
167  if ( a->acceptsMultipleValues() )
168  std::cout << '*';
169  else
170  std::cout << count++;
171  std::cout << ':';
172  if ( !a->isRequired() )
173  std::cout << ':';
174 
175  std::cout << a->getName() << ':';
176  std::map<std::string, std::string>::iterator compArg = common.find(a->getName());
177  if ( compArg != common.end() )
178  {
179  std::cout << compArg->second;
180  }
181  else
182  {
183  std::cout << "_guard \"^-*\" " << a->getName();
184  }
185  std::cout << '\'';
186 }
187 
188 inline void ZshCompletionOutput::printOption(Arg* a, std::string mutex)
189 {
190  std::string flag = a->flagStartChar() + a->getFlag();
191  std::string name = a->nameStartString() + a->getName();
192  std::string desc = a->getDescription();
193 
194  // remove full stop and capitalisation from description as
195  // this is the convention for zsh function
196  if (!desc.compare(0, 12, "(required) "))
197  {
198  desc.erase(0, 12);
199  }
200  if (!desc.compare(0, 15, "(OR required) "))
201  {
202  desc.erase(0, 15);
203  }
204  size_t len = desc.length();
205  if (len && desc.at(--len) == '.')
206  {
207  desc.erase(len);
208  }
209  if (len)
210  {
211  desc.replace(0, 1, 1, tolower(desc.at(0)));
212  }
213 
214  std::cout << " \\" << std::endl << " '" << mutex;
215 
216  if ( a->getFlag().empty() )
217  {
218  std::cout << name;
219  }
220  else
221  {
222  std::cout << "'{" << flag << ',' << name << "}'";
223  }
224  if ( theDelimiter == '=' && a->isValueRequired() )
225  std::cout << "=-";
226  quoteSpecialChars(desc);
227  std::cout << '[' << desc << ']';
228 
229  if ( a->isValueRequired() )
230  {
231  std::string arg = a->shortID();
232  arg.erase(0, arg.find_last_of(theDelimiter) + 1);
233  if ( arg.at(arg.length()-1) == ']' )
234  arg.erase(arg.length()-1);
235  if ( arg.at(arg.length()-1) == ']' )
236  {
237  arg.erase(arg.length()-1);
238  }
239  if ( arg.at(0) == '<' )
240  {
241  arg.erase(arg.length()-1);
242  arg.erase(0, 1);
243  }
244  size_t p = arg.find('|');
245  if ( p != std::string::npos )
246  {
247  do
248  {
249  arg.replace(p, 1, 1, ' ');
250  }
251  while ( (p = arg.find_first_of('|', p)) != std::string::npos );
252  quoteSpecialChars(arg);
253  std::cout << ": :(" << arg << ')';
254  }
255  else
256  {
257  std::cout << ':' << arg;
258  std::map<std::string, std::string>::iterator compArg = common.find(arg);
259  if ( compArg != common.end() )
260  {
261  std::cout << ':' << compArg->second;
262  }
263  }
264  }
265 
266  std::cout << '\'';
267 }
268 
270 {
271  XorHandler xorHandler = _cmd.getXorHandler();
272  std::vector< std::vector<Arg*> > xorList = xorHandler.getXorList();
273 
274  if (a->getName() == "help" || a->getName() == "version")
275  {
276  return "(-)";
277  }
278 
279  std::ostringstream list;
280  if ( a->acceptsMultipleValues() )
281  {
282  list << '*';
283  }
284 
285  for ( int i = 0; static_cast<unsigned int>(i) < xorList.size(); i++ )
286  {
287  for ( ArgVectorIterator it = xorList[i].begin();
288  it != xorList[i].end();
289  it++)
290  if ( a == (*it) )
291  {
292  list << '(';
293  for ( ArgVectorIterator iu = xorList[i].begin();
294  iu != xorList[i].end();
295  iu++ )
296  {
297  bool notCur = (*iu) != a;
298  bool hasFlag = !(*iu)->getFlag().empty();
299  if ( iu != xorList[i].begin() && (notCur || hasFlag) )
300  list << ' ';
301  if (hasFlag)
302  list << (*iu)->flagStartChar() << (*iu)->getFlag() << ' ';
303  if ( notCur || hasFlag )
304  list << (*iu)->nameStartString() << (*iu)->getName();
305  }
306  list << ')';
307  return list.str();
308  }
309  }
310 
311  // wasn't found in xor list
312  if (!a->getFlag().empty()) {
313  list << "(" << a->flagStartChar() << a->getFlag() << ' ' <<
314  a->nameStartString() << a->getName() << ')';
315  }
316 
317  return list.str();
318 }
319 
320 } //namespace TCLAP
321 #endif