Add "--wordwrap on/off" option for CLI columnar modes, qwbox shortcut
FossilOrigin-Name: 10dbc278708cd2cce7fef90738082dbe31750d93e44b5fa5413a9a32dae7703a
This commit is contained in:
parent
5aabdaebd5
commit
cc4d55c9cb
17
manifest
17
manifest
@ -1,5 +1,5 @@
|
||||
C CLI:\sIn\s".mode\scolumn"\soutput,\sif\sany\srow\scontains\sa\snewline\sor\swraps,\sthen\nput\sa\ssingle\sblank\sline\sin\sbetween\seach\spair\sof\srows\sto\sprovide\sadditional\nvisual\sseparately.
|
||||
D 2022-02-01T00:00:08.128
|
||||
C Add\s"--wordwrap\son/off"\soption\sfor\sCLI\scolumnar\smodes,\sqwbox\sshortcut
|
||||
D 2022-02-01T02:50:45.569
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
||||
@ -553,7 +553,7 @@ F src/random.c 097dc8b31b8fba5a9aca1697aeb9fd82078ec91be734c16bffda620ced7ab83c
|
||||
F src/resolve.c 24032ae57aec10df2f3fa2e20be0aae7d256bc704124b76c52d763440c7c0fe9
|
||||
F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92
|
||||
F src/select.c a6d2d4bed279d7fe4fcedaf297eaf6441e8e17c6e3947a32d24d23be52ac02f2
|
||||
F src/shell.c.in 8ae0e33c265c14a6932233b2eb37b090a67a3cb816671da66d26319b1d98cbfd
|
||||
F src/shell.c.in 4f5e0a9f38aa648ca529efb66f338308262b47a72b6c5c95a1f704619fa1aef0
|
||||
F src/sqlite.h.in eaade58049152dac850d57415bcced885ca27ae9582f8aea2cfb7f1db78a521b
|
||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||
F src/sqlite3ext.h 5d54cf13d3406d8eb65d921a0d3c349de6126b732e695e79ecd4830ce86b4f8a
|
||||
@ -1386,7 +1386,7 @@ F test/sharedA.test 49d87ec54ab640fbbc3786ee3c01de94aaa482a3a9f834ad3fe92770eb69
|
||||
F test/sharedB.test 16cc7178e20965d75278f410943109b77b2e645e
|
||||
F test/shared_err.test 32634e404a3317eeb94abc7a099c556a346fdb8fb3858dbe222a4cbb8926a939
|
||||
F test/sharedlock.test 5ede3c37439067c43b0198f580fd374ebf15d304
|
||||
F test/shell1.test ce2f370886645f38fabdde44976c14a004400f166edea8fdd9741079b645fef6
|
||||
F test/shell1.test 1859ba21623b6a804ab2527b2a7c10b54513e8c4e40cec2b462d0e9f082d4fec
|
||||
F test/shell2.test f00a0501c00583cbc46f7510e1d713366326b2b3e63d06d15937284171a8787c
|
||||
F test/shell3.test cb4b835a901742c9719437a89171172ecc4a8823ad97349af8e4e841e6f82566
|
||||
F test/shell4.test 8f6c0fce4abed19a8a7f7262517149812a04caa905d01bdc8f5e92573504b759
|
||||
@ -1942,8 +1942,9 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P 070fae3a09cea675e722340870cb2bee9e1ac96954d3baacfdb7f5400ddb1b20
|
||||
R da80598e94d04369e4a04ce4c1915aa8
|
||||
U drh
|
||||
Z 366282a4b771bc969cd1f7f43a0d9728
|
||||
P fd42f4c304079356358e606dd96d4b84cf211c4334c586118b99fe9ad20e20ea
|
||||
Q +f51a17b6271a8dd7c48725e4ec2df1fde0460866c81c7225dc27216ab389591e
|
||||
R 9664e5ccc659386bbaeacc1cefed4830
|
||||
U larrybr
|
||||
Z c1cf64e5874e5b6ab186498f765ac9eb
|
||||
# Remove this line to create a well-formed Fossil manifest.
|
||||
|
@ -1 +1 @@
|
||||
fd42f4c304079356358e606dd96d4b84cf211c4334c586118b99fe9ad20e20ea
|
||||
10dbc278708cd2cce7fef90738082dbe31750d93e44b5fa5413a9a32dae7703a
|
130
src/shell.c.in
130
src/shell.c.in
@ -1066,6 +1066,16 @@ struct EQPGraph {
|
||||
char zPrefix[100]; /* Graph prefix */
|
||||
};
|
||||
|
||||
/* Parameters affecting columnar mode result display (defaulting together) */
|
||||
typedef struct ColModeOpts {
|
||||
int iWrap; /* In columnar modes, wrap lines reaching this limit */
|
||||
u8 bQuote; /* Quote results for .mode box and table */
|
||||
u8 bWordWrap; /* In columnar modes, wrap at word boundaries */
|
||||
} ColModeOpts;
|
||||
#define ColModeOpts_default { 60, 0, 0 }
|
||||
#define ColModeOpts_default_qbox { 60, 1, 0 }
|
||||
#define ColModeOpts_default_qwbox { 60, 1, 1 }
|
||||
|
||||
/*
|
||||
** State information about the database connection is contained in an
|
||||
** instance of the following structure.
|
||||
@ -1084,8 +1094,7 @@ struct ShellState {
|
||||
u8 eTraceType; /* SHELL_TRACE_* value for type of trace */
|
||||
u8 bSafeMode; /* True to prohibit unsafe operations */
|
||||
u8 bSafeModePersist; /* The long-term value of bSafeMode */
|
||||
u8 bQuote; /* Quote results for .mode box and table */
|
||||
int iWrap; /* Wrap lines this long or longer in some output modes */
|
||||
ColModeOpts cmOpts; /* Option values affecting columnar mode output */
|
||||
unsigned statsOn; /* True to display memory stats before each finalize */
|
||||
unsigned mEqpLines; /* Mask of veritical lines in the EQP output graph */
|
||||
int inputNesting; /* Track nesting level of .read and other redirects */
|
||||
@ -3173,16 +3182,18 @@ static void print_box_row_separator(
|
||||
**
|
||||
** Compute characters to display on the first line of z[]. Stop at the
|
||||
** first \r, \n, or \f. Expand \t into spaces. Return a copy (obtained
|
||||
** from malloc()) of that first line. Write anything to display
|
||||
** on the next line into *pzTail. If this is the last line, write a NULL
|
||||
** into *pzTail.
|
||||
** from malloc()) of that first line, which caller should free sometime.
|
||||
** Write anything to display on the next line into *pzTail. If this is
|
||||
** the last line, write a NULL into *pzTail. (*pzTail is not allocated.)
|
||||
*/
|
||||
static char *translateForDisplayAndDup(
|
||||
const unsigned char *z,
|
||||
const unsigned char **pzTail,
|
||||
int mxWidth
|
||||
int mxWidth,
|
||||
u8 bWordWrap
|
||||
){
|
||||
int i, j, n;
|
||||
int i, j, n; /* in-index, code-skip, code-count */
|
||||
int iLastWhite = 0, nLastWhite = 0;
|
||||
unsigned char *zOut;
|
||||
if( z==0 ){
|
||||
*pzTail = 0;
|
||||
@ -3194,6 +3205,10 @@ static char *translateForDisplayAndDup(
|
||||
while( n<mxWidth ){
|
||||
if( z[i]>=' ' ){
|
||||
n++;
|
||||
if( IsSpace(z[i]) ){
|
||||
iLastWhite = i;
|
||||
nLastWhite = n;
|
||||
}
|
||||
do{ i++; j++; }while( (z[i]&0xc0)==0x80 );
|
||||
continue;
|
||||
}
|
||||
@ -3207,6 +3222,11 @@ static char *translateForDisplayAndDup(
|
||||
}
|
||||
break;
|
||||
}
|
||||
if( bWordWrap && iLastWhite>0 && n>=mxWidth ){
|
||||
/* Will word wrap only if it is requested and can do any good. */
|
||||
mxWidth = nLastWhite;
|
||||
i = iLastWhite;
|
||||
}
|
||||
if( n>=mxWidth && z[i]>=' ' ){
|
||||
*pzTail = &z[i];
|
||||
}else if( z[i]=='\r' && z[i+1]=='\n' ){
|
||||
@ -3312,7 +3332,7 @@ static void exec_prepared_stmt_columnar(
|
||||
azNextLine = sqlite3_malloc64( nColumn*sizeof(char*) );
|
||||
shell_check_oom((void*)azNextLine);
|
||||
memset((void*)azNextLine, 0, nColumn*sizeof(char*) );
|
||||
if( p->bQuote ){
|
||||
if( p->cmOpts.bQuote ){
|
||||
azQuoted = sqlite3_malloc64( nColumn*sizeof(char*) );
|
||||
shell_check_oom(azQuoted);
|
||||
memset(azQuoted, 0, nColumn*sizeof(char*) );
|
||||
@ -3334,11 +3354,15 @@ static void exec_prepared_stmt_columnar(
|
||||
}
|
||||
for(i=0; i<nColumn; i++){
|
||||
const unsigned char *zNotUsed;
|
||||
u8 bw = 0;
|
||||
int wx = p->colWidth[i];
|
||||
if( wx==0 ) wx = p->iWrap;
|
||||
if( wx==0 ){
|
||||
wx = p->cmOpts.iWrap;
|
||||
bw = p->cmOpts.bWordWrap;
|
||||
}
|
||||
if( wx<0 ) wx = -wx;
|
||||
uz = (const unsigned char*)sqlite3_column_name(pStmt,i);
|
||||
azData[i] = translateForDisplayAndDup(uz, &zNotUsed, wx);
|
||||
azData[i] = translateForDisplayAndDup(uz, &zNotUsed, wx, bw);
|
||||
}
|
||||
do{
|
||||
int useNextLine = bNextLine;
|
||||
@ -3353,19 +3377,24 @@ static void exec_prepared_stmt_columnar(
|
||||
abRowDiv[nRow] = 1;
|
||||
nRow++;
|
||||
for(i=0; i<nColumn; i++){
|
||||
u8 bw = 0;
|
||||
int wx = p->colWidth[i];
|
||||
if( wx==0 ) wx = p->iWrap;
|
||||
if( wx==0 ){
|
||||
wx = p->cmOpts.iWrap;
|
||||
bw = p->cmOpts.bWordWrap;
|
||||
}
|
||||
if( wx<0 ) wx = -wx;
|
||||
if( useNextLine ){
|
||||
uz = azNextLine[i];
|
||||
}else if( p->bQuote ){
|
||||
}else if( p->cmOpts.bQuote ){
|
||||
sqlite3_free(azQuoted[i]);
|
||||
azQuoted[i] = quoted_column(pStmt,i);
|
||||
uz = (const unsigned char*)azQuoted[i];
|
||||
}else{
|
||||
uz = (const unsigned char*)sqlite3_column_text(pStmt,i);
|
||||
}
|
||||
azData[nRow*nColumn + i] = translateForDisplayAndDup(uz, &azNextLine[i], wx);
|
||||
azData[nRow*nColumn + i]
|
||||
= translateForDisplayAndDup(uz, &azNextLine[i], wx, bw);
|
||||
if( azNextLine[i] ){
|
||||
bNextLine = 1;
|
||||
abRowDiv[nRow-1] = 0;
|
||||
@ -4278,16 +4307,18 @@ static const char *(azHelp[]) = {
|
||||
" list Values delimited by \"|\"",
|
||||
" markdown Markdown table format",
|
||||
" qbox Shorthand for \"box --width 60 --quote\"",
|
||||
" qwbox Shorthand for \"box --width 60 --wordwrap on --quote\"",
|
||||
" quote Escape answers as for SQL",
|
||||
" table ASCII-art table",
|
||||
" tabs Tab-separated values",
|
||||
" tcl TCL list elements",
|
||||
" OPTIONS: (value for columnar modes only):",
|
||||
" --wrap N Wrap output lines longer than N character",
|
||||
" --quote Quote output text as SQL literals",
|
||||
" --noquote Do not quote output text",
|
||||
" TABLE The name of SQL table used for \"insert\" mode",
|
||||
".nonce STRING Disable safe mode for one command if the nonce matches",
|
||||
" OPTIONS: (for columnar modes or insert mode):",
|
||||
" --wrap N Wrap output lines to no longer than N characters",
|
||||
" --wordwrap B Wrap or not at word boundaries per B (on/off) ",
|
||||
" --quote Quote output text as SQL literals",
|
||||
" --noquote Do not quote output text",
|
||||
" TABLE The name of SQL table used for \"insert\" mode",
|
||||
".nonce STRING Suspend safe mode for one command if nonce matches",
|
||||
".nullvalue STRING Use STRING in place of NULL values",
|
||||
".once ?OPTIONS? ?FILE? Output for the next SQL command only to FILE",
|
||||
" If FILE begins with '|' then open as a pipe",
|
||||
@ -9070,21 +9101,31 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
const char *zMode = 0;
|
||||
const char *zTabname = 0;
|
||||
int i, n2;
|
||||
int bQuoteChng = 0;
|
||||
int bWrapChng = 0;
|
||||
ColModeOpts cmOpts = ColModeOpts_default;
|
||||
for(i=1; i<nArg; i++){
|
||||
const char *z = azArg[i];
|
||||
if( optionMatch(z,"wrap") && i+1<nArg ){
|
||||
p->iWrap = integerValue(azArg[++i]);
|
||||
bWrapChng = 1;
|
||||
cmOpts.iWrap = integerValue(azArg[++i]);
|
||||
}else if( optionMatch(z,"wordwrap") && i+1<nArg ){
|
||||
cmOpts.bWordWrap = (u8)booleanValue(azArg[++i]);
|
||||
}else if( optionMatch(z,"quote") ){
|
||||
p->bQuote = 1;
|
||||
bQuoteChng = 1;
|
||||
cmOpts.bQuote = 1;
|
||||
}else if( optionMatch(z,"noquote") ){
|
||||
p->bQuote = 0;
|
||||
bQuoteChng = 1;
|
||||
cmOpts.bQuote = 0;
|
||||
}else if( zMode==0 ){
|
||||
zMode = z;
|
||||
/* Apply defaults for qbox and qwbox pseudo-modes. If that
|
||||
* overwrites already-set values, user was informed of this.
|
||||
*/
|
||||
if( strcmp(z, "qbox")==0 ){
|
||||
ColModeOpts cmo = ColModeOpts_default_qbox;
|
||||
zMode = "box";
|
||||
cmOpts = cmo;
|
||||
}else if( strcmp(z, "qwbox")==0 ){
|
||||
ColModeOpts cmo = ColModeOpts_default_qwbox;
|
||||
zMode = "box";
|
||||
cmOpts = cmo;
|
||||
}
|
||||
}else if( zTabname==0 ){
|
||||
zTabname = z;
|
||||
}else if( z[0]=='-' ){
|
||||
@ -9092,6 +9133,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
utf8_printf(stderr, "options:\n"
|
||||
" --noquote\n"
|
||||
" --quote\n"
|
||||
" --wordwrap on/off\n"
|
||||
" --wrap N\n");
|
||||
rc = 1;
|
||||
goto meta_command_exit;
|
||||
@ -9105,12 +9147,15 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
if( p->mode==MODE_Column
|
||||
|| (p->mode>=MODE_Markdown && p->mode<=MODE_Box)
|
||||
){
|
||||
raw_printf(p->out, "current output mode: %s --wrap %d --%squote\n",
|
||||
modeDescr[p->mode], p->iWrap, p->bQuote ? "" : "no");
|
||||
raw_printf
|
||||
(p->out,
|
||||
"current output mode: %s --wrap %d --wordwrap %s --%squote\n",
|
||||
modeDescr[p->mode], p->cmOpts.iWrap,
|
||||
p->cmOpts.bWordWrap ? "on" : "off",
|
||||
p->cmOpts.bQuote ? "" : "no");
|
||||
}else{
|
||||
raw_printf(p->out, "current output mode: %s\n", modeDescr[p->mode]);
|
||||
}
|
||||
bWrapChng = bQuoteChng = 1;
|
||||
zMode = modeDescr[p->mode];
|
||||
}
|
||||
n2 = strlen30(zMode);
|
||||
@ -9123,8 +9168,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
p->showHeader = 1;
|
||||
}
|
||||
sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
|
||||
if( !bWrapChng ) p->iWrap = 0;
|
||||
if( !bQuoteChng ) p->bQuote = 0;
|
||||
p->cmOpts = cmOpts;
|
||||
}else if( strncmp(zMode,"list",n2)==0 ){
|
||||
p->mode = MODE_List;
|
||||
sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Column);
|
||||
@ -9155,20 +9199,13 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Record);
|
||||
}else if( strncmp(zMode,"markdown",n2)==0 ){
|
||||
p->mode = MODE_Markdown;
|
||||
if( !bWrapChng ) p->iWrap = 0;
|
||||
if( !bQuoteChng ) p->bQuote = 0;
|
||||
p->cmOpts = cmOpts;
|
||||
}else if( strncmp(zMode,"table",n2)==0 ){
|
||||
p->mode = MODE_Table;
|
||||
if( !bWrapChng ) p->iWrap = 0;
|
||||
if( !bQuoteChng ) p->bQuote = 0;
|
||||
p->cmOpts = cmOpts;
|
||||
}else if( strncmp(zMode,"box",n2)==0 ){
|
||||
p->mode = MODE_Box;
|
||||
if( !bWrapChng ) p->iWrap = 0;
|
||||
if( !bQuoteChng ) p->bQuote = 0;
|
||||
}else if( strcmp(zMode,"qbox")==0 ){
|
||||
p->mode = MODE_Box;
|
||||
if( !bWrapChng ) p->iWrap = 60;
|
||||
if( !bQuoteChng ) p->bQuote = 1;
|
||||
p->cmOpts = cmOpts;
|
||||
}else if( strncmp(zMode,"count",n2)==0 ){
|
||||
p->mode = MODE_Count;
|
||||
}else if( strncmp(zMode,"off",n2)==0 ){
|
||||
@ -9178,7 +9215,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
}else{
|
||||
raw_printf(stderr, "Error: mode should be one of: "
|
||||
"ascii box column csv html insert json line list markdown "
|
||||
"qbox quote table tabs tcl\n");
|
||||
"qbox quote qwbox table tabs tcl\n");
|
||||
rc = 1;
|
||||
}
|
||||
p->cMode = p->mode;
|
||||
@ -10329,8 +10366,11 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
if( p->mode==MODE_Column
|
||||
|| (p->mode>=MODE_Markdown && p->mode<=MODE_Box)
|
||||
){
|
||||
utf8_printf(p->out, "%12.12s: %s --wrap %d --%squote\n", "mode",
|
||||
modeDescr[p->mode], p->iWrap, p->bQuote ? "" : "no");
|
||||
utf8_printf
|
||||
(p->out, "%12.12s: %s --wrap %d --wordwrap %s --%squote\n", "mode",
|
||||
modeDescr[p->mode], p->cmOpts.iWrap,
|
||||
p->cmOpts.bWordWrap ? "on" : "off",
|
||||
p->cmOpts.bQuote ? "" : "no");
|
||||
}else{
|
||||
utf8_printf(p->out, "%12.12s: %s\n","mode", modeDescr[p->mode]);
|
||||
}
|
||||
|
@ -205,10 +205,10 @@ do_test shell1-2.2.4 {
|
||||
} {0 {}}
|
||||
do_test shell1-2.2.5 {
|
||||
catchcmd "test.db" ".mode \"insert FOO"
|
||||
} {1 {Error: mode should be one of: ascii box column csv html insert json line list markdown qbox quote table tabs tcl}}
|
||||
} {1 {Error: mode should be one of: ascii box column csv html insert json line list markdown qbox quote qwbox table tabs tcl}}
|
||||
do_test shell1-2.2.6 {
|
||||
catchcmd "test.db" ".mode \'insert FOO"
|
||||
} {1 {Error: mode should be one of: ascii box column csv html insert json line list markdown qbox quote table tabs tcl}}
|
||||
} {1 {Error: mode should be one of: ascii box column csv html insert json line list markdown qbox quote qwbox table tabs tcl}}
|
||||
|
||||
# check multiple tokens, and quoted tokens
|
||||
do_test shell1-2.3.1 {
|
||||
@ -236,7 +236,7 @@ do_test shell1-2.3.7 {
|
||||
# check quoted args are unquoted
|
||||
do_test shell1-2.4.1 {
|
||||
catchcmd "test.db" ".mode FOO"
|
||||
} {1 {Error: mode should be one of: ascii box column csv html insert json line list markdown qbox quote table tabs tcl}}
|
||||
} {1 {Error: mode should be one of: ascii box column csv html insert json line list markdown qbox quote qwbox table tabs tcl}}
|
||||
do_test shell1-2.4.2 {
|
||||
catchcmd "test.db" ".mode csv"
|
||||
} {0 {}}
|
||||
@ -437,7 +437,7 @@ do_test shell1-3.13.1 {
|
||||
} {0 {current output mode: list}}
|
||||
do_test shell1-3.13.2 {
|
||||
catchcmd "test.db" ".mode FOO"
|
||||
} {1 {Error: mode should be one of: ascii box column csv html insert json line list markdown qbox quote table tabs tcl}}
|
||||
} {1 {Error: mode should be one of: ascii box column csv html insert json line list markdown qbox quote qwbox table tabs tcl}}
|
||||
do_test shell1-3.13.3 {
|
||||
catchcmd "test.db" ".mode csv"
|
||||
} {0 {}}
|
||||
|
Loading…
Reference in New Issue
Block a user