diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml index aa71674731..e7fcc734b5 100644 --- a/doc/src/sgml/ref/psql-ref.sgml +++ b/doc/src/sgml/ref/psql-ref.sgml @@ -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 HTML format, this will translate directly - into the border=... attribute; in the - other formats only values 0 (no border), 1 (internal dividing lines), - and 2 (table frame) make sense. + into the border=... attribute; in latex and latex-longtable - also support a border 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 border = 2. @@ -2306,6 +2306,36 @@ lo_import 152801 + + + unicode_border_style + + + Sets the border drawing style for the unicode linestyle to one + of single or double. + + + + + + unicode_column_style + + + Sets the column drawing style for the unicode linestyle to one + of single or double. + + + + + + unicode_header_style + + + Sets the header drawing style for the unicode linestyle to one + of single or double. + + + diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c index 5d90ca28ed..2227db476a 100644 --- a/src/bin/psql/command.c +++ b/src/bin/psql/command.c @@ -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); diff --git a/src/bin/psql/help.c b/src/bin/psql/help.c index ef35696339..6035a7771a 100644 --- a/src/bin/psql/help.c +++ b/src/bin/psql/help.c @@ -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 tag attributes, or unset if none\n")); diff --git a/src/bin/psql/print.c b/src/bin/psql/print.c index 0ada8a4eb5..3b3c3b73d9 100644 --- a/src/bin/psql/print.c +++ b/src/bin/psql/print.c @@ -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 diff --git a/src/bin/psql/print.h b/src/bin/psql/print.h index 87b2856282..f668b23295 100644 --- a/src/bin/psql/print.h +++ b/src/bin/psql/print.h @@ -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" diff --git a/src/bin/psql/startup.c b/src/bin/psql/startup.c index b879d0c35d..11a159a164 100644 --- a/src/bin/psql/startup.c +++ b/src/bin/psql/startup.c @@ -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; diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c index 4ce47e99ef..b80fe13168 100644 --- a/src/bin/psql/tab-complete.c +++ b/src/bin/psql/tab-complete.c @@ -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) { diff --git a/src/test/regress/expected/psql.out b/src/test/regress/expected/psql.out index 199036d595..3764127558 100644 --- a/src/test/regress/expected/psql.out +++ b/src/test/regress/expected/psql.out @@ -68,6 +68,9 @@ Record separator (recordsep) is . 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