Add detection of psql pager to trigger on wide output. Also add pager

detection for wrapped lines or lines with newlines that need pager to
display.
This commit is contained in:
Bruce Momjian 2008-05-16 16:59:05 +00:00
parent e6dbcb72fa
commit 43ee22826b
2 changed files with 130 additions and 59 deletions

View 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 PostgreSQL documentation
--> -->
@ -1555,7 +1555,8 @@ lo_import 152801
<term><literal>columns</literal></term> <term><literal>columns</literal></term>
<listitem> <listitem>
<para> <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 Zero (the default) causes the <literal>wrapped</> format to
affect only screen output. affect only screen output.
</para> </para>
@ -1717,10 +1718,9 @@ lo_import 152801
When the pager is <literal>off</>, the pager is not used. When the pager 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 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. output is to a terminal and will not fit on the screen.
(<application>psql</> does not do a perfect job of estimating <literal>\pset pager</> turns the pager on and off. Pager can
when to use the pager.) <literal>\pset pager</> turns the also be set to <literal>always</>, which causes the pager to be
pager on and off. Pager can also be set to <literal>always</>, always used.
which causes the pager to be always used.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
@ -2734,8 +2734,9 @@ $endif
<listitem> <listitem>
<para> <para>
Used for the <literal>wrapped</> output format if If <literal>\pset columns</> is zero, controls the
<literal>\pset columns</> is zero. width for the <literal>wrapped</> format and width for determining
if wide output requires the pager.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>

View File

@ -3,7 +3,7 @@
* *
* Copyright (c) 2000-2008, PostgreSQL Global Development Group * 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" #include "postgres_fe.h"
@ -45,6 +45,8 @@ static char *thousands_sep;
/* Local functions */ /* Local functions */
static int strlen_max_width(unsigned char *str, int *target_width, int encoding); 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 * static void *
@ -394,7 +396,7 @@ _print_horizontal_line(const unsigned int ncolumns, const unsigned int *widths,
* Print pretty boxes around cells. * Print pretty boxes around cells.
*/ */
static void 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_tuples_only = cont->opt->tuples_only;
bool opt_numeric_locale = cont->opt->numericLocale; 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 char **format_buf;
unsigned int width_total; unsigned int width_total;
unsigned int total_header_width; unsigned int total_header_width;
unsigned int extra_row_output_lines = 0;
unsigned int extra_output_lines = 0;
const char * const *ptr; 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? */ bool *header_done; /* Have all header lines been output? */
int *bytes_output; /* Bytes output for column value */ int *bytes_output; /* Bytes output for column value */
int output_columns = 0; /* Width of interactive console */ int output_columns = 0; /* Width of interactive console */
bool is_pager = false;
if (cancel_pressed) if (cancel_pressed)
return; return;
@ -476,9 +481,14 @@ print_aligned_text(const printTableContent *cont, bool is_pager, FILE *fout)
max_nl_lines[i] = nl_lines; max_nl_lines[i] = nl_lines;
if (bytes_required > max_bytes[i]) if (bytes_required > max_bytes[i])
max_bytes[i] = bytes_required; max_bytes[i] = bytes_required;
if (nl_lines > extra_row_output_lines)
extra_row_output_lines = nl_lines;
width_header[i] = width; 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 */ /* scan all cells, find maximum width, compute cell_count */
for (i = 0, ptr = cont->cells; *ptr; ptr++, i++, 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, nl_lines,
bytes_required; bytes_required;
/* Get width, ignore nl_lines */
pg_wcssize((unsigned char *) *ptr, strlen(*ptr), encoding, pg_wcssize((unsigned char *) *ptr, strlen(*ptr), encoding,
&width, &nl_lines, &bytes_required); &width, &nl_lines, &bytes_required);
if (opt_numeric_locale && cont->aligns[i % col_count] == 'r') 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++) for (i = 0; i < col_count; i++)
width_wrap[i] = max_width[i]; width_wrap[i] = max_width[i];
/*
* 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;
#ifdef TIOCGWINSZ
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) 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)
{
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
}
/* /*
* Optional optimized word wrap. Shrink columns with a high max/avg * Optional optimized word wrap. Shrink columns with a high max/avg
* ratio. Slighly bias against wider columns. (Increases chance a * 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 */ /* time to output */
if (cont->opt->start_table) 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++) for (i = 0; i < col_count; i++)
free(format_buf[i]); free(format_buf[i]);
free(format_buf); 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 void
printTable(const printTableContent *cont, FILE *fout, FILE *flog) IsPagerNeeded(const printTableContent *cont, const int extra_lines, FILE **fout,
bool *is_pager)
{ {
FILE *output; if (*fout == stdout)
bool is_pager = false;
if (cancel_pressed)
return;
if (cont->opt->format == PRINT_NOTHING)
return;
if (fout == stdout)
{ {
int lines; int lines;
@ -2150,58 +2199,79 @@ printTable(const printTableContent *cont, FILE *fout, FILE *flog)
lines++; lines++;
} }
output = PageOutput(lines, cont->opt->pager); *fout = PageOutput(lines + extra_lines, cont->opt->pager);
is_pager = (output != fout); *is_pager = (*fout != stdout);
} }
else 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 */ /* print the stuff */
if (flog) if (flog)
print_aligned_text(cont, is_pager, flog); print_aligned_text(cont, flog);
switch (cont->opt->format) switch (cont->opt->format)
{ {
case PRINT_UNALIGNED: case PRINT_UNALIGNED:
if (cont->opt->expanded) if (cont->opt->expanded)
print_unaligned_vertical(cont, output); print_unaligned_vertical(cont, fout);
else else
print_unaligned_text(cont, output); print_unaligned_text(cont, fout);
break; break;
case PRINT_ALIGNED: case PRINT_ALIGNED:
case PRINT_WRAPPED: case PRINT_WRAPPED:
if (cont->opt->expanded) if (cont->opt->expanded)
print_aligned_vertical(cont, output); print_aligned_vertical(cont, fout);
else else
print_aligned_text(cont, is_pager, output); print_aligned_text(cont, fout);
break; break;
case PRINT_HTML: case PRINT_HTML:
if (cont->opt->expanded) if (cont->opt->expanded)
print_html_vertical(cont, output); print_html_vertical(cont, fout);
else else
print_html_text(cont, output); print_html_text(cont, fout);
break; break;
case PRINT_LATEX: case PRINT_LATEX:
if (cont->opt->expanded) if (cont->opt->expanded)
print_latex_vertical(cont, output); print_latex_vertical(cont, fout);
else else
print_latex_text(cont, output); print_latex_text(cont, fout);
break; break;
case PRINT_TROFF_MS: case PRINT_TROFF_MS:
if (cont->opt->expanded) if (cont->opt->expanded)
print_troff_ms_vertical(cont, output); print_troff_ms_vertical(cont, fout);
else else
print_troff_ms_text(cont, output); print_troff_ms_text(cont, fout);
break; break;
default: default:
fprintf(stderr, _("invalid output format (internal error): %d"), fprintf(stderr, _("invalid fout format (internal error): %d"),
cont->opt->format); cont->opt->format);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
if (is_pager) if (is_pager)
ClosePager(output); ClosePager(fout);
} }
/* /*