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
This commit is contained in:
Andres Freund 2014-09-02 13:05:48 +02:00
parent bd3b7a9eef
commit 51bb79569f
5 changed files with 47 additions and 6 deletions

View File

@ -3315,6 +3315,15 @@ testdb=&gt; <userinput>INSERT INTO my_table VALUES (:'content');</userinput>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><literal>%l</literal></term>
<listitem>
<para>
The line number inside the current statement, starting from <literal>1</>.
</para>
</listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term><literal>%</literal><replaceable class="parameter">digits</replaceable></term> <term><literal>%</literal><replaceable class="parameter">digits</replaceable></term>
<listitem> <listitem>

View File

@ -517,8 +517,8 @@ bool
handleCopyIn(PGconn *conn, FILE *copystream, bool isbinary, PGresult **res) handleCopyIn(PGconn *conn, FILE *copystream, bool isbinary, PGresult **res)
{ {
bool OK; bool OK;
const char *prompt;
char buf[COPYBUFSIZ]; char buf[COPYBUFSIZ];
bool showprompt = false;
/* /*
* Establish longjmp destination for exiting from wait-for-input. (This is * 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 */ /* Prompt if interactive input */
if (isatty(fileno(copystream))) if (isatty(fileno(copystream)))
{ {
showprompt = true;
if (!pset.quiet) if (!pset.quiet)
puts(_("Enter data to be copied followed by a newline.\n" puts(_("Enter data to be copied followed by a newline.\n"
"End with a backslash and a period on a line by itself.")); "End with a backslash and a period on a line by itself."));
prompt = get_prompt(PROMPT_COPY);
} }
else
prompt = NULL;
OK = true; OK = true;
if (isbinary) if (isbinary)
{ {
/* interactive input probably silly, but give one prompt anyway */ /* interactive input probably silly, but give one prompt anyway */
if (prompt) if (showprompt)
{ {
const char *prompt = get_prompt(PROMPT_COPY);
fputs(prompt, stdout); fputs(prompt, stdout);
fflush(stdout); fflush(stdout);
} }
@ -589,8 +588,9 @@ handleCopyIn(PGconn *conn, FILE *copystream, bool isbinary, PGresult **res)
bool firstload; bool firstload;
bool linedone; bool linedone;
if (prompt) if (showprompt)
{ {
const char *prompt = get_prompt(PROMPT_COPY);
fputs(prompt, stdout); fputs(prompt, stdout);
fflush(stdout); fflush(stdout);
} }
@ -650,7 +650,10 @@ handleCopyIn(PGconn *conn, FILE *copystream, bool isbinary, PGresult **res)
} }
if (copystream == pset.cur_cmd_source) if (copystream == pset.cur_cmd_source)
{
pset.lineno++; pset.lineno++;
pset.stmt_lineno++;
}
} }
} }

View File

@ -58,6 +58,7 @@ MainLoop(FILE *source)
pset.cur_cmd_source = source; pset.cur_cmd_source = source;
pset.cur_cmd_interactive = ((source == stdin) && !pset.notty); pset.cur_cmd_interactive = ((source == stdin) && !pset.notty);
pset.lineno = 0; pset.lineno = 0;
pset.stmt_lineno = 1;
/* Create working state */ /* Create working state */
scan_state = psql_scan_create(); scan_state = psql_scan_create();
@ -110,6 +111,7 @@ MainLoop(FILE *source)
count_eof = 0; count_eof = 0;
slashCmdStatus = PSQL_CMD_UNKNOWN; slashCmdStatus = PSQL_CMD_UNKNOWN;
prompt_status = PROMPT_READY; prompt_status = PROMPT_READY;
pset.stmt_lineno = 1;
cancel_pressed = false; cancel_pressed = false;
if (pset.cur_cmd_interactive) if (pset.cur_cmd_interactive)
@ -225,7 +227,10 @@ MainLoop(FILE *source)
{ {
PsqlScanResult scan_result; PsqlScanResult scan_result;
promptStatus_t prompt_tmp = prompt_status; 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); scan_result = psql_scan(scan_state, query_buf, &prompt_tmp);
prompt_status = prompt_tmp; prompt_status = prompt_tmp;
@ -235,6 +240,22 @@ MainLoop(FILE *source)
exit(EXIT_FAILURE); 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 * Send command if semicolon found, or if end of line and we're in
* single-line mode. * single-line mode.
@ -256,6 +277,7 @@ MainLoop(FILE *source)
/* execute query */ /* execute query */
success = SendQuery(query_buf->data); success = SendQuery(query_buf->data);
slashCmdStatus = success ? PSQL_CMD_SEND : PSQL_CMD_ERROR; slashCmdStatus = success ? PSQL_CMD_SEND : PSQL_CMD_ERROR;
pset.stmt_lineno = 1;
/* transfer query to previous_buf by pointer-swapping */ /* transfer query to previous_buf by pointer-swapping */
{ {
@ -303,6 +325,7 @@ MainLoop(FILE *source)
query_buf : previous_buf); query_buf : previous_buf);
success = slashCmdStatus != PSQL_CMD_ERROR; success = slashCmdStatus != PSQL_CMD_ERROR;
pset.stmt_lineno = 1;
if ((slashCmdStatus == PSQL_CMD_SEND || slashCmdStatus == PSQL_CMD_NEWEDIT) && if ((slashCmdStatus == PSQL_CMD_SEND || slashCmdStatus == PSQL_CMD_NEWEDIT) &&
query_buf->len == 0) query_buf->len == 0)

View File

@ -44,6 +44,7 @@
* in prompt2 -, *, ', or "; * in prompt2 -, *, ', or ";
* in prompt3 nothing * in prompt3 nothing
* %x - transaction status: empty, *, !, ? (unknown or no connection) * %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) * %? - the error code of the last query (not yet implemented)
* %% - a percent sign * %% - a percent sign
* *
@ -229,6 +230,10 @@ get_prompt(promptStatus_t status)
} }
break; break;
case 'l':
snprintf(buf, sizeof(buf), UINT64_FORMAT, pset.stmt_lineno);
break;
case '?': case '?':
/* not here yet */ /* not here yet */
break; break;

View File

@ -88,6 +88,7 @@ typedef struct _psqlSettings
const char *progname; /* in case you renamed psql */ const char *progname; /* in case you renamed psql */
char *inputfile; /* file being currently processed, if any */ char *inputfile; /* file being currently processed, if any */
uint64 lineno; /* also for error reporting */ uint64 lineno; /* also for error reporting */
uint64 stmt_lineno; /* line number inside the current statement */
bool timing; /* enable timing of all queries */ bool timing; /* enable timing of all queries */