diff --git a/Utils/Console/Executor.cc b/Utils/Console/Executor.cc index e3f09216f24f5bc150e4c00efe5b38ea4b73db7f..10d45df3aca7cdb1f602502ccbd59d88a95e88fb 100644 --- a/Utils/Console/Executor.cc +++ b/Utils/Console/Executor.cc @@ -35,6 +35,7 @@ #include "../../Utils/Range.hh" #include "../../Utils/String.hh" #include "../../Utils/range.hh" +#include "Server.hh" //#include "Executor.mpp" #define prefix_ @@ -112,6 +113,13 @@ prefix_ void senf::console::Executor::execute(std::ostream & output, ls( output, command.commandPath() ); break; + case ParseCommandInfo::BuiltinLR : + if (skipping()) + break; + // The parser ensures, we have either one or no argument + lr( output, command.commandPath() ); + break; + case ParseCommandInfo::BuiltinPUSHD : // The parser ensures, we have exactly one argument if (skipping()) @@ -218,12 +226,21 @@ 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; 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 %|20t|%.59s\n"); + boost::format fmt ("%s%s %|28t|%s\n"); for (; i != i_end; ++i) output << fmt % i->first @@ -232,7 +249,66 @@ prefix_ void senf::console::Executor::ls(std::ostream & output, : i->second->isLink() ? "@" : "" ) - % i->second->shorthelp(); + % i->second->shorthelp().substr(0,width); +} + +namespace { + + typedef std::map<senf::console::DirectoryNode*,std::string> NodesMap; + + 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"); + 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()) { + std::string subbase (base); + if (! subbase.empty()) + subbase += "/"; + subbase += i->first; + nodes.insert(std::make_pair(&subnode, subbase)); + dolr(output, width, nodes, subbase, level+1, subnode); + } else + output << pad << " -> " << j->second << "\n"; + } + } + } + +} + +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); } prefix_ void senf::console::Executor::pushd(ParseCommandInfo::TokensRange dir) diff --git a/Utils/Console/Executor.hh b/Utils/Console/Executor.hh index 9341dedee2d18bd77144eeaa632834ef360368cb..2fc9c06ee911789f0ca0674c40ddea1c0578df92 100644 --- a/Utils/Console/Executor.hh +++ b/Utils/Console/Executor.hh @@ -138,6 +138,7 @@ namespace console { void cd(ParseCommandInfo::TokensRange dir); void ls(std::ostream & output, ParseCommandInfo::TokensRange dir); + void lr(std::ostream & output, ParseCommandInfo::TokensRange dir); void pushd(ParseCommandInfo::TokensRange dir); void popd(); void exit(); diff --git a/Utils/Console/Executor.test.cc b/Utils/Console/Executor.test.cc index f02943bf2ac101e48f2aff5e0683cbca528afd2d..d4df850b45ed07915c154ce78646f1bfb3ed7211 100644 --- a/Utils/Console/Executor.test.cc +++ b/Utils/Console/Executor.test.cc @@ -100,9 +100,9 @@ BOOST_AUTO_UNIT_TEST(executor) executor(os, commands.back()); BOOST_CHECK_EQUAL( commands.back().builtin(), senf::console::ParseCommandInfo::BuiltinLS ); BOOST_CHECK_EQUAL( os.str(), - "dir1/ \n" - "dir2/ Helptext\n" - "sys/ \n" ); + "dir1/ \n" + "dir2/ Helptext\n" + "sys/ \n" ); } { @@ -110,7 +110,7 @@ BOOST_AUTO_UNIT_TEST(executor) parser.parse("ls dir1", &setCommand); executor(os, commands.back()); BOOST_CHECK_EQUAL( commands.back().builtin(), senf::console::ParseCommandInfo::BuiltinLS ); - BOOST_CHECK_EQUAL( os.str(), "dir3/ \n" ); + BOOST_CHECK_EQUAL( os.str(), "dir3/ \n" ); } { @@ -121,6 +121,19 @@ BOOST_AUTO_UNIT_TEST(executor) BOOST_CHECK_EQUAL( os.str(), "" ); } + { + std::stringstream os; + parser.parse("lr", &setCommand); + executor(os, commands.back()); + BOOST_CHECK_EQUAL( commands.back().builtin(), senf::console::ParseCommandInfo::BuiltinLR ); + BOOST_CHECK_EQUAL( os.str().substr(0,213), + "dir1/ \n" + " dir3/ \n" + "dir2/ Helptext\n" + " test \n" + "sys/ \n" ); + } + { std::stringstream os; parser.parse("dir1/dir3 { }", &setCommand); @@ -216,7 +229,7 @@ BOOST_AUTO_UNIT_TEST(executorPolicy) parser.parse("ls dir1", &setCommand); executor(os, commands.back()); BOOST_CHECK_EQUAL( commands.back().builtin(), senf::console::ParseCommandInfo::BuiltinLS ); - BOOST_CHECK_EQUAL( os.str(), "dir3/ \n" ); + BOOST_CHECK_EQUAL( os.str(), "dir3/ \n" ); } { diff --git a/Utils/Console/LineEditor.cc b/Utils/Console/LineEditor.cc index 31df1f7829717fd48576138b936db6a67019d776..df9d0652fd0a20b6964ccc032ad3b8e51108427e 100644 --- a/Utils/Console/LineEditor.cc +++ b/Utils/Console/LineEditor.cc @@ -65,6 +65,12 @@ prefix_ void senf::console::detail::LineEditorSwitcher::v_write(std::string cons reader_->write(data); } +prefix_ unsigned senf::console::detail::LineEditorSwitcher::v_width() + const +{ + return reader_->width(); +} + /////////////////////////////////////////////////////////////////////////// // senf::console::detail::LineEditorClientReader @@ -109,6 +115,12 @@ prefix_ void senf::console::detail::LineEditorClientReader::v_write(std::string BaseTelnetProtocol::write(data); } +prefix_ unsigned senf::console::detail::LineEditorClientReader::v_width() + const +{ + return editor_.width(); +} + prefix_ void senf::console::detail::LineEditorClientReader::executeLine(std::string const & text) { diff --git a/Utils/Console/LineEditor.hh b/Utils/Console/LineEditor.hh index 2a94a7e62f3d345dc36e9ce81e0961d6d354efbd..6fe3ea33bb1bbc432739c790cdee1ee7fce70f3a 100644 --- a/Utils/Console/LineEditor.hh +++ b/Utils/Console/LineEditor.hh @@ -60,6 +60,7 @@ namespace detail { virtual void v_disablePrompt(); virtual void v_enablePrompt(); virtual void v_write(std::string const & data); + virtual unsigned v_width() const; boost::scoped_ptr<ClientReader> reader_; }; @@ -83,6 +84,7 @@ namespace detail { virtual void v_disablePrompt(); virtual void v_enablePrompt(); virtual void v_write(std::string const & data); + virtual unsigned v_width() const; // Editor callbacks void executeLine(std::string const & text); diff --git a/Utils/Console/Parse.cc b/Utils/Console/Parse.cc index 28fa61a0c972cca392358c5c69bef80d52624375..5281be5db3aac2095be77abddeca2d0361f0c006 100644 --- a/Utils/Console/Parse.cc +++ b/Utils/Console/Parse.cc @@ -76,6 +76,11 @@ namespace detail { info_->builtin(ParseCommandInfo::BuiltinLS); setBuiltinPathArg(path); } + void builtin_lr(std::vector<Token> & path) + { info_->clear(); + info_->builtin(ParseCommandInfo::BuiltinLR); + setBuiltinPathArg(path); } + void pushDirectory() { // Do NOT call clear since pushDirectory is set in ADDITION // to an ordinary command (which may be only a directory name) @@ -169,7 +174,7 @@ prefix_ std::ostream & senf::console::operator<<(std::ostream & stream, } } else { - char const * builtins[] = { 0, "cd", "ls", "pushd", "popd", "exit", "help" }; + char const * builtins[] = { 0, "cd", "ls", "lr", "pushd", "popd", "exit", "help" }; stream << "builtin-" << builtins[info.builtin()]; } diff --git a/Utils/Console/Parse.hh b/Utils/Console/Parse.hh index 4303fc2a4d162dfb8ae21fa58253bb76fe28df64..e7712e00c5e60787eb6e5c04bd9998e521f981f2 100644 --- a/Utils/Console/Parse.hh +++ b/Utils/Console/Parse.hh @@ -366,6 +366,7 @@ namespace console { enum BuiltinCommand { NoBuiltin, BuiltinCD, BuiltinLS, + BuiltinLR, BuiltinPUSHD, BuiltinPOPD, BuiltinEXIT, diff --git a/Utils/Console/Parse.ih b/Utils/Console/Parse.ih index d99e168f24c02f82c40ccc7c51970aa3a61aeb5f..00745ccecdfc89bf7a9ee474b00c7e3332e2cba7 100644 --- a/Utils/Console/Parse.ih +++ b/Utils/Console/Parse.ih @@ -220,6 +220,9 @@ namespace detail { | self.keyword_p("ls") >> ! path >> eps_p [ bind(&PD::builtin_ls)(d_, path_) ] + | self.keyword_p("lr") + >> ! path + >> eps_p [ bind(&PD::builtin_lr)(d_, path_) ] | self.keyword_p("exit") [ bind(&PD::builtin_exit)(d_) ] | self.keyword_p("help") >> ! path diff --git a/Utils/Console/Parse.test.cc b/Utils/Console/Parse.test.cc index 5d625e336558f340ac2fc3d747d1e0eb83cfb5b6..bbc2c686afc6220335325f5b4d3691be96631f30 100644 --- a/Utils/Console/Parse.test.cc +++ b/Utils/Console/Parse.test.cc @@ -66,6 +66,8 @@ namespace { os_ << "builtin_cd( " << senf::stringJoin(path, "/") << " )\n"; } void builtin_ls(std::vector<senf::console::Token> const & path) { os_ << "builtin_ls( " << senf::stringJoin(path, "/") << " )\n"; } + void builtin_lr(std::vector<senf::console::Token> const & path) + { os_ << "builtin_lr( " << senf::stringJoin(path, "/") << " )\n"; } void builtin_exit() { os_ << "builtin_exit()\n"; } void builtin_help(std::vector<senf::console::Token> const & path) @@ -130,6 +132,15 @@ BOOST_AUTO_UNIT_TEST(commandGrammar) BOOST_CHECK_EQUAL( ss.str(), "builtin_ls( None('')/Word('foo')/Word('bar') )\n" ); } + { + ss.str(""); + BOOST_CHECK( boost::spirit::parse( + "lr /foo/bar;", + grammar.use_parser<Grammar::CommandParser>(), + grammar.use_parser<Grammar::SkipParser>() ) . full ); + BOOST_CHECK_EQUAL( ss.str(), "builtin_lr( None('')/Word('foo')/Word('bar') )\n" ); + } + { ss.str(""); BOOST_CHECK( boost::spirit::parse( diff --git a/Utils/Console/ParsedCommand.test.cc b/Utils/Console/ParsedCommand.test.cc index 595365848f90a628699c81358d6575e57042e82b..b9c095a789e149cc3b082e0506218b43b4ce5afc 100644 --- a/Utils/Console/ParsedCommand.test.cc +++ b/Utils/Console/ParsedCommand.test.cc @@ -303,7 +303,9 @@ BOOST_AUTO_UNIT_TEST(directoryReturn) SENF_CHECK_NO_THROW( parser.parse("test/test { ls; }", boost::bind<void>( boost::ref(executor), boost::ref(ss), _1 )) ); - BOOST_CHECK_EQUAL( ss.str(), "<Directory at '/test/dircb'>\ncb1 \n" ); + BOOST_CHECK_EQUAL( ss.str(), + "<Directory at '/test/dircb'>\n" + "cb1 \n" ); } } diff --git a/Utils/Console/Server.cc b/Utils/Console/Server.cc index 41475c29ec35c3d2ec59f902eea12791d342e751..afcf92282d7500cf46c0969ee44e0fb46d343508 100644 --- a/Utils/Console/Server.cc +++ b/Utils/Console/Server.cc @@ -180,6 +180,12 @@ prefix_ void senf::console::detail::DumbClientReader::v_write(std::string const handle().write(data); } +prefix_ unsigned senf::console::detail::DumbClientReader::v_width() + const +{ + return 80; +} + /////////////////////////////////////////////////////////////////////////// // senf::console::detail::NoninteractiveClientReader @@ -202,6 +208,12 @@ prefix_ void senf::console::detail::NoninteractiveClientReader::v_write(std::str handle().write(data); } +prefix_ unsigned senf::console::detail::NoninteractiveClientReader::v_width() + const +{ + return 80; +} + prefix_ void senf::console::detail::NoninteractiveClientReader::newData(int event) { diff --git a/Utils/Console/Server.cci b/Utils/Console/Server.cci index 62e6fadec018879bc525deb9d33375e73dee327e..488fb3a7cbccfbcdeec96cf6d9d3e514b4b75cd4 100644 --- a/Utils/Console/Server.cci +++ b/Utils/Console/Server.cci @@ -163,6 +163,12 @@ prefix_ std::string const & senf::console::Client::backtrace() return backtrace_; } +prefix_ unsigned senf::console::Client::width() + const +{ + return reader_->width(); +} + prefix_ senf::console::Client & senf::console::Client::get(std::ostream & os) { return dynamic_cast<detail::NonblockingSocketOStream&>(os)->client(); @@ -236,6 +242,12 @@ prefix_ void senf::console::detail::ClientReader::write(std::string const & data v_write(data); } +prefix_ unsigned senf::console::detail::ClientReader::width() + const +{ + return v_width(); +} + prefix_ senf::console::detail::ClientReader::ClientReader(Client & client) : client_ (client) {} diff --git a/Utils/Console/Server.hh b/Utils/Console/Server.hh index 7d0a10de99b48040a520020104505d49bcae3c3d..4c5e66ff5a78ee6d28a23cd3613c30b11374a591 100644 --- a/Utils/Console/Server.hh +++ b/Utils/Console/Server.hh @@ -177,6 +177,7 @@ namespace console { Server::Mode mode() const; void write(std::string const & data) const; std::string const & backtrace() const; + unsigned width() const; static Client & get(std::ostream & os); diff --git a/Utils/Console/Server.ih b/Utils/Console/Server.ih index d97c1c9c60fdbe2dce125144c1916b4cb78a7b56..aa77d74d607d8cdd4aa735eb43ee62b757288dd0 100644 --- a/Utils/Console/Server.ih +++ b/Utils/Console/Server.ih @@ -114,6 +114,7 @@ namespace detail { void disablePrompt(); void enablePrompt(); void write(std::string const & data); + unsigned width() const; protected: ClientReader(Client & client); @@ -122,6 +123,7 @@ namespace detail { virtual void v_disablePrompt() = 0; virtual void v_enablePrompt() = 0; virtual void v_write(std::string const & data) = 0; + virtual unsigned v_width() const = 0; Client & client_; }; @@ -141,6 +143,7 @@ namespace detail { virtual void v_disablePrompt(); virtual void v_enablePrompt(); virtual void v_write(std::string const & data); + virtual unsigned v_width() const; void clientData(senf::ReadHelper<ClientHandle>::ptr helper); void showPrompt(); @@ -165,6 +168,7 @@ namespace detail { virtual void v_disablePrompt(); virtual void v_enablePrompt(); virtual void v_write(std::string const & data); + virtual unsigned v_width() const; void newData(int event); diff --git a/Utils/Termlib/AbstractTerminal.hh b/Utils/Termlib/AbstractTerminal.hh index b3f396d0576708cdce4a112c8d6fad8687d2ecee..95408f6b45f93d4c3415e90a1f293b58e70e0e1b 100644 --- a/Utils/Termlib/AbstractTerminal.hh +++ b/Utils/Termlib/AbstractTerminal.hh @@ -69,8 +69,8 @@ namespace term { virtual void setCallbacks(Callbacks & cb) = 0; ///< Register terminal callbacks virtual std::string terminalType() = 0; ///< Get the terminal type - virtual unsigned width() = 0; ///< Get current terminal window width - virtual unsigned height() = 0; ///< Get current terminal window height + virtual unsigned width() const = 0; ///< Get current terminal window width + virtual unsigned height() const = 0; ///< Get current terminal window height virtual void write(char ch) = 0; ///< Write character to terminal }; diff --git a/Utils/Termlib/Editor.cc b/Utils/Termlib/Editor.cc index ce6a3fb140dc5a7719b2a2de3d5a3f4fc19fe00c..0122904da71794f0b8950ed9f9f80ef82207a455 100644 --- a/Utils/Termlib/Editor.cc +++ b/Utils/Termlib/Editor.cc @@ -253,11 +253,13 @@ prefix_ void senf::term::BaseEditor::processKeys() } prefix_ unsigned senf::term::BaseEditor::width() + const { return terminal_->width(); } prefix_ unsigned senf::term::BaseEditor::height() + const { return terminal_->height(); } diff --git a/Utils/Termlib/Editor.hh b/Utils/Termlib/Editor.hh index bacfeff1bdd54aeb3e8609ac4b1ab028abf029a5..952291faec36e41086b6717e414c9f8bd1d668b1 100644 --- a/Utils/Termlib/Editor.hh +++ b/Utils/Termlib/Editor.hh @@ -81,8 +81,8 @@ namespace term { unsigned currentColumn() const; ///< Return number of current column unsigned currentLine() const; ///< Return number of current relative line - unsigned width(); ///< Return current screen width - unsigned height(); ///< Return current screen height + unsigned width() const; ///< Return current screen width + unsigned height() const; ///< Return current screen height protected: virtual bool cb_init(); ///< Called when terminal is initialized diff --git a/Utils/Termlib/TelnetTerminal.cc b/Utils/Termlib/TelnetTerminal.cc index 3445d5c244b9fe80646d03d505236dbc4332920b..758a360751cefc06bf76fcda92c134f7f0295135 100644 --- a/Utils/Termlib/TelnetTerminal.cc +++ b/Utils/Termlib/TelnetTerminal.cc @@ -51,11 +51,13 @@ prefix_ std::string senf::term::TelnetTerminal::terminalType() } prefix_ unsigned senf::term::TelnetTerminal::width() + const { return telnethandler::NAWS::width(); } prefix_ unsigned senf::term::TelnetTerminal::height() + const { return telnethandler::NAWS::height(); } diff --git a/Utils/Termlib/TelnetTerminal.hh b/Utils/Termlib/TelnetTerminal.hh index 650ce1f9288a48faf4cedb92cd0748d2e2803b3f..09aea80847cbdd70d37824349dd7fbfaccf5ae6f 100644 --- a/Utils/Termlib/TelnetTerminal.hh +++ b/Utils/Termlib/TelnetTerminal.hh @@ -62,8 +62,8 @@ namespace term { ///\{ virtual void setCallbacks(AbstractTerminal::Callbacks & cb); virtual std::string terminalType(); - virtual unsigned width(); - virtual unsigned height(); + virtual unsigned width() const; + virtual unsigned height() const; virtual void write(char ch); ///\}