aboutsummaryrefslogtreecommitdiff
path: root/text-util.c
diff options
context:
space:
mode:
authorMarc André Tanner <mat@brain-dump.org>2016-05-24 21:39:58 +0200
committerMarc André Tanner <mat@brain-dump.org>2016-05-24 21:39:58 +0200
commit3cea78b00dcebe76da9a69d58c33c8b2a58d41ed (patch)
treec23f89a8eafe1b7547ebdf57c6b01701d709b0bc /text-util.c
parent9bcfd3f83098dcd4246b95fc37d523e06129ed12 (diff)
downloadvis-3cea78b00dcebe76da9a69d58c33c8b2a58d41ed.tar.gz
vis-3cea78b00dcebe76da9a69d58c33c8b2a58d41ed.tar.xz
Add utility function to calculate display width of a string
This is based on the implementation of text_line_width_get from text-motions.c. There might be an opportunity for code sharing.
Diffstat (limited to 'text-util.c')
-rw-r--r--text-util.c38
1 files changed, 38 insertions, 0 deletions
diff --git a/text-util.c b/text-util.c
index 6794a78..c7a1349 100644
--- a/text-util.c
+++ b/text-util.c
@@ -2,6 +2,7 @@
#include "util.h"
#include <wchar.h>
#include <errno.h>
+#include <stdlib.h>
bool text_range_valid(const Filerange *r) {
return r->start != EPOS && r->end != EPOS && r->start <= r->end;
@@ -75,3 +76,40 @@ int text_char_count(const char *data, size_t len) {
}
return count;
}
+
+int text_string_width(const char *data, size_t len) {
+
+ int width = 0;
+ mbstate_t ps = { 0 };
+ const char *s = data;
+
+ while (len > 0) {
+ char buf[MB_CUR_MAX];
+ wchar_t wc;
+ size_t wclen = mbrtowc(&wc, s, len, &ps);
+ if (wclen == (size_t)-1 && errno == EILSEQ) {
+ /* assume a replacement symbol will be displayed */
+ width++;
+ wclen = 1;
+ } else if (wclen == (size_t)-2) {
+ /* do nothing, advance to next character */
+ wclen = 1;
+ } else if (wclen == 0) {
+ /* assume NUL byte will be displayed as ^@ */
+ width += 2;
+ wclen = 1;
+ } else if (buf[0] == '\t') {
+ width++;
+ wclen = 1;
+ } else {
+ int w = wcwidth(wc);
+ if (w == -1)
+ w = 2; /* assume non-printable will be displayed as ^{char} */
+ width += w;
+ }
+ len -= wclen;
+ s += wclen;
+ }
+
+ return width;
+}