Add unicode_{column|header|border}_style to psql

With the unicode linestyle, this adds support to control if the
column, header, or border style should be single or double line
unicode characters.  The default remains 'single'.

In passing, clean up the border documentation and address some
minor formatting/spelling issues.

Pavel Stehule, with some additional changes by me.
This commit is contained in:
Stephen Frost 2014-09-12 12:04:37 -04:00
parent 82962838d4
commit a2dabf0e1d
8 changed files with 306 additions and 33 deletions

View File

@ -1996,12 +1996,12 @@ lo_import 152801
the number the more borders and lines the tables will have,
but this depends on the particular format. In
<acronym>HTML</acronym> format, this will translate directly
into the <literal>border=...</literal> attribute; in the
other formats only values 0 (no border), 1 (internal dividing lines),
and 2 (table frame) make sense.
into the <literal>border=...</literal> attribute; in
<literal>latex</literal> and <literal>latex-longtable</literal>
also support a <literal>border</literal> value of 3 which adds
a dividing line between each row.
formats, a value of 3 will add a dividing line between each row; in
the other formats only values 0 (no border), 1 (internal dividing
lines), and 2 (table frame) make sense and values above 2 will be
treated the same as <literal>border = 2</literal>.
</para>
</listitem>
</varlistentry>
@ -2306,6 +2306,36 @@ lo_import 152801
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>unicode_border_style</literal></term>
<listitem>
<para>
Sets the border drawing style for the unicode linestyle to one
of <literal>single</literal> or <literal>double</literal>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>unicode_column_style</literal></term>
<listitem>
<para>
Sets the column drawing style for the unicode linestyle to one
of <literal>single</literal> or <literal>double</literal>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>unicode_header_style</literal></term>
<listitem>
<para>
Sets the header drawing style for the unicode linestyle to one
of <literal>single</literal> or <literal>double</literal>.
</para>
</listitem>
</varlistentry>
</variablelist>
</para>

View File

@ -1054,6 +1054,9 @@ exec_command(const char *cmd,
"footer", "format", "linestyle", "null",
"numericlocale", "pager", "recordsep",
"tableattr", "title", "tuples_only",
"unicode_border_linestyle",
"unicode_column_linestyle",
"unicode_header_linestyle",
NULL
};
@ -2248,6 +2251,41 @@ _align2string(enum printFormat in)
return "unknown";
}
/*
* Parse entered unicode linestyle. Returns true, when entered string is
* known linestyle: single, double else returns false.
*/
static bool
set_unicode_line_style(printQueryOpt *popt, const char *value, size_t vallen,
unicode_linestyle *linestyle)
{
if (pg_strncasecmp("single", value, vallen) == 0)
*linestyle = UNICODE_LINESTYLE_SINGLE;
else if (pg_strncasecmp("double", value, vallen) == 0)
*linestyle = UNICODE_LINESTYLE_DOUBLE;
else
return false;
/* input is ok, generate new unicode style */
refresh_utf8format(&(popt->topt));
return true;
}
static const char *
_unicode_linestyle2string(int linestyle)
{
switch (linestyle)
{
case UNICODE_LINESTYLE_SINGLE:
return "single";
break;
case UNICODE_LINESTYLE_DOUBLE:
return "double";
break;
}
return "unknown";
}
bool
do_pset(const char *param, const char *value, printQueryOpt *popt, bool quiet)
@ -2305,6 +2343,45 @@ do_pset(const char *param, const char *value, printQueryOpt *popt, bool quiet)
}
/* set unicode border line style */
else if (strcmp(param, "unicode_border_linestyle") == 0)
{
if (!value)
;
else if (!set_unicode_line_style(popt, value, vallen,
&popt->topt.unicode_border_linestyle))
{
psql_error("\\pset: allowed unicode border linestyle are single, double\n");
return false;
}
}
/* set unicode column line style */
else if (strcmp(param, "unicode_column_linestyle") == 0)
{
if (!value)
;
else if (!set_unicode_line_style(popt, value, vallen,
&popt->topt.unicode_column_linestyle))
{
psql_error("\\pset: allowed unicode column linestyle are single, double\n");
return false;
}
}
/* set unicode header line style */
else if (strcmp(param, "unicode_header_linestyle") == 0)
{
if (!value)
;
else if (!set_unicode_line_style(popt, value, vallen,
&popt->topt.unicode_header_linestyle))
{
psql_error("\\pset: allowed unicode header linestyle are single, double\n");
return false;
}
}
/* set border style/width */
else if (strcmp(param, "border") == 0)
{
@ -2601,6 +2678,25 @@ printPsetInfo(const char *param, struct printQueryOpt *popt)
printf(_("Tuples only (%s) is off.\n"), param);
}
/* unicode style formatting */
else if (strcmp(param, "unicode_border_linestyle") == 0)
{
printf(_("Unicode border linestyle is \"%s\".\n"),
_unicode_linestyle2string(popt->topt.unicode_border_linestyle));
}
else if (strcmp(param, "unicode_column_linestyle") == 0)
{
printf(_("Unicode column linestyle is \"%s\".\n"),
_unicode_linestyle2string(popt->topt.unicode_column_linestyle));
}
else if (strcmp(param, "unicode_header_linestyle") == 0)
{
printf(_("Unicode border linestyle is \"%s\".\n"),
_unicode_linestyle2string(popt->topt.unicode_header_linestyle));
}
else
{
psql_error("\\pset: unknown option: %s\n", param);

View File

@ -249,7 +249,8 @@ slashUsage(unsigned short int pager)
ON(pset.popt.topt.format == PRINT_HTML));
fprintf(output, _(" \\pset [NAME [VALUE]] set table output option\n"
" (NAME := {format|border|expanded|fieldsep|fieldsep_zero|footer|null|\n"
" numericlocale|recordsep|recordsep_zero|tuples_only|title|tableattr|pager})\n"));
" numericlocale|recordsep|recordsep_zero|tuples_only|title|tableattr|pager|\n"
" unicode_border_linestyle|unicode_column_linestyle|unicode_header_linestyle})\n"));
fprintf(output, _(" \\t [on|off] show only rows (currently %s)\n"),
ON(pset.popt.topt.tuples_only));
fprintf(output, _(" \\T [STRING] set HTML <table> tag attributes, or unset if none\n"));

