]> git.neil.brown.name Git - edlib.git/commitdiff
linecount: allow attachment to a viewer stack.
authorNeilBrown <neil@brown.name>
Sun, 2 Jul 2023 11:42:57 +0000 (21:42 +1000)
committerNeilBrown <neil@brown.name>
Wed, 12 Jul 2023 22:17:52 +0000 (08:17 +1000)
Sometimes we want linecount to count lines in a view, not in a document.

Instead of having the view pretend to be a document for linecount,
change it to explicitly support attachment.

Signed-off-by: NeilBrown <neil@brown.name>
DOC/TODO.md
doc-email.c
lib-linecount.c
modules.ini
render-format.c

index 7603af241a70245f515abb1ecf6f62918e71c43b..cb0572d71010a935db3333cbd9a75651ac78f315 100644 (file)
@@ -27,7 +27,7 @@ the file.
       off top of screen
 - [X] emacs: :C-q to recognise names of Unicode chars: e.g. WASTEBASKET
        Possibly matches a list which continued :C-q cycles through
-- [ ] linecount 'view' mode improvements
+- [X] linecount 'view' mode improvements
 - [ ] allocate pane->data together with pane.  A single allocation so
       that we can avoid the cost of a dereference.
 
@@ -35,7 +35,7 @@ the file.
 
 - [X] lib-mergeview improvements
 - [X] lib-diff slowness with large diff
-- [ ] linecount :when used in 'view' mode, stack the counting pane with all the
+- [X] linecount :when used in 'view' mode, stack the counting pane with all the
       others so it can easily catch view-changed.
 - [X] C config module that reads an ini-style file to set attributes
       based on path
@@ -73,6 +73,10 @@ Requirements for a v1.0 release
 Core features
 -------------
 
+- [ ] Add optional unit-test interface for modules.  This should be
+      implemented at least by lib-search, doc-text and probably
+      many others.  It is particularly for things that are awkward
+      to test with the ncurses/replay test approach.
 - [ ] Send global notify before/after refresh.  LOG must suspend
       logging (or notifications at least) during refresh if is visible
       anywhere
@@ -172,10 +176,13 @@ Module features
 
 ### lib-linecount
 
-- [ ] when used in 'view' mode, stack the counting pane with all the
+- [X] when used in 'view' mode, stack the counting pane with all the
       others so it can easily catch view-changed.  In general, make it
       easier to use this way.  e.g. easier than catching
       doc:request:doc:CountLines.
+- [ ] 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.
 
 ### lib-server
 
@@ -194,6 +201,9 @@ Module features
 
 ### lib-textfill
 
+- [ ] auto-wrap on a line like this one doesn't recognize all the
+  punctuation a the start of the line ... should it?
+
 
 ### render-format
 
@@ -277,6 +287,8 @@ Module features
 
 ### emacs
 
+- [ ] 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.
 - [X] Num-C-l doesn't work if it would require part of a wrapped line
       off top of screen
 - [X] :C-q to recognise names of Unicode chars: e.g. WASTEBASKET
index 30b9abed369c02ef4db02c50f90aadc185290066..14ce11067bb8b895d2ff200729d7a08e7d488945 100644 (file)
@@ -1171,8 +1171,6 @@ DEF_CMD(email_view_set_attr)
                          1, m2);
                call("view:changed", ci->focus, 0, m1, NULL, 0, m2);
                call("Notify:clip", ci->focus, 0, m1, NULL, 0, m2);
-               /* for CountLines */
-               pane_notify("doc:replaced", ci->home, 0, m1, NULL, 0, m2);
                mark_free(m1);
                mark_free(m2);
 
@@ -1192,45 +1190,9 @@ DEF_CMD(email_view_set_attr)
        return Efallthrough;
 }
 
