]> granicus.if.org Git - postgresql/commitdiff
Add detection of psql pager to trigger on wide output. Also add pager
authorBruce Momjian <bruce@momjian.us>
Fri, 16 May 2008 16:59:05 +0000 (16:59 +0000)
committerBruce Momjian <bruce@momjian.us>
Fri, 16 May 2008 16:59:05 +0000 (16:59 +0000)
detection for wrapped lines or lines with newlines that need pager to
display.

doc/src/sgml/ref/psql-ref.sgml
src/bin/psql/print.c

index 32346e413f37afacfb96ed073eb6f9444e8e5035..75392accf7d662bcfa4e1ff7637edca97697a6e2 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/psql-ref.sgml,v 1.204 2008/05/14 04:07:01 momjian Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/psql-ref.sgml,v 1.205 2008/05/16 16:59:05 momjian Exp $
 PostgreSQL documentation
 -->
 
@@ -1555,7 +1555,8 @@ lo_import 152801
           <term><literal>columns</literal></term>
           <listitem>
           <para>
-          Controls the target width for the <literal>wrapped</> format.
+          Controls the target width for the <literal>wrapped</> format,
+          and width for determining if wide output requires the pager.
           Zero (the default) causes the <literal>wrapped</> format to
           affect only screen output.
           </para>
@@ -1717,10 +1718,9 @@ lo_import 152801
           When the pager is <literal>off</>, the pager is not used. When the pager
           is <literal>on</>, the pager is used only when appropriate, i.e. the
           output is to a terminal and will not fit on the screen.
-          (<application>psql</> does not do a perfect job of estimating
-          when to use the pager.) <literal>\pset pager</> turns the
-          pager on and off. Pager can also be set to <literal>always</>,
-          which causes the pager to be always used.
+          <literal>\pset pager</> turns the pager on and off. Pager can
+          also be set to <literal>always</>, which causes the pager to be
+          always used.
           </para>
           </listitem>
           </varlistentry>
@@ -2734,8 +2734,9 @@ $endif
 
     <listitem>
      <para>
-      Used for the <literal>wrapped</> output format if 
-      <literal>\pset columns</> is zero.
+      If <literal>\pset columns</> is zero, controls the
+      width for the <literal>wrapped</> format and width for determining
+      if wide output requires the pager.
      </para>
     </listitem>
    </varlistentry>
index f27c1e1f4887135df589aa526f514badf2d05cb6..9f531f25faafcdad6a194a73376807229a934650 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2000-2008, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/bin/psql/print.c,v 1.101 2008/05/13 00:14:11 alvherre Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/print.c,v 1.102 2008/05/16 16:59:05 momjian Exp $
  */
 #include "postgres_fe.h"
 
@@ -45,6 +45,8 @@ static char *thousands_sep;
 
 /* Local functions */
 static int strlen_max_width(unsigned char *str, int *target_width, int encoding);
+static void IsPagerNeeded(const printTableContent *cont, const int extra_lines,
+                                                 FILE **fout, bool *is_pager);
 
 
 static void *
