aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--parser.cpp223
-rw-r--r--parser.h14
2 files changed, 178 insertions, 59 deletions
diff --git a/parser.cpp b/parser.cpp
index b63658d..c5acecc 100644
--- a/parser.cpp
+++ b/parser.cpp
@@ -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;
+}
diff --git a/parser.h b/parser.h
index c21f872..86751bc 100644
--- a/parser.h
+++ b/parser.h
@@ -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;
}