#include <boost/type_traits/is_same.hpp>
#include <boost/mpl/if.hpp>
#include <boost/utility.hpp>
+#include <boost/parameter/keyword.hpp>
+#include <boost/parameter/parameters.hpp>
#include "../config.hh"
#include "OverloadedCommand.hh"
-#include "ParseParameter.hh"
+#include "Traits.hh"
#include "../Utils/type_traits.hh"
#include "ParsedCommand.ih"
namespace senf {
namespace console {
+ namespace detail { class ArgumentInfoBase; }
+
+ /** \brief CommandOverload implementation with automatic argument parsing
+
+ ParsedCommandOverloadBase implements a CommandOverload implementation supporting automatic
+ parsing of arguments. This is \e not a node, it's a CommandOverload which is then added to
+ an OverloadedCommandNode instance.
+
+ Automatic argument parsing and return value processing consists of several components:
+ \li \ref overload_add Adding overload instances to the tree
+ \li (Advanced) \ref overload_parse
+ \li (Advanced) \ref overload_format
+
+ \section overload_add Adding argument parsing callbacks to the tree
+
+ Adding appropriate callbacks to the tree is very simple: just path a function pointer to
+ DirectoryNode::add() or a member function pointer to ScopedDirectory::add().
+ \code
+ std::string taskStatus(int id);
+
+ senf::console::root().add("taskStatus", &taskStatus);
+ \endcode
+
+ There are quite a number of additional parameters available to be set. These parameters are
+ documented in ParsedArgumentAttributor. Parameters are set by adding them as additional
+ calls after adding the node:
+
+ \code
+ senf::console::root().add("taskStatus", &taskStatus)
+ .doc("Query the current task status")
+ .arg( name = "id",
+ description = "numeric id of task to check, -1 for the current task."
+ default_value = -1 );
+ \endcode
+
+ You may also add an additional \c std::ostream & Argument as first argument to the
+ callback. If this argument is present, the stream connected to the console which issued the
+ command will be passed there. This allows writing arbitrary messages to the console.
+
+ Additionally, overloading is supported by registering multiple commands under the same
+ name. So, elaborating on above example:
+ \code
+ std::string taskStatus(int id);
+ std::string taskStatus(std::string const & name);
+
+ senf::console::root()
+ .add("taskStatus", static_cast<std::string (*)(int)>(&taskStatus))
+ .doc("Query the current task status")
+ .overloadDoc("Query status by id")
+ .arg( name = "id",
+ description = "numeric id of task to check, -1 for the current task."
+ default_value = -1 );
+ senf::console::root()
+ .add("taskStatus", static_cast<std::string (*)(std::string const &)>(&taskStatus))
+ .overloadDoc("Query status by name")
+ .arg( name = "name",
+ description = "name of task to check" );
+ \endcode
+
+ We can see here, that taking the address of an overloaded function requires a cast. If you
+ can give unique names to each of the C++ overloads (not the overloads in the console), you
+ should do so to make the unwieldy casts unnecessary.
+
+ \section overload_parse Custom parameter parsers
+
+ By default, parameters are parsed using \c boost::lexical_cast and therefore using \c
+ iostreams. This means, that any type which can be read from a stream can automatically be
+ used as argument type.
+
+ However, argument parsing can be configured by specializing
+ senf::console::ArgumentTraits. See that class for more information.
+
+ \section overload_format Custom return-value formatters
+
+ By default, return values are streamed to an ostream. This automatically allows any
+ streamable type to be used as return value. To add new types or customize the formating, the
+ senf::console::ReturnValueTraits template needs to be specialized for that type. See
+ that class for more information.
+
+ \ingroup console_commands
+ */
class ParsedCommandOverloadBase
: public CommandOverload
{
public:
typedef boost::intrusive_ptr<ParsedCommandOverloadBase> ptr;
- detail::ParameterInfoBase & arg(unsigned n) const;
- template <class Type> detail::ParameterInfo<Type> & arg(unsigned n) const;
+ detail::ArgumentInfoBase & arg(unsigned n) const;
+ template <class Type> detail::ArgumentInfo<Type> & arg(unsigned n) const;
void doc(std::string const & d);
virtual void v_argumentDoc(unsigned index, ArgumentDoc & doc) const;
virtual std::string v_doc() const;
- typedef std::vector<detail::ParameterInfoBase::ptr> Parameters;
+ typedef std::vector<detail::ArgumentInfoBase::ptr> Parameters;
Parameters parameters_;
std::string doc_;
};
+ /** \brief Parsed command overload
+
+ ParsedCommandOverload provides the command overload added to an OverloadedCommandNode for an
+ automatically parsed command.
+
+ This class is normally instantiated automatically when adding a function or member-function
+ pointer as callback to the tree. Manually instantiation this type of overload is \e not
+ simple, since the function signature has to be manipulated correctly to support the optional
+ \c std::ostream first argument.
+
+ \implementation This class is specialized for each supported number of command arguments.
+ */
template <class FunctionTraits, unsigned arity=FunctionTraits::arity>
- class ParsedCommandOverload {};
+ class ParsedCommandOverload : public ParsedCommandOverloadBase
+ {
+ public:
+ typedef boost::intrusive_ptr<ParsedCommandOverload> ptr;
+
+#ifdef DOXYGEN
+ static ptr create(Function fn);
+#endif
+ };
+
+#ifndef DOXYGEN
# define BOOST_PP_ITERATION_PARAMS_1 (4, (0, SENF_CONSOLE_MAX_COMMAND_ARITY, \
SENF_ABSOLUTE_INCLUDE_PATH(Console/ParsedCommand.mpp), \
1))
# include BOOST_PP_ITERATE()
+#endif
+
+ /** \brief Generic ParsedCommandOverladBase attributes
+
+ Attributes for parsed commands are not set directly on the node. They are set via a special
+ attributor temporary returned when adding a parsed command to the tree.
+
+ This class is the base class for those attributors. It provides members which do not depend
+ in any way on the exact type of command added.
+ */
+ class ParsedCommandAttributorBase
+ {
+ public:
+ OverloadedCommandNode & node() const; ///< Return the node object
+ operator OverloadedCommandNode & () const; ///< Automatically convert to node object
+
+ protected:
+ ParsedCommandAttributorBase(ParsedCommandOverloadBase & overload, unsigned index);
+
+ void argName(std::string const & name) const;
+ void argDoc(std::string const & doc) const;
+ template <class Type> void defaultValue(Type const & value) const;
+
+ ParsedCommandOverloadBase & overload() const;
+ void overloadDoc(std::string const & doc) const;
+
+ void nodeDoc(std::string const & doc) const;
+
+ private:
+ ParsedCommandOverloadBase & overload_;
+ unsigned index_;
+ };
+
+ /** \brief Non argument dependent ParsedCommandBase attributes
+
+ Attributes for parsed commands are not set directly on the node. They are set via a special
+ attributor temporary returned when adding a parsed command to the tree.
+
+ This class adds all those members, which do depend on the type of command added (and thereby
+ on that commands signature) but do not depend on the type of any single argument.
+
+ \fixme Implement compile-time checking, that after a defaulted arg only defaulted args are
+ allowed.
+ */
+ template <class Overload>
+ class ParsedCommandAttributor
+ : public ParsedCommandAttributorBase
+ {
+ public:
+ Overload & overload() const; ///< Get the command overload
+
+ protected:
+ ParsedCommandAttributor(Overload & overload, unsigned index);
+
+ private:
+ };
+
+ /** \brief Keyword argument tags
+
+ The tags defined in this namespace are used as keyword arguments via the <a
+ href="http://www.boost.org/doc/libs/1_33_1/libs/parameter/doc/html/index.html">Boost.Parameter</a>
+ library.
+
+ For the keyword tags, the standard C++ scoping rules apply:
+ \li Either qualify them with their complete namespace: <tt>arg( senf::console::kw::name =
+ "name" )</tt>
+ \li or use a namespace alias: <tt>namespace kw = senf::console::kw; arg( kw::name = "name"
+ );</tt>
+ \li import the keywords into your namespace: <tt>using namespace senf::console::kw; arg(
+ name = "name");</tt>
+
+ The second alternative is preferred, the <tt>using namespace</tt> directive may be used as
+ long as the keyword names do not clash with another visible symbol.
+ */
+ namespace kw {
+ BOOST_PARAMETER_KEYWORD(type, name) ///< Argument name
+ BOOST_PARAMETER_KEYWORD(type, description) ///< One-line Argument description
+ BOOST_PARAMETER_KEYWORD(type, default_value) ///< Argument default value
+ }
+
+ /** \brief Derived class dependent ParsedCommandBase attributes
+
+ Attributes for parsed commands are not set directly on the node. They are set via a special
+ attributor temporary returned when adding a parsed command to the tree.
+
+ This class adds all those members, which do not depend on any specific argument but which
+ need to return the correct attributor type.
+ */
+ template <class Overload, class Self>
+ class ParsedArgumentAttributorBase
+ : public ParsedCommandAttributor<Overload>
+ {
+ public:
+ Self doc(std::string const & doc) const; ///< Set documentation for all overloads
+ Self overloadDoc(std::string const & doc) const; ///< Set overload specific documentation
+
+ protected:
+ ParsedArgumentAttributorBase(Overload & overload, unsigned index);
+
+ private:
+ };
+
+
+ /** \brief Argument dependent ParsedCommandBase attributes
+
+ Attributes for parsed commands are not set directly on the node. They are set via a special
+ attributor temporary returned when adding a parsed command to the tree.
+
+ This class adds all those members, which depend on a specific argument. Each call to \c arg
+ will advance to the next argument.
+ */
+ template < class Overload,
+ unsigned index=0,
+ bool flag=(index < unsigned(Overload::traits::arity)) >
+ class ParsedArgumentAttributor
+ : public ParsedArgumentAttributorBase< Overload,
+ ParsedArgumentAttributor<Overload, index, flag> >
+ {
+ typedef boost::parameter::parameters<
+ kw::type::name,
+ kw::type::description,
+ kw::type::default_value> arg_params;
+
+ public:
+ typedef OverloadedCommandNode node_type;
+ typedef ParsedArgumentAttributor return_type;
+
+ typedef typename senf::function_traits_arg_type<
+ typename Overload::traits, int(index) >::type arg_type;
+ typedef typename senf::remove_cvref< arg_type >::type value_type;
+ typedef ParsedArgumentAttributor<Overload, index+1> next_type;
+
+ next_type arg() const; ///< Set argument attributes
+ /**< This member changes the attributes for the current
+ argument. The attributes are passed to arg() as keyword
+ arguments using the <a
+ href="http://www.boost.org/doc/libs/1_33_1/libs/parameter/doc/html/index.html">Boost.Parameter</a>
+ library. The valid keywords are defined in the
+ senf::console::kw namespace.
+
+ This member is only present, if there is an argument at
+ the current index. */
+
+#ifndef DOXYVEN
+
+# define BOOST_PP_ITERATION_PARAMS_1 \
+ (4, (1, 3, SENF_ABSOLUTE_INCLUDE_PATH(Console/ParsedCommand.mpp), 5))
+# include BOOST_PP_ITERATE()
+
+#endif
+
+ private:
+ explicit ParsedArgumentAttributor(Overload & overload);
+
+ template <class ArgumentPack>
+ next_type argInfo(ArgumentPack const & args) const;
+ template <class Kw, class ArgumentPack>
+ void argInfo(Kw const &, ArgumentPack const &, boost::mpl::true_)
+ const;
+
+ template <class ArgumentPack>
+ void argInfo(boost::parameter::keyword<kw::type::name> const &,
+ ArgumentPack const & args, boost::mpl::false_)
+ const;
+ template <class ArgumentPack>
+ void argInfo(boost::parameter::keyword<kw::type::description> const &,
+ ArgumentPack const & args, boost::mpl::false_)
+ const;
+ template <class ArgumentPack>
+ void argInfo(boost::parameter::keyword<kw::type::default_value> const &,
+ ArgumentPack const & args, boost::mpl::false_)
+ const;
+
+ next_type next() const;
+
+ void defaultValue(value_type const & value) const;
+
+ template <class O, unsigned i, bool f>
+ friend class ParsedArgumentAttributor;
+
#ifndef DOXYGEN
+
+ template <class Function>
+ friend ParsedArgumentAttributor<
+ ParsedCommandOverload<typename detail::ParsedCommandTraits<Function>::traits> >
+ senf_console_add_node(DirectoryNode & node, std::string const & name, Function fn, int);
+
+ template <class Owner, class Function>
+ friend ParsedArgumentAttributor<
+ ParsedCommandOverload<typename detail::ParsedCommandTraits<Function>::traits> >
+ senf_console_add_node(DirectoryNode & node, Owner & owner, std::string const & name,
+ Function fn, int,
+ typename boost::enable_if_c<
+ detail::ParsedCommandTraits<Function>::is_member>::type * = 0);
+
+#endif
+ };
+
+#ifndef DOXYGEN
+
+ template <class Overload, unsigned index>
+ class ParsedArgumentAttributor<Overload, index, false>
+ : public ParsedArgumentAttributorBase< Overload,
+ ParsedArgumentAttributor<Overload, index, false> >
+ {
+ public:
+ typedef OverloadedCommandNode node_type;
+ typedef ParsedArgumentAttributor return_type;
+
+ private:
+ explicit ParsedArgumentAttributor(Overload & overload);
+
+ template <class O, unsigned i, bool f>
+ friend class ParsedArgumentAttributor;
+
+ template <class Function>
+ friend ParsedArgumentAttributor<
+ ParsedCommandOverload<typename detail::ParsedCommandTraits<Function>::traits> >
+ senf_console_add_node(DirectoryNode & node, std::string const & name, Function fn, int);
+
+ template <class Owner, class Function>
+ friend ParsedArgumentAttributor<
+ ParsedCommandOverload<typename detail::ParsedCommandTraits<Function>::traits> >
+ senf_console_add_node(DirectoryNode & node, Owner & owner, std::string const & name,
+ Function fn, int,
+ typename boost::enable_if_c<
+ detail::ParsedCommandTraits<Function>::is_member>::type * = 0);
+ };
template <class Function>
- ParsedCommandOverload<typename detail::ParsedCommandTraits<Function>::traits> &
+ ParsedArgumentAttributor<
+ ParsedCommandOverload<typename detail::ParsedCommandTraits<Function>::traits> >
senf_console_add_node(DirectoryNode & node, std::string const & name, Function fn, int);
template <class Owner, class Function>
- ParsedCommandOverload<typename detail::ParsedCommandTraits<Function>::traits> &
+ ParsedArgumentAttributor<
+ ParsedCommandOverload<typename detail::ParsedCommandTraits<Function>::traits> >
senf_console_add_node(DirectoryNode & node, Owner & owner, std::string const & name,
Function fn, int,
- typename boost::enable_if_c<detail::ParsedCommandTraits<Function>::is_member>::type * = 0);
+ typename boost::enable_if_c<
+ detail::ParsedCommandTraits<Function>::is_member>::type * = 0);
#endif
#include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP()
BOOST_TYPEOF_REGISTER_TEMPLATE(senf::console::ParsedCommandOverload, (class,unsigned))
+BOOST_TYPEOF_REGISTER_TEMPLATE(senf::console::ParsedArgumentAttributor, (class, unsigned, bool))
BOOST_TYPEOF_REGISTER_TEMPLATE(boost::function_traits, 1)
///////////////////////////////hh.e////////////////////////////////////////