diff options
author | Robin Haberkorn <robin.haberkorn@googlemail.com> | 2012-11-14 05:40:16 +0100 |
---|---|---|
committer | Robin Haberkorn <robin.haberkorn@googlemail.com> | 2012-11-14 05:40:16 +0100 |
commit | a054db598ae07479bf70c4465434938085f91e03 (patch) | |
tree | 7049e06bf365efae59ac79d3d272d100eef64dc2 | |
parent | 399cc7a1ab9751fdbbeae3507e8612dbbbc99f5b (diff) | |
download | sciteco-a054db598ae07479bf70c4465434938085f91e03.tar.gz |
error checking and colon modifier support for lots of commands
-rw-r--r-- | parser.cpp | 185 | ||||
-rw-r--r-- | parser.h | 6 | ||||
-rw-r--r-- | sciteco.h | 19 |
3 files changed, 165 insertions, 45 deletions
@@ -341,29 +341,43 @@ StateStart::StateStart() : State() transitions['X'] = &States::copytoqreg; } -void -StateStart::move(gint64 n) +tecoBool +StateStart::move_chars(gint64 n) { sptr_t pos = editor_msg(SCI_GETCURRENTPOS); + + if (!Validate::pos(pos + n)) + return FAILURE; + editor_msg(SCI_GOTOPOS, pos + n); undo.push_msg(SCI_GOTOPOS, pos); + return SUCCESS; } -void +tecoBool StateStart::move_lines(gint64 n) { sptr_t pos = editor_msg(SCI_GETCURRENTPOS); - editor_msg(SCI_GOTOLINE, editor_msg(SCI_LINEFROMPOSITION, pos) + n); + sptr_t line = editor_msg(SCI_LINEFROMPOSITION, pos) + n; + + if (!Validate::line(line)) + return FAILURE; + + editor_msg(SCI_GOTOLINE, line); undo.push_msg(SCI_GOTOPOS, pos); + return SUCCESS; } -void +tecoBool StateStart::delete_words(gint64 n) { + sptr_t pos, size; + if (!n) - return; + return SUCCESS; - undo.push_msg(SCI_UNDO); + pos = editor_msg(SCI_GETCURRENTPOS); + size = editor_msg(SCI_GETLENGTH); editor_msg(SCI_BEGINUNDOACTION); /* * FIXME: would be nice to do this with constant amount of @@ -371,21 +385,44 @@ StateStart::delete_words(gint64 n) * the internal document buffer. */ if (n > 0) { - while (n--) + while (n--) { + sptr_t size = editor_msg(SCI_GETLENGTH); editor_msg(SCI_DELWORDRIGHTEND); + if (size == editor_msg(SCI_GETLENGTH)) + break; + } } else { - while (n++) { + n *= -1; + while (n--) { + sptr_t pos = editor_msg(SCI_GETCURRENTPOS); //editor_msg(SCI_DELWORDLEFTEND); editor_msg(SCI_WORDLEFTEND); + if (pos == editor_msg(SCI_GETCURRENTPOS)) + break; editor_msg(SCI_DELWORDRIGHTEND); } } editor_msg(SCI_ENDUNDOACTION); + + if (n >= 0) { + if (size != editor_msg(SCI_GETLENGTH)) { + editor_msg(SCI_UNDO); + editor_msg(SCI_GOTOPOS, pos); + } + return FAILURE; + } + + undo.push_msg(SCI_GOTOPOS, pos); + undo.push_msg(SCI_UNDO); + return SUCCESS; } State * StateStart::custom(gchar chr) { + gint64 v; + tecoBool rc; + /* * <CTRL/x> commands implemented in StateCtrlCmd */ @@ -533,15 +570,14 @@ StateStart::custom(gchar chr) } break; - case ';': { - gint64 v; + case ';': BEGIN_EXEC(this); - v = expressions.pop_num_calc(1, qregisters["_"]->integer); + rc = expressions.pop_num_calc(1, qregisters["_"]->integer); if (eval_colon()) - v = ~v; + rc = ~rc; - if (IS_FAILURE(v)) { + if (IS_FAILURE(rc)) { expressions.discard_args(); g_assert(expressions.pop_op() == Expressions::OP_LOOP); expressions.pop_num(); /* pc */ @@ -552,7 +588,6 @@ StateStart::custom(gchar chr) mode = MODE_PARSE_ONLY_LOOP; } break; - } /* * control structures (conditionals) @@ -610,58 +645,110 @@ StateStart::custom(gchar chr) */ case 'J': BEGIN_EXEC(this); - undo.push_msg(SCI_GOTOPOS, editor_msg(SCI_GETCURRENTPOS)); - editor_msg(SCI_GOTOPOS, expressions.pop_num_calc(1, 0)); + v = expressions.pop_num_calc(1, 0); + if (Validate::pos(v)) { + undo.push_msg(SCI_GOTOPOS, + editor_msg(SCI_GETCURRENTPOS)); + editor_msg(SCI_GOTOPOS, v); + + if (eval_colon()) + expressions.push(SUCCESS); + } else if (eval_colon()) { + expressions.push(FAILURE); + } else { + return NULL; /* FIXME */ + } break; case 'C': BEGIN_EXEC(this); - move(expressions.pop_num_calc()); + rc = move_chars(expressions.pop_num_calc()); + if (eval_colon()) + expressions.push(rc); + else if (IS_FAILURE(rc)) + return NULL; /* FIXME */ break; case 'R': BEGIN_EXEC(this); - move(-expressions.pop_num_calc()); + rc = move_chars(-expressions.pop_num_calc()); + if (eval_colon()) + expressions.push(rc); + else if (IS_FAILURE(rc)) + return NULL; /* FIXME */ break; case 'L': BEGIN_EXEC(this); - move_lines(expressions.pop_num_calc()); + rc = move_lines(expressions.pop_num_calc()); + if (eval_colon()) + expressions.push(rc); + else if (IS_FAILURE(rc)) + return NULL; /* FIXME */ break; case 'B': BEGIN_EXEC(this); - move_lines(-expressions.pop_num_calc()); + rc = move_lines(-expressions.pop_num_calc()); + if (eval_colon()) + expressions.push(rc); + else if (IS_FAILURE(rc)) + return NULL; /* FIXME */ break; case 'W': { + sptr_t pos; + unsigned int msg = SCI_WORDRIGHTEND; + BEGIN_EXEC(this); - gint64 words = expressions.pop_num_calc(); + v = expressions.pop_num_calc(); - undo.push_msg(SCI_GOTOPOS, editor_msg(SCI_GETCURRENTPOS)); + pos = editor_msg(SCI_GETCURRENTPOS); /* * FIXME: would be nice to do this with constant amount of * editor messages. E.g. by using custom algorithm accessing * the internal document buffer. */ - if (words >= 0) { - while (words--) - editor_msg(SCI_WORDRIGHTEND); + if (v < 0) { + v *= -1; + msg = SCI_WORDLEFTEND; + } + while (v--) { + sptr_t pos = editor_msg(SCI_GETCURRENTPOS); + editor_msg(msg); + if (pos == editor_msg(SCI_GETCURRENTPOS)) + break; + } + if (v < 0) { + undo.push_msg(SCI_GOTOPOS, pos); + if (eval_colon()) + expressions.push(SUCCESS); } else { - while (words++) - editor_msg(SCI_WORDLEFTEND); + editor_msg(SCI_GOTOPOS, pos); + if (eval_colon()) + expressions.push(FAILURE); + else + return NULL; /* FIXME */ } break; } case 'V': BEGIN_EXEC(this); - delete_words(expressions.pop_num_calc()); + rc = delete_words(expressions.pop_num_calc()); + if (eval_colon()) + expressions.push(rc); + else if (IS_FAILURE(rc)) + return NULL; /* FIXME */ break; case 'Y': BEGIN_EXEC(this); - delete_words(-expressions.pop_num_calc()); + rc = delete_words(-expressions.pop_num_calc()); + if (eval_colon()) + expressions.push(rc); + else if (IS_FAILURE(rc)) + return NULL; /* FIXME */ break; case '=': @@ -681,30 +768,41 @@ StateStart::custom(gchar chr) from = editor_msg(SCI_GETCURRENTPOS); if (chr == 'D') { len = expressions.pop_num_calc(); + rc = TECO_BOOL(Validate::pos(from + len)); } else /* chr == 'K' */ { - sptr_t line = editor_msg(SCI_LINEFROMPOSITION, from) + - expressions.pop_num_calc(); - len = editor_msg(SCI_POSITIONFROMLINE, line) - from; + sptr_t line; + line = editor_msg(SCI_LINEFROMPOSITION, from) + + expressions.pop_num_calc(); + len = editor_msg(SCI_POSITIONFROMLINE, line) + - from; + rc = TECO_BOOL(Validate::line(line)); } if (len < 0) { - from += len; len *= -1; + from -= len; } } else { gint64 to = expressions.pop_num(); from = expressions.pop_num(); len = to - from; + rc = TECO_BOOL(len >= 0 && Validate::pos(from) && + Validate::pos(to)); } - if (len > 0) { - undo.push_msg(SCI_GOTOPOS, - editor_msg(SCI_GETCURRENTPOS)); - undo.push_msg(SCI_UNDO); + if (eval_colon()) + expressions.push(rc); + else if (IS_FAILURE(rc)) + return NULL; /* FIXME */ - editor_msg(SCI_BEGINUNDOACTION); - editor_msg(SCI_DELETERANGE, from, len); - editor_msg(SCI_ENDUNDOACTION); - } + if (len == 0 || IS_FAILURE(rc)) + break; + + undo.push_msg(SCI_GOTOPOS, editor_msg(SCI_GETCURRENTPOS)); + undo.push_msg(SCI_UNDO); + + editor_msg(SCI_BEGINUNDOACTION); + editor_msg(SCI_DELETERANGE, from, len); + editor_msg(SCI_ENDUNDOACTION); break; } @@ -1356,6 +1454,9 @@ StateSearch::done(const gchar *str) if (eval_colon()) expressions.push(search_reg->integer); + else if (IS_FAILURE(search_reg->integer) && + !expressions.find_op(Expressions::OP_LOOP) /* in loop */) + message_display(GTK_MESSAGE_ERROR, "Search string not found!"); return &States::start; } @@ -106,9 +106,9 @@ public: StateStart(); private: - void move(gint64 n); - void move_lines(gint64 n); - void delete_words(gint64 n); + tecoBool move_chars(gint64 n); + tecoBool move_lines(gint64 n); + tecoBool delete_words(gint64 n); State *custom(gchar chr); }; @@ -26,8 +26,11 @@ sptr_t editor_msg(unsigned int iMessage, uptr_t wParam = 0, sptr_t lParam = 0); #define CTL_ECHO(C) ((C) | 0x40) #define CTL_KEY(C) ((C) & ~0x40) +typedef gint64 tecoBool; + #define SUCCESS (-1) #define FAILURE (0) +#define TECO_BOOL(X) ((X) ? SUCCESS : FAILURE) #define IS_SUCCESS(X) ((X) < 0) #define IS_FAILURE(X) (!IS_SUCCESS(X)) @@ -54,4 +57,20 @@ append(gchar *&str, gchar chr) } /* namespace String */ +namespace Validate { + +static inline bool +pos(gint n) +{ + return n >= 0 && n <= editor_msg(SCI_GETLENGTH); +} + +static inline bool +line(gint n) +{ + return n >= 0 && n < editor_msg(SCI_GETLINECOUNT); +} + +} /* namespace Validate */ + #endif |