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 public header */
26 #ifndef HH_SENF_Utils_Termlib_Editor_
27 #define HH_SENF_Utils_Termlib_Editor_ 1
33 #include <senf/Scheduler/ClockService.hh>
34 #include <senf/Scheduler/TimerEvent.hh>
35 #include "AbstractTerminal.hh"
36 #include "Terminfo.hh"
38 //#include "Editor.mpp"
39 ///////////////////////////////hh.p////////////////////////////////////////
44 /** \brief Provide editor support terminal functionality
46 This base class utilizes an arbitrary AbstractTerminal and provides terminfo based
47 terminal navigation and key parsing.
49 All navigation is relative to the current line. The display area can then be extended
50 downwards up to a maximum of height() lines. Resetting this extended display area will
51 return to a one line area containing only the top line.
53 All navigation is restricted to a width() x height() area. The last column may not be
54 written to since auto-margin terminals will move the cursor to the next line when writing to
57 This base class calls v_keyReceived() which must be defined in a derived class whenever a
61 : public AbstractTerminal::Callbacks
64 typedef KeyParser::keycode_t keycode_t;
66 static unsigned const DEFAULT_KEY_TIMEOUT_MS = 500u;
68 explicit BaseEditor(AbstractTerminal & terminal);
70 void newline(); ///< Move to beginning of a new, empty line
71 void toColumn(unsigned c); ///< Move cursor to column \p c
72 void put(char ch); ///< Write \p ch at current column
73 void put(std::string const & text); ///< Write \a text starting at current column
74 void clearLine(); ///< Clear current line and move cursor to first column
75 void setBold(); ///< Set bold char display
76 void setNormal(); ///< Set normal char display
77 void maybeClrScr(); ///< Clear screen if possible
79 void toLine(unsigned l); ///< Move to relative display line \a l
80 void reset(); ///< Reset display area to single line
82 unsigned currentColumn() const; ///< Return number of current column
83 unsigned currentLine() const; ///< Return number of current relative line
84 unsigned width(); ///< Return current screen width
85 unsigned height(); ///< Return current screen height
88 virtual bool cb_init(); ///< Called when terminal is initialized
89 virtual void cb_windowSizeChanged();
90 ///< Called whenever the terminal window size changes
95 virtual void v_keyReceived(keycode_t key) = 0; ///< Called whenever a key is received
98 virtual void cb_charReceived(char c);
100 void keySequenceTimeout();
104 void write(std::string const & s);
106 AbstractTerminal * terminal_;
108 KeyParser keyParser_;
109 std::string inputBuffer_;
110 ClockService::clock_type keyTimeout_;
111 scheduler::TimerEvent timer_;
113 unsigned displayHeight_;
117 /** \brief Single line interactive text editor
119 LineEditor implements a single-line input widget on an arbitrary AbstractTerminal.
121 \li It supports all the customary editing functions
122 \li It is possible to arbitrarily assign functions to keys via a key map
123 \li LineEditor has builtin TAB completion support
124 \li The LineEditor has a built-in history
125 \li The LineEditor supports an arbitrary auxiliary display area below the input line
126 \li The LineEditor has hide() / show() support to allow editing to be temporarily
129 The LineEditor will query the user for an input line. When the user accepts a line,
130 LineEditor will call a user callback function. After the callback has been called, the
131 editor is disabled. To accept a new input line, call show().
133 \section editor_keymap The editor key map
135 Keys are defined in the keymap using defineKey(). The default bindings are:
138 <tr><td>\c Return</td> <td>bindings::accept</td></tr>
139 <tr><td>\c Right</td> <td>bindings::forwardChar</td></tr>
140 <tr><td>\c Left</td> <td>bindings::backwardChar</td></tr>
141 <tr><td>\c Up</td> <td>bindings::prevHistory</td></tr>
142 <tr><td>\c Down</td> <td>bindings::nextHistory</td></tr>
143 <tr><td>\c Backspace</td> <td>bindings::backwardDeleteChar</td></tr>
144 <tr><td>\c Delete</td> <td>bindings::deleteChar</td></tr>
145 <tr><td>\c Home</td> <td>bindings::beginningOfLine</td></tr>
146 <tr><td>\c End</td> <td>bindings::endOfLine</td></tr>
147 <tr><td>\c Ctrl-K</td> <td>bindings::deleteToEndOfLine</td></tr>
148 <tr><td>\c Ctrl-A</td> <td>bindings::beginningOfLine</td></tr>
149 <tr><td>\c Ctrl-E</td> <td>bindings::endOfLine</td></tr>
150 <tr><td>\c Ctrl-D</td> <td>bindings::deleteChar</td></tr>
151 <tr><td>\c Ctrl-C</td> <td>bindings::restartEdit</td></tr>
152 <tr><td>\c Ctrl-L</td> <td>bindings::clearScreen</td></tr>
155 See the senf::term::bindings namespace for a list of all default provided key binding
159 \section editor_complete Completion suppoprt
161 Completion support is provided by senf::term::bindings::complete(). To use the completer,
162 you need to implement a completion function and pass it as second argument to
163 bindings::complete():
166 void myCompleter(senf::term::LineEditor & editor, unsigned b, unsigned e,
167 std::vector<std::string> & completions)
169 // Get text to complete
170 std::string text (editor.text().substr(b, e-b));
172 // Return possible completions in 'completions' array
173 completions.push_back( ... );
176 senf::term::LineEditor editor (...);
177 editor.defineKey(senf::term::KeyParser::TAB,
178 boost::bind(&senf::term::bindings::complete, _1, &myCompleter));
181 When \c myCompleter is a class member, use senf::membind() and pass this instead of \c
182 &myCompleter to \c boost::bind() and thus to senf::term::bindings::complete.
185 \section editor_auxarea The aux display area
187 The auxiliary display area is accessed using auxDisplay() and clearAuxDisplay(). The aux
188 display area is \e cleared \e before each new key is processed. Therefore it is only
189 temporary. The aux display area however will survive hide() / show().
192 \section editor_hideshow Temporarily disabling the editor
194 Calling hide() will temporarily disable the editor. All editor display will be
195 removed. Calling show() will redisplay the editor in it's current state including the aux
202 ///////////////////////////////////////////////////////////////////////////
205 typedef boost::function<void (LineEditor&)> KeyBinding; ///< Type of a key binding function
206 typedef boost::function<void (std::string const &)> AcceptCallback;
207 ///< Callback function type
209 static unsigned const MAX_HISTORY_SIZE = 1024u;
211 ///////////////////////////////////////////////////////////////////////////
213 LineEditor(AbstractTerminal & terminal, AcceptCallback cb);
214 ///< Create a LineEditor
215 /**< \parm[in] terminal abstract terminal interface
216 \parm[in] cb callback to call for complete input
219 ///////////////////////////////////////////////////////////////////////////
221 ///\name Overall edit control
224 void show(); ///< Enable editor widget
225 void hide(); ///< Disable editor widget
226 void accept(); ///< Accept current user input and call the accept callback
227 void clear(); ///< Clear editor buffer
228 void redisplay(); ///< Mark the editor buffer for redisplay
229 void forceRedisplay(); ///< Redisplay the editor buffer \e now
230 void prompt(std::string const & text); ///< Set prompt string
234 ///\name Cursor and display movement
237 void gotoChar(unsigned n); ///< Move cursor to position \a n
238 void scrollTo(unsigned n); ///< Move positon \n to beginning of display line
242 ///\name Text manipulation
245 void deleteChar(unsigned n=1); ///< Delete \a n characters at point
246 void insert(char ch); ///< Insert \a ch at point
247 void insert(std::string const & text); ///< Insert \a text at point
248 void set(std::string const & text, unsigned pos = 0u);
249 ///< Set edit buffer contents
250 /**< The edit buffer contents will be replaced by \a
251 text. The cursor will be placed at position \a pos
259 void pushHistory(std::string const & text); ///< Add string \a text to history
260 void prevHistory(); ///< Switch to previous history entry
261 void nextHistory(); ///< Switch to next history entry
268 void auxDisplay(int line, std::string const & text);
269 ///< Display \a text on aux display line \a lilne
270 unsigned maxAuxDisplayHeight(); ///< Get maximum height of the aux display area
271 void clearAuxDisplay(); ///< Clear the aux display area
275 ///\name Get information
278 std::string const & text(); ///< Get current editor buffer contents
279 unsigned point(); ///< Get current cursor position
280 unsigned displayPos(); ///< Get current display position
281 keycode_t lastKey(); ///< Get last key code received
285 ///\name Key bindings
288 void defineKey(keycode_t key, KeyBinding binding);
289 ///< Bind key \a key to \a binding
290 void unsetKey(keycode_t key); ///< Remove all bindings for \a key
295 virtual bool cb_init();
296 virtual void cb_windowSizeChanged();
297 virtual void v_keyReceived(keycode_t key);
299 typedef std::map<keycode_t, KeyBinding> KeyMap;
300 typedef std::vector<std::string> History;
301 typedef std::vector<std::string> AuxDisplay;
304 bool redisplayNeeded_;
306 unsigned promptWidth_;
310 unsigned displayPos_;
312 AcceptCallback callback_;
315 unsigned historyPoint_;
316 AuxDisplay auxDisplay_;
319 /** \brief LineEditor key bindings
323 void selfInsertCommand (LineEditor & editor); ///< Insert key as literal character
324 void forwardChar (LineEditor & editor); ///< Move one char forward
325 void backwardChar (LineEditor & editor); ///< Move one char backwards
326 void accept (LineEditor & editor); ///< Accept input line
327 void backwardDeleteChar (LineEditor & editor); ///< Delete char before cursor
328 void deleteChar (LineEditor & editor); ///< Delete char at cursor
329 void beginningOfLine (LineEditor & editor); ///< Move to beginning of line
330 void endOfLine (LineEditor & editor); ///< Move to end of line
331 void deleteToEndOfLine (LineEditor & editor); ///< Delete from cursor to end of line
332 void restartEdit (LineEditor & editor); ///< Clear edit buffer and restart edit
333 void prevHistory (LineEditor & editor); ///< Move to previous history entry
334 void nextHistory (LineEditor & editor); ///< Move to next history entry
335 void clearScreen (LineEditor & editor); ///< Clear screen and redisplay editor
337 typedef boost::function<void (LineEditor &, unsigned b, unsigned e, std::vector<std::string> &)> Completer;
338 void complete (LineEditor & editor, Completer completer);
339 ///< Complete text at cursor
340 /**< This function calls \a completer to find the list of
341 possible completions for the text between \a b and \a e
342 (as passed to the completer). The completer must add
343 all possible completions to the completions vector.
345 \see \ref editor_complete */
351 ///////////////////////////////hh.e////////////////////////////////////////
352 //#include "Editor.cci"
353 //#include "Editor.ct"
354 //#include "Editor.cti"
361 // comment-column: 40
362 // c-file-style: "senf"
363 // indent-tabs-mode: nil
364 // ispell-local-dictionary: "american"
365 // compile-command: "scons -u test"