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>
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.
- [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
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
### 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
### 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
### 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
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);
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;
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);
}
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)
* 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>
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;
}
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");
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");
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;
}
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;
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);
}
lib-linecount =
Countlines
CountLinesAsync
+ attach-line-count
lib-search =
text-search
text-match
char *attr_cache;
void *cache_pos;
int cache_field;
- bool no_linecount;
};
static inline short FIELD_NUM(int i) { return i >> 16; }
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)
{
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);
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)