Add psql PROMPT variable showing which line of a statement is being edited.
authorAndres Freund <andres@anarazel.de>
Tue, 2 Sep 2014 11:05:48 +0000 (13:05 +0200)
committerAndres Freund <andres@anarazel.de>
Tue, 2 Sep 2014 11:06:11 +0000 (13:06 +0200)
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
src/bin/psql/copy.c
src/bin/psql/mainloop.c
src/bin/psql/prompt.c
src/bin/psql/settings.h

index 74d46183e51b344bb7a0b5a1aaf04a1bf79fa4cf..db314c326fd104708d3654d983087b050d6ab3e7 100644 (file)
@@ -3315,6 +3315,15 @@ testdb=&gt; <userinput>INSERT INTO my_table VALUES (:'content');</userinput>
         </listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><literal>%l</literal></term>
+        <listitem>
+         <para>
+          The line number inside the current statement, starting from <literal>1</>.
+         </para>
+        </listitem>
+      </varlistentry>
+
       <varlistentry>
         <term><literal>%</literal><replaceable class="parameter">digits</replaceable></term>
         <listitem>
index 4b749154adf951c3e02c6d3152f0ecf2d85373fd..90f4a24fa5dc2e8d9e5a45babe3311705ee18a90 100644 (file)
@@ -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++;
+           }
        }
    }
 
index c3aff208bf18192ea3de698cd53cba03bbea2cab..98211dcb2a7365bc2380d22ab36b803009c94338 100644 (file)
@@ -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)
index 26fca04756daabbcef52da924ce75133b1741c46..f2db9a97bc53ac7ab3dfe2c724f55984eac27d1c 100644 (file)
@@ -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;
index 453d6c889df12864808f88fe6ea131a57276dcaa..ef24a4ef985dc0f4a3cfdde34c3c9b8e60c53f37 100644 (file)
@@ -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 */