1 | // **************************************************************************
|
---|
2 | /** @class Shell
|
---|
3 |
|
---|
4 | @brief Implementation of a console based user shell with an input and output window
|
---|
5 |
|
---|
6 | Shell is based on the ReadlineWindow class. It creates two windows
|
---|
7 | (panels) using ncurses which are used for input and output. The output
|
---|
8 | window panel is displayed on top of the input panel, but can be hidden
|
---|
9 | for example by pressing F1.
|
---|
10 |
|
---|
11 | The idea is that continous messages like logging messages do not interfere
|
---|
12 | with the input area, although one still has both diplayed in the same
|
---|
13 | console window.
|
---|
14 |
|
---|
15 | To get a list of the command and functions supported by Shell
|
---|
16 | type 'h' or 'help' at a command line prompt.
|
---|
17 |
|
---|
18 | The usage is quite simple. Instantiate an object of Shell with the
|
---|
19 | programname as an argument. For its meaning see the base class
|
---|
20 | documentation Readline::Readline(). The created input- and output-
|
---|
21 | stream can be accessed through GetStreamIn() and GetStreamOut()
|
---|
22 | whihc are both ostreams, one redirected to the input window and the
|
---|
23 | other one redirected to the output window. Especially, GetStreamIn()
|
---|
24 | should not be used while the Readline prompt is in progress, but can for
|
---|
25 | example be used to display errors about what was entered.
|
---|
26 |
|
---|
27 | The recommanded way of usage is:
|
---|
28 |
|
---|
29 | \code
|
---|
30 |
|
---|
31 | static Shell shell("myprog"); // readline will read the myprog.his history file
|
---|
32 |
|
---|
33 | while (1)
|
---|
34 | {
|
---|
35 | string txt = shell.Prompt("prompt> ");
|
---|
36 | if (txt=="quit)
|
---|
37 | break;
|
---|
38 |
|
---|
39 | // ... do something ...
|
---|
40 |
|
---|
41 | shell.AddHistory(txt);
|
---|
42 | }
|
---|
43 |
|
---|
44 | // On destruction redline will write the current history to the file
|
---|
45 | // By declaring the Shell static the correct terminal is restored even
|
---|
46 | // the program got killed (not if killed with SIGABRT)
|
---|
47 |
|
---|
48 | \endcode
|
---|
49 |
|
---|
50 | If for some reason the terminal is not correctly restored type (maybe blindly)
|
---|
51 | <I>reset</I> in your console. This should restor everything back to normal.
|
---|
52 |
|
---|
53 | @section References
|
---|
54 |
|
---|
55 | - <A HREF="http://cnswww.cns.cwru.edu/php/chet/readline/rltop.html">GNU Readline</A>
|
---|
56 | - <A HREF="http://www.gnu.org/software/ncurses">GNU Ncurses</A>
|
---|
57 |
|
---|
58 |
|
---|
59 | @todo
|
---|
60 | - Introduce the possibility to scroll in both windows
|
---|
61 | - Add redisplay functionality for both panels if the console was resized
|
---|
62 |
|
---|
63 | */
|
---|
64 | // **************************************************************************
|
---|
65 | #include "Shell.h"
|
---|
66 |
|
---|
67 | #include <fstream>
|
---|
68 | #include <iostream>
|
---|
69 |
|
---|
70 | #include <signal.h> // SIGWINCH
|
---|
71 | #include <sys/wait.h> // waitpid
|
---|
72 | #include <sys/ioctl.h> // ioctl
|
---|
73 |
|
---|
74 | #include <panel.h>
|
---|
75 |
|
---|
76 | #define FORK_ALLOWED
|
---|
77 |
|
---|
78 | using namespace std;
|
---|
79 |
|
---|
80 | Shell *Shell::This = 0;
|
---|
81 |
|
---|
82 | // --------------------------------------------------------------------------
|
---|
83 | //
|
---|
84 | //! This initializes the Ncurses environment. Since the ncurses environment
|
---|
85 | //! is global only one instance of this class is allowed.
|
---|
86 | //!
|
---|
87 | //! The first 8 color pairs (COLOR_PAIR) are set to the first 8 color
|
---|
88 | //! with default background.
|
---|
89 | //!
|
---|
90 | //! The shells windows and panels are created. And their pointers are
|
---|
91 | //! propagated to the two associated WindowLog streams.
|
---|
92 | //!
|
---|
93 | //! Also some key bindings are initialized.
|
---|
94 | //
|
---|
95 | Shell::Shell(const char *prgname) : ReadlineWindow(prgname),
|
---|
96 | fPanelHeight(13), fIsVisible(1), fLine(0)
|
---|
97 | {
|
---|
98 | if (stdscr!=0)
|
---|
99 | {
|
---|
100 | endwin();
|
---|
101 | cout << "ERROR - Only one instance of class Shell is allowed." << endl;
|
---|
102 | exit(-1);
|
---|
103 | }
|
---|
104 |
|
---|
105 | This = this;
|
---|
106 |
|
---|
107 | // ---------------------- Setup ncurses -------------------------
|
---|
108 |
|
---|
109 | initscr(); // Start curses mode
|
---|
110 |
|
---|
111 | cbreak(); // Line buffering disabled, Pass on
|
---|
112 | noecho(); // Switch off echo mode
|
---|
113 | nonl(); // Associate return with CR
|
---|
114 |
|
---|
115 | intrflush(stdscr, FALSE);
|
---|
116 | keypad(stdscr, FALSE); // Switch off keymapping for function keys
|
---|
117 |
|
---|
118 | start_color(); // Initialize ncurses colors
|
---|
119 | use_default_colors(); // Assign terminal default colors to -1
|
---|
120 | //assume_default_colors(-1, -1); // standard terminal colors assigned to pair 0
|
---|
121 |
|
---|
122 | // Setup colors
|
---|
123 | for (int i=1; i<8; i++)
|
---|
124 | init_pair(i, i, -1); // -1: def background
|
---|
125 |
|
---|
126 | signal(SIGWINCH, HandleResizeImp); // Attach HandleResize to SIGWINCH signal
|
---|
127 |
|
---|
128 | // ---------------------- Setup pansl --------------------------
|
---|
129 |
|
---|
130 | // Create the necessary windows
|
---|
131 | WINDOW *wins[4];
|
---|
132 | CreateWindows(wins);
|
---|
133 |
|
---|
134 | // Initialize the panels
|
---|
135 | fPanelIn = new_panel(wins[0]);
|
---|
136 | fPanelFrame = new_panel(wins[1]);
|
---|
137 | fPanelOut = new_panel(wins[2]);
|
---|
138 |
|
---|
139 | win.SetWindow(wins[0]);
|
---|
140 | wout.SetWindow(wins[2]);
|
---|
141 |
|
---|
142 | // Get the panels into the right order for startup
|
---|
143 | ShowHide(1);
|
---|
144 |
|
---|
145 | // Setup Readline
|
---|
146 | SetWindow(wins[0]);
|
---|
147 | SetColorPrompt(COLOR_PAIR(COLOR_BLUE));
|
---|
148 |
|
---|
149 | // ------------------- Setup key bindings -----------------------
|
---|
150 | BindKeySequence("\033OP", rl_proc_F1); // \033OP
|
---|
151 | BindKeySequence("\033[1;5B", rl_scroll_top); // \033OP
|
---|
152 | BindKeySequence("\033[1;5A", rl_scroll_top); // \033OP
|
---|
153 | BindKeySequence("\033[1;3A", rl_scroll_bot); // \033OP
|
---|
154 | BindKeySequence("\033[1;3B", rl_scroll_bot); // \033OP
|
---|
155 | BindKeySequence("\033[5;3~", rl_top_inc); // \033OP
|
---|
156 | BindKeySequence("\033[6;3~", rl_top_dec); // \033OP
|
---|
157 | BindKeySequence("\033+", rl_top_resize); // \033OP
|
---|
158 | BindKeySequence("\033-", rl_top_resize); // \033OP
|
---|
159 |
|
---|
160 | /*
|
---|
161 | rl_bind_keyseq("\033\t", rl_complete); // Meta-Tab
|
---|
162 | rl_bind_keyseq("\033[1~", home); // Home (console)
|
---|
163 | rl_bind_keyseq("\033[H", home); // Home (x)
|
---|
164 | rl_bind_keyseq("\033[4~", end); // End (console)
|
---|
165 | rl_bind_keyseq("\033[F", end); // End (x)
|
---|
166 | rl_bind_keyseq("\033[A", up); // Up
|
---|
167 | rl_bind_keyseq("\033[B", down); // Down
|
---|
168 | rl_bind_keyseq("\033[[B", accept); // F2 (console)
|
---|
169 | rl_bind_keyseq("\033OQ", accept); // F2 (x)
|
---|
170 | rl_bind_keyseq("\033[21~", cancel); // F10
|
---|
171 | */
|
---|
172 |
|
---|
173 | // Ctrl+dn: \033[1;5B
|
---|
174 | // Ctrl+up: \033[1;5A
|
---|
175 | // Alt+up: \033[1;3A
|
---|
176 | // Alt+dn: \033[1;3B
|
---|
177 | // Alt+pg up: \033[5;3~
|
---|
178 | // Alt+pg dn: \033[6;3~
|
---|
179 | }
|
---|
180 |
|
---|
181 | // --------------------------------------------------------------------------
|
---|
182 | //
|
---|
183 | //! Ends the ncurses environment by calling endwin().
|
---|
184 | //
|
---|
185 | Shell::~Shell()
|
---|
186 | {
|
---|
187 | // Maybe not needed because the window is more or less valid until the
|
---|
188 | // object is destructed anyway.
|
---|
189 | //win.SetWindow(0);
|
---|
190 | //wout.SetWindow(0);
|
---|
191 | //SetWindow(0);
|
---|
192 |
|
---|
193 | endwin();
|
---|
194 | cout << "The end." << endl;
|
---|
195 | }
|
---|
196 |
|
---|
197 | // --------------------------------------------------------------------------
|
---|
198 | //
|
---|
199 | //! This function gets the windows into the expected order which is:
|
---|
200 | //!
|
---|
201 | //! @param v
|
---|
202 | //! - \b 0: Do not show the output panel
|
---|
203 | //! - \b 1: Show the output panel
|
---|
204 | //! - \b -1: Toggle the visibility of the output panel
|
---|
205 | //! - \b -2: Just update the panels, do not change their visibility
|
---|
206 | //
|
---|
207 | void Shell::ShowHide(int v)
|
---|
208 | {
|
---|
209 | if (v>-2)
|
---|
210 | fIsVisible = v==-1 ? !fIsVisible : v;
|
---|
211 |
|
---|
212 | if (fIsVisible)
|
---|
213 | {
|
---|
214 | show_panel(fPanelIn);
|
---|
215 | show_panel(fPanelFrame);
|
---|
216 | show_panel(fPanelOut);
|
---|
217 | }
|
---|
218 | else
|
---|
219 | {
|
---|
220 | show_panel(fPanelIn);
|
---|
221 | hide_panel(fPanelFrame);
|
---|
222 | hide_panel(fPanelOut);
|
---|
223 | }
|
---|
224 |
|
---|
225 | update_panels();
|
---|
226 | doupdate();
|
---|
227 | }
|
---|
228 |
|
---|
229 |
|
---|
230 | // --------------------------------------------------------------------------
|
---|
231 | //
|
---|
232 | //! Creates the windows to be used as panels and draws a frame around one
|
---|
233 | //!
|
---|
234 | //! @param w
|
---|
235 | //! pointers to the three windows which have been created are returned
|
---|
236 | //!
|
---|
237 | //! @param all
|
---|
238 | //! If all is false do not (re-)create the bottom or input-window
|
---|
239 | //
|
---|
240 | void Shell::CreateWindows(WINDOW *w[3], int all)
|
---|
241 | {
|
---|
242 | int maxx, maxy;
|
---|
243 | getmaxyx(stdscr, maxy, maxx);
|
---|
244 |
|
---|
245 | int separator = maxy-fPanelHeight;
|
---|
246 |
|
---|
247 | WINDOW *new_in = all ? newwin(maxy, maxx, 0, 0) : 0;
|
---|
248 | WINDOW *new_frame = newwin(separator-1, maxx, 0, 0);
|
---|
249 | WINDOW *new_out = newwin(separator-1-2, maxx-2, 1, 1);
|
---|
250 |
|
---|
251 | box(new_frame, 0,0);
|
---|
252 | wmove(new_frame, 0, 1);
|
---|
253 | waddch(new_frame, ACS_RTEE);
|
---|
254 | wprintw(new_frame, " F1 ");
|
---|
255 | waddch(new_frame, ACS_LTEE);
|
---|
256 |
|
---|
257 | scrollok(new_out, true);
|
---|
258 | leaveok (new_out, true);
|
---|
259 |
|
---|
260 | if (new_in)
|
---|
261 | {
|
---|
262 | scrollok(new_in, true); // Allow scrolling
|
---|
263 | leaveok (new_in, false); // Move the cursor with the output
|
---|
264 |
|
---|
265 | wmove(new_in, maxy-1, 0);
|
---|
266 | }
|
---|
267 |
|
---|
268 | w[0] = new_in;
|
---|
269 | w[1] = new_frame;
|
---|
270 | w[2] = new_out;
|
---|
271 | }
|
---|
272 |
|
---|
273 | // --------------------------------------------------------------------------
|
---|
274 | //
|
---|
275 | //! Key binding for F1. Toggles upper panel by calling ShowHide(-1)
|
---|
276 | //
|
---|
277 | int Shell::rl_proc_F1(int /*cnt*/, int /*key*/)
|
---|
278 | {
|
---|
279 | This->ShowHide(-1); // toggle
|
---|
280 | return 0;
|
---|
281 | }
|
---|
282 |
|
---|
283 | int Shell::rl_scroll_top(int, int key)
|
---|
284 | {
|
---|
285 | This->win << "Scroll " << key << endl;
|
---|
286 | return 0;
|
---|
287 | }
|
---|
288 |
|
---|
289 | int Shell::rl_scroll_bot(int, int key)
|
---|
290 | {
|
---|
291 | This->win << "Scroll " << key << endl;
|
---|
292 | return 0;
|
---|
293 | }
|
---|
294 |
|
---|
295 | int Shell::rl_top_inc(int, int key)
|
---|
296 | {
|
---|
297 | This->win << "Increase " << key << endl;
|
---|
298 | return 0;
|
---|
299 | }
|
---|
300 |
|
---|
301 | int Shell::rl_top_dec(int, int key)
|
---|
302 | {
|
---|
303 | This->win << "Increase " << key << endl;
|
---|
304 | return 0;
|
---|
305 | }
|
---|
306 |
|
---|
307 | int Shell::rl_top_resize(int, int key)
|
---|
308 | {
|
---|
309 | This->Resize(key=='+' ? This->fPanelHeight-1 : This->fPanelHeight+1);
|
---|
310 | return 0;
|
---|
311 | }
|
---|
312 |
|
---|
313 |
|
---|
314 | // --------------------------------------------------------------------------
|
---|
315 | //
|
---|
316 | //! Signal handler for SIGWINCH, calls HandleResize
|
---|
317 | //
|
---|
318 | void Shell::HandleResizeImp(int)
|
---|
319 | {
|
---|
320 | This->HandleResize();
|
---|
321 | }
|
---|
322 |
|
---|
323 | // --------------------------------------------------------------------------
|
---|
324 | //
|
---|
325 | //! Signal handler for SIGWINCH. It resizes the terminal and all panels
|
---|
326 | //! according to the new terminal size and redisplay the backlog buffer
|
---|
327 | //! in both windows
|
---|
328 | //!
|
---|
329 | //! @todo
|
---|
330 | //! Maybe there are more efficient ways than to display the whole buffers
|
---|
331 | //
|
---|
332 | void Shell::HandleResize()
|
---|
333 | {
|
---|
334 | // Get the new terminal size
|
---|
335 | struct winsize w;
|
---|
336 | ioctl(0, TIOCGWINSZ, &w);
|
---|
337 |
|
---|
338 | // propagate it to the terminal
|
---|
339 | resize_term(w.ws_row, w.ws_col);
|
---|
340 |
|
---|
341 | // Store the pointer to the old windows
|
---|
342 | WINDOW *w_in = panel_window(fPanelIn);
|
---|
343 | WINDOW *w_frame = panel_window(fPanelFrame);
|
---|
344 | WINDOW *w_out = panel_window(fPanelOut);
|
---|
345 |
|
---|
346 | // Create new windows
|
---|
347 | WINDOW *wins[3];
|
---|
348 | CreateWindows(wins);
|
---|
349 |
|
---|
350 | // Redirect the streams and the readline output to the new windows
|
---|
351 | win.SetWindow(wins[0]);
|
---|
352 | wout.SetWindow(wins[2]);
|
---|
353 |
|
---|
354 | SetWindow(wins[0]);
|
---|
355 |
|
---|
356 | // Replace windows in the panels
|
---|
357 | replace_panel(fPanelIn, wins[0]);
|
---|
358 | replace_panel(fPanelFrame, wins[1]);
|
---|
359 | replace_panel(fPanelOut, wins[2]);
|
---|
360 |
|
---|
361 | // delete the old obsolete windows
|
---|
362 | delwin(w_in);
|
---|
363 | delwin(w_out);
|
---|
364 | delwin(w_frame);
|
---|
365 |
|
---|
366 | // FIXME: NEEDED also in Redisplay panel
|
---|
367 | //Redisplay();
|
---|
368 |
|
---|
369 | // Redisplay their contents
|
---|
370 | win.Display();
|
---|
371 | wout.Display();
|
---|
372 | }
|
---|
373 |
|
---|
374 | // --------------------------------------------------------------------------
|
---|
375 | //
|
---|
376 | //! This resized the top panel or output panel as requested by the argument.
|
---|
377 | //! The argument is the number of lines which are kept free for the input
|
---|
378 | //! panel below the top panel
|
---|
379 | //!
|
---|
380 | //! @returns
|
---|
381 | //! always true
|
---|
382 | //
|
---|
383 | bool Shell::Resize(int h)
|
---|
384 | {
|
---|
385 | // Get curretn terminal size
|
---|
386 | int lines, cols;
|
---|
387 | getmaxyx(stdscr, lines, cols);
|
---|
388 |
|
---|
389 | // Check if we are in a valid range
|
---|
390 | if (h<1 || h>lines-5)
|
---|
391 | return false;
|
---|
392 |
|
---|
393 | // Set new height for panel to be kept free
|
---|
394 | fPanelHeight = h;
|
---|
395 |
|
---|
396 | // Store the pointers of the old windows associated with the panels
|
---|
397 | // which should be resized
|
---|
398 | WINDOW *w_frame = panel_window(fPanelFrame);
|
---|
399 | WINDOW *w_out = panel_window(fPanelOut);
|
---|
400 |
|
---|
401 | // Create new windows
|
---|
402 | WINDOW *wins[3];
|
---|
403 | CreateWindows(wins, false);
|
---|
404 |
|
---|
405 | // Redirect the output stream to the new window
|
---|
406 | wout.SetWindow(wins[2]);
|
---|
407 |
|
---|
408 | // Replace the windows associated with the panels
|
---|
409 | replace_panel(fPanelFrame, wins[1]);
|
---|
410 | replace_panel(fPanelOut, wins[2]);
|
---|
411 |
|
---|
412 | // delete the ols windows
|
---|
413 | delwin(w_out);
|
---|
414 | delwin(w_frame);
|
---|
415 |
|
---|
416 | // FIXME: NEEDED also in Redisplay panel
|
---|
417 | //Redisplay();
|
---|
418 |
|
---|
419 | // Redisplay the contents
|
---|
420 | wout.Display();
|
---|
421 |
|
---|
422 | return true;
|
---|
423 | }
|
---|
424 |
|
---|
425 | // --------------------------------------------------------------------------
|
---|
426 | //
|
---|
427 | //! This wrapt the given readline function into a redirection to a file,
|
---|
428 | //! which contents is then displayed afterwards in the input panel.
|
---|
429 | //!
|
---|
430 | //! For convinience the given title is printed in bold before the list.
|
---|
431 | //!
|
---|
432 | //! This allows to show some readline output in the panel.
|
---|
433 | //!
|
---|
434 | //! @param function
|
---|
435 | //! Takes a function of type bool(*)() as argument
|
---|
436 | //!
|
---|
437 | //! @param title
|
---|
438 | //! A title streamed in bold before the output starts
|
---|
439 | //!
|
---|
440 | //! @returns
|
---|
441 | //! The return value of the function
|
---|
442 | //
|
---|
443 | bool Shell::RedirectionWrapper(bool (*function)(), const char *title)
|
---|
444 | {
|
---|
445 | FILE *save = SetStreamOut(tmpfile());
|
---|
446 | const bool rc = function();
|
---|
447 | FILE *file = SetStreamOut(save);
|
---|
448 |
|
---|
449 | const bool empty = ftell(file)==0;
|
---|
450 |
|
---|
451 | rewind(file);
|
---|
452 |
|
---|
453 | win << endl;
|
---|
454 | win << kBold << title << endl;
|
---|
455 |
|
---|
456 | if (empty)
|
---|
457 | {
|
---|
458 | win << " <empty>" << endl;
|
---|
459 | fclose(file);
|
---|
460 | return rc;
|
---|
461 | }
|
---|
462 |
|
---|
463 | while (1)
|
---|
464 | {
|
---|
465 | const int c = getc(file);
|
---|
466 | if (feof(file))
|
---|
467 | break;
|
---|
468 | win << (char)c;
|
---|
469 | }
|
---|
470 | win << endl;
|
---|
471 |
|
---|
472 | fclose(file);
|
---|
473 |
|
---|
474 | return rc;
|
---|
475 | }
|
---|
476 |
|
---|
477 | // --------------------------------------------------------------------------
|
---|
478 | //
|
---|
479 | //! Can be overwritten to display user defined commands when the command
|
---|
480 | //! c is issued.
|
---|
481 | //!
|
---|
482 | //! @returns
|
---|
483 | //! always true
|
---|
484 | //
|
---|
485 | bool Shell::PrintCommands()
|
---|
486 | {
|
---|
487 | win << endl;
|
---|
488 | win << " " << kUnderline << " Commands:" << endl;
|
---|
489 | win << " No application specific commands defined." << endl;
|
---|
490 | win << endl;
|
---|
491 |
|
---|
492 | return true;
|
---|
493 | }
|
---|
494 |
|
---|
495 | // --------------------------------------------------------------------------
|
---|
496 | //
|
---|
497 | //! Displays the available ncurses attributes, like color.
|
---|
498 | //!
|
---|
499 | //! @returns
|
---|
500 | //! always true
|
---|
501 | //
|
---|
502 | bool Shell::PrintAttributes()
|
---|
503 | {
|
---|
504 | //ostream &win = wout;
|
---|
505 | win << endl;
|
---|
506 | win << " Attributes:" << endl;
|
---|
507 | win << " " << kReset << "kReset" << endl;
|
---|
508 | win << " " << kNormal << "kNormal" << endl;
|
---|
509 | win << " " << kHighlight << "kHighlight" << endl;
|
---|
510 | win << " " << kReverse << "kReverse" << endl;
|
---|
511 | win << " " << kUnderline << "kUnderline" << endl;
|
---|
512 | win << " " << kBlink << "kBlink" << endl;
|
---|
513 | win << " " << kDim << "kDim" << endl;
|
---|
514 | win << " " << kBold << "kBold" << endl;
|
---|
515 | win << " " << kProtect << "kProtect" << endl;
|
---|
516 | win << " " << kInvisible << "kInvisible" << endl;
|
---|
517 | win << " " << kAltCharset << "kAltCharset" << kReset << " (kAltCharset)" << endl;
|
---|
518 | win << endl;
|
---|
519 | win << " Colors:" << endl;
|
---|
520 | win << " " << kDefault << "kDefault " << kBold << "+ kBold" << endl;
|
---|
521 | win << " " << kRed << "kRed " << kBold << "+ kBold" << endl;
|
---|
522 | win << " " << kGreen << "kGreen " << kBold << "+ kBold" << endl;
|
---|
523 | win << " " << kYellow << "kYellow " << kBold << "+ kBold" << endl;
|
---|
524 | win << " " << kBlue << "kBlue " << kBold << "+ kBold" << endl;
|
---|
525 | win << " " << kMagenta << "kMagenta " << kBold << "+ kBold" << endl;
|
---|
526 | win << " " << kCyan << "kCyan " << kBold << "+ kBold" << endl;
|
---|
527 | win << " " << kWhite << "kWhite " << kBold << "+ kBold" << endl;
|
---|
528 | win << " " << endl;
|
---|
529 |
|
---|
530 | return true;
|
---|
531 | }
|
---|
532 |
|
---|
533 | // --------------------------------------------------------------------------
|
---|
534 | //
|
---|
535 | //! Displays the keybindings available due to the Shell class
|
---|
536 | //!
|
---|
537 | //! @returns
|
---|
538 | //! always true
|
---|
539 | //!
|
---|
540 | //! @todo
|
---|
541 | //! Update output
|
---|
542 | //
|
---|
543 | bool Shell::PrintKeyBindings()
|
---|
544 | {
|
---|
545 | win << endl;
|
---|
546 | win << " " << kUnderline << "Key bindings:" << endl;
|
---|
547 | win << kBold << " Page-up " << kReset << "Search backward in history" << endl;
|
---|
548 | win << kBold << " Page-dn " << kReset << "Search forward in history" << endl;
|
---|
549 | win << kBold << " Ctrl-left " << kReset << "One word backward" << endl;
|
---|
550 | win << kBold << " Ctrl-right " << kReset << "One word forward" << endl;
|
---|
551 | win << kBold << " Ctrl-y " << kReset << "Delete line" << endl;
|
---|
552 | win << kBold << " Alt-end/Ctrl-k " << kReset << "Delete until the end of the line" << endl;
|
---|
553 | win << kBold << " F1 " << kReset << "Toggle visibility of upper panel" << endl;
|
---|
554 | win << endl;
|
---|
555 | win << " Default key-bindings are identical with your bash." << endl;
|
---|
556 | win << endl;
|
---|
557 |
|
---|
558 | return true;
|
---|
559 | }
|
---|
560 |
|
---|
561 | // --------------------------------------------------------------------------
|
---|
562 | //
|
---|
563 | //! Print a general help text which also includes the commands pre-defined
|
---|
564 | //! by the Shell class.
|
---|
565 | //!
|
---|
566 | //! @returns
|
---|
567 | //! always true
|
---|
568 | //!
|
---|
569 | //! @todo
|
---|
570 | //! Get it up-to-date
|
---|
571 | //
|
---|
572 | bool Shell::PrintGeneralHelp()
|
---|
573 | {
|
---|
574 | win << endl;
|
---|
575 | win << " " << kUnderline << "General help:" << endl;
|
---|
576 | win << kBold << " h,help " << kReset << "Print this help message" << endl;
|
---|
577 | win << kBold << " clear " << kReset << "Clear history buffer" << endl;
|
---|
578 | win << kBold << " lh,history " << kReset << "Dump the history buffer to the screen" << endl;
|
---|
579 | win << kBold << " v,variable " << kReset << "Dump readline variables" << endl;
|
---|
580 | win << kBold << " f,function " << kReset << "Dump readline functions" << endl;
|
---|
581 | win << kBold << " m,funmap " << kReset << "Dump readline funmap" << endl;
|
---|
582 | win << kBold << " c,command " << kReset << "Dump available commands" << endl;
|
---|
583 | win << kBold << " k,keylist " << kReset << "Dump key bindings" << endl;
|
---|
584 | win << kBold << " a,attrs " << kReset << "Dump available stream attributes" << endl;
|
---|
585 | win << kBold << " .q,quit " << kReset << "Quit" << endl;
|
---|
586 | win << endl;
|
---|
587 | win << " The command history is automatically loaded and saves to" << endl;
|
---|
588 | win << " and from " << GetName() << endl;
|
---|
589 | win << endl;
|
---|
590 |
|
---|
591 | return true;
|
---|
592 | }
|
---|
593 |
|
---|
594 |
|
---|
595 | // --------------------------------------------------------------------------
|
---|
596 | //
|
---|
597 | //! Processes the command provided by the Shell-class.
|
---|
598 | //!
|
---|
599 | //! @returns
|
---|
600 | //! whether a command was successfully processed or could not be found
|
---|
601 | //
|
---|
602 | bool Shell::Process(const string &str)
|
---|
603 | {
|
---|
604 | // Implement readline commands:
|
---|
605 | // rl set (rl_variable_bind(..))
|
---|
606 | // rl_read_init_file(filename)
|
---|
607 | // int rl_add_defun (const char *name, rl_command_func_t *function, int key)
|
---|
608 |
|
---|
609 | // ----------- Readline -----------
|
---|
610 |
|
---|
611 | if (str=="lh" || str=="history")
|
---|
612 | return RedirectionWrapper(DumpHistory, "History:");
|
---|
613 |
|
---|
614 | if (str=="v" || str=="variable")
|
---|
615 | return RedirectionWrapper(DumpVariables, "Variables:");
|
---|
616 |
|
---|
617 | if (str=="f" || str=="function")
|
---|
618 | return RedirectionWrapper(DumpFunctions, "Functions:");
|
---|
619 |
|
---|
620 | if (str=="m" || str=="funmap")
|
---|
621 | return RedirectionWrapper(DumpFunmap, "Funmap:");
|
---|
622 |
|
---|
623 | if (Readline::Process(str))
|
---|
624 | return true;
|
---|
625 |
|
---|
626 | // ------------ ReadlineWindow -------------
|
---|
627 |
|
---|
628 | if (str=="a" || str=="attrs")
|
---|
629 | return PrintAttributes();
|
---|
630 |
|
---|
631 | // ----------- ReadlineNcurses -----------
|
---|
632 |
|
---|
633 | if (string(str)=="hide")
|
---|
634 | {
|
---|
635 | ShowHide(0);
|
---|
636 | return true;
|
---|
637 | }
|
---|
638 | if (string(str)=="show")
|
---|
639 | {
|
---|
640 | ShowHide(1);
|
---|
641 | return true;
|
---|
642 | }
|
---|
643 |
|
---|
644 | if (str.substr(0, 7)=="height ")
|
---|
645 | {
|
---|
646 | int h;
|
---|
647 | sscanf(str.c_str()+7, "%d", &h);
|
---|
648 | return Resize(h);
|
---|
649 | }
|
---|
650 |
|
---|
651 | if (str=="d")
|
---|
652 | {
|
---|
653 | wout.Display();
|
---|
654 | return true;
|
---|
655 | }
|
---|
656 |
|
---|
657 | return false;
|
---|
658 | }
|
---|
659 |
|
---|
660 | // --------------------------------------------------------------------------
|
---|
661 | //
|
---|
662 | //! Overwrites Shutdown. It's main purpose is to re-output
|
---|
663 | //! the prompt and the buffer using the WindowLog stream so that it is
|
---|
664 | //! buffered in its backlog.
|
---|
665 | //!
|
---|
666 | //! @param buf
|
---|
667 | //! A pointer to the buffer returned by readline
|
---|
668 | //!
|
---|
669 | void Shell::Shutdown(const char *buf)
|
---|
670 | {
|
---|
671 | ReadlineWindow::Shutdown(buf);
|
---|
672 |
|
---|
673 | // Now move the cursor to the start of the prompt
|
---|
674 | RewindCursor();
|
---|
675 |
|
---|
676 | // Output the text ourself to get it into the backlog
|
---|
677 | // buffer of win. We cannot use GetBuffer() because rl_end
|
---|
678 | // is not updated finally.
|
---|
679 | win << kBlue << GetPrompt() << kReset << buf << endl;
|
---|
680 | }
|
---|