]> granicus.if.org Git - postgresql/commitdiff
Add unicode_{column|header|border}_style to psql
authorStephen Frost <sfrost@snowman.net>
Fri, 12 Sep 2014 16:04:37 +0000 (12:04 -0400)
committerStephen Frost <sfrost@snowman.net>
Fri, 12 Sep 2014 16:04:37 +0000 (12:04 -0400)
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.

doc/src/sgml/ref/psql-ref.sgml
src/bin/psql/command.c
src/bin/psql/help.c
src/bin/psql/print.c
src/bin/psql/print.h
src/bin/psql/startup.c
src/bin/psql/tab-complete.c
src/test/regress/expected/psql.out

index aa71674731e23a1855dbb691ed057444958700b5..e7fcc734b535226b69df78d3d80d9971317ee059 100644 (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>
 
index 5d90ca28edf446ad9ac944d14d9fc2d50d119ef4..2227db476a4b76c19b9ebeff16218375dd1e53b2 100644 (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);
index ef35696339b6e6dcbfaff8dbc36275ca2ecd779b..6035a7771a921a8fa2aae7119365d906e4c811f2 100644 (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"));
index 0ada8a4eb573c5bf8b13751b17d4826859206aed..3b3c3b73d957f76b3191ea2055e3ce80336d4684 100644 (file)
@@ -89,35 +89,97 @@ const printTextFormat pg_asciiformat_old =
        false
 };
 
-const printTextFormat pg_utf8format =
-{
-       "unicode",
-       {
-               /* ─, ┌, ┬, ┐ */
-               {"\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"}
+/* 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\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
index 87b28562821417e3359b16c4930f725fb5251a0a..f668b232952ac8873d5fac2b734f09f85d20f959 100644 (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"
index b879d0c35d3289bff98de65f0403820504cdf417..11a159a16494748783797ee0e6a539dcd088d6bc 100644 (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;
 
index 4ce47e99ef5700840bf8a7885e26dcaed1bbfb58..b80fe13168342e4d3b2e190c43dcafd5ea936435 100644 (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)
        {
index 199036d595c4b24f845967545ae2349fa5a289bf..3764127558c815ba627a7b66fd2301342fb7b450 100644 (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