Packets: Add StringParser ostream operation
[senf.git] / Utils / Console / LineEditor.cc
index bf4d869..00faa8b 100644 (file)
@@ -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
 
@@ -81,6 +87,7 @@ LineEditorClientReader(Client & client, LineEditorSwitcher & switcher)
                       boost::bind(&term::bindings::complete,
                                   _1, 
                                   senf::membind(&LineEditorClientReader::completePath, this)));
+    editor_.defineKey(senf::term::KeyParser::Return, &senf::term::bindings::acceptWithRepeat);
 }
 
 prefix_ void senf::console::detail::LineEditorClientReader::v_setupFailed()
@@ -109,6 +116,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)
 {
@@ -128,10 +141,27 @@ senf::console::detail::LineEditorClientReader::deleteCharOrExit(term::LineEditor
 }
 
 prefix_ void senf::console::detail::LineEditorClientReader::
-completePath(term::LineEditor & editor, unsigned b, unsigned e,
+completePath(term::LineEditor & editor, unsigned & b, unsigned & e, std::string & prefix,
              std::vector<std::string> & completions)
 {
-    std::string base (editor.text().substr(b,e));
+    std::string const & t (editor.text());
+    // Search backward from e finding the longest valid path. This does *not* accept all valid
+    // path's, only those without embedded white-space. However, this is only for completion so
+    // it's ok. 
+    if (b<e) {
+        unsigned bb (e-1);
+        for (;;) {
+            if (! CommandParser::isWordChar(t[bb]) && t[bb] != '/') {
+                ++bb;
+                break;
+            }
+            if (bb == b)
+                break;
+            --bb;
+        }
+        b = bb;
+    }
+    std::string base (t.substr(b,e));
     CommandParser parser;
     ParseCommandInfo cmd;
     try {
@@ -145,28 +175,27 @@ completePath(term::LineEditor & editor, unsigned b, unsigned e,
     if (path.empty()) {
         DirectoryNode::ChildrenRange cs (client().cwd().children());
         for (DirectoryNode::ChildrenRange::iterator i (cs.begin()); i != cs.end(); ++i)
-            completions.push_back(i->first + (i->second->isDirectory() ? "/" : ""));
+            completions.push_back(i->first + (i->second->followLink().isDirectory() ? "/" : " "));
         return;
     }
     
     ParseCommandInfo::TokensRange::const_iterator i (path.begin());
     ParseCommandInfo::TokensRange::const_iterator const i_end (boost::prior(path.end()));
     DirectoryNode * dir (& client().cwd());
-    std::string basePath;
     for (; i != i_end; ++i)
         if (*i == NoneToken()) {
             if (i == path.begin()) {
                 dir = & client().root();
-                basePath = "/";
+                prefix = "/";
             }
         }
         else if (*i == WordToken("..")) {
             DirectoryNode * parent (dir->parent().get());
             if (parent) dir = parent;
-            basePath += "../";
+            prefix += "../";
         }
         else if (*i == WordToken(".")) 
-            basePath += "./";
+            prefix += "./";
         else {
             if (dir->hasChild(i->value())) {
                 try {
@@ -175,16 +204,16 @@ completePath(term::LineEditor & editor, unsigned b, unsigned e,
                 catch (std::bad_cast &) {
                     return;
                 }
-                basePath += i->value() + "/";
+                prefix += i->value() + "/";
             } 
             else {
                 DirectoryNode::ChildrenRange cs (dir->completions(i->value()));
                 if (has_one_elt(cs)) {
-                    GenericNode * node (cs.begin()->second.get());
-                    if (!node->isDirectory())
+                    GenericNode & node (cs.begin()->second->followLink());
+                    if (!node.isDirectory())
                         return;
-                    dir = static_cast<DirectoryNode*>(node);
-                    basePath += cs.begin()->first + "/";
+                    dir = static_cast<DirectoryNode*>(&node);
+                    prefix += cs.begin()->first + "/";
                 }
                 else
                     return;
@@ -193,7 +222,7 @@ completePath(term::LineEditor & editor, unsigned b, unsigned e,
 
     DirectoryNode::ChildrenRange cs (dir->completions(i->value()));
     for (DirectoryNode::ChildrenRange::iterator j (cs.begin()); j != cs.end(); ++j)
-        completions.push_back(basePath + j->first + (j->second->isDirectory() ? "/" : ""));
+        completions.push_back(j->first + (j->second->followLink().isDirectory() ? "/" : " "));
 }
 
 ///////////////////////////////cc.e////////////////////////////////////////