// Custom includes
#include "../Logger/SenfLog.hh"
+#include "../../Utils/range.hh"
//#include "LineEditor.mpp"
#define prefix_
reader_->write(data);
}
+prefix_ unsigned senf::console::detail::LineEditorSwitcher::v_width()
+ const
+{
+ return reader_->width();
+}
+
///////////////////////////////////////////////////////////////////////////
// senf::console::detail::LineEditorClientReader
editor_.prompt(promptString());
editor_.defineKey(senf::term::KeyParser::Ctrl('D'),
senf::membind(&LineEditorClientReader::deleteCharOrExit, this));
+ editor_.defineKey(senf::term::KeyParser::Tab,
+ 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()
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)
{
term::bindings::deleteChar(editor);
}
+prefix_ void senf::console::detail::LineEditorClientReader::
+completePath(term::LineEditor & editor, unsigned & b, unsigned & e, std::string & prefix,
+ std::vector<std::string> & completions)
+{
+ 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 {
+ parser.parsePath(base, cmd);
+ }
+ catch (CommandParser::ParserErrorException & ex) {
+ return;
+ }
+
+ ParseCommandInfo::TokensRange path (cmd.commandPath());
+ 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->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());
+ for (; i != i_end; ++i)
+ if (*i == NoneToken()) {
+ if (i == path.begin()) {
+ dir = & client().root();
+ prefix = "/";
+ }
+ }
+ else if (*i == WordToken("..")) {
+ DirectoryNode * parent (dir->parent().get());
+ if (parent) dir = parent;
+ prefix += "../";
+ }
+ else if (*i == WordToken("."))
+ prefix += "./";
+ else {
+ if (dir->hasChild(i->value())) {
+ try {
+ dir = & dir->getDirectory(i->value());
+ }
+ catch (std::bad_cast &) {
+ return;
+ }
+ prefix += i->value() + "/";
+ }
+ else {
+ DirectoryNode::ChildrenRange cs (dir->completions(i->value()));
+ if (has_one_elt(cs)) {
+ GenericNode & node (cs.begin()->second->followLink());
+ if (!node.isDirectory())
+ return;
+ dir = static_cast<DirectoryNode*>(&node);
+ prefix += cs.begin()->first + "/";
+ }
+ else
+ return;
+ }
+ }
+
+ DirectoryNode::ChildrenRange cs (dir->completions(i->value()));
+ for (DirectoryNode::ChildrenRange::iterator j (cs.begin()); j != cs.end(); ++j)
+ completions.push_back(j->first + (j->second->followLink().isDirectory() ? "/" : " "));
+}
+
///////////////////////////////cc.e////////////////////////////////////////
#undef prefix_
//#include "LineEditor.mpp"