aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorRobin Haberkorn <robin.haberkorn@googlemail.com>2013-02-03 18:43:12 +0100
committerRobin Haberkorn <robin.haberkorn@googlemail.com>2013-02-08 22:25:06 +0100
commitc37e2d75d09145d2236388e5b739c6a41e4f3780 (patch)
tree019e90415692db23ce3b8d6f416f134c12fc4512
parent8816b7c7aded7ef8defca0bc6a78b2f5887faea6 (diff)
downloadsciteco-c37e2d75d09145d2236388e5b739c6a41e4f3780.tar.gz
delegate commandline replacements ("}") to the cmdline macro level
allows commandline editing scripted by macros
-rw-r--r--src/cmdline.cpp45
-rw-r--r--src/parser.cpp54
-rw-r--r--src/parser.h23
-rw-r--r--src/qregisters.cpp6
-rw-r--r--src/qregisters.h9
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 *&macro, gint &stop_pos) throw (State::Error)
+Execute::step(const gchar *&macro, gint &stop_pos)
+ throw (State::Error, ReplaceCmdline)
{
while (macro_pc < stop_pos) {
#ifdef DEBUG
@@ -89,7 +90,8 @@ Execute::step(const gchar *&macro, 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 *&macro, gint &stop_pos) throw (State::Error);
- void macro(const gchar *macro, bool locals = true) throw (State::Error);
+ void step(const gchar *&macro, 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 &reg) throw (Error)
}
State *
-StateMacro::got_register(QRegister &reg) throw (Error)
+StateMacro::got_register(QRegister &reg) 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 &reg) throw (Error) = 0;
+ virtual State *got_register(QRegister &reg)
+ throw (Error, ReplaceCmdline) = 0;
};
class StatePushQReg : public StateExpectQReg {
@@ -328,7 +329,7 @@ private:
class StateMacro : public StateExpectQReg {
private:
- State *got_register(QRegister &reg) throw (Error);
+ State *got_register(QRegister &reg) throw (Error, ReplaceCmdline);
};
class StateCopyToQReg : public StateExpectQReg {