-DEF_CMD(email_request)
-{
-       /* Someone wants to count lines - attach the line count here,
-        * rather than let it fall through to document.
-        */
-       pane_add_notify(ci->focus, ci->home, ksuffix(ci, "doc:request:"));
-       if (strcmp(ci->key, "doc:request:doc:replaced") == 0)
-               /* Though for doc:replaced, we want the doc to respond too */
-               return Efallthrough;
-       return 1;
-}
-
-DEF_CMD(email_countlines)
-{
-       return pane_notify(ksuffix(ci, "doc:notify:"),
-                          ci->home,
-                          ci->num, ci->mark, ci->str,
-                          ci->num2, ci->mark2, ci->str2, ci->comm2);
-}
-
-DEF_CMD(status_changed)
-{
-       /* line-count sent a status-change message */
-       call("doc:status-changed", ci->focus->parent);
-       return 1;
-}
-
-DEF_CMD(doc_replaced)
-{
-       /* doc sent a doc;replaced message */
-       pane_notify("doc:replaced", ci->home,
-                   ci->num, ci->mark, ci->str,
-                   ci->num2, ci->mark2, ci->str2, ci->comm2);
-       return 1;
-}
-
 DEF_CMD(attach_email_view)
 {
-       struct pane *p;
+       struct pane *p, *p2;
        struct email_view *evi;
        struct mark *m;
        int n, i;
@@ -1263,9 +1225,9 @@ DEF_CMD(attach_email_view)
                free(evi);
                return Efail;
        }
-       /* get doc:replaced from the email so I can pass it to linecount */
-       home_call(ci->focus, "doc:request:doc:replaced", p);
-       pane_add_notify(p, p, "doc:status-changed");
+       p2 = call_ret(pane, "attach-line-count", p);
+       if (p2)
+               p = p2;
        attr_set_str(&p->attrs, "render-hide-CR", "yes");
        return comm_call(ci->comm2, "callback:attach", p);
 }
@@ -1287,11 +1249,6 @@ static void email_init_map(void)
        key_add(email_view_map, "email:select:hide", &email_select_hide);
        key_add(email_view_map, "email:select:full", &email_select_full);
        key_add(email_view_map, "email:select:extras", &email_select_extras);
-       key_add(email_view_map, "doc:request:doc:CountLines", &email_request);
-       key_add(email_view_map, "doc:request:doc:replaced", &email_request);
-       key_add(email_view_map, "doc:notify:doc:CountLines", &email_countlines);
-       key_add(email_view_map, "doc:status-changed", &status_changed);
-       key_add(email_view_map, "doc:replaced", &doc_replaced);
 }
 
 void edlib_init(struct pane *ed safe)
index 07a7f9e77a55f1ed39097e843c967ff6fd2ff3d9..9913526896ff4e43a90a7d905a94954b7b9e0c24 100644 (file)
  * When it is called on a mark in the pane, attributes are set on the
  * mark to indicate the line, work and char where the mark is.
  * These are always at least 1.
+ *
+ * Alternately, the pane can be attaching in the view stack so that it
+ * applies to the view rather than the document.  This is useful when
+ * There are views imposed that dramatically alter the number of
+ * lines/words, or that hide parts of the document that really shouldn't
+ * be counted.  The view on an RFC2822 email or the results of a notmuch
+ * search are good and current examples.
  */
 
 #include <unistd.h>
