00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00026 #include "LineEditor.hh"
00027
00028
00029
00030 #include <senf/Utils/Logger/SenfLog.hh>
00031 #include <senf/Utils/Range.hh>
00032 #include <senf/Utils/membind.hh>
00033
00034
00035 #define prefix_
00036
00037
00038
00039
00040
00041 prefix_ senf::console::detail::LineEditorSwitcher::LineEditorSwitcher(Client & client)
00042 : ClientReader(client),
00043 reader_ (new LineEditorClientReader(client, *this))
00044 {}
00045
00046 prefix_ void senf::console::detail::LineEditorSwitcher::editorSetupFailed()
00047 {
00048
00049
00050 reader_.reset(0);
00051 reader_.reset(new DumbClientReader(client()));
00052 }
00053
00054 prefix_ void senf::console::detail::LineEditorSwitcher::v_disablePrompt()
00055 {
00056 reader_->disablePrompt();
00057 }
00058
00059 prefix_ void senf::console::detail::LineEditorSwitcher::v_enablePrompt()
00060 {
00061 reader_->enablePrompt();
00062 }
00063
00064 prefix_ void senf::console::detail::LineEditorSwitcher::v_write(std::string const & data)
00065 {
00066 reader_->write(data);
00067 }
00068
00069 prefix_ unsigned senf::console::detail::LineEditorSwitcher::v_width()
00070 const
00071 {
00072 return reader_->width();
00073 }
00074
00075
00076
00077
00078 prefix_ senf::console::detail::LineEditorClientReader::
00079 LineEditorClientReader(Client & client, LineEditorSwitcher & switcher)
00080 : term::BaseTelnetProtocol(client.handle()), ClientReader(client),
00081 editor_ (*this, senf::membind(&LineEditorClientReader::executeLine, this)),
00082 switcher_ (&switcher)
00083 {
00084 editor_.prompt(promptString());
00085 editor_.defineKey(senf::term::KeyParser::Ctrl('D'),
00086 senf::membind(&LineEditorClientReader::deleteCharOrExit, this));
00087 editor_.defineKey(senf::term::KeyParser::Tab,
00088 boost::bind(&term::bindings::complete,
00089 _1,
00090 senf::membind(&LineEditorClientReader::completePath, this)));
00091 editor_.defineKey(senf::term::KeyParser::Return, &senf::term::bindings::acceptWithRepeat);
00092 }
00093
00094 prefix_ void senf::console::detail::LineEditorClientReader::v_setupFailed()
00095 {
00096
00097 switcher_->editorSetupFailed();
00098 }
00099
00100 prefix_ void senf::console::detail::LineEditorClientReader::v_eof()
00101 {
00102 stopClient();
00103 }
00104
00105 prefix_ void senf::console::detail::LineEditorClientReader::v_disablePrompt()
00106 {
00107 editor_.hide();
00108 }
00109
00110 prefix_ void senf::console::detail::LineEditorClientReader::v_enablePrompt()
00111 {
00112 editor_.show();
00113 }
00114
00115 prefix_ void senf::console::detail::LineEditorClientReader::v_write(std::string const & data)
00116 {
00117 BaseTelnetProtocol::write(data);
00118 }
00119
00120 prefix_ unsigned senf::console::detail::LineEditorClientReader::v_width()
00121 const
00122 {
00123 return editor_.width();
00124 }
00125
00126 prefix_ void
00127 senf::console::detail::LineEditorClientReader::executeLine(std::string const & text)
00128 {
00129 handleInput(text);
00130 stream() << std::flush;
00131 editor_.prompt(promptString());
00132 editor_.show();
00133 }
00134
00135 prefix_ void
00136 senf::console::detail::LineEditorClientReader::deleteCharOrExit(term::LineEditor & editor)
00137 {
00138 if (editor.text().empty())
00139 ClientReader::handle().facet<TCPSocketProtocol>().shutdown(TCPSocketProtocol::ShutRD);
00140 else
00141 term::bindings::deleteChar(editor);
00142 }
00143
00144 prefix_ void senf::console::detail::LineEditorClientReader::
00145 completePath(term::LineEditor & editor, unsigned & b, unsigned & e, std::string & prefix,
00146 std::vector<std::string> & completions)
00147 {
00148 std::string const & t (editor.text());
00149
00150
00151
00152 if (b<e) {
00153 unsigned bb (e-1);
00154 for (;;) {
00155 if (! CommandParser::isWordChar(t[bb]) && t[bb] != '/') {
00156 ++bb;
00157 break;
00158 }
00159 if (bb == b)
00160 break;
00161 --bb;
00162 }
00163 b = bb;
00164 }
00165 std::string base (t.substr(b,e));
00166 CommandParser parser;
00167 ParseCommandInfo cmd;
00168 try {
00169 parser.parsePath(base, cmd);
00170 }
00171 catch (CommandParser::ParserErrorException & ex) {
00172 return;
00173 }
00174
00175 ParseCommandInfo::TokensRange path (cmd.commandPath());
00176 if (path.empty()) {
00177 DirectoryNode::ChildrenRange cs (client().cwd().children());
00178 for (DirectoryNode::ChildrenRange::iterator i (cs.begin()); i != cs.end(); ++i)
00179 completions.push_back(i->first + (i->second->followLink().isDirectory() ? "/" : " "));
00180 return;
00181 }
00182
00183 ParseCommandInfo::TokensRange::const_iterator i (path.begin());
00184 ParseCommandInfo::TokensRange::const_iterator const i_end (boost::prior(path.end()));
00185 DirectoryNode * dir (& client().cwd());
00186 for (; i != i_end; ++i)
00187 if (*i == NoneToken()) {
00188 if (i == path.begin()) {
00189 dir = & client().root();
00190 prefix = "/";
00191 }
00192 }
00193 else if (*i == WordToken("..")) {
00194 DirectoryNode * parent (dir->parent().get());
00195 if (parent) dir = parent;
00196 prefix += "../";
00197 }
00198 else if (*i == WordToken("."))
00199 prefix += "./";
00200 else {
00201 if (dir->hasChild(i->value())) {
00202 try {
00203 dir = & dir->getDirectory(i->value());
00204 }
00205 catch (std::bad_cast &) {
00206 return;
00207 }
00208 prefix += i->value() + "/";
00209 }
00210 else {
00211 DirectoryNode::ChildrenRange cs (dir->completions(i->value()));
00212 if (has_one_elt(cs)) {
00213 GenericNode & node (cs.begin()->second->followLink());
00214 if (!node.isDirectory())
00215 return;
00216 dir = static_cast<DirectoryNode*>(&node);
00217 prefix += cs.begin()->first + "/";
00218 }
00219 else
00220 return;
00221 }
00222 }
00223
00224 DirectoryNode::ChildrenRange cs (dir->completions(i->value()));
00225 for (DirectoryNode::ChildrenRange::iterator j (cs.begin()); j != cs.end(); ++j)
00226 completions.push_back(j->first + (j->second->followLink().isDirectory() ? "/" : " "));
00227 }
00228
00229
00230 #undef prefix_
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242