Fossil SCM

Further help improvemens. Add the "fossil apropos" command for searching help. "fossil help options" and "fossil help COMMAND options" give sensible results.

drh 2025-02-28 20:22 trunk
Commit 90e564f213d38efcc903deb87428a668df3979231b40f78527c2ca664a2f473d
3 files changed +123 -49 +39 +13 -2
+123 -49
--- src/dispatch.c
+++ src/dispatch.c
@@ -1079,49 +1079,94 @@
10791079
const char *z, /* Full original help text */
10801080
Blob *pOut, /* Write simplified help text here */
10811081
const char *zTopic, /* TOPIC */
10821082
const char *zSubtopic /* SUBTOPIC */
10831083
){
1084
- Blob in, line;
1084
+ Blob in, line, subsection;
10851085
int n = 0;
1086
- char *zGlob = mprintf("> fossil %s *%s*", zTopic, zSubtopic);
1086
+ size_t nSub; /* Length of zSubtopic */
1087
+ char *zQTop = re_quote(zTopic);
1088
+ char *zQSub = re_quote(zSubtopic);
1089
+ char *zPattern = mprintf("> fossil %s .*\\b%s\\b", zQTop, zQSub);
1090
+ ReCompiled *pRe = 0;
10871091
1092
+ fossil_free(zQTop);
1093
+ fossil_free(zQSub);
1094
+ re_compile(&pRe, zPattern, 0);
1095
+ fossil_free(zPattern);
10881096
blob_init(&in, z, -1);
10891097
while( blob_line(&in, &line) ){
1090
- if( sqlite3_strglob(zGlob, blob_str(&line))==0 ){
1098
+ if( re_match(pRe, (unsigned char*)blob_buffer(&line), blob_strlen(&line)) ){
10911099
blob_appendb(pOut, &line);
10921100
n++;
1093
- while( blob_line(&in, &line) && blob_str(&line)[0]!='>' ){
1101
+ while( blob_line(&in, &line) && blob_buffer(&line)[0]!='>' ){
10941102
blob_appendb(pOut, &line);
10951103
n++;
10961104
}
10971105
break;
10981106
}
10991107
}
1100
- fossil_free(zGlob);
1108
+ blob_reset(&line);
1109
+ re_free(pRe);
11011110
if( n ){
11021111
blob_trim(pOut);
11031112
blob_reset(&in);
11041113
return n;
11051114
}
11061115
1107
- /* If no subtop name zSubtopic if found, try again for any LIKE
1108
- ** pattern match of zSubtopic.
1116
+ /* No subtopic found. If zSubtopic is "options", print all command-line
1117
+ ** options in the help text.
1118
+ */
1119
+ if( fossil_strcmp("options",zSubtopic)==0 ){
1120
+ blob_rewind(&in);
1121
+ blob_init(&subsection, 0, 0);
1122
+ re_compile(&pRe, "^ +-.* ", 0);
1123
+ while( blob_line(&in, &line) ){
1124
+ size_t len = blob_strlen(&line);
1125
+ if( re_match(pRe, (unsigned char*)blob_buffer(&line), (int)len) ){
1126
+ if( blob_strlen(&subsection) && blob_buffer(&line)[0]!='>' ){
1127
+ blob_appendb(pOut, &subsection);
1128
+ blob_reset(&subsection);
1129
+ }
1130
+ blob_appendb(pOut, &line);
1131
+ n++;
1132
+ }else if( len>9 && strncmp(blob_buffer(&line),"> fossil ",9)==0 ){
1133
+ subsection = line;
1134
+ }
1135
+ }
1136
+ re_free(pRe);
1137
+ if( n ){
1138
+ blob_trim(pOut);
1139
+ blob_reset(&in);
1140
+ return n;
1141
+ }
1142
+ }
1143
+
1144
+
1145
+ /* If no subtopic name zSubtopic if found, try to match any text.
11091146
*/
11101147
blob_rewind(&in);
1111
- if( zSubtopic[0]=='/' && zSubtopic[1]!=0 ) zSubtopic++;
1112
- zGlob = mprintf("%%%s%%", zSubtopic);
1148
+ blob_init(&subsection, 0, 0);
1149
+ nSub = (int)strlen(zSubtopic);
11131150
while( blob_line(&in, &line) ){
1114
- if( sqlite3_strlike(zGlob, blob_str(&line),0)==0 ){
1151
+ size_t len = blob_strlen(&line);
1152
+ if( memmem(blob_buffer(&line), len, zSubtopic, nSub)!=0 ){
1153
+ if( blob_strlen(&subsection) && blob_buffer(&line)[0]!='>' ){
1154
+ blob_appendb(pOut, &subsection);
1155
+ blob_reset(&subsection);
1156
+ }
11151157
blob_appendb(pOut, &line);
11161158
n++;
1159
+ }else if( len>9 && strncmp(blob_buffer(&line),"> fossil ",9)==0 ){
1160
+ subsection = line;
11171161
}
11181162
}
1119
- fossil_free(zGlob);
11201163
blob_reset(&in);
11211164
if( n ){
11221165
blob_trim(pOut);
1166
+ }else{
1167
+ blob_reset(pOut);
11231168
}
11241169
return n;
11251170
}
11261171
11271172
/*
@@ -1145,11 +1190,11 @@
11451190
int n = 0;
11461191
11471192
re_compile(&pRe, "^(Usage: | *[Oo]r: +%fossi |> fossil )", 0);
11481193
blob_init(&in, z, -1);
11491194
while( blob_line(&in, &line) ){
1150
- if( re_match(pRe, (unsigned char*)blob_str(&line), blob_strlen(&line)) ){
1195
+ if( re_match(pRe, (unsigned char*)blob_buffer(&line), blob_strlen(&line)) ){
11511196
blob_appendb(pOut, &line);
11521197
n++;
11531198
}
11541199
}
11551200
re_free(pRe);
@@ -1254,24 +1299,44 @@
12541299
** for "fossil help --usage COMMAND [SUBCOMMAND]"
12551300
*/
12561301
void usage_cmd(void){
12571302
help_cmd();
12581303
}
1304
+
1305
+/*
1306
+** COMMAND: apropos
1307
+**
1308
+** Usage: %fossil apropos KEYWORD ...
1309
+**
1310
+** Search the built-in help pages for Fossil for topics that
1311
+** match the KEYWORD(s)
1312
+*/
1313
+void usage_apropos(void){
1314
+ char **azNewArgv = fossil_malloc( (g.argc+2)*sizeof(char*) );
1315
+ memcpy(azNewArgv, g.argv, g.argc);
1316
+ azNewArgv[0] = g.argv[0];
1317
+ azNewArgv[1] = "apropos";
1318
+ azNewArgv[2] = "-h";
1319
+ memcpy(&azNewArgv[3], &g.argv[2], (g.argc-2) * sizeof(char*));
1320
+ g.argc++;
1321
+ azNewArgv[g.argc] = 0;
1322
+ g.argv = azNewArgv;
1323
+ search_cmd();
1324
+}
12591325
12601326
/*
12611327
** COMMAND: help
12621328
**
1263
-** Usage: %fossil help [OPTIONS] [TOPIC] [SUBCOMMAND|PATTERN]
1329
+** Usage: %fossil help [OPTIONS] [TOPIC] [SUBCOMMAND|options|PATTERN]
12641330
**
12651331
** Display information on how to use TOPIC, which may be a command, webpage, or
12661332
** setting. Webpage names begin with "/". If TOPIC is omitted, a list of
12671333
** topics is returned. If there is an extra argument after TOPIC it is either
12681334
** the name of a subcommand, in which case only the help text for that one
1269
-** subcommand is show, or it is a LIKE pattern to search for, in which case all
1270
-** lines of text that match that pattern are returned. If the search pattern
1271
-** starts with "-", prepend "/" so that it will not be interpreted as an
1272
-** option to the help command itself.
1335
+** subcommand is shown, or it is the keyword "options" which displays all
1336
+** command-line options for TOPIC, or it is a text pattern which causes all
1337
+** lines of the help text that match that pattern to be shown.
12731338
**
12741339
** The following options can be used when TOPIC is omitted:
12751340
**
12761341
** -a|--all List both common and auxiliary commands
12771342
** -e|--everything List all help on all topics
@@ -1362,58 +1427,67 @@
13621427
verify_all_options();
13631428
if( g.argc<3 ){
13641429
z = g.argv[0];
13651430
fossil_print(
13661431
"Usage: %s help TOPIC\n"
1367
- "Try \"%s help help\" or \"%s help -a\" for more options\n"
1368
- "Frequently used commands:\n",
1369
- z, z, z);
1432
+ "Things to try:\n\n"
1433
+ " %s help help\n"
1434
+ " %s help options\n"
1435
+ " %s help -a\n"
1436
+ " %s apropos TOPIC\n\n"
1437
+ "Other common values for TOPIC:\n\n",
1438
+ z, z, z, z, z);
13701439
command_list(CMDFLAG_1ST_TIER,verboseFlag,useHtml);
13711440
if( !verboseFlag ) version_cmd();
13721441
return;
13731442
}
13741443
zTopic = g.argv[2];
13751444
zSubtopic = g.argc>=4 ? g.argv[3] : 0;
13761445
isPage = ('/' == zTopic[0]) ? 1 : 0;
1377
- if(isPage){
1446
+ if( isPage ){
13781447
zCmdOrPage = "page";
13791448
}else if( commandsFlag ){
13801449
mask = CMDFLAG_COMMAND;
13811450
zCmdOrPage = "command";
13821451
}else{
13831452
zCmdOrPage = "command or setting";
13841453
}
1385
- rc = dispatch_name_search(g.argv[2], mask|CMDFLAG_PREFIX, &pCmd);
1386
- if( rc ){
1387
- int i, n;
1388
- const char *az[5];
1389
- if( rc==1 ){
1390
- fossil_print("unknown %s: %s\n", zCmdOrPage, g.argv[2]);
1391
- }else{
1392
- fossil_print("ambiguous %s prefix: %s\n",
1393
- zCmdOrPage, g.argv[2]);
1394
- }
1395
- fossil_print("Did you mean one of these TOPICs:\n");
1396
- n = dispatch_approx_match(g.argv[2], 5, az);
1397
- for(i=0; i<n; i++){
1398
- fossil_print(" * %s\n", az[i]);
1399
- }
1400
- fossil_print("Other commands to try:\n");
1401
- fossil_print(" fossil search -h PATTERN ;# search all help text\n");
1402
- fossil_print(" fossil help -a ;# show all commands\n");
1403
- fossil_print(" fossil help -w ;# show all web-pages\n");
1404
- fossil_print(" fossil help -s ;# show all settings\n");
1405
- fossil_print(" fossil help -o ;# show global options\n");
1406
- return;
1454
+ if( fossil_strcmp(zTopic,"options")==0 ){
1455
+ z = zOptions;
1456
+ pCmd = 0;
1457
+ }else{
1458
+ rc = dispatch_name_search(g.argv[2], mask|CMDFLAG_PREFIX, &pCmd);
1459
+ if( rc ){
1460
+ int i, n;
1461
+ const char *az[5];
1462
+ if( rc==1 ){
1463
+ fossil_print("unknown %s: %s\n", zCmdOrPage, g.argv[2]);
1464
+ }else{
1465
+ fossil_print("ambiguous %s prefix: %s\n",
1466
+ zCmdOrPage, g.argv[2]);
1467
+ }
1468
+ fossil_print("Did you mean one of these TOPICs:\n");
1469
+ n = dispatch_approx_match(g.argv[2], 5, az);
1470
+ for(i=0; i<n; i++){
1471
+ fossil_print(" * %s\n", az[i]);
1472
+ }
1473
+ fossil_print("Other commands to try:\n");
1474
+ fossil_print(" fossil apropos PATTERN ;# search all help text\n");
1475
+ fossil_print(" fossil help -a ;# show all commands\n");
1476
+ fossil_print(" fossil help -w ;# show all web-pages\n");
1477
+ fossil_print(" fossil help -s ;# show all settings\n");
1478
+ fossil_print(" fossil help -o ;# show global options\n");
1479
+ return;
1480
+ }
1481
+ z = pCmd->zHelp;
1482
+ if( z==0 ){
1483
+ fossil_fatal("no help available for the %s %s",
1484
+ pCmd->zName, zCmdOrPage);
1485
+ }
14071486
}
14081487
blob_init(&subtext1, 0, 0);
14091488
blob_init(&subtext2, 0, 0);
1410
- z = pCmd->zHelp;
1411
- if( z==0 ){
1412
- fossil_fatal("no help available for the %s %s",
1413
- pCmd->zName, zCmdOrPage);
1414
- }
14151489
if( zSubtopic!=0 ){
14161490
if( simplify_to_subtopic(z, &subtext1, zTopic, zSubtopic) ){
14171491
z = blob_str(&subtext1);
14181492
}else{
14191493
fossil_print("No subtopic \"%s\" for \"%s\".\n", zTopic, zSubtopic);
@@ -1423,11 +1497,11 @@
14231497
}
14241498
}
14251499
if( bUsage && simplify_to_usage(z, &subtext2, zTopic) ){
14261500
z = blob_str(&subtext2);
14271501
}
1428
- if( pCmd->eCmdFlags & CMDFLAG_SETTING ){
1502
+ if( pCmd && pCmd->eCmdFlags & CMDFLAG_SETTING ){
14291503
const Setting *pSetting = db_find_setting(pCmd->zName, 0);
14301504
char *zDflt = 0;
14311505
if( pSetting!=0 && pSetting->def!=0 && *pSetting->def!=0 ){
14321506
zDflt = mprintf(" (default: %s)", pSetting->def);
14331507
}
14341508
--- src/dispatch.c
+++ src/dispatch.c
@@ -1079,49 +1079,94 @@
1079 const char *z, /* Full original help text */
1080 Blob *pOut, /* Write simplified help text here */
1081 const char *zTopic, /* TOPIC */
1082 const char *zSubtopic /* SUBTOPIC */
1083 ){
1084 Blob in, line;
1085 int n = 0;
1086 char *zGlob = mprintf("> fossil %s *%s*", zTopic, zSubtopic);
 
 
 
 
1087
 
 
 
 
1088 blob_init(&in, z, -1);
1089 while( blob_line(&in, &line) ){
1090 if( sqlite3_strglob(zGlob, blob_str(&line))==0 ){
1091 blob_appendb(pOut, &line);
1092 n++;
1093 while( blob_line(&in, &line) && blob_str(&line)[0]!='>' ){
1094 blob_appendb(pOut, &line);
1095 n++;
1096 }
1097 break;
1098 }
1099 }
1100 fossil_free(zGlob);
 
1101 if( n ){
1102 blob_trim(pOut);
1103 blob_reset(&in);
1104 return n;
1105 }
1106
1107 /* If no subtop name zSubtopic if found, try again for any LIKE
1108 ** pattern match of zSubtopic.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1109 */
1110 blob_rewind(&in);
1111 if( zSubtopic[0]=='/' && zSubtopic[1]!=0 ) zSubtopic++;
1112 zGlob = mprintf("%%%s%%", zSubtopic);
1113 while( blob_line(&in, &line) ){
1114 if( sqlite3_strlike(zGlob, blob_str(&line),0)==0 ){
 
 
 
 
 
1115 blob_appendb(pOut, &line);
1116 n++;
 
 
1117 }
1118 }
1119 fossil_free(zGlob);
1120 blob_reset(&in);
1121 if( n ){
1122 blob_trim(pOut);
 
 
1123 }
1124 return n;
1125 }
1126
1127 /*
@@ -1145,11 +1190,11 @@
1145 int n = 0;
1146
1147 re_compile(&pRe, "^(Usage: | *[Oo]r: +%fossi |> fossil )", 0);
1148 blob_init(&in, z, -1);
1149 while( blob_line(&in, &line) ){
1150 if( re_match(pRe, (unsigned char*)blob_str(&line), blob_strlen(&line)) ){
1151 blob_appendb(pOut, &line);
1152 n++;
1153 }
1154 }
1155 re_free(pRe);
@@ -1254,24 +1299,44 @@
1254 ** for "fossil help --usage COMMAND [SUBCOMMAND]"
1255 */
1256 void usage_cmd(void){
1257 help_cmd();
1258 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1259
1260 /*
1261 ** COMMAND: help
1262 **
1263 ** Usage: %fossil help [OPTIONS] [TOPIC] [SUBCOMMAND|PATTERN]
1264 **
1265 ** Display information on how to use TOPIC, which may be a command, webpage, or
1266 ** setting. Webpage names begin with "/". If TOPIC is omitted, a list of
1267 ** topics is returned. If there is an extra argument after TOPIC it is either
1268 ** the name of a subcommand, in which case only the help text for that one
1269 ** subcommand is show, or it is a LIKE pattern to search for, in which case all
1270 ** lines of text that match that pattern are returned. If the search pattern
1271 ** starts with "-", prepend "/" so that it will not be interpreted as an
1272 ** option to the help command itself.
1273 **
1274 ** The following options can be used when TOPIC is omitted:
1275 **
1276 ** -a|--all List both common and auxiliary commands
1277 ** -e|--everything List all help on all topics
@@ -1362,58 +1427,67 @@
1362 verify_all_options();
1363 if( g.argc<3 ){
1364 z = g.argv[0];
1365 fossil_print(
1366 "Usage: %s help TOPIC\n"
1367 "Try \"%s help help\" or \"%s help -a\" for more options\n"
1368 "Frequently used commands:\n",
1369 z, z, z);
 
 
 
 
1370 command_list(CMDFLAG_1ST_TIER,verboseFlag,useHtml);
1371 if( !verboseFlag ) version_cmd();
1372 return;
1373 }
1374 zTopic = g.argv[2];
1375 zSubtopic = g.argc>=4 ? g.argv[3] : 0;
1376 isPage = ('/' == zTopic[0]) ? 1 : 0;
1377 if(isPage){
1378 zCmdOrPage = "page";
1379 }else if( commandsFlag ){
1380 mask = CMDFLAG_COMMAND;
1381 zCmdOrPage = "command";
1382 }else{
1383 zCmdOrPage = "command or setting";
1384 }
1385 rc = dispatch_name_search(g.argv[2], mask|CMDFLAG_PREFIX, &pCmd);
1386 if( rc ){
1387 int i, n;
1388 const char *az[5];
1389 if( rc==1 ){
1390 fossil_print("unknown %s: %s\n", zCmdOrPage, g.argv[2]);
1391 }else{
1392 fossil_print("ambiguous %s prefix: %s\n",
1393 zCmdOrPage, g.argv[2]);
1394 }
1395 fossil_print("Did you mean one of these TOPICs:\n");
1396 n = dispatch_approx_match(g.argv[2], 5, az);
1397 for(i=0; i<n; i++){
1398 fossil_print(" * %s\n", az[i]);
1399 }
1400 fossil_print("Other commands to try:\n");
1401 fossil_print(" fossil search -h PATTERN ;# search all help text\n");
1402 fossil_print(" fossil help -a ;# show all commands\n");
1403 fossil_print(" fossil help -w ;# show all web-pages\n");
1404 fossil_print(" fossil help -s ;# show all settings\n");
1405 fossil_print(" fossil help -o ;# show global options\n");
1406 return;
 
 
 
 
 
 
 
 
 
 
1407 }
1408 blob_init(&subtext1, 0, 0);
1409 blob_init(&subtext2, 0, 0);
1410 z = pCmd->zHelp;
1411 if( z==0 ){
1412 fossil_fatal("no help available for the %s %s",
1413 pCmd->zName, zCmdOrPage);
1414 }
1415 if( zSubtopic!=0 ){
1416 if( simplify_to_subtopic(z, &subtext1, zTopic, zSubtopic) ){
1417 z = blob_str(&subtext1);
1418 }else{
1419 fossil_print("No subtopic \"%s\" for \"%s\".\n", zTopic, zSubtopic);
@@ -1423,11 +1497,11 @@
1423 }
1424 }
1425 if( bUsage && simplify_to_usage(z, &subtext2, zTopic) ){
1426 z = blob_str(&subtext2);
1427 }
1428 if( pCmd->eCmdFlags & CMDFLAG_SETTING ){
1429 const Setting *pSetting = db_find_setting(pCmd->zName, 0);
1430 char *zDflt = 0;
1431 if( pSetting!=0 && pSetting->def!=0 && *pSetting->def!=0 ){
1432 zDflt = mprintf(" (default: %s)", pSetting->def);
1433 }
1434
--- src/dispatch.c
+++ src/dispatch.c
@@ -1079,49 +1079,94 @@
1079 const char *z, /* Full original help text */
1080 Blob *pOut, /* Write simplified help text here */
1081 const char *zTopic, /* TOPIC */
1082 const char *zSubtopic /* SUBTOPIC */
1083 ){
1084 Blob in, line, subsection;
1085 int n = 0;
1086 size_t nSub; /* Length of zSubtopic */
1087 char *zQTop = re_quote(zTopic);
1088 char *zQSub = re_quote(zSubtopic);
1089 char *zPattern = mprintf("> fossil %s .*\\b%s\\b", zQTop, zQSub);
1090 ReCompiled *pRe = 0;
1091
1092 fossil_free(zQTop);
1093 fossil_free(zQSub);
1094 re_compile(&pRe, zPattern, 0);
1095 fossil_free(zPattern);
1096 blob_init(&in, z, -1);
1097 while( blob_line(&in, &line) ){
1098 if( re_match(pRe, (unsigned char*)blob_buffer(&line), blob_strlen(&line)) ){
1099 blob_appendb(pOut, &line);
1100 n++;
1101 while( blob_line(&in, &line) && blob_buffer(&line)[0]!='>' ){
1102 blob_appendb(pOut, &line);
1103 n++;
1104 }
1105 break;
1106 }
1107 }
1108 blob_reset(&line);
1109 re_free(pRe);
1110 if( n ){
1111 blob_trim(pOut);
1112 blob_reset(&in);
1113 return n;
1114 }
1115
1116 /* No subtopic found. If zSubtopic is "options", print all command-line
1117 ** options in the help text.
1118 */
1119 if( fossil_strcmp("options",zSubtopic)==0 ){
1120 blob_rewind(&in);
1121 blob_init(&subsection, 0, 0);
1122 re_compile(&pRe, "^ +-.* ", 0);
1123 while( blob_line(&in, &line) ){
1124 size_t len = blob_strlen(&line);
1125 if( re_match(pRe, (unsigned char*)blob_buffer(&line), (int)len) ){
1126 if( blob_strlen(&subsection) && blob_buffer(&line)[0]!='>' ){
1127 blob_appendb(pOut, &subsection);
1128 blob_reset(&subsection);
1129 }
1130 blob_appendb(pOut, &line);
1131 n++;
1132 }else if( len>9 && strncmp(blob_buffer(&line),"> fossil ",9)==0 ){
1133 subsection = line;
1134 }
1135 }
1136 re_free(pRe);
1137 if( n ){
1138 blob_trim(pOut);
1139 blob_reset(&in);
1140 return n;
1141 }
1142 }
1143
1144
1145 /* If no subtopic name zSubtopic if found, try to match any text.
1146 */
1147 blob_rewind(&in);
1148 blob_init(&subsection, 0, 0);
1149 nSub = (int)strlen(zSubtopic);
1150 while( blob_line(&in, &line) ){
1151 size_t len = blob_strlen(&line);
1152 if( memmem(blob_buffer(&line), len, zSubtopic, nSub)!=0 ){
1153 if( blob_strlen(&subsection) && blob_buffer(&line)[0]!='>' ){
1154 blob_appendb(pOut, &subsection);
1155 blob_reset(&subsection);
1156 }
1157 blob_appendb(pOut, &line);
1158 n++;
1159 }else if( len>9 && strncmp(blob_buffer(&line),"> fossil ",9)==0 ){
1160 subsection = line;
1161 }
1162 }
 
1163 blob_reset(&in);
1164 if( n ){
1165 blob_trim(pOut);
1166 }else{
1167 blob_reset(pOut);
1168 }
1169 return n;
1170 }
1171
1172 /*
@@ -1145,11 +1190,11 @@
1190 int n = 0;
1191
1192 re_compile(&pRe, "^(Usage: | *[Oo]r: +%fossi |> fossil )", 0);
1193 blob_init(&in, z, -1);
1194 while( blob_line(&in, &line) ){
1195 if( re_match(pRe, (unsigned char*)blob_buffer(&line), blob_strlen(&line)) ){
1196 blob_appendb(pOut, &line);
1197 n++;
1198 }
1199 }
1200 re_free(pRe);
@@ -1254,24 +1299,44 @@
1299 ** for "fossil help --usage COMMAND [SUBCOMMAND]"
1300 */
1301 void usage_cmd(void){
1302 help_cmd();
1303 }
1304
1305 /*
1306 ** COMMAND: apropos
1307 **
1308 ** Usage: %fossil apropos KEYWORD ...
1309 **
1310 ** Search the built-in help pages for Fossil for topics that
1311 ** match the KEYWORD(s)
1312 */
1313 void usage_apropos(void){
1314 char **azNewArgv = fossil_malloc( (g.argc+2)*sizeof(char*) );
1315 memcpy(azNewArgv, g.argv, g.argc);
1316 azNewArgv[0] = g.argv[0];
1317 azNewArgv[1] = "apropos";
1318 azNewArgv[2] = "-h";
1319 memcpy(&azNewArgv[3], &g.argv[2], (g.argc-2) * sizeof(char*));
1320 g.argc++;
1321 azNewArgv[g.argc] = 0;
1322 g.argv = azNewArgv;
1323 search_cmd();
1324 }
1325
1326 /*
1327 ** COMMAND: help
1328 **
1329 ** Usage: %fossil help [OPTIONS] [TOPIC] [SUBCOMMAND|options|PATTERN]
1330 **
1331 ** Display information on how to use TOPIC, which may be a command, webpage, or
1332 ** setting. Webpage names begin with "/". If TOPIC is omitted, a list of
1333 ** topics is returned. If there is an extra argument after TOPIC it is either
1334 ** the name of a subcommand, in which case only the help text for that one
1335 ** subcommand is shown, or it is the keyword "options" which displays all
1336 ** command-line options for TOPIC, or it is a text pattern which causes all
1337 ** lines of the help text that match that pattern to be shown.
 
1338 **
1339 ** The following options can be used when TOPIC is omitted:
1340 **
1341 ** -a|--all List both common and auxiliary commands
1342 ** -e|--everything List all help on all topics
@@ -1362,58 +1427,67 @@
1427 verify_all_options();
1428 if( g.argc<3 ){
1429 z = g.argv[0];
1430 fossil_print(
1431 "Usage: %s help TOPIC\n"
1432 "Things to try:\n\n"
1433 " %s help help\n"
1434 " %s help options\n"
1435 " %s help -a\n"
1436 " %s apropos TOPIC\n\n"
1437 "Other common values for TOPIC:\n\n",
1438 z, z, z, z, z);
1439 command_list(CMDFLAG_1ST_TIER,verboseFlag,useHtml);
1440 if( !verboseFlag ) version_cmd();
1441 return;
1442 }
1443 zTopic = g.argv[2];
1444 zSubtopic = g.argc>=4 ? g.argv[3] : 0;
1445 isPage = ('/' == zTopic[0]) ? 1 : 0;
1446 if( isPage ){
1447 zCmdOrPage = "page";
1448 }else if( commandsFlag ){
1449 mask = CMDFLAG_COMMAND;
1450 zCmdOrPage = "command";
1451 }else{
1452 zCmdOrPage = "command or setting";
1453 }
1454 if( fossil_strcmp(zTopic,"options")==0 ){
1455 z = zOptions;
1456 pCmd = 0;
1457 }else{
1458 rc = dispatch_name_search(g.argv[2], mask|CMDFLAG_PREFIX, &pCmd);
1459 if( rc ){
1460 int i, n;
1461 const char *az[5];
1462 if( rc==1 ){
1463 fossil_print("unknown %s: %s\n", zCmdOrPage, g.argv[2]);
1464 }else{
1465 fossil_print("ambiguous %s prefix: %s\n",
1466 zCmdOrPage, g.argv[2]);
1467 }
1468 fossil_print("Did you mean one of these TOPICs:\n");
1469 n = dispatch_approx_match(g.argv[2], 5, az);
1470 for(i=0; i<n; i++){
1471 fossil_print(" * %s\n", az[i]);
1472 }
1473 fossil_print("Other commands to try:\n");
1474 fossil_print(" fossil apropos PATTERN ;# search all help text\n");
1475 fossil_print(" fossil help -a ;# show all commands\n");
1476 fossil_print(" fossil help -w ;# show all web-pages\n");
1477 fossil_print(" fossil help -s ;# show all settings\n");
1478 fossil_print(" fossil help -o ;# show global options\n");
1479 return;
1480 }
1481 z = pCmd->zHelp;
1482 if( z==0 ){
1483 fossil_fatal("no help available for the %s %s",
1484 pCmd->zName, zCmdOrPage);
1485 }
1486 }
1487 blob_init(&subtext1, 0, 0);
1488 blob_init(&subtext2, 0, 0);
 
 
 
 
 
1489 if( zSubtopic!=0 ){
1490 if( simplify_to_subtopic(z, &subtext1, zTopic, zSubtopic) ){
1491 z = blob_str(&subtext1);
1492 }else{
1493 fossil_print("No subtopic \"%s\" for \"%s\".\n", zTopic, zSubtopic);
@@ -1423,11 +1497,11 @@
1497 }
1498 }
1499 if( bUsage && simplify_to_usage(z, &subtext2, zTopic) ){
1500 z = blob_str(&subtext2);
1501 }
1502 if( pCmd && pCmd->eCmdFlags & CMDFLAG_SETTING ){
1503 const Setting *pSetting = db_find_setting(pCmd->zName, 0);
1504 char *zDflt = 0;
1505 if( pSetting!=0 && pSetting->def!=0 && *pSetting->def!=0 ){
1506 zDflt = mprintf(" (default: %s)", pSetting->def);
1507 }
1508
+39
--- src/regexp.c
+++ src/regexp.c
@@ -682,10 +682,49 @@
682682
if( j>0 && pRe->zInit[j-1]==0 ) j--;
683683
pRe->nInit = j;
684684
}
685685
return pRe->zErr;
686686
}
687
+
688
+/*
689
+** The input zIn is a string that we want to match exactly as part of
690
+** a regular expression. Return a new string (in space obtained from
691
+** fossil_malloc() or the equivalent) that escapes all regexp syntax
692
+** characters in zIn.
693
+*/
694
+char *re_quote(const char *zIn){
695
+ Blob out;
696
+ blob_init(&out, 0, 0);
697
+ while( zIn[0] ){
698
+ switch( zIn[0] ){
699
+ case '.':
700
+ case '?':
701
+ case '*':
702
+ case '+':
703
+ case '\\':
704
+ case '(':
705
+ case ')':
706
+ case '[':
707
+ case ']':
708
+ case '|':
709
+ case '^':
710
+ case '$':
711
+ case '{':
712
+ case '}': {
713
+ blob_appendf(&out,"\\x%02x", (unsigned char)zIn[0]);
714
+ break;
715
+ }
716
+ default: {
717
+ blob_append_char(&out, zIn[0]);
718
+ break;
719
+ }
720
+ }
721
+ zIn++;
722
+ }
723
+ blob_materialize(&out);
724
+ return out.aData;
725
+}
687726
688727
/*
689728
** Implementation of the regexp() SQL function. This function implements
690729
** the build-in REGEXP operator. The first argument to the function is the
691730
** pattern and the second argument is the string. So, the SQL statements:
692731
--- src/regexp.c
+++ src/regexp.c
@@ -682,10 +682,49 @@
682 if( j>0 && pRe->zInit[j-1]==0 ) j--;
683 pRe->nInit = j;
684 }
685 return pRe->zErr;
686 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
687
688 /*
689 ** Implementation of the regexp() SQL function. This function implements
690 ** the build-in REGEXP operator. The first argument to the function is the
691 ** pattern and the second argument is the string. So, the SQL statements:
692
--- src/regexp.c
+++ src/regexp.c
@@ -682,10 +682,49 @@
682 if( j>0 && pRe->zInit[j-1]==0 ) j--;
683 pRe->nInit = j;
684 }
685 return pRe->zErr;
686 }
687
688 /*
689 ** The input zIn is a string that we want to match exactly as part of
690 ** a regular expression. Return a new string (in space obtained from
691 ** fossil_malloc() or the equivalent) that escapes all regexp syntax
692 ** characters in zIn.
693 */
694 char *re_quote(const char *zIn){
695 Blob out;
696 blob_init(&out, 0, 0);
697 while( zIn[0] ){
698 switch( zIn[0] ){
699 case '.':
700 case '?':
701 case '*':
702 case '+':
703 case '\\':
704 case '(':
705 case ')':
706 case '[':
707 case ']':
708 case '|':
709 case '^':
710 case '$':
711 case '{':
712 case '}': {
713 blob_appendf(&out,"\\x%02x", (unsigned char)zIn[0]);
714 break;
715 }
716 default: {
717 blob_append_char(&out, zIn[0]);
718 break;
719 }
720 }
721 zIn++;
722 }
723 blob_materialize(&out);
724 return out.aData;
725 }
726
727 /*
728 ** Implementation of the regexp() SQL function. This function implements
729 ** the build-in REGEXP operator. The first argument to the function is the
730 ** pattern and the second argument is the string. So, the SQL statements:
731
+13 -2
--- src/search.c
+++ src/search.c
@@ -630,10 +630,14 @@
630630
zSnip[k++] = '&';
631631
j += 4;
632632
}else{
633633
zSnip[k++] = c;
634634
}
635
+ }else if( c=='%' && strncmp(&zSnip[j],"%fossil",7)==0 ){
636
+ /* no-op */
637
+ }else if( (c=='[' || c==']') && zSnip[j+1]==c ){
638
+ j++;
635639
}else{
636640
zSnip[k++] = c;
637641
}
638642
}
639643
zSnip[k] = 0;
@@ -1054,21 +1058,28 @@
10541058
" FROM event JOIN blob on event.objid=blob.rid"
10551059
" WHERE search_match('',body('f',rid,NULL));"
10561060
);
10571061
}
10581062
if( (srchFlags & SRCH_HELP)!=0 ){
1063
+ const char *zPrefix;
10591064
helptext_vtab_register(g.db);
1065
+ if( srchFlags==SRCH_HELP ){
1066
+ zPrefix = "The";
1067
+ }else{
1068
+ zPrefix = "Built-in help for the";
1069
+ }
10601070
db_multi_exec(
10611071
"INSERT INTO x(label,url,score,id,snip)"
1062
- " SELECT format('Built-in help for the \"%%s\" %%s',name,type),"
1072
+ " SELECT format('%q \"%%s\" %%s',name,type),"
10631073
" '/help?cmd='||name,"
10641074
" search_score(),"
10651075
" 'h'||rowid,"
10661076
" search_snippet()"
10671077
" FROM helptext"
10681078
" WHERE search_match(format('the \"%%s\" %%s',name,type),"
1069
- " helptext.helptext);"
1079
+ " helptext.helptext);",
1080
+ zPrefix
10701081
);
10711082
}
10721083
}
10731084
10741085
/*
10751086
--- src/search.c
+++ src/search.c
@@ -630,10 +630,14 @@
630 zSnip[k++] = '&';
631 j += 4;
632 }else{
633 zSnip[k++] = c;
634 }
 
 
 
 
635 }else{
636 zSnip[k++] = c;
637 }
638 }
639 zSnip[k] = 0;
@@ -1054,21 +1058,28 @@
1054 " FROM event JOIN blob on event.objid=blob.rid"
1055 " WHERE search_match('',body('f',rid,NULL));"
1056 );
1057 }
1058 if( (srchFlags & SRCH_HELP)!=0 ){
 
1059 helptext_vtab_register(g.db);
 
 
 
 
 
1060 db_multi_exec(
1061 "INSERT INTO x(label,url,score,id,snip)"
1062 " SELECT format('Built-in help for the \"%%s\" %%s',name,type),"
1063 " '/help?cmd='||name,"
1064 " search_score(),"
1065 " 'h'||rowid,"
1066 " search_snippet()"
1067 " FROM helptext"
1068 " WHERE search_match(format('the \"%%s\" %%s',name,type),"
1069 " helptext.helptext);"
 
1070 );
1071 }
1072 }
1073
1074 /*
1075
--- src/search.c
+++ src/search.c
@@ -630,10 +630,14 @@
630 zSnip[k++] = '&';
631 j += 4;
632 }else{
633 zSnip[k++] = c;
634 }
635 }else if( c=='%' && strncmp(&zSnip[j],"%fossil",7)==0 ){
636 /* no-op */
637 }else if( (c=='[' || c==']') && zSnip[j+1]==c ){
638 j++;
639 }else{
640 zSnip[k++] = c;
641 }
642 }
643 zSnip[k] = 0;
@@ -1054,21 +1058,28 @@
1058 " FROM event JOIN blob on event.objid=blob.rid"
1059 " WHERE search_match('',body('f',rid,NULL));"
1060 );
1061 }
1062 if( (srchFlags & SRCH_HELP)!=0 ){
1063 const char *zPrefix;
1064 helptext_vtab_register(g.db);
1065 if( srchFlags==SRCH_HELP ){
1066 zPrefix = "The";
1067 }else{
1068 zPrefix = "Built-in help for the";
1069 }
1070 db_multi_exec(
1071 "INSERT INTO x(label,url,score,id,snip)"
1072 " SELECT format('%q \"%%s\" %%s',name,type),"
1073 " '/help?cmd='||name,"
1074 " search_score(),"
1075 " 'h'||rowid,"
1076 " search_snippet()"
1077 " FROM helptext"
1078 " WHERE search_match(format('the \"%%s\" %%s',name,type),"
1079 " helptext.helptext);",
1080 zPrefix
1081 );
1082 }
1083 }
1084
1085 /*
1086

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button