Skip to content
Snippets Groups Projects
Commit d95f726f authored by g0dil's avatar g0dil
Browse files

Utils/Console: Move link target in lr output one line up

Utils/Console: Add documentation to Client members
Utils/Console: Add support for std::pair parsing/formatting
Utils/Console: Some more documentation
parent b5e713e0
No related branches found
No related tags found
No related merge requests found
......@@ -31,6 +31,7 @@
#include <boost/range/iterator_range.hpp>
#include <boost/bind.hpp>
#include <boost/format.hpp>
#include <boost/preprocessor/stringize.hpp>
#include "../../Utils/senfassert.hh"
#include "../../Utils/Range.hh"
#include "../../Utils/String.hh"
......@@ -232,21 +233,15 @@ prefix_ void senf::console::Executor::cd(ParseCommandInfo::TokensRange dir)
prefix_ void senf::console::Executor::ls(std::ostream & output,
ParseCommandInfo::TokensRange path)
{
unsigned width (80);
try {
width = senf::console::Client::get(output).width();
}
catch (std::bad_cast &)
{}
if (width<60)
width = 80;
width -= 28+1;
# define HELP_COLUMN 28
unsigned width (senf::console::Client::getWidth(output, 80u, 60u)-(HELP_COLUMN+1));
Path dir (cwd_);
traverseDirectory(path, dir);
DirectoryNode & node (*dir.back().lock());
DirectoryNode::child_iterator i (node.children().begin());
DirectoryNode::child_iterator const i_end (node.children().end());
boost::format fmt ("%s%s %|28t|%s\n");
boost::format fmt ("%s%s %|" BOOST_PP_STRINGIZE(HELP_COLUMN) "t|%s\n");
for (; i != i_end; ++i)
output << fmt
% i->first
......@@ -256,8 +251,12 @@ prefix_ void senf::console::Executor::ls(std::ostream & output,
? "@"
: "" )
% i->second->shorthelp().substr(0,width);
# undef HELP_COLUMN
}
# define HELP_COLUMN 40
namespace {
typedef std::map<senf::console::DirectoryNode*,std::string> NodesMap;
......@@ -265,25 +264,20 @@ namespace {
void dolr(std::ostream & output, unsigned width, NodesMap & nodes, std::string const & base,
unsigned level, senf::console::DirectoryNode & node)
{
boost::format fmt ("%s%s%s %|40t|%s\n");
boost::format fmt ("%s%s%s %|" BOOST_PP_STRINGIZE(HELP_COLUMN) "t|%s\n");
std::string pad (2*level, ' ');
senf::console::DirectoryNode::child_iterator i (node.children().begin());
senf::console::DirectoryNode::child_iterator const i_end (node.children().end());
for (; i != i_end; ++i) {
output << fmt
% pad
% i->first
% ( i->second->isDirectory()
? "/"
: i->second->isLink()
? "@"
: "" )
% i->second->shorthelp().substr(0,width);
if (i->second->followLink().isDirectory()) {
senf::console::DirectoryNode & subnode (
static_cast<senf::console::DirectoryNode&>(i->second->followLink()));
NodesMap::iterator j (nodes.find(&subnode));
if (j == nodes.end()) {
output << fmt
% pad % i->first
% ( i->second->isDirectory() ? "/" : i->second->isLink() ? "@" : "" )
% i->second->shorthelp().substr(0,width);
std::string subbase (base);
if (! subbase.empty())
subbase += "/";
......@@ -291,7 +285,14 @@ namespace {
nodes.insert(std::make_pair(&subnode, subbase));
dolr(output, width, nodes, subbase, level+1, subnode);
} else
output << pad << " -> " << j->second << "\n";
output << pad << i->first
<< ( i->second->isDirectory() ? "/" : i->second->isLink() ? "@" : "" )
<< " -> " << j->second << "\n";
} else {
output << fmt
% pad % i->first
% ( i->second->isDirectory() ? "/" : i->second->isLink() ? "@" : "" )
% i->second->shorthelp().substr(0,width);
}
}
}
......@@ -301,22 +302,16 @@ namespace {
prefix_ void senf::console::Executor::lr(std::ostream & output,
ParseCommandInfo::TokensRange path)
{
unsigned width (80);
try {
width = senf::console::Client::get(output).width();
}
catch (std::bad_cast &)
{}
if (width<60)
width = 80;
width -= 40+1;
Path dir (cwd_);
traverseDirectory(path, dir);
DirectoryNode & node (*dir.back().lock());
NodesMap nodes;
dolr(output, width, nodes, "", 0, node);
dolr(output, senf::console::Client::getWidth(output, 80u, 60u)-(HELP_COLUMN+1),
nodes, "", 0, node);
}
#undef HELP_COLUMN
prefix_ void senf::console::Executor::pushd(ParseCommandInfo::TokensRange dir)
{
Path newDir (cwd_);
......
......@@ -223,7 +223,17 @@ namespace console {
class DirectoryNode;
class CommandNode;
/** \brief Get console root node */
DirectoryNode & root();
/** \brief Dump console directory structure
Recursively dumps the console directory structure starting at \a dir. By default, dumps the
complete tree beginning at the root node.
In contrast to the console 'lr' command, links are dumped by showing the \e absolute path
to the target node.
*/
void dump(std::ostream & os, DirectoryNode & dir=root());
/** \brief Config/console node tree base-class
......
......@@ -26,6 +26,7 @@
//#include "VectorSupport.ih"
// Custom includes
#include <boost/format.hpp>
#define prefix_
///////////////////////////////ct.p////////////////////////////////////////
......@@ -82,6 +83,42 @@ prefix_ void senf::console::SequenceReturnValueTraits<Sequence>::format(type con
os << ")";
}
template <class T1, class T2>
prefix_ void senf::console::ArgumentTraits< std::pair<T1,T2> >::
parse(ParseCommandInfo::TokensRange const & tokens, type & out)
{
CheckedArgumentIteratorWrapper arg (tokens);
senf::console::parse( *(arg++), out.first );
senf::console::parse( *(arg++), out.second );
}
template <class T1, class T2>
prefix_ std::string senf::console::ArgumentTraits< std::pair<T1,T2> >::description()
{
return (boost::format("pair<%s,%s>")
% ArgumentTraits<T1>::description()
% ArgumentTraits<T2>::description()).str();
}
template <class T1, class T2>
prefix_ std::string senf::console::ArgumentTraits< std::pair<T1,T2> >::str(type const & value)
{
std::stringstream ss;
senf::console::format(value, ss);
return ss.str();
}
template <class T1, class T2>
prefix_ void senf::console::ReturnValueTraits< std::pair<T1,T2> >::format(type const & value,
std::ostream & os)
{
os << "(";
senf::console::format(value.first, os);
os << " ";
senf::console::format(value.second, os);
os << ")";
}
#endif
///////////////////////////////ct.e////////////////////////////////////////
......
......@@ -78,6 +78,25 @@ namespace console {
: public SequenceReturnValueTraits< std::list<T,Alloc> >
{};
template <class T1, class T2>
struct ArgumentTraits< std::pair<T1,T2> >
{
typedef std::pair<T1,T2> type;
static bool const singleToken = false;
static void parse(ParseCommandInfo::TokensRange const & tokens, type & out);
static std::string description();
static std::string str(type const & value);
};
template <class T1, class T2>
struct ReturnValueTraits< std::pair<T1,T2> >
{
typedef std::pair<T1,T2> type;
static void format(type const & value, std::ostream & os);
};
#endif
}}
......
......@@ -336,6 +336,17 @@ prefix_ void senf::console::Client::v_write(senf::log::time_type timestamp,
reader_->enablePrompt();
}
prefix_ unsigned senf::console::Client::getWidth(std::ostream & os, unsigned defaultWidth,
unsigned minWidth)
{
unsigned rv (defaultWidth);
try {
rv = get(os).width();
}
catch (std::bad_cast &) {}
return rv < minWidth ? defaultWidth : rv;
}
///////////////////////////////////////////////////////////////////////////
// senf::console::Client::SysBacktrace
......
......@@ -168,18 +168,51 @@ namespace console {
void stop(); ///< Stop the client
/**< This will close the client socket. */
std::string const & name() const;
ClientHandle handle() const;
std::ostream & stream();
std::string promptString() const;
DirectoryNode & root() const;
DirectoryNode & cwd() const;
Server::Mode mode() const;
std::string const & name() const; ///< Get name of the client instance
/**< This name is used in the prompt string and is set by
the server. */
ClientHandle handle() const; ///< Get the client's network socket handle
std::ostream & stream(); ///< Get client's output stream
/**< Data sent to this stream is sent out over the network
via the client's socket handle. Write operation is
non-blocking and data may be dropped. Data is written
using Client::write(). */
std::string promptString() const; ///< Get the prompt string
DirectoryNode & root() const; ///< Get configured root node
DirectoryNode & cwd() const; ///< Get current directory
/**< This is the directory, the console currently is changed
into by the user of the console. */
Server::Mode mode() const; ///< Get operation mode
/**< \see Server::mode() */
void write(std::string const & data) const;
std::string const & backtrace() const;
unsigned width() const;
///< Write data to network socket
/**< The data is automatically filtered depending on the
type of connection (e.g. on a telnet connection,
specific bytes are quoted). */
std::string const & backtrace() const; ///< Get backtrace of last console error, if any
unsigned width() const; ///< Get console width
/**< If possible, this will be the width of the connected
terminal, otherwise a default value (normally 80) is
returned. */
static Client & get(std::ostream & os);
///< Access client instance
/**< Allows to access the client instance from console
command implementations. The first argument to a
console command is a stream object. \e If this stream
object belongs to a network console client, this call
will return the associated Client instance reference.
\throws std::bad_cast if \a os is not associated with a
Client instance. */
static unsigned getWidth(std::ostream & os, unsigned defaultWidth = 0,
unsigned minWidth = 0);
///< Get width of client console if possible
/**< If possible, the width of the client console attached
to the stream \a os is returned. If this is not
possible, the \a defaultValue will be used.
If the width obtained this way is smaller than \a
minWidth, \a defaultValue will be returned instead. */
protected:
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment