4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
5 // Competence Center NETwork research (NET), St. Augustin, GERMANY
6 // Stefan Bund <g0dil@berlios.de>
8 // This program is free software; you can redistribute it and/or modify
9 // it under the terms of the GNU General Public License as published by
10 // the Free Software Foundation; either version 2 of the License, or
11 // (at your option) any later version.
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU General Public License for more details.
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the
20 // Free Software Foundation, Inc.,
21 // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 \brief Editor non-inline non-template implementation */
27 //#include "Editor.ih"
30 #include <senf/Utils/membind.hh>
31 #include <senf/Scheduler/Scheduler.hh>
33 //#include "Editor.mpp"
35 ///////////////////////////////cc.p////////////////////////////////////////
37 prefix_ senf::term::BaseEditor::BaseEditor(AbstractTerminal & terminal)
38 : terminal_ (&terminal),
39 keyTimeout_ (senf::ClockService::milliseconds(DEFAULT_KEY_TIMEOUT_MS)),
40 timer_ ("senf::term::BaseEditor::keySequenceTimeout",
41 senf::membind(&BaseEditor::keySequenceTimeout, this)),
44 terminal_->setCallbacks(*this);
47 prefix_ void senf::term::BaseEditor::newline()
50 write(tifo_.getString(Terminfo::properties::ClrEol));
54 prefix_ void senf::term::BaseEditor::toColumn(unsigned c)
59 if (tifo_.hasProperty(Terminfo::properties::ParmRightCursor)) {
60 write(tifo_.formatString(Terminfo::properties::ParmRightCursor, c - column_));
64 char const * cuf1 (tifo_.getString(Terminfo::properties::CursorRight));
71 else if (c < column_) {
72 if (tifo_.hasProperty(Terminfo::properties::ParmLeftCursor)) {
73 write(tifo_.formatString(Terminfo::properties::ParmLeftCursor, column_ - c));
77 char const * cub1 (tifo_.getString(Terminfo::properties::CursorLeft));
86 prefix_ void senf::term::BaseEditor::put(char ch)
88 if (column_ >= width()-1)
94 prefix_ void senf::term::BaseEditor::put(std::string const & text)
96 if (text.size() > width()-column_-1) {
97 write(text.substr(0,width()-column_-1));
98 column_ = width() - 1;
102 column_ += text.size();
106 prefix_ void senf::term::BaseEditor::clearLine()
109 write(tifo_.getString(Terminfo::properties::ClrEol));
113 prefix_ void senf::term::BaseEditor::setBold()
115 if (tifo_.hasProperty(Terminfo::properties::EnterBoldMode) &&
116 tifo_.hasProperty(Terminfo::properties::ExitAttributeMode))
117 write(tifo_.getString(Terminfo::properties::EnterBoldMode));
120 prefix_ void senf::term::BaseEditor::setNormal()
122 if (tifo_.hasProperty(Terminfo::properties::EnterBoldMode) &&
123 tifo_.hasProperty(Terminfo::properties::ExitAttributeMode))
124 write(tifo_.getString(Terminfo::properties::ExitAttributeMode));
127 prefix_ void senf::term::BaseEditor::maybeClrScr()
129 if (tifo_.hasProperty(Terminfo::properties::ClearScreen))
130 write(tifo_.getString(Terminfo::properties::ClearScreen));
133 prefix_ unsigned senf::term::BaseEditor::currentColumn()
139 prefix_ bool senf::term::BaseEditor::cb_init()
142 tifo_.load(terminal_->terminalType());
143 keyParser_.load(tifo_);
145 catch (Terminfo::InvalidTerminfoException & ex) {
149 typedef Terminfo::properties p;
150 if (! (tifo_.hasProperty(p::ClrEol) &&
151 (tifo_.hasProperty(p::ParmRightCursor) || tifo_.hasProperty(p::CursorRight)) &&
152 (tifo_.hasProperty(p::ParmLeftCursor) || tifo_.hasProperty(p::CursorLeft))))
155 if (tifo_.hasProperty(Terminfo::properties::KeypadXmit))
156 write(tifo_.getString(Terminfo::properties::KeypadXmit));
160 prefix_ void senf::term::BaseEditor::cb_charReceived(char c)
163 timer_.timeout(senf::scheduler::eventTime() + keyTimeout_);
167 prefix_ void senf::term::BaseEditor::cb_windowSizeChanged()
169 if (column_ >= width())
173 prefix_ void senf::term::BaseEditor::keySequenceTimeout()
175 while (!inputBuffer_.empty()) {
177 v_keyReceived(keycode_t(inputBuffer_[0]));
178 inputBuffer_.erase(0, 1);
182 prefix_ void senf::term::BaseEditor::processKeys()
185 std::pair<senf::term::KeyParser::keycode_t, std::string::size_type> result
186 (keyParser_.lookup(inputBuffer_));
187 if (result.first == senf::term::KeyParser::Incomplete)
189 v_keyReceived(result.first);
190 inputBuffer_.erase(0, result.second);
191 } while (! inputBuffer_.empty());
195 prefix_ unsigned senf::term::BaseEditor::width()
197 return terminal_->width();
200 prefix_ void senf::term::BaseEditor::write(char ch)
202 terminal_->write(ch);
205 prefix_ void senf::term::BaseEditor::write(std::string const & s)
207 for (std::string::const_iterator i (s.begin()); i != s.end(); ++i)
211 ///////////////////////////////////////////////////////////////////////////
213 prefix_ senf::term::LineEditor::LineEditor(AbstractTerminal & terminal, AcceptCallback cb)
214 : BaseEditor(terminal), enabled_ (true), prompt_ ("$"), promptWidth_ (1u), editWidth_ (0u),
215 text_ (""), point_ (0u), displayPos_ (0u), lastKey_ (0u), callback_ (cb), historyPoint_ (0u)
217 defineKey(KeyParser::Return, &bindings::accept);
218 defineKey(KeyParser::Right, &bindings::forwardChar);
219 defineKey(KeyParser::Left, &bindings::backwardChar);
220 defineKey(KeyParser::Up, &bindings::prevHistory);
221 defineKey(KeyParser::Down, &bindings::nextHistory);
222 defineKey(KeyParser::Backspace, &bindings::backwardDeleteChar);
223 defineKey(KeyParser::Delete, &bindings::deleteChar);
224 defineKey(KeyParser::Home, &bindings::beginningOfLine);
225 defineKey(KeyParser::End, &bindings::endOfLine);
226 defineKey(KeyParser::Ctrl('K'), &bindings::deleteToEndOfLine);
227 defineKey(KeyParser::Ctrl('A'), &bindings::beginningOfLine);
228 defineKey(KeyParser::Ctrl('E'), &bindings::endOfLine);
229 defineKey(KeyParser::Ctrl('D'), &bindings::deleteChar);
230 defineKey(KeyParser::Ctrl('C'), &bindings::restartEdit);
231 defineKey(KeyParser::Ctrl('L'), &bindings::clearScreen);
234 prefix_ void senf::term::LineEditor::prompt(std::string const & text)
237 promptWidth_ = prompt_.size();
238 if (promptWidth_ > width() - 4 && width() > 4)
239 promptWidth_ = width() - 4;
240 editWidth_ = width() - promptWidth_ - 3;
245 prefix_ void senf::term::LineEditor::set(std::string const & text, unsigned pos)
249 if (point_ > text.size())
250 point_ = text.size();
252 if (point_ > editWidth_)
253 displayPos_ = point_ - editWidth_;
257 prefix_ void senf::term::LineEditor::show()
265 prefix_ void senf::term::LineEditor::hide()
273 prefix_ void senf::term::LineEditor::accept()
283 prefix_ void senf::term::LineEditor::clear()
286 historyPoint_ = history_.size();
289 prefix_ void senf::term::LineEditor::redisplay()
291 redisplayNeeded_ = true;
294 prefix_ void senf::term::LineEditor::forceRedisplay()
300 if (prompt_.size() > promptWidth_)
301 put(prompt_.substr(prompt_.size()-promptWidth_));
304 put( displayPos_ > 0 ? '<' : ' ' );
305 if (text_.size() > displayPos_ + editWidth_) {
306 toColumn(editWidth_ + promptWidth_ + 1);
308 toColumn(promptWidth_ + 1);
311 put(text_.substr(displayPos_, editWidth_));
312 toColumn(point_ - displayPos_ + promptWidth_ + 1);
313 redisplayNeeded_ = false;
316 prefix_ void senf::term::LineEditor::gotoChar(unsigned n)
319 if (point_ > text_.size())
320 point_ = text_.size();
321 if (point_ < displayPos_)
322 displayPos_ = point_;
323 if (point_ > displayPos_+editWidth_)
324 displayPos_ = point_-editWidth_;
328 prefix_ void senf::term::LineEditor::scrollTo(unsigned n)
331 if (displayPos_ > text_.size())
332 displayPos_ = text_.size();
333 if (point_ < displayPos_)
334 point_ = displayPos_;
335 if (point_ > displayPos_+editWidth_)
336 point_ = displayPos_+editWidth_;
340 prefix_ void senf::term::LineEditor::deleteChar(unsigned n)
342 if (point_ >= text_.size())
344 text_.erase(point_, n);
348 prefix_ void senf::term::LineEditor::insert(char ch)
350 text_.insert(point_, std::string(1, ch));
355 prefix_ void senf::term::LineEditor::insert(std::string const & text)
357 text_.insert(point_, text);
358 gotoChar(point_+text.size());
362 prefix_ void senf::term::LineEditor::pushHistory(std::string const & text)
365 && (historyPoint_ == history_.size() || history_[historyPoint_] != text)
366 && (history_.empty() || history_.back() != text)) {
367 history_.push_back(text);
368 while (history_.size() > MAX_HISTORY_SIZE)
369 history_.erase(history_.begin());
370 historyPoint_ = history_.size() - 1;
374 prefix_ void senf::term::LineEditor::prevHistory()
376 if (historyPoint_ <= 0)
379 std::string entry (history_[--historyPoint_]);
380 set(entry, entry.size());
383 prefix_ void senf::term::LineEditor::nextHistory()
385 if (historyPoint_ >= history_.size())
389 if (historyPoint_ >= history_.size())
392 std::string entry (history_[historyPoint_]);
393 set(entry, entry.size());
397 prefix_ std::string const & senf::term::LineEditor::text()
402 prefix_ unsigned senf::term::LineEditor::point()
407 prefix_ unsigned senf::term::LineEditor::displayPos()
412 prefix_ senf::term::LineEditor::keycode_t senf::term::LineEditor::lastKey()
417 prefix_ void senf::term::LineEditor::defineKey(keycode_t key, KeyBinding binding)
419 bindings_[key] = binding;
422 prefix_ void senf::term::LineEditor::unsetKey(keycode_t key)
424 bindings_.erase(key);
427 prefix_ bool senf::term::LineEditor::cb_init()
429 if (!BaseEditor::cb_init())
436 prefix_ void senf::term::LineEditor::cb_windowSizeChanged()
438 BaseEditor::cb_windowSizeChanged();
444 prefix_ void senf::term::LineEditor::v_keyReceived(keycode_t key)
449 KeyMap::iterator i (bindings_.find(key));
450 if (i != bindings_.end())
452 else if (key >= ' ' && key < 256)
454 if (redisplayNeeded_)
458 ///////////////////////////////////////////////////////////////////////////
460 prefix_ void senf::term::bindings::selfInsertCommand(LineEditor & editor)
462 LineEditor::keycode_t key (editor.lastKey());
463 if (key >= ' ' && key < 256)
467 prefix_ void senf::term::bindings::forwardChar(LineEditor & editor)
469 editor.gotoChar(editor.point()+1);
472 prefix_ void senf::term::bindings::backwardChar(LineEditor & editor)
474 unsigned p (editor.point());
476 editor.gotoChar(p-1);
479 prefix_ void senf::term::bindings::accept(LineEditor & editor)
484 prefix_ void senf::term::bindings::backwardDeleteChar(LineEditor & editor)
486 unsigned p (editor.point());
488 editor.gotoChar(p-1);
493 prefix_ void senf::term::bindings::deleteChar(LineEditor & editor)
498 prefix_ void senf::term::bindings::beginningOfLine(LineEditor & editor)
503 prefix_ void senf::term::bindings::endOfLine(LineEditor & editor)
505 editor.gotoChar(editor.text().size());
508 prefix_ void senf::term::bindings::deleteToEndOfLine(LineEditor & editor)
510 editor.deleteChar(editor.text().size()-editor.point());
513 prefix_ void senf::term::bindings::restartEdit(LineEditor & editor)
520 prefix_ void senf::term::bindings::prevHistory(LineEditor & editor)
522 editor.prevHistory();
525 prefix_ void senf::term::bindings::nextHistory(LineEditor & editor)
527 editor.nextHistory();
530 prefix_ void senf::term::bindings::clearScreen(LineEditor & editor)
532 editor.maybeClrScr();
534 editor.forceRedisplay();
537 ///////////////////////////////cc.e////////////////////////////////////////
539 //#include "Editor.mpp"
545 // comment-column: 40
546 // c-file-style: "senf"
547 // indent-tabs-mode: nil
548 // ispell-local-dictionary: "american"
549 // compile-command: "scons -u test"