[balsa/74-quote-wrapped-lines] mime: Use Pango to find line-break positions



commit 5257155e19f710ffaccb8dc2c22f135ef7679232
Author: Peter Bloomfield <PeterBloomfield bellsouth net>
Date:   Wed Apr 13 16:49:19 2022 -0400

    mime: Use Pango to find line-break positions
    
    In libbalsa_wrap_quoted_string(), use PangoLogAttr to find possible
    places to break a long line, instead of literal space characters.
    
    This has the side effect of leaving trailing white space on the wrapped
    lines, which is included in the line length calculation. If the text is
    copy/pasted into a file, it can be unwrapped to something like the
    original. The trailing spaces could be trimmed, but would still be
    counted toward the line length, so it doesn't seem worthwhile.

 libbalsa/mime.c | 56 ++++++++++++++++++++++++++++++++------------------------
 1 file changed, 32 insertions(+), 24 deletions(-)
---
diff --git a/libbalsa/mime.c b/libbalsa/mime.c
index 8d6d5f353..3d39c4594 100644
--- a/libbalsa/mime.c
+++ b/libbalsa/mime.c
@@ -1316,6 +1316,7 @@ libbalsa_wrap_quoted_string(const char *str,
     char **lines;
     char **line;
     GString *wrapped;
+    PangoLogAttr *log_attrs = NULL;
 
     g_return_val_if_fail(str != NULL, NULL);
     g_return_val_if_fail(quote_regex != NULL, NULL);
@@ -1325,52 +1326,59 @@ libbalsa_wrap_quoted_string(const char *str,
 
     for (line = lines; *line != NULL; line++) {
         unsigned quote_len, quote_len_utf8;
-        const char *start_pos, *space_pos, *ptr;
+        const char *start_ptr, *break_ptr, *ptr;
         const unsigned minl = width / 2;
-        unsigned te = 0;    /* tabs' extra space */
-        unsigned ptr_offset, line_begin_offset, space_pos_offset;
+        unsigned ptr_offset, start_offset, break_offset;
+        int num_chars;
+        int attrs_len;
+        unsigned cursor;
+
+        num_chars = g_utf8_strlen(*line, -1);
+        attrs_len = num_chars + 1;
+        log_attrs = g_renew(PangoLogAttr, log_attrs, attrs_len);
+        pango_get_log_attrs(*line, -1, -1, pango_language_get_default(), log_attrs, attrs_len);
 
         libbalsa_match_regex(*line, quote_regex, NULL, &quote_len);
 
         g_string_append_len(wrapped, *line, quote_len);
         ptr = *line + quote_len;
 
-        quote_len_utf8 = g_utf8_pointer_to_offset(*line, ptr);
-        ptr_offset = quote_len_utf8;
+        ptr_offset = g_utf8_pointer_to_offset(*line, ptr);
+        cursor = quote_len_utf8 = ptr_offset;
 
-        line_begin_offset = space_pos_offset = 0;
-        start_pos = space_pos = ptr;
+        start_ptr = break_ptr = ptr;
+        start_offset = break_offset = ptr_offset;
 
         while (*ptr != '\0') {
-            switch (*ptr) {
-            case '\t':
-                te += 7;
-                break;
-            case ' ':
-                space_pos = ptr;
-                space_pos_offset = ptr_offset;
-                break;
+            gunichar c = g_utf8_get_char(ptr);
+
+            if (c == '\t')
+                cursor = ((cursor + 8) / 8) * 8;
+            else
+                cursor++;
+
+            if (log_attrs[ptr_offset].is_line_break) {
+                break_ptr = ptr;
+                break_offset = ptr_offset;
             }
 
-            if (ptr_offset - line_begin_offset >= width - te &&
-                space_pos_offset >= line_begin_offset + minl) {
-                g_string_append_len(wrapped, start_pos, space_pos - start_pos);
+            if (cursor >= width && break_offset >= start_offset + minl) {
+                g_string_append_len(wrapped, start_ptr, break_ptr - start_ptr);
                 g_string_append_c(wrapped, '\n');
-
                 g_string_append_len(wrapped, *line, quote_len);
-                ptr_offset += quote_len_utf8;
 
-                start_pos = space_pos + 1;
-                line_begin_offset = space_pos_offset + 1;
-                te = 0;
+                start_ptr = break_ptr;
+                start_offset = break_offset;
+                cursor = quote_len_utf8 + ptr_offset - start_offset;
             }
             ptr = g_utf8_next_char(ptr);
             ptr_offset++;
         }
-        g_string_append(wrapped, start_pos);
+        g_string_append(wrapped, start_ptr);
         g_string_append_c(wrapped, '\n');
     }
 
+    g_free(log_attrs);
     g_strfreev(lines);
 
     return (char *) g_string_free(wrapped, FALSE);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]