From 51bb79569f934ad2135c2ff859c61b9ab8d51750 Mon Sep 17 00:00:00 2001 From: Andres Freund Date: Tue, 2 Sep 2014 13:05:48 +0200 Subject: [PATCH] Add psql PROMPT variable showing which line of a statement is being edited. The new %l substitution shows the line number inside a (potentially multi-line) statement starting from one. Author: Sawada Masahiko, heavily editorialized by me. Reviewed-By: Jeevan Chalke, Alvaro Herrera --- doc/src/sgml/ref/psql-ref.sgml | 9 +++++++++ src/bin/psql/copy.c | 15 +++++++++------ src/bin/psql/mainloop.c | 23 +++++++++++++++++++++++ src/bin/psql/prompt.c | 5 +++++ src/bin/psql/settings.h | 1 + 5 files changed, 47 insertions(+), 6 deletions(-) diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml index 74d46183e5..db314c326f 100644 --- a/doc/src/sgml/ref/psql-ref.sgml +++ b/doc/src/sgml/ref/psql-ref.sgml @@ -3315,6 +3315,15 @@ testdb=> INSERT INTO my_table VALUES (:'content'); + + %l + + + The line number inside the current statement, starting from 1. + + + + %digits diff --git a/src/bin/psql/copy.c b/src/bin/psql/copy.c index 4b749154ad..90f4a24fa5 100644 --- a/src/bin/psql/copy.c +++ b/src/bin/psql/copy.c @@ -517,8 +517,8 @@ bool handleCopyIn(PGconn *conn, FILE *copystream, bool isbinary, PGresult **res) { bool OK; - const char *prompt; char buf[COPYBUFSIZ]; + bool showprompt = false; /* * Establish longjmp destination for exiting from wait-for-input. (This is @@ -540,21 +540,20 @@ handleCopyIn(PGconn *conn, FILE *copystream, bool isbinary, PGresult **res) /* Prompt if interactive input */ if (isatty(fileno(copystream))) { + showprompt = true; if (!pset.quiet) puts(_("Enter data to be copied followed by a newline.\n" "End with a backslash and a period on a line by itself.")); - prompt = get_prompt(PROMPT_COPY); } - else - prompt = NULL; OK = true; if (isbinary) { /* interactive input probably silly, but give one prompt anyway */ - if (prompt) + if (showprompt) { + const char *prompt = get_prompt(PROMPT_COPY); fputs(prompt, stdout); fflush(stdout); } @@ -589,8 +588,9 @@ handleCopyIn(PGconn *conn, FILE *copystream, bool isbinary, PGresult **res) bool firstload; bool linedone; - if (prompt) + if (showprompt) { + const char *prompt = get_prompt(PROMPT_COPY); fputs(prompt, stdout); fflush(stdout); } @@ -650,7 +650,10 @@ handleCopyIn(PGconn *conn, FILE *copystream, bool isbinary, PGresult **res) } if (copystream == pset.cur_cmd_source) + { pset.lineno++; + pset.stmt_lineno++; + } } } diff --git a/src/bin/psql/mainloop.c b/src/bin/psql/mainloop.c index c3aff208bf..98211dcb2a 100644 --- a/src/bin/psql/mainloop.c +++ b/src/bin/psql/mainloop.c @@ -58,6 +58,7 @@ MainLoop(FILE *source) pset.cur_cmd_source = source; pset.cur_cmd_interactive = ((source == stdin) && !pset.notty); pset.lineno = 0; + pset.stmt_lineno = 1; /* Create working state */ scan_state = psql_scan_create(); @@ -110,6 +111,7 @@ MainLoop(FILE *source) count_eof = 0; slashCmdStatus = PSQL_CMD_UNKNOWN; prompt_status = PROMPT_READY; + pset.stmt_lineno = 1; cancel_pressed = false; if (pset.cur_cmd_interactive) @@ -225,7 +227,10 @@ MainLoop(FILE *source) { PsqlScanResult scan_result; promptStatus_t prompt_tmp = prompt_status; + size_t pos_in_query; + char *tmp_line; + pos_in_query = query_buf->len; scan_result = psql_scan(scan_state, query_buf, &prompt_tmp); prompt_status = prompt_tmp; @@ -235,6 +240,22 @@ MainLoop(FILE *source) exit(EXIT_FAILURE); } + /* + * Increase statement line number counter for each linebreak added + * to the query buffer by the last psql_scan() call. There only + * will be ones to add when navigating to a statement in + * readline's history containing newlines. + */ + tmp_line = query_buf->data + pos_in_query; + while (*tmp_line != '\0') + { + if (*(tmp_line++) == '\n') + pset.stmt_lineno++; + } + + if (scan_result == PSCAN_EOL) + pset.stmt_lineno++; + /* * Send command if semicolon found, or if end of line and we're in * single-line mode. @@ -256,6 +277,7 @@ MainLoop(FILE *source) /* execute query */ success = SendQuery(query_buf->data); slashCmdStatus = success ? PSQL_CMD_SEND : PSQL_CMD_ERROR; + pset.stmt_lineno = 1; /* transfer query to previous_buf by pointer-swapping */ { @@ -303,6 +325,7 @@ MainLoop(FILE *source) query_buf : previous_buf); success = slashCmdStatus != PSQL_CMD_ERROR; + pset.stmt_lineno = 1; if ((slashCmdStatus == PSQL_CMD_SEND || slashCmdStatus == PSQL_CMD_NEWEDIT) && query_buf->len == 0) diff --git a/src/bin/psql/prompt.c b/src/bin/psql/prompt.c index 26fca04756..f2db9a97bc 100644 --- a/src/bin/psql/prompt.c +++ b/src/bin/psql/prompt.c @@ -44,6 +44,7 @@ * in prompt2 -, *, ', or "; * in prompt3 nothing * %x - transaction status: empty, *, !, ? (unknown or no connection) + * %l - The line number inside the current statement, starting from 1. * %? - the error code of the last query (not yet implemented) * %% - a percent sign * @@ -229,6 +230,10 @@ get_prompt(promptStatus_t status) } break; + case 'l': + snprintf(buf, sizeof(buf), UINT64_FORMAT, pset.stmt_lineno); + break; + case '?': /* not here yet */ break; diff --git a/src/bin/psql/settings.h b/src/bin/psql/settings.h index 453d6c889d..ef24a4ef98 100644 --- a/src/bin/psql/settings.h +++ b/src/bin/psql/settings.h @@ -88,6 +88,7 @@ typedef struct _psqlSettings const char *progname; /* in case you renamed psql */ char *inputfile; /* file being currently processed, if any */ uint64 lineno; /* also for error reporting */ + uint64 stmt_lineno; /* line number inside the current statement */ bool timing; /* enable timing of all queries */ -- 2.40.0