]> git.neil.brown.name Git - edlib.git/commitdiff
lib-search: add "reverse" command for search commands.
authorNeilBrown <neil@brown.name>
Wed, 1 Nov 2023 06:23:07 +0000 (17:23 +1100)
committerNeilBrown <neil@brown.name>
Wed, 1 Nov 2023 06:38:07 +0000 (17:38 +1100)
A "search" command created with make-search now responds to
"reverse" and does a backwards search.

Signed-off-by: NeilBrown <neil@brown.name>
DOC/TODO.md
lib-search.c

index 8eb73263dea66d44d8bbb3bb5842e07bb127119f..77ec877ce374bf0d48130f635bc2a3304399b9d7 100644 (file)
@@ -34,18 +34,7 @@ the file.
 - [X] search hangs when seeking "^( *)"
 - [X] selection-menu item to show git-commit from list of known git
       trees
-- [ ] selection-menu item for word-count
 - [X] selection-menu item for QR-code
-- [ ] selection-menu sub-menu for UPPER lower Caps ??
-- [ ] selection-menu item for text-fill
-- [ ] selection-menu item for spell-check ??
-- [ ] selection-menu item to view a named file - in Popup:Tile
-- [ ] notmuch - capture errors about multiple Subject lines and
-      display them better.
-- [ ] switch display-pygtk to use Draw:scale-image
-- [ ] when add address to a query in notmuch, reassess the current
-      query.  Maybe don't reload, but make sure that next reload will
-      used updated query.
 - [X] get too many Failed:: C-N C-P Up C-R history:C-R A-!
       Maybe these should return Efalse, not Efail
 
@@ -64,7 +53,7 @@ the file.
 
 - [X] split range management out of autospell so it can be used by other
       modules.
-- [ ] make it easy for a make-search command to search backwards
+- [X] make it easy for a make-search command to search backwards
 - [X] Make a start on CUA mode with mouse/menu/selection support.
       Also Function keys: help, close, refresh
 
@@ -265,6 +254,7 @@ Module features
 
 ### lib-linecount
 
+- [ ] selection-menu item for word-count
 - [ ] handle view:changed properly, and make sure total count changes
       appropriately in notmuch-query-view.  Maybe view:changed should
       report if content changed, or just attributes.
@@ -295,6 +285,7 @@ Module features
 - [X] auto-wrap on a line like this one doesn't recognize all the
   punctuation a the start of the line ... should it?
 - [X] fill mode to handle all punctuation at start of this line
+- [ ] selection-menu item for text-fill
 
 ### render-format
 
@@ -303,7 +294,7 @@ Module features
 
 ### lib-search
 
-- [ ] make it easy for a make-search command to search backwards
+- [X] make it easy for a make-search command to search backwards
 
 ### autosave
 
@@ -356,6 +347,8 @@ Module features
 
 ### emacs
 
+- [ ] selection-menu sub-menu for UPPER lower Caps ??
+- [ ] selection-menu item to view a named file - in Popup:Tile
 - [ ] multi-file search-replace.  Find files with 'git-grep'
 - [ ] there is no way to count characters in a range, or find how many
       characters into the document I am.  Maybe bytes would be good too.
@@ -400,6 +393,7 @@ Module features
 
 ### pygtk
 
+- [ ] switch display-pygtk to use Draw:scale-image
 - [ ] can we capture the substates of character composition, and give
       feed-back?
 
@@ -629,6 +623,9 @@ Module features
 
 ###  Notmuch message display
 
+- [ ] when add address to a query in notmuch, reassess the current
+      query.  Maybe don't reload, but make sure that next reload will
+      used updated query.
 - [X] notmuch addresses in From: list to have menu to add address to
       any from-* query
 - [ ] "%d quoted lines" still not quite right.  Moving 'down' past it
@@ -683,6 +680,8 @@ Module features
 
 ### Notmuch composition
 
+- [ ] notmuch - capture errors about multiple Subject lines and
+      display them better.
 - [ ] when aborting email composition, unlink the file if it is
       empty.  Probably dispose of autosave too.
 - [ ] should I look for Delivered-to headers. Even;
