4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
6 // The contents of this file are subject to the Fraunhofer FOKUS Public License
7 // Version 1.0 (the "License"); you may not use this file except in compliance
8 // with the License. You may obtain a copy of the License at
9 // http://senf.berlios.de/license.html
11 // The Fraunhofer FOKUS Public License Version 1.0 is based on,
12 // but modifies the Mozilla Public License Version 1.1.
13 // See the full license text for the amendments.
15 // Software distributed under the License is distributed on an "AS IS" basis,
16 // WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
17 // for the specific language governing rights and limitations under the License.
19 // The Original Code is Fraunhofer FOKUS code.
21 // The Initial Developer of the Original Code is Fraunhofer-Gesellschaft e.V.
22 // (registered association), Hansastraße 27 c, 80686 Munich, Germany.
23 // All Rights Reserved.
26 // Stefan Bund <g0dil@berlios.de>
29 \brief Editor public header */
31 #ifndef HH_SENF_Utils_Termlib_Editor_
32 #define HH_SENF_Utils_Termlib_Editor_ 1
38 #include <senf/Scheduler/ClockService.hh>
39 #include <senf/Scheduler/TimerEvent.hh>
40 #include "AbstractTerminal.hh"
41 #include "Terminfo.hh"
43 //#include "Editor.mpp"
44 //-/////////////////////////////////////////////////////////////////////////////////////////////////
49 /** \brief Provide editor support terminal functionality
51 This base class utilizes an arbitrary AbstractTerminal and provides terminfo based
52 terminal navigation and key parsing.
54 All navigation is relative to the current line. The display area can then be extended
55 downwards up to a maximum of height() lines. Resetting this extended display area will
56 return to a one line area containing only the top line.
58 All navigation is restricted to a width() x height() area. The last column may not be
59 written to since auto-margin terminals will move the cursor to the next line when writing to
62 This base class calls v_keyReceived() which must be defined in a derived class whenever a
66 : public AbstractTerminal::Callbacks
69 typedef KeyParser::keycode_t keycode_t;
71 static unsigned const DEFAULT_KEY_TIMEOUT_MS = 500u;
73 explicit BaseEditor(AbstractTerminal & terminal);
75 void newline(); ///< Move to beginning of a new, empty line
76 void toColumn(unsigned c); ///< Move cursor to column \p c
77 void put(char ch); ///< Write \p ch at current column
78 void put(std::string const & text); ///< Write \a text starting at current column
79 void clearLine(); ///< Clear current line and move cursor to first column
80 void setBold(); ///< Set bold char display
81 void setNormal(); ///< Set normal char display
82 void maybeClrScr(); ///< Clear screen if possible
84 void toLine(unsigned l); ///< Move to relative display line \a l
85 void reset(); ///< Reset display area to single line
87 unsigned currentColumn() const; ///< Return number of current column
88 unsigned currentLine() const; ///< Return number of current relative line
89 unsigned width() const; ///< Return current screen width
90 unsigned height() const; ///< Return current screen height
93 virtual bool cb_init(); ///< Called when terminal is initialized
94 virtual void cb_windowSizeChanged();
95 ///< Called whenever the terminal window size changes
100 virtual void v_keyReceived(keycode_t key) = 0; ///< Called whenever a key is received
103 virtual void cb_charReceived(char c);
105 void keySequenceTimeout();
109 void write(std::string const & s);
111 AbstractTerminal * terminal_;
113 KeyParser keyParser_;
114 std::string inputBuffer_;
115 ClockService::clock_type keyTimeout_;
116 scheduler::TimerEvent timer_;
118 unsigned displayHeight_;
122 /** \brief Single line interactive text editor
124 LineEditor implements a single-line input widget on an arbitrary AbstractTerminal.
126 \li It supports all the customary editing functions
127 \li It is possible to arbitrarily assign functions to keys via a key map
128 \li LineEditor has builtin TAB completion support
129 \li The LineEditor has a built-in history
130 \li The LineEditor supports an arbitrary auxiliary display area below the input line
131 \li The LineEditor has hide() / show() support to allow editing to be temporarily
134 The LineEditor will query the user for an input line. When the user accepts a line,
135 LineEditor will call a user callback function. After the callback has been called, the
136 editor is disabled. To accept a new input line, call show().
138 \section editor_keymap The editor key map
140 Keys are defined in the keymap using defineKey(). The default bindings are:
143 <tr><td>\c Return</td> <td>bindings::accept</td></tr>
144 <tr><td>\c Right</td> <td>bindings::forwardChar</td></tr>
145 <tr><td>\c Left</td> <td>bindings::backwardChar</td></tr>
146 <tr><td>\c Up</td> <td>bindings::prevHistory</td></tr>
147 <tr><td>\c Down</td> <td>bindings::nextHistory</td></tr>
148 <tr><td>\c Backspace</td> <td>bindings::backwardDeleteChar</td></tr>
149 <tr><td>\c Delete</td> <td>bindings::deleteChar</td></tr>
150 <tr><td>\c Home</td> <td>bindings::beginningOfLine</td></tr>
151 <tr><td>\c End</td> <td>bindings::endOfLine</td></tr>
152 <tr><td>\c Ctrl-K</td> <td>bindings::deleteToEndOfLine</td></tr>
153 <tr><td>\c Ctrl-A</td> <td>bindings::beginningOfLine</td></tr>
154 <tr><td>\c Ctrl-E</td> <td>bindings::endOfLine</td></tr>
155 <tr><td>\c Ctrl-D</td> <td>bindings::deleteChar</td></tr>
156 <tr><td>\c Ctrl-C</td> <td>bindings::restartEdit</td></tr>
157 <tr><td>\c Ctrl-L</td> <td>bindings::clearScreen</td></tr>
160 See the senf::term::bindings namespace for a list of all default provided key binding
164 \section editor_complete Completion support
166 Completion support is provided by senf::term::bindings::complete(). To use the completer,
167 you need to implement a completion function and pass it as second argument to
168 bindings::complete():
171 void myCompleter(senf::term::LineEditor & editor, unsigned & b, unsigned & e,
172 std::string & prefix, std::vector<std::string> & completions)
174 // Get text to complete
175 std::string text (editor.text().substr(b, e-b));
177 // Return possible completions in 'completions' array
178 completions.push_back( ... );
181 senf::term::LineEditor editor (...);
182 editor.defineKey(senf::term::KeyParser::TAB,
183 boost::bind(&senf::term::bindings::complete, _1, &myCompleter));
186 When \c myCompleter is a class member, use senf::membind() and pass this instead of \c
187 &myCompleter to \c boost::bind() and thus to senf::term::bindings::complete.
189 The completion protocol is as follows: When completion is desired, the completer function is
190 called. \a b and \a e are set to 0 and <tt>editor.point()</tt> respectively. \a prefix and
191 \a completions are empty.
193 \li the completer may restrict the to-be-completed string to any subrange by changing \a b
194 and \a e accordingly.
195 \li If there is an initial substring which applies to \e all completions but should not be
196 listed in the list of completions, assign this value to \a prefix.
197 \li Add all possible completions to the \a completions vector not including the \a prefix.
198 \li The completion result is taken from the size of the \a completions vector \e only: If
199 this vector is empty, completion failed (even if \a prefix is set), a single entry in \a
200 completions (even if it is the empty string) signals a unique completion.
203 \section editor_auxarea The aux display area
205 The auxiliary display area is accessed using auxDisplay() and clearAuxDisplay(). The aux
206 display area is \e cleared \e before each new key is processed. Therefore it is only
207 temporary. The aux display area however will survive hide() / show().
210 \section editor_hideshow Temporarily disabling the editor
212 Calling hide() will temporarily disable the editor. All editor display will be
213 removed. Calling show() will redisplay the editor in it's current state including the aux
220 //-////////////////////////////////////////////////////////////////////////
223 typedef boost::function<void (LineEditor&)> KeyBinding; ///< Type of a key binding function
224 typedef boost::function<void (std::string const &)> AcceptCallback;
225 ///< Callback function type
227 static unsigned const MAX_HISTORY_SIZE = 1024u;
229 //-////////////////////////////////////////////////////////////////////////
231 LineEditor(AbstractTerminal & terminal, AcceptCallback cb);
232 ///< Create a LineEditor
233 /**< \param[in] terminal abstract terminal interface
234 \param[in] cb callback to call for complete input
237 //-////////////////////////////////////////////////////////////////////////
239 ///\name Overall edit control
242 void show(); ///< Enable editor widget
243 void hide(); ///< Disable editor widget
244 void accept(); ///< Accept current user input and call the accept callback
245 void clear(); ///< Clear editor buffer
246 void redisplay(); ///< Mark the editor buffer for redisplay
247 void forceRedisplay(); ///< Redisplay the editor buffer \e now
248 void prompt(std::string const & text); ///< Set prompt string
252 ///\name Cursor and display movement
255 void gotoChar(unsigned n); ///< Move cursor to position \a n
256 void scrollTo(unsigned n); ///< Move position \n to beginning of display line
260 ///\name Text manipulation
263 void deleteChar(unsigned n=1); ///< Delete \a n characters at point
264 void insert(char ch); ///< Insert \a ch at point
265 void insert(std::string const & text); ///< Insert \a text at point
266 void set(std::string const & text, unsigned pos = 0u);
267 ///< Set edit buffer contents
268 /**< The edit buffer contents will be replaced by \a
269 text. The cursor will be placed at position \a pos
277 void pushHistory(std::string const & text, bool accept = false);
278 ///< Add string \a text to history
279 void prevHistory(); ///< Switch to previous history entry
280 void nextHistory(); ///< Switch to next history entry
287 void auxDisplay(unsigned line, std::string const & text);
288 ///< Display \a text on aux display line \a line
289 unsigned maxAuxDisplayHeight(); ///< Get maximum height of the aux display area
290 void clearAuxDisplay(); ///< Clear the aux display area
294 ///\name Get information
297 std::string const & text(); ///< Get current editor buffer contents
298 unsigned point(); ///< Get current cursor position
299 unsigned displayPos(); ///< Get current display position
300 keycode_t lastKey(); ///< Get last key code received
304 ///\name Key bindings
307 void defineKey(keycode_t key, KeyBinding binding);
308 ///< Bind key \a key to \a binding
309 void unsetKey(keycode_t key); ///< Remove all bindings for \a key
314 virtual bool cb_init();
315 virtual void cb_windowSizeChanged();
316 virtual void v_keyReceived(keycode_t key);
318 typedef std::map<keycode_t, KeyBinding> KeyMap;
319 typedef std::vector<std::string> History;
320 typedef std::vector<std::string> AuxDisplay;
323 bool redisplayNeeded_;
325 unsigned promptWidth_;
329 unsigned displayPos_;
331 AcceptCallback callback_;
334 unsigned historyPoint_;
335 AuxDisplay auxDisplay_;
338 /** \brief LineEditor key bindings
342 void selfInsertCommand (LineEditor & editor); ///< Insert key as literal character
343 void forwardChar (LineEditor & editor); ///< Move one char forward
344 void backwardChar (LineEditor & editor); ///< Move one char backwards
345 void accept (LineEditor & editor); ///< Accept input line
346 void acceptWithRepeat (LineEditor & editor); ///< Accept, possibly repeat last history entry
347 void backwardDeleteChar (LineEditor & editor); ///< Delete char before cursor
348 void deleteChar (LineEditor & editor); ///< Delete char at cursor
349 void beginningOfLine (LineEditor & editor); ///< Move to beginning of line
350 void endOfLine (LineEditor & editor); ///< Move to end of line
351 void deleteToEndOfLine (LineEditor & editor); ///< Delete from cursor to end of line
352 void restartEdit (LineEditor & editor); ///< Clear edit buffer and restart edit
353 void prevHistory (LineEditor & editor); ///< Move to previous history entry
354 void nextHistory (LineEditor & editor); ///< Move to next history entry
355 void clearScreen (LineEditor & editor); ///< Clear screen and redisplay editor
357 typedef boost::function<void (LineEditor &, unsigned & b, unsigned & e,
358 std::string & prefix, std::vector<std::string> &)> Completer;
359 void complete (LineEditor & editor, Completer completer);
360 ///< Complete text at cursor
361 /**< This function calls \a completer to find the list of
362 possible completions for the text between \a b and \a e
363 (as passed to the completer). The completer must add
364 all possible completions to the \a completions vector.
366 \see \ref editor_complete */
372 //-/////////////////////////////////////////////////////////////////////////////////////////////////
373 //#include "Editor.cci"
374 //#include "Editor.ct"
375 //#include "Editor.cti"
382 // comment-column: 40
383 // c-file-style: "senf"
384 // indent-tabs-mode: nil
385 // ispell-local-dictionary: "american"
386 // compile-command: "scons -u test"