Fossil

Changes On Branch 5ee83f28076e8163
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Changes In Branch diff-keyboard-navigation Through [5ee83f2807] Excluding Merge-Ins

This is equivalent to a diff from 171127fd14 to 5ee83f2807

2025-09-26
12:53
Sync with trunk. check-in: f3ff04466d user: florian tags: diff-keyboard-navigation
2025-08-21
14:08
Add the robot-exception setting. check-in: 86b6ef7fe3 user: drh tags: trunk
12:08
Sync with trunk. check-in: 286a900699 user: florian tags: standard-cli-colors
12:07
Sync with trunk. check-in: a0377ebb9d user: florian tags: diff-word-wrap
12:06
Sync with trunk. check-in: 5ee83f2807 user: florian tags: diff-keyboard-navigation
12:04
Sync with trunk. check-in: bab295db10 user: florian tags: timeline-keyboard-navigation
12:02
Change [3710202914] to call the function to load the diff-related JS code even for blocked diffs. By default, the loader function is already a no-op if diffs are blocked, so the behavior intended by [3710202914] is retained. But other branches are patching the loader function because they rely on the JS code even if the diffs are hidden. check-in: 171127fd14 user: florian tags: trunk
10:51
Rearrange fields in the Robot Defense setup to make it easier to understand. check-in: 58a48e3abe user: drh tags: trunk
2025-07-21
12:16
Sync with trunk. check-in: 75244ee4fd user: florian tags: diff-keyboard-navigation

Changes to src/fossil.diff.js.
92
93
94
95
96
97
98






99
100




























































































































101
102
103
104
105
106
107
        /* Toggle all entries to match this new state. We use click()
           instead of ckbox.checked=... so that the on-change event handler
           fires. */
        if(ckbox.checked!==show) ckbox.click();
      }
    }, false);
  }






});





























































































































window.fossil.onPageLoad(function(){
  const F = window.fossil, D = F.dom;
  const Diff = F.diff = {
    e:{/*certain cached DOM elements*/},
    config: {
      chunkLoadLines: (
        F.config.diffContextLines * 3







>
>
>
>
>
>


>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
        /* Toggle all entries to match this new state. We use click()
           instead of ckbox.checked=... so that the on-change event handler
           fires. */
        if(ckbox.checked!==show) ckbox.click();
      }
    }, false);
  }
  function resetToggles(){
    var cb = document.querySelectorAll(
                        'input[type="checkbox"].diff-toggle:not(:checked)');
    for( var i=0; i<cb.length; i++ ) cb[i].checked = true;
  }
  setTimeout(resetToggles);
});