@@ -160,7 +167,7 @@ static void do_count(struct pane *p safe, struct pane *owner safe,
 
 DEF_CMD(linecount_restart)
 {
-       pane_call(ci->home, "doc:CountLines", ci->focus, 1);
+       pane_call(ci->home, "CountLinesAsync", pane_leaf(ci->focus), 1);
        return Efalse;
 }
 
@@ -308,6 +315,10 @@ DEF_CMD(linecount_notify_replace)
        struct count_info *cli = ci->home->data;
        struct mark *m, *m2;
 
+       if (ci->mark && !ci->mark2)
+               /* I might not care about this one... */
+               return Efallthrough;
+
        attr_del(&d->attrs, "lines");
        attr_del(&d->attrs, "words");
        attr_del(&d->attrs, "chars");
@@ -317,7 +328,7 @@ DEF_CMD(linecount_notify_replace)
        else
                m = vmark_first(d, cli->view_num, ci->home);
        if (!m)
-               return 1;
+               return Efallthrough;
 
        attr_del(mark_attr(m), "lines");
        attr_del(mark_attr(m), "words");
@@ -328,17 +339,39 @@ DEF_CMD(linecount_notify_replace)
                mark_free(m2);
 
        call_comm("event:free", ci->home, &linecount_restart);
-       return 1;
+       return Efallthrough;
 }
 
 DEF_CMD(linecount_notify_count)
 {
        struct pane *d = ci->focus;
        struct count_info *cli = ci->home->data;
-       /* Option mark is "mark2" as "mark" gets the "point" */
+       /* Option mark is "mark2" as "mark" gets the "point" so is never NULL */
        /* num==1 means we don't want to wait for precision */
+       bool sync = ci->mark2 && ci->num != 1;
+
+       if (strcmp(ci->key, "CountLinesAsync") == 0)
+               sync = False;
        count_calculate(d, ci->mark2, ci->home, cli->view_num,
-                       ci->mark2 && ci->num != 1);
+                       sync);
+       return 1;
+}
+
+DEF_CMD(linecount_view_count)
+{
+       struct pane *d = ci->focus;
+       struct count_info *cli = ci->home->data;
+       bool sync = strcmp(ci->key, "CountLines") == 0;
+
+       if (strcmp(ci->key, "CountLinesAsync") == 0)
+               sync = False;
+
+       if (ci->mark && ci->str && strcmp(ci->str, "goto:line") == 0 &&
+           ci->num != NO_NUMERIC) {
+               pane_call(ci->home, "doc:GotoLine", d, ci->num, ci->mark);
+       }
+       count_calculate(d, ci->mark, ci->home, cli->view_num,
+                       sync);
        return 1;
 }
 
@@ -416,10 +449,40 @@ DEF_CMD(count_lines)
        return 1;
 }
 
+DEF_CMD(linecount_attach)
+{
+       struct count_info *cli;
+       struct pane *p;
+
+       alloc(cli, pane);
+       p = pane_register(ci->focus, 0,
+                         &handle_count_lines.c, cli);
+       if (!p)
+               return Efail;
+       cli->view_num = home_call(p, "doc:add-view", p) - 1;
+       call("doc:request:doc:replaced", p);
+       call("doc:request:Notify:Close", p);
+       call_comm("event:on-idle", p, &linecount_restart, 1);
+
+       comm_call(ci->comm2, "cb", p);
+       return 1;
+}
+
+DEF_CMD(linecount_clone)
+{
+       struct pane *p;
+
+       p = comm_call_ret(pane, &linecount_attach, "attach", ci->focus);
+       pane_clone_children(ci->home, p);
+       return 1;
+}
+
 void edlib_init(struct pane *ed safe)
 {
        call_comm("global-set-command", ed, &count_lines, 0, NULL, "CountLines");
        call_comm("global-set-command", ed, &count_lines, 0, NULL, "CountLinesAsync");
+       call_comm("global-set-command", ed, &linecount_attach, 0, NULL,
+                 "attach-line-count");
 
        if (linecount_map)
                return;
@@ -430,4 +493,10 @@ void edlib_init(struct pane *ed safe)
        key_add(linecount_map, "doc:CountLines", &linecount_notify_count);
        key_add(linecount_map, "doc:GotoLine", &linecount_notify_goto);
        key_add(linecount_map, "Free", &edlib_do_free);
+
+       /* For view-attached version */
+       key_add(linecount_map, "CountLines", &linecount_view_count);
+       key_add(linecount_map, "CountLinesAsync", &linecount_view_count);
+       //key_add(linecount_map, "view:changed", &linecount_notify_replace);
+       key_add(linecount_map, "Clone", &linecount_clone);
 }