View File

@ -89,35 +89,97 @@ const printTextFormat pg_asciiformat_old =
false
};
const printTextFormat pg_utf8format =
{
"unicode",
/* Default unicode linestyle format */
const printTextFormat pg_utf8format;
typedef struct unicodeStyleRowFormat {
const char *horizontal;
const char *vertical_and_right[2];
const char *vertical_and_left[2];
} unicodeStyleRowFormat;
typedef struct unicodeStyleColumnFormat {
const char *vertical;
const char *vertical_and_horizontal[2];
const char *up_and_horizontal[2];
const char *down_and_horizontal[2];
} unicodeStyleColumnFormat;
typedef struct unicodeStyleBorderFormat {
const char *up_and_right;
const char *vertical;
const char *down_and_right;
const char *horizontal;
const char *down_and_left;
const char *left_and_right;
} unicodeStyleBorderFormat;
typedef struct unicodeStyleFormat {
unicodeStyleRowFormat row_style[2];
unicodeStyleColumnFormat column_style[2];
unicodeStyleBorderFormat border_style[2];
const char *header_nl_left;
const char *header_nl_right;
const char *nl_left;
const char *nl_right;
const char *wrap_left;
const char *wrap_right;
bool wrap_right_border;
} unicodeStyleFormat;
const unicodeStyleFormat unicode_style = {
{
/* ─, ┌, ┬, ┐ */
{"\342\224\200", "\342\224\214", "\342\224\254", "\342\224\220"},
/* ─, ├, ┼, ┤ */
{"\342\224\200", "\342\224\234", "\342\224\274", "\342\224\244"},
/* ─, └, ┴, ┘ */
{"\342\224\200", "\342\224\224", "\342\224\264", "\342\224\230"},
/* N/A, │, │, │ */
{"", "\342\224\202", "\342\224\202", "\342\224\202"}
{
/* ─ */
"\342\224\200",
/* ├╟ */
{"\342\224\234", "\342\225\237"},
/* ┤╢ */
{"\342\224\244", "\342\225\242"},
},
{
/* ═ */
"\342\225\220",
/* ╞╠ */
{"\342\225\236", "\342\225\240"},
/* ╡╣ */
{"\342\225\241", "\342\225\243"},
},
},
{
{
/* │ */
"\342\224\202",
/* ┼╪ */
{"\342\224\274", "\342\225\252"},
/* ┴╧ */
{"\342\224\264", "\342\225\247"},
/* ┬╤ */
{"\342\224\254", "\342\225\244"},
},
{
/* ║ */
"\342\225\221",
/* ╫╬ */
{"\342\225\253", "\342\225\254"},
/* ╨╩ */
{"\342\225\250", "\342\225\251"},
/* ╥╦ */
{"\342\225\245", "\342\225\246"},
},
},
{
/* └│┌─┐┘ */
{"\342\224\224", "\342\224\202", "\342\224\214", "\342\224\200", "\342\224\220", "\342\224\230"},
/* ╚║╔═╗╝ */
{"\342\225\232", "\342\225\221", "\342\225\224", "\342\225\220", "\342\225\227", "\342\225\235"},
},
/* │ */
"\342\224\202",
/* │ */
"\342\224\202",
/* │ */
"\342\224\202",
" ",
/* ↵ */
"\342\206\265",
"\342\206\265", /* ↵ */
" ",
/* ↵ */
"\342\206\265",
/* … */
"\342\200\246",
/* … */
"\342\200\246",
"\342\206\265", /* ↵ */
"\342\200\246", /* … */
"\342\200\246", /* … */
true
};
@ -1289,7 +1351,7 @@ print_aligned_vertical(const printTableContent *cont, FILE *fout)
}
else
/*
* For border = 2, two more for the pipes (|) at the begging and
* For border = 2, two more for the pipes (|) at the beginning and
* at the end of the lines.
*/
swidth = 7;
@ -2952,6 +3014,58 @@ get_line_style(const printTableOpt *opt)
return &pg_asciiformat;
}
void
refresh_utf8format(const printTableOpt *opt)
{
printTextFormat *popt = (printTextFormat *) &pg_utf8format;
const unicodeStyleBorderFormat *border;
const unicodeStyleRowFormat *header;
const unicodeStyleColumnFormat *column;
popt->name = "unicode";
border = &unicode_style.border_style[opt->unicode_border_linestyle];
header = &unicode_style.row_style[opt->unicode_header_linestyle];
column = &unicode_style.column_style[opt->unicode_column_linestyle];
popt->lrule[PRINT_RULE_TOP].hrule = border->horizontal;
popt->lrule[PRINT_RULE_TOP].leftvrule = border->down_and_right;
popt->lrule[PRINT_RULE_TOP].midvrule = column->down_and_horizontal[opt->unicode_border_linestyle];
popt->lrule[PRINT_RULE_TOP].rightvrule = border->down_and_left;
popt->lrule[PRINT_RULE_MIDDLE].hrule = header->horizontal;
popt->lrule[PRINT_RULE_MIDDLE].leftvrule = header->vertical_and_right[opt->unicode_border_linestyle];
popt->lrule[PRINT_RULE_MIDDLE].midvrule = column->vertical_and_horizontal[opt->unicode_header_linestyle];
popt->lrule[PRINT_RULE_MIDDLE].rightvrule = header->vertical_and_left[opt->unicode_border_linestyle];
popt->lrule[PRINT_RULE_BOTTOM].hrule = border->horizontal;
popt->lrule[PRINT_RULE_BOTTOM].leftvrule = border->up_and_right;
popt->lrule[PRINT_RULE_BOTTOM].midvrule = column->up_and_horizontal[opt->unicode_border_linestyle];
popt->lrule[PRINT_RULE_BOTTOM].rightvrule = border->left_and_right;
/* N/A */
popt->lrule[PRINT_RULE_DATA].hrule = "";
popt->lrule[PRINT_RULE_DATA].leftvrule = border->vertical;
popt->lrule[PRINT_RULE_DATA].midvrule = column->vertical;
popt->lrule[PRINT_RULE_DATA].rightvrule = border->vertical;
popt->midvrule_nl = column->vertical;
popt->midvrule_wrap = column->vertical;
popt->midvrule_blank = column->vertical;
/* Same for all unicode today */
popt->header_nl_left = unicode_style.header_nl_left;
popt->header_nl_right = unicode_style.header_nl_right;
popt->nl_left = unicode_style.nl_left;
popt->nl_right = unicode_style.nl_right;
popt->wrap_left = unicode_style.wrap_left;
popt->wrap_right = unicode_style.wrap_right;
popt->wrap_right_border = unicode_style.wrap_right_border;
return;
}
/*
* Compute the byte distance to the end of the string or *target_width
* display character positions, whichever comes first. Update *target_width

View File

@ -68,6 +68,12 @@ typedef struct printTextFormat
* marks when border=0? */
} printTextFormat;
typedef enum unicode_linestyle
{
UNICODE_LINESTYLE_SINGLE = 0,
UNICODE_LINESTYLE_DOUBLE
} unicode_linestyle;
struct separator
{
char *separator;
@ -97,6 +103,9 @@ typedef struct printTableOpt
int encoding; /* character encoding */
int env_columns; /* $COLUMNS on psql start, 0 is unset */
int columns; /* target width for wrapped format */
unicode_linestyle unicode_border_linestyle;
unicode_linestyle unicode_column_linestyle;
unicode_linestyle unicode_header_linestyle;
} printTableOpt;
/*
@ -178,6 +187,7 @@ extern void printQuery(const PGresult *result, const printQueryOpt *opt,
extern void setDecimalLocale(void);
extern const printTextFormat *get_line_style(const printTableOpt *opt);
extern void refresh_utf8format(const printTableOpt *opt);
#ifndef __CYGWIN__
#define DEFAULT_PAGER "more"

View File

@ -26,6 +26,7 @@
#include "help.h"
#include "input.h"
#include "mainloop.h"
#include "print.h"
#include "settings.h"
@ -131,6 +132,13 @@ main(int argc, char *argv[])
pset.popt.topt.start_table = true;
pset.popt.topt.stop_table = true;
pset.popt.topt.default_footer = true;
pset.popt.topt.unicode_border_linestyle = UNICODE_LINESTYLE_SINGLE;
pset.popt.topt.unicode_column_linestyle = UNICODE_LINESTYLE_SINGLE;
pset.popt.topt.unicode_header_linestyle = UNICODE_LINESTYLE_SINGLE;
refresh_utf8format(&(pset.popt.topt));
/* We must get COLUMNS here before readline() sets it */
pset.popt.topt.env_columns = getenv("COLUMNS") ? atoi(getenv("COLUMNS")) : 0;

