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:
parent
e6dbcb72fa
commit
43ee22826b
@ -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>
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Loading…
x
Reference in New Issue
Block a user