/*
** Diff keyboard navigation shortcuts:
**
** ### NOTE: The keyboard shortcuts are listed in the /vdiff help screen. ###
**
** Ideas and TODOs:
**
**  o The `timeline-keyboard-navigation' branch removes the unload handler from
**    pages containing timeline snippets, so it's no longer necessary to reset
**    the diff toggles on back/forward navigation in case the mentioned branch
**    is merged with `diff-keyboard-navigation'.
*/
(function(){
  window.addEventListener('load',function(){
    function btnScrollIntoView(e){
      e = e.parentElement;
      var rc = e.getBoundingClientRect();
      var y = 0;
      do{
        y += e.offsetTop;
      }while( e = e.offsetParent );
      window.scrollTo(0,y-6*rc.height);
    }
    document.addEventListener('keydown',function(evt){
      if( evt.target.tagName=='INPUT' || evt.target.tagName=='SELECT' ) return;
      var
        mSHIFT = 1<<13,
        kSHOW = mSHIFT | 73 /* SHIFT+I */,
        kHIDE = 73 /* I */,
        kNEXT = 80 /* P */,
        kPREV = 79 /* O (Letter O) */,
        kUNID = 85 /* U */,
        kSBSD = mSHIFT | 85 /* SHIFT+U */,
        kNULD = 48 /* 0 (Digit Zero) */,
        kUDCD = 68 /* D */,
        mod = evt.altKey<<15|evt.ctrlKey<<14|evt.shiftKey<<13|evt.metaKey<<12,
        key = ( evt.which || evt.keyCode ) | mod;
      switch( key ){
        case kSHOW:
        case kHIDE:
        case kNEXT:
        case kPREV:
        case kUNID:
        case kSBSD:
        case kNULD:
        case kUDCD: break;
        default: return;
      }
      evt.preventDefault();
      evt.stopPropagation();
      if( key==kSHOW || key==kHIDE ){
        var btn = document.getElementsByClassName('diff-toggle');
        if( btn.length>0 ){
          var chg = 0;
          for( var i=0; i<btn.length; i++ ){
            if( btn[i].checked && key==kHIDE ){
              btn[i].click();
              chg++;
            }
            else if( !btn[i].checked && key==kSHOW ){
              btn[i].click();
              chg++;
            }
          }
          if( chg>0 ) btnScrollIntoView(btn[0]);
        }
      }
      else if( key==kNEXT || key==kPREV ){
        var btn = document.getElementsByClassName('diff-toggle');
        if( btn.length>1 ){
          var nFolded = 0, n = -2;
          for( var i=0; i<btn.length; i++ ){
            if( !btn[i].checked ) nFolded++;
          }
          if( nFolded==0 ){
            n = ( key==kNEXT ? 0 : btn.length-1 );
            for( var i=0; i<btn.length; i++ ){
              if( n!=i ) btn[i].click();
            }
          }
          else{
            for( var i=0; i<btn.length; i++ ){
              if( btn[i].checked ){
                if( n==-2 ) n = ( key==kNEXT ? i+1 : i-1 );
                if( n!=i ) btn[i].click();
              }
            }
          }
          if( n==-2 ) n = ( key==kNEXT ? 0 : btn.length-1 );
          if( n in btn ){
            if( !btn[n].checked ) btn[n].click();
            btnScrollIntoView(btn[n]);
          }
        }
        else if( btn.length>0 ){
          btn[0].click();
          btnScrollIntoView(btn[0]);
        }
      }
      else if( key==kUNID || key==kSBSD || key==kNULD ){
        var T={}; T[kUNID]='unified', T[kSBSD]='side-by-side', T[kNULD]='hide';
        var
          type = T[key],
          link = document.querySelector('.smb-'+type+'-diff')
                  || document.querySelector('.sml-'+type+'-diff'),
          href;
        if( link ){
          if( link.dataset.href ) href = link.dataset.href;   // anti-bot
          else href = link.href;
        }
        if( href && href!=location.href.slice(-href.length) ){
          location.href = href;
        }
      }
      else if( key==kUDCD ){
        if( !/[?&]udc=1/.test(location.href) ){
          var sep = /\?/.test(location.href) ? '&' : '?';
          location.href += sep + 'udc=1';
        }
      }
    }/*,true*/);
  },false);
}());

