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);
         ///\}