]> git.neil.brown.name Git - edlib.git/commitdiff
linecount: enable async line-counts
authorNeilBrown <neil@brown.name>
Sat, 3 Jun 2023 02:38:03 +0000 (12:38 +1000)
committerNeilBrown <neil@brown.name>
Wed, 28 Jun 2023 05:40:21 +0000 (15:40 +1000)
When requested, linecounts progress about 300 lines at a time with only
the first 1000 done sync.  The rest happen on a timer.

Don't test the async line count though - it is too hard to match the timing.

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

index 86e3c685084a13b0cae220c8605d66287f0358d2..91a0732e9a73d6a501cb94640fb499e0b1ddf800 100644 (file)
@@ -24,7 +24,7 @@ the file.
 
 ### Medium
 
-- [ ] Always do word-count async.
+- [X] Always do word-count async.
 - [ ] lib-url
 - [ ] lib-mergeview improvements
 - [ ] lib-diff slowness with large diff
@@ -405,7 +405,10 @@ Module features
 ### line count
 
 - [X] count-lines seems to go very slowly in base64/utf-8 email
-- [ ] Always do word-count async.
+- [X] Always do word-count async.
+- [ ] Find a way to locate mark faster than walking the whole list
+      adding up the interval counts.  Maybe a version number and
+      async update.
 
 ### lib-utf-8
 
index 86a2a0585853eabda99bdb00941b621969bad0fa..da0baff87e92088d1274fda4f5aac7a15b6e94ff 100644 (file)
@@ -869,7 +869,7 @@ void mark_step(struct mark *m safe, int forward)
 void mark_step_sharesref(struct mark *m safe, int forward)
 {
        /* step mark forward, or backward, over all marks with same
-        * ref, ignoring the .i, and sets '.' to a safe value wrt the
+        * ref, ignoring the .i, and sets '.i' to a safe value wrt the
         * last mark stepped over.
         */
        struct mark *m2, *target = m;
index 99bc212acaf7d7ffb818239e5821efe2c7e9145f..9052479afa25dbdeb40120d9b37bd70525e81a1b 100644 (file)
@@ -38,6 +38,8 @@
 static struct map *linecount_map;
 DEF_LOOKUP_CMD(handle_count_lines, linecount_map);
 
+static bool testing = False;
+
 struct count_info {
        int view_num;
 };
@@ -83,6 +85,9 @@ static void do_count(struct pane *p safe, struct mark *start safe, struct mark *
                        *wordp += words;
                        *charp += chars;
                        lines = words = chars = 0;
+                       add_marks -= 1;
+                       if (!add_marks)
+                               return;
                        m = mark_dup_view(m);
                }
        }
@@ -97,6 +102,12 @@ static void do_count(struct pane *p safe, struct mark *start safe, struct mark *
        mark_free(m);
 }
 
+DEF_CMD(linecount_restart)
+{
+       pane_notify("doc:CountLines", ci->focus, 1);
+       return Efalse;
+}
+
 static int need_recalc(struct pane *p safe, struct mark *m)
 {
        struct mark *next;
@@ -112,6 +123,9 @@ static int need_recalc(struct pane *p safe, struct mark *m)
                mark_free(next);
                ret = 1;
        }
+       if (ret)
+               /* The background task needs to be stopped */
+               call_comm("event:free", p, &linecount_restart);
        return ret;
 }
 
@@ -123,6 +137,9 @@ static void count_calculate(struct pane *p safe,
        int lines, words, chars, l, w, c;
        struct mark *m, *m2;
 
+       if (testing)
+               sync = True;
+
        if (!end && attr_find(p->attrs, "lines"))
                /* nothing to do */
                return;
@@ -134,13 +151,21 @@ static void count_calculate(struct pane *p safe,
                if (!m)
                        return;
                call("doc:set-ref", p, 1, m);
-               do_count(p, m, NULL, &l, &w, &c, 1);
+               do_count(p, m, NULL, &l, &w, &c, sync ? -1 : 3);
+               if (!sync) {
+                       call_comm("event:timer", p, &linecount_restart, 10, end);
+                       return;
+               }
        }
 
-       if (need_recalc(p, m))
+       if (need_recalc(p, m)) {
                /* need to update this one */
-               do_count(p, m, vmark_next(m), &l, &w, &c, 1);
-
+               do_count(p, m, vmark_next(m), &l, &w, &c, sync ? -1 : 3);
+               if (!sync) {
+                       call_comm("event:timer", p, &linecount_restart, 10, end);
+                       return;
+               }
+       }
        /* Add totals from m to before end. Then count to 'end'.
         */
        lines = words = chars = 0;
@@ -151,8 +176,13 @@ static void count_calculate(struct pane *p safe,
                words += attr_find_int(*mark_attr(m), "words");
                chars += attr_find_int(*mark_attr(m), "chars");
                m = m2;
-               if (need_recalc(p, m))
-                       do_count(p, m, vmark_next(m), &l, &w, &c, 1);
+               if (!need_recalc(p, m))
+                       continue;
+               do_count(p, m, vmark_next(m), &l, &w, &c, sync ? -1 : 3);
+               if (!sync) {
+                       call_comm("event:timer", p, &linecount_restart, 10, end);
+                       return;
+               }
        }
        /* m is the last mark before end */
        if (!end) {
@@ -175,6 +205,8 @@ static void count_calculate(struct pane *p safe,
                attr_set_int(&p->attrs, "lines", lines);
                attr_set_int(&p->attrs, "words", words);
                attr_set_int(&p->attrs, "chars", chars);
+               if (!testing)
+                       pane_notify("doc:status-changed", p);
        }
 }
 
@@ -183,6 +215,8 @@ DEF_CMD(linecount_close)
        struct pane *d = ci->focus;
        struct count_info *cli = ci->home->data;
        struct mark *m;
+
+       call_comm("event:free", d, &linecount_restart);
        while ((m = vmark_first(d, cli->view_num, ci->home)) != NULL)
                mark_free(m);
        home_call(d, "doc:del-view", ci->home, cli->view_num);
@@ -215,6 +249,7 @@ DEF_CMD(linecount_notify_replace)
               (!ci->mark2 || mark_ordered_or_same(m2, ci->mark2)))
                mark_free(m2);
 
+       call_comm("event:free", d, &linecount_restart);
        return 1;
 }
 
@@ -311,6 +346,9 @@ 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");
 
+       if (getenv("EDLIB_TESTING"))
+               testing = True;
+
        if (linecount_map)
                return;