# HG changeset patch # User John W. Eaton # Date 1558629386 14400 # Node ID 822a2fe5bb510a58f15cd5c459ff4d91c935adaf # Parent 7c4b04a6346d75eeef343b2b3fda9a3b495977d6 move command window to separate file and other refactoring diff -r 7c4b04a6346d -r 822a2fe5bb51 NOTES --- a/NOTES Thu May 23 11:26:44 2019 -0400 +++ b/NOTES Thu May 23 12:36:26 2019 -0400 @@ -77,3 +77,72 @@ * Do we need text position markers to keep track of the prompt position (beginning of current line) when inserting or clearing text? + + +readline callback functions: + +// -- Variable: rl_getc_func_t * rl_getc_function +// If non-zero, Readline will call indirectly through this pointer to +// get a character from the input stream. By default, it is set to +// `rl_getc', the default Readline character input function (*note +// Character Input::). + +// -- Variable: rl_voidfunc_t * rl_redisplay_function +// If non-zero, Readline will call indirectly through this pointer to +// update the display with the current contents of the editing buffer. +// By default, it is set to `rl_redisplay', the default Readline +// redisplay function (*note Redisplay::). + +// -- Variable: rl_vintfunc_t * rl_prep_term_function +// If non-zero, Readline will call indirectly through this pointer to +// initialize the terminal. The function takes a single argument, an +// `int' flag that says whether or not to use eight-bit characters. +// By default, this is set to `rl_prep_terminal' (*note Terminal +// Management::). + +// -- Variable: rl_voidfunc_t * rl_deprep_term_function +// If non-zero, Readline will call indirectly through this pointer to +// reset the terminal. This function should undo the effects of +// `rl_prep_term_function'. By default, this is set to +// `rl_deprep_terminal' (*note Terminal Management::). + +// -- Function: void rl_callback_handler_install (const char *prompt, +// rl_vcpfunc_t *lhandler) +// Set up the terminal for readline I/O and display the initial +// expanded value of PROMPT. Save the value of LHANDLER to use as a +// function to call when a complete line of input has been entered. +// The function takes the text of the line as an argument. + +// -- Function: void rl_callback_read_char (void) +// Whenever an application determines that keyboard input is +// available, it should call `rl_callback_read_char()', which will +// read the next character from the current input source. If that +// character completes the line, `rl_callback_read_char' will invoke +// the LHANDLER function saved by `rl_callback_handler_install' to +// process the line. Before calling the LHANDLER function, the +// terminal settings are reset to the values they had before calling +// `rl_callback_handler_install'. If the LHANDLER function returns, +// the terminal settings are modified for Readline's use again. +// `EOF' is indicated by calling LHANDLER with a `NULL' line. + +// -- Function: void rl_callback_handler_remove (void) +// Restore the terminal to its initial state and remove the line +// handler. This may be called from within a callback as well as +// independently. If the LHANDLER installed by +// `rl_callback_handler_install' does not exit the program, either +// this function or the function referred to by the value of +// `rl_deprep_term_function' should be called before the program +// exits to reset the terminal settings. + +// -- Variable: rl_compdisp_func_t * rl_completion_display_matches_hook +// If non-zero, then this is the address of a function to call when +// completing a word would normally display the list of possible +// matches. This function is called in lieu of Readline displaying +// the list. It takes three arguments: (`char **'MATCHES, `int' +// NUM_MATCHES, `int' MAX_LENGTH) where MATCHES is the array of +// matching strings, NUM_MATCHES is the number of strings in that +// array, and MAX_LENGTH is the length of the longest string in that +// array. Readline provides a convenience function, +// `rl_display_match_list', that takes care of doing the display to +// Readline's output stream. That function may be called from this +// hook. diff -r 7c4b04a6346d -r 822a2fe5bb51 calc.pro --- a/calc.pro Thu May 23 11:26:44 2019 -0400 +++ b/calc.pro Thu May 23 12:36:26 2019 -0400 @@ -1,20 +1,21 @@ MAKEFILE = calc.mk SOURCES = \ - parser.cpp \ + command-window.cpp \ + gui-main.cpp \ interpreter.cpp \ main.cpp \ - gui-main.cpp \ - tty-main.cpp \ - qt-interpreter.cpp + parser.cpp \ + qt-interpreter.cpp \ + tty-main.cpp HEADERS = \ - parser.h \ + command-window.h \ + gui-main.h \ interpreter.h \ - main.h \ - gui-main.h \ - tty-main.h \ - qt-interpreter.h + parser.h \ + qt-interpreter.h \ + tty-main.h LIBS += -lreadline diff -r 7c4b04a6346d -r 822a2fe5bb51 command-window.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/command-window.cpp Thu May 23 12:36:26 2019 -0400 @@ -0,0 +1,379 @@ +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include "command-window.h" +#include "interpreter.h" +#include "parser.h" + +#include +#include + +namespace calc +{ + static int available_char = 0; + + // vvvvv readline vvvvv + + static int getc (FILE *) + { + int tmp = available_char; + available_char = 0; + return tmp; + } + + static void redisplay (void) + { + if (command_window::the_command_window) + emit command_window::the_command_window->redisplay_signal (); + } + + static void prep_term (int) + { + } + + static void deprep_term (void) + { + } + + static void accept_line (char *line) + { + if (command_window::the_command_window) + command_window::the_command_window->accept_line (line ? line : ""); + } + + static void display_completion_matches (char **matches, int num_matches, + int /* max_length */) + { + if (command_window::the_command_window) + { + std::ostringstream buf; + + if (num_matches > 1) + buf << "\n"; + + for (int i = 1; i < num_matches; i++) + buf << matches[i] << "\n"; + + command_window::the_command_window->insert_at_end (buf.str ()); + + emit command_window::the_command_window->redisplay_signal (); + } + } + + void readline_init (void) + { + rl_initialize (); + + rl_getc_function = getc; + rl_redisplay_function = redisplay; + rl_prep_term_function = prep_term; + rl_deprep_term_function = deprep_term; + rl_completion_display_matches_hook = display_completion_matches; + + rl_callback_handler_install (">> ", accept_line); + } + + void readline_fini (void) + { + rl_callback_handler_remove (); + } + + // ^^^^^ readline ^^^^^ + + command_window *command_window::the_command_window = nullptr; + + command_window::command_window (QWidget *p) + : QTextEdit (p), + m_buffer (new QTextDocument ()), + m_interpreter (new calc::qt_interpreter ()), + beg_mark (), prompt_mark () + { + if (the_command_window) + { + std::cerr << "multiple command_windows are not possible!" << std::endl; + exit (1); + } + + the_command_window = this; + + setWindowTitle ("Qt::TextEdit example"); + + setMinimumSize (QSize (600, 400)); + + setDocument (m_buffer); + + connect (m_interpreter, SIGNAL (result_ready (double)), + this, SLOT (handle_result (double))); + + connect (m_interpreter, SIGNAL (error_signal (const QString&)), + this, SLOT (handle_error (const QString&))); + + connect (this, SIGNAL (input_char_available (int)), + this, SLOT (handle_input_char (int))); + + connect (this, SIGNAL (redisplay_signal (void)), + this, SLOT (redisplay (void))); + + connect (this, SIGNAL (accept_line_signal (const QString&)), + m_interpreter, SLOT (accept_input_line (const QString&))); + + insert_at_end + ("Qt Example Calculator.\n" + "Available operations: + - * / ^ ()\n" + "Semicolon terminates statement.\n" + "Up Arrow key moves to previous line in the command history.\n" + "Down Arrow key moves to next line in the comand history.\n\n"); + + beg_mark = set_mark (); + + // Defer initializing and executing the interpreter until after the main + // window and QApplication are running to prevent race conditions + QTimer::singleShot (0, m_interpreter, SLOT (execute (void))); + } + + // Accept an input line, parse and possibly execute it. + + void command_window::accept_line (const std::string& line) + { + insert_at_end ("\n"); + + if (! line.empty ()) + { + add_history (line.c_str ()); + using_history (); + + emit accept_line_signal (QString::fromStdString (line)); + } + } + + void command_window::insert_at_end (const std::string& text) + { + scroll_to_bottom (); + + insert_at_cursor (text); + } + + void command_window::handle_error (const QString& msg) + { + insert_at_end ("parse error: " + msg.toStdString () + "\n"); + + rl_abort (0, 0); + } + + // FIXME: do we really need this extra function? + void command_window::handle_result (double value) + { + insert_result (value); + } + + // Redisplay current command line. + + void command_window::redisplay (void) + { + erase_line (); + + std::string line = rl_line_buffer ? rl_line_buffer : ""; + std::string prompt = (rl_prompt && parser::beg_of_stmt) ? rl_prompt : ""; + + insert_line (prompt, line); + + scroll_to_bottom (); + + QTextCursor cursor = textCursor (); + + cursor.setPosition (prompt_mark + rl_point, QTextCursor::MoveAnchor); + + setTextCursor (cursor); + } + + void command_window::keyPressEvent (QKeyEvent *event) + { + if (! event) + return; + + if (event->type () == QEvent::KeyPress) + { + int key = event->key (); + + switch (key) + { + case Qt::Key_Return: + key = 0x0A; + break; + + case Qt::Key_Backspace: + key = 0x08; + break; + + case Qt::Key_Tab: + key = 0x09; + break; + + case Qt::Key_Escape: + key = 0x1b; + break; + + case Qt::Key_Up: + case Qt::Key_Down: + case Qt::Key_Right: + case Qt::Key_Left: + key = do_arrow_key (key); + break; + + default: + { + switch (event->modifiers ()) + { + case Qt::ControlModifier: + if (key > 0x3f && key < 0x7b) + key &= 0x1f; + else + key = -1; + break; + + default: + { + // Don't shoot me, this is just a demo... + QString text = event->text (); + QByteArray latin_text = text.toLatin1 (); + key = latin_text[0]; + } + break; + } + } + break; + } + + if (key >= 0) + emit input_char_available (key); + } + } + + void command_window::handle_input_char (int key) + { + available_char = key; + rl_callback_read_char (); + } + + int command_window::do_arrow_key (int arrow_key) + { + int retval = 0; + + available_char = 0x1b; + rl_callback_read_char (); + + available_char = '['; + rl_callback_read_char (); + + switch (arrow_key) + { + case Qt::Key_Up: + retval = 'A'; + break; + + case Qt::Key_Down: + retval = 'B'; + break; + + case Qt::Key_Right: + retval = 'C'; + break; + + case Qt::Key_Left: + retval = 'D'; + break; + } + + return retval; + } + + // Retrieve a command from the history list and insert it on the + // current command. + + void command_window::history (bool up) + { + HIST_ENTRY *entry = up ? previous_history () : next_history (); + + if (entry) + { + erase_line (); + + std::string prompt = rl_prompt ? rl_prompt : ""; + + insert_line (prompt, entry->line); + } + else if (! up) + erase_line (); + + scroll_to_bottom (); + } + + void command_window::erase_line (void) + { + QTextCursor cursor = textCursor (); + + cursor.movePosition (QTextCursor::End); + cursor.select (QTextCursor::LineUnderCursor); + cursor.removeSelectedText (); + + setTextCursor (cursor); + } + + void command_window::insert_at_cursor (const std::string& text) + { + QTextCursor cursor = textCursor (); + + cursor.insertText (QString::fromStdString (text)); + + setTextCursor (cursor); + } + + void command_window::insert_line (const std::string& prompt, + const std::string& line) + { + beg_mark = set_mark (); + + insert_at_cursor (prompt); + + prompt_mark = set_mark (); + + insert_at_cursor (line); + } + + int command_window::set_mark (void) + { + return textCursor ().position (); + } + + void command_window::insert_result (double value) + { + std::ostringstream buf; + + buf << "ans = " << value << "\n"; + + insert_at_cursor (buf.str ()); + + beg_mark = set_mark (); + + scroll_to_bottom (); + } + + void command_window::scroll_to_bottom (void) + { + QTextCursor cursor = textCursor (); + + cursor.movePosition (QTextCursor::End); + + setTextCursor (cursor); + } +} diff -r 7c4b04a6346d -r 822a2fe5bb51 command-window.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/command-window.h Thu May 23 12:36:26 2019 -0400 @@ -0,0 +1,93 @@ +#if ! defined (calc_command_window_h) +#define calc_command_window_h 1 + +#include + +#include +#include + +#include "qt-interpreter.h" + +namespace calc +{ + class command_window : public QTextEdit + { + Q_OBJECT + + public: + + static command_window *the_command_window; + + command_window (QWidget *p = nullptr); + + virtual ~command_window (void) = default; + + // Accept an input line, parse and possibly execute it. + + void accept_line (const std::string& line); + + // Redisplay current command line. + + void insert_at_end (const std::string& text); + + void emit_error (const std::string& msg); + + void emit_result (double value); + + signals: + + void input_char_available (int key); + + void accept_line_signal (const QString& line); + + void redisplay_signal (void); + + public slots: + + void handle_input_char (int key); + + void handle_error (const QString& msg); + + void handle_result (double value); + + void redisplay (void); + + protected: + + void keyPressEvent (QKeyEvent *event); + + int do_arrow_key (int arrow_key); + + // Retrieve a command from the history list and insert it on the + // current command. + + void history (bool up); + + void erase_line (void); + + void insert_at_cursor (const std::string& text); + + void insert_line (const std::string& prompt, const std::string& line); + + int set_mark (void); + + void insert_result (double value); + + void scroll_to_bottom (void); + + // Child widgets: + + QTextDocument *m_buffer; + + calc::qt_interpreter *m_interpreter; + + int beg_mark; + int prompt_mark; + }; + + extern void readline_init (void); + + extern void readline_fini (void); +} + +#endif diff -r 7c4b04a6346d -r 822a2fe5bb51 gui-main.cpp --- a/gui-main.cpp Thu May 23 11:26:44 2019 -0400 +++ b/gui-main.cpp Thu May 23 12:36:26 2019 -0400 @@ -6,383 +6,19 @@ #include #include -#include -#include -#include -#include -#include "gui-main.h" -#include "main.h" - +#include "command-window.h" #include "gui-main.h" -#include "interpreter.h" -#include "parser.h" - -#include -#include - -namespace gui -{ - static int available_char = 0; - - static command_window *calc_interaction_window = 0; - - static inline int ctrl (int c) - { - return c & 0x1f; - } - - static int getc (FILE *) - { - int tmp = available_char; - available_char = 0; - return tmp; - } - - static void redisplay (void) - { - if (calc_interaction_window) - emit calc_interaction_window->redisplay_signal (); - } - - static void prep_term (int) - { - } - - static void deprep_term (void) - { - } - - static void accept_line (char *line) - { - if (calc_interaction_window) - calc_interaction_window->accept_line (line ? line : ""); - } - - static void display_completion_matches (char **matches, int num_matches, - int /* max_length */) - { - if (calc_interaction_window) - { - std::ostringstream buf; - - if (num_matches > 1) - buf << "\n"; - - for (int i = 1; i < num_matches; i++) - buf << matches[i] << "\n"; - - calc_interaction_window->insert_at_end (buf.str ()); - - emit calc_interaction_window->redisplay_signal (); - } - } - - static void readline_init (void) - { - rl_initialize (); - - rl_getc_function = getc; - rl_redisplay_function = redisplay; - rl_prep_term_function = prep_term; - rl_deprep_term_function = deprep_term; - rl_completion_display_matches_hook = display_completion_matches; - - rl_callback_handler_install (">> ", accept_line); - } - - static void readline_fini (void) - { - rl_callback_handler_remove (); - } - - command_window::command_window (QWidget *p) - : QTextEdit (p), - m_buffer (new QTextDocument ()), - m_interpreter (new calc::qt_interpreter ()), - beg_mark (), prompt_mark () - { - setWindowTitle ("Qt::TextEdit example"); - - setMinimumSize (QSize (600, 400)); - - setDocument (m_buffer); - - connect (m_interpreter, SIGNAL (result_ready (double)), - this, SLOT (handle_result (double))); - - connect (m_interpreter, SIGNAL (error_signal (const QString&)), - this, SLOT (handle_error (const QString&))); - - connect (this, SIGNAL (input_char_available (int)), - this, SLOT (handle_input_char (int))); - - connect (this, SIGNAL (redisplay_signal (void)), - this, SLOT (redisplay (void))); - - connect (this, SIGNAL (accept_line_signal (const QString&)), - m_interpreter, SLOT (accept_input_line (const QString&))); - - insert_at_end - ("Qt Example Calculator.\n" - "Available operations: + - * / ^ ()\n" - "Semicolon terminates statement.\n" - "Up Arrow key moves to previous line in the command history.\n" - "Down Arrow key moves to next line in the comand history.\n\n"); - - beg_mark = set_mark (); - - // Defer initializing and executing the interpreter until after the main - // window and QApplication are running to prevent race conditions - QTimer::singleShot (0, m_interpreter, SLOT (execute (void))); - } - - // Accept an input line, parse and possibly execute it. - - void command_window::accept_line (const std::string& line) - { - if (calc::debug_mode) - std::cerr << "accept: " << line << std::endl; - - insert_at_end ("\n"); - - if (! line.empty ()) - { - add_history (line.c_str ()); - using_history (); - - emit accept_line_signal (QString::fromStdString (line)); - } - } - - void command_window::insert_at_end (const std::string& text) - { - scroll_to_bottom (); - - insert_at_cursor (text); - } - - void command_window::handle_error (const QString& msg) - { - insert_at_end ("parse error: " + msg.toStdString () + "\n"); - - rl_abort (0, 0); - } - - // FIXME: do we really need this extra function? - void command_window::handle_result (double value) - { - insert_result (value); - } - - // Redisplay current command line. - - void command_window::redisplay (void) - { - erase_line (); - - std::string line = rl_line_buffer ? rl_line_buffer : ""; - std::string prompt = (rl_prompt && parser::beg_of_stmt) ? rl_prompt : ""; - - insert_line (prompt, line); - - scroll_to_bottom (); - - QTextCursor cursor = textCursor (); - - cursor.setPosition (prompt_mark + rl_point, QTextCursor::MoveAnchor); - setTextCursor (cursor); - } - - void command_window::keyPressEvent (QKeyEvent *event) - { - if (! event) - return; - - if (event->type () == QEvent::KeyPress) - { - int key = event->key (); - - switch (key) - { - case Qt::Key_Return: - key = 0x0A; - break; - - case Qt::Key_Backspace: - key = 0x08; - break; - - case Qt::Key_Tab: - key = 0x09; - break; - - case Qt::Key_Escape: - key = 0x1b; - break; - - case Qt::Key_Up: - case Qt::Key_Down: - case Qt::Key_Right: - case Qt::Key_Left: - key = do_arrow_key (key); - break; - - default: - { - switch (event->modifiers ()) - { - case Qt::ControlModifier: - if (key > 0x3f && key < 0x7b) - key &= 0x1f; - else - key = -1; - break; - - default: - { - // Don't shoot me, this is just a demo... - QString text = event->text (); - QByteArray latin_text = text.toLatin1 (); - key = latin_text[0]; - } - break; - } - } - break; - } - - if (key >= 0) - emit input_char_available (key); - } - } - - void command_window::handle_input_char (int key) - { - available_char = key; - rl_callback_read_char (); - } - - int command_window::do_arrow_key (int arrow_key) - { - int retval = 0; - - available_char = 0x1b; - rl_callback_read_char (); - - available_char = '['; - rl_callback_read_char (); - - switch (arrow_key) - { - case Qt::Key_Up: - retval = 'A'; - break; - - case Qt::Key_Down: - retval = 'B'; - break; - - case Qt::Key_Right: - retval = 'C'; - break; - - case Qt::Key_Left: - retval = 'D'; - break; - } - - return retval; - } - - // Retrieve a command from the history list and insert it on the - // current command. - - void command_window::history (bool up) - { - HIST_ENTRY *entry = up ? previous_history () : next_history (); - - if (entry) - { - erase_line (); - - std::string prompt = rl_prompt ? rl_prompt : ""; - - insert_line (prompt, entry->line); - } - else if (! up) - erase_line (); - - scroll_to_bottom (); - } - - void command_window::erase_line (void) - { - QTextCursor cursor = textCursor (); - - cursor.movePosition (QTextCursor::End); - cursor.select (QTextCursor::LineUnderCursor); - cursor.removeSelectedText (); - - setTextCursor (cursor); - } - - void command_window::insert_at_cursor (const std::string& text) - { - QTextCursor cursor = textCursor (); - - cursor.insertText (QString::fromStdString (text)); - - setTextCursor (cursor); - } - - void command_window::insert_line (const std::string& prompt, - const std::string& line) - { - beg_mark = set_mark (); - - insert_at_cursor (prompt); - - prompt_mark = set_mark (); - - insert_at_cursor (line); - } - - int command_window::set_mark (void) - { - return textCursor ().position (); - } - - void command_window::insert_result (double value) - { - std::ostringstream buf; - - buf << "ans = " << value << "\n"; - - insert_at_cursor (buf.str ()); - - beg_mark = set_mark (); - - scroll_to_bottom (); - } - - void command_window::scroll_to_bottom (void) - { - QTextCursor cursor = textCursor (); - - cursor.movePosition (QTextCursor::End); - - setTextCursor (cursor); - } - - int main (int argc, char *argv[]) +namespace calc +{ + int gui_main (int argc, char *argv[]) { QApplication app (argc, argv); - calc_interaction_window = new command_window (); + command_window command_window; - calc_interaction_window->show (); + command_window.show (); readline_init (); @@ -393,69 +29,3 @@ return status; } } - -// -- Variable: rl_getc_func_t * rl_getc_function -// If non-zero, Readline will call indirectly through this pointer to -// get a character from the input stream. By default, it is set to -// `rl_getc', the default Readline character input function (*note -// Character Input::). - -// -- Variable: rl_voidfunc_t * rl_redisplay_function -// If non-zero, Readline will call indirectly through this pointer to -// update the display with the current contents of the editing buffer. -// By default, it is set to `rl_redisplay', the default Readline -// redisplay function (*note Redisplay::). - -// -- Variable: rl_vintfunc_t * rl_prep_term_function -// If non-zero, Readline will call indirectly through this pointer to -// initialize the terminal. The function takes a single argument, an -// `int' flag that says whether or not to use eight-bit characters. -// By default, this is set to `rl_prep_terminal' (*note Terminal -// Management::). - -// -- Variable: rl_voidfunc_t * rl_deprep_term_function -// If non-zero, Readline will call indirectly through this pointer to -// reset the terminal. This function should undo the effects of -// `rl_prep_term_function'. By default, this is set to -// `rl_deprep_terminal' (*note Terminal Management::). - -// -- Function: void rl_callback_handler_install (const char *prompt, -// rl_vcpfunc_t *lhandler) -// Set up the terminal for readline I/O and display the initial -// expanded value of PROMPT. Save the value of LHANDLER to use as a -// function to call when a complete line of input has been entered. -// The function takes the text of the line as an argument. - -// -- Function: void rl_callback_read_char (void) -// Whenever an application determines that keyboard input is -// available, it should call `rl_callback_read_char()', which will -// read the next character from the current input source. If that -// character completes the line, `rl_callback_read_char' will invoke -// the LHANDLER function saved by `rl_callback_handler_install' to -// process the line. Before calling the LHANDLER function, the -// terminal settings are reset to the values they had before calling -// `rl_callback_handler_install'. If the LHANDLER function returns, -// the terminal settings are modified for Readline's use again. -// `EOF' is indicated by calling LHANDLER with a `NULL' line. - -// -- Function: void rl_callback_handler_remove (void) -// Restore the terminal to its initial state and remove the line -// handler. This may be called from within a callback as well as -// independently. If the LHANDLER installed by -// `rl_callback_handler_install' does not exit the program, either -// this function or the function referred to by the value of -// `rl_deprep_term_function' should be called before the program -// exits to reset the terminal settings. - -// -- Variable: rl_compdisp_func_t * rl_completion_display_matches_hook -// If non-zero, then this is the address of a function to call when -// completing a word would normally display the list of possible -// matches. This function is called in lieu of Readline displaying -// the list. It takes three arguments: (`char **'MATCHES, `int' -// NUM_MATCHES, `int' MAX_LENGTH) where MATCHES is the array of -// matching strings, NUM_MATCHES is the number of strings in that -// array, and MAX_LENGTH is the length of the longest string in that -// array. Readline provides a convenience function, -// `rl_display_match_list', that takes care of doing the display to -// Readline's output stream. That function may be called from this -// hook. diff -r 7c4b04a6346d -r 822a2fe5bb51 gui-main.h --- a/gui-main.h Thu May 23 11:26:44 2019 -0400 +++ b/gui-main.h Thu May 23 12:36:26 2019 -0400 @@ -1,89 +1,9 @@ #if ! defined (calc_gui_main_h) #define calc_gui_main_h 1 -#include - -#include -#include - -#include "qt-interpreter.h" - -namespace gui +namespace calc { - class command_window : public QTextEdit - { - Q_OBJECT - - public: - - command_window (QWidget *p = nullptr); - - virtual ~command_window (void) = default; - - // Accept an input line, parse and possibly execute it. - - void accept_line (const std::string& line); - - // Redisplay current command line. - - void insert_at_end (const std::string& text); - - void emit_error (const std::string& msg); - - void emit_result (double value); - - signals: - - void input_char_available (int key); - - void accept_line_signal (const QString& line); - - void redisplay_signal (void); - - public slots: - - void handle_input_char (int key); - - void handle_error (const QString& msg); - - void handle_result (double value); - - void redisplay (void); - - protected: - - void keyPressEvent (QKeyEvent *event); - - int do_arrow_key (int arrow_key); - - // Retrieve a command from the history list and insert it on the - // current command. - - void history (bool up); - - void erase_line (void); - - void insert_at_cursor (const std::string& text); - - void insert_line (const std::string& prompt, const std::string& line); - - int set_mark (void); - - void insert_result (double value); - - void scroll_to_bottom (void); - - // Child widgets: - - QTextDocument *m_buffer; - - calc::qt_interpreter *m_interpreter; - - int beg_mark; - int prompt_mark; - }; - - extern int main (int argc, char **argv); + extern int gui_main (int argc, char **argv); } #endif diff -r 7c4b04a6346d -r 822a2fe5bb51 interpreter.cpp --- a/interpreter.cpp Thu May 23 11:26:44 2019 -0400 +++ b/interpreter.cpp Thu May 23 12:36:26 2019 -0400 @@ -6,7 +6,6 @@ #include "interpreter.h" #include "parser.h" -#include "main.h" #include "gui-main.h" #include "tty-main.h" @@ -18,7 +17,7 @@ : m_error_handler ([] (const char *msg) { std::cerr << "error: " << msg << std::endl; }), m_result_handler ([] (double value) - { std::cout << value << std::endl; }) + { std::cout << "ans = " << value << std::endl; }) { if (the_interpreter) { diff -r 7c4b04a6346d -r 822a2fe5bb51 main.cpp --- a/main.cpp Thu May 23 11:26:44 2019 -0400 +++ b/main.cpp Thu May 23 12:36:26 2019 -0400 @@ -5,15 +5,11 @@ #include "gui-main.h" #include "tty-main.h" -namespace calc -{ - bool tty_mode = false; - bool debug_mode = false; -} - int main (int argc, char **argv) { + bool tty_mode = false; + int new_argc = 0; char **new_argv = new char* [argc + 1]; @@ -23,19 +19,14 @@ for (int i = 1; i < argc; i++) { if (argv[i] == std::string ("--tty")) - calc::tty_mode = true; - else - new_argv[new_argc++] = argv[i]; - - if (argv[i] == std::string ("--debug")) - calc::debug_mode = true; + tty_mode = true; else new_argv[new_argc++] = argv[i]; } - int status = calc::tty_mode - ? tty::main (new_argc, new_argv) - : gui::main (new_argc, new_argv); + int status = tty_mode + ? calc::tty_main (new_argc, new_argv) + : calc::gui_main (new_argc, new_argv); delete [] new_argv; diff -r 7c4b04a6346d -r 822a2fe5bb51 main.h --- a/main.h Thu May 23 11:26:44 2019 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,10 +0,0 @@ -#if ! defined (calc_main_h) -#define calc_main_h 1 - -namespace calc -{ - extern bool tty_mode; - extern bool debug_mode; -} - -#endif diff -r 7c4b04a6346d -r 822a2fe5bb51 parser.yy --- a/parser.yy Thu May 23 11:26:44 2019 -0400 +++ b/parser.yy Thu May 23 12:36:26 2019 -0400 @@ -12,9 +12,6 @@ #include #include "interpreter.h" -#include "main.h" -#include "gui-main.h" -#include "tty-main.h" #include "parser.h" namespace parser @@ -27,8 +24,6 @@ bool beg_of_stmt = true; static int yylex (void); - - static void debug_trace (const char *); } static void yyerror (char const *); @@ -54,7 +49,6 @@ | input line | error { - parser::debug_trace ("ABORT"); YYABORT; } ; @@ -70,49 +64,41 @@ exp : NUM { - parser::debug_trace ("NUM"); $$ = $1; parser::beg_of_stmt = false; } | exp '+' exp { - parser::debug_trace ("ADD"); $$ = $1 + $3; parser::beg_of_stmt = false; } | exp '-' exp { - parser::debug_trace ("SUB"); $$ = $1 - $3; parser::beg_of_stmt = false; } | exp '*' exp { - parser::debug_trace ("MUL"); $$ = $1 * $3; parser::beg_of_stmt = false; } | exp '/' exp { - parser::debug_trace ("DIV"); $$ = $1 / $3; parser::beg_of_stmt = false; } | '-' exp %prec NEG { - parser::debug_trace ("NEG"); $$ = -$2; parser::beg_of_stmt = false; } | exp '^' exp { - parser::debug_trace ("EXP"); $$ = std::pow ($1, $3); parser::beg_of_stmt = false; } | '(' exp ')' { - parser::debug_trace ("PAREN"); $$ = $2; parser::beg_of_stmt = false; } @@ -190,12 +176,6 @@ return -2; } - - void debug_trace (const char *msg) - { - if (calc::debug_mode) - std::cerr << msg << std::endl; - } } static void yyerror (char const *msg) diff -r 7c4b04a6346d -r 822a2fe5bb51 tty-main.cpp --- a/tty-main.cpp Thu May 23 11:26:44 2019 -0400 +++ b/tty-main.cpp Thu May 23 12:36:26 2019 -0400 @@ -7,15 +7,14 @@ #include #include -#include "gui-main.h" #include "tty-main.h" #include "interpreter.h" #include "parser.h" -namespace tty +namespace calc { - int main (int, char **) + int tty_main (int, char **) { std::cout << "Example Calculator.\n" @@ -50,14 +49,4 @@ return 0; } - - void emit_result (double value) - { - std::cout << "ans = " << value << std::endl; - } - - void emit_error (const char *msg) - { - std::cerr << "parse error: " << msg << std::endl; - } } diff -r 7c4b04a6346d -r 822a2fe5bb51 tty-main.h --- a/tty-main.h Thu May 23 11:26:44 2019 -0400 +++ b/tty-main.h Thu May 23 12:36:26 2019 -0400 @@ -1,12 +1,9 @@ #if ! defined (calc_tty_main_h) #define calc_tty_main_h 1 -namespace tty +namespace calc { - extern int main (int argc, char **argv); - - extern void emit_result (double value); - extern void emit_error (const char *msg); + extern int tty_main (int argc, char **argv); } #endif