diff --git a/src/chars.c b/src/chars.c index d7343d92..5ff07386 100644 --- a/src/chars.c +++ b/src/chars.c @@ -332,6 +332,35 @@ int parse_mbchar(const char *buf, char *chr, size_t *col) return length; } +/* Return the length (in bytes) of the character at the start of + * the given string, and add this character's width to *column. */ +int advance_over(const char *string, size_t *column) +{ + int charlen; + +#ifdef ENABLE_UTF8 + if ((signed char)*string < 0) { + charlen = mblen(string, MAXCHARLEN); + if (charlen <= 0) + charlen = 1; + } else +#endif + charlen = 1; + + if (*string == '\t') + *column += tabsize - *column % tabsize; + else if (is_cntrl_mbchar(string)) + *column += 2; + else if (charlen == 1) + *column += 1; +#ifdef ENABLE_UTF8 + else + *column += mbwidth(string); +#endif + + return charlen; +} + /* Return the index in buf of the beginning of the multibyte character * before the one at pos. */ size_t step_left(const char *buf, size_t pos) diff --git a/src/proto.h b/src/proto.h index 0028e498..5e6aa345 100644 --- a/src/proto.h +++ b/src/proto.h @@ -217,6 +217,7 @@ char *make_mbchar(long chr, int *chr_mb_len); int char_length(const char *pointer); size_t mbstrlen(const char *s); int parse_mbchar(const char *buf, char *chr, size_t *col); +int advance_over(const char *string, size_t *column); size_t step_left(const char *buf, size_t pos); size_t step_right(const char *buf, size_t pos); int mbstrcasecmp(const char *s1, const char *s2); diff --git a/src/text.c b/src/text.c index ef4ef875..499597c3 100644 --- a/src/text.c +++ b/src/text.c @@ -1579,7 +1579,7 @@ ssize_t break_line(const char *line, ssize_t goal, bool snap_at_nl) break; } - charlen = parse_mbchar(line, NULL, &column); + charlen = advance_over(line, &column); line += charlen; index += charlen; } diff --git a/src/utils.c b/src/utils.c index cd3c7d06..d1f80eb8 100644 --- a/src/utils.c +++ b/src/utils.c @@ -379,7 +379,7 @@ size_t actual_x(const char *text, size_t column) /* The current accumulated span, in columns. */ while (*text != '\0') { - int charlen = parse_mbchar(text, NULL, &width); + int charlen = advance_over(text, &width); if (width > column) break; @@ -400,7 +400,7 @@ size_t wideness(const char *text, size_t maxlen) return 0; while (*text != '\0') { - size_t charlen = parse_mbchar(text, NULL, &width); + size_t charlen = advance_over(text, &width); if (maxlen <= charlen) break; @@ -418,7 +418,7 @@ size_t breadth(const char *text) size_t span = 0; while (*text != '\0') - text += parse_mbchar(text, NULL, &span); + text += advance_over(text, &span); return span; } diff --git a/src/winio.c b/src/winio.c index 82d09df0..f315f64b 100644 --- a/src/winio.c +++ b/src/winio.c @@ -3045,7 +3045,7 @@ size_t get_softwrap_breakpoint(const char *text, size_t leftedge, /* First find the place in text where the current chunk starts. */ while (*text != '\0' && column < leftedge) - text += parse_mbchar(text, NULL, &column); + text += advance_over(text, &column); /* Now find the place in text where this chunk should end. */ while (*text != '\0' && column <= goal_column) { @@ -3056,7 +3056,7 @@ size_t get_softwrap_breakpoint(const char *text, size_t leftedge, } breaking_col = (*text == '\t' ? goal_column : column); - text += parse_mbchar(text, NULL, &column); + text += advance_over(text, &column); } /* If we didn't overshoot the limit, we've found a breaking point; @@ -3069,7 +3069,7 @@ size_t get_softwrap_breakpoint(const char *text, size_t leftedge, /* If we're softwrapping at blanks and we found at least one blank, break * after that blank -- if it doesn't overshoot the screen's edge. */ if (farthest_blank != NULL) { - parse_mbchar(farthest_blank, NULL, &last_blank_col); + advance_over(farthest_blank, &last_blank_col); if (last_blank_col <= goal_column) return last_blank_col;