I wrote:
> I have often found myself wanting that psql automatically switch between
> normal and \x mode depending on the width of the output.  Would others
> find this useful?
> 
> Attached is a crude demo patch.  Enable with \pset expanded auto.

Here is a finalized patch for this.  The first hunk of the patch is the
documentation change, so you can see there how it's supposed to work.
Let me know what you think.

diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml
index d6941e0..e0f5ef4 100644
--- a/doc/src/sgml/ref/psql-ref.sgml
+++ b/doc/src/sgml/ref/psql-ref.sgml
@@ -1876,15 +1876,19 @@ lo_import 152801
           <term><literal>expanded</literal> (or <literal>x</literal>)</term>
           <listitem>
           <para>
-          If <replaceable class="parameter">value</replaceable> is specified
-          it must be either <literal>on</literal> or <literal>off</literal>
-          which will enable or disable expanded mode.  If <replaceable
-          class="parameter">value</replaceable> is omitted the command toggles
-          between regular and expanded mode.
-          When expanded mode is enabled, query results
-          are displayed in two columns, with the column name on the left and
-          the data on the right. This mode is useful if the data wouldn't fit
-          on the screen in the normal <quote>horizontal</quote> mode.
+          If <replaceable class="parameter">value</replaceable> is specified it
+          must be either <literal>on</literal> or <literal>off</literal>, which
+          will enable or disable expanded mode, or <literal>auto</literal>.
+          If <replaceable class="parameter">value</replaceable> is omitted the
+          command toggles between the on and off settings.  When expanded mode
+          is enabled, query results are displayed in two columns, with the
+          column name on the left and the data on the right. This mode is
+          useful if the data wouldn't fit on the screen in the
+          normal <quote>horizontal</quote> mode.  In the auto setting, the
+          expanded mode is used whenever the query output is wider than the
+          screen, otherwise the regular mode is used.  The auto setting is only
+          effective in the aligned and wrapped formats.  In other formats, it
+          always behaves as if the expanded mode is off.
           </para>
           </listitem>
           </varlistentry>
@@ -2326,10 +2330,10 @@ lo_import 152801
 
 
       <varlistentry>
-        <term><literal>\x</literal></term>
+        <term><literal>\x [ <replaceable class="parameter">on</replaceable> | <replaceable class="parameter">off</replaceable> | <replaceable class="parameter">auto</replaceable> ]</literal></term>
         <listitem>
         <para>
-        Toggles expanded table formatting mode. As such it is equivalent to
+        Sets or toggles expanded table formatting mode. As such it is equivalent to
         <literal>\pset expanded</literal>.
        </para>
        </listitem>
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
index 2c38902..5edeeb1 100644
--- a/src/bin/psql/command.c
+++ b/src/bin/psql/command.c
@@ -1343,7 +1343,7 @@ exec_command(const char *cmd,
 		free(fname);
 	}
 
-	/* \x -- toggle expanded table representation */
+	/* \x -- set or toggle expanded table representation */
 	else if (strcmp(cmd, "x") == 0)
 	{
 		char	   *opt = psql_scan_slash_option(scan_state,
@@ -2177,14 +2177,21 @@ do_pset(const char *param, const char *value, printQueryOpt *popt, bool quiet)
 	/* set expanded/vertical mode */
 	else if (strcmp(param, "x") == 0 || strcmp(param, "expanded") == 0 || strcmp(param, "vertical") == 0)
 	{
-		if (value)
+		if (value && pg_strcasecmp(value, "auto") == 0)
+			popt->topt.expanded = 2;
+		else if (value)
 			popt->topt.expanded = ParseVariableBool(value);
 		else
 			popt->topt.expanded = !popt->topt.expanded;
 		if (!quiet)
-			printf(popt->topt.expanded
-				   ? _("Expanded display is on.\n")
-				   : _("Expanded display is off.\n"));
+		{
+			if (popt->topt.expanded == 1)
+				printf(_("Expanded display is on.\n"));
+			else if (popt->topt.expanded == 2)
+				printf(_("Expanded display is used automatically.\n"));
+			else
+				printf(_("Expanded display is off.\n"));
+		}
 	}
 
 	/* locale-aware numeric output */
diff --git a/src/bin/psql/print.c b/src/bin/psql/print.c
index 0d18665..c693040 100644
--- a/src/bin/psql/print.c
+++ b/src/bin/psql/print.c
@@ -122,9 +122,11 @@ const printTextFormat pg_utf8format =
 
 /* 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,
+static void IsPagerNeeded(const printTableContent *cont, const int extra_lines, bool expanded,
 			  FILE **fout, bool *is_pager);
 
+static void print_aligned_vertical(const printTableContent *cont, FILE *fout);
+
 
 static void *
 pg_local_malloc(size_t size)
@@ -713,6 +715,17 @@ print_aligned_text(const printTableContent *cont, FILE *fout)
 		}
 	}
 
+	/*
+	 * If in expanded auto mode, we have now calculated the expected width, so
+	 * we can now escape to vertical mode if necessary.
+	 */
+	if (cont->opt->expanded == 2 &&
+		(output_columns < total_header_width || output_columns < width_total))
+	{
+		print_aligned_vertical(cont, fout);
+		return;
+	}
+
 	/* If we wrapped beyond the display width, use the pager */
 	if (!is_pager && fout == stdout && output_columns > 0 &&
 		(output_columns < total_header_width || output_columns < width_total))
@@ -756,7 +769,7 @@ print_aligned_text(const printTableContent *cont, FILE *fout)
 				extra_row_output_lines = 0;
 			}
 		}