@@ -394,7 +396,7 @@ _print_horizontal_line(const unsigned int ncolumns, const unsigned int *widths,
  *     Print pretty boxes around cells.
  */
 static void
-print_aligned_text(const printTableContent *cont, bool is_pager, FILE *fout)
+print_aligned_text(const printTableContent *cont, FILE *fout)
 {
        bool            opt_tuples_only = cont->opt->tuples_only;
        bool            opt_numeric_locale = cont->opt->numericLocale;
@@ -416,6 +418,8 @@ print_aligned_text(const printTableContent *cont, bool is_pager, FILE *fout)
        unsigned char **format_buf;
        unsigned int width_total;
        unsigned int total_header_width;
+       unsigned int extra_row_output_lines = 0;
+       unsigned int extra_output_lines = 0;
 
        const char * const *ptr;
 
@@ -424,6 +428,7 @@ print_aligned_text(const printTableContent *cont, bool is_pager, FILE *fout)
        bool       *header_done;        /* Have all header lines been output? */
        int                *bytes_output;       /* Bytes output for column value */
        int                     output_columns = 0;     /* Width of interactive console */
+       bool            is_pager = false;
 
        if (cancel_pressed)
                return;
@@ -476,9 +481,14 @@ print_aligned_text(const printTableContent *cont, bool is_pager, FILE *fout)
                        max_nl_lines[i] = nl_lines;
                if (bytes_required > max_bytes[i])
                        max_bytes[i] = bytes_required;
+               if (nl_lines > extra_row_output_lines)
+                       extra_row_output_lines = nl_lines;
 
                width_header[i] = width;
        }
+       /* Add height of tallest header column */
+       extra_output_lines += extra_row_output_lines;
+       extra_row_output_lines = 0;
 
        /* scan all cells, find maximum width, compute cell_count */
        for (i = 0, ptr = cont->cells; *ptr; ptr++, i++, cell_count++)
@@ -487,7 +497,6 @@ print_aligned_text(const printTableContent *cont, bool is_pager, FILE *fout)
                                        nl_lines,
                                        bytes_required;
 
-               /* Get width, ignore nl_lines */
                pg_wcssize((unsigned char *) *ptr, strlen(*ptr), encoding,
                                   &width, &nl_lines, &bytes_required);
                if (opt_numeric_locale && cont->aligns[i % col_count] == 'r')
@@ -552,28 +561,28 @@ print_aligned_text(const printTableContent *cont, bool is_pager, FILE *fout)
        for (i = 0; i < col_count; i++)
                width_wrap[i] = max_width[i];
 
-       if (cont->opt->format == PRINT_WRAPPED)
+       /*
+        * Choose target output width: \pset columns, or $COLUMNS, or ioctl
+        */
+       if (cont->opt->columns > 0)
+               output_columns = cont->opt->columns;
+       else if ((fout == stdout && isatty(fileno(stdout))) || is_pager)
        {
-               /*
-                * Choose target output width: \pset columns, or $COLUMNS, or ioctl
-                */
-               if (cont->opt->columns > 0)
-                       output_columns = cont->opt->columns;
-               else if ((fout == stdout && isatty(fileno(stdout))) || is_pager)
-               {
-                       if (cont->opt->env_columns > 0)
-                               output_columns = cont->opt->env_columns;
+               if (cont->opt->env_columns > 0)
+                       output_columns = cont->opt->env_columns;
 #ifdef TIOCGWINSZ
-                       else
-                       {
-                               struct winsize screen_size;
-       
-                               if (ioctl(fileno(stdout), TIOCGWINSZ, &screen_size) != -1)
-                                       output_columns = screen_size.ws_col;
-                       }
-#endif
+               else
+               {
+                       struct winsize screen_size;
+
+                       if (ioctl(fileno(stdout), TIOCGWINSZ, &screen_size) != -1)
+                               output_columns = screen_size.ws_col;
                }
+#endif
+       }
 
+       if (cont->opt->format == PRINT_WRAPPED)
+       {
                /*
                 * Optional optimized word wrap. Shrink columns with a high max/avg
                 * ratio.  Slighly bias against wider columns. (Increases chance a
@@ -623,6 +632,49 @@ print_aligned_text(const printTableContent *cont, bool is_pager, FILE *fout)
                }
        }
 
+       /* If we wrapped beyond the display width, use the pager */
+       if (!is_pager && output_columns > 0 &&
+               (output_columns < total_header_width || output_columns < width_total))
+       {
+               fout = PageOutput(INT_MAX, cont->opt->pager);   /* force pager */
+               is_pager = true;
+       }
+       
+       /* Check if newlines or our wrapping now need the pager */
+       if (!is_pager)
+       {
+               /* scan all cells, find maximum width, compute cell_count */
+               for (i = 0, ptr = cont->cells; *ptr; ptr++, i++, cell_count++)
+               {
+                       int                     width,
+                                               nl_lines,
+                                               bytes_required;
+       
+                       pg_wcssize((unsigned char *) *ptr, strlen(*ptr), encoding,
+                                          &width, &nl_lines, &bytes_required);
+                       if (opt_numeric_locale && cont->align[i % col_count] == 'r')
+                               width += additional_numeric_locale_len(*ptr);
+       
+                       /*
+                        *      A row can have both wrapping and newlines that cause
+                        *      it to display across multiple lines.  We check
+                        *      for both cases below.
+                        */
+                       if (width > 0 && width_wrap[i] &&
+                               (width-1) / width_wrap[i] + nl_lines > extra_row_output_lines)
+                               extra_row_output_lines = (width-1) / width_wrap[i] + nl_lines;
+
+                       /* If last column, add tallest column height */
+                       if (i % col_count == col_count - 1)
+                       {
+                               /* Add height of tallest row */
+                               extra_output_lines += extra_row_output_lines;
+                               extra_row_output_lines = 0;
+                       }
+               }
+               IsPagerNeeded(cont, extra_output_lines, &fout, &is_pager);
+       }
+       
        /* time to output */
        if (cont->opt->start_table)
        {
@@ -882,6 +934,9 @@ print_aligned_text(const printTableContent *cont, bool is_pager, FILE *fout)
        for (i = 0; i < col_count; i++)
                free(format_buf[i]);
        free(format_buf);
+
+       if (is_pager)
+               ClosePager(fout);
 }
 
 
@@ -2115,21 +2170,15 @@ printTableCleanup(printTableContent *content)
 }
 
 /*
- * Use this to print just any table in the supported formats.
+ * IsPagerNeeded
+ *
+ * Setup pager if required
  */
 void
-printTable(const printTableContent *cont, FILE *fout, FILE *flog)
+IsPagerNeeded(const printTableContent *cont, const int extra_lines, FILE **fout,
+                         bool *is_pager)
 {
-       FILE       *output;
-       bool            is_pager = false;
-       
-       if (cancel_pressed)
-               return;
-
-       if (cont->opt->format == PRINT_NOTHING)
-               return;
-
-       if (fout == stdout)
+       if (*fout == stdout)
        {
                int                     lines;
 
@@ -2150,58 +2199,79 @@ printTable(const printTableContent *cont, FILE *fout, FILE *flog)
                                lines++;
                }
 
-               output = PageOutput(lines, cont->opt->pager);
-               is_pager = (output != fout);
+               *fout = PageOutput(lines + extra_lines, cont->opt->pager);
+               *is_pager = (*fout != stdout);
        }
        else
-               output = fout;
+               *is_pager = false;
+}
+
+/*
+ * Use this to print just any table in the supported formats.
+ */
+void
+printTable(const printTableContent *cont, FILE *fout, FILE *flog)
+{
+       bool            is_pager = false;
+       
+       if (cancel_pressed)
+               return;
+
+       if (cont->opt->format == PRINT_NOTHING)
+               return;
+
+       /* print_aligned_text() handles the pager itself */
+       if ((cont->opt->format != PRINT_ALIGNED &&
+                cont->opt->format != PRINT_WRAPPED) ||
+                cont->opt->expanded)
+               IsPagerNeeded(cont, 0, &fout, &is_pager);
 
        /* print the stuff */
 
        if (flog)
-               print_aligned_text(cont, is_pager, flog);
+               print_aligned_text(cont, flog);
 
        switch (cont->opt->format)
        {
                case PRINT_UNALIGNED:
                        if (cont->opt->expanded)
-                               print_unaligned_vertical(cont, output);
+                               print_unaligned_vertical(cont, fout);
                        else
-                               print_unaligned_text(cont, output);
+                               print_unaligned_text(cont, fout);
                        break;
                case PRINT_ALIGNED:
                case PRINT_WRAPPED:
                        if (cont->opt->expanded)
-                               print_aligned_vertical(cont, output);
+                               print_aligned_vertical(cont, fout);
                        else
-                               print_aligned_text(cont, is_pager, output);
+                               print_aligned_text(cont, fout);
                        break;
                case PRINT_HTML:
                        if (cont->opt->expanded)
-                               print_html_vertical(cont, output);
+                               print_html_vertical(cont, fout);
                        else
-                               print_html_text(cont, output);
+                               print_html_text(cont, fout);
                        break;
                case PRINT_LATEX:
                        if (cont->opt->expanded)
-                               print_latex_vertical(cont, output);
+                               print_latex_vertical(cont, fout);
                        else
-                               print_latex_text(cont, output);
+                               print_latex_text(cont, fout);
                        break;
                case PRINT_TROFF_MS:
                        if (cont->opt->expanded)
-                               print_troff_ms_vertical(cont, output);
+                               print_troff_ms_vertical(cont, fout);
                        else
-                               print_troff_ms_text(cont, output);
+                               print_troff_ms_text(cont, fout);
                        break;
                default:
-                       fprintf(stderr, _("invalid output format (internal error): %d"),
+                       fprintf(stderr, _("invalid fout format (internal error): %d"),
                                        cont->opt->format);
                        exit(EXIT_FAILURE);
        }
 
        if (is_pager)
-               ClosePager(output);
+               ClosePager(fout);
 }
 
 /*