index bf41b5174790b485b218165d334b1b0c5db4b936..eee2beca92e54dec21e91b9835a8305f5b31f8db 100644 (file)
@@ -8,6 +8,7 @@ lib-popup = PopupTile
 lib-linecount =
        Countlines
        CountLinesAsync
+       attach-line-count
 lib-search =
        text-search
        text-match
index f445844d639d6bee54af95bcbe4f12a8aa9f8c5f..c2028af97041e142133097ebb53ad8fafce1cd0f 100644 (file)
@@ -38,7 +38,6 @@ struct rf_data {
        char *attr_cache;
        void *cache_pos;
        int cache_field;
-       bool no_linecount;
 };
 
 static inline short FIELD_NUM(int i) { return i >> 16; }
@@ -930,46 +929,6 @@ DEF_CMD(render_line_prev2)
        return 1;
 }
 
-DEF_CMD(format_request)
-{
-       /* Someone wants to count lines - attach the line count here,
-        * rather than let it fall through to document.
-        */
-       struct rf_data *rd = ci->home->data;
-
-       if (rd->no_linecount)
-               return Efallthrough;
-       pane_add_notify(ci->focus, ci->home, ksuffix(ci, "doc:request:"));
-       if (strcmp(ci->key, "doc:request:doc:replaced") == 0)
-               /* Though for doc:replaced, we want the doc to respond too */
-               return Efallthrough;
-       return 1;
-}
-
-DEF_CMD(format_countlines)
-{
-       return pane_notify(ksuffix(ci, "doc:notify:"),
-                          ci->home,
-                          ci->num, ci->mark, ci->str,
-                          ci->num2, ci->mark2, ci->str2, ci->comm2);
-}
-
-DEF_CMD(status_changed)
-{
-       /* line-count sent a status-change message */
-       call("doc:status-changed", ci->focus->parent);
-       return 1;
-}
-
-DEF_CMD(doc_replaced)
-{
-       /* doc sent a doc;replaced message */
-       pane_notify("doc:replaced", ci->home,
-                   ci->num, ci->mark, ci->str,
-                   ci->num2, ci->mark2, ci->str2, ci->comm2);
-       return 1;
-}
-
 static struct pane *do_render_format_attach(struct pane *parent safe);
 DEF_CMD(format_clone)
 {
@@ -1006,11 +965,6 @@ static void render_format_register_map(void)
        key_add(rf2_map, "doc:content", &format_content2);
        key_add(rf2_map, "Free", &format_free);
        key_add(rf2_map, "doc:shares-ref", &format_noshare_ref);
-       key_add(rf2_map, "doc:request:doc:CountLines", &format_request);
-       key_add(rf2_map, "doc:request:doc:replaced", &format_request);
-       key_add(rf2_map, "doc:notify:doc:CountLines", &format_countlines);
-       key_add(rf2_map, "doc:status-changed", &status_changed);
-       key_add(rf2_map, "doc:replaced", &doc_replaced);
 }
 
 DEF_LOOKUP_CMD(render_format_handle, rf_map);
@@ -1031,12 +985,11 @@ static struct pane *do_render_format_attach(struct pane *parent safe)
                        render_format_register_map();
 
                alloc(rf, pane);
-               if (pane_attr_get(parent, "format:no-linecount"))
-                       rf->no_linecount = True;
                p = pane_register(parent, 0, &render_format2_handle.c, rf);
-               if (p) {
-                       pane_add_notify(p, p, "doc:status-changed");
-                       home_call(parent, "doc:request:doc:replaced", p);
+               if (p && !pane_attr_get(parent, "format:no-linecount")) {
+                       struct pane *p2 = call_ret(pane, "attach-line-count", p);
+                       if (p2)
+                               p = p2;
                }
        }
        if (!p)