View File

@ -3622,7 +3622,8 @@ psql_completion(const char *text, int start, int end)
{"border", "columns", "expanded", "fieldsep", "fieldsep_zero",
"footer", "format", "linestyle", "null", "numericlocale",
"pager", "recordsep", "recordsep_zero", "tableattr", "title",
"tuples_only", NULL};
"tuples_only", "unicode_border_linestyle",
"unicode_column_linestyle", "unicode_header_linestyle", NULL};
COMPLETE_WITH_LIST_CS(my_list);
}
@ -3643,6 +3644,16 @@ psql_completion(const char *text, int start, int end)
COMPLETE_WITH_LIST_CS(my_list);
}
else if (strcmp(prev_wd, "unicode_border_linestyle") == 0 ||
strcmp(prev_wd, "unicode_column_linestyle") == 0 ||
strcmp(prev_wd, "unicode_header_linestyle") == 0)
{
static const char *const my_list[] =
{"single", "double", NULL};
COMPLETE_WITH_LIST_CS(my_list);
}
}
else if (strcmp(prev_wd, "\\unset") == 0)
{

View File

@ -68,6 +68,9 @@ Record separator (recordsep) is <newline>.
Table attributes (tableattr) unset.
Title (title) unset.
Tuples only (tuples_only) is off.
Unicode border linestyle is "single".
Unicode column linestyle is "single".
Unicode border linestyle is "single".
-- test multi-line headers, wrapping, and newline indicators
prepare q as select array_to_string(array_agg(repeat('x',2*n)),E'\n') as "ab