@@ -849,6 +848,7 @@ Module features
 - [ ] Some way for 'c-mode' to report where comments are so they can be spell-checked
 - [ ] drop-down with options
 - [ ] unify UI with dynamic-completion
+- [ ] selection-menu item for spell-check ??
 - [X] split range management out of autospell so it can be used by other
   modules.
 
index feda3da8a69eb25c8dfc4bbae39378c96ab41411..81ab9f0d45656c9426660e46452ad3d48ceaeda5 100644 (file)
@@ -217,6 +217,101 @@ DEF_CB(search_test)
                free(ret);
                return 1;
        }
+       if (strcmp(ci->key, "reverse") == 0) {
+               /* Search backward from @mark in @focus for a match, or
+                * until we hit @mark2.  Leave @mark at the start of the
+                * match.  Return length of match, or negative.
+                *
+                * rexel only lets us search forwards, and stepping back one
+                * char at a time to match the pattern is too slow.
+                * So we step back a steadily growing number of chars and search
+                * forward as far as the previous location.  Once we
+                * find any match, we check if there is a later one that
+                * still satisfies.
+                */
+               int step_size = 65536;
+               int maxlen;
+               int ret = -1;
+               struct mark *m, *start, *end, *endmark;
+               struct mark *m2 = ci->mark2;
+               struct pane *p = ci->focus;
+
+               if (!ci->mark)
+                       return Enoarg;
+               m = mark_dup(ci->mark); /* search cursor */
+               start = mark_dup(ci->mark); /* start of the range being searched */
+               end = mark_dup(ci->mark); /* end of the range being searched */
+
+               ss->end = end;
+               if (!ss->endmark)
+                       ss->endmark = ci->mark;
+               endmark = ss->endmark;
+               ss->anchor_at_end = True;
+
+               pane_set_time(p);
+
+               while (!m2 || m2->seq < start->seq) {
+                       mark_to_mark(end, start);
+                       call("doc:char", p, -step_size, start, NULL, 0, m2);
+                       if (mark_same(start, end))
+                               /* We have hit the start(m2), don't continue */
+                               break;
+                       step_size *= 2;
+                       ss->prev_ch = doc_prior(p, start);
+                       ss->st = rxl_prepare(ss->rxl, 0);
+                       ss->prev_point = ss->point ? mark_same(ss->point, m) : False;
+
+                       mark_to_mark(m, start);
+                       call_comm("doc:content", p, &ss->c, 0, m);
+                       rxl_info(ss->st, &maxlen, NULL, NULL, NULL);
+                       rxl_free_state(ss->st);
+                       if (maxlen >= 0) {
+                               /* found a match */
+                               ret = maxlen;
+                               break;
+                       }
+
+                       if (pane_too_long(p, 2000)) {
+                               /* FIXME returning success is wrong if
+                                * we timed out But I want to move the
+                                * point, and this is easiest.  What do
+                                * I really want here?  Do I just need
+                                * to make reverse search faster?
+                                */
+                               mark_to_mark(endmark, start);
+                               ret = 0;
+                               break;
+                       }
+               }
+               while (maxlen >= 0) {
+                       /* There is a match starting at 'endmark'.
+                        * The might be a later match - check for it.
+                        */
+                       call("doc:char", p, -maxlen, ss->endmark);
+                       if (mark_ordered_not_same(end, ss->endmark))
+                               break;
+                       ret = maxlen;
+                       if (endmark != ss->endmark &&
+                           mark_ordered_or_same(ss->endmark, endmark))
+                               /* Didn't move forward!!  Presumably
+                                * buggy doc:step implementation.
+                                */
+                               break;
+
+                       mark_to_mark(endmark, ss->endmark);
+                       ss->endmark = m;
+                       mark_to_mark(start, endmark);
+                       ss->prev_ch = doc_next(p, start);
+                       ss->st = rxl_prepare(ss->rxl, 0);
+                       call_comm("doc:content", p, &ss->c, 0, start);
+                       rxl_info(ss->st, &maxlen, NULL, NULL, NULL);
+                       rxl_free_state(ss->st);
+               }
+               mark_free(start);
+               mark_free(end);
+               mark_free(m);
+               return ret;
+       }
        return Efail;
 }
 
