diff options
-rw-r--r-- | src/cmdline.cpp | 45 | ||||
-rw-r--r-- | src/parser.cpp | 54 | ||||
-rw-r--r-- | src/parser.h | 23 | ||||
-rw-r--r-- | src/qregisters.cpp | 6 | ||||
-rw-r--r-- | src/qregisters.h | 9 |
5 files changed, 77 insertions, 60 deletions
diff --git a/src/cmdline.cpp b/src/cmdline.cpp index 6e4c9d3..4796560 100644 --- a/src/cmdline.cpp +++ b/src/cmdline.cpp @@ -61,6 +61,9 @@ namespace States { void cmdline_keypress(gchar key) { + gchar *old_cmdline = NULL; + gint repl_pos; + const gchar *insert; gchar *echo; @@ -85,23 +88,43 @@ cmdline_keypress(gchar key) while (cmdline_pos <= (gint)strlen(cmdline)) { try { Execute::step((const gchar *&)cmdline, cmdline_pos); + } catch (ReplaceCmdline &r) { + undo.pop(r.pos); + + old_cmdline = cmdline; + cmdline = r.new_cmdline; + cmdline_pos = repl_pos = r.pos; + macro_pc = r.pos-1; } catch (...) { - /* - * Undo tokens may have been emitted (or had to be) - * before the exception is thrown. They must be - * executed so as if the character had never been - * inserted. - */ - undo.pop(cmdline_pos); - cmdline[cmdline_pos-1] = '\0'; - /* program counter could be messed up */ - macro_pc = cmdline_pos - 1; - break; + if (old_cmdline) { + undo.pop(repl_pos); + + g_free(cmdline); + cmdline = old_cmdline; + cmdline[strlen(cmdline)-1] = '\0'; + old_cmdline = NULL; + cmdline_pos = repl_pos-1; + macro_pc = repl_pos-1; + } else { + /* + * Undo tokens may have been emitted (or had to be) + * before the exception is thrown. They must be + * executed so as if the character had never been + * inserted. + */ + undo.pop(cmdline_pos); + cmdline[cmdline_pos-1] = '\0'; + /* program counter could be messed up */ + macro_pc = cmdline_pos - 1; + break; + } } cmdline_pos++; } + g_free(old_cmdline); + /* * Echo command line */ diff --git a/src/parser.cpp b/src/parser.cpp index cb4180e..d63f0f7 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -71,7 +71,8 @@ gchar *strings[2] = {NULL, NULL}; gchar escape_char = '\x1B'; void -Execute::step(const gchar *¯o, gint &stop_pos) throw (State::Error) +Execute::step(const gchar *¯o, gint &stop_pos) + throw (State::Error, ReplaceCmdline) { while (macro_pc < stop_pos) { #ifdef DEBUG @@ -89,7 +90,8 @@ Execute::step(const gchar *¯o, gint &stop_pos) throw (State::Error) } void -Execute::macro(const gchar *macro, bool locals) throw (State::Error) +Execute::macro(const gchar *macro, bool locals) + throw (State::Error, ReplaceCmdline) { gint macro_len = strlen(macro); @@ -168,6 +170,13 @@ Execute::file(const gchar *filename, bool locals) return true; } +ReplaceCmdline::ReplaceCmdline(gchar *_new_cmdline) + : new_cmdline(_new_cmdline) +{ + for (pos = 0; cmdline[pos] && cmdline[pos] == new_cmdline[pos]; pos++); + pos++; +} + State::Error::Error(const gchar *fmt, ...) { va_list ap; @@ -195,7 +204,7 @@ State::eval_colon(void) } void -State::input(gchar chr) throw (Error) +State::input(gchar chr) throw (Error, ReplaceCmdline) { State *state = States::current; @@ -216,7 +225,7 @@ State::input(gchar chr) throw (Error) } State * -State::get_next_state(gchar chr) throw (Error) +State::get_next_state(gchar chr) throw (Error, ReplaceCmdline) { State *next = NULL; guint upper = g_ascii_toupper(chr); @@ -602,7 +611,7 @@ StateStart::delete_words(gint64 n) } State * -StateStart::custom(gchar chr) throw (Error) +StateStart::custom(gchar chr) throw (Error, ReplaceCmdline) { gint64 v; tecoBool rc; @@ -847,8 +856,8 @@ StateStart::custom(gchar chr) throw (Error) } case '}': { - gint size, i; - gchar *old_cmdline, *new_cmdline; + gint size; + gchar *new_cmdline; BEGIN_EXEC(this); if (!undo.enabled) @@ -859,35 +868,8 @@ StateStart::custom(gchar chr) throw (Error) new_cmdline = (gchar *)g_malloc(size); interface.ssm(SCI_GETTEXT, size, (sptr_t)new_cmdline); - for (i = 0; cmdline[i] && cmdline[i] == new_cmdline[i]; i++); - undo.pop(i+1); - - old_cmdline = cmdline; - cmdline = new_cmdline; - cmdline_pos = i+1; - macro_pc = i; /* FIXME */ - - while (cmdline_pos <= (gint)strlen(cmdline)) { - try { - Execute::step((const gchar *&)cmdline, cmdline_pos); - } catch (...) { - undo.pop(i+1); - cmdline = old_cmdline; - cmdline[strlen(cmdline)-1] = '\0'; - g_free(new_cmdline); - old_cmdline = NULL; - cmdline_pos = i; - macro_pc = i-1; /* FIXME */ - break; - } - - cmdline_pos++; - } - - g_free(old_cmdline); - - /* state may have changed due to undoing */ - return States::current; + /* replace cmdline in the outer macro environment */ + throw ReplaceCmdline(new_cmdline); } /* diff --git a/src/parser.h b/src/parser.h index 8ee15d7..865cf85 100644 --- a/src/parser.h +++ b/src/parser.h @@ -26,6 +26,15 @@ /* TECO uses only lower 7 bits for commands */ #define MAX_TRANSITIONS 127 +/* thrown as exception, executed at cmdline macro level */ +class ReplaceCmdline { +public: + gchar *new_cmdline; + gint pos; + + ReplaceCmdline(gchar *_new_cmdline); +}; + class State { public: class Error { @@ -86,14 +95,14 @@ protected: public: State(); - static void input(gchar chr) throw (Error); - State *get_next_state(gchar chr) throw (Error); + static void input(gchar chr) throw (Error, ReplaceCmdline); + State *get_next_state(gchar chr) throw (Error, ReplaceCmdline); protected: static bool eval_colon(void); virtual State * - custom(gchar chr) throw (Error) + custom(gchar chr) throw (Error, ReplaceCmdline) { throw SyntaxError(chr); return NULL; @@ -164,7 +173,7 @@ private: tecoBool delete_words(gint64 n); - State *custom(gchar chr) throw (Error); + State *custom(gchar chr) throw (Error, ReplaceCmdline); }; class StateControl : public State { @@ -253,8 +262,10 @@ extern gchar *strings[2]; extern gchar escape_char; namespace Execute { - void step(const gchar *¯o, gint &stop_pos) throw (State::Error); - void macro(const gchar *macro, bool locals = true) throw (State::Error); + void step(const gchar *¯o, gint &stop_pos) + throw (State::Error, ReplaceCmdline); + void macro(const gchar *macro, bool locals = true) + throw (State::Error, ReplaceCmdline); bool file(const gchar *filename, bool locals = true); } diff --git a/src/qregisters.cpp b/src/qregisters.cpp index a13fba1..b2987b3 100644 --- a/src/qregisters.cpp +++ b/src/qregisters.cpp @@ -171,7 +171,7 @@ QRegister::undo_edit(void) } void -QRegister::execute(bool locals) throw (State::Error) +QRegister::execute(bool locals) throw (State::Error, ReplaceCmdline) { gchar *str = get_string(); @@ -359,7 +359,7 @@ StateExpectQReg::StateExpectQReg() : State(), got_local(false) } State * -StateExpectQReg::custom(gchar chr) throw (Error) +StateExpectQReg::custom(gchar chr) throw (Error, ReplaceCmdline) { QRegister *reg; @@ -509,7 +509,7 @@ StateIncreaseQReg::got_register(QRegister ®) throw (Error) } State * -StateMacro::got_register(QRegister ®) throw (Error) +StateMacro::got_register(QRegister ®) throw (Error, ReplaceCmdline) { BEGIN_EXEC(&States::start); diff --git a/src/qregisters.h b/src/qregisters.h index 19fd3cd..651be1e 100644 --- a/src/qregisters.h +++ b/src/qregisters.h @@ -116,7 +116,7 @@ public: virtual void edit(void); virtual void undo_edit(void); - void execute(bool locals = true) throw (State::Error); + void execute(bool locals = true) throw (State::Error, ReplaceCmdline); bool load(const gchar *filename); inline void @@ -268,10 +268,11 @@ public: StateExpectQReg(); private: - State *custom(gchar chr) throw (Error); + State *custom(gchar chr) throw (Error, ReplaceCmdline); protected: - virtual State *got_register(QRegister ®) throw (Error) = 0; + virtual State *got_register(QRegister ®) + throw (Error, ReplaceCmdline) = 0; }; class StatePushQReg : public StateExpectQReg { @@ -328,7 +329,7 @@ private: class StateMacro : public StateExpectQReg { private: - State *got_register(QRegister ®) throw (Error); + State *got_register(QRegister ®) throw (Error, ReplaceCmdline); }; class StateCopyToQReg : public StateExpectQReg { |