less: experimental code to enable wrap/no-wrap
authorDenis Vlasenko <vda.linux@googlemail.com>
Fri, 24 Oct 2008 10:42:21 +0000 (10:42 -0000)
committerDenis Vlasenko <vda.linux@googlemail.com>
Fri, 24 Oct 2008 10:42:21 +0000 (10:42 -0000)
 and adapting to resized xterm windows. disabled for now.

miscutils/less.c

index 049814319cfc109786fa3b6e638aa5a3e3405b07..c66788007eb45c6223264731389c14f33c93decc 100644 (file)
@@ -28,6 +28,9 @@
 #include "xregex.h"
 #endif
 
+/* In progress */
+#define ENABLE_FEATURE_LESS_REWRAP 0
+
 /* FIXME: currently doesn't work right */
 #undef ENABLE_FEATURE_LESS_FLAGCS
 #define ENABLE_FEATURE_LESS_FLAGCS 0
@@ -81,6 +84,7 @@ enum {
        FLAG_TILDE = 1 << 4,
        FLAG_I = 1 << 5,
 /* hijack command line options variable for internal state vars */
+       LESS_STATE_NO_WRAP = 1 << 14,
        LESS_STATE_MATCH_BACKWARDS = 1 << 15,
 };
 
@@ -214,6 +218,88 @@ static void less_exit(int code)
        exit(code);
 }
 
+#if ENABLE_FEATURE_LESS_REWRAP
+static void re_wrap(void)
+{
+       int w = width;
+       int rem;
+       int src_idx;
+       int dst_idx;
+       int new_cur_fline = 0;
+       uint32_t lineno;
+       char linebuf[w + 1];
+       const char **old_flines = flines;
+       const char *s;
+       char **new_flines = NULL;
+       char *d;
+
+       if (option_mask32 & FLAG_N)
+               w -= 8;
+
+       src_idx = 0;
+       dst_idx = 0;
+       s = old_flines[0];
+       lineno = LINENO(s);
+       d = linebuf;
+       rem = w;
+       while (1) {
+               *d = *s;
+               if (*d != '\0') {
+                       s++;
+                       d++;
+                       rem--;
+                       if (rem == 0) {
+                               int sz;
+                               /* new line is full, create next one */
+                               *d = '\0';
+ next_new:
+                               sz = (d - linebuf) + 1; /* + 1: NUL */
+                               d = ((char*)xmalloc(sz + 4)) + 4;
+                               LINENO(d) = lineno;
+                               memcpy(d, linebuf, sz);
+                               new_flines = xrealloc_vector(new_flines, 8, dst_idx);
+                               new_flines[dst_idx] = d;
+                               dst_idx++;
+                               if (rem) {
+                                       /* did we come here thru "goto next_new"? */
+                                       if (src_idx > max_fline)
+                                               break;
+                                       lineno = LINENO(s);
+                               }
+                               d = linebuf;
+                               rem = w;
+                       }
+                       continue;
+               }
+               /* *d == NUL: old line ended, go to next old one */
+               free(MEMPTR(old_flines[src_idx]));
+               /* btw, convert cur_fline... */
+               if (cur_fline == src_idx) {
+                       new_cur_fline = dst_idx;
+               }
+               src_idx++;
+               /* no more lines? finish last new line (and exit the loop) */
+               if (src_idx > max_fline) {
+                       goto next_new;
+               }
+               s = old_flines[src_idx];
+               if (lineno != LINENO(s)) {
+                       /* this is not a continuation line!
+                        * create next _new_ line too */
+                       goto next_new;
+               }
+       }
+
+       free(old_flines);
+       flines = (const char **)new_flines;
+
+       max_fline = dst_idx - 1;
+       linepos = 0; // XXX
+       cur_fline = new_cur_fline;
+       /* max_lineno is screen-size independent */
+}
+#endif
+
 #if ENABLE_FEATURE_LESS_REGEXP
 static void fill_match_lines(unsigned pos);
 #else
@@ -502,7 +588,7 @@ static void lineno_str(char *nbuf9, const char *line)
                }
                /* Width of 7 preserves tab spacing in the text */
                fmt = "%7u ";
-               n = LINENO(line);
+               n = LINENO(line) + 1;
                if (n > 9999999) {
                        n %= 10000000;
                        fmt = "%07u ";
@@ -633,6 +719,35 @@ static void buffer_print(void)
        status_print();
 }
 
+#if ENABLE_FEATURE_LESS_REWRAP
+static void buffer_fill_and_print(void)
+{
+       unsigned i = 0;
+       int fpos = cur_fline + i;
+
+       if (option_mask32 & LESS_STATE_NO_WRAP) {
+               /* Go back to the beginning of this line */
+               while (fpos && LINENO(flines[fpos]) == LINENO(flines[fpos-1]))
+                       fpos--;
+       }
+
+       while (i <= max_displayed_line && fpos <= max_fline) {
+               int lineno = LINENO(flines[fpos]);
+               buffer[i] = flines[fpos];
+               i++;
+               do {
+                       fpos++;
+               } while ((fpos <= max_fline)
+                     && (option_mask32 & LESS_STATE_NO_WRAP)
+                     && lineno == LINENO(flines[fpos])
+               );
+       }
+       for (; i <= max_displayed_line; i++) {
+               buffer[i] = empty_line_marker;
+       }
+       buffer_print();
+}
+#else
 static void buffer_fill_and_print(void)
 {
        unsigned i;
@@ -644,6 +759,7 @@ static void buffer_fill_and_print(void)
        }
        buffer_print();
 }
+#endif
 
 /* Move the buffer up and down in the file in order to scroll */
 static void buffer_down(int nlines)
@@ -1371,6 +1487,25 @@ static void keypress_process(int keypress)
        case ':':
                colon_process();
                break;
+#if ENABLE_FEATURE_LESS_REWRAP
+       case '*':
+               option_mask32 ^= FLAG_N;
+               get_terminal_width_height(kbd_fd, &width, &max_displayed_line);
+               if (width < 20) /* 20: two tabstops + 4 */
+                       width = 20;
+               if (max_displayed_line < 3)
+                       max_displayed_line = 3;
+               max_displayed_line -= 2;
+               free(buffer);
+               buffer = xmalloc((max_displayed_line+1) * sizeof(char *));
+               re_wrap();
+               buffer_fill_and_print();
+               break;
+       case '&':
+               option_mask32 ^= LESS_STATE_NO_WRAP;
+               buffer_fill_and_print();
+               break;
+#endif
        }
 
        if (isdigit(keypress))