diff options
author | Robin Haberkorn <robin.haberkorn@googlemail.com> | 2012-12-03 00:45:25 +0100 |
---|---|---|
committer | Robin Haberkorn <robin.haberkorn@googlemail.com> | 2012-12-03 03:54:00 +0100 |
commit | 14246a1c5a8b542eadd19d74640d9e69c7df9b98 (patch) | |
tree | 09ec8402e77e33ac6a1cbc5bd613eaec21a3e654 | |
parent | 2d626d832ba4d05fa71b9a403d5682e63fe7343c (diff) | |
download | sciteco-14246a1c5a8b542eadd19d74640d9e69c7df9b98.tar.gz |
first draft of N command based on S
-rw-r--r-- | parser.cpp | 223 | ||||
-rw-r--r-- | parser.h | 14 |
2 files changed, 178 insertions, 59 deletions
@@ -28,6 +28,7 @@ namespace States { StateScintilla_lParam scintilla_lparam; StateInsert insert; StateSearch search; + StateSearchAll searchall; State *current = &start; } @@ -451,6 +452,7 @@ StateStart::StateStart() : State() transitions['E'] = &States::ecommand; transitions['I'] = &States::insert; transitions['S'] = &States::search; + transitions['N'] = &States::searchall; transitions['['] = &States::pushqreg; transitions[']'] = &States::popqreg; @@ -1432,31 +1434,32 @@ StateInsert::done(const gchar *str __attribute__((unused))) throw (Error) void StateSearch::initial(void) throw (Error) { - gint64 v; + gint64 v1, v2; - undo.push_var<Parameters>(parameters); + undo.push_var(parameters); parameters.dot = interface.ssm(SCI_GETCURRENTPOS); - v = expressions.pop_num_calc(); + + v2 = expressions.pop_num_calc(); if (expressions.args()) { /* TODO: optional count argument? */ - parameters.count = 1; - parameters.from = (gint)expressions.pop_num_calc(); - parameters.to = (gint)v; + v1 = expressions.pop_num_calc(); + if (v1 <= v2) { + parameters.count = 1; + parameters.from = (gint)v1; + parameters.to = (gint)v2; + } else { + parameters.count = -1; + parameters.from = (gint)v2; + parameters.to = (gint)v1; + } if (!Validate::pos(parameters.from) || !Validate::pos(parameters.to)) throw RangeError("S"); - - if (parameters.from > parameters.to) { - v = parameters.from; - parameters.from = parameters.to; - parameters.to = v; - parameters.count *= -1; - } } else { - parameters.count = (gint)v; - if (v >= 0) { + parameters.count = (gint)v2; + if (v2 >= 0) { parameters.from = parameters.dot; parameters.to = interface.ssm(SCI_GETLENGTH); } else { @@ -1464,6 +1467,9 @@ StateSearch::initial(void) throw (Error) parameters.to = parameters.dot; } } + + parameters.from_buffer = ring.current; + parameters.to_buffer = NULL; } static inline const gchar * @@ -1669,49 +1675,18 @@ error: } void -StateSearch::process(const gchar *str, - gint new_chars __attribute__((unused))) throw (Error) +StateSearch::do_search(GRegex *re, gint from, gint to, gint &count) { - static const gint flags = G_REGEX_CASELESS | G_REGEX_MULTILINE | - G_REGEX_DOTALL | G_REGEX_RAW; - - QRegister *search_reg = QRegisters::globals["_"]; - gchar *re_pattern; - GRegex *re; GMatchInfo *info; const gchar *buffer; gint matched_from = -1, matched_to = -1; - undo.push_msg(SCI_GOTOPOS, interface.ssm(SCI_GETCURRENTPOS)); - - search_reg->undo_set_integer(); - search_reg->set_integer(FAILURE); - - /* NOTE: pattern2regexp() modifies str pointer */ - re_pattern = pattern2regexp(str); -#ifdef DEBUG - g_printf("REGEXP: %s\n", re_pattern); -#endif - if (!re_pattern) { - interface.ssm(SCI_GOTOPOS, parameters.dot); - return; - } - re = g_regex_new(re_pattern, (GRegexCompileFlags)flags, - (GRegexMatchFlags)0, NULL); - g_free(re_pattern); - if (!re) { - interface.ssm(SCI_GOTOPOS, parameters.dot); - return; - } - buffer = (const gchar *)interface.ssm(SCI_GETCHARACTERPOINTER); - g_regex_match_full(re, buffer, (gssize)parameters.to, parameters.from, + g_regex_match_full(re, buffer, (gssize)to, from, (GRegexMatchFlags)0, &info, NULL); - if (parameters.count >= 0) { - gint count = parameters.count; - + if (count >= 0) { while (g_match_info_matches(info) && --count) g_match_info_next(info, NULL); @@ -1724,8 +1699,7 @@ StateSearch::process(const gchar *str, struct Range { gint from, to; }; - gint count = -parameters.count; - Range *matched = new Range[count]; + Range *matched = new Range[-count]; gint matched_total = 0, i = 0; while (g_match_info_matches(info)) { @@ -1734,10 +1708,11 @@ StateSearch::process(const gchar *str, &matched[i].to); g_match_info_next(info, NULL); - i = ++matched_total % count; + i = ++matched_total % -count; } - if (matched_total >= count) { + count = MIN(count + matched_total, 0); + if (!count) { /* successful, i points to stack bottom */ matched_from = matched[i].from; matched_to = matched[i].to; @@ -1748,15 +1723,98 @@ StateSearch::process(const gchar *str, g_match_info_free(info); - if (matched_from >= 0 && matched_to >= 0) { + if (matched_from >= 0 && matched_to >= 0) /* match success */ - search_reg->set_integer(SUCCESS); interface.ssm(SCI_SETSEL, matched_from, matched_to); - } else { - interface.ssm(SCI_GOTOPOS, parameters.dot); +} + +void +StateSearch::process(const gchar *str, + gint new_chars __attribute__((unused))) throw (Error) +{ + static const gint flags = G_REGEX_CASELESS | G_REGEX_MULTILINE | + G_REGEX_DOTALL | G_REGEX_RAW; + + QRegister *search_reg = QRegisters::globals["_"]; + + gchar *re_pattern; + GRegex *re; + + gint count = parameters.count; + + undo.push_msg(SCI_GOTOPOS, interface.ssm(SCI_GETCURRENTPOS)); + + search_reg->undo_set_integer(); + search_reg->set_integer(FAILURE); + + /* NOTE: pattern2regexp() modifies str pointer */ + re_pattern = pattern2regexp(str); +#ifdef DEBUG + g_printf("REGEXP: %s\n", re_pattern); +#endif + if (!re_pattern) + goto failure; + re = g_regex_new(re_pattern, (GRegexCompileFlags)flags, + (GRegexMatchFlags)0, NULL); + g_free(re_pattern); + if (!re) + goto failure; + + if (ring.current != parameters.from_buffer) { + ring.undo_edit(); + parameters.from_buffer->edit(); + } + + do_search(re, parameters.from, parameters.to, count); + + if (parameters.to_buffer && count) { + Buffer *buffer = parameters.from_buffer; + + if (ring.current == buffer) + ring.undo_edit(); + + if (count > 0) { + do { + buffer = buffer->next() ? : ring.first(); + buffer->edit(); + + if (buffer == parameters.to_buffer) { + do_search(re, 0, parameters.dot, count); + break; + } + + do_search(re, 0, interface.ssm(SCI_GETLENGTH), + count); + } while (count); + } else /* count < 0 */ { + do { + buffer = buffer->prev() ? : ring.last(); + buffer->edit(); + + if (buffer == parameters.to_buffer) { + do_search(re, parameters.dot, + interface.ssm(SCI_GETLENGTH), + count); + break; + } + + do_search(re, 0, interface.ssm(SCI_GETLENGTH), + count); + } while (count); + } + + ring.current = buffer; } + search_reg->set_integer(TECO_BOOL(!count)); + g_regex_unref(re); + + if (!count) + return; + +failure: + interface.ssm(SCI_GOTOPOS, parameters.dot); } State * @@ -1783,3 +1841,54 @@ StateSearch::done(const gchar *str) throw (Error) return &States::start; } + +void +StateSearchAll::initial(void) throw (Error) +{ + gint64 v1, v2; + + undo.push_var(parameters); + + parameters.dot = interface.ssm(SCI_GETCURRENTPOS); + + v2 = expressions.pop_num_calc(); + if (expressions.args()) { + /* TODO: optional count argument? */ + v1 = expressions.pop_num_calc(); + if (v1 <= v2) { + parameters.count = 1; + parameters.from_buffer = ring.find(v1); + parameters.to_buffer = ring.find(v2); + } else { + parameters.count = -1; + parameters.from_buffer = ring.find(v2); + parameters.to_buffer = ring.find(v1); + } + + if (!parameters.from_buffer || !parameters.to_buffer) + throw RangeError("N"); + } else { + parameters.count = (gint)v2; + /* NOTE: on Q-Registers, behave like "S" */ + parameters.from_buffer = parameters.to_buffer = ring.current; + } + + if (parameters.count >= 0) { + parameters.from = parameters.dot; + parameters.to = interface.ssm(SCI_GETLENGTH); + } else { + parameters.from = 0; + parameters.to = parameters.dot; + } +} + +State * +StateSearchAll::done(const gchar *str) throw (Error) +{ + BEGIN_EXEC(&States::start); + + StateSearch::done(str); + + QRegisters::hook(QRegisters::HOOK_EDIT); + return &States::start; +} @@ -225,11 +225,13 @@ private: }; class StateSearch : public StateExpectString { -private: +protected: struct Parameters { gint dot; gint from, to; gint count; + + Buffer *from_buffer, *to_buffer; } parameters; enum MatchState { @@ -244,9 +246,16 @@ private: gchar *class2regexp(MatchState &state, const gchar *&pattern, bool escape_default = false); gchar *pattern2regexp(const gchar *&pattern, bool single_expr = false); + void do_search(GRegex *re, gint from, gint to, gint &count); + virtual void initial(void) throw (Error); + virtual void process(const gchar *str, gint new_chars) throw (Error); + virtual State *done(const gchar *str) throw (Error); +}; + +class StateSearchAll : public StateSearch { +private: void initial(void) throw (Error); - void process(const gchar *str, gint new_chars) throw (Error); State *done(const gchar *str) throw (Error); }; @@ -260,6 +269,7 @@ namespace States { extern StateScintilla_lParam scintilla_lparam; extern StateInsert insert; extern StateSearch search; + extern StateSearchAll searchall; extern State *current; } |