diff options
author | Robin Haberkorn <robin.haberkorn@googlemail.com> | 2012-11-08 04:28:54 +0100 |
---|---|---|
committer | Robin Haberkorn <robin.haberkorn@googlemail.com> | 2012-11-08 04:28:54 +0100 |
commit | b58893781bcb8feeba8c4743ae3d5e6083dc010e (patch) | |
tree | 2fc9c98fa2f7fadf67508536be8c2c08843422e4 | |
parent | d0020c7f6faeff4b415f15884eea3270d306aff9 (diff) | |
download | sciteco-b58893781bcb8feeba8c4743ae3d5e6083dc010e.tar.gz |
insert (I) and <TAB> commands implemented
* StateExpectString does not yet handle string building chars
-rw-r--r-- | parser.cpp | 108 | ||||
-rw-r--r-- | parser.h | 26 |
2 files changed, 132 insertions, 2 deletions
@@ -1,3 +1,5 @@ +#include <string.h> + #include <glib.h> #include <glib/gprintf.h> @@ -26,6 +28,8 @@ static gint nest_level = 0; gchar *strings[2] = {NULL, NULL}; +static gchar escape_char = '\x1B'; + bool macro_execute(const gchar *macro) { @@ -101,6 +105,63 @@ State::get_next_state(gchar chr) return next; } +State * +StateExpectString::custom(gchar chr) +{ + gchar insert[255]; + gchar *new_str; + + if (chr == '\0') { + BEGIN_EXEC(this); + initial(); + return this; + } + + /* + * String termination handling + */ + if (modifiers.at) { + undo.push_var<bool>(modifiers.at); + modifiers.at = false; + undo.push_var<gchar>(escape_char); + escape_char = g_ascii_toupper(chr); + + return this; + } + + if (g_ascii_toupper(chr) == escape_char) { + State *next = done(strings[0]); + + undo.push_var<gchar>(escape_char); + escape_char = '\x1B'; + undo.push_str(strings[0]); + g_free(strings[0]); + strings[0] = NULL; + /* TODO: save and reset string building machine state */ + + return next; + } + + /* + * String building characters + */ + /* TODO */ + insert[0] = chr; + insert[1] = '\0'; + + /* + * String accumulation + */ + undo.push_str(strings[0]); + new_str = g_strconcat(strings[0] ? : "", insert, NULL); + g_free(strings[0]); + strings[0] = new_str; + + BEGIN_EXEC(this); + process(strings[0], strlen(insert)); + return this; +} + StateStart::StateStart() : State() { transitions['\0'] = this; @@ -108,6 +169,7 @@ StateStart::StateStart() : State() transitions['!'] = &states.label; transitions['^'] = &states.control; + transitions['I'] = &states.insert; } void @@ -448,7 +510,6 @@ StateControl::custom(gchar chr) expressions.set_radix(expressions.pop_num_calc()); break; -#if 0 /* * Alternatives: ^i, ^I, <CTRL/I>, <TAB> */ @@ -457,7 +518,6 @@ StateControl::custom(gchar chr) expressions.eval(); expressions.push('\t'); return &states.insert; -#endif /* * Alternatives: ^[, <CTRL/[>, <ESC> @@ -491,3 +551,47 @@ StateControl::custom(gchar chr) return &states.start; } + +/* + * NOTE: cannot support VideoTECO's <n>I because + * beginning and end of strings must be determined + * syntactically + */ +void +StateInsert::initial(void) +{ + int args; + + expressions.eval(); + args = expressions.args(); + if (!args) + return; + + editor_msg(SCI_BEGINUNDOACTION); + for (int i = args; i > 0; i--) { + /* FIXME: if possible prevent pops with index != 1 */ + gchar chr = (gchar)expressions.pop_num_calc(i); + editor_msg(SCI_ADDTEXT, 1, (sptr_t)&chr); + } + editor_msg(SCI_ENDUNDOACTION); + + undo.push_msg(SCI_UNDO); +} + +void +StateInsert::process(const gchar *str, gint new_chars) +{ + editor_msg(SCI_BEGINUNDOACTION); + editor_msg(SCI_ADDTEXT, new_chars, + (sptr_t)str + strlen(str) - new_chars); + editor_msg(SCI_ENDUNDOACTION); + + undo.push_msg(SCI_UNDO); +} + +State * +StateInsert::done(const gchar *str __attribute__((unused))) +{ + /* nothing to be done when done */ + return &states.start; +} @@ -39,6 +39,24 @@ protected: } }; +/* + * Super-class for states accepting string arguments + * Opaquely cares about alternative-escape characters, + * string building commands and accumulation into a string + */ +class StateExpectString : public State { +public: + StateExpectString() : State() {} + +private: + virtual State *custom(gchar chr); + +protected: + virtual void initial(void) {} + virtual void process(const gchar *str, gint new_chars) {} + virtual State *done(const gchar *str) = 0; +}; + class StateStart : public State { public: StateStart(); @@ -58,6 +76,13 @@ private: State *custom(gchar chr); }; +class StateInsert : public StateExpectString { +private: + void initial(void); + void process(const gchar *str, gint new_chars); + State *done(const gchar *str); +}; + #include "goto.h" extern gint macro_pc; @@ -66,6 +91,7 @@ extern struct States { StateStart start; StateLabel label; StateControl control; + StateInsert insert; } states; extern enum Mode { |