From: drh <> Date: Thu, 23 Apr 2026 15:05:46 +0000 (+0000) Subject: New CLI prompt escape sequences: /r, /A, /v, /V, and /D../D. X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=ed95a9d1034a01176ce7980b13b1758db852b35a;p=thirdparty%2Fsqlite.git New CLI prompt escape sequences: /r, /A, /v, /V, and /D../D. FossilOrigin-Name: e7c7acd1a4e5cb0f8e68f119352480c1aa9dd3c2b289c92f88e9e697a2e440e0 --- diff --git a/manifest b/manifest index 933c581773..445e8014d5 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sharmless\scompiler\swarning. -D 2026-04-23T14:49:21.443 +C New\sCLI\sprompt\sescape\ssequences:\s\s/r,\s/A,\s/v,\s/V,\sand\s/D../D. +D 2026-04-23T15:05:46.973 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -736,7 +736,7 @@ F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c F src/resolve.c 928ff887f2a7c64275182060d94d06fdddbe32226c569781cf7e7edc6f58d7fd F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97 F src/select.c 4c05cde130f26991b7411d8c6809e0630625e18078742c963a047b4b9cc01d49 -F src/shell.c.in 20e359ac77d07e5dc636e526ef85da692384228e7997d7ec28568125a028a8f7 +F src/shell.c.in ae78db9539da5f8ada1ac2761b77b865e56ec2ba9145461e56de6eb762aeef18 F src/sqlite.h.in 39d2e09114d2bdb7afd998f4a469c8f8cd065f8093835a7d0422f260fc78fb4f F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479 F src/sqlite3ext.h 9788c301f95370fa30e808861f1d2e6f022a816ddbe2a4f67486784c1b31db2e @@ -1624,7 +1624,7 @@ F test/sharedA.test 64bdd21216dda2c6a3bd3475348ccdc108160f34682c97f2f51c19fc0e21 F test/sharedB.test 1a84863d7a2204e0d42f2e1606577c5e92e4473fa37ea0f5bdf829e4bf8ee707 F test/shared_err.test 32634e404a3317eeb94abc7a099c556a346fdb8fb3858dbe222a4cbb8926a939 F test/sharedlock.test 5ede3c37439067c43b0198f580fd374ebf15d304 -F test/shell-prompt.sql 43ed98433bfde83171b5d06c300525154f4cab9230570a326ca606aaef351db6 +F test/shell-prompt.sql c3517832b8570025619707bf5883847f6894e958bd92a5e0d2e2f157f768c2a1 F test/shell1.test c84eff209f93ad17ccdf7e1634969fc8231684254edeb21d9b13d67c3179cdb5 F test/shell2.test dc541d2681503e55466a24d35a4cbf8ca5b90b8fcdef37fc4db07373a67d31d3 F test/shell3.test 91efdd545097a61a1f72cf79c9ad5b49da080f3f10282eaf4c3c272cd1012db2 @@ -2203,8 +2203,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh a554d13f6e5cf3760f041b87939e3d616ec6961859c3245e8ef701d1eafc2ca2 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 3fa0500b964869c45f7b49717680b791049f7cd8c47a06a337dd22351d2002f9 -R 71b891a74b506696ae0597a74a57a86c +P 706373dcbe43752cf21604f278f96fb3015a36089ad64f069bb3a64bc526d137 +R d97f1546f6e3e8815d53cf5cfb6143b0 U drh -Z 6b30685bdb9a615afb7f74468ca1c1e4 +Z b0844759ca50f5075fba7f38fd3b6ac9 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index c05a2d1eea..3d05c96a11 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -706373dcbe43752cf21604f278f96fb3015a36089ad64f069bb3a64bc526d137 +e7c7acd1a4e5cb0f8e68f119352480c1aa9dd3c2b289c92f88e9e697a2e440e0 diff --git a/src/shell.c.in b/src/shell.c.in index 6217223e22..52233de295 100644 --- a/src/shell.c.in +++ b/src/shell.c.in @@ -921,12 +921,25 @@ static char *local_getline(char *zLine, FILE *in){ ** The default prompts. */ #ifndef SQLITE_PS1 -# define SQLITE_PS1 "SQLite /f> " +# define SQLITE_PS1 "/A /f> " #endif #ifndef SQLITE_PS2 # define SQLITE_PS2 "/B.../H> " #endif +/* +** Redefinable escape value for the prompt string. +*/ +#ifndef SQLITE_PS_APP +# define SQLITE_PS_APP "SQLite" /* Expansion for /A */ +#endif +#ifndef SQLITE_PS_RELEASE +# define SQLITE_PS_VERSION_RELEASE shellRelease() /* Expansion for /v */ +#endif +#ifndef SQLITE_PS_PATCH +# define SQLITE_PS_VERSION_PATCH shellPatch() /* Expansion for /V */ +#endif + /* ** Return the raw (unexpanded) prompt string. This will be the ** first of the following that exist: @@ -976,6 +989,20 @@ static const char *prompt_filename(ShellState *p){ return zFN; } +/* +** Return strings appropriate to substitute for /V and /v +*/ +static const char *shellPatch(void){ return sqlite3_libversion(); } +static const char *shellRelease(void){ + static char zRel[16]; + const char *zF = shellPatch(); + const char *zD = strrchr(zF,'.'); + int i = (int)(zD - zF); + memcpy(zRel,zF,i); + zRel[i] = 0; + return zRel; +} + /* ** Expand escapes in the given input prompt string. Return the ** expanded prompt in memory obtained from sqlite3_malloc(). The @@ -997,12 +1024,13 @@ static char *expand_prompt( sqlite3_str *pOut = sqlite3_str_new(0); int i; char c; - int onoff = 1; + unsigned int mOff = 0; /* Bitmask of FALSE for if/then/else */ int idxSpace = -1; + int iDate = -1; for(i=0; zPrompt[i]; i++){ if( zPrompt[i]!='/' ) continue; if( i>0 ){ - if( onoff ) sqlite3_str_append(pOut, zPrompt, i); + if( !mOff ) sqlite3_str_append(pOut, zPrompt, i); zPrompt += i; i = 0; } @@ -1025,14 +1053,36 @@ static char *expand_prompt( while( i<=2 && zPrompt[i+1]>='0' && zPrompt[i+1]<='7' ){ v = v*8 + zPrompt[++i] - '0'; } - if( onoff ) sqlite3_str_appendchar(pOut, 1, v); + if( !mOff ) sqlite3_str_appendchar(pOut, 1, v); zPrompt += i+1; i = -1; continue; } if( c=='e' ){ /* /e is shorthand for /033 which is U+001B "Escape" */ - if( onoff ) sqlite3_str_append(pOut, "\033", 1); + if( !mOff ) sqlite3_str_append(pOut, "\033", 1); + zPrompt += 2; + i = -1; + continue; + } + if( c=='A' ){ + /* /A expands to the application name */ + if( !mOff ) sqlite3_str_appendall(pOut, SQLITE_PS_APP); + zPrompt += 2; + i = -1; + continue; + } + if( c=='V' ){ + /* /V expands to the version number with patch level */ + if( !mOff ) sqlite3_str_appendall(pOut, SQLITE_PS_VERSION_PATCH); + zPrompt += 2; + i = -1; + continue; + } + if( c=='v' ){ + /* /v expands to the version number without the patch level */ + /* /V expands to the version number with patch level */ + if( !mOff ) sqlite3_str_appendall(pOut, SQLITE_PS_VERSION_RELEASE); zPrompt += 2; i = -1; continue; @@ -1052,22 +1102,29 @@ static char *expand_prompt( ** .prompt '/e[1;/x31/:34/;m~f>/e[0m ' */ if( c==':' ){ - /* toggle display on/off */ - onoff = !onoff; + /* ELSE: toggle display on/off */ + mOff ^= 1; zPrompt += 2; i = -1; continue; } if( c==';' ){ - /* Turn display on */ - onoff = 1; + /* ENDIF: Turn display on */ + mOff >>= 1; zPrompt += 2; i = -1; continue; } if( c=='x' ){ /* /x turns display off not in a transaction, on if in txn */ - onoff = p->db && !sqlite3_get_autocommit(p->db); + mOff = (mOff<<1) | (p->db==0 || sqlite3_get_autocommit(p->db)!=0); + zPrompt += 2; + i = -1; + continue; + } + if( c=='r' ){ + /* /r turns display off if database is read/write, on if read-only */ + mOff = (mOff<<1) | (p->db==0 || sqlite3_db_readonly(p->db,0)==0); zPrompt += 2; i = -1; continue; @@ -1077,7 +1134,7 @@ static char *expand_prompt( /* /f becomes the tail of the database filename */ /* /F becomes the full pathname */ /* /~ becomes the full pathname relative to $HOME */ - if( onoff ){ + if( !mOff ){ const char *zFN = prompt_filename(p); if( c=='f' ){ #ifdef _WIN32 @@ -1106,7 +1163,7 @@ static char *expand_prompt( if( c=='H' ){ /* /H becomes text needed to terminate current input */ - if( onoff ){ + if( !mOff ){ sqlite3_int64 R = zPrior ? sqlite3_incomplete(zPrior) : 0; int cc = (R>>16)&0xff; int nParen = R>>32; @@ -1140,18 +1197,44 @@ static char *expand_prompt( /* /B is a no-op for the main prompt. For the continuation prompt, ** /B expands to zero or more spaces to make the continuation prompt ** at least as wide as the main prompt. */ - if( onoff ) idxSpace = sqlite3_str_length(pOut); + if( !mOff ) idxSpace = sqlite3_str_length(pOut); + zPrompt += 2; + i = -1; + continue; + } + + if( c=='D' ){ + /* /D.../D replaces all of the text between the two /D escapes with + ** the result from strftime(). */ + if( iDate<0 ){ + iDate = sqlite3_str_length(pOut); + }else{ + if( !mOff ){ + time_t now; + char zBuf[200]; + zBuf[0] = 0; + time(&now); + strftime(zBuf, sizeof(zBuf)-1, sqlite3_str_value(pOut)+iDate, + localtime(&now)); + zBuf[199] = 0; + sqlite3_str_truncate(pOut, iDate); + sqlite3_str_appendall(pOut, zBuf); + } + iDate = -1; + } zPrompt += 2; i = -1; continue; } - /* No match to a known escape. Generate an error. */ - if( onoff ) sqlite3_str_appendf(pOut,"UNKNOWN(\"/%c\")",c); + /* No match to a known escape. Generate an error. The mOff flag + ** is ignored for this output, so that errors appear even if they + ** are in an unused branch. */ + sqlite3_str_appendf(pOut,"UNKNOWN(\"/%c\")",c); zPrompt += 2; i = -1; } - if( i>0 && onoff ){ + if( i>0 && !mOff ){ sqlite3_str_append(pOut, zPrompt, i); } diff --git a/test/shell-prompt.sql b/test/shell-prompt.sql index c1f3bfa6cf..ebb0011475 100644 --- a/test/shell-prompt.sql +++ b/test/shell-prompt.sql @@ -29,7 +29,7 @@ .testcase 110 .prompt --show .check < ' +Main prompt: '/A /f> ' Continuation: '/B.../H> ' END .testcase 111 @@ -48,7 +48,7 @@ END .testcase 113 .prompt --reset --show .check < ' +Main prompt: '/A /f> ' Continuation: '/B.../H> ' END @@ -137,4 +137,12 @@ SELECT shell_prompt_test(NULL); SELECT shell_prompt_test(NULL); .check 'SQLite test.db> '; -.testcase +.testcase 3000 +SELECT shell_prompt_test('(/A-/V)'); +.check --glob '(SQLite-3.#.#)' +.testcase 3001 +SELECT shell_prompt_test('(/A-/v)'); +.check --glob '(SQLite-3.#)' +.testcase 3002 +SELECT shell_prompt_test('(/A-/D%Y-%m-%dT%H:%M:%S/D)'); +.check --glob '(SQLite-20#-#-#T#:#:#)'