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
-->
@ -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>

View 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];
/*
* 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)
{
/*
* 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
* 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);
}
/*