From 3e70af604d45f1115c4f5aaf92d240545178ab5a Mon Sep 17 00:00:00 2001 From: mes5k Date: Sun, 4 Mar 2007 19:28:57 +0000 Subject: [PATCH] added patches for ZSH and DocBook output --- examples/test4.cpp | 4 + include/tclap/DocBookOutput.h | 128 ++++++----- include/tclap/Makefile.am | 1 + include/tclap/ZshCompletionOutput.h | 318 ++++++++++++++++++++++++++++ 4 files changed, 398 insertions(+), 53 deletions(-) create mode 100644 include/tclap/ZshCompletionOutput.h diff --git a/examples/test4.cpp b/examples/test4.cpp index 7a9dfb2..a1dd88e 100644 --- a/examples/test4.cpp +++ b/examples/test4.cpp @@ -1,6 +1,8 @@ #include "tclap/CmdLine.h" +#include "tclap/DocBookOutput.h" +#include "tclap/ZshCompletionOutput.h" #include #include @@ -65,6 +67,8 @@ void parseOptions(int argc, char** argv) // set the output MyOutput my; + //ZshCompletionOutput my; + //DocBookOutput my; cmd.setOutput(&my); // diff --git a/include/tclap/DocBookOutput.h b/include/tclap/DocBookOutput.h index 5dbfb26..86f8090 100644 --- a/include/tclap/DocBookOutput.h +++ b/include/tclap/DocBookOutput.h @@ -78,9 +78,12 @@ class DocBookOutput : public CmdLineOutput */ void substituteSpecialChars( std::string& s, char r, std::string& x ); void removeChar( std::string& s, char r); + void basename( std::string& s ); void printShortArg(Arg* it); void printLongArg(Arg* it); + + char theDelimiter; }; @@ -94,30 +97,28 @@ inline void DocBookOutput::usage(CmdLineInterface& _cmd ) std::list argList = _cmd.getArgList(); std::string progName = _cmd.getProgramName(); std::string version = _cmd.getVersion(); + theDelimiter = _cmd.getDelimiter(); XorHandler xorHandler = _cmd.getXorHandler(); std::vector< std::vector > xorList = xorHandler.getXorList(); - + basename(progName); std::cout << "" << std::endl; - std::cout << "" << std::endl << std::endl; - std::cout << "" << std::endl; std::cout << "" << std::endl; std::cout << "" << std::endl; - std::cout << "" << std::endl; - std::cout << progName << std::endl; - std::cout << "" << std::endl; + std::cout << "" << progName << "" << std::endl; std::cout << "1" << std::endl; std::cout << "" << std::endl; std::cout << "" << std::endl; - std::cout << "" << std::endl; - std::cout << progName << std::endl; - std::cout << "" << std::endl; + std::cout << "" << progName << "" << std::endl; + std::cout << "" << _cmd.getMessage() << "" << std::endl; std::cout << "" << std::endl; + std::cout << "" << std::endl; std::cout << "" << std::endl; std::cout << "" << progName << "" << std::endl; @@ -139,6 +140,7 @@ inline void DocBookOutput::usage(CmdLineInterface& _cmd ) printShortArg((*it)); std::cout << "" << std::endl; + std::cout << "" << std::endl; std::cout << "" << std::endl; std::cout << "Description" << std::endl; @@ -149,32 +151,13 @@ inline void DocBookOutput::usage(CmdLineInterface& _cmd ) std::cout << "" << std::endl; std::cout << "Options" << std::endl; - std::cout << "" << std::endl; - std::cout << "" << std::endl; - // xor - for ( int i = 0; (unsigned int)i < xorList.size(); i++ ) - { - std::cout << "" << std::endl; - size_t xlen = xorList.size() - 1; - size_t xcount = 0; - for ( ArgVectorIterator it = xorList[i].begin(); - it != xorList[i].end(); it++, xcount++ ) - { - printLongArg((*it)); - if ( xcount < xlen ) - std::cout << "OR" << std::endl; - } - std::cout << "" << std::endl; - } + std::cout << "" << std::endl; - // rest of args for (ArgListIterator it = argList.begin(); it != argList.end(); it++) - if ( !xorHandler.contains( (*it) ) ) - printLongArg((*it)); + printLongArg((*it)); - std::cout << "" << std::endl; - std::cout << "" << std::endl; + std::cout << "" << std::endl; std::cout << "" << std::endl; std::cout << "" << std::endl; @@ -185,7 +168,6 @@ inline void DocBookOutput::usage(CmdLineInterface& _cmd ) std::cout << "" << std::endl; std::cout << "" << std::endl; - std::cout << "" << std::endl; } @@ -217,6 +199,15 @@ inline void DocBookOutput::removeChar( std::string& s, char r) } } +inline void DocBookOutput::basename( std::string& s ) +{ + size_t p = s.find_last_of('/'); + if ( p != std::string::npos ) + { + s.erase(0, p + 1); + } +} + inline void DocBookOutput::printShortArg(Arg* a) { std::string lt = "<"; @@ -230,17 +221,30 @@ inline void DocBookOutput::printShortArg(Arg* a) std::string choice = "opt"; if ( a->isRequired() ) - choice = "req"; + choice = "plain"; - std::string repeat = "norepeat"; + std::cout << "acceptsMultipleValues() ) - repeat = "repeat"; + std::cout << " rep='repeat'"; - - - std::cout << "" - << id << "" << std::endl; + + std::cout << '>'; + if ( !a->getFlag().empty() ) + std::cout << a->flagStartChar() << a->getFlag(); + else + std::cout << a->nameStartString() << a->getName(); + if ( a->isValueRequired() ) + { + std::string arg = a->shortID(); + removeChar(arg,'['); + removeChar(arg,']'); + removeChar(arg,'<'); + removeChar(arg,'>'); + arg.erase(0, arg.find_last_of(theDelimiter) + 1); + std::cout << theDelimiter; + std::cout << "" << arg << ""; + } + std::cout << "" << std::endl; } @@ -249,27 +253,45 @@ inline void DocBookOutput::printLongArg(Arg* a) std::string lt = "<"; std::string gt = ">"; - std::string id = a->longID(); - substituteSpecialChars(id,'<',lt); - substituteSpecialChars(id,'>',gt); - removeChar(id,'['); - removeChar(id,']'); - std::string desc = a->getDescription(); substituteSpecialChars(desc,'<',lt); substituteSpecialChars(desc,'>',gt); - std::cout << "" << std::endl; + std::cout << "" << std::endl; - std::cout << "" << std::endl; - std::cout << id << std::endl; - std::cout << "" << std::endl; + if ( !a->getFlag().empty() ) + { + std::cout << "" << std::endl; + std::cout << "" << std::endl; + std::cout << "" << std::endl; + } - std::cout << "" << std::endl; + std::cout << "" << std::endl; + std::cout << "" << std::endl; + std::cout << "" << std::endl; + + std::cout << "" << std::endl; + std::cout << "" << std::endl; std::cout << desc << std::endl; - std::cout << "" << std::endl; + std::cout << "" << std::endl; + std::cout << "" << std::endl; - std::cout << "" << std::endl; + std::cout << "" << std::endl; } } //namespace TCLAP diff --git a/include/tclap/Makefile.am b/include/tclap/Makefile.am index a406942..7a2c350 100644 --- a/include/tclap/Makefile.am +++ b/include/tclap/Makefile.am @@ -19,6 +19,7 @@ libtclapinclude_HEADERS = \ CmdLineOutput.h \ StdOutput.h \ DocBookOutput.h \ + ZshCompletionOutput.h \ OptionalUnlabeledTracker.h \ Constraint.h \ ValuesConstraint.h diff --git a/include/tclap/ZshCompletionOutput.h b/include/tclap/ZshCompletionOutput.h new file mode 100644 index 0000000..2aaff04 --- /dev/null +++ b/include/tclap/ZshCompletionOutput.h @@ -0,0 +1,318 @@ +/****************************************************************************** + * + * file: ZshCompletionOutput.h + * + * Copyright (c) 2006, Oliver Kiddle + * All rights reverved. + * + * See the file COPYING in the top directory of this distribution for + * more information. + * + * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + *****************************************************************************/ + +#ifndef TCLAP_ZSHCOMPLETIONOUTPUT_H +#define TCLAP_ZSHCOMPLETIONOUTPUT_H + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace TCLAP { + +/** + * A class that generates a Zsh completion function as output from the usage() + * method for the given CmdLine and its Args. + */ +class ZshCompletionOutput : public CmdLineOutput +{ + + public: + + ZshCompletionOutput(); + + /** + * Prints the usage to stdout. Can be overridden to + * produce alternative behavior. + * \param c - The CmdLine object the output is generated for. + */ + virtual void usage(CmdLineInterface& c); + + /** + * Prints the version to stdout. Can be overridden + * to produce alternative behavior. + * \param c - The CmdLine object the output is generated for. + */ + virtual void version(CmdLineInterface& c); + + /** + * Prints (to stderr) an error message, short usage + * Can be overridden to produce alternative behavior. + * \param c - The CmdLine object the output is generated for. + * \param e - The ArgException that caused the failure. + */ + virtual void failure(CmdLineInterface& c, + ArgException& e ); + + protected: + + void basename( std::string& s ); + void quoteSpecialChars( std::string& s ); + + std::string getMutexList( CmdLineInterface& _cmd, Arg* a ); + void printOption( Arg* it, std::string mutex ); + void printArg( Arg* it ); + + std::map common; + char theDelimiter; +}; + +ZshCompletionOutput::ZshCompletionOutput() +{ + common["host"] = "_hosts"; + common["hostname"] = "_hosts"; + common["file"] = "_files"; + common["filename"] = "_files"; + common["user"] = "_users"; + common["username"] = "_users"; + common["directory"] = "_directories"; + common["path"] = "_directories"; + common["url"] = "_urls"; +} + +inline void ZshCompletionOutput::version(CmdLineInterface& _cmd) +{ + std::cout << _cmd.getVersion() << std::endl; +} + +inline void ZshCompletionOutput::usage(CmdLineInterface& _cmd ) +{ + std::list argList = _cmd.getArgList(); + std::string progName = _cmd.getProgramName(); + std::string version = _cmd.getVersion(); + theDelimiter = _cmd.getDelimiter(); + basename(progName); + + std::cout << "#compdef " << progName << std::endl << std::endl << + "# " << progName << " version " << _cmd.getVersion() << std::endl << std::endl << + "_arguments -s -S"; + + for (ArgListIterator it = argList.begin(); it != argList.end(); it++) + { + if ( (*it)->shortID().at(0) == '<' ) + printArg((*it)); + else if ( (*it)->getFlag() != "-" ) + printOption((*it), getMutexList(_cmd, *it)); + } + + std::cout << std::endl; +} + +inline void ZshCompletionOutput::failure( CmdLineInterface& _cmd, + ArgException& e ) +{ + std::cout << e.what() << std::endl; +} + +inline void ZshCompletionOutput::quoteSpecialChars( std::string& s ) +{ + size_t idx = s.find_last_of(':'); + while ( idx != std::string::npos ) + { + s.insert(idx, 1, '\\'); + idx = s.find_last_of(':', idx); + } + idx = s.find_last_of('\''); + while ( idx != std::string::npos ) + { + s.insert(idx, "'\\'"); + if (idx == 0) + idx = std::string::npos; + else + idx = s.find_last_of('\'', --idx); + } +} + +inline void ZshCompletionOutput::basename( std::string& s ) +{ + size_t p = s.find_last_of('/'); + if ( p != std::string::npos ) + { + s.erase(0, p + 1); + } +} + +inline void ZshCompletionOutput::printArg(Arg* a) +{ + static int count = 1; + + std::cout << " \\" << std::endl << " '"; + if ( a->acceptsMultipleValues() ) + std::cout << '*'; + else + std::cout << count++; + std::cout << ':'; + if ( !a->isRequired() ) + std::cout << ':'; + + std::cout << a->getName() << ':'; + std::map::iterator compArg = common.find(a->getName()); + if ( compArg != common.end() ) + { + std::cout << compArg->second; + } + else + { + std::cout << "_guard \"^-*\" " << a->getName(); + } + std::cout << '\''; +} + +inline void ZshCompletionOutput::printOption(Arg* a, std::string mutex) +{ + std::string flag = a->flagStartChar() + a->getFlag(); + std::string name = a->nameStartString() + a->getName(); + std::string desc = a->getDescription(); + + // remove full stop and capitalisation from description as + // this is the convention for zsh function + if (!desc.compare(0, 12, "(required) ")) + { + desc.erase(0, 12); + } + if (!desc.compare(0, 15, "(OR required) ")) + { + desc.erase(0, 15); + } + size_t len = desc.length(); + if (len && desc.at(--len) == '.') + { + desc.erase(len); + } + if (len) + { + desc.replace(0, 1, 1, tolower(desc.at(0))); + } + + std::cout << " \\" << std::endl << " '" << mutex; + + if ( a->getFlag().empty() ) + { + std::cout << name; + } + else + { + std::cout << "'{" << flag << ',' << name << "}'"; + } + if ( theDelimiter == '=' && a->isValueRequired() ) + std::cout << "=-"; + quoteSpecialChars(desc); + std::cout << '[' << desc << ']'; + + if ( a->isValueRequired() ) + { + std::string arg = a->shortID(); + arg.erase(0, arg.find_last_of(theDelimiter) + 1); + if ( arg.at(arg.length()-1) == ']' ) + arg.erase(arg.length()-1); + if ( arg.at(arg.length()-1) == ']' ) + { + arg.erase(arg.length()-1); + } + if ( arg.at(0) == '<' ) + { + arg.erase(arg.length()-1); + arg.erase(0, 1); + } + size_t p = arg.find('|'); + if ( p != std::string::npos ) + { + do + { + arg.replace(p, 1, 1, ' '); + } + while ( (p = arg.find_first_of('|', p)) != std::string::npos ); + quoteSpecialChars(arg); + std::cout << ": :(" << arg << ')'; + } + else + { + std::cout << ':' << arg; + std::map::iterator compArg = common.find(arg); + if ( compArg != common.end() ) + { + std::cout << ':' << compArg->second; + } + } + } + + std::cout << '\''; +} + +inline std::string ZshCompletionOutput::getMutexList( CmdLineInterface& _cmd, Arg* a) +{ + XorHandler xorHandler = _cmd.getXorHandler(); + std::vector< std::vector > xorList = xorHandler.getXorList(); + + if (a->getName() == "help" || a->getName() == "version") + { + return "(-)"; + } + + std::ostringstream list; + if ( a->acceptsMultipleValues() ) + { + list << '*'; + } + + for ( int i = 0; static_cast(i) < xorList.size(); i++ ) + { + for ( ArgVectorIterator it = xorList[i].begin(); + it != xorList[i].end(); + it++) + if ( a == (*it) ) + { + list << '('; + for ( ArgVectorIterator iu = xorList[i].begin(); + iu != xorList[i].end(); + iu++ ) + { + bool notCur = (*iu) != a; + bool hasFlag = !(*iu)->getFlag().empty(); + if ( iu != xorList[i].begin() && (notCur || hasFlag) ) + list << ' '; + if (hasFlag) + list << (*iu)->flagStartChar() << (*iu)->getFlag() << ' '; + if ( notCur || hasFlag ) + list << (*iu)->nameStartString() << (*iu)->getName(); + } + list << ')'; + return list.str(); + } + } + + // wasn't found in xor list + if (!a->getFlag().empty()) { + list << "(" << a->flagStartChar() << a->getFlag() << ' ' << + a->nameStartString() << a->getName() << ')'; + } + + return list.str(); +} + +} //namespace TCLAP +#endif