From df7552a346d5c7926308c319a3a299fac4735e35 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Fri, 18 Aug 2023 17:09:20 +1000 Subject: [PATCH] render-line:measure now reports if the line ended properly If the last line in a document doesn't end with a newline character, we need to handle that interesting case. Make it easier to do so. Signed-off-by: NeilBrown --- DOC/TODO.md | 2 +- lib-renderline.c | 37 ++++++++++++++++++++++++------------- render-lines.c | 20 +++++++++++--------- 3 files changed, 36 insertions(+), 23 deletions(-) diff --git a/DOC/TODO.md b/DOC/TODO.md index df9b5a36..128dbf71 100644 --- a/DOC/TODO.md +++ b/DOC/TODO.md @@ -27,7 +27,7 @@ the file. - [ ] When is left_margin used? Can I use it for hanging indent? If not, how do I do that? Can I tab out, set margin, tab back for text? Am I using points properly? -- [ ] find a better way to handle "case when EOF is at the end" of +- [X] find a better way to handle "case when EOF is at the end" of a non-empty line. - [ ] as renderline changes result if cursor is present, cursor pos must ALWAYS be given. diff --git a/lib-renderline.c b/lib-renderline.c index c8f63924..7dad2bdb 100644 --- a/lib-renderline.c +++ b/lib-renderline.c @@ -584,7 +584,7 @@ static int calc_tab(int num, int margin, int scale) return margin + num * scale / 1000; } -static bool measure_line(struct pane *p safe, struct pane *focus safe, int offset) +static int measure_line(struct pane *p safe, struct pane *focus safe, int offset) { /* First measure each render_item entry setting * height, ascent, width. @@ -592,6 +592,11 @@ static bool measure_line(struct pane *p safe, struct pane *focus safe, int offse * each unit. * Finally identify line-break locations if needed and set 'y' * positions + * + * Return 1 if there is an EOL ('\n') + * 2 if there is an end-of-page ('\f') + * 3 if both. + * 0 if neither */ struct rline_data *rd = &p->data; struct render_item *ri, *wraprl; @@ -604,20 +609,23 @@ static bool measure_line(struct pane *p safe, struct pane *focus safe, int offse int xdiff, ydiff; struct call_return cr; int x, y; - bool eop = False; + int ret = 0; bool seen_rtab = False; if (!rd->content) - return eop; + return ret; if (xyscale.x == rd->scale && p->w == rd->measure_width && shift_left == rd->measure_shift_left && offset == rd->measure_offset) { /* No change */ - for (ri = rd->content ; ri ; ri = ri->next) + for (ri = rd->content ; ri ; ri = ri->next) { + if (ri->eol && rd->line[ri->start] == '\n') + ret |= 1; if (ri->eol && rd->line[ri->start] == '\f') - eop = True; + ret |= 2; + } pane_resize(p, p->x, p->y, p->w, rd->measure_height); - return eop; + return ret; } rd->scale = xyscale.x; rd->measure_width = p->w; @@ -650,8 +658,10 @@ static bool measure_line(struct pane *p safe, struct pane *focus safe, int offse /* Ensure attributes of newline add to line * height. The width will be ignored. */ strcpy(tmp, "M"); + if (rd->line[ri->start] == '\n') + ret |= 1; if (rd->line[ri->start] == '\f') - eop = True; + ret |= 2; } else if (rd->line[ri->start] == '\t') { strcpy(tmp, " "); } else { @@ -863,7 +873,7 @@ static bool measure_line(struct pane *p safe, struct pane *focus safe, int offse ydiff + rd->line_height; pane_resize(p, p->x, p->y, p->w, rd->measure_height); attr_set_int(&p->attrs, "line-height", rd->line_height); - return eop; + return ret; } static void draw_line(struct pane *p safe, struct pane *focus safe, int offset) @@ -1221,13 +1231,14 @@ DEF_CMD(renderline_refresh) DEF_CMD(renderline_measure) { struct rline_data *rd = &ci->home->data; - bool end_of_page; + int ret; + if (rd->image) return render_image(ci->home, ci->focus, rd->line, False, ci->num, False, 0, 0); - end_of_page = measure_line(ci->home, ci->focus, - ci->num < 0 ? -1 : rd->prefix_bytes + ci->num); + ret = measure_line(ci->home, ci->focus, + ci->num < 0 ? -1 : rd->prefix_bytes + ci->num); rd->prefix_pixels = 0; if (rd->prefix_bytes) { struct xy xy = find_curs(ci->home, rd->prefix_bytes, NULL); @@ -1238,12 +1249,12 @@ DEF_CMD(renderline_measure) const char *cursattr = NULL; struct xy xy; xy = find_curs(ci->home, rd->prefix_bytes + ci->num, &cursattr); - comm_call(ci->comm2, "cb", ci->focus, end_of_page, NULL, + comm_call(ci->comm2, "cb", ci->focus, ret, NULL, cursattr); ci->home->cx = xy.x; ci->home->cy = xy.y; } - return end_of_page ? 2 : 1; + return ret | 4; } DEF_CMD(renderline_findxy) diff --git a/render-lines.c b/render-lines.c index bf136195..3d485991 100644 --- a/render-lines.c +++ b/render-lines.c @@ -166,7 +166,7 @@ static bool vmark_is_valid(struct mark *m safe) } /* Returns 'true' at end-of-page */ -static bool _measure_line(struct pane *p safe, struct pane *focus safe, +static int _measure_line(struct pane *p safe, struct pane *focus safe, struct mark *mk safe, short cursor_offset, char **cursor_attr) { @@ -181,20 +181,20 @@ static bool _measure_line(struct pane *p safe, struct pane *focus safe, if (cursor_attr) *cursor_attr = cr.s; /* end-of-page flag */ - return cr.ret == 2; + return cr.ret & 3; } #define measure_line(...) VFUNC(measure_line, __VA_ARGS__) -static inline bool measure_line3(struct pane *p safe, struct pane *focus safe, +static inline int measure_line3(struct pane *p safe, struct pane *focus safe, struct mark *mk safe) { return _measure_line(p, focus, mk, -1, NULL); } -static inline bool measure_line4(struct pane *p safe, struct pane *focus safe, +static inline int measure_line4(struct pane *p safe, struct pane *focus safe, struct mark *mk safe, short cursor_offset) { return _measure_line(p, focus, mk, cursor_offset, NULL); } -static inline bool measure_line5(struct pane *p safe, struct pane *focus safe, +static inline int measure_line5(struct pane *p safe, struct pane *focus safe, struct mark *mk safe, short cursor_offset, char **cursor_attr) { @@ -648,7 +648,7 @@ static void find_lines(struct mark *pm safe, struct pane *p safe, if (start->mdata) { struct pane *hp = start->mdata; int curs_width; - found_end = measure_line(p, focus, start, offset); + found_end = measure_line(p, focus, start, offset) & 2; curs_width = pane_attr_get_int( start->mdata, "curs_width", 1); @@ -1115,10 +1115,12 @@ static int revalidate_start(struct rl_data *rl safe, start_of_file = doc_prior(focus, start) == WEOF; for (m = start; m && !found_end && y < p->h; m = vmark_next(m)) { struct pane *hp; + int found; if (refresh_all) vmark_invalidate(m); call_render_line(p, focus, m, NULL); - found_end = measure_line(p, focus, m); + found = measure_line(p, focus, m); + found_end = found & 2; hp = m->mdata; if (!mark_valid(m) || !hp) break; @@ -1132,12 +1134,12 @@ static int revalidate_start(struct rl_data *rl safe, } y += hp->h; m2 = vmark_next(m); - /* The doc_prior handles case when EOF is at the end + /* The "found & 1" handles case when EOF is at the end * of a non-empty line. */ if (pm && m2 && mark_ordered_or_same(m, pm) && (mark_ordered_not_same(pm, m2) || - (mark_same(pm, m2) && !is_eol(doc_prior(focus,m2))))) { + (mark_same(pm, m2) && !(found & 1)))) { /* Cursor is on this line */ int offset = call_render_line_to_point(focus, -- 2.39.5