-		IsPagerNeeded(cont, extra_output_lines, &fout, &is_pager);
+		IsPagerNeeded(cont, extra_output_lines, false, &fout, &is_pager);
 	}
 
 	/* time to output */
@@ -1125,6 +1138,7 @@ print_aligned_vertical(const printTableContent *cont, FILE *fout)
 				dformatsize = 0;
 	struct lineptr *hlineptr,
 			   *dlineptr;
+	bool		is_pager = false;
 
 	if (cancel_pressed)
 		return;
@@ -1139,6 +1153,13 @@ print_aligned_vertical(const printTableContent *cont, FILE *fout)
 		return;
 	}
 
+	/*
+	 * Deal with the pager here instead of in printTable(), because we could
+	 * get here via print_aligned_text() in expanded auto mode, and so we have
+	 * to recalcuate the pager requirement based on vertical output.
+	 */
+	IsPagerNeeded(cont, 0, true, &fout, &is_pager);
+
 	/* Find the maximum dimensions for the headers */
 	for (i = 0; i < cont->ncolumns; i++)
 	{
@@ -1295,6 +1316,9 @@ print_aligned_vertical(const printTableContent *cont, FILE *fout)
 	free(dlineptr->ptr);
 	free(hlineptr);
 	free(dlineptr);
+
+	if (is_pager)
+		ClosePager(fout);
 }
 
 
@@ -2265,14 +2289,14 @@ printTableCleanup(printTableContent *const content)
  * Setup pager if required
  */
 static void
-IsPagerNeeded(const printTableContent *cont, const int extra_lines, FILE **fout,
+IsPagerNeeded(const printTableContent *cont, const int extra_lines, bool expanded, FILE **fout,
 			  bool *is_pager)
 {
 	if (*fout == stdout)
 	{
 		int			lines;
 
-		if (cont->opt->expanded)
+		if (expanded)
 			lines = (cont->ncolumns + 1) * cont->nrows;
 		else
 			lines = cont->nrows + 1;
@@ -2310,11 +2334,10 @@ printTable(const printTableContent *cont, FILE *fout, FILE *flog)
 	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_aligned_*() handles the pager themselves */
+	if (cont->opt->format != PRINT_ALIGNED &&
+		cont->opt->format != PRINT_WRAPPED)
+		IsPagerNeeded(cont, 0, (cont->opt->expanded == 1), &fout, &is_pager);
 
 	/* print the stuff */
 
@@ -2324,32 +2347,32 @@ printTable(const printTableContent *cont, FILE *fout, FILE *flog)
 	switch (cont->opt->format)
 	{
 		case PRINT_UNALIGNED:
-			if (cont->opt->expanded)
+			if (cont->opt->expanded == 1)
 				print_unaligned_vertical(cont, fout);
 			else
 				print_unaligned_text(cont, fout);
 			break;
 		case PRINT_ALIGNED:
 		case PRINT_WRAPPED:
-			if (cont->opt->expanded)
+			if (cont->opt->expanded == 1)
 				print_aligned_vertical(cont, fout);
 			else
 				print_aligned_text(cont, fout);
 			break;
 		case PRINT_HTML:
-			if (cont->opt->expanded)
+			if (cont->opt->expanded == 1)
 				print_html_vertical(cont, fout);
 			else
 				print_html_text(cont, fout);
 			break;
 		case PRINT_LATEX:
-			if (cont->opt->expanded)
+			if (cont->opt->expanded == 1)
 				print_latex_vertical(cont, fout);
 			else
 				print_latex_text(cont, fout);
 			break;
 		case PRINT_TROFF_MS:
-			if (cont->opt->expanded)
+			if (cont->opt->expanded == 1)
 				print_troff_ms_vertical(cont, fout);
 			else
 				print_troff_ms_text(cont, fout);
diff --git a/src/bin/psql/print.h b/src/bin/psql/print.h
index 35bb4cd..bb20613 100644
--- a/src/bin/psql/print.h
+++ b/src/bin/psql/print.h
@@ -70,8 +70,8 @@ typedef struct printTextFormat
 typedef struct printTableOpt
 {
 	enum printFormat format;	/* see enum above */
-	bool		expanded;		/* expanded/vertical output (if supported by
-								 * output format) */
+	unsigned short int expanded;/* expanded/vertical output (if supported by
+								 * output format); 0=no, 1=yes, 2=auto */
 	unsigned short int border;	/* Print a border around the table. 0=none,
 								 * 1=dividing lines, 2=full */
 	unsigned short int pager;	/* use pager for output (if to stdout and
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to