window.fossil.onPageLoad(function(){
  const F = window.fossil, D = F.dom;
  const Diff = F.diff = {
    e:{/*certain cached DOM elements*/},
    config: {
      chunkLoadLines: (
        F.config.diffContextLines * 3
Changes to src/info.c.
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
  }
}

/*
** Generate javascript to enhance HTML diffs.
*/
void append_diff_javascript(int diffType){
  if( diffType==0 ) return;
  builtin_fossil_js_bundle_or("diff", NULL);
}

/*
** Construct an appropriate diffFlag for text_diff() based on query
** parameters and the to boolean arguments.
*/







|







458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
  }
}

/*
** Generate javascript to enhance HTML diffs.
*/
void append_diff_javascript(int diffType){
  /* Load fossil.diff.js even if diffType==0 to enable keyboard shortcuts. */
  builtin_fossil_js_bundle_or("diff", NULL);
}

/*
** Construct an appropriate diffFlag for text_diff() based on query
** parameters and the to boolean arguments.
*/
643
644
645
646
647
648
649





650


651
652
653


654
655
656
657
658
659
660
661
  if( DCfg.diffFlags & DIFF_SIDEBYSIDE ){
    DCfg.diffFlags |= DIFF_HTML | DIFF_NOTTOOBIG;
  }else{
    DCfg.diffFlags |= DIFF_LINENO | DIFF_HTML | DIFF_NOTTOOBIG;
  }
  @ <div class="sectionmenu info-changes-menu">
  zW = (DCfg.diffFlags&DIFF_IGNORE_ALLWS)?"&w":"";





  if( diffType!=1 ){


    @ %z(chref("button","%R?diff=1%s",zW))Unified&nbsp;Diff</a>
  }
  if( diffType!=2 ){


    @ %z(chref("button","%R?diff=2%s",zW))Side-by-Side&nbsp;Diff</a>
  }
  if( diffType!=0 ){
    if( *zW ){
      @ %z(chref("button","%R?diff=%d",diffType))\
      @ Show&nbsp;Whitespace&nbsp;Changes</a>
    }else{
      @ %z(chref("button","%R?diff=%d&w",diffType))Ignore&nbsp;Whitespace</a>







>
>
>
>
>

>
>
|


>
>
|







643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
  if( DCfg.diffFlags & DIFF_SIDEBYSIDE ){
    DCfg.diffFlags |= DIFF_HTML | DIFF_NOTTOOBIG;
  }else{
    DCfg.diffFlags |= DIFF_LINENO | DIFF_HTML | DIFF_NOTTOOBIG;
  }
  @ <div class="sectionmenu info-changes-menu">
  zW = (DCfg.diffFlags&DIFF_IGNORE_ALLWS)?"&w":"";
  if( diffType!=0 ){
    /* Class "smb-hide-diff" required by the fossil.diff.js script. */
    const char *zBtnClass = "button smb-hide-diff";
    @ %z(chref(zBtnClass,"%R?diff=0"))Hide&nbsp;Diff</a>
  }
  if( diffType!=1 ){
    /* Class "smb-unified-diff" required by the fossil.diff.js script. */
    const char *zBtnClass = "button smb-unified-diff";
    @ %z(chref(zBtnClass,"%R?diff=1%s",zW))Unified&nbsp;Diff</a>
  }
  if( diffType!=2 ){
    /* Class "smb-side-by-side-diff" required by the fossil.diff.js script. */
    const char *zBtnClass = "button smb-side-by-side-diff";
    @ %z(chref(zBtnClass,"%R?diff=2%s",zW))Side-by-Side&nbsp;Diff</a>
  }
  if( diffType!=0 ){
    if( *zW ){
      @ %z(chref("button","%R?diff=%d",diffType))\
      @ Show&nbsp;Whitespace&nbsp;Changes</a>
    }else{
      @ %z(chref("button","%R?diff=%d&w",diffType))Ignore&nbsp;Whitespace</a>
821
822
823
824
825
826
827



828
829
830
831
832
833
834
** when using "fossil ui --from PATH", the --from argument becomes the value
** of the exbase query parameter for the start page.  Note that if PATH
** is a pure hexadecimal string, it is decoded first before being used as
** the pathname.  Real pathnames should contain at least one directory
** separator character.
**
** Other query parameters related to diffs are also accepted.



*/
void ckout_page(void){
  int vid;
  const char *zHome;          /* Home directory */
  int nHome;
  const char *zExBase;
  char *zHostname;







>
>
>







830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
** when using "fossil ui --from PATH", the --from argument becomes the value
** of the exbase query parameter for the start page.  Note that if PATH
** is a pure hexadecimal string, it is decoded first before being used as
** the pathname.  Real pathnames should contain at least one directory
** separator character.
**
** Other query parameters related to diffs are also accepted.
**
** See the help screen for the /vdiff web page for a list of available
** keyboard shortcuts.
*/
void ckout_page(void){
  int vid;
  const char *zHome;          /* Home directory */
  int nHome;
  const char *zExBase;
  char *zHostname;
888
889
890
891
892
893
894



895
896
897
898
899
900
901
902
903
904
905
906
907

908
909
910
911
912
913
914
**
** Display information about a particular check-in.  The exact
** same information is shown on the /info page if the name query
** parameter to /info describes a check-in.
**
** The ARTIFACTID can be a unique prefix for the HASH of the check-in,
** or a tag or branch name that identifies the check-in.



*/
void ci_page(void){
  Stmt q1, q2, q3;
  int rid;
  int isLeaf;
  int diffType;        /* 0: no diff,  1: unified,  2: side-by-side */
  const char *zName;   /* Name of the check-in to be displayed */
  const char *zUuid;   /* Hash of zName, found via blob.uuid */
  const char *zParent; /* Hash of the parent check-in (if any) */
  const char *zRe;     /* regex parameter */
  ReCompiled *pRe = 0; /* regex */
  const char *zW;               /* URL param for ignoring whitespace */
  const char *zPage = "vinfo";  /* Page that shows diffs */

  const char *zBrName;          /* Branch name */
  DiffConfig DCfg,*pCfg;        /* Type of diff */

  login_check_credentials();
  if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
  style_set_current_feature("vinfo");
  zName = P("name");







>
>
>













>







900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
**
** Display information about a particular check-in.  The exact
** same information is shown on the /info page if the name query
** parameter to /info describes a check-in.
**
** The ARTIFACTID can be a unique prefix for the HASH of the check-in,
** or a tag or branch name that identifies the check-in.
**
** See the help screen for the /vdiff web page for a list of available
** keyboard shortcuts.
*/
void ci_page(void){
  Stmt q1, q2, q3;
  int rid;
  int isLeaf;
  int diffType;        /* 0: no diff,  1: unified,  2: side-by-side */
  const char *zName;   /* Name of the check-in to be displayed */
  const char *zUuid;   /* Hash of zName, found via blob.uuid */
  const char *zParent; /* Hash of the parent check-in (if any) */
  const char *zRe;     /* regex parameter */
  ReCompiled *pRe = 0; /* regex */
  const char *zW;               /* URL param for ignoring whitespace */
  const char *zPage = "vinfo";  /* Page that shows diffs */
  const char *zPageHide = "ci"; /* Page that hides diffs */
  const char *zBrName;          /* Branch name */
  DiffConfig DCfg,*pCfg;        /* Type of diff */

  login_check_credentials();
  if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
  style_set_current_feature("vinfo");
  zName = P("name");
1173
1174
1175
1176
1177
1178
1179






1180


1181
1182
1183
1184


1185
1186
1187
1188
1189
1190
1191
1192
  @ <div class="accordion_panel">
  @ <div class="sectionmenu info-changes-menu">
  /* ^^^ .info-changes-menu is used by diff scroll sync */
  pCfg = construct_diff_flags(diffType, &DCfg);
  DCfg.diffFlags |= DIFF_NUMSTAT; /* Show stats in the 'Changes' section */
  DCfg.pRe = pRe;
  zW = (DCfg.diffFlags&DIFF_IGNORE_ALLWS)?"&w":"";






  if( diffType!=1 ){


    @ %z(chref("button","%R/%s/%T?diff=1%s",zPage,zName,zW))\
    @ Unified&nbsp;Diff</a>
  }
  if( diffType!=2 ){


    @ %z(chref("button","%R/%s/%T?diff=2%s",zPage,zName,zW))\
    @ Side-by-Side&nbsp;Diff</a>
  }
  if( diffType!=0 ){
    if( *zW ){
      @ %z(chref("button","%R/%s/%T?diff=%d",zPage,zName,diffType))
      @ Show&nbsp;Whitespace&nbsp;Changes</a>
    }else{







>
>
>
>
>
>

>
>
|



>
>
|







1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
  @ <div class="accordion_panel">
  @ <div class="sectionmenu info-changes-menu">
  /* ^^^ .info-changes-menu is used by diff scroll sync */
  pCfg = construct_diff_flags(diffType, &DCfg);
  DCfg.diffFlags |= DIFF_NUMSTAT; /* Show stats in the 'Changes' section */
  DCfg.pRe = pRe;
  zW = (DCfg.diffFlags&DIFF_IGNORE_ALLWS)?"&w":"";
  if( diffType!=0 ){
    /* Class "smb-hide-diff" required by the fossil.diff.js script. */
    const char *zBtnClass = "button smb-hide-diff";
    @ %z(chref(zBtnClass,"%R/%s/%T?diff=0",zPageHide,zName))\
    @ Hide&nbsp;Diff</a>
  }
  if( diffType!=1 ){
    /* Class "smb-unified-diff" required by the fossil.diff.js script. */
    const char *zBtnClass = "button smb-unified-diff";
    @ %z(chref(zBtnClass,"%R/%s/%T?diff=1%s",zPage,zName,zW))\
    @ Unified&nbsp;Diff</a>
  }
  if( diffType!=2 ){
    /* Class "smb-side-by-side-diff" required by the fossil.diff.js script. */
    const char *zBtnClass = "button smb-side-by-side-diff";
    @ %z(chref(zBtnClass,"%R/%s/%T?diff=2%s",zPage,zName,zW))\
    @ Side-by-Side&nbsp;Diff</a>
  }
  if( diffType!=0 ){
    if( *zW ){
      @ %z(chref("button","%R/%s/%T?diff=%d",zPage,zName,diffType))
      @ Show&nbsp;Whitespace&nbsp;Changes</a>
    }else{
1399
1400
1401
1402
1403
1404
1405














1406
1407
1408
1409
1410
1411
1412
**   dc=N            show N lines of context around each diff
**   w=BOOLEAN       ignore whitespace when computing diffs
**   nohdr           omit the description at the top of the page
**   nc              omit branch coloration from the header graph
**   inv             "Invert".  Exchange the roles of from= and to=
**
** Show all differences between two check-ins.














*/
void vdiff_page(void){
  int ridFrom, ridTo;
  int diffType = 0;        /* 0: none, 1: unified, 2: side-by-side */
  Manifest *pFrom, *pTo;
  ManifestFile *pFileFrom, *pFileTo;
  const char *zBranch;







>
>
>
>
>
>
>
>
>
>
>
>
>
>







1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
**   dc=N            show N lines of context around each diff
**   w=BOOLEAN       ignore whitespace when computing diffs
**   nohdr           omit the description at the top of the page
**   nc              omit branch coloration from the header graph
**   inv             "Invert".  Exchange the roles of from= and to=
**
** Show all differences between two check-ins.
**
** Keyboard navigation shortcuts:
**
**    I     Show all file changes.
**    i     Hide all file changes.
**    p     Show only next file change.
**    o     Show only previous file change.
**    u     Reload page in Unified Diff mode.
**    U     Reload page in Side-By-Side Diff mode.
**    0     Reload page in Hidden Diff mode.
**    d     Reload page and set current Diff mode as default.
**
** The keyboard shortcuts also apply to /ckout, /vinfo, /ci and /fdiff
** pages, and to /info pages describing check-in information.
*/
void vdiff_page(void){
  int ridFrom, ridTo;
  int diffType = 0;        /* 0: none, 1: unified, 2: side-by-side */
  Manifest *pFrom, *pTo;
  ManifestFile *pFileFrom, *pFileTo;
  const char *zBranch;
1486
1487
1488
1489
1490
1491
1492



1493
1494
1495
1496
1497
1498
1499
    blob_appendf(&qp, "&w");
  }
  cgi_check_for_malice();
  style_set_current_feature("vdiff");
  if( zBranch==0 ){
    style_submenu_element("Path", "%R/timeline?me=%T&you=%T", zFrom, zTo);
  }



  if( diffType!=2 ){
    style_submenu_element("Side-by-Side Diff", "%R/vdiff?diff=2&%b%b", &qp,
                          &qpGlob);
  }
  if( diffType!=1 ) {
    style_submenu_element("Unified Diff", "%R/vdiff?diff=1&%b%b", &qp, &qpGlob);
  }







>
>
>







1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
    blob_appendf(&qp, "&w");
  }
  cgi_check_for_malice();
  style_set_current_feature("vdiff");
  if( zBranch==0 ){
    style_submenu_element("Path", "%R/timeline?me=%T&you=%T", zFrom, zTo);
  }
  if( diffType!=0 ){
    style_submenu_element("Hide Diff", "%R/vdiff?diff=0&%b%b", &qp, &qpGlob);
  }
  if( diffType!=2 ){
    style_submenu_element("Side-by-Side Diff", "%R/vdiff?diff=2&%b%b", &qp,
                          &qpGlob);
  }
  if( diffType!=1 ) {
    style_submenu_element("Unified Diff", "%R/vdiff?diff=1&%b%b", &qp, &qpGlob);
  }
1973
1974
1975
1976
1977
1978
1979



1980
1981
1982
1983
1984
1985
1986
**
**      dc=N             Show N lines of context around each diff
**      patch            Use the patch diff format
**      regex=REGEX      Only show differences that match REGEX
**      sbs=BOOLEAN      Turn side-by-side diffs on and off (default: on)
**      verbose=BOOLEAN  Show more detail when describing artifacts
**      w=BOOLEAN        Ignore whitespace



*/
void diff_page(void){
  int v1, v2;
  int isPatch = P("patch")!=0;
  int diffType;          /* 0: none, 1: unified,  2: side-by-side */
  char *zV1;
  char *zV2;







>
>
>







2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
**
**      dc=N             Show N lines of context around each diff
**      patch            Use the patch diff format
**      regex=REGEX      Only show differences that match REGEX
**      sbs=BOOLEAN      Turn side-by-side diffs on and off (default: on)
**      verbose=BOOLEAN  Show more detail when describing artifacts
**      w=BOOLEAN        Ignore whitespace
**
** See the help screen for the /vdiff web page for a list of available
** keyboard shortcuts.
*/
void diff_page(void){
  int v1, v2;
  int isPatch = P("patch")!=0;
  int diffType;          /* 0: none, 1: unified,  2: side-by-side */
  char *zV1;
  char *zV2;
3310
3311
3312
3313
3314
3315
3316



3317
3318
3319
3320
3321
3322
3323
**
** The NAME argument is any valid artifact name: an artifact hash,
** a timestamp, a tag name, etc.
**
** Because NAME can match so many different things (commit artifacts,
** wiki pages, ticket comments, forum posts...) the format of the output
** page depends on the type of artifact that NAME matches.



*/
void info_page(void){
  const char *zName;
  Blob uuid;
  int rid;
  int rc;
  int nLen;







>
>
>







3356
3357
3358
3359
3360
3361
3362
3363
3364
3365
3366
3367
3368
3369
3370
3371
3372
**
** The NAME argument is any valid artifact name: an artifact hash,
** a timestamp, a tag name, etc.
**
** Because NAME can match so many different things (commit artifacts,
** wiki pages, ticket comments, forum posts...) the format of the output
** page depends on the type of artifact that NAME matches.
**
** See the help screen for the /vdiff web page for a list of available
** keyboard shortcuts (if the NAME argument refers to a check-in).
*/
void info_page(void){
  const char *zName;
  Blob uuid;
  int rid;
  int rc;
  int nLen;