@@ -265,85 +360,24 @@ static int search_backward(struct pane *p safe,
         * rexel only lets us search forwards, and stepping back
         * one char at a time to match the pattern is too slow.
         * So we step back a steadily growing number of
-        * chars, and search forward as far as the previous location.
+        * chars, and search forward as pfar as the previous location.
         * Once we find any match, we check if there is a later one
         * that still satisfies.
         */
        struct search_state ss;
-       int step_size = 65536;
-       int maxlen;
-       int ret = -1;
-       struct mark *start = mark_dup(m); /* Start of the range to search */
-       struct mark *end = mark_dup(m);
 
-       ss.end = end;
+       if (m2 && m->seq <= m2->seq)
+               return -1;
+
+       ss.rxl = rxl;
+       ss.st = rxl_prepare(rxl, 0);
+       ss.prefix_len = rxl_prefix(rxl, ss.prefix, sizeof(ss.prefix));
+       ss.end = m2;
        ss.endmark = endmark;
        ss.point = point;
+       ss.prev_point = point ? mark_same(point, m) : False;
        ss.c = search_test;
-       ss.prefix_len = rxl_prefix(rxl, ss.prefix, sizeof(ss.prefix));
-       ss.anchor_at_end = True;
-
-       pane_set_time(p);
-
-       while (!m2 || m2->seq < start->seq) {
-               mark_to_mark(end, start);
-               call("doc:char", p, -step_size, start, NULL, 0, m2);
-               if (mark_same(start, end))
-                       /* We have hit the start, don't continue */
-                       break;
-               step_size *= 2;
-               ss.prev_ch = doc_prior(p, start);
-               ss.st = rxl_prepare(rxl, 0);
-               ss.prev_point = point ? mark_same(point, m) : False;
-
-               mark_to_mark(m, start);
-               call_comm("doc:content", p, &ss.c, 0, m);
-               rxl_info(ss.st, &maxlen, NULL, NULL, NULL);
-               rxl_free_state(ss.st);
-               if (maxlen >= 0) {
-                       /* found a match */
-                       ret = maxlen;
-                       break;
-               }
-
-               if (pane_too_long(p, 2000)) {
-                       /* FIXME returning success is wrong if we timed out
-                        * But I want to move the point, and this is easiest.
-                        * What do I really want here?
-                        * Do I just need to make reverse search faster?
-                        */
-                       mark_to_mark(endmark, start);
-                       ret = 0;
-                       break;
-               }
-       }
-       while (maxlen >= 0) {
-               /* There is a match starting at 'endmark'.
-                * The might be a later match - check for it.
-                */
-               call("doc:char", p, -maxlen, ss.endmark);
-               if (mark_ordered_not_same(end, ss.endmark))
-                       break;
-               ret = maxlen;
-               if (endmark != ss.endmark &&
-                   mark_ordered_or_same(ss.endmark, endmark))
-                       /* Didn't move forward!!  Presumably
-                        * buggy doc:step implementation.
-                        */
-                       break;
-
-               mark_to_mark(endmark, ss.endmark);
-               ss.endmark = m;
-               mark_to_mark(start, endmark);
-               ss.prev_ch = doc_next(p, start);
-               ss.st = rxl_prepare(rxl, 0);
-               call_comm("doc:content", p, &ss.c, 0, start);
-               rxl_info(ss.st, &maxlen, NULL, NULL, NULL);
-               rxl_free_state(ss.st);
-       }
-       mark_free(start);
-       mark_free(end);
-       return ret;
+       return comm_call(&ss.c, "reverse", p, 0, m, NULL, 0, m2);
 }
 
 DEF_CMD(text_search)