diff options
-rw-r--r-- | src/cmdline.cpp | 8 | ||||
-rw-r--r-- | src/error.cpp | 17 | ||||
-rw-r--r-- | src/error.h | 23 | ||||
-rw-r--r-- | src/interface-curses.cpp | 24 | ||||
-rw-r--r-- | src/interface-gtk.cpp | 44 | ||||
-rw-r--r-- | src/main.cpp | 24 | ||||
-rw-r--r-- | src/qregisters.cpp | 54 | ||||
-rw-r--r-- | src/ring.cpp | 1 |
8 files changed, 151 insertions, 44 deletions
diff --git a/src/cmdline.cpp b/src/cmdline.cpp index e28ce35..e78db60 100644 --- a/src/cmdline.cpp +++ b/src/cmdline.cpp @@ -20,7 +20,6 @@ #endif #include <string.h> -#include <stdlib.h> #include <signal.h> #include <glib.h> @@ -253,10 +252,9 @@ process_edit_cmd(gchar key) break; } - if (quit_requested) { - /* FIXME */ - exit(EXIT_SUCCESS); - } + if (quit_requested) + /* cought by user interface */ + throw Quit(); undo.clear(); interface.ssm(SCI_EMPTYUNDOBUFFER); diff --git a/src/error.cpp b/src/error.cpp index 7bdd6f2..8dd4534 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -81,9 +81,24 @@ Error::FileFrame::display(gint nr) } Error::Frame * +Error::EDHookFrame::copy() const +{ + /* coordinates do not matter */ + return new EDHookFrame(type); +} + +void +Error::EDHookFrame::display(gint nr) +{ + interface.msg(InterfaceCurrent::MSG_INFO, + "#%d in \"%s\" hook execution", + nr, type); +} + +Error::Frame * Error::ToplevelFrame::copy() const { - Frame *frame = new ToplevelFrame; + Frame *frame = new ToplevelFrame(); frame->pos = pos; frame->line = line; diff --git a/src/error.h b/src/error.h index d0849c7..9029b86 100644 --- a/src/error.h +++ b/src/error.h @@ -37,6 +37,12 @@ public: ReplaceCmdline(); }; +/* + * Thrown as exception to signify that program + * should be terminated. + */ +class Quit {}; + class Error { gchar *description; GSList *frames; @@ -90,6 +96,23 @@ public: void display(gint nr); }; + class EDHookFrame : public Frame { + gchar *type; + + public: + EDHookFrame(const gchar *_type) + : type(g_strdup(_type)) {} + + Frame *copy() const; + + ~EDHookFrame() + { + g_free(type); + } + + void display(gint nr); + }; + class ToplevelFrame : public Frame { public: Frame *copy() const; diff --git a/src/interface-curses.cpp b/src/interface-curses.cpp index ad7296f..f4ea463 100644 --- a/src/interface-curses.cpp +++ b/src/interface-curses.cpp @@ -478,9 +478,29 @@ InterfaceCurses::event_loop_impl(void) #ifdef EMSCRIPTEN PDC_emscripten_set_handler(event_loop_iter, TRUE); + /* + * We must not block emscripten's main loop, + * instead event_loop_iter() is called asynchronously. + * We also must not exit the event_loop() method, since + * SciTECO would assume ordinary program termination. + * We also must not call exit() since that would run + * the global destructors. + * The following exits the main() function immediately + * while keeping the "runtime" alive. + */ + emscripten_exit_with_live_runtime(); #else - for (;;) - event_loop_iter(); + try { + for (;;) + event_loop_iter(); + } catch (Quit) { + /* SciTECO termination (e.g. EX$$) */ + } + + /* + * Restore ordinary terminal behaviour + */ + endwin(); #endif } diff --git a/src/interface-gtk.cpp b/src/interface-gtk.cpp index 3421d6f..e94c42c 100644 --- a/src/interface-gtk.cpp +++ b/src/interface-gtk.cpp @@ -253,20 +253,10 @@ scintilla_notify(ScintillaObject *sci, uptr_t idFrom, interface.process_notify(notify); } -static gboolean -cmdline_key_pressed(GtkWidget *widget, GdkEventKey *event, - gpointer user_data) +static inline void +handle_key_press(bool is_shift, bool is_ctl, guint keyval) { - bool is_shift = event->state & GDK_SHIFT_MASK; - bool is_ctl = event->state & GDK_CONTROL_MASK; - -#ifdef DEBUG - g_printf("KEY \"%s\" (%d) SHIFT=%d CNTRL=%d\n", - event->string, *event->string, - event->state & GDK_SHIFT_MASK, event->state & GDK_CONTROL_MASK); -#endif - - switch (event->keyval) { + switch (keyval) { case GDK_Escape: cmdline_keypress('\x1B'); break; @@ -296,7 +286,7 @@ cmdline_key_pressed(GtkWidget *widget, GdkEventKey *event, gchar macro_name[3+1]; g_snprintf(macro_name, sizeof(macro_name), - "F%d", event->keyval - GDK_F1 + 1); + "F%d", keyval - GDK_F1 + 1); cmdline_fnmacro(macro_name); break; } @@ -316,7 +306,7 @@ cmdline_key_pressed(GtkWidget *widget, GdkEventKey *event, * Control keys and keys with printable representation */ default: - gunichar u = gdk_keyval_to_unicode(event->keyval); + gunichar u = gdk_keyval_to_unicode(keyval); if (u && g_unichar_to_utf8(u, NULL) == 1) { gchar key; @@ -330,6 +320,30 @@ cmdline_key_pressed(GtkWidget *widget, GdkEventKey *event, cmdline_keypress(key); } } +} + +static gboolean +cmdline_key_pressed(GtkWidget *widget, GdkEventKey *event, + gpointer user_data) +{ + bool is_shift = event->state & GDK_SHIFT_MASK; + bool is_ctl = event->state & GDK_CONTROL_MASK; + +#ifdef DEBUG + g_printf("KEY \"%s\" (%d) SHIFT=%d CNTRL=%d\n", + event->string, *event->string, + event->state & GDK_SHIFT_MASK, event->state & GDK_CONTROL_MASK); +#endif + + try { + handle_key_press(is_shift, is_ctl, event->keyval); + } catch (Quit) { + /* + * SciTECO should terminate, so we exit + * the main loop. event_loop() will return. + */ + gtk_main_quit(); + } return TRUE; } diff --git a/src/main.cpp b/src/main.cpp index 5697063..e7cf62b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -308,6 +308,11 @@ main(int argc, char **argv) /* add remaining arguments to unnamed buffer */ for (int i = 1; i < argc; i++) { + /* + * FIXME: arguments may contain line-feeds. + * Once SciTECO is 8-byte clear, we can add the + * command-line params null-terminated. + */ interface.ssm(SCI_APPENDTEXT, strlen(argv[i]), (sptr_t)argv[i]); interface.ssm(SCI_APPENDTEXT, 1, (sptr_t)"\n"); } @@ -323,6 +328,7 @@ main(int argc, char **argv) error.add_frame(new Error::ToplevelFrame()); throw; /* forward */ } + QRegisters::hook(QRegisters::HOOK_QUIT); exit(EXIT_SUCCESS); } @@ -331,7 +337,7 @@ main(int argc, char **argv) /* FIXME: make quit immediate in batch/macro mode (non-UNDO)? */ if (quit_requested) { - /* FIXME */ + QRegisters::hook(QRegisters::HOOK_QUIT); exit(EXIT_SUCCESS); } } @@ -355,5 +361,21 @@ main(int argc, char **argv) interface.event_loop(); + /* + * Ordinary application termination: + * Interface is shut down, so we are + * in non-interactive mode again. + */ + undo.enabled = false; + interface.ssm(SCI_EMPTYUNDOBUFFER); + undo.clear(); + + try { + QRegisters::hook(QRegisters::HOOK_QUIT); + } catch (Error &error) { + error.display_full(); + exit(EXIT_FAILURE); + } + return 0; } diff --git a/src/qregisters.cpp b/src/qregisters.cpp index 89b2afd..230dc5b 100644 --- a/src/qregisters.cpp +++ b/src/qregisters.cpp @@ -366,32 +366,46 @@ QRegisterStack::~QRegisterStack() void QRegisters::hook(Hook type) { + static const gchar *type2name[] = { + /* [HOOK_ADD-1] = */ "ADD", + /* [HOOK_EDIT-1] = */ "EDIT", + /* [HOOK_CLOSE-1] = */ "CLOSE", + /* [HOOK_QUIT-1] = */ "QUIT", + }; + QRegister *reg; if (!(Flags::ed & Flags::ED_HOOKS)) return; - reg = globals["ED"]; - if (!reg) - throw Error("Undefined ED-hook register (\"ED\")"); + try { + reg = globals["ED"]; + if (!reg) + throw Error("Undefined ED-hook register (\"ED\")"); - /* - * ED-hook execution should not see any - * integer parameters but the hook type. - * Such parameters could confuse the ED macro - * and macro authors do not expect side effects - * of ED macros on the expression stack. - * Also make sure it does not leave behind - * additional arguments on the stack. - * - * So this effectively executes: - * (typeM[ED]^[) - */ - expressions.push(Expressions::OP_BRACE); - expressions.push(type); - reg->execute(); - expressions.discard_args(); - expressions.eval(true); + /* + * ED-hook execution should not see any + * integer parameters but the hook type. + * Such parameters could confuse the ED macro + * and macro authors do not expect side effects + * of ED macros on the expression stack. + * Also make sure it does not leave behind + * additional arguments on the stack. + * + * So this effectively executes: + * (typeM[ED]^[) + */ + expressions.push(Expressions::OP_BRACE); + expressions.push(type); + reg->execute(); + expressions.discard_args(); + expressions.eval(true); + } catch (Error &error) { + const gchar *type_str = type2name[type-1]; + + error.add_frame(new Error::EDHookFrame(type_str)); + throw; /* forward */ + } } void diff --git a/src/ring.cpp b/src/ring.cpp index 1c7087e..575d0e7 100644 --- a/src/ring.cpp +++ b/src/ring.cpp @@ -485,6 +485,7 @@ Ring::close(void) { Buffer *buffer = current; + QRegisters::hook(QRegisters::HOOK_CLOSE); close(buffer); current = buffer->next() ? : buffer->prev(); /* transfer responsibility to UndoToken object */ |