aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/cmdline.cpp8
-rw-r--r--src/error.cpp17
-rw-r--r--src/error.h23
-rw-r--r--src/interface-curses.cpp24
-rw-r--r--src/interface-gtk.cpp44
-rw-r--r--src/main.cpp24
-rw-r--r--src/qregisters.cpp54
-rw-r--r--src/ring.cpp1
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 */